use std::{
any::Any,
sync::{mpsc::SyncSender, Arc},
time::Duration,
};
use basedrop::Owned;
use crossbeam_queue::ArrayQueue;
use four_cc::FourCC;
use crate::{
modulation::{ModulationSource, ModulationTarget},
parameter::{Parameter, ParameterValueUpdate},
source::{unique_source_id, Source},
utils::db_to_linear,
Error, MixerId, NotePlaybackId, PlaybackId, PlaybackStatusContext, PlaybackStatusEvent,
SourceTime,
};
pub mod empty;
#[cfg(feature = "fundsp")]
pub mod fundsp;
pub mod sampler;
pub(crate) fn unique_note_id() -> usize {
unique_source_id()
}
#[derive(Debug, Clone, Copy)]
pub struct GeneratorPlaybackOptions {
pub volume: f32,
pub panning: f32,
pub voices: usize,
pub target_mixer: Option<MixerId>,
pub measure_cpu_load: bool,
pub playback_pos_emit_rate: Option<Duration>,
}
impl Default for GeneratorPlaybackOptions {
fn default() -> Self {
Self {
volume: 1.0,
panning: 0.0,
voices: 8,
target_mixer: None,
measure_cpu_load: false,
playback_pos_emit_rate: Some(Duration::from_secs(1)),
}
}
}
impl GeneratorPlaybackOptions {
pub fn volume(mut self, volume: f32) -> Self {
self.volume = volume;
self
}
pub fn volume_db(mut self, volume_db: f32) -> Self {
self.volume = db_to_linear(volume_db);
self
}
pub fn panning(mut self, panning: f32) -> Self {
self.panning = panning;
self
}
pub fn voices(mut self, voices: usize) -> Self {
self.voices = voices;
self
}
pub fn target_mixer(mut self, mixer_id: MixerId) -> Self {
self.target_mixer = Some(mixer_id);
self
}
pub fn measure_cpu_load(mut self, measure: bool) -> Self {
self.measure_cpu_load = measure;
self
}
pub fn playback_pos_emit_rate(mut self, duration: std::time::Duration) -> Self {
self.playback_pos_emit_rate = Some(duration);
self
}
pub fn playback_pos_emit_disabled(mut self) -> Self {
self.playback_pos_emit_rate = None;
self
}
pub fn validate(&self) -> Result<(), Error> {
if self.volume < 0.0 || self.volume.is_nan() {
return Err(Error::ParameterError(format!(
"playback options 'volume' value is '{}'",
self.volume
)));
}
if !(-1.0..=1.0).contains(&self.panning) || self.panning.is_nan() {
return Err(Error::ParameterError(format!(
"playback options 'panning' value is '{}'",
self.panning
)));
}
if self.voices == 0 {
return Err(Error::ParameterError(format!(
"playback options voice count is '{}'",
self.voices
)));
}
Ok(())
}
}
pub trait GeneratorMessage: Any + Send + Sync {
fn generator_name(&self) -> &'static str;
fn payload(&self) -> &dyn Any;
}
pub type GeneratorMessagePayload = dyn GeneratorMessage;
pub enum GeneratorPlaybackEvent {
NoteOn {
note_id: NotePlaybackId,
note: u8,
volume: Option<f32>,
panning: Option<f32>,
context: Option<PlaybackStatusContext>,
},
NoteOff { note_id: NotePlaybackId },
AllNotesOff,
SetSpeed {
note_id: NotePlaybackId,
speed: f64,
glide: Option<f32>,
},
SetVolume {
note_id: NotePlaybackId,
volume: f32,
},
SetPanning {
note_id: NotePlaybackId,
panning: f32,
},
SetParameter {
id: FourCC,
value: Owned<ParameterValueUpdate>,
},
SetParameters {
values: Owned<Vec<(FourCC, ParameterValueUpdate)>>,
},
SetModulation {
source: FourCC,
target: FourCC,
amount: f32,
bipolar: bool,
},
ClearModulation { source: FourCC, target: FourCC },
ProcessMessage {
message: Box<GeneratorMessagePayload>,
},
}
pub enum GeneratorPlaybackMessage {
Stop,
Trigger { event: GeneratorPlaybackEvent },
}
pub trait Generator: Source {
fn into_box(self) -> Box<dyn Generator>
where
Self: Sized,
{
Box::new(self)
}
fn generator_name(&self) -> String;
fn playback_id(&self) -> PlaybackId;
fn playback_options(&self) -> &GeneratorPlaybackOptions;
fn playback_message_queue(&self) -> Arc<ArrayQueue<GeneratorPlaybackMessage>>;
fn playback_status_sender(&self) -> Option<SyncSender<PlaybackStatusEvent>>;
fn set_playback_status_sender(&mut self, sender: Option<SyncSender<PlaybackStatusEvent>>);
fn is_transient(&self) -> bool;
fn set_is_transient(&mut self, is_transient: bool);
fn parameters(&self) -> Vec<&dyn Parameter> {
vec![]
}
fn process_parameter_update(
&mut self,
_id: FourCC,
_value: &ParameterValueUpdate,
) -> Result<(), Error> {
debug_assert!(
self.parameters().is_empty(),
"When providing parameters, implement 'process_parameter_update' too!"
);
Ok(())
}
fn process_parameter_updates(
&mut self,
values: &[(FourCC, ParameterValueUpdate)],
) -> Result<(), Error> {
for (id, value) in values {
self.process_parameter_update(*id, value)?
}
Ok(())
}
fn modulation_sources(&self) -> Vec<ModulationSource> {
vec![]
}
fn modulation_targets(&self) -> Vec<ModulationTarget> {
vec![]
}
fn set_modulation(
&mut self,
_source: FourCC,
_target: FourCC,
_amount: f32,
_bipolar: bool,
) -> Result<(), Error> {
Err(Error::ParameterError(
"Modulation routing not supported by this generator".to_string(),
))
}
fn clear_modulation(&mut self, _source: FourCC, _target: FourCC) -> Result<(), Error> {
Err(Error::ParameterError(
"Modulation routing not supported by this generator".to_string(),
))
}
fn process_message(&mut self, _message: &GeneratorMessagePayload) -> Result<(), Error> {
Err(Error::ParameterError(format!(
"{}: Received unexpected message payload.",
self.generator_name()
)))
}
}
impl Source for Box<dyn Generator> {
fn sample_rate(&self) -> u32 {
(**self).sample_rate()
}
fn channel_count(&self) -> usize {
(**self).channel_count()
}
fn is_exhausted(&self) -> bool {
(**self).is_exhausted()
}
fn weight(&self) -> usize {
(**self).weight()
}
fn write(&mut self, output: &mut [f32], time: &SourceTime) -> usize {
(**self).write(output, time)
}
}
impl Generator for Box<dyn Generator> {
fn into_box(self) -> Box<dyn Generator> {
self
}
fn generator_name(&self) -> String {
(**self).generator_name()
}
fn playback_id(&self) -> PlaybackId {
(**self).playback_id()
}
fn playback_options(&self) -> &GeneratorPlaybackOptions {
(**self).playback_options()
}
fn playback_message_queue(&self) -> Arc<ArrayQueue<GeneratorPlaybackMessage>> {
(**self).playback_message_queue()
}
fn playback_status_sender(&self) -> Option<SyncSender<PlaybackStatusEvent>> {
(**self).playback_status_sender()
}
fn set_playback_status_sender(&mut self, sender: Option<SyncSender<PlaybackStatusEvent>>) {
(**self).set_playback_status_sender(sender)
}
fn is_transient(&self) -> bool {
(**self).is_transient()
}
fn set_is_transient(&mut self, is_transient: bool) {
(**self).set_is_transient(is_transient)
}
fn parameters(&self) -> Vec<&dyn Parameter> {
(**self).parameters()
}
fn process_parameter_update(
&mut self,
id: FourCC,
value: &ParameterValueUpdate,
) -> Result<(), Error> {
(**self).process_parameter_update(id, value)
}
fn process_parameter_updates(
&mut self,
values: &[(FourCC, ParameterValueUpdate)],
) -> Result<(), Error> {
(**self).process_parameter_updates(values)
}
fn modulation_sources(&self) -> Vec<ModulationSource> {
(**self).modulation_sources()
}
fn modulation_targets(&self) -> Vec<ModulationTarget> {
(**self).modulation_targets()
}
fn set_modulation(
&mut self,
source: FourCC,
target: FourCC,
amount: f32,
bipolar: bool,
) -> Result<(), Error> {
(**self).set_modulation(source, target, amount, bipolar)
}
fn clear_modulation(&mut self, source: FourCC, target: FourCC) -> Result<(), Error> {
(**self).clear_modulation(source, target)
}
fn process_message(&mut self, message: &GeneratorMessagePayload) -> Result<(), Error> {
(**self).process_message(message)
}
}