From 6c2680e9327ccfee91624d0eb9446817831eb444 Mon Sep 17 00:00:00 2001 From: wareya Date: Thu, 19 Dec 2024 00:50:45 -0300 Subject: [PATCH] `AudioStreamPlaybackWAV`: inherit from `Resampled` Co-authored-by: DeeJayLSP --- scene/resources/audio_stream_wav.cpp | 193 +++++++++------------------ scene/resources/audio_stream_wav.h | 26 ++-- 2 files changed, 69 insertions(+), 150 deletions(-) diff --git a/scene/resources/audio_stream_wav.cpp b/scene/resources/audio_stream_wav.cpp index 0043e076e42b..887bf17d8ef9 100644 --- a/scene/resources/audio_stream_wav.cpp +++ b/scene/resources/audio_stream_wav.cpp @@ -56,6 +56,7 @@ void AudioStreamPlaybackWAV::start(double p_from_pos) { sign = 1; active = true; + begin_resample(); } void AudioStreamPlaybackWAV::stop() { @@ -71,7 +72,7 @@ int AudioStreamPlaybackWAV::get_loop_count() const { } double AudioStreamPlaybackWAV::get_playback_position() const { - return float(offset >> MIX_FRAC_BITS) / base->mix_rate; + return double(offset) / base->mix_rate; } void AudioStreamPlaybackWAV::seek(double p_time) { @@ -86,20 +87,17 @@ void AudioStreamPlaybackWAV::seek(double p_time) { p_time = max - 0.001; } - offset = uint64_t(p_time * base->mix_rate) << MIX_FRAC_BITS; + offset = uint32_t(p_time * base->mix_rate); } template -void AudioStreamPlaybackWAV::do_resample(const Depth *p_src, AudioFrame *p_dst, int64_t &p_offset, int32_t &p_increment, uint32_t p_amount, IMA_ADPCM_State *p_ima_adpcm, QOA_State *p_qoa) { +void AudioStreamPlaybackWAV::decode_samples(const Depth *p_src, AudioFrame *p_dst, int32_t &p_offset, int32_t &p_increment, uint32_t p_amount, IMA_ADPCM_State *p_ima_adpcm, QOA_State *p_qoa) { // this function will be compiled branchless by any decent compiler - int32_t final = 0, final_r = 0, next = 0, next_r = 0; + int32_t final = 0, final_r = 0; while (p_amount) { p_amount--; - int64_t pos = p_offset >> MIX_FRAC_BITS; - if (is_stereo && !is_ima_adpcm && !is_qoa) { - pos <<= 1; - } + int64_t pos = p_offset << (is_stereo && !is_ima_adpcm && !is_qoa ? 1 : 0); if (is_ima_adpcm) { int64_t sample_pos = pos + p_ima_adpcm[0].window_ofs; @@ -175,82 +173,32 @@ void AudioStreamPlaybackWAV::do_resample(const Depth *p_src, AudioFrame *p_dst, final_r = p_ima_adpcm[1].predictor; } - } else { - if (is_qoa) { - if (pos != p_qoa->cache_pos) { // Prevents triple decoding on lower mix rates. - for (int i = 0; i < 2; i++) { - // Sign operations prevent triple decoding on backward loops, maxing prevents pop. - uint32_t interp_pos = MIN(pos + (i * sign) + (sign < 0), p_qoa->desc.samples - 1); - uint32_t new_data_ofs = 8 + interp_pos / QOA_FRAME_LEN * p_qoa->frame_len; - - if (p_qoa->data_ofs != new_data_ofs) { - p_qoa->data_ofs = new_data_ofs; - const uint8_t *ofs_src = (uint8_t *)p_src + p_qoa->data_ofs; - qoa_decode_frame(ofs_src, p_qoa->frame_len, &p_qoa->desc, p_qoa->dec.ptr(), &p_qoa->dec_len); - } + } else if (is_qoa) { + uint32_t new_data_ofs = 8 + pos / QOA_FRAME_LEN * p_qoa->frame_len; - uint32_t dec_idx = (interp_pos % QOA_FRAME_LEN) * p_qoa->desc.channels; - - if ((sign > 0 && i == 0) || (sign < 0 && i == 1)) { - final = p_qoa->dec[dec_idx]; - p_qoa->cache[0] = final; - if (is_stereo) { - final_r = p_qoa->dec[dec_idx + 1]; - p_qoa->cache_r[0] = final_r; - } - } else { - next = p_qoa->dec[dec_idx]; - p_qoa->cache[1] = next; - if (is_stereo) { - next_r = p_qoa->dec[dec_idx + 1]; - p_qoa->cache_r[1] = next_r; - } - } - } - p_qoa->cache_pos = pos; - } else { - final = p_qoa->cache[0]; - if (is_stereo) { - final_r = p_qoa->cache_r[0]; - } - - next = p_qoa->cache[1]; - if (is_stereo) { - next_r = p_qoa->cache_r[1]; - } - } - } else { - final = p_src[pos]; - if (is_stereo) { - final_r = p_src[pos + 1]; - } + if (p_qoa->data_ofs != new_data_ofs) { + p_qoa->data_ofs = new_data_ofs; + const uint8_t *ofs_src = (uint8_t *)p_src + p_qoa->data_ofs; + qoa_decode_frame(ofs_src, p_qoa->frame_len, &p_qoa->desc, p_qoa->dec.ptr(), &p_qoa->dec_len); + } - if constexpr (sizeof(Depth) == 1) { /* conditions will not exist anymore when compiled! */ - final <<= 8; - if (is_stereo) { - final_r <<= 8; - } - } + uint32_t dec_idx = pos % QOA_FRAME_LEN << (is_stereo ? 1 : 0); - if (is_stereo) { - next = p_src[pos + 2]; - next_r = p_src[pos + 3]; - } else { - next = p_src[pos + 1]; - } - - if constexpr (sizeof(Depth) == 1) { - next <<= 8; - if (is_stereo) { - next_r <<= 8; - } - } + final = p_qoa->dec[dec_idx]; + if (is_stereo) { + final_r = p_qoa->dec[dec_idx + 1]; } - int32_t frac = int64_t(p_offset & MIX_FRAC_MASK); - final = final + ((next - final) * frac >> MIX_FRAC_BITS); + } else { + final = p_src[pos]; if (is_stereo) { - final_r = final_r + ((next_r - final_r) * frac >> MIX_FRAC_BITS); + final_r = p_src[pos + 1]; + } + if constexpr (sizeof(Depth) == 1) { /* conditions will not exist anymore when compiled! */ + final <<= 8; + if (is_stereo) { + final_r <<= 8; + } } } @@ -266,7 +214,7 @@ void AudioStreamPlaybackWAV::do_resample(const Depth *p_src, AudioFrame *p_dst, } } -int AudioStreamPlaybackWAV::mix(AudioFrame *p_buffer, float p_rate_scale, int p_frames) { +int AudioStreamPlaybackWAV::_mix_internal(AudioFrame *p_buffer, int p_frames) { if (base->data.is_empty() || !active) { for (int i = 0; i < p_frames; i++) { p_buffer[i] = AudioFrame(0, 0); @@ -294,13 +242,10 @@ int AudioStreamPlaybackWAV::mix(AudioFrame *p_buffer, float p_rate_scale, int p_ len /= 2; } - /* some 64-bit fixed point precaches */ - - int64_t loop_begin_fp = ((int64_t)base->loop_begin << MIX_FRAC_BITS); - int64_t loop_end_fp = ((int64_t)base->loop_end << MIX_FRAC_BITS); - int64_t length_fp = ((int64_t)len << MIX_FRAC_BITS); - int64_t begin_limit = (base->loop_mode != AudioStreamWAV::LOOP_DISABLED) ? loop_begin_fp : 0; - int64_t end_limit = (base->loop_mode != AudioStreamWAV::LOOP_DISABLED) ? loop_end_fp : length_fp - MIX_FRAC_LEN; + int64_t loop_begin = base->loop_begin; + int64_t loop_end = base->loop_end; + int64_t begin_limit = (base->loop_mode != AudioStreamWAV::LOOP_DISABLED) ? loop_begin : 0; + int64_t end_limit = (base->loop_mode != AudioStreamWAV::LOOP_DISABLED) ? loop_end : len - 1; bool is_stereo = base->stereo; int32_t todo = p_frames; @@ -309,13 +254,7 @@ int AudioStreamPlaybackWAV::mix(AudioFrame *p_buffer, float p_rate_scale, int p_ sign = -1; } - float base_rate = AudioServer::get_singleton()->get_mix_rate(); - float srate = base->mix_rate; - srate *= p_rate_scale; - float playback_speed_scale = AudioServer::get_singleton()->get_playback_speed_scale(); - float fincrement = (srate * playback_speed_scale) / base_rate; - int32_t increment = int32_t(MAX(fincrement * MIX_FRAC_LEN, 1)); - increment *= sign; + int32_t increment = sign; //looping @@ -324,13 +263,13 @@ int AudioStreamPlaybackWAV::mix(AudioFrame *p_buffer, float p_rate_scale, int p_ /* audio data */ - const uint8_t *data = base->data.ptr() + AudioStreamWAV::DATA_PAD; + const uint8_t *data = base->data.ptr(); AudioFrame *dst_buff = p_buffer; if (format == AudioStreamWAV::FORMAT_IMA_ADPCM) { if (loop_format != AudioStreamWAV::LOOP_DISABLED) { - ima_adpcm[0].loop_pos = loop_begin_fp >> MIX_FRAC_BITS; - ima_adpcm[1].loop_pos = loop_begin_fp >> MIX_FRAC_BITS; + ima_adpcm[0].loop_pos = loop_begin; + ima_adpcm[1].loop_pos = loop_begin; loop_format = AudioStreamWAV::LOOP_FORWARD; } } @@ -344,16 +283,16 @@ int AudioStreamPlaybackWAV::mix(AudioFrame *p_buffer, float p_rate_scale, int p_ if (increment < 0) { /* going backwards */ - if (loop_format != AudioStreamWAV::LOOP_DISABLED && offset < loop_begin_fp) { + if (loop_format != AudioStreamWAV::LOOP_DISABLED && offset < loop_begin) { /* loopstart reached */ if (loop_format == AudioStreamWAV::LOOP_PINGPONG) { /* bounce ping pong */ - offset = loop_begin_fp + (loop_begin_fp - offset); + offset = loop_begin + (loop_begin - offset); increment = -increment; sign *= -1; } else { /* go to loop-end */ - offset = loop_end_fp - (loop_begin_fp - offset); + offset = loop_end - (loop_begin - offset); } } else { /* check for sample not reaching beginning */ @@ -364,12 +303,12 @@ int AudioStreamPlaybackWAV::mix(AudioFrame *p_buffer, float p_rate_scale, int p_ } } else { /* going forward */ - if (loop_format != AudioStreamWAV::LOOP_DISABLED && offset >= loop_end_fp) { + if (loop_format != AudioStreamWAV::LOOP_DISABLED && offset >= loop_end) { /* loopend reached */ if (loop_format == AudioStreamWAV::LOOP_PINGPONG) { /* bounce ping pong */ - offset = loop_end_fp - (offset - loop_end_fp); + offset = loop_end - (offset - loop_end); increment = -increment; sign *= -1; } else { @@ -379,16 +318,16 @@ int AudioStreamPlaybackWAV::mix(AudioFrame *p_buffer, float p_rate_scale, int p_ for (int i = 0; i < 2; i++) { ima_adpcm[i].step_index = ima_adpcm[i].loop_step_index; ima_adpcm[i].predictor = ima_adpcm[i].loop_predictor; - ima_adpcm[i].last_nibble = loop_begin_fp >> MIX_FRAC_BITS; + ima_adpcm[i].last_nibble = loop_begin; } - offset = loop_begin_fp; + offset = loop_begin; } else { - offset = loop_begin_fp + (offset - loop_end_fp); + offset = loop_begin + (offset - loop_end); } } } else { /* no loop, check for end of sample */ - if (offset >= length_fp) { + if (offset >= len) { active = false; break; } @@ -415,32 +354,32 @@ int AudioStreamPlaybackWAV::mix(AudioFrame *p_buffer, float p_rate_scale, int p_ switch (base->format) { case AudioStreamWAV::FORMAT_8_BITS: { if (is_stereo) { - do_resample((int8_t *)data, dst_buff, offset, increment, target, ima_adpcm, &qoa); + decode_samples((int8_t *)data, dst_buff, offset, increment, target, ima_adpcm, &qoa); } else { - do_resample((int8_t *)data, dst_buff, offset, increment, target, ima_adpcm, &qoa); + decode_samples((int8_t *)data, dst_buff, offset, increment, target, ima_adpcm, &qoa); } } break; case AudioStreamWAV::FORMAT_16_BITS: { if (is_stereo) { - do_resample((int16_t *)data, dst_buff, offset, increment, target, ima_adpcm, &qoa); + decode_samples((int16_t *)data, dst_buff, offset, increment, target, ima_adpcm, &qoa); } else { - do_resample((int16_t *)data, dst_buff, offset, increment, target, ima_adpcm, &qoa); + decode_samples((int16_t *)data, dst_buff, offset, increment, target, ima_adpcm, &qoa); } } break; case AudioStreamWAV::FORMAT_IMA_ADPCM: { if (is_stereo) { - do_resample((int8_t *)data, dst_buff, offset, increment, target, ima_adpcm, &qoa); + decode_samples((int8_t *)data, dst_buff, offset, increment, target, ima_adpcm, &qoa); } else { - do_resample((int8_t *)data, dst_buff, offset, increment, target, ima_adpcm, &qoa); + decode_samples((int8_t *)data, dst_buff, offset, increment, target, ima_adpcm, &qoa); } } break; case AudioStreamWAV::FORMAT_QOA: { if (is_stereo) { - do_resample((uint8_t *)data, dst_buff, offset, increment, target, ima_adpcm, &qoa); + decode_samples((uint8_t *)data, dst_buff, offset, increment, target, ima_adpcm, &qoa); } else { - do_resample((uint8_t *)data, dst_buff, offset, increment, target, ima_adpcm, &qoa); + decode_samples((uint8_t *)data, dst_buff, offset, increment, target, ima_adpcm, &qoa); } } break; } @@ -460,6 +399,10 @@ int AudioStreamPlaybackWAV::mix(AudioFrame *p_buffer, float p_rate_scale, int p_ return p_frames; } +float AudioStreamPlaybackWAV::get_stream_sampling_rate() { + return base->mix_rate; +} + void AudioStreamPlaybackWAV::tag_used_streams() { base->tag_used(get_playback_position()); } @@ -552,7 +495,7 @@ double AudioStreamWAV::get_length() const { break; case AudioStreamWAV::FORMAT_QOA: qoa_desc desc = {}; - qoa_decode_header(data.ptr() + DATA_PAD, data_bytes, &desc); + qoa_decode_header(data.ptr(), data_bytes, &desc); len = desc.samples * desc.channels; break; } @@ -571,28 +514,14 @@ bool AudioStreamWAV::is_monophonic() const { void AudioStreamWAV::set_data(const Vector &p_data) { AudioServer::get_singleton()->lock(); - int src_data_len = p_data.size(); - - data.clear(); - - int alloc_len = src_data_len + DATA_PAD * 2; - data.resize(alloc_len); - memset(data.ptr(), 0, alloc_len); - memcpy(data.ptr() + DATA_PAD, p_data.ptr(), src_data_len); - data_bytes = src_data_len; + data = p_data; + data_bytes = p_data.size(); AudioServer::get_singleton()->unlock(); } Vector AudioStreamWAV::get_data() const { - Vector pv; - - if (data_bytes) { - pv.resize(data_bytes); - memcpy(pv.ptrw(), data.ptr() + DATA_PAD, data_bytes); - } - - return pv; + return data; } Error AudioStreamWAV::save_to_wav(const String &p_path) { @@ -681,7 +610,7 @@ Ref AudioStreamWAV::instantiate_playback() { sample->base = Ref(this); if (format == AudioStreamWAV::FORMAT_QOA) { - uint32_t ffp = qoa_decode_header(data.ptr() + DATA_PAD, data_bytes, &sample->qoa.desc); + uint32_t ffp = qoa_decode_header(data.ptr(), data_bytes, &sample->qoa.desc); ERR_FAIL_COND_V(ffp != 8, Ref()); sample->qoa.frame_len = qoa_max_frame_size(&sample->qoa.desc); int samples_len = (sample->qoa.desc.samples > QOA_FRAME_LEN ? QOA_FRAME_LEN : sample->qoa.desc.samples); diff --git a/scene/resources/audio_stream_wav.h b/scene/resources/audio_stream_wav.h index e36d33cfa933..f44ae8ac6bb4 100644 --- a/scene/resources/audio_stream_wav.h +++ b/scene/resources/audio_stream_wav.h @@ -36,13 +36,8 @@ class AudioStreamWAV; -class AudioStreamPlaybackWAV : public AudioStreamPlayback { - GDCLASS(AudioStreamPlaybackWAV, AudioStreamPlayback); - enum { - MIX_FRAC_BITS = 13, - MIX_FRAC_LEN = (1 << MIX_FRAC_BITS), - MIX_FRAC_MASK = MIX_FRAC_LEN - 1, - }; +class AudioStreamPlaybackWAV : public AudioStreamPlaybackResampled { + GDCLASS(AudioStreamPlaybackWAV, AudioStreamPlaybackResampled); struct IMA_ADPCM_State { int16_t step_index = 0; @@ -61,23 +56,24 @@ class AudioStreamPlaybackWAV : public AudioStreamPlayback { uint32_t frame_len = 0; LocalVector dec; uint32_t dec_len = 0; - int64_t cache_pos = -1; - int16_t cache[2] = { 0, 0 }; - int16_t cache_r[2] = { 0, 0 }; } qoa; - int64_t offset = 0; + int32_t offset = 0; int sign = 1; bool active = false; friend class AudioStreamWAV; Ref base; template - void do_resample(const Depth *p_src, AudioFrame *p_dst, int64_t &p_offset, int32_t &p_increment, uint32_t p_amount, IMA_ADPCM_State *p_ima_adpcm, QOA_State *p_qoa); + void decode_samples(const Depth *p_src, AudioFrame *p_dst, int32_t &p_offset, int32_t &p_increment, uint32_t p_amount, IMA_ADPCM_State *p_ima_adpcm, QOA_State *p_qoa); bool _is_sample = false; Ref sample_playback; +protected: + virtual int _mix_internal(AudioFrame *p_buffer, int p_frames) override; + virtual float get_stream_sampling_rate() override; + public: virtual void start(double p_from_pos = 0.0) override; virtual void stop() override; @@ -88,8 +84,6 @@ class AudioStreamPlaybackWAV : public AudioStreamPlayback { virtual double get_playback_position() const override; virtual void seek(double p_time) override; - virtual int mix(AudioFrame *p_buffer, float p_rate_scale, int p_frames) override; - virtual void tag_used_streams() override; virtual void set_is_sample(bool p_is_sample) override; @@ -124,10 +118,6 @@ class AudioStreamWAV : public AudioStream { private: friend class AudioStreamPlaybackWAV; - enum { - DATA_PAD = 16 //padding for interpolation - }; - Format format = FORMAT_8_BITS; LoopMode loop_mode = LOOP_DISABLED; bool stereo = false;