From 8a4202e556a5cac7179563e2e9bbad685a78d021 Mon Sep 17 00:00:00 2001 From: Rehkitzdev Date: Wed, 10 May 2023 21:10:27 +0200 Subject: [PATCH 1/5] add pitch --- js/audio.js | 13 ++++++++++++- src/lib.rs | 2 ++ src/mixer.rs | 28 ++++++++++++++++++++++------ src/web_snd.rs | 9 +++++++-- 4 files changed, 43 insertions(+), 9 deletions(-) diff --git a/js/audio.js b/js/audio.js index aa78005..7ee7d0c 100644 --- a/js/audio.js +++ b/js/audio.js @@ -114,9 +114,11 @@ function stop(playback) { } } -function audio_play_buffer(sound_key, volume, repeat) { +function audio_play_buffer(sound_key, volume, pitch, repeat) { let playback_key = playback_key_next++; + console.log("play pitch:", pitch); + let pb = recycle_playback(); pb.sound_key = sound_key; @@ -177,6 +179,14 @@ function audio_playback_set_volume(playback_key, volume) { } } +function audio_playback_set_pitch(playback_key, pitch) { + let playback = playbacks.find(playback => playback.playback_key === playback_key); + + if (playback != null) { + console.log("audio_playback_set_pitch", pitch); + } +} + function register_plugin(importObject) { importObject.env.audio_init = audio_init; importObject.env.audio_add_buffer = audio_add_buffer; @@ -187,6 +197,7 @@ function register_plugin(importObject) { importObject.env.audio_source_delete = audio_source_delete; importObject.env.audio_playback_stop = audio_playback_stop; importObject.env.audio_playback_set_volume = audio_playback_set_volume; + importObject.env.audio_playback_set_pitch = audio_playback_set_pitch; } miniquad_add_plugin({ register_plugin, version: "0.1.0", name: "macroquad_audio" }); diff --git a/src/lib.rs b/src/lib.rs index d3cf812..0469809 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -34,6 +34,7 @@ pub use snd::{AudioContext, Playback, Sound}; pub struct PlaySoundParams { pub looped: bool, pub volume: f32, + pub pitch: f32, } impl Default for PlaySoundParams { @@ -41,6 +42,7 @@ impl Default for PlaySoundParams { PlaySoundParams { looped: false, volume: 1., + pitch: 1., } } } diff --git a/src/mixer.rs b/src/mixer.rs index 98f8895..8df683c 100644 --- a/src/mixer.rs +++ b/src/mixer.rs @@ -7,10 +7,11 @@ use std::sync::mpsc; enum AudioMessage { AddSound(u32, Vec), - Play(u32, u32, bool, f32), + Play(u32, u32, bool, f32, f32), Stop(u32), StopAll(u32), SetVolume(u32, f32), + SetPitch(u32, f32), SetVolumeAll(u32, f32), Delete(u32), } @@ -23,6 +24,7 @@ pub struct SoundState { data: Arc<[f32]>, looped: bool, volume: f32, + pitch: f32, } impl SoundState { @@ -95,6 +97,7 @@ impl MixerControl { play_id, params.looped, params.volume, + params.pitch, )); self.play_id.set(play_id + 1); @@ -155,7 +158,7 @@ impl Mixer { AudioMessage::AddSound(id, data) => { self.sounds.insert(id, data.into()); } - AudioMessage::Play(sound_id, play_id, looped, volume) => { + AudioMessage::Play(sound_id, play_id, looped, volume, pitch) => { if let Some(data) = self.sounds.get(&sound_id) { self.mixer_state.push(SoundState { sound_id, @@ -164,6 +167,7 @@ impl Mixer { data: data.clone(), looped, volume, + pitch, }); } } @@ -194,6 +198,12 @@ impl Mixer { sound.volume = volume; } } + AudioMessage::SetPitch(play_id, pitch) => { + if let Some(sound) = self.mixer_state.iter_mut().find(|s| s.play_id == play_id) + { + sound.pitch = pitch; + } + } AudioMessage::Delete(sound_id) => { for i in (0..self.mixer_state.len()).rev() { if self.mixer_state[i].sound_id == sound_id { @@ -212,17 +222,23 @@ impl Mixer { let mut i = 0; while let Some(sound) = self.mixer_state.get_mut(i) { + let pitch = sound.pitch; let volume = sound.volume; let mut remainder = buffer.len(); loop { - let samples = sound.get_samples(remainder); - for (b, s) in buffer.iter_mut().zip(samples) { - *b += s * volume; + let samples = sound.get_samples(((remainder as f32) * pitch) as usize); + + let len = (samples.len() as f32 / pitch).ceil() as usize; + + let mut sample_index = 0.; + for i in 0..len { + buffer[i] += samples[sample_index as usize] * volume; + sample_index += pitch; } - remainder -= samples.len(); + remainder -= len; if remainder > 0 && sound.looped { sound.rewind(); diff --git a/src/web_snd.rs b/src/web_snd.rs index 357ec30..0521759 100644 --- a/src/web_snd.rs +++ b/src/web_snd.rs @@ -3,13 +3,14 @@ use crate::PlaySoundParams; extern "C" { fn audio_init(); fn audio_add_buffer(content: *const u8, content_len: u32) -> u32; - fn audio_play_buffer(buffer: u32, volume: f32, repeat: bool) -> u32; + fn audio_play_buffer(buffer: u32, volume: f32, pitch: f32, repeat: bool) -> u32; fn audio_source_is_loaded(buffer: u32) -> bool; fn audio_source_set_volume(buffer: u32, volume: f32); fn audio_source_stop(buffer: u32); fn audio_source_delete(buffer: u32); fn audio_playback_stop(playback: u32); fn audio_playback_set_volume(playback: u32, volume: f32); + fn audio_playback_set_pitch(playback: u32, pitch: f32); } #[no_mangle] @@ -67,7 +68,7 @@ impl Sound { } pub fn play(&self, _ctx: &AudioContext, params: PlaySoundParams) -> Playback { - let id = unsafe { audio_play_buffer(self.0, params.volume, params.looped) }; + let id = unsafe { audio_play_buffer(self.0, params.volume, params.pitch, params.looped) }; Playback(id) } @@ -80,6 +81,10 @@ impl Sound { unsafe { audio_source_set_volume(self.0, volume) } } + pub fn set_pitch(&self, _ctx: &AudioContext, pitch: f32) { + unsafe { audio_source_set_pitch(self.0, pitch) } + } + pub fn delete(&self, _ctx: &AudioContext) { unsafe { audio_source_delete(self.0) } } From 90cd1c63c28a3ccf1dfe8772058d6b0b86b0796d Mon Sep 17 00:00:00 2001 From: Rehkitzdev Date: Thu, 11 May 2023 00:12:27 +0200 Subject: [PATCH 2/5] some fixes. webapi works --- js/audio.js | 3 ++- src/mixer.rs | 4 ++-- src/web_snd.rs | 8 ++++---- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/js/audio.js b/js/audio.js index 7ee7d0c..49fda03 100644 --- a/js/audio.js +++ b/js/audio.js @@ -129,6 +129,7 @@ function audio_play_buffer(sound_key, volume, pitch, repeat) { pb.gain_node.gain.value = volume; pb.source.loop = repeat; + pb.source.playbackRate.value = pitch; pb.ended = function() { stop(pb); @@ -183,7 +184,7 @@ function audio_playback_set_pitch(playback_key, pitch) { let playback = playbacks.find(playback => playback.playback_key === playback_key); if (playback != null) { - console.log("audio_playback_set_pitch", pitch); + playback.source.playbackRate.value = pitch; } } diff --git a/src/mixer.rs b/src/mixer.rs index 8df683c..d424918 100644 --- a/src/mixer.rs +++ b/src/mixer.rs @@ -228,9 +228,9 @@ impl Mixer { loop { - let samples = sound.get_samples(((remainder as f32) * pitch) as usize); + let samples = sound.get_samples((remainder as f32 * pitch).ceil() as usize); - let len = (samples.len() as f32 / pitch).ceil() as usize; + let len = usize::min((samples.len() as f32 / pitch) as usize, remainder); let mut sample_index = 0.; for i in 0..len { diff --git a/src/web_snd.rs b/src/web_snd.rs index 0521759..2c3f5fb 100644 --- a/src/web_snd.rs +++ b/src/web_snd.rs @@ -46,6 +46,10 @@ impl Playback { pub fn set_volume(&self, _ctx: &AudioContext, volume: f32) { unsafe { audio_playback_set_volume(self.0, volume) } } + + pub fn set_pitch(&self, _ctx: &AudioContext, pitch: f32) { + unsafe { audio_playback_set_pitch(self.0, pitch) } + } } impl Sound { @@ -81,10 +85,6 @@ impl Sound { unsafe { audio_source_set_volume(self.0, volume) } } - pub fn set_pitch(&self, _ctx: &AudioContext, pitch: f32) { - unsafe { audio_source_set_pitch(self.0, pitch) } - } - pub fn delete(&self, _ctx: &AudioContext) { unsafe { audio_source_delete(self.0) } } From 2e6ca14ad446c4faca46ba4955b4afeb9946c46c Mon Sep 17 00:00:00 2001 From: Rehkitzdev Date: Thu, 11 May 2023 00:19:18 +0200 Subject: [PATCH 3/5] remove log --- js/audio.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/js/audio.js b/js/audio.js index 49fda03..924060b 100644 --- a/js/audio.js +++ b/js/audio.js @@ -117,8 +117,6 @@ function stop(playback) { function audio_play_buffer(sound_key, volume, pitch, repeat) { let playback_key = playback_key_next++; - console.log("play pitch:", pitch); - let pb = recycle_playback(); pb.sound_key = sound_key; From 2fc9f2520ca46d8c07b546a083c00769aa90684a Mon Sep 17 00:00:00 2001 From: Rehkitzdev Date: Thu, 11 May 2023 21:45:22 +0200 Subject: [PATCH 4/5] lerp samples. fixed indexing --- src/mixer.rs | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/src/mixer.rs b/src/mixer.rs index d424918..a8536cc 100644 --- a/src/mixer.rs +++ b/src/mixer.rs @@ -227,15 +227,28 @@ impl Mixer { let mut remainder = buffer.len(); loop { + let req = (remainder as f32 * pitch).ceil() as usize + 1; + let samples = sound.get_samples(req); - let samples = sound.get_samples((remainder as f32 * pitch).ceil() as usize); - - let len = usize::min((samples.len() as f32 / pitch) as usize, remainder); + let mut len = remainder; + if samples.len() != req { + if pitch <= 1. { + len = samples.len() -1; + } + else{ + len = (samples.len() as f32 / pitch) as usize; + } + } - let mut sample_index = 0.; + let mut sample_position = 0.; for i in 0..len { - buffer[i] += samples[sample_index as usize] * volume; - sample_index += pitch; + let sample_index = sample_position as usize; + let sample1 = samples[sample_index]; + let sample2 = samples[sample_index + 1]; + let sample_lerp = sample1 + f32::fract(sample_position) * (sample2 - sample1); + buffer[i] += sample_lerp * volume; + + sample_position += pitch; } remainder -= len; @@ -259,7 +272,7 @@ impl Mixer { /// Parse ogg/wav/etc and get resampled to 44100, 2 channel data pub fn load_samples_from_file(bytes: &[u8]) -> Result, ()> { - let mut audio_stream = { + let mut audio_stream = { let file = std::io::Cursor::new(bytes); audrey::Reader::new(file).unwrap() }; From 859495dcb58184f00f24129a9886f970fcf754b1 Mon Sep 17 00:00:00 2001 From: Rehkitzdev Date: Thu, 11 May 2023 21:47:05 +0200 Subject: [PATCH 5/5] format --- src/mixer.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mixer.rs b/src/mixer.rs index a8536cc..61206c9 100644 --- a/src/mixer.rs +++ b/src/mixer.rs @@ -272,7 +272,7 @@ impl Mixer { /// Parse ogg/wav/etc and get resampled to 44100, 2 channel data pub fn load_samples_from_file(bytes: &[u8]) -> Result, ()> { - let mut audio_stream = { + let mut audio_stream = { let file = std::io::Cursor::new(bytes); audrey::Reader::new(file).unwrap() };