Skip to main content

pfx_sound/
mix.rs

1use std::collections::{BTreeMap, VecDeque};
2use std::sync::{Arc, Mutex, MutexGuard};
3
4use crate::channel::{
5    BUILT_IN, Channel, ChannelId, DuckState, Ducking, RAMP_SECONDS, clamp_volume, ramp_frames,
6};
7use crate::clip::Clip;
8use crate::envelope::{EnvState, Envelope};
9use crate::filter::Kind;
10use crate::heard::{Bounds, MusicPlace};
11use crate::interp::{Kernel, MAX_RATIO, MIN_RATIO, Resample};
12use crate::music::{Curve, Direction, MusicTrack};
13use crate::pcm::{PcmSender, pcm_pair};
14use crate::sound::{Body, Rng, SoundDef, SoundId, SoundSpec, Steal, draw};
15use crate::synth::{Synth, Wave};
16use crate::voice::{Block, History, Source, Voice};
17
18pub const FILTER_RAMP_SECONDS: f32 = 0.03;
19
20const DEFAULT_SEED: u64 = 0x5EED_A0D1_0000_0001;
21
22#[derive(Clone, Copy, Debug, PartialEq)]
23pub struct Level {
24    pub volume: f32,
25    pub pan: f32,
26    pub fade_in: u64,
27    pub fade_out: u64,
28}
29
30impl Default for Level {
31    fn default() -> Self {
32        Self {
33            volume: 1.0,
34            pan: 0.0,
35            fade_in: 0,
36            fade_out: 0,
37        }
38    }
39}
40
41#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
42pub struct VoiceId(u64);
43
44#[derive(Clone, Debug)]
45pub struct Placement {
46    pub at: u64,
47    pub clip: Clip,
48    pub level: Level,
49}
50
51#[derive(Clone, Debug)]
52pub struct Timeline {
53    pub rate: u32,
54    pub channels: u16,
55    pub placements: Vec<Placement>,
56}
57
58impl Timeline {
59    pub fn new(rate: u32, channels: u16) -> Self {
60        Self {
61            rate,
62            channels,
63            placements: Vec::new(),
64        }
65    }
66
67    pub fn place(&mut self, at: u64, clip: Clip, level: Level) {
68        self.placements.push(Placement { at, clip, level });
69    }
70}
71
72pub fn mixdown(timeline: &Timeline) -> Vec<f32> {
73    let mut mixer = Mixer::new(timeline.rate, timeline.channels);
74    let mut end = 0u64;
75    for placement in &timeline.placements {
76        let matched = placement.clip.for_rate(timeline.rate);
77        end = end.max(placement.at.saturating_add(matched.frames()));
78        mixer.play_prepared(
79            ChannelId::EFFECTS,
80            placement.at,
81            matched,
82            None,
83            placement.level,
84        );
85    }
86    mixer.render(usize::try_from(end).unwrap_or(usize::MAX))
87}
88
89pub(crate) struct PcmQueue {
90    inner: Mutex<QueueInner>,
91}
92
93struct QueueInner {
94    samples: VecDeque<f32>,
95    ended: bool,
96}
97
98impl PcmQueue {
99    pub(crate) fn new() -> Arc<Self> {
100        Arc::new(Self {
101            inner: Mutex::new(QueueInner {
102                samples: VecDeque::new(),
103                ended: false,
104            }),
105        })
106    }
107
108    pub(crate) fn push(&self, samples: &[f32]) {
109        if samples.is_empty() {
110            return;
111        }
112        lock(&self.inner).samples.extend(samples);
113    }
114
115    pub(crate) fn end(&self) {
116        lock(&self.inner).ended = true;
117    }
118
119    pub(crate) fn len(&self) -> usize {
120        lock(&self.inner).samples.len()
121    }
122
123    pub(crate) fn reader_ended(&self) -> bool {
124        lock(&self.inner).ended
125    }
126
127    pub(crate) fn pop_frames(&self, frames: usize, channels: usize) -> Pop {
128        if channels == 0 || frames == 0 {
129            return Pop {
130                samples: Vec::new(),
131                real: 0,
132                available: 0,
133                ended: lock(&self.inner).ended,
134            };
135        }
136        let mut guard = lock(&self.inner);
137        let available = guard.samples.len().checked_div(channels).unwrap_or(0);
138        let real = available.min(frames);
139        let take = real * channels;
140        let mut samples: Vec<f32> = guard.samples.drain(..take).collect();
141        let ended = guard.ended;
142        drop(guard);
143        if let Some(len) = frames.checked_mul(channels) {
144            samples.resize(len, 0.0);
145        }
146        Pop {
147            samples,
148            real,
149            available,
150            ended,
151        }
152    }
153
154    pub(crate) fn is_finished(&self, channels: u16) -> bool {
155        let guard = lock(&self.inner);
156        guard.ended && guard.samples.len() < usize::from(channels.max(1))
157    }
158}
159
160pub(crate) struct Pop {
161    pub(crate) samples: Vec<f32>,
162    pub(crate) real: usize,
163    pub(crate) available: usize,
164    pub(crate) ended: bool,
165}
166
167pub struct Mixer {
168    rate: u32,
169    channels: u16,
170    clock: u64,
171    next_id: u64,
172    voices: Vec<Voice>,
173    buses: BTreeMap<ChannelId, Channel>,
174    master: Channel,
175    limiter: Option<f32>,
176    duck: Option<DuckState>,
177    music: Option<VoiceId>,
178    sounds: Vec<SoundDef>,
179    rng: Rng,
180    kernel: Kernel,
181    scratch: Vec<f32>,
182    duck_gains: Vec<f32>,
183    activity: Vec<bool>,
184}
185
186impl Mixer {
187    pub fn new(rate: u32, channels: u16) -> Self {
188        let mut buses = BTreeMap::new();
189        for id in BUILT_IN {
190            buses.insert(id, Channel::new());
191        }
192        Self {
193            rate,
194            channels,
195            clock: 0,
196            next_id: 0,
197            voices: Vec::new(),
198            buses,
199            master: Channel::new(),
200            limiter: None,
201            duck: None,
202            music: None,
203            sounds: Vec::new(),
204            rng: Rng::new(DEFAULT_SEED),
205            kernel: Kernel::new(),
206            scratch: Vec::new(),
207            duck_gains: Vec::new(),
208            activity: Vec::new(),
209        }
210    }
211
212    pub fn rate(&self) -> u32 {
213        self.rate
214    }
215
216    pub fn channels(&self) -> u16 {
217        self.channels
218    }
219
220    pub fn clock(&self) -> u64 {
221        self.clock
222    }
223
224    pub fn set_seed(&mut self, seed: u64) {
225        self.rng = Rng::new(seed);
226    }
227
228    pub fn set_master_volume(&mut self, volume: f32) {
229        self.master.volume = clamp_volume(volume);
230        retarget(&mut self.master, self.rate);
231    }
232
233    pub fn set_master_muted(&mut self, muted: bool) {
234        self.master.muted = muted;
235        retarget(&mut self.master, self.rate);
236    }
237
238    pub fn master_volume(&self) -> f32 {
239        self.master.volume
240    }
241
242    pub fn master_muted(&self) -> bool {
243        self.master.muted
244    }
245
246    pub fn set_limiter(&mut self, threshold: Option<f32>) {
247        self.limiter = threshold.map(|value| {
248            if value.is_nan() {
249                1.0
250            } else {
251                value.clamp(0.05, 0.999)
252            }
253        });
254    }
255
256    pub fn limiter(&self) -> Option<f32> {
257        self.limiter
258    }
259
260    pub fn set_channel_volume(&mut self, channel: ChannelId, volume: f32) {
261        let rate = self.rate;
262        let volume = clamp_volume(volume);
263        match self.buses.get_mut(&channel) {
264            Some(bus) => {
265                bus.volume = volume;
266                retarget(bus, rate);
267            }
268            None => {
269                let mut bus = Channel::new();
270                bus.volume = volume;
271                bus.gain.snap(volume);
272                self.buses.insert(channel, bus);
273            }
274        }
275    }
276
277    pub fn set_channel_muted(&mut self, channel: ChannelId, muted: bool) {
278        let rate = self.rate;
279        match self.buses.get_mut(&channel) {
280            Some(bus) => {
281                bus.muted = muted;
282                retarget(bus, rate);
283            }
284            None => {
285                let mut bus = Channel::new();
286                bus.muted = muted;
287                bus.gain.snap(bus.effective());
288                self.buses.insert(channel, bus);
289            }
290        }
291    }
292
293    pub fn channel_volume(&self, channel: ChannelId) -> f32 {
294        self.buses.get(&channel).map_or(1.0, |bus| bus.volume)
295    }
296
297    pub fn channel_gain(&self, channel: ChannelId) -> f32 {
298        self.buses
299            .get(&channel)
300            .map_or(1.0, |bus| bus.gain.current())
301    }
302
303    pub fn master_gain(&self) -> f32 {
304        self.master.gain.current()
305    }
306
307    pub fn channel_muted(&self, channel: ChannelId) -> bool {
308        self.buses.get(&channel).is_some_and(|bus| bus.muted)
309    }
310
311    pub fn set_channel_pitch(&mut self, channel: ChannelId, ratio: f32) {
312        self.glide_channel_pitch(channel, ratio, RAMP_SECONDS);
313    }
314
315    pub fn glide_channel_pitch(&mut self, channel: ChannelId, ratio: f32, seconds: f32) {
316        let frames = glide_frames(seconds, self.rate);
317        let ratio = clamp_ratio(ratio);
318        match self.buses.get_mut(&channel) {
319            Some(bus) => bus.pitch.to(ratio, frames),
320            None => {
321                let mut bus = Channel::new();
322                bus.pitch.snap(ratio);
323                self.buses.insert(channel, bus);
324            }
325        }
326    }
327
328    pub fn channel_pitch(&self, channel: ChannelId) -> f32 {
329        self.buses
330            .get(&channel)
331            .map_or(1.0, |bus| bus.pitch.current())
332    }
333
334    pub fn set_channel_lowpass(&mut self, channel: ChannelId, hz: Option<f32>) {
335        self.glide_channel_filter(channel, Kind::LowPass, hz, FILTER_RAMP_SECONDS);
336    }
337
338    pub fn set_channel_highpass(&mut self, channel: ChannelId, hz: Option<f32>) {
339        self.glide_channel_filter(channel, Kind::HighPass, hz, FILTER_RAMP_SECONDS);
340    }
341
342    pub fn glide_channel_lowpass(&mut self, channel: ChannelId, hz: Option<f32>, seconds: f32) {
343        self.glide_channel_filter(channel, Kind::LowPass, hz, seconds);
344    }
345
346    pub fn glide_channel_highpass(&mut self, channel: ChannelId, hz: Option<f32>, seconds: f32) {
347        self.glide_channel_filter(channel, Kind::HighPass, hz, seconds);
348    }
349
350    pub fn channel_lowpass(&self, channel: ChannelId) -> Option<f32> {
351        self.buses
352            .get(&channel)
353            .and_then(|bus| bus.lowpass.target())
354    }
355
356    pub fn channel_highpass(&self, channel: ChannelId) -> Option<f32> {
357        self.buses
358            .get(&channel)
359            .and_then(|bus| bus.highpass.target())
360    }
361
362    fn glide_channel_filter(
363        &mut self,
364        channel: ChannelId,
365        kind: Kind,
366        hz: Option<f32>,
367        seconds: f32,
368    ) {
369        let frames = glide_frames(seconds, self.rate);
370        let rate = self.rate;
371        let bus = self.buses.entry(channel).or_insert_with(Channel::new);
372        match kind {
373            Kind::LowPass => bus.lowpass.set(hz, frames, rate),
374            Kind::HighPass => bus.highpass.set(hz, frames, rate),
375        }
376    }
377
378    pub fn set_ducking(&mut self, ducking: Option<Ducking>) {
379        self.duck = ducking.map(DuckState::new);
380    }
381
382    pub fn ducking(&self) -> Option<Ducking> {
383        self.duck.as_ref().map(|state| state.config)
384    }
385
386    pub fn ducked_db(&self) -> f32 {
387        self.duck.as_ref().map_or(0.0, |state| state.reduction_db)
388    }
389
390    pub fn play(&mut self, clip: &Clip, level: Level) -> VoiceId {
391        self.play_on(ChannelId::EFFECTS, clip, level)
392    }
393
394    pub fn play_at(&mut self, at: u64, clip: &Clip, level: Level) -> VoiceId {
395        self.play_at_on(ChannelId::EFFECTS, at, clip, level)
396    }
397
398    pub fn play_on(&mut self, channel: ChannelId, clip: &Clip, level: Level) -> VoiceId {
399        self.play_at_on(channel, self.clock, clip, level)
400    }
401
402    pub fn play_at_on(
403        &mut self,
404        channel: ChannelId,
405        at: u64,
406        clip: &Clip,
407        level: Level,
408    ) -> VoiceId {
409        self.play_prepared(channel, at, clip.for_rate(self.rate), None, level)
410    }
411
412    pub fn play_music(&mut self, track: &MusicTrack, fade_seconds: f32, level: Level) -> VoiceId {
413        let looping = track.loop_frames(self.rate);
414        let clip = track.clip.for_rate(self.rate);
415        let id = self.play_prepared(ChannelId::MUSIC, self.clock, clip, looping, level);
416        self.begin_music(id, fade_seconds);
417        id
418    }
419
420    pub fn stop_music(&mut self, fade_seconds: f32) {
421        if let Some(old) = self.music.take() {
422            self.stop(old, fade_seconds);
423        }
424    }
425
426    pub fn music(&self) -> Option<VoiceId> {
427        self.music
428            .filter(|id| self.voices.iter().any(|voice| voice.id == *id))
429    }
430
431    pub fn music_position(&self) -> Option<f64> {
432        let place = self.music_place()?;
433        Some(place.frame_after(0.0) / f64::from(self.rate.max(1)))
434    }
435
436    pub(crate) fn music_place(&self) -> Option<MusicPlace> {
437        let id = self.music?;
438        let voice = self.voices.iter().find(|voice| voice.id == id)?;
439        let bounds = match &voice.source {
440            Source::Buffer {
441                frames,
442                looping: Some((start, end)),
443                ..
444            } if *end > *start => Bounds::Loop(*start, *end),
445            Source::Buffer { frames, .. } => Bounds::Once(*frames),
446            _ => Bounds::Open,
447        };
448        let played = match bounds {
449            Bounds::Loop(start, end) if voice.laps > 0 => {
450                end as f64 + (voice.laps - 1) as f64 * (end - start) as f64 + voice.cursor
451                    - start as f64
452            }
453            _ => voice.cursor,
454        };
455        let bus = self
456            .buses
457            .get(&voice.channel)
458            .map_or(1.0, |bus| bus.pitch.current());
459        let ratio = (voice.pitch.current() * bus).clamp(MIN_RATIO, MAX_RATIO);
460        Some(MusicPlace {
461            played,
462            ratio: f64::from(ratio),
463            bounds,
464        })
465    }
466
467    pub fn stop(&mut self, id: VoiceId, fade_seconds: f32) {
468        let len = seconds_to_frames(fade_seconds, self.rate);
469        let clock = self.clock;
470        if let Some(voice) = self.voices.iter_mut().find(|voice| voice.id == id) {
471            voice.ends = None;
472        }
473        if let Some(voice) = self.voices.iter_mut().find(|voice| voice.id == id)
474            && let Some(state) = voice.envelope.as_mut()
475        {
476            if voice.rendered {
477                state.release(len);
478            } else {
479                self.voices.retain(|voice| voice.id != id);
480            }
481            return;
482        }
483        if len == 0 {
484            self.voices.retain(|voice| voice.id != id);
485            return;
486        }
487        if let Some(voice) = self.voices.iter_mut().find(|voice| voice.id == id) {
488            voice.curve = Some(Curve {
489                start: clock,
490                len,
491                direction: Direction::Out,
492            });
493        }
494    }
495
496    pub fn set_volume(&mut self, id: VoiceId, volume: f32) {
497        if let Some(voice) = self.voices.iter_mut().find(|voice| voice.id == id) {
498            voice.level.volume = volume;
499        }
500    }
501
502    pub fn set_pan(&mut self, id: VoiceId, pan: f32) {
503        if let Some(voice) = self.voices.iter_mut().find(|voice| voice.id == id) {
504            voice.level.pan = pan;
505        }
506    }
507
508    pub fn set_pitch(&mut self, id: VoiceId, ratio: f32) {
509        self.glide_pitch(id, ratio, RAMP_SECONDS);
510    }
511
512    pub fn glide_pitch(&mut self, id: VoiceId, ratio: f32, seconds: f32) {
513        let frames = glide_frames(seconds, self.rate);
514        if let Some(voice) = self.voices.iter_mut().find(|voice| voice.id == id) {
515            voice.pitch.to(clamp_ratio(ratio), frames);
516        }
517    }
518
519    pub fn pitch(&self, id: VoiceId) -> Option<f32> {
520        self.voices
521            .iter()
522            .find(|voice| voice.id == id)
523            .map(|voice| voice.pitch.current())
524    }
525
526    pub fn set_resample(&mut self, id: VoiceId, resample: Resample) {
527        if let Some(voice) = self.voices.iter_mut().find(|voice| voice.id == id) {
528            voice.resample = resample;
529        }
530    }
531
532    pub fn set_gain(&mut self, id: VoiceId, gain: f32) {
533        self.glide_gain(id, gain, RAMP_SECONDS);
534    }
535
536    pub fn glide_gain(&mut self, id: VoiceId, gain: f32, seconds: f32) {
537        let frames = glide_frames(seconds, self.rate);
538        let gain = if gain.is_nan() { 0.0 } else { gain.max(0.0) };
539        if let Some(voice) = self.voices.iter_mut().find(|voice| voice.id == id) {
540            voice.gain.to(gain, frames);
541        }
542    }
543
544    pub fn tone(&mut self, channel: ChannelId, wave: Wave, hz: f32, volume: f32) -> VoiceId {
545        self.tone_in(0, channel, wave, hz, volume)
546    }
547
548    pub fn tone_in(
549        &mut self,
550        offset: u64,
551        channel: ChannelId,
552        wave: Wave,
553        hz: f32,
554        volume: f32,
555    ) -> VoiceId {
556        let level = Level {
557            volume,
558            ..Level::default()
559        };
560        let seed = self.rng.seed();
561        self.push_voice(
562            channel,
563            self.clock.saturating_add(offset),
564            Source::Tone(Synth::new(wave, hz, seed)),
565            level,
566        )
567    }
568
569    pub fn set_envelope(&mut self, id: VoiceId, envelope: Option<Envelope>) {
570        let rate = self.rate;
571        if let Some(voice) = self.voices.iter_mut().find(|voice| voice.id == id) {
572            voice.envelope = envelope.map(|envelope| EnvState::new(envelope, rate, voice.rendered));
573        }
574    }
575
576    pub fn envelope_level(&self, id: VoiceId) -> Option<f32> {
577        self.voices
578            .iter()
579            .find(|voice| voice.id == id)
580            .and_then(|voice| voice.envelope.as_ref().map(EnvState::level))
581    }
582
583    pub fn pcm_stream(
584        &mut self,
585        channel: ChannelId,
586        channels: u16,
587        capacity_seconds: f32,
588        level: Level,
589    ) -> (VoiceId, PcmSender) {
590        let capacity = seconds_to_frames(capacity_seconds, self.rate) as usize;
591        let (voice, sender) = pcm_pair(channels.max(1), capacity, self.rate);
592        let id = self.push_voice(channel, self.clock, Source::Pcm(voice), level);
593        (id, sender)
594    }
595
596    pub fn set_tone_frequency(&mut self, id: VoiceId, hz: f32) {
597        self.glide_tone_frequency(id, hz, RAMP_SECONDS);
598    }
599
600    pub fn glide_tone_frequency(&mut self, id: VoiceId, hz: f32, seconds: f32) {
601        let frames = glide_frames(seconds, self.rate);
602        let hz = if hz.is_nan() { 0.0 } else { hz.max(0.0) };
603        if let Some(voice) = self.voices.iter_mut().find(|voice| voice.id == id)
604            && let Source::Tone(synth) = &mut voice.source
605        {
606            synth.frequency.to(hz, frames);
607        }
608    }
609
610    pub fn sound(&mut self, clip: &Clip, spec: SoundSpec) -> SoundId {
611        let prepared = clip.for_rate(self.rate);
612        let frames = prepared.frames();
613        let channels = prepared.channels;
614        self.sounds.push(SoundDef {
615            body: Body::Clip {
616                samples: Arc::new(prepared.samples),
617                channels,
618                frames,
619            },
620            spec,
621        });
622        SoundId(self.sounds.len() - 1)
623    }
624
625    pub fn tone_sound(
626        &mut self,
627        wave: Wave,
628        hz: f32,
629        seconds: Option<f32>,
630        spec: SoundSpec,
631    ) -> SoundId {
632        let hz = if hz.is_nan() { 0.0 } else { hz.max(0.0) };
633        let frames = seconds.map(|seconds| seconds_to_frames(seconds, self.rate));
634        self.sounds.push(SoundDef {
635            body: Body::Tone { wave, hz, frames },
636            spec,
637        });
638        SoundId(self.sounds.len() - 1)
639    }
640
641    pub fn trigger(&mut self, sound: SoundId) -> Option<VoiceId> {
642        self.trigger_at(self.clock, sound)
643    }
644
645    pub fn trigger_in(&mut self, offset: u64, sound: SoundId) -> Option<VoiceId> {
646        self.trigger_at(self.clock.saturating_add(offset), sound)
647    }
648
649    pub fn trigger_at(&mut self, at: u64, sound: SoundId) -> Option<VoiceId> {
650        self.trigger_at_with(at, sound, 1.0)
651    }
652
653    pub fn trigger_with(&mut self, sound: SoundId, volume: f32) -> Option<VoiceId> {
654        self.trigger_at_with(self.clock, sound, volume)
655    }
656
657    pub fn trigger_in_with(&mut self, offset: u64, sound: SoundId, volume: f32) -> Option<VoiceId> {
658        self.trigger_at_with(self.clock.saturating_add(offset), sound, volume)
659    }
660
661    pub fn trigger_at_with(&mut self, at: u64, sound: SoundId, volume: f32) -> Option<VoiceId> {
662        let volume = if volume.is_nan() {
663            0.0
664        } else {
665            volume.max(0.0)
666        };
667        let spec = self.sounds.get(sound.0)?.spec;
668        if spec.max_voices == 0 {
669            return None;
670        }
671        let rate = self.rate;
672        let fade = seconds_to_frames(spec.steal_fade, rate);
673        self.make_room(sound, &spec);
674        let drawn = draw(&spec, &mut self.rng);
675        let (source, ends) = match &self.sounds[sound.0].body {
676            Body::Clip {
677                samples,
678                channels,
679                frames,
680            } => (
681                Source::Buffer {
682                    samples: Arc::clone(samples),
683                    channels: *channels,
684                    frames: *frames,
685                    looping: None,
686                },
687                None,
688            ),
689            &Body::Tone { wave, hz, frames } => (
690                Source::Tone(Synth::new(wave, hz, self.rng.seed())),
691                frames.map(|frames| (at.saturating_add(frames), fade)),
692            ),
693        };
694        let mut level = spec.level;
695        level.volume *= drawn.volume * volume;
696        let id = self.push_voice(spec.channel, at, source, level);
697        if let Some(voice) = self.voices.last_mut() {
698            voice.sound = Some(sound);
699            voice.pitch.snap(clamp_ratio(drawn.pitch));
700            voice.resample = spec.resample;
701            voice.ends = ends;
702            voice.envelope = spec
703                .envelope
704                .map(|envelope| EnvState::new(envelope, rate, false));
705        }
706        Some(id)
707    }
708
709    pub fn voices_of(&self, sound: SoundId) -> usize {
710        self.voices
711            .iter()
712            .filter(|voice| voice.sound == Some(sound) && !voice.fading())
713            .count()
714    }
715
716    pub fn voice_count(&self) -> usize {
717        self.voices.len()
718    }
719
720    fn make_room(&mut self, sound: SoundId, spec: &SoundSpec) {
721        let clock = self.clock;
722        let fade = seconds_to_frames(spec.steal_fade, self.rate);
723        let mut live = self.voices_of(sound);
724        while live >= spec.max_voices {
725            let candidates = self
726                .voices
727                .iter()
728                .enumerate()
729                .filter(|(_, voice)| voice.sound == Some(sound) && !voice.fading());
730            let pick = match spec.steal {
731                Steal::Oldest => candidates.min_by_key(|(_, voice)| (voice.start, voice.id)),
732                Steal::Quietest => candidates.min_by(|(_, a), (_, b)| {
733                    a.loudness(clock)
734                        .total_cmp(&b.loudness(clock))
735                        .then(a.id.cmp(&b.id))
736                }),
737            };
738            let Some((index, _)) = pick else {
739                break;
740            };
741            live -= 1;
742            let voice = &mut self.voices[index];
743            voice.ends = None;
744            if voice.rendered && fade > 0 {
745                voice.curve = Some(Curve {
746                    start: clock,
747                    len: fade,
748                    direction: Direction::Out,
749                });
750            } else {
751                self.voices.remove(index);
752            }
753        }
754    }
755
756    pub fn render(&mut self, frames: usize) -> Vec<f32> {
757        let len = frames.saturating_mul(self.channels as usize);
758        let mut out = vec![0.0; len];
759        self.render_into(&mut out);
760        out
761    }
762
763    pub fn render_into(&mut self, out: &mut [f32]) {
764        let out_channels = self.channels as usize;
765        let frames = out.len().checked_div(out_channels).unwrap_or(0);
766        let body = frames * out_channels;
767        out[..body].fill(0.0);
768        out[body..].fill(0.0);
769        if frames == 0 {
770            return;
771        }
772        let clock = self.clock;
773        for bus in self.buses.values_mut() {
774            bus.touched = false;
775            bus.prepare_pitch(frames);
776        }
777        self.fill_duck_gains(clock, frames);
778        for voice in &mut self.voices {
779            let Some(bus) = self.buses.get_mut(&voice.channel) else {
780                continue;
781            };
782            if !bus.touched {
783                bus.bus.clear();
784                bus.bus.resize(body, 0.0);
785                bus.touched = true;
786            }
787            let block = Block {
788                clock,
789                frames,
790                out_channels,
791                rate: self.rate,
792                kernel: &self.kernel,
793                pitch: bus.pitch_on.then_some(bus.pitch_curve.as_slice()),
794            };
795            voice.mix_into(&mut bus.bus, &block);
796        }
797        let duck_target = self.duck.as_ref().map(|state| state.config.target);
798        for (id, bus) in self.buses.iter_mut() {
799            if !bus.touched {
800                bus.gain.skip(frames);
801                bus.lowpass.idle(frames);
802                bus.highpass.idle(frames);
803                continue;
804            }
805            bus.lowpass
806                .process(&mut bus.bus, frames, out_channels, self.rate);
807            bus.highpass
808                .process(&mut bus.bus, frames, out_channels, self.rate);
809            let ducked = duck_target == Some(*id);
810            for frame in 0..frames {
811                let mut gain = bus.gain.next();
812                if ducked {
813                    gain *= self.duck_gains[frame];
814                }
815                let base = frame * out_channels;
816                for channel in 0..out_channels {
817                    out[base + channel] += bus.bus[base + channel] * gain;
818                }
819            }
820        }
821        for frame in 0..frames {
822            let gain = self.master.gain.next();
823            let base = frame * out_channels;
824            for channel in 0..out_channels {
825                out[base + channel] *= gain;
826            }
827        }
828        if let Some(threshold) = self.limiter {
829            for sample in &mut out[..body] {
830                *sample = soft_limit(*sample, threshold);
831            }
832        }
833        for sample in &mut out[..body] {
834            *sample = sample.clamp(-1.0, 1.0);
835        }
836        self.clock = self.clock.saturating_add(frames as u64);
837        let clock = self.clock;
838        self.voices.retain(|voice| !voice.finished(clock));
839    }
840
841    pub(crate) fn render_i16(&mut self, out: &mut [i16]) {
842        let channels = self.channels as usize;
843        let frames = out.len().checked_div(channels).unwrap_or(0);
844        let len = frames.saturating_mul(channels);
845        let mut scratch = std::mem::take(&mut self.scratch);
846        scratch.resize(len, 0.0);
847        self.render_into(&mut scratch);
848        for (slot, sample) in out.iter_mut().zip(scratch.iter()) {
849            *slot = (sample.clamp(-1.0, 1.0) * f32::from(i16::MAX)) as i16;
850        }
851        for slot in out.iter_mut().skip(scratch.len()) {
852            *slot = 0;
853        }
854        self.scratch = scratch;
855    }
856
857    pub(crate) fn stream(&mut self, queue: Arc<PcmQueue>, channels: u16, level: Level) -> VoiceId {
858        self.stream_on(ChannelId::EFFECTS, queue, channels, level)
859    }
860
861    pub(crate) fn stream_on(
862        &mut self,
863        channel: ChannelId,
864        queue: Arc<PcmQueue>,
865        channels: u16,
866        level: Level,
867    ) -> VoiceId {
868        self.push_voice(
869            channel,
870            self.clock,
871            Source::Stream {
872                queue,
873                channels,
874                history: History::new(),
875            },
876            level,
877        )
878    }
879
880    #[cfg_attr(not(feature = "vorbis"), allow(dead_code))]
881    pub(crate) fn stream_music(
882        &mut self,
883        queue: Arc<PcmQueue>,
884        channels: u16,
885        fade_seconds: f32,
886        level: Level,
887    ) -> VoiceId {
888        let id = self.stream_on(ChannelId::MUSIC, queue, channels, level);
889        self.begin_music(id, fade_seconds);
890        id
891    }
892
893    fn begin_music(&mut self, id: VoiceId, fade_seconds: f32) {
894        let len = seconds_to_frames(fade_seconds, self.rate);
895        let clock = self.clock;
896        if let Some(old) = self.music.replace(id) {
897            self.stop(old, fade_seconds);
898        }
899        if len > 0
900            && let Some(voice) = self.voices.iter_mut().find(|voice| voice.id == id)
901        {
902            voice.curve = Some(Curve {
903                start: clock,
904                len,
905                direction: Direction::In,
906            });
907        }
908    }
909
910    fn fill_duck_gains(&mut self, clock: u64, frames: usize) {
911        let Some(state) = self.duck.as_mut() else {
912            return;
913        };
914        self.activity.clear();
915        self.activity.resize(frames, false);
916        let end = clock + frames as u64;
917        for voice in self
918            .voices
919            .iter()
920            .filter(|voice| voice.channel == state.config.trigger)
921        {
922            let (from, to) = voice.audible_span(clock, end);
923            let from = from.max(clock);
924            let to = to.min(end);
925            for at in from..to {
926                self.activity[(at - clock) as usize] = true;
927            }
928        }
929        self.duck_gains.clear();
930        for frame in 0..frames {
931            self.duck_gains
932                .push(state.step(self.activity[frame], self.rate));
933        }
934    }
935
936    fn play_prepared(
937        &mut self,
938        channel: ChannelId,
939        at: u64,
940        clip: Clip,
941        looping: Option<(u64, u64)>,
942        level: Level,
943    ) -> VoiceId {
944        let frames = clip.frames();
945        self.push_voice(
946            channel,
947            at,
948            Source::Buffer {
949                samples: Arc::new(clip.samples),
950                channels: clip.channels,
951                frames,
952                looping,
953            },
954            level,
955        )
956    }
957
958    fn push_voice(&mut self, channel: ChannelId, at: u64, source: Source, level: Level) -> VoiceId {
959        let id = self.alloc();
960        self.buses.entry(channel).or_insert_with(Channel::new);
961        self.voices.push(Voice::new(id, channel, at, level, source));
962        id
963    }
964
965    fn alloc(&mut self) -> VoiceId {
966        self.next_id = self.next_id.saturating_add(1);
967        VoiceId(self.next_id)
968    }
969}
970
971fn retarget(channel: &mut Channel, rate: u32) {
972    let target = channel.effective();
973    channel.gain.to(target, ramp_frames(rate));
974}
975
976fn seconds_to_frames(seconds: f32, rate: u32) -> u64 {
977    if seconds.is_nan() || seconds <= 0.0 {
978        return 0;
979    }
980    (f64::from(seconds) * f64::from(rate)).round() as u64
981}
982
983fn glide_frames(seconds: f32, rate: u32) -> u32 {
984    u32::try_from(seconds_to_frames(seconds, rate))
985        .unwrap_or(u32::MAX)
986        .max(1)
987}
988
989fn clamp_ratio(ratio: f32) -> f32 {
990    if ratio.is_nan() {
991        1.0
992    } else {
993        ratio.clamp(MIN_RATIO, MAX_RATIO)
994    }
995}
996
997fn soft_limit(sample: f32, threshold: f32) -> f32 {
998    let magnitude = sample.abs();
999    if magnitude <= threshold {
1000        return sample;
1001    }
1002    let over = (magnitude - threshold) / (1.0 - threshold);
1003    let shaped = threshold + (1.0 - threshold) * over / (1.0 + over);
1004    shaped.copysign(sample)
1005}
1006
1007pub(crate) fn lock<T>(mutex: &Mutex<T>) -> MutexGuard<'_, T> {
1008    mutex.lock().unwrap_or_else(|poison| poison.into_inner())
1009}
1010
1011#[cfg(test)]
1012mod tests {
1013    use super::*;
1014    use crate::interp::tone_level;
1015
1016    fn bits(samples: &[f32]) -> Vec<u32> {
1017        samples.iter().map(|sample| sample.to_bits()).collect()
1018    }
1019
1020    fn mono(samples: &[f32]) -> Clip {
1021        Clip {
1022            rate: 48_000,
1023            channels: 1,
1024            samples: samples.to_vec(),
1025        }
1026    }
1027
1028    #[test]
1029    fn mixer_sums_and_clips() {
1030        let mut mixer = Mixer::new(48_000, 1);
1031        mixer.play(&mono(&[0.25]), Level::default());
1032        mixer.play(&mono(&[0.25]), Level::default());
1033        assert_eq!(bits(&mixer.render(1)), bits(&[0.5]));
1034
1035        let mut mixer = Mixer::new(48_000, 1);
1036        mixer.play(&mono(&[0.75]), Level::default());
1037        mixer.play(&mono(&[0.5]), Level::default());
1038        assert_eq!(bits(&mixer.render(1)), bits(&[1.0]));
1039
1040        let mut mixer = Mixer::new(48_000, 1);
1041        mixer.play(&mono(&[-0.75]), Level::default());
1042        mixer.play(&mono(&[-0.5]), Level::default());
1043        assert_eq!(bits(&mixer.render(1)), bits(&[-1.0]));
1044
1045        let mut mixer = Mixer::new(48_000, 1);
1046        mixer.play(
1047            &mono(&[1.0]),
1048            Level {
1049                volume: 2.0,
1050                ..Level::default()
1051            },
1052        );
1053        assert_eq!(bits(&mixer.render(1)), bits(&[1.0]));
1054
1055        let mut mixer = Mixer::new(48_000, 2);
1056        mixer.play(
1057            &mono(&[1.0]),
1058            Level {
1059                pan: -1.0,
1060                ..Level::default()
1061            },
1062        );
1063        mixer.play(
1064            &mono(&[1.0]),
1065            Level {
1066                pan: 1.0,
1067                ..Level::default()
1068            },
1069        );
1070        assert_eq!(bits(&mixer.render(1)), bits(&[1.0, 1.0]));
1071
1072        let mut mixer = Mixer::new(48_000, 2);
1073        mixer.play(&mono(&[1.0]), Level::default());
1074        mixer.play(&mono(&[1.0]), Level::default());
1075        assert_eq!(bits(&mixer.render(1)), bits(&[1.0, 1.0]));
1076
1077        let mut mixer = Mixer::new(48_000, 1);
1078        let id = mixer.play(&mono(&[0.5, 0.5]), Level::default());
1079        assert_eq!(bits(&mixer.render(1)), bits(&[0.5]));
1080        mixer.set_volume(id, 0.0);
1081        mixer.set_pan(id, -1.0);
1082        assert_eq!(bits(&mixer.render(1)), bits(&[0.0]));
1083        assert_eq!(bits(&mixer.render(1)), bits(&[0.0]));
1084    }
1085
1086    #[test]
1087    fn fades_ramp_at_the_start_and_the_end() {
1088        let clip = mono(&[1.0; 8]);
1089        let mut mixer = Mixer::new(48_000, 1);
1090        mixer.play(
1091            &clip,
1092            Level {
1093                fade_in: 4,
1094                ..Level::default()
1095            },
1096        );
1097        assert_eq!(
1098            bits(&mixer.render(8)),
1099            bits(&[0.0, 0.25, 0.5, 0.75, 1.0, 1.0, 1.0, 1.0])
1100        );
1101
1102        let mut mixer = Mixer::new(48_000, 1);
1103        mixer.play(
1104            &clip,
1105            Level {
1106                fade_out: 4,
1107                ..Level::default()
1108            },
1109        );
1110        assert_eq!(
1111            bits(&mixer.render(8)),
1112            bits(&[1.0, 1.0, 1.0, 1.0, 1.0, 0.75, 0.5, 0.25])
1113        );
1114
1115        let mut mixer = Mixer::new(48_000, 1);
1116        mixer.play(
1117            &mono(&[1.0; 4]),
1118            Level {
1119                fade_in: 4,
1120                fade_out: 4,
1121                ..Level::default()
1122            },
1123        );
1124        assert_eq!(bits(&mixer.render(4)), bits(&[0.0, 0.1875, 0.25, 0.1875]));
1125    }
1126
1127    #[test]
1128    fn matching_rates_play_the_samples_unchanged() {
1129        let samples = vec![0.0, 1.0, 0.0, -1.0];
1130        let clip = Clip {
1131            rate: 16_000,
1132            channels: 1,
1133            samples: samples.clone(),
1134        };
1135        let mut mixer = Mixer::new(16_000, 1);
1136        mixer.play(&clip, Level::default());
1137        assert_eq!(bits(&mixer.render(4)), bits(&samples));
1138
1139        let stereo = vec![0.1, -0.2, 0.3, -0.4, 0.5, -0.6];
1140        let clip = Clip {
1141            rate: 16_000,
1142            channels: 2,
1143            samples: stereo.clone(),
1144        };
1145        let mut mixer = Mixer::new(16_000, 2);
1146        mixer.play(&clip, Level::default());
1147        assert_eq!(bits(&mixer.render(3)), bits(&stereo));
1148    }
1149
1150    #[test]
1151    fn a_stream_plays_queued_samples_and_fades_once_it_ends() {
1152        let queue = PcmQueue::new();
1153        queue.push(&[0.25, -0.25, 0.5, -0.5]);
1154        let mut mixer = Mixer::new(48_000, 2);
1155        mixer.stream(Arc::clone(&queue), 2, Level::default());
1156        assert_eq!(bits(&mixer.render(2)), bits(&[0.25, -0.25, 0.5, -0.5]));
1157        assert_eq!(bits(&mixer.render(1)), bits(&[0.0, 0.0]));
1158
1159        let queue = PcmQueue::new();
1160        queue.push(&[1.0, 1.0, 1.0, 1.0]);
1161        let mut mixer = Mixer::new(48_000, 1);
1162        mixer.stream(
1163            Arc::clone(&queue),
1164            1,
1165            Level {
1166                fade_out: 2,
1167                ..Level::default()
1168            },
1169        );
1170        assert_eq!(bits(&mixer.render(4)), bits(&[1.0, 1.0, 1.0, 1.0]));
1171
1172        let queue = PcmQueue::new();
1173        queue.push(&[1.0, 1.0, 1.0, 1.0]);
1174        queue.end();
1175        let mut mixer = Mixer::new(48_000, 1);
1176        mixer.stream(
1177            queue,
1178            1,
1179            Level {
1180                fade_out: 2,
1181                ..Level::default()
1182            },
1183        );
1184        assert_eq!(bits(&mixer.render(2)), bits(&[1.0, 1.0]));
1185        assert_eq!(bits(&mixer.render(2)), bits(&[1.0, 0.5]));
1186    }
1187
1188    #[test]
1189    fn mixdown_bytes_are_the_sample_exact_sum() {
1190        let mut timeline = Timeline::new(48_000, 1);
1191        let clip = mono(&[0.5, 0.5, 0.5, 0.5]);
1192        timeline.place(0, clip.clone(), Level::default());
1193        timeline.place(2, clip, Level::default());
1194        let once = mixdown(&timeline);
1195        let twice = mixdown(&timeline);
1196        let expect = [0.5, 0.5, 1.0, 1.0, 0.5, 0.5];
1197        assert_eq!(bits(&once), bits(&expect));
1198        assert_eq!(bits(&once), bits(&twice));
1199        let wav_once = Clip {
1200            rate: 48_000,
1201            channels: 1,
1202            samples: once,
1203        }
1204        .to_wav();
1205        let wav_twice = Clip {
1206            rate: 48_000,
1207            channels: 1,
1208            samples: twice,
1209        }
1210        .to_wav();
1211        assert_eq!(wav_once, wav_twice);
1212    }
1213
1214    fn constant(value: f32, frames: usize) -> Clip {
1215        mono(&vec![value; frames])
1216    }
1217
1218    fn slow(value: f32, frames: usize) -> Clip {
1219        Clip {
1220            rate: 1000,
1221            channels: 1,
1222            samples: vec![value; frames],
1223        }
1224    }
1225
1226    fn sine(period: f32, amplitude: f32, frames: usize) -> Clip {
1227        mono(
1228            &(0..frames)
1229                .map(|i| amplitude * (std::f32::consts::TAU * i as f32 / period).sin())
1230                .collect::<Vec<_>>(),
1231        )
1232    }
1233
1234    fn power(samples: &[f32]) -> f32 {
1235        samples.iter().map(|sample| sample * sample).sum::<f32>() / samples.len() as f32
1236    }
1237
1238    fn decibels(ratio: f32) -> f32 {
1239        10.0 * ratio.log10()
1240    }
1241
1242    #[test]
1243    fn today_s_calls_play_on_the_effects_channel() {
1244        let mut mixer = Mixer::new(48_000, 1);
1245        mixer.play(&constant(0.5, 2000), Level::default());
1246        mixer.set_channel_volume(ChannelId::EFFECTS, 0.0);
1247        mixer.render(600);
1248        assert_eq!(mixer.render(1)[0], 0.0);
1249
1250        let mut mixer = Mixer::new(48_000, 1);
1251        mixer.play(&constant(0.5, 2000), Level::default());
1252        mixer.set_channel_volume(ChannelId::MUSIC, 0.0);
1253        mixer.set_channel_volume(ChannelId::DIALOG, 0.0);
1254        mixer.render(600);
1255        assert_eq!(mixer.render(1)[0], 0.5);
1256    }
1257
1258    #[test]
1259    fn channel_volumes_master_and_voice_level_multiply() {
1260        let mut mixer = Mixer::new(48_000, 1);
1261        mixer.set_master_volume(0.5);
1262        mixer.set_channel_volume(ChannelId::MUSIC, 0.5);
1263        mixer.set_channel_volume(ChannelId::EFFECTS, 0.25);
1264        mixer.set_channel_volume(ChannelId::DIALOG, 1.0);
1265        let half = Level {
1266            volume: 0.5,
1267            ..Level::default()
1268        };
1269        mixer.play_on(ChannelId::MUSIC, &constant(0.8, 2000), half);
1270        mixer.play_on(ChannelId::EFFECTS, &constant(0.8, 2000), Level::default());
1271        mixer.play_on(ChannelId::DIALOG, &constant(0.2, 2000), Level::default());
1272        mixer.render(700);
1273        let settled = mixer.render(1)[0];
1274        let expect = 0.5 * (0.8 * 0.5 * 0.5 + 0.8 * 0.25 + 0.2);
1275        assert!((settled - expect).abs() < 1e-6, "{settled} vs {expect}");
1276        assert_eq!(mixer.master_gain(), 0.5);
1277        assert_eq!(mixer.channel_gain(ChannelId::MUSIC), 0.5);
1278    }
1279
1280    #[test]
1281    fn a_custom_channel_has_its_own_volume() {
1282        let ui = ChannelId::custom(0);
1283        let mut mixer = Mixer::new(48_000, 1);
1284        mixer.set_channel_volume(ui, 0.25);
1285        mixer.play_on(ui, &constant(1.0, 10), Level::default());
1286        mixer.play(&constant(0.5, 10), Level::default());
1287        assert_eq!(mixer.render(1)[0], 0.75);
1288        assert_eq!(mixer.channel_volume(ui), 0.25);
1289        assert_eq!(mixer.channel_volume(ChannelId::custom(1)), 1.0);
1290    }
1291
1292    #[test]
1293    fn muting_a_channel_silences_only_that_channel() {
1294        let mut mixer = Mixer::new(48_000, 1);
1295        mixer.play_on(ChannelId::MUSIC, &constant(0.25, 4000), Level::default());
1296        mixer.play_on(ChannelId::EFFECTS, &constant(0.5, 4000), Level::default());
1297        mixer.set_channel_muted(ChannelId::MUSIC, true);
1298        assert!(mixer.channel_muted(ChannelId::MUSIC));
1299        assert_eq!(mixer.channel_volume(ChannelId::MUSIC), 1.0);
1300        mixer.render(600);
1301        assert_eq!(mixer.render(1)[0], 0.5);
1302        mixer.set_channel_muted(ChannelId::MUSIC, false);
1303        mixer.render(600);
1304        assert_eq!(mixer.render(1)[0], 0.75);
1305        mixer.set_master_muted(true);
1306        mixer.render(600);
1307        assert_eq!(mixer.render(1)[0], 0.0);
1308        assert!(mixer.master_muted());
1309    }
1310
1311    #[test]
1312    fn a_volume_change_ramps_in_steps_of_a_few_thousandths() {
1313        let mut mixer = Mixer::new(48_000, 1);
1314        mixer.play(&constant(1.0, 4000), Level::default());
1315        mixer.render(10);
1316        mixer.set_channel_volume(ChannelId::EFFECTS, 0.0);
1317        let down = mixer.render(600);
1318        mixer.set_channel_volume(ChannelId::EFFECTS, 1.0);
1319        let up = mixer.render(600);
1320        mixer.set_master_volume(0.0);
1321        let master = mixer.render(600);
1322        for run in [&down, &up, &master] {
1323            let largest = run
1324                .windows(2)
1325                .map(|pair| (pair[1] - pair[0]).abs())
1326                .fold(0.0, f32::max);
1327            assert!(largest < 0.003, "step {largest}");
1328        }
1329        assert_eq!(*down.last().unwrap(), 0.0);
1330        assert_eq!(*up.last().unwrap(), 1.0);
1331        assert!(down[0] > 0.0 && down[0] < 1.0);
1332        assert_eq!(*master.last().unwrap(), 0.0);
1333    }
1334
1335    #[test]
1336    fn the_music_position_follows_the_loop_and_unwraps_for_the_latency() {
1337        let track = MusicTrack::with_loop(constant(0.5, 1000), 200, 800);
1338        let mut mixer = Mixer::new(48_000, 1);
1339        assert_eq!(mixer.music_position(), None);
1340        mixer.play_music(&track, 0.0, Level::default());
1341        assert_eq!(mixer.music_position(), Some(0.0));
1342        mixer.render(1000);
1343        assert_eq!(mixer.music_position(), Some(400.0 / 48_000.0));
1344        let place = mixer.music_place().unwrap();
1345        assert_eq!(place.frame_after(-300.0), 700.0);
1346        assert_eq!(place.frame_after(-1200.0), 0.0);
1347        mixer.render(1200);
1348        assert_eq!(mixer.music_place().unwrap().frame_after(-300.0), 700.0);
1349        mixer.stop_music(0.0);
1350        assert_eq!(mixer.music_position(), None);
1351    }
1352
1353    #[test]
1354    fn a_loop_seam_is_as_smooth_as_the_tone_itself() {
1355        let tone = sine(100.0, 0.5, 1000);
1356        let track = MusicTrack::with_loop(tone.clone(), 200, 800);
1357        let mut mixer = Mixer::new(48_000, 1);
1358        mixer.play_music(&track, 0.0, Level::default());
1359        let out = mixer.render(3000);
1360        assert_eq!(bits(&out[..800]), bits(&tone.samples[..800]));
1361        assert_eq!(out[800].to_bits(), tone.samples[200].to_bits());
1362        assert_eq!(out[1400].to_bits(), tone.samples[200].to_bits());
1363        let intrinsic = 0.5 * std::f32::consts::TAU / 100.0;
1364        let largest = out
1365            .windows(2)
1366            .map(|pair| (pair[1] - pair[0]).abs())
1367            .fold(0.0, f32::max);
1368        assert!(largest <= intrinsic * 1.001, "{largest} vs {intrinsic}");
1369        assert!(mixer.music().is_some());
1370    }
1371
1372    #[test]
1373    fn a_track_without_a_loop_ends() {
1374        let mut mixer = Mixer::new(48_000, 1);
1375        mixer.play_music(&MusicTrack::once(constant(0.5, 4)), 0.0, Level::default());
1376        assert_eq!(
1377            bits(&mixer.render(6)),
1378            bits(&[0.5, 0.5, 0.5, 0.5, 0.0, 0.0])
1379        );
1380        assert!(mixer.music().is_none());
1381    }
1382
1383    #[test]
1384    fn a_crossfade_keeps_the_music_within_half_a_decibel() {
1385        let first = MusicTrack::looping(sine(100.0, 0.5, 4800));
1386        let second = MusicTrack::looping(sine(80.0, 0.5, 4800));
1387        let mut mixer = Mixer::new(48_000, 1);
1388        let old = mixer.play_music(&first, 0.0, Level::default());
1389        let before = mixer.render(4800);
1390        let reference = power(&before);
1391        let new = mixer.play_music(&second, 0.1, Level::default());
1392        assert_ne!(old, new);
1393        assert_eq!(mixer.music(), Some(new));
1394        let fade = mixer.render(4800);
1395        for window in fade.chunks(1200) {
1396            let drift = decibels(power(window) / reference);
1397            assert!(drift.abs() < 0.5, "{drift} dB");
1398        }
1399        assert_eq!(mixer.voices.len(), 1);
1400        let after = mixer.render(4800);
1401        assert!((decibels(power(&after) / reference)).abs() < 0.5);
1402    }
1403
1404    #[test]
1405    fn stopping_with_a_fade_ends_the_voice_at_silence() {
1406        let mut mixer = Mixer::new(1000, 1);
1407        let id = mixer.play(&slow(1.0, 5000), Level::default());
1408        mixer.render(10);
1409        mixer.stop(id, 0.1);
1410        let out = mixer.render(100);
1411        assert!(out[0] > 0.99 && out[99] < 0.05);
1412        assert!(mixer.voices.is_empty());
1413        let id = mixer.play(&slow(1.0, 5000), Level::default());
1414        mixer.stop(id, 0.0);
1415        assert_eq!(mixer.render(1)[0], 0.0);
1416    }
1417
1418    fn ducked_mixer() -> Mixer {
1419        let mut mixer = Mixer::new(1000, 1);
1420        mixer.play_music(&MusicTrack::looping(slow(0.5, 100)), 0.0, Level::default());
1421        mixer.play_at_on(ChannelId::DIALOG, 200, &slow(0.0, 500), Level::default());
1422        mixer
1423    }
1424
1425    #[test]
1426    fn ducking_is_off_until_a_game_sets_it() {
1427        let mut mixer = ducked_mixer();
1428        assert_eq!(mixer.ducking(), None);
1429        let out = mixer.render(900);
1430        assert!(out.iter().all(|sample| *sample == 0.5));
1431        assert_eq!(mixer.ducked_db(), 0.0);
1432    }
1433
1434    #[test]
1435    fn dialog_ducks_the_music_with_attack_and_release_timing() {
1436        let ducking = Ducking::dialog_over_music(12.0, 0.1, 0.2);
1437        let mut mixer = ducked_mixer();
1438        mixer.set_ducking(Some(ducking));
1439        assert_eq!(mixer.ducking(), Some(ducking));
1440        let out = mixer.render(1000);
1441        let full = 0.5 * 10f32.powf(-12.0 / 20.0);
1442        let half = 0.5 * 10f32.powf(-6.0 / 20.0);
1443        assert_eq!(out[199], 0.5);
1444        assert!(out[200] < 0.5 && out[200] > half);
1445        assert!((out[249] - half).abs() < 1e-4, "{}", out[249]);
1446        assert!((out[299] - full).abs() < 1e-4, "{}", out[299]);
1447        assert!((out[500] - full).abs() < 1e-4);
1448        assert!((out[699] - full).abs() < 1e-4);
1449        assert!((out[799] - half).abs() < 1e-4, "{}", out[799]);
1450        assert!((out[899] - 0.5).abs() < 1e-4, "{}", out[899]);
1451        assert_eq!(out[999], 0.5);
1452        let monotone = out[200..300].windows(2).all(|pair| pair[1] < pair[0]);
1453        assert!(monotone);
1454
1455        let mut blocks = ducked_mixer();
1456        blocks.set_ducking(Some(ducking));
1457        let mut pieces = Vec::new();
1458        for size in [37, 1, 150, 12, 800] {
1459            pieces.extend(blocks.render(size));
1460        }
1461        assert_eq!(bits(&pieces), bits(&out));
1462    }
1463
1464    #[test]
1465    fn ducking_only_dips_its_target_channel() {
1466        let mut mixer = ducked_mixer();
1467        mixer.set_ducking(Some(Ducking::dialog_over_music(12.0, 0.1, 0.2)));
1468        mixer.play(&slow(0.25, 1000), Level::default());
1469        let out = mixer.render(500);
1470        let full = 0.5 * 10f32.powf(-12.0 / 20.0);
1471        assert!((out[400] - (full + 0.25)).abs() < 1e-4);
1472    }
1473
1474    fn looped_sine(mixer: &mut Mixer, hz: u32, amplitude: f32) -> VoiceId {
1475        let rate = mixer.rate();
1476        let clip = Clip {
1477            rate,
1478            channels: 1,
1479            samples: (0..rate)
1480                .map(|i| {
1481                    amplitude
1482                        * (std::f64::consts::TAU * f64::from(hz) * f64::from(i) / f64::from(rate))
1483                            .sin() as f32
1484                })
1485                .collect(),
1486        };
1487        mixer.play_music(&MusicTrack::looping(clip), 0.0, Level::default())
1488    }
1489
1490    fn largest_step(samples: &[f32]) -> f32 {
1491        samples
1492            .windows(2)
1493            .map(|pair| (pair[1] - pair[0]).abs())
1494            .fold(0.0, f32::max)
1495    }
1496
1497    fn up_crossings(samples: &[f32], rate: f32) -> f32 {
1498        let mut times = Vec::new();
1499        for (i, pair) in samples.windows(2).enumerate() {
1500            if pair[0] < 0.0 && pair[1] >= 0.0 {
1501                times.push(i as f32 + pair[0].abs() / (pair[1] - pair[0]));
1502            }
1503        }
1504        let span = times[times.len() - 1] - times[0];
1505        (times.len() - 1) as f32 * rate / span
1506    }
1507
1508    #[test]
1509    fn a_voice_pitch_scales_its_frequency_and_the_channel_pitch_scales_all() {
1510        let mut mixer = Mixer::new(48_000, 1);
1511        let id = looped_sine(&mut mixer, 1000, 0.5);
1512        mixer.set_pitch(id, 1.5);
1513        mixer.render(2000);
1514        let out = mixer.render(8192);
1515        assert!(tone_level(&out, 48_000.0, 1500.0) > 0.49);
1516        assert!(tone_level(&out, 48_000.0, 1000.0) < 0.005);
1517        assert_eq!(mixer.pitch(id), Some(1.5));
1518
1519        let mut mixer = Mixer::new(48_000, 1);
1520        looped_sine(&mut mixer, 1000, 0.5);
1521        mixer.set_channel_pitch(ChannelId::MUSIC, 0.5);
1522        mixer.render(2000);
1523        let out = mixer.render(8192);
1524        assert!(tone_level(&out, 48_000.0, 500.0) > 0.49);
1525        assert_eq!(mixer.channel_pitch(ChannelId::MUSIC), 0.5);
1526        assert_eq!(mixer.channel_pitch(ChannelId::EFFECTS), 1.0);
1527    }
1528
1529    #[test]
1530    fn pitch_stays_inside_its_limits() {
1531        let mut mixer = Mixer::new(48_000, 1);
1532        let id = looped_sine(&mut mixer, 100, 0.5);
1533        mixer.set_pitch(id, 1000.0);
1534        mixer.render(1000);
1535        assert_eq!(mixer.pitch(id), Some(8.0));
1536        mixer.set_pitch(id, f32::NAN);
1537        mixer.render(1000);
1538        assert_eq!(mixer.pitch(id), Some(1.0));
1539    }
1540
1541    #[test]
1542    fn interpolated_playback_matches_the_tone_at_a_fractional_rate() {
1543        let mut mixer = Mixer::new(48_000, 1);
1544        let id = looped_sine(&mut mixer, 480, 0.5);
1545        mixer.set_pitch(id, 1.25);
1546        mixer.render(2000);
1547        let out = mixer.render(4800);
1548        let worst = out
1549            .iter()
1550            .enumerate()
1551            .map(|(i, sample)| {
1552                let t = (2000 + i) as f64 + 1.0;
1553                let _ = t;
1554                sample.abs()
1555            })
1556            .fold(0.0, f32::max);
1557        assert!((worst - 0.5).abs() < 0.01, "{worst}");
1558        assert!(tone_level(&out, 48_000.0, 600.0) > 0.495);
1559    }
1560
1561    #[test]
1562    fn pitch_rate_cutoff_and_volume_ramps_never_click() {
1563        let intrinsic = |hz: f32| 0.5 * std::f32::consts::TAU * hz / 48_000.0;
1564
1565        let mut mixer = Mixer::new(48_000, 1);
1566        let id = looped_sine(&mut mixer, 440, 0.5);
1567        mixer.render(500);
1568        mixer.glide_pitch(id, 4.0, 0.3);
1569        let up = mixer.render(20_000);
1570        mixer.glide_pitch(id, 0.25, 0.3);
1571        let down = mixer.render(20_000);
1572        assert!(
1573            largest_step(&up) <= intrinsic(1760.0) * 1.05,
1574            "{}",
1575            largest_step(&up)
1576        );
1577        assert!(
1578            largest_step(&down) <= intrinsic(1760.0) * 1.05,
1579            "{}",
1580            largest_step(&down)
1581        );
1582
1583        let mut mixer = Mixer::new(48_000, 1);
1584        looped_sine(&mut mixer, 440, 0.5);
1585        mixer.render(500);
1586        mixer.glide_channel_pitch(ChannelId::MUSIC, 3.0, 0.2);
1587        let swept = mixer.render(20_000);
1588        assert!(largest_step(&swept) <= intrinsic(1320.0) * 1.05);
1589        mixer.set_channel_pitch(ChannelId::MUSIC, 1.0);
1590        let jumped = mixer.render(2000);
1591        assert!(largest_step(&jumped) <= intrinsic(1320.0) * 1.05);
1592
1593        let mut mixer = Mixer::new(48_000, 1);
1594        looped_sine(&mut mixer, 440, 0.5);
1595        mixer.render(500);
1596        mixer.set_channel_lowpass(ChannelId::MUSIC, Some(300.0));
1597        let closing = mixer.render(4000);
1598        mixer.set_channel_highpass(ChannelId::MUSIC, Some(2000.0));
1599        let high = mixer.render(4000);
1600        mixer.set_channel_lowpass(ChannelId::MUSIC, None);
1601        mixer.set_channel_highpass(ChannelId::MUSIC, None);
1602        let opening = mixer.render(4000);
1603        for run in [&closing, &high, &opening] {
1604            eprintln!(
1605                "filter run step {} vs {}",
1606                largest_step(run),
1607                intrinsic(440.0)
1608            );
1609            assert!(
1610                largest_step(run) <= intrinsic(440.0) * 1.5,
1611                "{}",
1612                largest_step(run)
1613            );
1614        }
1615
1616        let mut mixer = Mixer::new(48_000, 1);
1617        let id = looped_sine(&mut mixer, 440, 0.5);
1618        mixer.render(500);
1619        mixer.glide_gain(id, 0.0, 0.05);
1620        let fade = mixer.render(4000);
1621        mixer.glide_gain(id, 1.0, 0.05);
1622        let back = mixer.render(4000);
1623        assert!(largest_step(&fade) <= intrinsic(440.0) * 1.1);
1624        assert!(largest_step(&back) <= intrinsic(440.0) * 1.1);
1625        assert_eq!(*fade.last().unwrap(), 0.0);
1626    }
1627
1628    #[test]
1629    fn aliasing_after_a_speed_up_is_far_below_the_tone() {
1630        let rate = 48_000.0;
1631        let cases = [
1632            (2.0, 17_000u32, 14_000.0f32),
1633            (2.0, 21_000, 6_000.0),
1634            (4.0, 11_000, 4_000.0),
1635            (4.0, 21_000, 12_000.0),
1636        ];
1637        for (ratio, source, alias) in cases {
1638            let mut mixer = Mixer::new(48_000, 1);
1639            let id = looped_sine(&mut mixer, source, 0.5);
1640            mixer.set_pitch(id, ratio);
1641            mixer.render(3000);
1642            let out = mixer.render(16_384);
1643            let level = tone_level(&out, rate, alias) / 0.5;
1644            let db = 20.0 * level.max(1e-9).log10();
1645            eprintln!("alias {ratio}x {source} Hz -> {alias} Hz: {db:.1} dB");
1646            assert!(db < -60.0, "{ratio}x {source} Hz: {db} dB");
1647        }
1648        for ratio in [2.0f32, 4.0] {
1649            let source = (3000.0 / ratio) as u32;
1650            let mut mixer = Mixer::new(48_000, 1);
1651            let id = looped_sine(&mut mixer, source, 0.5);
1652            mixer.set_pitch(id, ratio);
1653            mixer.render(3000);
1654            let out = mixer.render(16_384);
1655            let gain = tone_level(&out, rate, source as f32 * ratio) / 0.5;
1656            let db = 20.0 * gain.log10();
1657            eprintln!("passband {ratio}x: {db:.3} dB");
1658            assert!(db.abs() < 0.1, "{db}");
1659        }
1660    }
1661
1662    fn hits() -> Clip {
1663        Clip {
1664            rate: 48_000,
1665            channels: 1,
1666            samples: (0..2400)
1667                .map(|i| {
1668                    let decay = 1.0 - i as f32 / 2400.0;
1669                    0.5 * decay * (std::f32::consts::TAU * 600.0 * i as f32 / 48_000.0).sin()
1670                })
1671                .collect(),
1672        }
1673    }
1674
1675    fn burst(seed: u64, steal: Steal, limiter: Option<f32>) -> (Vec<f32>, usize) {
1676        let mut mixer = Mixer::new(48_000, 1);
1677        mixer.set_seed(seed);
1678        mixer.set_limiter(limiter);
1679        let sound = mixer.sound(
1680            &hits(),
1681            SoundSpec {
1682                max_voices: 12,
1683                steal,
1684                pitch_jitter: 3.0,
1685                volume_jitter: 0.3,
1686                ..SoundSpec::default()
1687            },
1688        );
1689        let mut out = Vec::new();
1690        let mut worst = 0;
1691        for _ in 0..48 {
1692            for _ in 0..209 {
1693                mixer.trigger(sound);
1694                assert!(mixer.voices_of(sound) <= 12);
1695            }
1696            worst = worst.max(mixer.voice_count());
1697            out.extend(mixer.render(1000));
1698        }
1699        (out, worst)
1700    }
1701
1702    #[test]
1703    fn ten_thousand_hits_in_a_second_play_a_capped_varied_set() {
1704        let (hard, worst) = burst(1, Steal::Oldest, None);
1705        assert!(worst <= 24, "{worst} voices");
1706        assert!(hard.iter().any(|sample| sample.abs() >= 1.0));
1707        let (soft, _) = burst(1, Steal::Oldest, Some(0.8));
1708        assert!(soft.iter().all(|sample| sample.abs() < 1.0));
1709        assert!(soft.iter().any(|sample| sample.abs() > 0.8));
1710        let (quiet, _) = burst(1, Steal::Quietest, Some(0.8));
1711        assert!(quiet.iter().all(|sample| sample.abs() < 1.0));
1712        assert_ne!(bits(&soft), bits(&quiet));
1713    }
1714
1715    #[test]
1716    fn the_cap_and_the_jitter_repeat_from_the_same_seed() {
1717        let (a, _) = burst(42, Steal::Oldest, Some(0.8));
1718        let (b, _) = burst(42, Steal::Oldest, Some(0.8));
1719        let (c, _) = burst(43, Steal::Oldest, Some(0.8));
1720        assert_eq!(bits(&a), bits(&b));
1721        assert_ne!(bits(&a), bits(&c));
1722
1723        let mut mixer = Mixer::new(48_000, 1);
1724        let sound = mixer.sound(
1725            &hits(),
1726            SoundSpec {
1727                pitch_jitter: 2.0,
1728                volume_jitter: 0.5,
1729                ..SoundSpec::default()
1730            },
1731        );
1732        let ids: Vec<VoiceId> = (0..50).filter_map(|_| mixer.trigger(sound)).collect();
1733        let pitches: Vec<f32> = ids.iter().filter_map(|id| mixer.pitch(*id)).collect();
1734        let low = 2f32.powf(-2.0 / 12.0);
1735        let high = 2f32.powf(2.0 / 12.0);
1736        assert!(pitches.iter().all(|p| *p >= low && *p <= high));
1737        let spread = pitches.iter().cloned().fold(0.0, f32::max)
1738            - pitches.iter().cloned().fold(f32::MAX, f32::min);
1739        assert!(spread > 0.05, "{spread}");
1740        assert_eq!(mixer.voices_of(sound), 50);
1741    }
1742
1743    #[test]
1744    fn a_full_sound_steals_its_oldest_or_its_quietest_voice() {
1745        for (steal, loud_first) in [(Steal::Oldest, true), (Steal::Quietest, true)] {
1746            let mut mixer = Mixer::new(48_000, 1);
1747            let sound = mixer.sound(
1748                &hits(),
1749                SoundSpec {
1750                    max_voices: 2,
1751                    steal,
1752                    ..SoundSpec::default()
1753                },
1754            );
1755            let first = mixer.trigger(sound).unwrap();
1756            let second = mixer.trigger(sound).unwrap();
1757            let (loud, soft) = if loud_first {
1758                (first, second)
1759            } else {
1760                (second, first)
1761            };
1762            mixer.set_volume(loud, 0.9);
1763            mixer.set_volume(soft, 0.2);
1764            mixer.render(10);
1765            let third = mixer.trigger(sound).unwrap();
1766            assert_eq!(mixer.voices_of(sound), 2);
1767            let victim = if steal == Steal::Oldest { first } else { soft };
1768            let fading: Vec<VoiceId> = mixer
1769                .voices
1770                .iter()
1771                .filter(|voice| voice.fading())
1772                .map(|voice| voice.id)
1773                .collect();
1774            assert_eq!(fading, vec![victim], "{steal:?}");
1775            assert!(mixer.voices.iter().any(|voice| voice.id == third));
1776            mixer.render(2000);
1777            assert!(mixer.voices.iter().all(|voice| voice.id != victim));
1778        }
1779        let mut mixer = Mixer::new(48_000, 1);
1780        let silent = mixer.sound(
1781            &hits(),
1782            SoundSpec {
1783                max_voices: 0,
1784                ..SoundSpec::default()
1785            },
1786        );
1787        assert!(mixer.trigger(silent).is_none());
1788    }
1789
1790    #[test]
1791    fn the_soft_limiter_is_off_by_default_and_never_reaches_full_scale() {
1792        let mut mixer = Mixer::new(48_000, 1);
1793        assert_eq!(mixer.limiter(), None);
1794        mixer.play(&constant(0.9, 4), Level::default());
1795        mixer.play(&constant(0.9, 4), Level::default());
1796        assert_eq!(bits(&mixer.render(4)), bits(&[1.0; 4]));
1797        mixer.set_limiter(Some(0.8));
1798        mixer.play(&constant(0.5, 4), Level::default());
1799        assert_eq!(mixer.render(1)[0], 0.5);
1800        mixer.render(3);
1801        mixer.play(&constant(0.9, 4), Level::default());
1802        mixer.play(&constant(0.9, 4), Level::default());
1803        mixer.play(&constant(-3.0, 4), Level::default());
1804        let out = mixer.render(1)[0];
1805        assert!(out < -0.8 && out > -1.0, "{out}");
1806        assert!(soft_limit(5.0, 0.8) < 1.0 && soft_limit(5.0, 0.8) > 0.95);
1807        assert_eq!(soft_limit(-0.3, 0.8), -0.3);
1808        let knee = soft_limit(0.8001, 0.8) - soft_limit(0.7999, 0.8);
1809        assert!((knee - 0.0002).abs() < 1e-4);
1810    }
1811
1812    fn tone_of(wave: Wave, hz: f32) -> f32 {
1813        let mut mixer = Mixer::new(48_000, 1);
1814        mixer.tone(ChannelId::EFFECTS, wave, hz, 0.5);
1815        let out = mixer.render(48_000);
1816        up_crossings(&out, 48_000.0)
1817    }
1818
1819    #[test]
1820    fn a_tone_voice_holds_its_frequency_within_a_tenth_of_a_percent() {
1821        for wave in [Wave::Sine, Wave::Square, Wave::Saw] {
1822            for hz in [110.0f32, 440.0, 1234.5, 4000.0] {
1823                let measured = tone_of(wave, hz);
1824                let error = (measured - hz).abs() / hz;
1825                assert!(error < 0.001, "{wave:?} {hz} Hz measured {measured}");
1826            }
1827        }
1828        let mut mixer = Mixer::new(48_000, 1);
1829        let id = mixer.tone(ChannelId::EFFECTS, Wave::Saw, 300.0, 0.5);
1830        mixer.set_pitch(id, 2.0);
1831        mixer.render(2000);
1832        let out = mixer.render(48_000);
1833        let measured = up_crossings(&out, 48_000.0);
1834        assert!((measured - 600.0).abs() / 600.0 < 0.001, "{measured}");
1835    }
1836
1837    #[test]
1838    fn a_tone_is_band_limited_and_bounded() {
1839        let mut mixer = Mixer::new(48_000, 1);
1840        mixer.tone(ChannelId::EFFECTS, Wave::Saw, 2000.0, 1.0);
1841        let out = mixer.render(16_384);
1842        assert!(out.iter().all(|sample| sample.abs() <= 1.0));
1843        let alias = tone_level(&out, 48_000.0, 20_000.0);
1844        let partial = tone_level(&out, 48_000.0, 2000.0);
1845        assert!(alias < 0.1 * partial, "{alias} vs {partial}");
1846        assert!(
1847            (partial - 2.0 / std::f32::consts::PI).abs() < 0.05,
1848            "{partial}"
1849        );
1850
1851        let mut mixer = Mixer::new(48_000, 1);
1852        mixer.tone(ChannelId::EFFECTS, Wave::Sine, 1000.0, 0.5);
1853        let out = mixer.render(8192);
1854        assert!((tone_level(&out, 48_000.0, 1000.0) - 0.5).abs() < 0.005);
1855    }
1856
1857    #[test]
1858    fn a_driven_tone_glides_and_fades_without_clicks() {
1859        let mut mixer = Mixer::new(48_000, 1);
1860        let id = mixer.tone(ChannelId::EFFECTS, Wave::Sine, 200.0, 1.0);
1861        mixer.render(1000);
1862        mixer.glide_tone_frequency(id, 2000.0, 0.5);
1863        let rising = mixer.render(30_000);
1864        assert!(largest_step(&rising) <= std::f32::consts::TAU * 2000.0 / 48_000.0 * 1.01);
1865        let settled = mixer.render(8192);
1866        assert!(tone_level(&settled, 48_000.0, 2000.0) > 0.99);
1867        mixer.glide_gain(id, 0.0, 0.05);
1868        let fade = mixer.render(4000);
1869        assert!(largest_step(&fade) <= std::f32::consts::TAU * 2000.0 / 48_000.0 * 1.01);
1870        assert_eq!(*fade.last().unwrap(), 0.0);
1871        mixer.stop(id, 0.01);
1872        mixer.render(1000);
1873        assert_eq!(mixer.voice_count(), 0);
1874    }
1875
1876    fn filtered_gain(low: bool, cutoff: f32) -> f32 {
1877        let mut mixer = Mixer::new(48_000, 1);
1878        looped_sine(&mut mixer, cutoff as u32, 0.5);
1879        if low {
1880            mixer.set_channel_lowpass(ChannelId::MUSIC, Some(cutoff));
1881        } else {
1882            mixer.set_channel_highpass(ChannelId::MUSIC, Some(cutoff));
1883        }
1884        mixer.render(8000);
1885        let out = mixer.render(9600);
1886        tone_level(&out, 48_000.0, cutoff) / 0.5
1887    }
1888
1889    #[test]
1890    fn the_filters_are_three_decibels_down_at_their_cutoff() {
1891        for cutoff in [200.0f32, 1000.0, 5000.0] {
1892            for low in [true, false] {
1893                let gain = filtered_gain(low, cutoff);
1894                let db = 20.0 * gain.log10();
1895                assert!((db + 3.01).abs() < 0.5, "low {low} {cutoff} Hz: {db} dB");
1896            }
1897        }
1898    }
1899
1900    #[test]
1901    fn the_filters_pass_and_stop_either_side_of_the_cutoff() {
1902        let response = |low: bool, cutoff: f32, tone: u32| {
1903            let mut mixer = Mixer::new(48_000, 1);
1904            looped_sine(&mut mixer, tone, 0.5);
1905            if low {
1906                mixer.set_channel_lowpass(ChannelId::MUSIC, Some(cutoff));
1907            } else {
1908                mixer.set_channel_highpass(ChannelId::MUSIC, Some(cutoff));
1909            }
1910            mixer.render(8000);
1911            let out = mixer.render(9600);
1912            tone_level(&out, 48_000.0, tone as f32) / 0.5
1913        };
1914        assert!(response(true, 2000.0, 200) > 0.99);
1915        assert!(response(true, 2000.0, 8000) < 0.1);
1916        assert!(response(false, 2000.0, 8000) > 0.99);
1917        assert!(response(false, 2000.0, 200) < 0.1);
1918
1919        let mut mixer = Mixer::new(48_000, 1);
1920        assert_eq!(mixer.channel_lowpass(ChannelId::MUSIC), None);
1921        mixer.set_channel_lowpass(ChannelId::MUSIC, Some(800.0));
1922        mixer.set_channel_highpass(ChannelId::MUSIC, Some(100.0));
1923        assert_eq!(mixer.channel_lowpass(ChannelId::MUSIC), Some(800.0));
1924        assert_eq!(mixer.channel_highpass(ChannelId::MUSIC), Some(100.0));
1925        mixer.set_channel_lowpass(ChannelId::MUSIC, None);
1926        assert_eq!(mixer.channel_lowpass(ChannelId::MUSIC), None);
1927    }
1928
1929    #[test]
1930    fn a_closed_filter_leaves_the_audio_bit_for_bit_alone() {
1931        let plain = {
1932            let mut mixer = Mixer::new(48_000, 1);
1933            looped_sine(&mut mixer, 440, 0.5);
1934            mixer.render(3000)
1935        };
1936        let mut mixer = Mixer::new(48_000, 1);
1937        looped_sine(&mut mixer, 440, 0.5);
1938        mixer.set_channel_lowpass(ChannelId::MUSIC, Some(300.0));
1939        mixer.render(10);
1940        mixer.set_channel_lowpass(ChannelId::MUSIC, None);
1941        mixer.render(2000);
1942        let after = mixer.render(1000);
1943        let clean = {
1944            let mut mixer = Mixer::new(48_000, 1);
1945            looped_sine(&mut mixer, 440, 0.5);
1946            mixer.render(2010);
1947            mixer.render(1000)
1948        };
1949        assert_eq!(bits(&after), bits(&clean));
1950        assert_eq!(plain.len(), 3000);
1951    }
1952
1953    #[test]
1954    fn a_stream_plays_faster_when_its_pitch_rises() {
1955        let queue = PcmQueue::new();
1956        queue.push(&vec![0.5; 400]);
1957        queue.end();
1958        let mut mixer = Mixer::new(48_000, 1);
1959        let id = mixer.stream(Arc::clone(&queue), 1, Level::default());
1960        mixer.set_pitch(id, 2.0);
1961        mixer.render(480);
1962        let out = mixer.render(400);
1963        let heard = out.iter().filter(|sample| sample.abs() > 0.01).count();
1964        assert!(heard < 40, "{heard}");
1965        assert_eq!(mixer.voice_count(), 0);
1966
1967        let queue = PcmQueue::new();
1968        queue.push(&vec![0.5; 4000]);
1969        queue.end();
1970        let mut mixer = Mixer::new(48_000, 1);
1971        let id = mixer.stream(queue, 1, Level::default());
1972        mixer.set_pitch(id, 0.5);
1973        mixer.render(480);
1974        let out = mixer.render(1000);
1975        assert!(out.iter().all(|sample| (sample - 0.5).abs() < 0.01));
1976    }
1977
1978    fn plain_hits() -> Clip {
1979        Clip {
1980            rate: 48_000,
1981            channels: 2,
1982            samples: (0..4800)
1983                .map(|i| {
1984                    let frame = i / 2;
1985                    let decay = 1.0 - frame as f32 / 2400.0;
1986                    let phase = (frame % 80) as f32 / 80.0;
1987                    let side = if i % 2 == 0 { 0.5 } else { 0.4 };
1988                    side * decay * (1.0 - 4.0 * (phase - 0.5).abs())
1989                })
1990                .collect(),
1991        }
1992    }
1993
1994    fn fnv(samples: &[f32]) -> u64 {
1995        samples
1996            .iter()
1997            .fold(0xcbf2_9ce4_8422_2325u64, |hash, sample| {
1998                (hash ^ u64::from(sample.to_bits())).wrapping_mul(0x0100_0000_01b3)
1999            })
2000    }
2001
2002    fn hit_spec() -> SoundSpec {
2003        SoundSpec {
2004            max_voices: 6,
2005            pitch_jitter: 2.0,
2006            volume_jitter: 0.25,
2007            ..SoundSpec::default()
2008        }
2009    }
2010
2011    #[test]
2012    fn sine_tones_and_jittered_hits_keep_their_bits_on_every_platform() {
2013        let mut mixer = Mixer::new(48_000, 2);
2014        mixer.set_seed(9);
2015        mixer.tone(ChannelId::EFFECTS, Wave::Sine, 440.0, 0.5);
2016        let beep = mixer.tone_sound(Wave::Sine, 700.0, Some(0.02), hit_spec());
2017        let hit = mixer.sound(&plain_hits(), hit_spec());
2018        let mut out = Vec::new();
2019        for tick in 0..60u64 {
2020            for k in 0..9 {
2021                mixer.trigger_in(k * 88, hit);
2022            }
2023            if tick % 3 == 0 {
2024                mixer.trigger_in(tick % 400, beep);
2025            }
2026            out.extend(mixer.render(800));
2027        }
2028        assert_eq!(fnv(&out), 12_859_396_616_140_308_833);
2029    }
2030
2031    #[test]
2032    fn a_tone_or_a_hit_starts_at_its_frame_offset_inside_the_block() {
2033        let mut reference = Mixer::new(48_000, 1);
2034        reference.tone(ChannelId::EFFECTS, Wave::Saw, 330.0, 0.5);
2035        let want = reference.render(2000);
2036        let mut mixer = Mixer::new(48_000, 1);
2037        mixer.render(100);
2038        mixer.tone_in(37, ChannelId::EFFECTS, Wave::Saw, 330.0, 0.5);
2039        let mut got = mixer.render(800);
2040        got.extend(mixer.render(800));
2041        assert!(got[..37].iter().all(|sample| *sample == 0.0));
2042        assert_eq!(bits(&got[37..]), bits(&want[..1600 - 37]));
2043
2044        let mut reference = Mixer::new(48_000, 2);
2045        reference.set_seed(5);
2046        let hit = reference.sound(&plain_hits(), hit_spec());
2047        reference.trigger(hit);
2048        let want = reference.render(2000);
2049        let mut mixer = Mixer::new(48_000, 2);
2050        mixer.set_seed(5);
2051        let hit = mixer.sound(&plain_hits(), hit_spec());
2052        mixer.trigger_in(900, hit);
2053        let mut got = mixer.render(800);
2054        got.extend(mixer.render(800));
2055        assert!(got[..1800].iter().all(|sample| *sample == 0.0));
2056        assert_eq!(bits(&got[1800..]), bits(&want[..1400]));
2057    }
2058
2059    #[test]
2060    fn tone_sounds_share_the_cap_stealing_and_jitter_of_clip_sounds() {
2061        let mut mixer = Mixer::new(48_000, 1);
2062        let beep = mixer.tone_sound(
2063            Wave::Sine,
2064            500.0,
2065            Some(0.01),
2066            SoundSpec {
2067                max_voices: 2,
2068                pitch_jitter: 2.0,
2069                ..SoundSpec::default()
2070            },
2071        );
2072        let first = mixer.trigger(beep).unwrap();
2073        let second = mixer.trigger(beep).unwrap();
2074        mixer.render(10);
2075        let third = mixer.trigger(beep).unwrap();
2076        assert_eq!(mixer.voices_of(beep), 2);
2077        let fading: Vec<VoiceId> = mixer
2078            .voices
2079            .iter()
2080            .filter(|voice| voice.fading())
2081            .map(|voice| voice.id)
2082            .collect();
2083        assert_eq!(fading, vec![first]);
2084        let pitches = [mixer.pitch(second).unwrap(), mixer.pitch(third).unwrap()];
2085        assert_ne!(pitches[0], pitches[1]);
2086        let low = 2f32.powf(-2.0 / 12.0) * 0.999;
2087        let high = 2f32.powf(2.0 / 12.0) * 1.001;
2088        assert!(pitches.iter().all(|p| *p > low && *p < high));
2089        let out = mixer.render(1000);
2090        assert_eq!(mixer.voice_count(), 0);
2091        assert!(out[700..].iter().all(|sample| *sample == 0.0));
2092    }
2093}