[RUST/HOUND] WavWriter 구조체 : write_sample 메소드를 사용해 FM(Frequency Modulation) 음원 WAV 파일 생성하기
■ WavWriter 구조체의 write_sample 메소드를 사용해 FM(Frequency Modulation) 음원의 WAV 파일을 생성하는 방법을 보여준다. ▶ Cargo.toml
1 2 3 4 5 6 7 8 9 |
[package] name = "test_project" version = "0.1.0" edition = "2021" [dependencies] hound = "3.4.0" |
▶ src/fm.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 |
use std::f32::consts; pub const SAMPLE_RATE : f32 = 44100.0; pub struct Note { pub scale : i32, // 음계 pub length : isize, // 음표 길이 pub gain : f32, // 음량 pub params : (f32, f32) // 음색 매개변수 } pub fn make_fm(wave_vector : &mut Vec<f32>, note : Note) { let frequency : f32 = get_frequency(note.scale); let a : f32 = 2.0 * consts::PI * frequency / SAMPLE_RATE; let wave_vector_length : usize = note.length as usize; let mut temporary_wave_vector1 :Vec<f32> = vec![0.0; wave_vector_length]; for i in 0..(note.length as usize) { let t : f32 = i as f32; let sin1 : f32 = note.params.0 * (a * t).sin(); let sin2 : f32 = note.params.1 * (a * t + sin1).sin(); let sin3 : f32 = (a * t + sin2).sin(); temporary_wave_vector1[i] = sin3; } let attack : usize = 3; let decay : usize = attack + 200; let sustain : f32 = 0.90; let release : usize = (wave_vector_length as f32 * 0.4) as usize; let temporary_wave_vector2 : Vec<f32> = temporary_wave_vector1.into_iter().enumerate().map ( |(index, value)| { let v1 : f32 = (value * note.gain) as f32; if index < attack { return index as f32 / attack as f32 * v1; } let v2 : f32 = v1 * sustain; if index < decay { let dec : f32 = (1.0 - (index as f32 / decay as f32)) * (1.0 - sustain) * v1.abs(); return if v2 > 0.0 { v1 + dec } else { v1 - dec } } else if index > (wave_vector_length - release) { let i : usize = index - (wave_vector_length - release); return (1.0 - i as f32 / release as f32) * v2; } return v2; } ).collect(); wave_vector.extend(temporary_wave_vector2); } // bpm : 분당 박자, beats per minute // note : 음표 예) 4(4분 음표) pub fn calculate_note_length(bpm : usize, note : usize) -> isize { return ((4.0 / note as f32) * (60.0 / bpm as f32) * SAMPLE_RATE) as isize; } // scale : 음계, 예) 60(도), 64(미), 67(솔) fn get_frequency(scale : i32) -> f32 { return 440.0 * 2.0f32.powf((scale - 69) as f32 / 12.0); } |
▶ src/main.rs