Created
July 14, 2023 12:52
-
-
Save kujirahand/cd5c8005127ce309c94a3608d9be07d8 to your computer and use it in GitHub Desktop.
サウンドフォント対応のMIDIプレイヤー。オーディオデバイスに直接音声データを書き込みます。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// $ 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