use rodio::{ChannelCount, DeviceSinkBuilder, MixerDeviceSink, Sample, SampleRate, Source};
use std::alloc::{self, GlobalAlloc, Layout};
use std::cell::Cell;
use std::fmt;
use std::sync::atomic::AtomicBool;
use std::sync::atomic::Ordering;
use std::sync::{Arc, Barrier, OnceLock};
use std::time::Duration;
#[derive(Default)]
pub struct Geiger<Alloc> {
inner: Alloc,
sink_handle: OnceLock<Option<MixerDeviceSink>>,
init: AtomicBool,
}
impl<Alloc: fmt::Debug> fmt::Debug for Geiger<Alloc> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Geiger")
.field("inner", &self.inner)
.finish_non_exhaustive()
}
}
pub type System = Geiger<alloc::System>;
thread_local! {
static BUSY: Cell<bool> = const { Cell::new(false) };
}
impl System {
pub const fn new() -> Self {
Geiger::with_alloc(alloc::System)
}
}
impl<Alloc> Geiger<Alloc> {
pub const fn with_alloc(inner: Alloc) -> Self {
Geiger {
inner,
sink_handle: OnceLock::new(),
init: AtomicBool::new(false),
}
}
fn bell(&self) {
BUSY.with(|busy| {
if !busy.replace(true) {
if let Some(handle) = self.get_handle() {
handle.mixer().add(Pulse::new());
}
busy.set(false);
}
});
}
fn get_handle(&self) -> &Option<MixerDeviceSink> {
if let Some(handle) = self.sink_handle.get() {
handle
} else if !self.init.swap(true, Ordering::AcqRel) {
self.sink_handle.get_or_init(rodio_init)
} else {
&None
}
}
}
unsafe impl<Alloc: GlobalAlloc> GlobalAlloc for Geiger<Alloc> {
#[inline]
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
self.bell();
unsafe { self.inner.alloc(layout) }
}
#[inline]
unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
self.bell();
unsafe { self.inner.alloc_zeroed(layout) }
}
#[inline]
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
self.bell();
unsafe { self.inner.dealloc(ptr, layout) }
}
#[inline]
unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
self.bell();
unsafe { self.inner.realloc(ptr, layout, new_size) }
}
}
fn rodio_init() -> Option<MixerDeviceSink> {
let mut sink_handle = DeviceSinkBuilder::open_default_sink().ok()?;
sink_handle.log_on_drop(false);
let (source, barrier) = BusySource::new();
sink_handle.mixer().add(source);
barrier.wait();
Some(sink_handle)
}
struct BusySource {
busy_address: usize,
barrier: Option<Arc<Barrier>>,
}
impl BusySource {
fn new() -> (Self, Arc<Barrier>) {
let barrier = Arc::new(Barrier::new(2));
let source = BusySource {
busy_address: BUSY.with(|busy| busy as *const _ as usize),
barrier: Some(Arc::clone(&barrier)),
};
(source, barrier)
}
}
impl Iterator for BusySource {
type Item = Sample;
fn next(&mut self) -> Option<Self::Item> {
BUSY.with(|busy| {
if self.busy_address == busy as *const _ as usize {
Some(0.0)
} else {
busy.set(true);
self.barrier.take()?.wait();
None
}
})
}
}
impl Source for BusySource {
fn channels(&self) -> ChannelCount {
const { ChannelCount::new(1).unwrap() }
}
fn sample_rate(&self) -> SampleRate {
const { SampleRate::new(100).unwrap() }
}
fn current_span_len(&self) -> Option<usize> {
None
}
fn total_duration(&self) -> Option<Duration> {
None
}
}
struct Pulse {
iter: std::slice::Iter<'static, Sample>,
}
impl Pulse {
fn new() -> Self {
Pulse { iter: PULSE.iter() }
}
}
impl Iterator for Pulse {
type Item = Sample;
fn next(&mut self) -> Option<Self::Item> {
Some(Sample::from(*self.iter.next()?))
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}
}
impl Source for Pulse {
fn channels(&self) -> ChannelCount {
const { ChannelCount::new(1).unwrap() }
}
fn sample_rate(&self) -> SampleRate {
const { SampleRate::new(48_000).unwrap() }
}
fn current_span_len(&self) -> Option<usize> {
None
}
fn total_duration(&self) -> Option<Duration> {
None
}
}
#[rustfmt::skip]
static PULSE: [f32; 97] = [
1.3913767e-8, -0.010158828, -0.017978106, -0.02122066, -0.018795315, -0.011103839,
-3.017612e-8, 0.011645474, 0.020674838, 0.024485376, 0.02176298, 0.0129044745,
1.2652691e-9, -0.013641826, -0.02432333, -0.02893726, -0.025843548, -0.015402081,
-2.1502865e-8, 0.016464282, 0.02953546, 0.035367765, 0.031807438, 0.019098602, 1.3913767e-8,
-0.020759324, -0.037590593, -0.045472838, -0.041349664, -0.025129724, -1.2652691e-9,
0.02808616, 0.051687073, 0.06366198, 0.059070963, 0.03672807, 1.3913767e-8, -0.04340587,
-0.08269934, -0.10610329, -0.10337417, -0.06820928, -1.3913767e-8, 0.09549298, 0.20674832,
0.31830987, 0.41349667, 0.47746482, 0.5, 0.47746482, 0.41349667, 0.31830987, 0.20674832,
0.09549298, -1.3913767e-8, -0.06820928, -0.10337417, -0.10610329, -0.08269934, -0.04340587,
1.3913767e-8, 0.03672807, 0.059070963, 0.06366198, 0.051687073, 0.02808616, -1.2652691e-9,
-0.025129724, -0.041349664, -0.045472838, -0.037590593, -0.020759324, 1.3913767e-8,
0.019098602, 0.031807438, 0.035367765, 0.02953546, 0.016464282, -2.1502865e-8, -0.015402081,
-0.025843548, -0.02893726, -0.02432333, -0.013641826, 1.2652691e-9, 0.0129044745, 0.02176298,
0.024485376, 0.020674838, 0.011645474, -3.017612e-8, -0.011103839, -0.018795315, -0.02122066,
-0.017978106, -0.010158828, 1.3913767e-8,
];