Magenta Music RNN を試してみる

### はじめに
近頃、楽曲生成に興味が湧いてきたため、第一歩としてMagentaを使用したドラム生成で遊んでみようと思います。

### Demo
こちらは、デモにあったコードを修正して試しに作ってみたデモになります。
区切り線より左側は、Userが入力し、それを元にMusicRNNのdrum_kitモデルを使用して続きを作成します。

https://mukaigawara.github.io/neural-drum-machine/src/

### Magentaとは？
https://magenta.tensorflow.org/
> An open source research project exploring the role of machine learning as a tool in the creative process.

Googleが出している、音楽などの機械学習プロジェクトのようです。

動かして見たかったので調べたところ、jsのライブラリがあり、web上で簡単に動かせそうだったので今回はこれを使ってみます。

https://github.com/magenta/magenta-js/tree/master/music

### RNNによる生成部分
```js
let rnn = new mm.MusicRNN(
  "https://storage.googleapis.com/download.magenta.tensorflow.org/tfjs_checkpoints/music_rnn/drum_kit_rnn"
);
```
まず、MusicRNNでどのモデルを使うか指定します。今回は`drum_kit_rnn`というドラムのモデルを使います。

```js
  /** パターンを生成 */
  function generatePattern(seed, length) {
    // シードをnoteSequenceに変換
    let seedSeq = toNoteSequence(seed);

    // RNNモデルを使ってシードから新しいシーケンスを生成
    return rnn
      .continueSequence(seedSeq, length, temperature)
      .then((r) => seed.concat(fromNoteSequence(r, length)));
  }
```
こちらが、実際にユーザーの入力したシード(Demoの赤い部分)から続きを作成する実装になります。
`rnn.continueSequence`はsequenceからその続きを生成してくれそうです。

https://github.com/magenta/magenta-js/blob/96bad8837da43beb53f2e5aaea9f29f3db4bdddb/music/src/music_rnn/model.ts#L198C3-L218C4

そのsequenceを入れるために、ユーザーからの入力であるseedをsequenceに変換する必要ありそうです。`toNoteSequence()`は以下のようになっており、`mm.sequences.quantizeNoteSequence()`を使用しています。

```js
  function toNoteSequence(pattern) {
    // パターンをノートシーケンスに変換
    return mm.sequences.quantizeNoteSequence(
      {
        // 1クォーターあたりのティック数を設定
        ticksPerQuarter: 220,
        // パターンの全体時間を設定（パターンの長さを2で割る）
        totalTime: pattern.length / 2,
        // 拍子記号を設定（4/4拍子）
        timeSignatures: [
          {
            time: 0,
            numerator: 4,
            denominator: 4,
          },
        ],
        // テンポを設定（120 BPM）
        tempos: [
          {
            time: 0,
            qpm: 120,
          },
        ],
        // パターンの各ステップをノートに変換
        notes: _.flatMap(pattern, (step, index) =>
          step.map((d) => ({
            // ドラムのMIDIピッチを設定
            pitch: midiDrums[d],
            // ノートの開始時間を設定
            startTime: index * 0.5,
            // ノートの終了時間を設定
            endTime: (index + 1) * 0.5,
          }))
        ),
      },
      // 精度を設定?
      1
    );
  }
  ```
### そもそもNoteSequenceとは?
チュートリアルには以下のように記載がありました。
> Everything in @magenta/music is centered around NoteSequences. This is an abstract representation of a series of notes, each with different pitches, instruments and strike velocities, much like MIDI.
引用:https://hello-magenta.glitch.me/

MIDIのような形式であり、音符の音程、楽器、打鍵速度などを表現しているようです。

https://magenta.github.io/magenta-js/music/modules/_core_sequences_.html

サンプルとして以下のような形式になっています。
```js
DRUMS = {
  notes: [
    { pitch: 36, quantizedStartStep: 0, quantizedEndStep: 1, isDrum: true },
    { pitch: 38, quantizedStartStep: 0, quantizedEndStep: 1, isDrum: true },
    { pitch: 42, quantizedStartStep: 0, quantizedEndStep: 1, isDrum: true },
    { pitch: 46, quantizedStartStep: 0, quantizedEndStep: 1, isDrum: true },
    { pitch: 42, quantizedStartStep: 2, quantizedEndStep: 3, isDrum: true },
    { pitch: 42, quantizedStartStep: 3, quantizedEndStep: 4, isDrum: true },
    { pitch: 42, quantizedStartStep: 4, quantizedEndStep: 5, isDrum: true },
    { pitch: 50, quantizedStartStep: 4, quantizedEndStep: 5, isDrum: true },
    { pitch: 36, quantizedStartStep: 6, quantizedEndStep: 7, isDrum: true },
    { pitch: 38, quantizedStartStep: 6, quantizedEndStep: 7, isDrum: true },
    { pitch: 42, quantizedStartStep: 6, quantizedEndStep: 7, isDrum: true },
    { pitch: 45, quantizedStartStep: 6, quantizedEndStep: 7, isDrum: true },
    { pitch: 36, quantizedStartStep: 8, quantizedEndStep: 9, isDrum: true },
    { pitch: 42, quantizedStartStep: 8, quantizedEndStep: 9, isDrum: true },
    { pitch: 46, quantizedStartStep: 8, quantizedEndStep: 9, isDrum: true },
    { pitch: 42, quantizedStartStep: 10, quantizedEndStep: 11, isDrum: true },
    { pitch: 48, quantizedStartStep: 10, quantizedEndStep: 11, isDrum: true },
    { pitch: 50, quantizedStartStep: 10, quantizedEndStep: 11, isDrum: true },
  ],
  quantizationInfo: {stepsPerQuarter: 4},
  tempos: [{time: 0, qpm: 120}],
  totalQuantizedSteps: 11
};
```

### その他のモデル
今回はRNNというモデルを使用しましたが、他にも種類があるみたいです。

> @magenta/music has several Machine Learning models, each with different strengths:
> 
> - MusicRNN - you give it a NoteSequence, and it continues it in the style of your original NoteSequence.
> - MusicVAE - generates brand new NoteSequences or interpolates between two sequences.
> - Onsets and Frames -- transcribes piano audio
> 引用:https://hello-magenta.glitch.me/

### その他できること
様々なDemoがあり、これを見てる感じ、他にもいろいろなことができそうです。

https://magenta.tensorflow.org/demos

年末の暇つぶしネタとしてもっと触ってみるのも面白そうです。

### 関連する面白そうな記事
https://qiita.com/yuwewe/items/c318469644ff37399f7a

https://qiita.com/DaikiSuyama/items/f47f7588c556255a77ef

https://qiita.com/Masanori_Aisaka/items/15f3653c0dcd17c895e3

### 参考
https://codepen.io/teropa/pen/JLjXGK