rs_audio/wav/exporter.rs
1use std::{
2 fs::File,
3 io::{BufReader, Error},
4};
5
6use hound::{WavSpec, WavWriter};
7use rodio::{Decoder, OutputStream, Sink};
8
9use crate::{waveform::generate_sample, Song};
10
11impl Song {
12 /**
13 Exports a Song struct to a .wav file.<br>
14 Usage:
15 ```
16 use rs_audio::*;
17 use rs_audio::{player::Song};
18
19 let song = Song::default();
20 song.export_to_wav("test.wav".to_string());
21 ```
22
23 # Panics
24 This function will panic if the file could not be created due to some error.
25 */
26 pub fn export_to_wav(&self, filename: String) -> Result<(), Box<dyn std::error::Error>> {
27 // set up wave file specs
28 let spec = WavSpec {
29 channels: 1,
30 sample_rate: 44100, // 44.1k Hz
31 bits_per_sample: 16, // 16 bit depth
32 sample_format: hound::SampleFormat::Int,
33 };
34
35 // create writer for writing to files
36 let mut writer = match WavWriter::create(filename, spec) {
37 Ok(e) => e,
38 Err(e) => {
39 panic!("RS-AUDIO: Error while creating file: {e}");
40 }
41 };
42
43 for note in &self.notes {
44 let total_samples = (note.dur * 44100.0) as usize;
45 for i in 0..total_samples {
46 let phase = (i as f64 * note.freq / 44100.0) % 1.0; // generate phase
47 let sample = generate_sample(¬e.wave, phase) * note.vol as f64; // generate sample from waveform
48 writer.write_sample((sample * i16::MAX as f64) as i16)?; // add the sample
49 }
50 }
51
52 writer.finalize()?;
53
54 Ok(())
55 }
56
57 /**
58 Plays a .wav file directly.<br>
59 Note that `.wav`'s are not converted to Songs in this function due to complexity.
60 <br>
61
62
63 Usage:
64 ```
65 use rs_audio::*;
66 use rs_audio::{player::Song};
67
68 Song::play_wav("test.wav").unwrap();
69 ```
70
71 **This function will return an Error if it encounters an error.<br>**
72 The recommended way to use it is the following:
73 ```
74 use rs_audio::*;
75 use rs_audio::{player::Song};
76
77 match Song::play_wav("test.wav") {
78 Ok(_) => (),
79 Err(e) => {
80 eprintln!("Error: {e}");
81 std::process::exit(1);
82 }
83 }
84 ```
85 */
86 pub fn play_wav(file_path: &str) -> Result<(), Error> {
87 let (_stream, handle) = match OutputStream::try_default() {
88 Ok(e) => e,
89 Err(e) => return Err(Error::other(e.to_string())),
90 };
91
92 let sink = match Sink::try_new(&handle) {
93 Ok(e) => e,
94
95 /* convert PlayError to std::io::Error */
96 Err(e) => return Err(Error::other(e.to_string())),
97 };
98
99 let file = File::open(file_path)?;
100
101 let source = match Decoder::new(BufReader::new(file)) {
102 Ok(e) => e,
103 Err(e) => return Err(Error::other(e.to_string())),
104 };
105
106 sink.append(source);
107 sink.sleep_until_end(); // blocks thread until finished
108
109 Ok(())
110 }
111}