1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
//! Declares the [`Polyphony`] struct, which allows for multiple signals of the
//! same type to play at the same time.
use std::{collections::HashMap, hash::Hash};
use crate::prelude::*;
/// A polyphonic signal.
///
/// This stores multiple instances of a signal `S`, which can be added and
/// stopped. Signals are internally removed as they are done, to save processing
/// power.
#[derive(Clone, Debug)]
pub struct Polyphony<K: Eq + Hash + Clone, S: Done> {
/// The signals currently playing.
signals: HashMap<K, S>,
/// The number of signals that have been added in total.
idx: usize,
}
impl<K: Eq + Hash + Clone, S: Done> Default for Polyphony<K, S> {
fn default() -> Self {
Self {
signals: HashMap::default(),
idx: 0,
}
}
}
impl<K: Eq + Hash + Clone, S: Done> Polyphony<K, S> {
/// Initializes a new polyphonic signal, playing nothing.
#[must_use]
pub fn new() -> Self {
Self::default()
}
/// Returns a reference to the structure of currently played signals.
///
/// **Note that this is subject to change.**
#[must_use]
pub const fn signals(&self) -> &HashMap<K, S> {
&self.signals
}
/// Adds a signal, using a given key.
pub fn add(&mut self, key: K, sgn: S) -> usize {
let idx = self.idx;
self.signals.insert(key, sgn);
self.idx += 1;
idx
}
/// Gets a reference to a particular signal.
#[must_use]
pub fn get(&self, key: &K) -> Option<&S> {
self.signals.get(key)
}
/// Gets a mutable reference to a particular signal.
pub fn get_mut(&mut self, key: &K) -> Option<&mut S> {
self.signals.get_mut(key)
}
/// Modifies a signal with the given key using the specified function.
/// Returns whether the signal was found.
pub fn modify<F: Fn(&mut S)>(&mut self, key: &K, f: F) -> bool {
if let Some(sgn) = self.get_mut(key) {
f(sgn);
true
} else {
false
}
}
/// Stops a given signal, returns whether it was successful.
pub fn stop(&mut self, key: &K) -> bool
where
S: Stop,
{
self.modify(key, S::stop)
}
// We don't implement `panic` as it would clash with the `Panic` impl.
}
impl<K: Eq + Hash + Clone, S: Done> Signal for Polyphony<K, S> {
type Sample = S::Sample;
fn get(&self) -> S::Sample {
self.signals.values().map(Signal::get).sum()
}
fn advance(&mut self) {
// Generators to clear.
let mut clear = Vec::new();
for (idx, sgn) in &mut self.signals {
sgn.advance();
if sgn.is_done() {
clear.push(idx.clone());
}
}
for idx in clear {
self.signals.remove(&idx);
}
}
fn retrigger(&mut self) {
self.signals.clear();
}
}
impl<K: Eq + Hash + Clone, S: Done> Base for Polyphony<K, S> {
type Base = Self;
fn base(&self) -> &Self::Base {
self
}
fn base_mut(&mut self) -> &mut Self::Base {
self
}
}
impl<K: Eq + Hash + Clone, S: Done> Panic for Polyphony<K, S> {
fn panic(&mut self) {
self.retrigger();
}
}