Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kujirahand/cd5c8005127ce309c94a3608d9be07d8 to your computer and use it in GitHub Desktop.
Save kujirahand/cd5c8005127ce309c94a3608d9be07d8 to your computer and use it in GitHub Desktop.
サウンドフォント対応のMIDIプレイヤー。オーディオデバイスに直接音声データを書き込みます。
// $ cargo add rustysynth@1.2.0
// $ cargo add tinyaudio@0.1.1
use rustysynth::{SynthesizerSettings, Synthesizer, SoundFont, MidiFile, MidiFileSequencer};
use tinyaudio::prelude::*;
// 定数の指定 --- (*1)
const FILE_SOUNDFONT: &str = "TimGM6mb.sf2"; // サウンドフォントのパス
const FILE_MIDI: &str = "sakura2.mid"; // 入力MIDIファイルのパス
const SAMPLE_RATE: usize = 44_100; // サンプリング周波数(CD音質)
fn main() {
// オーディオの出力設定 --- (*2)
let params = OutputDeviceParameters {
channels_count: 2, // ステレオ
sample_rate: SAMPLE_RATE, // サンプリング周波数
channel_sample_count: SAMPLE_RATE / 2, // バッファサイズ
};
// 書き込み先のバッファを確保 --- (*3)
let mut left_buf:Vec<f32> = vec![0.0f32; params.channel_sample_count];
let mut right_buf:Vec<f32> = vec![0.0f32; params.channel_sample_count];
// 用意したサウンドフォントを読み込む --- (*4)
let mut sf2 = std::fs::File::open(FILE_SOUNDFONT).unwrap();
let sound_font = std::sync::Arc::new(SoundFont::new(&mut sf2).unwrap());
// シンセサイザーの作成 --- (*5)
let settings = SynthesizerSettings::new(SAMPLE_RATE as i32);
let synthesizer = Synthesizer::new(&sound_font, &settings).unwrap();
// MIDIシーケンサーを作成してMIDIファイルを読み込む --- (*6)
let mut sequencer = MidiFileSequencer::new(synthesizer);
let mut mid = std::fs::File::open(FILE_MIDI).unwrap();
let midi_file = std::sync::Arc::new(MidiFile::new(&mut mid).unwrap());
// シーケンサーの開始 --- (*7)
sequencer.play(&midi_file, true); // 繰り返し再生を有効にする
// オーディオの出力を開始 --- (*8)
let _device = run_output_device(params, {
move |data| {
// 再生位置を標準出力に表示
println!("{:03.1}/{} [Enter]で終了", sequencer.get_position(),
midi_file.get_length() as u32);
// シーケンサーによる波形生成 --- (*9)
let mut clock = 0;
sequencer.render(&mut left_buf[..], &mut right_buf[..]);
// 出力デバイスに書き込む --- (*10)
for samples in data.chunks_mut(params.channels_count as usize) {
// チャンネルごとに波形を書き込む --- (*11)
for (ch, sample) in samples.iter_mut().enumerate() {
let v = if ch == 0 { left_buf[clock] } else { right_buf[clock] };
*sample = v;
}
clock = (clock + 1) % params.channel_sample_count;
}
}
})
.unwrap();
// [Enter]で終了 --- (*12)
std::io::stdin().read_line(&mut String::new()).unwrap();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment