ヴァイオリンを整備に出した/友人と久々に会った

ヴァイオリンを整備に出した

昨日起きたG線の鳴りの件で、数駅離れたところにある大きな楽器屋(なんと弦楽器リペアマンが常駐している)に来た。楽器を見てもらうと、G線の鳴りの問題はE線のチューブ(説明するのが難しいが、一番細いE線には駒への食い込みを防ぐために1cmくらい幅のチューブが通されており、必要ならばこれを駒に噛ませる。が、大抵の駒は駒の方に食い込み防止の皮が張ってあるので、あまり使われない)が遊んでいたからだった。これを除去するなり、弦の端の太い部分に押し込んで動かなくするなりしておく必要がある。

割とよくあるトラップなので、これを見抜けなかったのはすこし悔しい。

詳しい説明はこちら

マイスターのQ&A

それはそうとして、リペアマンに楽器全体を点検してもらうと他にも数箇所調整の必要がある箇所が見つかった。この際なので、全部やってもらうことにした。加えて、消耗品の交換もする。10日ほどかかるらしい。

待ち時間に楽器店を見て回ったりサイレントヴァイオリンを試奏したりした。やはり本来ヴァイオリンにある木の箱を鳴らすという感覚がなかったのは仕方ないが、逆に言えばそれだけで、想像以上に本物のヴァイオリンに近い音がした。ある音を弾いたときに他の弦が共鳴して鳴る現象もきちんと拾えていた。

奥には防音室のモデルルームがあった。大学の研究で使っていたような狭くて圧迫感があるものだけではなく、グランドピアノが入るほど巨大、かつガラス張りで開放感もあるようなすごい製品もあるようだ(もちろんお値段もすごい)。僕としては音楽を演奏することは日常生活の一部だから、騒音を気にする風潮は緩和されてほしいのだが、それはそれとしてここまでして音楽をやるという執念もまたすごいと思った。一方で安いモデルでは薄い樹脂の板を自分ではめ込んで作る簡易的・軽量な製品もあるらしい。ただこれはやはり防音性能が弱い。ヴァイオリンの生演奏にはほぼ無力だろう。ヴァイオリン演奏という観点では、弓が大きく動くので一人でも広め・高めの部屋が必要になる。そういうところに配慮した製品もあるようだ。

友人と久々に会った

今日は東大の五月祭で、友人がそれに合わせて遠方から遊びに来たので、酒を飲んだ。大学を出てもう満4年になるが、友情はいつどれだけ温め直しても良い。無料のお冷を頼んでも無視されたけどウーロン茶はすぐ来たので、飲食店ではちゃんとお金を出して飲もうね。

ヴァイオリンで1の指を2の指の半音下の位置に置けない

ヴァイオリンは12歳で始めて20歳までは頻繁に弾いていて、それ以降は練習場所がなくなってやめていた。最近やっぱりやりたいなという気持ちが強くなって、色々工夫しながら弾いている。騒音は繊細の問題なのであまり書かないようにするが、様々な場所で、様々な対策を取りながら練習している。しかし基本的にヴァイオリンはある程度響く屋内で弾くように作られているので、練習もそういう環境でできるのがベストだ。

ヴァイオリンは弾きたいが、それは日々練習して少しずつ身体的に上達していく趣味がほしいということであって、特に弾きたい曲はない。だからボウイング、スケール、練習曲をやっている。特に練習曲は『セブシック』をやることにした。これは左手をとことんいじめる~マゾ向け~ストイックで有名な教本だ。

僕のフォームには1つ問題があり、2の指のローポジション(A線におけるCナチュラル)から1の指(A線におけるH)に移行するとき、2の指に隣接した場所に1の指を置くことが困難で、一瞬手首をひねって手のひらをネックと平行に近づけないと1の指を正しい場所に置けない。昔からこの問題は認識していて解決しようとしていたが、うまくいかなかったしそれほど高度な曲は弾いてなかったので実害も少なかった。しかし特定の指の動かし方をするときに手首を連動させる必要があるというのは素早いフィンガリングを阻害するので、高度な曲を弾く際には問題になる。

調べてみると同種の問題に直面している人は少しはいるらしい。

(もしかしてお前の指太い?みたいなコメントがあって笑っちゃった)

本当は先生について見てもらうべきなんだけど、そこまで真剣にやれるかなあというのはまだ微妙なので自分で分析した感じだと、上りと下りで同じ手の形を徹底できていない、そもそも上りでもかなり無理な力で制御しているので柔軟性が足りていない、ということのようだった。そこで『セブシック』で徹底的な反復練習をして鍛えようということだ。

それはそうと、今日よく聞いてみたらG線でフォルテで鳴らしたときに楽器のどこかが変に振動して異音が鳴っていることに気づいた。自分でわかる範囲に原因はなかったので、そうなるとどこかのニカワが剥がれているという可能性がある。ヴァイオリンのニカワはつけ外しできるものなので致命的ではないが、修理に出すとやはりお金はかかる。

ヴァイオリンは結構維持費がかかる。前述のように分解・再組み立てができるものなのでちゃんと作られた楽器をちゃんとメンテナンスしていれば長く使えるのだが、消耗するパーツもある。たとえば弓の毛(ウマのしっぽの毛)は半年程度、弦は3ヶ月~半年程度で交換する。

ブログであまりヴァイオリンのことを書いていなかった。ブログを初めたのがヴァイオリンをやめたあとだったからだ。しかしヴァイオリンを再開してからの生活の潤いを考えると、やはり僕の人生には音楽が必要だったのだなあと思った。

Raspberry Pi Zero WHでNASしたい、失敗録1

配線

私はRaspberry Pi Zero WHを所有していて、これまで自宅の室温を記録してサーバーに送信していた。突然NASを組みたくなり、これを利用できないかと考えた。

ざっくりラズパイにストレージが接続さえできればあとはどうにでもなりそうだったので、アダプター類を購入して準備した。具体的には、Zero WHはUSB micro-B凹端子しかないので、ここから

  • USB micro-B凸 to USB A凹 変換
  • USB A凸 to USB A凹 ハブ(給電機能つき)
  • USB A凸 to SATA

の3段階を経てタンスに打ち捨てられていたHDDに接続。つないでlsblkするだけで認識できた。

HDDの準備

母艦側PCでHDDの中身を適当にサルベージしたあと、フォーマットしてLUKS暗号化しつつBtrfsでパーティションを作成。このあたりは全部UbuntuのdiskユーティリティでGUI操作可能だった。ただしGUI上でBtrfsを選択するためにはaptでbtrfs-progsを入れておく必要がある。

Raspberry Piのソフトウェアレイヤーの準備

よくあるチュートリアルのようにOpenMediaVaultを入れようとしたのだが、そのためにはRaspberry PiのOSがGUIをサポートしないバージョンでなければならない。そのために面倒な思いをしてOSを入れ直した。しかし改めてOMVを入れようとしたが、一般的なインストールスクリプトはRaspberry Pi Zeroには対応してないらしい。

RPi revision code :: 9000c1
This RPi1 is not supported (not true armhf).  Exiting...

仕方なくsambaに方針転換してインストールしてみた。

HDDをマウントする

LUKSで暗号化されたストレージは先に

sudo cryptsetup luksOpen /dev/sda storage

する必要があるのだが、なんとこれを実行するメモリが足りなかった(そんなことある!?)

Not enough available memory to open a keyslot.

ので、HDDを再フォーマットしてチャレンジします…

2023GW振り返り

今年はカレンダー通りなので5/4スタートです。連休を作りすぎるとやることがない人生に絶望して悲しくなるので…

5/3(水)

河原でヴァイオリン練習。カノンを録音してセルフ多重して一人で楽しんでた。河原は音を気にしなくていいけど車が通るのと風が強いのが難点。

その後カレーの材料を買って作った。

5/4(木)

スポーツクラブで体力テストのイベントがあったので参加。

鍛えている足や腹筋は悪くないスコアが出たが、握力は全く鍛えてないし、柔軟はいつも痛いし、有酸素は時間取れてないので宜なるかな。体力年齢60-64歳でガックリ。あと30年くらい維持すれば年齢相応になる。

もうちょっと良いマイクがほしいなとなんとなく思って秋葉原に行ってSONYのやつを買ってみたけど、discordで友達に聴き比べてもらったら大差なかったので意味のない買い物だった。悲しいね。

5/5(金)

ネット上の「ダーツの旅」アプリで渋谷区猿楽町を引いたので、友人と歩いた。謎の寺、超高そうなマンション(後で調べたら月200万〜)、何を売ってるのかよくわからない商品密度が異様に低い店、美容室、大使館、古墳などがあった。

ランチはメキシコ料理屋。マンションの上層階にあり、高級住宅街の中にあるとは思えない大音量大陽気大メキシコミュージックで入店直後にもうウキウキ。『ER』でグリーン先生が死ぬ前日に飲んでいたカクテル「マイタイ」を飲むことができた。

その後のんびりと麻布に向かって散歩。白根記念渋谷区郷土博物館・文学館がこどもの日で無料だった(そもそも普段も100円だし、私はこどもではない)。結構充実してる。

麻布周辺の超高級住宅街を見て、全く違う階層の生活だなあと関心してしまった。労働者では一生あそこには行けないね…。

恵比寿駅に戻って電車で帰宅。足がクタクタ。

5/6(土)

足が筋肉痛だったので休養日…と言いつつ、家系ラーメンを食べたり散髪したりヴァイオリンを練習したりした。渡辺明の坊主頭がカッコいいと思っていて、あれを真似しようかと思ったけど度胸がなくてやめた。あと家系ラーメン食べると尿が白濁してて怖い。翌日には治ります。

5/7(日)

NAS組みたくなって、ラズパイはすでにあったので秋葉原でHDD接続用のUSBハブを買った。その後大学のサークルの先輩たちと酒を飲んだ。

Next.jsのReact EssentialsのServer Componentsの説明をオレオレ翻訳しながら読む

これの話

https://nextjs.org/docs/getting-started/react-essentials#server-components

正確さではなく(それならAIでいいよね)、自分の理解に引き寄せて翻訳してみる。

Server Components

Server and Client Components があるとサーバーとクライアントの両側にまたがるアプリケーションを作れます。クライアントサイドのリッチなインタラクティビティと伝統的なサーバーレンダリングのパフォーマンスを組み合わせることができます。

Thinking in Server Components

ReactはUI設計の考え方を変えました。同じようにReact Server Componentsは、サーバーとクライアントの両方を活かしたハイブリッドアプリケーションを作るための新しい考え方です。

Reactはこれまで全てをクライアントサイドでレンダリングしていました(SPAというやつです)。しかし、Server Componentsがあると目的に応じてどこでレンダリングするかを決められます。

たとえば、アプリケーションのpageを考えます。

ページをコンポーネントに分割すると、実は大多数のコンポーネントはインタラクティブではないです。つまりサーバーサイドでServer Componentとしてレンダリングできます。そしてその中にインタラクティブなクライアントコンポーネントを点在させるのです。これはNext.jsのサーバーファーストなアプローチと相性がいいです。

Why Server Components?

Server Componentsのメリットは何?という疑問が浮かぶでしょう。

Server Componentsはサーバーのインフラを活用しやすいです。たとえば、巨大な依存パッケージをクライアントに送信する必要がありません。こうなるとReactはPHPやRoRのよう(テンプレートエンジンのように?)に扱えます。

Server Componentsは初期ページ読み込みが早いです。バンドルサイズが小さくなります。根幹部分のクライアント側ランタイムはキャッシュ可能かつサイズの予測が可能で、アプリケーションが成長しても増えません。追加されるJavaScriptは、Client Componentsが使われたときだけ増えます(この辺あんまりわかってない)。

Next.jsでrouteが読み込まれたとき、初期HTMLがサーバーでレンダリングされます。このHTMLはブラウザで段階的に成長し、クライアントがアプリケーションを引き継ぎ、インタラクティビティが付加されます。このためのランタイムの読み込みは非同期的です。

Server Componentsに楽に移行できるように、App Router内のコンポーネントは全てデフォルトでServer Componentsにします。special filesやcolocated componentsも同様です。だからあなたは何もしなくてもServer Componentsを採用して優れたパフォーマンスを得られます。ここに use client directiveを使うことでClient Componentsをオプトインできます。

Client Components

Client Componentsを使うとクライアント側でのインタラクティビティを付加できます。これはNext.jsではサーバーでのpre-renderingとクライアント側でのhydrationで実現しています。Client ComponentsはこれまでのPage Routerと同じ動きです。

The "use client" directive

use client directiveはServer / Client Componentsの境界線を宣言するものです。

'use client';

import { useState } from 'react';

export default function Counter() {
  const [count, setCount] = useState(0);

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>Click me</button>
    </div>
  );
}

"use client" はサーバーとクライアントのコードの間に配置します。ファイルの一番上、importsよりも上に書きます。"use client" が宣言されると、そのファイルがimportしている全てのモジュール(子コンポーネントなど)はクライアントバンドルの一部と認識されます。

デフォルトはServer Componentsなので、 "use client" 宣言がない限り全てはServer Component moduleに含まれます。

豆知識

  • Server Component moduleに含まれるComponentはサーバーでのみレンダリングされることが保証されます
  • Client Componentはクライアントでレンダリングされるものですが、Next.jsは事前にサーバーでレンダリングすることもあります
  • "use client" はファイルの一番上で宣言しなければなりません
  • "use client" は全てのファイルで宣言する必要はなく、Server Componentsとの境界でだけ宣言すれば十分です(そのファイルがimportしているファイルもクライアントバンドルになるので、"use client" が宣言されたファイルはentry pointとみなすことができます)

おわりに

Server Componentsが何なのか知りたくて調べていたんだけど、なんか概念的な記事しかなくてよくわからなくて、この記事もそうだった。完。でも概念はちょっとわかった。

goでmysqlにDATETIMEを入れるときにgo-mysql-driverとbunでタイムゾーンの扱いが違う

goのTimeは日時とタイムゾーンの情報を持っている。日本標準時のタイムゾーンを持ったTimeを作ってみる。

location, err := time.LoadLocation("Asia/Tokyo")
if err != nil {
    log.Fatal(err)
}
t := time.Date(2019, 1, 2, 3, 4, 5, 0, location) // 2019年1月2日3時4分5秒

これをmysqlに突っ込む。mysqlとのコネクションはこんな感じ。

cfg := mysql.Config{
    User:      "root",
    Passwd:    "password",
    Net:       "tcp",
    Addr:      "127.0.0.1:4306",
    DBName:    "time",
    ParseTime: true,
}

Locは指定していない。その場合UTCになる。

https://github.com/go-sql-driver/mysql/blob/191a7c4c519ef60cf3e8656fde8728eee9194308/dsn.go#L73

// NewConfig creates a new Config and sets default values.
func NewConfig() *Config {
    return &Config{
        Collation:            defaultCollation,
        Loc:                  time.UTC,
        MaxAllowedPacket:     defaultMaxAllowedPacket,
        Logger:               defaultLogger,
        AllowNativePasswords: true,
        CheckConnLiveness:    true,
    }
}

go-mysql-driverで生のSQLを書いてmysqlにINSERTする

db.Exec("INSERT INTO `time` (`id`, `time`) VALUES (?, ?);", "Asia/Tokyo 2019-01-02T03:04:05", t)

このとき発行されるクエリをgeneral_logで確認すると、この段階でUTCの 2019-01-01 18:04:05 に変換されている。

2023-05-06T14:33:27.581647Z     9 Execute   INSERT INTO `time` (`id`, `time`) VALUES ('Asia/Tokyo 2019-01-02T03:04:05', '2019-01-01 18:04:05')

これはgo-mysql-driverがTimeをシリアライズする前にInでタイムゾーンをUTCに変換しているからだ。

https://github.com/go-sql-driver/mysql/blob/191a7c4c519ef60cf3e8656fde8728eee9194308/packets.go#L1119

b, err = appendDateTime(b, v.In(mc.cfg.Loc))

ではbunでTimeをINSERTするとどうなるか

type BTime struct {
    bun.BaseModel `bun:"time2"`
    ID            string
    Time          time.Time
}
bundb.NewInsert().Model(&BTime{ID: "BUN Asia/Tokyo 2019-01-02T03:04:05", Time: t}).Exec(ctx)

このとき発行されるクエリでは、Timeに設定されているタイムゾーンを無視して 2019-01-02 03:04:05 とシリアライズしている。

2023-05-06T14:41:39.343913Z    10 Query INSERT INTO `time2` (`id`, `time`) VALUES ('BUN Asia/Tokyo 2019-01-02T03:04:05', '2019-01-02 03:04:05')

どうやらこれは意図的な変更の結果らしい。mysqlやgo-mysql-driverなどと二重変換してしまって正常に動作しないという問題があったようだ(←わかってない)。

https://github.com/uptrace/bun/issues/168

とにかく、じゃあどうやれば安心してDATETIMEを扱えるんだよという話になるんだけど、mysqlとまたがる範囲で暗黙的な変換が入ると状態の把握が難しくなるので、goのアプリケーション側で確実にUTCにしちゃってからORMなりクエリビルダーなりに放り込むことにした。そうすれば少なくともバグったときにfmt.Printfでなんとかなる。

goとmysqlの間で苦しんでる人はたくさんいた(類似記事が多い)がbunの話してる人は全然いなかったのでテキトーに書いてみた。

おまけ dockerのmysqlでgeneral_logを見る

適当なファイルに以下を書いておいて

[mysqld]
general_log=1

そのファイルが入ったディレクトリを、コンテナの/etc/mysql/conf.dにマウントする

-v /path/to/cnf-dir/:/etc/mysql/conf.d

コンテナ起動後にコンテナに入ってファイルの場所を探してtailする

nerdctl exec -it <container_id> /bin/sh
mysql -u root --host 127.0.0.1 -p
> SHOW VARIABLES LIKE '%general_log%';
> exit;
tail /path/to/general.log

なんで general_log_file 使わないの?

なんか general_log_file=/var/log/mysql/general.log するとmysqlの設定値はそこになるんだけどファイルが作られないんだよね。パーミッションの問題とかあるのかな。

上記の方法でやるとログファイルは /var/lib/mysql/hoge.log に生える。

Ubuntu 23.04への式年遷宮 トラブル録

普段はLTSしか使わないのだが、なんかやりたい気持ちになったので珍しく奇数系を入れてみた。

https://www.ubuntulinux.jp/News/ubuntu2304-ja-remix

をUSBメモリに焼いて(今はUbuntu公式でもEtcher使えって書いてるんですね、昔はUbuntuにUbuntuのイメージを焼くためのソフトウェアが付属していた気がするが)、PC再起動。

インストールの手順については、特に変化はなさそう。今回はLVM使用、ディスク暗号化をつけてみた。

gnome-text-editorで日本語入力できない

毎度の鬼門(と言いつつ、熱心な日本Ubuntuユーザーが結構情報を残してくれているので言うほどではない)。こちらのページが参考になった。

https://www.kkaneko.jp/tools/server/gnome_ja_input_method.html

注意点として、23.04では(正確には22.10から)はgeditに代わってgnome-text-editorというソフトウェアが入っている。こいつがfcitxとの相性が悪いのか、日本語変換が一切効かない(日本語入力モードに入れない)。シェルから開いてみるとこんなエラーメッセージが残されていた。

(gnome-text-editor:9858): Gtk-WARNING **: 03:13:56.134: No IM module matching GTK_IM_MODULE=fcitx found

意味はよくわからないのだが、fcitxを使えと言われているがgnome-text-editorがそれを理解できていないように見える。実際にはgnome-text-editorのリポジトリにこのようなエラーメッセージはなさそうなので、GTK自体に何らかの問題があるのかもしれない。

20230507追記

fcitxじゃなくてfcitx5を入れると問題が起きなかった。

vscodeで日本語入力時に確定するまで文字が表示されない

確定するまでは変換ボックスを見ないと入力中の文字が確認できず、Enterで確定すると一気にエディタ上に文字が追加される状態になった。これはUbuntu Softwareからデフォルトのsnapで入れていたのが悪いので、消してdebで入れ直したら直った。

bluetoothヘッドホンで音が鳴らない・途切れる・汚い

Linuxでbluetoothヘッドホンを使うのはコツがいる。僕が使ってるのはWH-1000XM4ね。

まず音が途切れるのはドライバのバッファリングが下手くそなせいなので、pavucontrol→出力デバイス→WH-1000XM4→高度な設定でLatency offsetを10msくらいにしてやる。ほんの少しでも設定してやるといい感じになる。

音が汚いのはコーデックがHSPになっているから。bluetoothヘッドホンの通信コーデックにはA2DPとHSPがあり、前者は聞く専用で高音質、後者はヘッドホンの付属マイクからの音声入力も可能だが音質は悪い。なのでA2DPに設定してやることで解決(これはbluemanからでも標準のbluetooth設定からでも、たぶんCLIからでもできる)。

音が鳴らないのは今回初めて遭遇した。HSPでの接続は可能だったがA2DPが選べなかったり、A2DPにすると音が鳴らなくなったりした。これは理由が不明だが、ペアリング直後にbluemanからA2DPに設定してやることで解決した。

ストレージデバイスのマウント

今回はなるべくGUIでやっちゃうのを目標にした。普段はストレージデバイスのマウントは/etc/fstabを手で編集してやっているが、今回は「ディスク」から。デバイス→パーティションを選択して、歯車マークのメニューから「マウントオプションを編集」でGUIからマウントを設定できる。ここで設定した内容がfstabに書き込まれていた。

やはり奇数系のUbuntuを使うのはエキサイティングだ。時間のあるときに限るが、楽しいんだこれが。