2026年2月13日金曜日

MPE (MIDI Polyphonic Expression) に対応した グリッド型 MIDI コントローラー Celltone、Isotone を作った

MPE (MIDI Polyphonic Expression) に対応した グリッド型 MIDI コントローラー CelltoneIsotone を作りました。 演奏しやすい配列で 2つアプリを作りました。 ついでに以前作った 4x4pad も MPE に対応させておきました。



タブレットで手軽に遊べる楽器アプリの配列を考えているとき、 いまさらながら MPE (MIDI Polyphonic Expression) を知りました。 知らなかったんかい、というレベルの話ですが…。 MPE はピッチベンドや音量をノート単位で管理して、表現力を高めることができます。 MIDI 2.0 を使うと MPE がなくても同様の仕組みを実現でき、同時打鍵数の制約がなくなります。 ただファイルサイズが大きくなる問題や、現状では拡張子が不安定な問題などがあります。 MPE は MIDI 1.0 の延長線上で作れるので、現状では MPE のほうが安定しそうです。 ちなみに MPE の実装を MIDI 2.0 に拡張するのは簡単そうです。ID をイベントに付与するだけかな。 Midy では MPE をサポートしていないかったので、実装してみました。

ただ MPE って音量の標準的な扱いがいまいちわからないんですよね。仕様的には Channel Pressure を想定しているのかな。 でも Channel Pressure は色々なエフェクトを盛り合わせにできるから、エフェクトを追加したい時にむしろ困る気がするんだよなあ。 私は CC11 で音量を調整しています。規約違反というほどではないし、いつでも実装は変えられるから、まあ良いかなと。 (本当はリリース後に「一応 Channel Pressure にしとくか」と思いつつ直すのを忘れていたことに気付きました。 いまのバージョンでも実害は何もなく、また Channel Pressure のほうに小ミスがあるように感じたので、次リリースでは直すかも知れません)。 Midy もだいぶ成長して、新しい仕様にサクッと追随できるくらいになってきました。

MPE を考慮した配列も同時に再検討しました。 ボタンを押す位置がすごく重要になるので、演奏は割と難しい気がします。 まずは指の位置でボリュームを変えられると良いのはすぐわかります。 また隣の鍵盤に触れたとき次の音を出せると嬉しいでしょう。 前は noteOn で処理していましたが、表現力を高くするには鍵盤の概念をもっと緩くして、 隣り合う鍵盤に近づいたときはピッチベンドで変化させると良いのでしょう。 このピッチベンドを主体に考えると、グリッサンドに強い配列が良いことになります。 ピアノ型の UI は縦方向の動きを音量、横方向をピッチベンドと考えると 操作しやすいかと思ったのですが、実際の製品を見るとすべてピッチベンドで実装してそう。 一番欲しいのは鍵盤ごとの音量調整かと思っていたけど、そうでもないのかな。 クロマトーン型の UI だとボタンごとの境界で距離に応じたピッチベンド、 ファーストタッチの位置で音量設定ができます。 縦方向に移動するときは横方向を音量に、横方向に移動するときは縦方向を音量にします。 アフタータッチで音量を変えにくいのは若干課題ですが、 タッチ位置を変えつつ連続タッチすれば一応は大丈夫そうかな。

配列に関しては、既存のものだと Janko-Piano がグリッサンドにまあまあ強くて良さそうです。 Celltone は Janko-Piano の配列を応用しています。これは普通のピアノとほとんど一緒なので演奏しやすいです。 Isotone は Janko-Piano が 2x6 なのに対して、3x4 に変更したらどうなるのだろうかと試行錯誤して作った配列です。 音程変化ボタンが増えすぎてしまうのが難点ですが…。ペダル用のボタンにしたりしても良いのかも知れませんね。 Isotone はタブレットのように 2本指で扱うことをメインに考えると、割と演奏しやすいです。 和音が非常に押しやすい配列になっており、指の数を増やしにくいタブレットではかなり有力だと思っています。 他にも様々な UI を既に考えてあるので今後作っていきます。

UI に関してはボタンとボタンの間に空間を用意しました。 空間部に触れながら指をスライドさせたときピッチベンドと音量変更が同時に変更できます。 まずはこの空間には gap を用意することでボタンとの違いを明示するようにしました。 gap がある程度大きくないとピッチベンドが効きすぎて音量だけ変更したいニーズに対応できないので、 一般的な MIDI コントローラーよりすこし空間を大きく設定しています。 ちなみにすべての場所でピッチベンドと音量変更が動いてしまうと、 音が変化しすぎて不便なだけなので、ボタンの中をスライドしても変化しません。 UI としてはこれ以上簡単にするのは難しいと思う。 感圧式タッチパネルなら音量を設定しやすいけど、ハードが高いので専用機器以外で主流になることはもうないでしょう。

ROLI Seaboard の初期発売は 2015年で、後続製品は今も MPE デバイスで一番面白そうに見えます。 現行製品と対等のアプリを作れるようになってきて、ようやく少し追いつけてきた感じ。 タブレットで実現できたことで、10万円近く掛かるデバイスを無料で遊べるようになりました。

2026年1月13日火曜日

手軽に遊べる楽器アプリ 4x4pad を作った

小中学生が遊べる楽器アプリを作りたいと思いました。 MIDI を使えば 200種類以上の楽器に強弱を付けて再生ができます。 タブレットでピアノの形状を模倣しても使いにくいので、もっとシンプルなものが必要です。 そこで実験的に作ってみたのが 4x4pad です。 4x4pad を使うと、子供向けの楽曲なら私でも簡単に演奏することができました。 なかなか良い。



作ってみて思ったのですが、昔は iOS に 3D Touch があったので pressure が得られたのですが、 今は廃止され pressure は常に 0 を返却します。Android も筆圧センサー搭載モデルは少ない。 同じようなことをするには width/height から pressure を推定するくらいしかないですが、 これは不安定で事実上使い物になりません。 最近は pressure を使ったアプリを作っていなかったので、今さら気付きました。 3D Touch を考慮した実装は入れてありますが、使えるデバイスは少ないのが不満です。 タブレットの楽器アプリは色々限界あるなあと思いました。 まあ昔から音ゲーを作るなどの用途でも様々な障害があってタブレットには苦労してきましたが…。

そんな訳で音の強弱は設定の Expression くらいでしか付けられませんが、 色々な音を出して合奏するには適したアプリになっていると思います。 ただボタンを配置するだけではなく、1つの指で複数のボタンを押せるようにしてあるので、和音が作りやすいですし、指を動かすだけでスムーズに音が鳴ります。 今回は MIDI コントローラーでよく使われる 4x4 グリッドを利用して作ってみましたが、 本当はもっと色々な配列を考えています。 いくつか楽器アプリを作ってみるつもりなので、そのうち配列などについての考察記事を投稿します。

4x4 グリッドの MIDI コントローラーは山ほどありますが、 どれも設定が必要で面倒臭すぎるので、設定なしで使える UI にしているのも、他と少し違うところです。 といっても MIDI コントローラーで遊んだことはなくて説明書などを見ながら言っているので、間違ってたらすまん。 選択しているドラムをグリッドに表示したりするともっとユーザーフレンドリーかなあ。

2025年12月14日日曜日

Web 上で使える Timidity++ っぽい MIDI プレイヤーを作った

Timidity++ っぽい MIDI プレイヤーを作りました。 前回に引き続き、Midy の機能確認やバグ潰しが目的で作ったアプリですが、 割と人気の UI ではあるので使い道もあるかも知れません。 本当は紹介のためにスクリーンレコーダーで録画してみたのですが、 Web Audio API がうまく録音できなかったです。音なしだと面白くないので動画は特になし。



私も割と好きな UI ですが Velocity は鍵盤の色で表現するほうが良いと思っていたので、 64〜191 の間で色を調整して表示しました。これだけでだいぶコンパクトにできます。 それ以外は Timidity++ とだいたい同じですが、簡易的なミキサーアプリとしても使えるようにしています。 スライダーがありきたり過ぎるので改良しようかとも思ったのですが…、 面倒すぎてデフォになりました。スライダーは弄ろうとするとなかなか大変です。

実装では鍵盤をどう光らせるかで多少悩みました。 Web Audio API でやろうとすると、ended event はありますが、started event がないので、意外と難しいです。 AudioBufferSource.start() と同じタイミングで動くようにタイマーを設定すると、 タイマーの数が 2倍になってしまって速度の問題が出てきてしまいます。 Web Audio API を使ったタイマーだと負荷が大きくなってしまうので、 requestAnimationFrame() で描画タイミングと同期しながら、 noteOn などの時間を監視して光らせるのがおそらく一番効率が良いです。 鍵盤を光らせるには Midy 内部で処理するイベントのタイムラインを見ながら処理します。

Midy の再生開始判定と、@marmooo/midi-player の判定は微妙に違っています。 @marmooo/midi-player は再生ボタンを押したときにサウンドフォントの読み込みもします。 このへんの処理をどうすれば楽にできるかを考えていて少しだけハマったので、 再生ボタンを押したときから isPlaying = true な変数を持つように実装を加えたところ、 割と簡単に GUI 拡張を作れるようになりました。 GUI 側でも isPlaying の状態を持つことで、再生の終了判定も容易になりました。 最近の Chrome は AudioContext をつけっぱなしにすると CPU をかなり消費するようになったので、こまめに AudioContext を ON/OFF しています。 Chrome の AudioContext の CPU 負荷はバグとしか思えないので、 そのうち直っているかも知れませんが。

最後に鍵盤を鳴らす実装をしていると、グリッサンドに耐えられない問題が発生しました。 事前にすべてをキャッシュするのも手と思ったのですが、 keyRange/velRange と 2つパラメーターがあるのでちょっとメモリが心配です。 そこで await で音声波形をデコードする前にスケジューリング配列に追加してしまうことで、 問題なく再生できるとわかりました。 ただこれだけだと処理時間が少ないことで運良く実行できているだけだと思うので、 スケジューリング配列に登録するとき note に pending 状態を付けて、 pending 中に noteOff が発生したときは、noteOn の処理内で noteOff も実行するようにしました。 これならリアルタイムな割り込みが発生しても問題なく処理できるはずです。

ここまでの実装で Timidy は動くようになったので公開としましたが、色々と余地はあります。 例えば midy 0.4.0 の noteOn は、SF2 modulation に渡す状態配列や noteOff と整合性を保つために await を付けて処理していますが、波形のデコードが 〜50ms で、 状態配列 (256 x 32bit = 1KB) のコピーが 〜0.02ms であることから、 noteOn から noteOff までの間に状態配列と SF2 modulation に変化がなければ、 await せず状態をコピーしながら処理でき、Worker で並列処理で高速化可能のはずです。 面倒そうだけど並列処理すればグリッサンドに対してより頑強になるはずです。 これもそのうち検証しようとは思いますが、まずはイベント数を減らすほうが確実とは思います。

2025年11月25日火曜日

GM2 MIDIミキサー Humidy を作った

MIDI Player/Synthesizer ライブラリ Midy の実装がだいぶ進んできて、 GM2 の再生も安定してできるようになってきました。 まだ細かい実装不足やバグ、再生負荷の課題はあると思うのですが、そろそろ実用段階に入ってきています。 そこでバグ潰しも兼ねて、GM2 の機能をすべて使える MIDI Mixer アプリ Humidy を作ってみました。



GM2 は仕様がかなり大きいので、機能をすべて使ったアプリとか見たことないんですが、実際のところどうなんでしょう。 ちなみにすべての機能を本気で使おうとすると UI が複雑になり過ぎるので省略している箇所はありますが、ライブラリからはもちろんすべて使えます。 なるべくシンプルに作ったつもりですが、複雑な機能は簡単な UI にはしにくいので、 普段は表示しないように押し込み、設定項目も無理やり減らしています。

名前は Timidity++ のもとになった英単語で timidity があって、 同じように midi が出現するもう一つの英単語として humidity があるので、 humidity と Midy をもじって Humidy としました。

Midy は自分に合わせて作っているので作りやすいのは当たり前とはいえ、 かなり短いコードで音楽ミキサーアプリを作ることができました。なかなかいい感じ。 動的サウンドフォント、動的 fetch プログラムチェンジ、GM2 なども動くようになったので、いよいよライブラリとしても完成度が高まってきました。 もう少し高速化したらすべての MIDI ライブラリは Midy に移行できそう。 速度も激ヤバ MIDI 以外なら問題になることはないので、もう実用レベルと思います。 激ヤバ MIDI は瞬間的なイベント数の負荷がブラウザの限界に達して死ぬので、イベント数を減らす処理をこれから入れていきます。

MIDI はサウンドフォント周りをもっと設定できたら面白そうなので、 もう少し色々改良したいなと思っています。個人的に気になるのはリバーブです。 MIDI はサウンドフォントで Reverb Effects Send を決め打ちしますが、 そこで決め打ちすると楽器によってはリバーブ効果がわからなくなります。 現実のリバーブは Reverb Effects Send のように楽器によって効果が決まるのではなく、 周波数に応じてリバーブの効果が変わる (低音ほど消える) はずなので、 音響理論で考えると微妙な気もして、設定できたほうが嬉しい機会もあると思いました。 開発者以外でこれに悩む人はいるのかという疑問はありますが、 MIDI プレイヤーをゼロから実装していると、こういう細かいところが気になってきます。

バグ潰しのために、さらに何種類かアプリを作ってみる予定です。

2025年10月2日木曜日

中学理科一問一答・中学社会一問一答を作った

中学理科一問一答と中学社会一問一答を作りました。 きちんと教科書を使って作っているので、教科書準拠の重要語句を手軽にチェックできます。 苦手分析もしっかりできるので、学校・塾・家庭でも使いやすいんじゃないかな。 中学理科は計算問題を含めていないので語句・公式の確認に使えるくらいですが、それだけでも多くの人に使い道があると思います。 四択問題で簡単なので、正答率は8割以上が目安なんじゃないかな。 間違った問題は復習が必要です。



重要語句の意味や事実は静的なので、AI 生成することで作ってみました。 穴埋め問題は AI が最も得意とする分野なので、精度も非常に高いことが期待できます。 とはいえ融通が効かず 10分前に話した内容をすぐ忘れる AI さんに作ってもらうのは大変でした。 それでも人間が作るより 100倍くらいはコストが低いと思いますし、 100倍楽なのだから頑張ろうと思って作りました。 いかに安定して生成させるか、いかに質を安定させるか、 いかに選択問題として使えるようにするか、いかにメンテできるようにするかが重要になります。 AI さんの知識量は凄いですが、行動は物忘れが激しいため細かい指定をしても守ってくれません。 テストをきちんと書くことが大切だなと思いました。 結構色々なチェックをしているので、問題がクソなケース以外はかなり除外できていると思います。 問題がクソかどうかはたくさんプレイしてみてわかることなので完璧は難しいですが、 ある程度は自分でもプレイしてみて確認はしています。 このへんの開発の手間具合は、1年経ったらまた状況は違うんでしょうが、現状は AI があってもやはり大変です。

アプリとして公開できるようにするためには、かなりチェックが必要でしたが、 それでも一度作ってしまえば、メンテコストは低いし、生成コストも、チェックのコストも低いのが良いところです。 違う問題を作ってと言えば、他の問題も作れます。 人間にこれをやらせると、個人開発では絶対無理だし、集団でもとんでもなく時間が掛かります。 人間や過去問をベースとして作るよりAI で作ったほうが、一般性も網羅性も高くなる利点はあるので、結構良い AI の利用例かなと思います。 ただ社会はかなり安定して問題を作れる一方で、 理科は AI さんも知識不足な気がするので、問題はだいぶ自作しました。 社会は割と安定して出力できるものの、やはり致命的なミスがたまにあったりするので、日頃の確認が必要です。

近年は高校受験や大学受験の問題を見ても、一問一答そのものが問題として出てくる機会はなくなっていますが、 知識確認には依然として有用です。 問題を解いた後に、どれくらい他のことを言えるか考えてみたり、使い道はたくさんあります。 人気の問題集とかを見ても、結局は一問一答の延長線である問題のほうが多いので、 実質的にはみんな今も使っている状態と思います。

そういえば AI で作れるよなー、くらいの気持ちで作ってみましたが、なかなか良いんじゃないかと思います。 他のアプリもまったく確認せず作り始めたのですが、いくつかはあるみたいですね。 まあ AI 生成ドリルとか、塾用のとか色々あるもんな。 でもなんというかすぐに使えるものはなかなかないし、実際欲しいのはすぐ使えるものなので、まあ良いかなという気持ちです。 今のところ中学社会一問一答・中学理科一問一答という名前にしていますが、 今後の実装レベルによっては名前を変えるかも知れません。

2025年9月7日日曜日

謎のエフェクトライブラリ emoji-particle を作った

謎のエフェクトライブラリ emoji-particle を作りました。 イメージ図のように、絵文字で花火を打ち上げたり、ポップコーンっぽいエフェクトを表示できるライブラリです。 柔軟なエフェクト設定ができるため様々な用途に応用できます。


Demo でおおまかな動作を確認できますし、 marmooo/emoji-particle から MIT ライセンスでコードを利用できます。

fontconv

前からずっと似たようなものは欲しかったのですが、 真面目に実装すると大変で放置していたのですが、 既存アプリが増えてきていよいよ欲しくなってきたので作りました。 Web Worker + OffscreenCanvas + 効率的な更新処理で実装しているので、 無駄に高速・高機能なライブラリとなっています。 内部の実装もかなり色々な最適化をしているので、大量に絵文字を飛ばしても重いと感じることはほぼないでしょう。

Worker を使ったライブラリを何も考えずに公開すると同一ドメインの制約があって使いにくいので、 インライン化することで簡単に使えるようにしています。 import { createWorker } from "emoji-particle"; するだけで使えるようになっています。 Worker 系のライブラリだとあるあるなんでしょうが、ビルドはみんなどうしてるんでしょう。 私はもちろん esbuild でオレオレビルドです。

こういったエフェクトは、良いものを作ろうとすると画像が必要ですが、 たくさん画像を使い始めると取り扱いが急に面倒になります。 RPG ツクールのホコグラっぽく管理すれば多少は…とは思うのですが、そういうことを考えるのも嫌です。 画像を扱い出すとと、ファイルサイズも大きくなるし、画像ファイルの管理も面倒だし、 ライブラリのロードも面倒になります。 絵文字はどんな環境でも使えるカラフルな画像集なので、 このようなときに最も扱いやすいです。

シンプルな割にはあらゆる場面で使えて便利なライブラリだと思っています。 これまで作ったアプリたちにもこれから組み込んでいきます。 それっぽいエフェクトを付けたい時には最も重宝するライブラリになりそう。

2025年8月26日火曜日

頻出順の英和辞書 mGSL を更新した

頻出順の英和辞書 mGSL を更新しました。 以前開発した mGSL は頻出順データ自体は最強でしたが、 既存の辞書を利用しているため和訳の粒度にバラツキがあり、英和辞書としては不安定でした。

mGSL

そこで生成 AI を活用して簡易的な和訳を作り、最強の和英辞書に作り変えました。 生成 AI を使って詳細な辞書を作るのはかなり苦しいと思いますが、 英単語学習では典型的な意味表現のみを知っていれば十分です。 なるべく覚える言葉自体が少なくなるように和訳の粒度を調整した辞書として mGSL を更新しました。 このような用途では生成 AI による文章生成が極めて有効です。 とはいえ既存の辞書データでさえ 3万語あったので、すぐにはできません。 AI の生成は頻繁に壊れるので完全には自動化できないため、 サボれる時間を見つけてちまちまと文章生成を繰り返すことで構築しました。

まずは既存の辞書に登録されていた 3万語まで和訳を付けました。 しかし既存の辞書のデータは頻度データをきちんと考慮していないので、 実際には頻度7000語くらいまでしか安定して登録されていません。 それ以降は歯抜けが多いので、ちまちまと翻訳を作っていく必要があります。 lemmatization されたデータは 6万件あります。 厳密な頻度で 3万語に到達する頃には、3万5000語くらいになってそうです。 これはさすがに果てしない…ということで、頻度 1万語までは完璧なものにしてこの記事を書きました。 それ以上はニーズの低さからやる気があまり出ないですが、ぼちぼちやりたいところ。 1万語あれば海外の大学生くらいの語彙数になるので、たいていのニーズは満たせるでしょう…。

生成された訳は目視で気になる点はチェックしており、 機械的に処理できるようにフォーマットを整えたりしています。 訳が不安定なところも微修正しています。 ドイツ語やイタリア語など、英語以外の語彙も含まれているので、英語学習には不向きなものも多々あります。 これらは機械的に除外できるようにしました。 AI さんに頼んでもすぐ崩壊するのでこのへんは手動で直すしかありません。 手動は手間ですが、和訳を作る部分が一番時間が掛かるので、90% は時間を削減できているでしょう。 それでも結構な時間は掛かりました。単調すぎて眠いのが地味に厳しかった。 ただその甲斐もあってか、以前は見つからなかったアラも多少修正できました。 依存ライブラリをがっつり減らすことができて、だいぶ気楽になりました。

英単語学習の辞書データとしては、より詳細なものを作る以外だと、 これ以上のものを作るのは難しいんじゃないかな。 あるとしたら lemmatization をちょっと改良できるくらい。これはいずれ検証したい。 あとはいよいよ接尾辞や現在分詞、過去分詞をもっと考慮して語彙数を減らしていくほうが、辞書としては質が高くなるのかもなあ。

Vocabee など既存の英単語アプリ、 graded-enja-corpus などの派生ライブラリには反映済みですが、 新規アプリも今後作っていきます。 やはり和訳の粒度を調整できているのはあまりにも大きい。 以前と変わらず CC-BY-SA で使えるので、使いたい人はどうぞ。