// This file contains the actual sound generation of a plugin that is shared between all backends. // The integration with VST is in the `vst_synt.rs` file. // The integration with Jack is in the `jack_synth.rs` file. use asprim::AsPrim; use num_traits::Float; use rand::{thread_rng, Rng}; use rsynth::event::{ ContextualEventHandler, EventHandler, Indexed, RawMidiEvent, SysExEvent, Timed, }; use rsynth::utilities::polyphony::{ simple_event_dispatching::{SimpleEventDispatcher, SimpleVoiceState}, EventDispatcher, RawMidiEventToneIdentifierDispatchClassifier, ToneIdentifier, Voice, }; use rsynth::{AudioHandler, ContextualAudioRenderer}; use std::default::Default; use midi_consts::channel_event::*; use rsynth::buffer::AudioBufferInOut; use rsynth::meta::{InOut, Meta, MetaData}; // The total number of samples to pre-calculate. // This is like recording a sample of white noise and then // using it as an oscillator. It saves on CPU overhead by // preventing us from having to use a random function each sample. static SAMPLE_SIZE: usize = 65536; static NUMBER_OF_VOICES: usize = 6; static AMPLIFY_MULTIPLIER: f32 = 1.0 / NUMBER_OF_VOICES as f32; // This struct defines the data that we will need to play one "noise" pub struct Noise { // Random data of the noise. white_noise: Vec, // At which sample in the noise we are. position: usize, // The amplitude. amplitude: f32, // This is used to know if this is currently playing and if so, what note. state: SimpleVoiceState, } impl Noise { fn new(sample_size: usize) -> Self { let mut rng = thread_rng(); let samples: Vec = rng .gen_iter::() .take(sample_size) .map(|r| { // The random generator generates noise between 0 and 1, // we map it to the range -1 to 1. 2.0 * r - 1.0 }) .collect::>(); Noise { white_noise: samples, position: 0, amplitude: 0.0, state: SimpleVoiceState::Idle, } } // Here, we use one implementation over all floating point types. // If you want to use SIMD optimization, you can have separate implementations // for `f32` and `f64`. fn render_audio_buffer(&mut self, buffer: &mut AudioBufferInOut) where S: AsPrim + Float, { if self.state == SimpleVoiceState::Idle { return; } let outputs = buffer.outputs(); assert_eq!(2, outputs.number_of_channels()); for output_channel in outputs.channel_iter_mut() { for sample in output_channel.iter_mut() { // We "add" to the output. // In this way, various noises can be heard together. *sample = *sample + self.white_noise[self.position].as_::() * self.amplitude.as_(); // Increment the position of our sound sample. // We loop this easily by using modulo. self.position = (self.position + 1) % self.white_noise.len(); } } } } // This enables using Sound in a polyphonic context. impl Voice> for Noise { fn state(&self) -> SimpleVoiceState { self.state } } impl EventHandler> for Noise { fn handle_event(&mut self, timed: Timed) { let state_and_chanel = timed.event.data()[0]; // We are digging into the details of midi-messages here. // Alternatively, you could use the `wmidi` crate. if state_and_chanel & EVENT_TYPE_MASK == NOTE_ON { self.amplitude = timed.event.data()[2] as f32 / 127.0 * AMPLIFY_MULTIPLIER; self.state = SimpleVoiceState::Active(ToneIdentifier(timed.event.data()[1])); } if state_and_chanel & EVENT_TYPE_MASK == NOTE_OFF { self.amplitude = 0.0; self.state = SimpleVoiceState::Idle; } } } pub struct NoisePlayer { meta_data: MetaData<&'static str, &'static str, &'static str>, voices: Vec, dispatcher: SimpleEventDispatcher, } impl NoisePlayer { fn meta_data() -> MetaData<&'static str, &'static str, &'static str> { MetaData { general_meta: "Noise generator", // The name of the plugin audio_port_meta: InOut { inputs: Vec::new(), // No audio inputs outputs: vec!["left", "right"], // Two audio outputs }, midi_port_meta: InOut { inputs: vec!["midi in"], // One midi in port outputs: Vec::new(), // No midi out port }, } } pub fn new() -> Self { let mut voices = Vec::new(); for _ in 0..NUMBER_OF_VOICES { voices.push(Noise::new(SAMPLE_SIZE)); } Self { meta_data: Self::meta_data(), voices: voices, dispatcher: SimpleEventDispatcher::default(), } } } impl Meta for NoisePlayer { type MetaData = MetaData<&'static str, &'static str, &'static str>; fn meta(&self) -> &Self::MetaData { &self.meta_data } } impl AudioHandler for NoisePlayer { fn set_sample_rate(&mut self, sample_rate: f64) { trace!("set_sample_rate(sample_rate={})", sample_rate); // We are not doing anything with this right now. } } #[allow(unused_variables)] impl ContextualAudioRenderer for NoisePlayer where S: AsPrim + Float, { fn render_buffer(&mut self, buffer: &mut AudioBufferInOut, _context: &mut Context) { for noise in self.voices.iter_mut() { noise.render_audio_buffer(buffer); } } } impl ContextualEventHandler, Context> for NoisePlayer { fn handle_event(&mut self, event: Timed, _context: &mut Context) { self.dispatcher.dispatch_event(event, &mut self.voices) } } // Only needed for Jack: delegate to the normal event handler. impl ContextualEventHandler>, Context> for NoisePlayer { fn handle_event(&mut self, event: Indexed>, context: &mut Context) { self.handle_event(event.event, context) } } impl<'a, Context> ContextualEventHandler>, Context> for NoisePlayer { fn handle_event(&mut self, _event: Timed>, _context: &mut Context) { // We don't do anything with SysEx events. } } // Only needed for Jack: delegate to the normal event handler. impl<'a, Context> ContextualEventHandler>>, Context> for NoisePlayer { fn handle_event(&mut self, event: Indexed>, context: &mut Context) { self.handle_event(event.event, context) } }