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();
    }
}