Skip to content

Commit

Permalink
Loop, increment, channels
Browse files Browse the repository at this point in the history
- Remove loop count, it's not present on WAV;
- Rename sign to increment;
- Remove channels in favor of stereo to match WAV;
  • Loading branch information
DeeJayLSP committed Apr 16, 2024
1 parent 8c1908d commit 43641e5
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 25 deletions.
40 changes: 23 additions & 17 deletions modules/qoa/audio_stream_qoa.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,13 +49,13 @@ int AudioStreamPlaybackQOA::_mix_internal(AudioFrame *p_buffer, int p_frames) {
while (todo && active) {
if (decoded_len <= decoded_offset) {
// Decode the next or previous QOA frame
data_offset += int(frame_data_len) * sign;
data_offset += int(frame_data_len) * increment;
qoa_decode_frame(qoa_stream->data.ptr() + data_offset, frame_data_len, qoad, decoded, &decoded_len);
decoded_offset = sign > 0 ? 0 : decoded_len - 1;
decoded_offset = increment > 0 ? 0 : decoded_len - 1;
}

uint32_t dec_index = decoded_offset * qoa_stream->channels;
p_buffer[p_frames - todo][0] = decoded[qoa_stream->channels == 1 ? dec_index : dec_index++];
uint32_t dec_index = decoded_offset * qoad->channels;
p_buffer[p_frames - todo][0] = decoded[qoa_stream->stereo ? dec_index++ : dec_index];
p_buffer[p_frames - todo][1] = decoded[dec_index];
p_buffer[p_frames - todo] /= 32767.0f;

Expand All @@ -64,20 +64,18 @@ int AudioStreamPlaybackQOA::_mix_internal(AudioFrame *p_buffer, int p_frames) {
if (frames_mixed <= begin_limit + 1) {
// Begin of file or loop
if (qoa_stream->loop_mode == AudioStreamQOA::LOOP_PINGPONG) {
sign = 1;
increment = 1;
} else if (qoa_stream->loop_mode == AudioStreamQOA::LOOP_BACKWARD) {
seek(double(end_limit - 1) / qoa_stream->mix_rate);
loops++;
}
}

if (frames_mixed >= end_limit - 1) {
// End of file or loop
if (qoa_stream->loop_mode == AudioStreamQOA::LOOP_FORWARD) {
seek(double(begin_limit) / qoa_stream->mix_rate);
loops++;
} else if (qoa_stream->loop_mode == AudioStreamQOA::LOOP_PINGPONG) {
sign = -1;
increment = -1;
} else if (qoa_stream->loop_mode == AudioStreamQOA::LOOP_DISABLED) {
frames_mixed_this_step = p_frames - todo;
//fill remainder with silence
Expand All @@ -89,8 +87,8 @@ int AudioStreamPlaybackQOA::_mix_internal(AudioFrame *p_buffer, int p_frames) {
}
}

frames_mixed += sign;
decoded_offset += sign;
frames_mixed += increment;
decoded_offset += increment;
}
return frames_mixed_this_step;
}
Expand All @@ -103,9 +101,8 @@ void AudioStreamPlaybackQOA::start(double p_from_pos) {
active = true;
seek(p_from_pos);
if (qoa_stream->loop_mode == AudioStreamQOA::LOOP_BACKWARD) {
sign = -1;
increment = -1;
}
loops = 0;
begin_resample();
}

Expand All @@ -118,7 +115,7 @@ bool AudioStreamPlaybackQOA::is_playing() const {
}

int AudioStreamPlaybackQOA::get_loop_count() const {
return loops;
return 0;
}

double AudioStreamPlaybackQOA::get_playback_position() const {
Expand Down Expand Up @@ -177,7 +174,6 @@ Ref<AudioStreamPlayback> AudioStreamQOA::instantiate_playback() {
qoas->data_offset = 0;
qoas->frames_mixed = 0;
qoas->active = false;
qoas->loops = 0;

ERR_FAIL_NULL_V(qoas->qoad, Ref<AudioStreamPlaybackQOA>());

Expand All @@ -197,12 +193,10 @@ void AudioStreamQOA::set_data(const Vector<uint8_t> &p_data) {
const uint8_t *src_datar = p_data.ptr();

qoa_desc qoad;
qoad.channels = 0;
qoad.samplerate = 0;
uint32_t ffp = qoa_decode_header(src_datar, src_data_len, &qoad);
ERR_FAIL_COND_MSG(ffp != 8, "Failed to decode QOA header. Make sure it is a valid QOA audio file.");

channels = qoad.channels;
stereo = qoad.channels > 1;
mix_rate = qoad.samplerate;
length = float(qoad.samples) / (mix_rate);
clear_data();
Expand Down Expand Up @@ -252,6 +246,14 @@ double AudioStreamQOA::get_length() const {
return length;
}

void AudioStreamQOA::set_stereo(bool p_stereo) {
stereo = p_stereo;
}

bool AudioStreamQOA::is_stereo() const {
return stereo;
}

bool AudioStreamQOA::is_monophonic() const {
return false;
}
Expand All @@ -272,11 +274,15 @@ void AudioStreamQOA::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_mix_rate", "hz"), &AudioStreamQOA::set_mix_rate);
ClassDB::bind_method(D_METHOD("get_mix_rate"), &AudioStreamQOA::get_mix_rate);

ClassDB::bind_method(D_METHOD("set_stereo", "stereo"), &AudioStreamQOA::set_stereo);
ClassDB::bind_method(D_METHOD("is_stereo"), &AudioStreamQOA::is_stereo);

ADD_PROPERTY(PropertyInfo(Variant::PACKED_BYTE_ARRAY, "data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_data", "get_data");
ADD_PROPERTY(PropertyInfo(Variant::INT, "loop_mode", PROPERTY_HINT_ENUM, "Disabled,Forward,Ping-Pong,Backward"), "set_loop_mode", "get_loop_mode");
ADD_PROPERTY(PropertyInfo(Variant::INT, "loop_begin"), "set_loop_begin", "get_loop_begin");
ADD_PROPERTY(PropertyInfo(Variant::INT, "loop_end"), "set_loop_end", "get_loop_end");
ADD_PROPERTY(PropertyInfo(Variant::INT, "mix_rate"), "set_mix_rate", "get_mix_rate");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "stereo"), "set_stereo", "is_stereo");

BIND_ENUM_CONSTANT(LOOP_DISABLED);
BIND_ENUM_CONSTANT(LOOP_FORWARD);
Expand Down
18 changes: 10 additions & 8 deletions modules/qoa/audio_stream_qoa.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,7 @@ class AudioStreamPlaybackQOA : public AudioStreamPlaybackResampled {
uint32_t decoded_offset = 0;

bool active = false;
int sign = 1;
int loops = 0;
int increment = 1;

friend class AudioStreamQOA;

Expand Down Expand Up @@ -98,7 +97,7 @@ class AudioStreamQOA : public AudioStream {
uint32_t data_len = 0;

LoopMode loop_mode = LOOP_DISABLED;
int channels = 1;
bool stereo = false;
float length = 0.0;
int loop_begin = 0;
int loop_end = -1;
Expand All @@ -121,16 +120,19 @@ class AudioStreamQOA : public AudioStream {
void set_mix_rate(int p_hz);
int get_mix_rate() const;

virtual Ref<AudioStreamPlayback> instantiate_playback() override;
virtual String get_stream_name() const override;

void set_data(const Vector<uint8_t> &p_data);
Vector<uint8_t> get_data() const;
void set_stereo(bool p_stereo);
bool is_stereo() const;

virtual double get_length() const override;

virtual bool is_monophonic() const override;

void set_data(const Vector<uint8_t> &p_data);
Vector<uint8_t> get_data() const;

virtual Ref<AudioStreamPlayback> instantiate_playback() override;
virtual String get_stream_name() const override;

AudioStreamQOA();
virtual ~AudioStreamQOA();
};
Expand Down
3 changes: 3 additions & 0 deletions modules/qoa/doc_classes/AudioStreamQOA.xml
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@
In games, common sample rates in use are [code]11025[/code], [code]16000[/code], [code]22050[/code], [code]32000[/code], [code]44100[/code], and [code]48000[/code].
According to the [url=https://en.wikipedia.org/wiki/Nyquist%E2%80%93Shannon_sampling_theorem]Nyquist-Shannon sampling theorem[/url], there is no quality difference to human hearing when going past 40,000 Hz (since most humans can only hear up to ~20,000 Hz, often less). If you are using lower-pitched sounds such as voices, lower sample rates such as [code]32000[/code] or [code]22050[/code] may be usable with no loss in quality.
</member>
<member name="stereo" type="bool" setter="set_stereo" getter="is_stereo" default="false">
If [code]true[/code], audio is stereo.
</member>
</members>
<constants>
<constant name="LOOP_DISABLED" value="0" enum="LoopMode">
Expand Down

0 comments on commit 43641e5

Please sign in to comment.