本記事について
仕事もひと段落し、Rustの勉強中にRustでサウンドが作れるということで、以前からやってみたかった夏休みの自由研究
「戦姫絶唱シンフォギアが永遠に当たる気分を作る」というテーマでやってみました。
参考動画
こちらの二つを掛け合わせてできました。
とても楽しかったです。
補足
シンフォギアライブ当選された方おめでとうございます!!
是非とも11月20日はみなさんの「絶唱」楽しみにしております。
うらやましいなぁ。。。
ソースコード
このコードに関する解説はぜひ本をお買い求めください。
追加のクレート
hound = "3.4.0"
main.rs
use hound;
const SAMPLE_RATE: f32 = 44100.0;
fn main() {
let spec = hound::WavSpec {
channels: 1,
sample_rate: SAMPLE_RATE as u32,
bits_per_sample: 32,
sample_format: hound::SampleFormat::Float,
};
let mut fw = hound::WavWriter::create("saw.wav", spec).unwrap();
let mut wav: Vec<f32> = vec![];
let bpm = 120;
wav.extend(sawtooth_wave(67, calc_len(bpm, 16), 0.4));
wav.extend(sawtooth_wave(72, calc_len(bpm, 16), 0.4));
wav.extend(sawtooth_wave(74, calc_len(bpm, 16), 0.4));
wav.extend(sawtooth_wave(75, calc_len(bpm, 16), 0.4));
wav.extend(sawtooth_wave(75, calc_len(bpm, 16), 0.4));
wav.extend(sawtooth_wave(75, calc_len(bpm, 16), 0.4));
wav.extend(sawtooth_wave(75, calc_len(bpm, 16), 0.4));
wav.extend(sawtooth_wave(75, calc_len(bpm, 16), 0.4));
wav.extend(sawtooth_wave(67, calc_len(bpm, 16), 0.4));
wav.extend(sawtooth_wave(67, calc_len(bpm, 16), 0.4));
wav.extend(sawtooth_wave(67, calc_len(bpm, 16), 0.4));
wav.extend(sawtooth_wave(67, calc_len(bpm, 16), 0.4));
wav.extend(sawtooth_wave(67, calc_len(bpm, 16), 0.4));
wav.extend(sawtooth_wave(67, calc_len(bpm, 16), 0.4));
wav.extend(sawtooth_wave(74, calc_len(bpm, 16), 0.4));
wav.extend(sawtooth_wave(74, calc_len(bpm, 16), 0.4));
wav.extend(sawtooth_wave(74, calc_len(bpm, 16), 0.4));
wav.extend(sawtooth_wave(74, calc_len(bpm, 16), 0.4));
wav.extend(sawtooth_wave(74, calc_len(bpm, 16), 0.4));
wav.extend(sawtooth_wave(74, calc_len(bpm, 16), 0.4));
wav.extend(sawtooth_wave(70, calc_len(bpm, 16), 0.4));
wav.extend(sawtooth_wave(70, calc_len(bpm, 16), 0.4));
wav.extend(sawtooth_wave(70, calc_len(bpm, 16), 0.4));
wav.extend(sawtooth_wave(70, calc_len(bpm, 16), 0.4));
wav.extend(sawtooth_wave(70, calc_len(bpm, 16), 0.4));
wav.extend(sawtooth_wave(70, calc_len(bpm, 16), 0.4));
wav.extend(sawtooth_wave(72, calc_len(bpm, 16), 0.4));
wav.extend(sawtooth_wave(72, calc_len(bpm, 16), 0.4));
wav.extend(sawtooth_wave(72, calc_len(bpm, 16), 0.4));
wav.extend(sawtooth_wave(72, calc_len(bpm, 16), 0.4));
wav.extend(sawtooth_wave(72, calc_len(bpm, 16), 0.4));
wav.extend(sawtooth_wave(72, calc_len(bpm, 16), 0.4));
wav.extend(sawtooth_wave(72, calc_len(bpm, 16), 0.4));
wav.extend(sawtooth_wave(72, calc_len(bpm, 16), 0.4));
wav.extend(sawtooth_wave(72, calc_len(bpm, 16), 0.4));
wav.extend(sawtooth_wave(72, calc_len(bpm, 4), 0.4));
for v in wav.into_iter() {
fw.write_sample(v).unwrap();
println!("{}", v);
}
}
fn noteno_to_hz(no: i32) -> f32 {
440.0 * 2.0f32.powf((no - 69) as f32 / 12.0)
}
fn calc_len(bpm: usize, n: usize) -> usize {
let base_len = (60.0 / bpm as f32) * SAMPLE_RATE;
((4.0 / n as f32) * base_len) as usize
}
fn sawtooth_wave(noteno: i32, len: usize, gain: f32) -> Vec<f32> {
let tone = noteno_to_hz(noteno);
let form_samples = SAMPLE_RATE / tone;
let mut wav: Vec<f32> = vec![0.0; len];
for i in 0..len {
let pif = (i as f32 / form_samples) % 1.0;
wav[i] = pif * 2.0 - 1.0;
}
wav.into_iter().map(|v| (v * gain) as f32).collect()
}