Skip to content

Commit

Permalink
Remove superfluous interior mutability
Browse files Browse the repository at this point in the history
  • Loading branch information
Ralith committed Sep 30, 2023
1 parent 9c860c9 commit 73eac23
Show file tree
Hide file tree
Showing 12 changed files with 109 additions and 143 deletions.
11 changes: 4 additions & 7 deletions src/adapt.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
use core::cell::Cell;

use crate::{math::Float, Frame, Signal};

/// Smoothly adjusts gain over time to keep average (RMS) signal level within a target range
Expand All @@ -15,7 +13,7 @@ use crate::{math::Float, Frame, Signal};
/// perception of loudness is logarithmic.
pub struct Adapt<T: ?Sized> {
options: AdaptOptions,
avg_squared: Cell<f32>,
avg_squared: f32,
inner: T,
}

Expand All @@ -27,7 +25,7 @@ impl<T> Adapt<T> {
pub fn new(signal: T, initial_rms: f32, options: AdaptOptions) -> Self {
Self {
options,
avg_squared: Cell::new(initial_rms * initial_rms),
avg_squared: initial_rms * initial_rms,
inner: signal,
}
}
Expand Down Expand Up @@ -73,9 +71,8 @@ where
self.inner.sample(interval, out);
for x in out {
let sample = x.channels().iter().sum::<f32>();
self.avg_squared
.set(sample * sample * alpha + self.avg_squared.get() * (1.0 - alpha));
let avg_peak = self.avg_squared.get().sqrt() * 2.0f32.sqrt();
self.avg_squared = sample * sample * alpha + self.avg_squared * (1.0 - alpha);
let avg_peak = self.avg_squared.sqrt() * 2.0f32.sqrt();
let gain = if avg_peak < self.options.low {
(self.options.low / avg_peak).min(self.options.max_gain)
} else if avg_peak > self.options.high {
Expand Down
14 changes: 6 additions & 8 deletions src/cycle.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
use alloc::sync::Arc;
use core::cell::Cell;

use crate::{frame, math::Float, Frame, Frames, Seek, Signal};

/// Loops [`Frames`] end-to-end to construct a repeating signal
pub struct Cycle<T> {
/// Current playback time, in samples
cursor: Cell<f64>,
cursor: f64,
frames: Arc<Frames<T>>,
}

Expand All @@ -15,7 +14,7 @@ impl<T> Cycle<T> {
// TODO: Crossfade
pub fn new(frames: Arc<Frames<T>>) -> Self {
Self {
cursor: Cell::new(0.0),
cursor: 0.0,
frames,
}
}
Expand All @@ -26,8 +25,8 @@ impl<T: Frame + Copy> Signal for Cycle<T> {

fn sample(&mut self, interval: f32, out: &mut [T]) {
let ds = interval * self.frames.rate() as f32;
let mut base = self.cursor.get() as usize;
let mut offset = (self.cursor.get() - base as f64) as f32;
let mut base = self.cursor as usize;
let mut offset = (self.cursor - base as f64) as f32;
for o in out {
let trunc = unsafe { offset.to_int_unchecked::<usize>() };
let fract = offset - trunc as f32;
Expand All @@ -50,15 +49,14 @@ impl<T: Frame + Copy> Signal for Cycle<T> {
*o = frame::lerp(&a, &b, fract);
offset += ds;
}
self.cursor.set(base as f64 + offset as f64);
self.cursor = base as f64 + offset as f64;
}
}

impl<T: Frame + Copy> Seek for Cycle<T> {
fn seek(&mut self, seconds: f32) {
let s = (self.cursor.get() + f64::from(seconds) * self.frames.rate() as f64)
self.cursor = (self.cursor + f64::from(seconds) * self.frames.rate() as f64)
.rem_euclid(self.frames.len() as f64);
self.cursor.set(s);
}
}

Expand Down
34 changes: 14 additions & 20 deletions src/fader.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
use alloc::sync::Arc;
use core::{
cell::{Cell, UnsafeCell},
mem,
};
use core::mem;

use crate::{frame, math::Float, Frame, Signal, Swap};

Expand All @@ -11,18 +8,18 @@ use crate::{frame, math::Float, Frame, Signal, Swap};
/// Uses constant-power fading, suitable for blending uncorrelated signals without distorting
/// perceived loudness
pub struct Fader<T> {
progress: Cell<f32>,
inner: UnsafeCell<T>,
progress: f32,
next: Arc<Swap<Option<Command<T>>>>,
inner: T,
}

impl<T> Fader<T> {
/// Create a fader initially wrapping `inner`
pub fn new(inner: T) -> (FaderControl<T>, Self) {
let signal = Self {
progress: Cell::new(1.0),
inner: UnsafeCell::new(inner),
progress: 1.0,
next: Arc::new(Swap::new(|| None)),
inner,
};
let control = FaderControl(signal.next.clone());
(control, signal)
Expand All @@ -37,15 +34,13 @@ where

#[allow(clippy::float_cmp)]
fn sample(&mut self, interval: f32, mut out: &mut [T::Frame]) {
let inner = unsafe { &mut *self.inner.get() };

if self.progress.get() >= 1.0 {
if self.progress >= 1.0 {
// A fade must complete before a new one begins
if self.next.refresh() {
self.progress.set(0.0);
self.progress = 0.0;
} else {
// Fast path
inner.sample(interval, out);
self.inner.sample(interval, out);
return;
}
}
Expand All @@ -55,23 +50,22 @@ where
while !out.is_empty() {
let mut buffer = [(); 1024].map(|()| T::Frame::ZERO);
let n = buffer.len().min(out.len());
inner.sample(interval, &mut buffer);
self.inner.sample(interval, &mut buffer);
next.fade_to.sample(interval, out);

for (o, x) in out.iter_mut().zip(&buffer) {
let fade_out = (1.0 - self.progress.get()).sqrt();
let fade_in = self.progress.get().sqrt();
let fade_out = (1.0 - self.progress).sqrt();
let fade_in = self.progress.sqrt();
*o = frame::mix(&frame::scale(x, fade_out), &frame::scale(o, fade_in));
self.progress
.set((self.progress.get() + increment).min(1.0));
self.progress = (self.progress + increment).min(1.0);
}
out = &mut out[n..];
}

if self.progress.get() >= 1.0 {
if self.progress >= 1.0 {
// We've finished fading; move the new signal into `self`, and stash the old one back in
// `next` to be dropped by a future `fade_to` call.
mem::swap(inner, &mut next.fade_to);
mem::swap(&mut self.inner, &mut next.fade_to);
}
}

Expand Down
16 changes: 7 additions & 9 deletions src/frames.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
use crate::alloc::{alloc, boxed::Box, sync::Arc};
use core::{
cell::Cell,
mem,
ops::{Deref, DerefMut},
ptr,
Expand Down Expand Up @@ -142,7 +141,7 @@ pub struct FramesSignal<T> {
/// Frames to play
data: Arc<Frames<T>>,
/// Playback position in seconds
t: Cell<f64>,
t: f64,
/// Approximation of t in samples, for reading from the control. We could store t's bits in an
/// AtomicU64 here, but that would sacrifice portability to platforms that don't have it,
/// e.g. mips32.
Expand All @@ -155,7 +154,7 @@ impl<T> FramesSignal<T> {
/// `start_seconds` adjusts the initial playback position, and may be negative.
pub fn new(data: Arc<Frames<T>>, start_seconds: f64) -> (FramesSignalControl, Self) {
let signal = Self {
t: Cell::new(start_seconds),
t: start_seconds,
sample_t: Arc::new(AtomicIsize::new((start_seconds * data.rate) as isize)),
data,
};
Expand All @@ -169,7 +168,7 @@ impl<T: Frame + Copy> Signal for FramesSignal<T> {

#[inline]
fn sample(&mut self, interval: f32, out: &mut [T]) {
let s0 = self.t.get() * self.data.rate;
let s0 = self.t * self.data.rate;
let ds = interval * self.data.rate as f32;
let base = s0 as isize;
if (ds - 1.0).abs() <= f32::EPSILON {
Expand All @@ -190,22 +189,21 @@ impl<T: Frame + Copy> Signal for FramesSignal<T> {
offset += ds;
}
}
self.t
.set(self.t.get() + f64::from(interval) * out.len() as f64);
self.t += f64::from(interval) * out.len() as f64;
self.sample_t
.store((self.t.get() * self.data.rate) as isize, Ordering::Relaxed);
.store((self.t * self.data.rate) as isize, Ordering::Relaxed);
}

#[inline]
fn is_finished(&self) -> bool {
self.t.get() >= self.data.samples.len() as f64 / self.data.rate
self.t >= self.data.samples.len() as f64 / self.data.rate
}
}

impl<T: Frame + Copy> Seek for FramesSignal<T> {
#[inline]
fn seek(&mut self, seconds: f32) {
self.t.set(self.t.get() + f64::from(seconds));
self.t += f64::from(seconds);
}
}

Expand Down
24 changes: 10 additions & 14 deletions src/gain.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
use alloc::sync::Arc;
use core::{
cell::RefCell,
sync::atomic::{AtomicU32, Ordering},
};
use core::sync::atomic::{AtomicU32, Ordering};

use crate::{frame, math::Float, Frame, Seek, Signal, Smoothed};

Expand Down Expand Up @@ -60,7 +57,7 @@ where
/// mapping the maximum volume to 0 decibels, and the minimum to e.g. -60.
pub struct Gain<T: ?Sized> {
shared: Arc<AtomicU32>,
gain: RefCell<Smoothed<f32>>,
gain: Smoothed<f32>,
inner: T,
}

Expand All @@ -69,7 +66,7 @@ impl<T> Gain<T> {
pub fn new(signal: T) -> (GainControl, Self) {
let signal = Gain {
shared: Arc::new(AtomicU32::new(1.0f32.to_bits())),
gain: RefCell::new(Smoothed::new(1.0)),
gain: Smoothed::new(1.0),
inner: signal,
};
let handle = GainControl(signal.shared.clone());
Expand All @@ -92,7 +89,7 @@ impl<T> Gain<T> {
/// needed, or even have its phase inverted with a negative factor.
pub fn set_amplitude_ratio(&mut self, factor: f32) {
self.shared.store(factor.to_bits(), Ordering::Relaxed);
*self.gain.get_mut() = Smoothed::new(factor);
self.gain = Smoothed::new(factor);
}
}

Expand All @@ -106,12 +103,11 @@ where
fn sample(&mut self, interval: f32, out: &mut [T::Frame]) {
self.inner.sample(interval, out);
let shared = f32::from_bits(self.shared.load(Ordering::Relaxed));
let mut gain = self.gain.borrow_mut();
if gain.target() != &shared {
gain.set(shared);
if self.gain.target() != &shared {
self.gain.set(shared);
}
if gain.progress() == 1.0 {
let g = gain.get();
if self.gain.progress() == 1.0 {
let g = self.gain.get();
if g != 1.0 {
for x in out {
*x = frame::scale(x, g);
Expand All @@ -120,8 +116,8 @@ where
return;
}
for x in out {
*x = frame::scale(x, gain.get());
gain.advance(interval / SMOOTHING_PERIOD);
*x = frame::scale(x, self.gain.get());
self.gain.advance(interval / SMOOTHING_PERIOD);
}
}

Expand Down
13 changes: 5 additions & 8 deletions src/mixer.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
use alloc::{boxed::Box, sync::Arc, vec};
use core::{
cell::RefCell,
sync::atomic::{AtomicBool, Ordering},
};
use core::sync::atomic::{AtomicBool, Ordering};

use crate::{frame, set, Frame, Set, SetHandle, Signal};

Expand Down Expand Up @@ -55,7 +52,7 @@ impl<T> MixedSignal<T> {

/// A [`Signal`] that mixes a dynamic set of [`Signal`]s
pub struct Mixer<T> {
recv: RefCell<Inner<T>>,
recv: Inner<T>,
}

impl<T> Mixer<T>
Expand All @@ -68,10 +65,10 @@ where
(
MixerControl(handle),
Self {
recv: RefCell::new(Inner {
recv: Inner {
set,
buffer: vec![T::ZERO; 1024].into(),
}),
},
},
)
}
Expand All @@ -86,7 +83,7 @@ impl<T: Frame> Signal for Mixer<T> {
type Frame = T;

fn sample(&mut self, interval: f32, out: &mut [T]) {
let this = &mut *self.recv.borrow_mut();
let this = &mut self.recv;
this.set.update();

for o in out.iter_mut() {
Expand Down
12 changes: 5 additions & 7 deletions src/ring.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,19 +81,17 @@ impl Ring {

#[cfg(test)]
mod tests {
use core::cell::Cell;

use super::*;

struct TimeSignal(Cell<f32>);
struct TimeSignal(f32);

impl Signal for TimeSignal {
type Frame = Sample;
fn sample(&mut self, interval: f32, out: &mut [Sample]) {
for x in out {
let t = self.0.get();
let t = self.0;
*x = t as f32;
self.0.set(t + interval);
self.0 = t + interval;
}
}
}
Expand All @@ -107,7 +105,7 @@ mod tests {
#[test]
fn fill() {
let mut r = Ring::new(4);
let mut s = TimeSignal(Cell::new(1.0));
let mut s = TimeSignal(1.0);

r.write(&mut s, 1, 1.0);
assert_eq!(r.write, 1.0);
Expand All @@ -124,7 +122,7 @@ mod tests {
#[test]
fn wrap() {
let mut r = Ring::new(4);
let mut s = TimeSignal(Cell::new(1.0));
let mut s = TimeSignal(1.0);

r.write(&mut s, 1, 3.0);
assert_eq!(r.buffer[..], [1.0, 2.0, 3.0, 0.0]);
Expand Down
Loading

0 comments on commit 73eac23

Please sign in to comment.