Tech

GoでSMF(MIDI)ファイルを読み込んでみた

投稿日:

はじめに

私の最近の趣味はDTMで、時々曲を作っているのですが、単に曲を作るだけでなく、その打ち込みデータを他のこともにも活用できないかと考えました。そこで、DTMで作成したMIDIデータをGoで読み込み、演奏情報を読み込み、音符情報に変換する部分をコードで書いてみました。

MIDIとは?

MIDIとは、電子楽器の演奏データを、機器間で転送するための規格です。例えば、MIDIキーボードでの演奏(INPUT)に対応して、音源から音を鳴らす(OUTPUT)ために、INPUT側の機器からOUTPUT側の機器にリアルタイムにデータを転送するための規格です。(実際には、INPUTがシーケンサであったり、OUTPUTが楽器以外にも照明機器など、さまざまなシーンで使用されています))
このMIDIデータをファイルに記録し、後から再生したり、楽譜として表示したりするための規格の1つにSMF(Standard Midi File)があります。今回はこのSMFを読み込んで、音符の情報に変換したいと思います。

SMFファイルについて

SMFファイルは、ヘッダチャンクとトラックチャンクという2つのチャンクから構成されています。ヘッダチャンクにはSMFファイル全体に関する内容が、トラックチャンクには演奏情報が含まれています。
詳しくは、こちらのサイトに詳しく解説されているのですが、最低限紹介しておきたい内容をピックアップします。

Tickと分解能

SMFでは、音の長さの最小単位がTickとなります。Tickの実際の音価(音の長さ)は、分解能によって決まります。分解能は、MIDIのヘッダ部に含まれていて、四分音符が何Tickで表されるかを示す数値です。分解能が細かければ細かいほど、きめ細かい間隔で音符を並べることができます。
例えば、分解能が1だと、四分音符=1となるため、4分音符より短い音符を置くことができません。通常や32分音符や、16分3連符など、より細かい音符を使うと思うので、分解能は480となっているシーケンサが多いようです。
(四分音符あたりの分解能を指定する他に、タイムコードによって分解能を決めることもできますが、ここでの説明は省略します。)

トラックチャンク

トラックチャンクには、演奏データが含まれます。今回は、音符に変換するにあたって必要な点のみ紹介します。

フィールド名 意味
Delta 480 tick 480 tick 待つ
Event ノートオン | キー番号: 72 | ベロシティ: 127 キー番号72 (真ん中のド) をベロシティ127で鳴らす
Delta 480 tick 480 tick 待つ
Event ノートオフ | キー番号: 72 キー番号72 (真ん中のド) を止める
・・・

上記のように、DeltaとEventを繰り返しながら演奏データが格納されていきます。EventはMIDIイベントのことで、今回はノートオンとノートオフのみを扱います。ちなみに、音を止めるために、ノートオンでベロシティ0と記録される場合もあるため、その場合でも音が止まったものとみなす必要があります。

gomidiを使ってSMFファイルを読み込む

それでは、実際にSMFファイルを読み込みたいと思います。

gomidiの導入

MIDIやSMFを扱うことができるgoのパッケージはいくつかあるのですが、その中でも最近もメンテナンスされているパッケージがgomidiです。

Gitlab:
https://gitlab.com/gomidi/midi

Documentation:
https://pkg.go.dev/gitlab.com/gomidi/midi/v2

以下のコマンドでgomidiを追加します。

実装

まずはソースの全景です。
今回は、SMFファイルの音符データを扱いやすくするために、音を鳴らすタイミング、音の長さ、キー、ベロシティをまとめたNote structを生成していきます。

このソースコードについて説明します。

  1. SMFファイルの読み込み
    SMFファイルを読み込むと、 SMF 型のインスタンスが取得できます。この中には、先ほど説明したヘッダチャンクとトラックチャンクに該当するフィールドを持っています。
  2. 分解能の取得 (ヘッダチャンク)
    分解能は1で取得したSMF内のtimeFormatフィールドで取得できます。こちらも先ほど説明した通り、四分音符あたりの分解能か、タイムコードによる分解能のどちらかの指定が入るため、それぞれに対応したMetricTicks型かTimeCode型のいずれかが入ります。
    いずれの型もTimeForma型を実装しているのですが、今回使用したいメソッドはMetricTicks型にしか実装されていなかったため、キャストしています。
  3. トラック1の読み込み (トラックチャンク)
    演奏データを読み込みます。(今回はトラック1のみにデータが入っています。)
    トラック0には、テンポや拍子など、全トラックに影響するデータが入っていて、実際の演奏情報はトラック1以降に入っています。
  4. MIDIイベントを順番に取得
    3で取得したトラックをforループで回すことで、イベントを取得します。
  5. 絶対時間の記録
    SMFファイル内には絶対時間は存在せず、イベント間のDeltaTime(経過時間)でのみ時間経過が表されているため、DeltaTimeを加算していくことで、絶対時間を保持します。
  6. メッセージによる分岐
    音の鳴り始めと鳴り終わりを取得するため、メッセージにより分岐しています。

    • ev.Message.GetNoteStart(&channel, &key, &velocity) は、メッセージがベロシティ1以上のノートオンメッセージである場合はtrueを返し、そうでなければfalseを返します。引数に与えられたポインタにメッセージの値を代入します。
      ノートオンの場合、Noteを生成して、startedNotesに一旦appendしておきます。
    • ev.Message.GetNoteEnd(&channel, &key) は、メッセージがノートオフメッセージ、もしくはベロシティ0のノートオンメッセージである場合はtrueを返し、そうでなければfalseを返します。引数に与えられたポインタに、メッセージの値を代入します。
      このメッセージである場合は、startedNotesから同じキーのNoteを探し、見つかった場合はその音の鳴り終わりとして、音の長さを代入し、notes配列にappendします。
  7. notesの出力
    ここで、 ticks.In64ths(v.Value) によって、Valueが実際に64分音符が何個分であるか取得しています。このメソッドの中身は次のようになっています。

    64分音符は、4分音符の1/16の長さです。
    仮に、分解能(q)が1だったとして計算してみると、16がreturnされます。

さいごに

gomidiを使うと、SMFファイルがパースされ、MIDIメッセージを取り出せることが分かりました。今のところメンテナンスもされているので、おすすめです!

おすすめ書籍

実用 Go言語 ―システム開発の現場で知っておきたいアドバイス エキスパートたちのGo言語 一流のコードから応用力を学ぶ Software Design plus 詳解Go言語Webアプリケーション開発

blog-page_footer_336




blog-page_footer_336




-Tech
-, ,

執筆者:


comment

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA


関連記事

Sign in with Appleの実装

1 はじめに2 Sign in with Appleとは2.1 iOS レビューガイドライン2.2 つまり3 準備4 実装5 デザイン6 さいごに7 おすすめ書籍 はじめに こんにちは、nukkyです ...

入門スクラム〜スクラムフレームワーク

1 はじめに2 スクラムの特徴2.1 シンプルなフレームワークであること2.2 素早い反復を繰り返すこと2.3 検査・適応・透明性3 スクラムの役割3.1 プロダクトオーナー3.2 スクラムマスター3 ...

ReactNative開発のスタート、シミュレータでのデバッグ

1 はじめに2 改めてシミュレータの起動3 表示内容を変更してみる3.1 App.js3.2 表示テキストの変更3.3 シミュレータの更新「command + R」4 デバッグメニュー4.1 Real ...

Bluetooth Low Energy(BLE)とは? Bluetoothの開発が初めての人向け!

1 はじめに2 Bluetoothの規格2.1 Bluetooth Classic2.2 BLE(Bluetooth Low Energy)3 BLEの役割4 サービスとキャラクタリスティック4.1 ...

ReactNative環境構築[Android/iOS]

1 はじめに2 準備2.1 HomeBrewをインストール2.2 node.jsのインストール2.3 Watchmanのインストール2.4 React Native CLIのインストール2.5 サンプ ...

フォロー

blog-page_side_responsive

2022年11月
 12345
6789101112
13141516171819
20212223242526
27282930  

アプリ情報

私たちは無料アプリもリリースしています、ぜひご覧ください。 下記のアイコンから無料でダウンロードできます。