Use simpler algorithm for PC speaker tones
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
Alex Page 2022-11-27 22:36:39 -05:00
parent 4b0b67c69a
commit 3ca0eb1eea
2 changed files with 42 additions and 32 deletions

View file

@ -46,11 +46,10 @@ impl SoundEffects {
pub fn new(sound_output: &SoundOutput) -> Self {
Self {
startup: sound_output.render_sound_effect(&SoundEffect {
sounds: (30..400)
.step_by(8)
sounds: (1..800)
.map(|x| Sound {
sound_type: SoundType::Tone(x),
duration: Duration::from_millis(24),
sound_type: SoundType::Tone(x / 2),
duration: Duration::from_millis(1),
})
.collect(),
}),

View file

@ -1,4 +1,4 @@
use std::{f32::consts::PI, sync::Arc};
use std::sync::Arc;
use cpal::{
traits::{DeviceTrait, HostTrait, StreamTrait},
@ -61,41 +61,54 @@ impl SoundOutput {
}
pub fn render_sound_effect(&self, effect: &SoundEffect) -> SoundSamples {
// Keep these outside the loop to remember phase
let mut half_cycle_counter: u32 = 0;
let mut speaker_out: bool = false;
let effect_buffer: Vec<f32> = effect
.sounds
.iter()
.flat_map(|sound| match sound.sound_type {
SoundType::Silence => (0
..(self.sample_rate.0 as f32 * sound.duration.as_secs_f32()) as usize)
SoundType::Silence => {
// Reset phase on silence
half_cycle_counter = 0;
speaker_out = false;
(0..(self.sample_rate.0 as f32 * sound.duration.as_secs_f32()) as usize)
.map(|_| 0f32)
.collect::<Vec<f32>>(),
.collect::<Vec<f32>>()
}
SoundType::Tone(freq) => {
// A frequency of 0 is silence
if freq == 0 {
half_cycle_counter = 0;
speaker_out = false;
return (0..(self.sample_rate.0 as f32 * sound.duration.as_secs_f32())
as usize)
.map(|_| 0f32)
.collect::<Vec<f32>>();
}
let num_harmonics = self.sample_rate.0 / (freq as u32 * 2);
let coefficients = (0..=num_harmonics)
.map(|i| {
if i == 0 {
return 0.0;
let mut buffer: Vec<f32> = vec![
0.;
(self.sample_rate.0 as f32 * sound.duration.as_secs_f32())
as usize
];
let half_cycle_counter_upper_bound: u32 = self.sample_rate.0 / freq;
for sample in &mut buffer {
if speaker_out {
*sample = 0.75;
}
(i as f32 * 0.5 * PI).sin() * 2.0 / (i as f32 * PI)
})
.collect::<Vec<f32>>();
let scaler = freq as f32 * PI * 2.0 / self.sample_rate.0 as f32;
(0..(self.sample_rate.0 as f32 * sound.duration.as_secs_f32()) as usize)
.map(|i| {
let temp = scaler * i as f32;
coefficients
.iter()
.enumerate()
.map(|(j, coef)| coef * (j as f32 * temp).cos())
.sum::<f32>()
})
.collect::<Vec<f32>>()
half_cycle_counter += 2;
if half_cycle_counter >= half_cycle_counter_upper_bound {
half_cycle_counter %= half_cycle_counter_upper_bound;
speaker_out = !speaker_out;
}
}
buffer
}
SoundType::Noise(min, max) => {
(0..(self.sample_rate.0 as f32 * sound.duration.as_secs_f32()) as usize)
@ -116,9 +129,7 @@ impl SoundOutput {
}
pub fn play_sound(&mut self, samples: SoundSamples) -> SoundEffectHandle {
let mut gain = oddio::Gain::new(
oddio::FramesSignal::from(samples)
);
let mut gain = oddio::Gain::new(oddio::FramesSignal::from(samples));
gain.set_gain(-10.0);
self.mixer_handle
.control::<oddio::Mixer<_>, _>()