Use simpler algorithm for PC speaker tones
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
parent
4b0b67c69a
commit
3ca0eb1eea
2 changed files with 42 additions and 32 deletions
|
@ -46,11 +46,10 @@ impl SoundEffects {
|
||||||
pub fn new(sound_output: &SoundOutput) -> Self {
|
pub fn new(sound_output: &SoundOutput) -> Self {
|
||||||
Self {
|
Self {
|
||||||
startup: sound_output.render_sound_effect(&SoundEffect {
|
startup: sound_output.render_sound_effect(&SoundEffect {
|
||||||
sounds: (30..400)
|
sounds: (1..800)
|
||||||
.step_by(8)
|
|
||||||
.map(|x| Sound {
|
.map(|x| Sound {
|
||||||
sound_type: SoundType::Tone(x),
|
sound_type: SoundType::Tone(x / 2),
|
||||||
duration: Duration::from_millis(24),
|
duration: Duration::from_millis(1),
|
||||||
})
|
})
|
||||||
.collect(),
|
.collect(),
|
||||||
}),
|
}),
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use std::{f32::consts::PI, sync::Arc};
|
use std::sync::Arc;
|
||||||
|
|
||||||
use cpal::{
|
use cpal::{
|
||||||
traits::{DeviceTrait, HostTrait, StreamTrait},
|
traits::{DeviceTrait, HostTrait, StreamTrait},
|
||||||
|
@ -61,41 +61,54 @@ impl SoundOutput {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn render_sound_effect(&self, effect: &SoundEffect) -> SoundSamples {
|
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
|
let effect_buffer: Vec<f32> = effect
|
||||||
.sounds
|
.sounds
|
||||||
.iter()
|
.iter()
|
||||||
.flat_map(|sound| match sound.sound_type {
|
.flat_map(|sound| match sound.sound_type {
|
||||||
SoundType::Silence => (0
|
SoundType::Silence => {
|
||||||
..(self.sample_rate.0 as f32 * sound.duration.as_secs_f32()) as usize)
|
// Reset phase on silence
|
||||||
.map(|_| 0f32)
|
half_cycle_counter = 0;
|
||||||
.collect::<Vec<f32>>(),
|
speaker_out = false;
|
||||||
|
(0..(self.sample_rate.0 as f32 * sound.duration.as_secs_f32()) as usize)
|
||||||
|
.map(|_| 0f32)
|
||||||
|
.collect::<Vec<f32>>()
|
||||||
|
}
|
||||||
SoundType::Tone(freq) => {
|
SoundType::Tone(freq) => {
|
||||||
|
// A frequency of 0 is silence
|
||||||
if freq == 0 {
|
if freq == 0 {
|
||||||
|
half_cycle_counter = 0;
|
||||||
|
speaker_out = false;
|
||||||
|
|
||||||
return (0..(self.sample_rate.0 as f32 * sound.duration.as_secs_f32())
|
return (0..(self.sample_rate.0 as f32 * sound.duration.as_secs_f32())
|
||||||
as usize)
|
as usize)
|
||||||
.map(|_| 0f32)
|
.map(|_| 0f32)
|
||||||
.collect::<Vec<f32>>();
|
.collect::<Vec<f32>>();
|
||||||
}
|
}
|
||||||
let num_harmonics = self.sample_rate.0 / (freq as u32 * 2);
|
|
||||||
let coefficients = (0..=num_harmonics)
|
let mut buffer: Vec<f32> = vec![
|
||||||
.map(|i| {
|
0.;
|
||||||
if i == 0 {
|
(self.sample_rate.0 as f32 * sound.duration.as_secs_f32())
|
||||||
return 0.0;
|
as usize
|
||||||
}
|
];
|
||||||
(i as f32 * 0.5 * PI).sin() * 2.0 / (i as f32 * PI)
|
let half_cycle_counter_upper_bound: u32 = self.sample_rate.0 / freq;
|
||||||
})
|
|
||||||
.collect::<Vec<f32>>();
|
for sample in &mut buffer {
|
||||||
let scaler = freq as f32 * PI * 2.0 / self.sample_rate.0 as f32;
|
if speaker_out {
|
||||||
(0..(self.sample_rate.0 as f32 * sound.duration.as_secs_f32()) as usize)
|
*sample = 0.75;
|
||||||
.map(|i| {
|
}
|
||||||
let temp = scaler * i as f32;
|
|
||||||
coefficients
|
half_cycle_counter += 2;
|
||||||
.iter()
|
if half_cycle_counter >= half_cycle_counter_upper_bound {
|
||||||
.enumerate()
|
half_cycle_counter %= half_cycle_counter_upper_bound;
|
||||||
.map(|(j, coef)| coef * (j as f32 * temp).cos())
|
speaker_out = !speaker_out;
|
||||||
.sum::<f32>()
|
}
|
||||||
})
|
}
|
||||||
.collect::<Vec<f32>>()
|
|
||||||
|
buffer
|
||||||
}
|
}
|
||||||
SoundType::Noise(min, max) => {
|
SoundType::Noise(min, max) => {
|
||||||
(0..(self.sample_rate.0 as f32 * sound.duration.as_secs_f32()) as usize)
|
(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 {
|
pub fn play_sound(&mut self, samples: SoundSamples) -> SoundEffectHandle {
|
||||||
let mut gain = oddio::Gain::new(
|
let mut gain = oddio::Gain::new(oddio::FramesSignal::from(samples));
|
||||||
oddio::FramesSignal::from(samples)
|
|
||||||
);
|
|
||||||
gain.set_gain(-10.0);
|
gain.set_gain(-10.0);
|
||||||
self.mixer_handle
|
self.mixer_handle
|
||||||
.control::<oddio::Mixer<_>, _>()
|
.control::<oddio::Mixer<_>, _>()
|
||||||
|
|
Loading…
Add table
Reference in a new issue