diff --git a/examples/echo.rs b/examples/echo.rs index ff3b896..efa8a80 100644 --- a/examples/echo.rs +++ b/examples/echo.rs @@ -43,6 +43,26 @@ type Chunk = Arc<[Sample; CHUNK_SAMPLES]>; /// Number of chunks the "Delay" actor (effect) has. const DELAY_CHUNKS: usize = 60; +/// A chunk of samples that represents the "dry" (original, authentic) signal. +struct DryChunk(Chunk); + +/// A chunk of sample that represents the "wet" (processed, edited) signal. +struct WetChunk(Chunk); + +/// DryChunk converts to (unspecified) Chunk (but not the other way around). +impl From for Chunk { + fn from(orig: DryChunk) -> Self { + orig.0 + } +} + +/// WetChunk converts to (unspecified) Chunk (but not the other way around). +impl From for Chunk { + fn from(orig: WetChunk) -> Self { + orig.0 + } +} + /// Dummy trigger for [`Input`] to read next chunk. struct ReadNext; @@ -50,12 +70,12 @@ fn silence_chunk() -> Chunk { Arc::new([[0i16; 2]; CHUNK_SAMPLES]) } -/// Actor to read and decode input stream (stdin) and produce sound chunks. -struct Input { - next: Recipient, +/// Actor to read and decode input stream (stdin) and produce sound [`DryChunk`]s. +struct Input { + next: Recipient, } -impl Actor for Input { +impl> Actor for Input { type Error = Error; type Message = ReadNext; @@ -76,14 +96,14 @@ impl Actor for Input { trace!("[Input] decoded chunk: {:?}...", &chunk[..5]); // Send the parsed chunk to the next actor. - self.next.try_send(MixerInput::Dry(chunk))?; + self.next.try_send(DryChunk(chunk))?; // Trigger a loop to read the next chunk. context.myself.try_send(ReadNext).map_err(Error::from) } } -/// Actor to encode and write sound chunks to output stream (stdout). +/// Actor to encode and write sound chunks to output stream (stdout). Consumes [`Chunk`]s, struct Output; impl Actor for Output { @@ -108,27 +128,45 @@ impl Actor for Output { /// A chunk that knows whether it is dry or wet. enum MixerInput { /// The original signal. - Dry(Chunk), + Dry(DryChunk), /// Signal from an effect. - Wet(Chunk), + Wet(WetChunk), +} + +impl From for MixerInput { + fn from(orig: DryChunk) -> Self { + Self::Dry(orig) + } +} + +impl From for MixerInput { + fn from(orig: WetChunk) -> Self { + Self::Wet(orig) + } } /// Audio mixer actor. Mixes 2 inputs (dry, wet) together, provides 2 equal outputs. -struct Mixer { - out_1: Recipient, - out_2: Recipient, - dry_buffer: Option, - wet_buffer: Option, +/// Consumer either [`DryChunk`]s or [`WetChunk`]s and produces [`Chunk`]s. +struct Mixer { + out_1: Recipient, + out_2: Recipient, + dry_buffer: Option, + wet_buffer: Option, } -impl Mixer { - fn new(out_1: Recipient, out_2: Recipient) -> Self { +impl Mixer { + fn new(out_1: Recipient, out_2: Recipient) -> Self { // Start with buffers filled, so that output is produced right for the first message. - Self { out_1, out_2, dry_buffer: Some(silence_chunk()), wet_buffer: Some(silence_chunk()) } + Self { + out_1, + out_2, + dry_buffer: Some(DryChunk(silence_chunk())), + wet_buffer: Some(WetChunk(silence_chunk())), + } } } -impl Actor for Mixer { +impl, M2: From> Actor for Mixer { type Error = Error; type Message = MixerInput; @@ -146,8 +184,9 @@ impl Actor for Mixer { // if both buffers are full, mix them and send out. if let (Some(dry), Some(wet)) = (&self.dry_buffer, &self.wet_buffer) { let mixed_slice: Arc<[Sample]> = dry + .0 .iter() - .zip(wet.iter()) + .zip(wet.0.iter()) .map(|(a, b)| [a[0].saturating_add(b[0]), a[1].saturating_add(b[1])]) .collect(); let mixed: Chunk = mixed_slice.try_into().expect("sample count is correct"); @@ -163,20 +202,21 @@ impl Actor for Mixer { } /// Delay audio effect actor. Technically just a fixed circular buffer. -struct Delay { - next: Recipient, +/// Consumes [`Chunk`]s and produces [`WetChunk`]s. +struct Delay { + next: Recipient, buffer: Vec, index: usize, } -impl Delay { - fn new(next: Recipient) -> Self { +impl Delay { + fn new(next: Recipient) -> Self { let buffer: Vec = repeat(silence_chunk()).take(DELAY_CHUNKS).collect(); Self { next, buffer, index: 0 } } } -impl Actor for Delay { +impl> Actor for Delay { type Error = Error; type Message = Chunk; @@ -191,16 +231,16 @@ impl Actor for Delay { self.index = (self.index + 1) % self.buffer.len(); // Send out the least recent chunk. - self.next.try_send(Arc::clone(&self.buffer[self.index])).map_err(Error::from) + self.next.try_send(WetChunk(Arc::clone(&self.buffer[self.index]))).map_err(Error::from) } } -/// Audio damper actor. Attenuates audio level a bit. -struct Damper { - next: Recipient, +/// Audio damper actor. Attenuates audio level a bit. Consumes [`Chunk`]s and produces [`WetChunk`]s. +struct Damper { + next: Recipient, } -impl Actor for Damper { +impl> Actor for Damper { type Error = Error; type Message = Chunk; @@ -214,7 +254,7 @@ impl Actor for Damper { let chunk: Chunk = chunk_slice.try_into().expect("sample count is correct"); // Pass it right on. - self.next.try_send(MixerInput::Wet(chunk)).map_err(Error::from) + self.next.try_send(WetChunk(chunk)).map_err(Error::from) } }