3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

JavaScriptでMIDIからUTAUのUSTファイルへ雑に変換する

Last updated at Posted at 2020-06-17

語弊を承知でいうと、ボーカロイドみたいなツールのUTAU
.midiファイルからUTAUで使う.ustファイルへ歌詞付きで雑に変換しダウンロードする方法のおぼえがきです。

前提

  • create-react-appベースのReactアプリ
  • ES6準拠のJavaScript

tone.jsでMIDIのインポート

だいぶつよいMIDIライブラリのtone.jsを利用します。

インストール

yarn add @tonejs/midi

インポート

import { Midi } from '@tonejs/midi';

ボタンクリックでMIDIを取り込めるようにする

ここは読み飛ばしていただいても。

import React, { useState } from 'react';
import { Midi } from '@tonejs/midi';

const MidiPage = (props) => {
  const [midi, setMidi] = useState(false);
  // FileReaderでMIDIファイルをArrayBufferで読み込む
  const handleChangeFile = (e) => {
    const file = e.target.files[0];
    const reader = new FileReader();
    reader.readAsArrayBuffer(file);
    reader.onload = (e) => {
      const midiData = e.target.result;
      if (midiData) {
         // tone.jsで変換
         const midi = new Midi(midiData);
      // stateに入れておく
         setMidi(midi); 
      }
    };
    reader.onerror = (e) => {
      // ロード失敗
    };
  };
  return (
    <div>
      <input
        type="file"
        accept="audio/midi, audio/x-midi"
        onChange={handleChangeFile}
       />
    </div>
  );

USTファイルに変換する

tone.jsでインポートしたMIDIをUSTに変換できるようにする

tone.jsのMIDIからUSTに雑に変換します。
歌詞にも一応対応してみます。

const parseMidiToUST = (midi, lyric, trackIndex, ustOptions = {
  // USTファイルのオプション
  projectName: '(no title)',
  flags: '',
  outFile: '',
  voiceDir: '${DEFAULT}/',
  mode2: true,
}) => {
  const json = midi.toJSON();
  const header = json.header;
  // MIDIヘッダから拍子を取得
  const beats = Array.isArray(header.timeSignatures) && header.timeSignatures.length > 0 ? header.timeSignatures[0].timeSignature : [4,4];
  // MIDIヘッダからテンポを取得
  // テンポ情報がないMIDIファイルの場合、UTAU-Synth側で50000になり操作不能になるので、ない場合は120
  const tempo = header.tempos.length ? midi.header.tempos.slice(-1)[0].bpm : '120';
  // 使用するトラックを指定
  const track = json.tracks[trackIndex];
  return `
    [#VERSION]
    UST Version2.0
    Charset=UTF-8
    [#SETTING]
    TimeSignatures=(${beats[0]}/${beats[1]}/0),
    Tempo=${tempo}
    ProjectName=${ustOptions.projectName}
    OutFile=${ustOptions.outFile}
    VoiceDir=${ustOptions.voiceDir}
    Flags=${ustOptions.flags}
    Mode2=${ustOptions.mode2 ? 'True' : 'False'}
    ${track.notes.map((note, index, origin) => {
      return `
        [#${('0000' + index).slice(-4)}]
        Delta=${index === 0 ? note.ticks : note.ticks - origin[index - 1].ticks}
        Duration=${note.durationTicks}
        Length=${origin[index + 1] ? origin[index + 1].ticks - note.ticks : note.durationTicks}
        Lyric=${lyric[index] ? lyric[index] : ''}
        NoteNum=${note.midi}
        Velocity=${Math.floor(note.velocity) * 10000 / 100}
        StartPoint=0.00
        Intensity=100
        Modulation=0
        PBS=-40.0,0.0
        PBW=80.0
        Envelope=5.0,1.0,0.0,100.0,
        100.0,100.0,100.0,7.0,80.0,1.0,100.0,0.0,1.0,100.0,1.0,100.0
        VBR=0,0,0,0,0,0,0,0,0,0`;
    }).join('')}
  [#TRACKEND]`.replace(/^\s+/gm, ''); // Stringリテラルのインデントを削除
}

USTファイルをダウンロードできるようにする

ここは読み飛ばしていただいても。

import React, { useState } from 'react';

const parseMidiToUST = ...

const MidiPage = (props) => {
   const [midi, setMidi] = useState(false);
   // 適当な歌詞
   const [lyric, setLyric] = useState(['か','し','で','す','よ']);
   const handleDownloadUST = () => {
    const text = parseMidiToUST(midi, lyric, 0);
    const blob = new Blob([text], {
      type: 'text/plain;charset=utf-8',
    });
    const a = document.createElement('a');
    a.download = 'score.ust';
    a.href = URL.createObjectURL(blob);
    a.click();
  };
  return (
    <div>
      <input
        type="file"
        accept="audio/midi, audio/x-midi"
        onChange={handleChangeFile}
       />
      <button type="button" onClick={handleDownloadUST}>ダウンロード</button>
    </div>
  );

間違いなどありましたらご指摘ください、なにかの役に立てば幸いです。
(似たような要領でMusicXMLも一応いけるのですが、雑すぎるので別にします)

3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?