rs_audio/
legacyplayer.rs

1use crate::assets::loader::load_asset;
2use crate::note::Note;
3use crate::waveform::WaveForm;
4use crate::BPMChoice;
5use rodio::{source::SineWave, OutputStream, Sink, Source};
6use std::{io::Error, time::Duration};
7
8/**
9# Deprecated
10This feature has been deprecated in the latest update. Please use the new player, not the legacy one.<br><br>
11
12Basic songs are collections of Notes. Each song can export to a .wav file.<br>
13
14Example:
15```
16use rs_audio::*;
17
18let mut song = BasicSong::default();
19song.play().unwrap();
20
21let mut second_song = BasicSong::new(vec![
22Note { freq: 880.0, dur: 1.0, vol: 0.20, wave: WaveForm::Sine },
23Note { freq: 220.0, dur: 1.0, vol: 0.20, wave: WaveForm::Square },
24Note { freq: 880.0, dur: 1.0, vol: 0.20, wave: WaveForm::Sine },
25Note { freq: 220.0, dur: 1.0, vol: 0.20, wave: WaveForm::Triangle },
26], BPMChoice::Default);
27
28second_song.play().unwrap(); // Uses the main thread.
29second_song.export_to_wav("test.wav".to_string());
30```
31*/
32pub struct BasicSong {
33    pub notes: Vec<Note>,
34
35    pub bpm: BPMChoice, // beats per minute
36}
37
38impl Default for BasicSong {
39    /**
40    # Deprecated
41    This feature has been deprecated in the latest update. Please use the new player, not the legacy one.<br><br>
42
43
44    Creates a default song that is useful for debugging purposes.<br><br>
45    It contains a single default sine wave.<br>
46    Usage:
47    ```
48    use rs_audio::*;
49    let song = BasicSong::default();
50    ```
51    */
52    fn default() -> Self {
53        BasicSong {
54            notes: vec![Note::default()],
55            bpm: BPMChoice::Default,
56        }
57    }
58}
59
60impl BasicSong {
61    pub fn new(notes: Vec<Note>, bpm: BPMChoice) -> Self {
62        BasicSong { notes, bpm }
63    }
64
65    pub fn play(&mut self) -> Result<(), Error> {
66        let mut volume_warning_given: bool = false;
67        // if the volume warning has been given (this is for volume warnings with sine waves)
68
69        // creates stream and sink (audio mixer)
70        let (_stream, handle) = match OutputStream::try_default() {
71            Ok(e) => e,
72            Err(e) => return Err(Error::other(e.to_string())),
73        };
74
75        let sink = match Sink::try_new(&handle) {
76            Ok(e) => e,
77            Err(e) => return Err(Error::other(e.to_string())),
78        };
79
80        // iterates over the notes
81        for note in &mut self.notes {
82            if !volume_warning_given && note.vol > 0.20 && note.wave == WaveForm::Sine {
83                // issue a warning
84
85                /* loads the warning ascii art */
86                println!("{}", load_asset("warning_ascii.txt"));
87
88                /* loads the volume warning text */
89                println!("{}", load_asset("warning_volume.txt"));
90
91                let mut input = String::new();
92
93                // wait for input
94                std::io::stdin()
95                    .read_line(&mut input)
96                    .expect("RS-AUDIO: Could not read input!");
97
98                match input.trim() {
99                    // handle options
100                    n if n.starts_with("c") => {
101                        volume_warning_given = true;
102                    } // do nothing
103
104                    n if n.starts_with("a") => {
105                        // abort
106                        println!("RS-AUDIO: Exiting...");
107                        std::process::exit(0);
108                        // no need to change volume_warning_given because we exited
109                    }
110
111                    n if n.starts_with("d") || n.is_empty() => {
112                        /*
113                        use the default value
114
115                        this is either "d" or just an empty string (achieved by pressing enter and trimming)
116                        */
117                        note.vol = 0.20;
118                        volume_warning_given = true;
119                    }
120
121                    _ => {
122                        eprintln!("RS-AUDIO: Input is invalid\nRS-AUDIO: Exiting...");
123                        std::process::exit(1);
124                        // no need to change volume_warning_given because we exitted
125                    }
126                }
127            }
128            let converted = match note.wave {
129                WaveForm::Sine => SineWave::new(note.freq as f32),
130                _ => note.to_approx_sine(),
131            }
132            .take_duration(Duration::from_secs_f64(note.dur))
133            .amplify(note.vol);
134
135            sink.append(converted);
136        }
137
138        sink.sleep_until_end();
139        Ok(())
140    }
141}