You've already forked godot
mirror of
https://github.com/godotengine/godot.git
synced 2025-11-04 12:00:25 +00:00
Merge pull request #96346 from DeeJayLSP/qoa-opt
Use `qoa.c` and custom compress procedure
This commit is contained in:
@@ -7,7 +7,13 @@ Import("env")
|
|||||||
|
|
||||||
thirdparty_obj = []
|
thirdparty_obj = []
|
||||||
|
|
||||||
thirdparty_sources = "#thirdparty/misc/mikktspace.c"
|
thirdparty_dir = "#thirdparty/misc/"
|
||||||
|
thirdparty_sources = [
|
||||||
|
"mikktspace.c",
|
||||||
|
"qoa.c"
|
||||||
|
]
|
||||||
|
|
||||||
|
thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources]
|
||||||
|
|
||||||
env_thirdparty = env.Clone()
|
env_thirdparty = env.Clone()
|
||||||
env_thirdparty.disable_warnings()
|
env_thirdparty.disable_warnings()
|
||||||
|
|||||||
@@ -1142,13 +1142,13 @@ Ref<AudioStreamWAV> AudioStreamWAV::load_from_buffer(const Vector<uint8_t> &p_fi
|
|||||||
is16 = false;
|
is16 = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector<uint8_t> pcm_data;
|
Vector<uint8_t> dst_data;
|
||||||
AudioStreamWAV::Format dst_format;
|
AudioStreamWAV::Format dst_format;
|
||||||
|
|
||||||
if (compression == 1) {
|
if (compression == 1) {
|
||||||
dst_format = AudioStreamWAV::FORMAT_IMA_ADPCM;
|
dst_format = AudioStreamWAV::FORMAT_IMA_ADPCM;
|
||||||
if (format_channels == 1) {
|
if (format_channels == 1) {
|
||||||
_compress_ima_adpcm(data, pcm_data);
|
_compress_ima_adpcm(data, dst_data);
|
||||||
} else {
|
} else {
|
||||||
//byte interleave
|
//byte interleave
|
||||||
Vector<float> left;
|
Vector<float> left;
|
||||||
@@ -1170,9 +1170,9 @@ Ref<AudioStreamWAV> AudioStreamWAV::load_from_buffer(const Vector<uint8_t> &p_fi
|
|||||||
_compress_ima_adpcm(right, bright);
|
_compress_ima_adpcm(right, bright);
|
||||||
|
|
||||||
int dl = bleft.size();
|
int dl = bleft.size();
|
||||||
pcm_data.resize(dl * 2);
|
dst_data.resize(dl * 2);
|
||||||
|
|
||||||
uint8_t *w = pcm_data.ptrw();
|
uint8_t *w = dst_data.ptrw();
|
||||||
const uint8_t *rl = bleft.ptr();
|
const uint8_t *rl = bleft.ptr();
|
||||||
const uint8_t *rr = bright.ptr();
|
const uint8_t *rr = bright.ptr();
|
||||||
|
|
||||||
@@ -1182,16 +1182,24 @@ Ref<AudioStreamWAV> AudioStreamWAV::load_from_buffer(const Vector<uint8_t> &p_fi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} else if (compression == 2) {
|
||||||
|
dst_format = AudioStreamWAV::FORMAT_QOA;
|
||||||
|
|
||||||
|
qoa_desc desc = {};
|
||||||
|
desc.samplerate = rate;
|
||||||
|
desc.samples = frames;
|
||||||
|
desc.channels = format_channels;
|
||||||
|
|
||||||
|
_compress_qoa(data, dst_data, &desc);
|
||||||
} else {
|
} else {
|
||||||
dst_format = is16 ? AudioStreamWAV::FORMAT_16_BITS : AudioStreamWAV::FORMAT_8_BITS;
|
dst_format = is16 ? AudioStreamWAV::FORMAT_16_BITS : AudioStreamWAV::FORMAT_8_BITS;
|
||||||
bool enforce16 = is16 || compression == 2;
|
dst_data.resize(data.size() * (is16 ? 2 : 1));
|
||||||
pcm_data.resize(data.size() * (enforce16 ? 2 : 1));
|
|
||||||
{
|
{
|
||||||
uint8_t *w = pcm_data.ptrw();
|
uint8_t *w = dst_data.ptrw();
|
||||||
|
|
||||||
int ds = data.size();
|
int ds = data.size();
|
||||||
for (int i = 0; i < ds; i++) {
|
for (int i = 0; i < ds; i++) {
|
||||||
if (enforce16) {
|
if (is16) {
|
||||||
int16_t v = CLAMP(data[i] * 32768, -32768, 32767);
|
int16_t v = CLAMP(data[i] * 32768, -32768, 32767);
|
||||||
encode_uint16(v, &w[i * 2]);
|
encode_uint16(v, &w[i * 2]);
|
||||||
} else {
|
} else {
|
||||||
@@ -1202,26 +1210,6 @@ Ref<AudioStreamWAV> AudioStreamWAV::load_from_buffer(const Vector<uint8_t> &p_fi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector<uint8_t> dst_data;
|
|
||||||
if (compression == 2) {
|
|
||||||
dst_format = AudioStreamWAV::FORMAT_QOA;
|
|
||||||
qoa_desc desc = {};
|
|
||||||
uint32_t qoa_len = 0;
|
|
||||||
|
|
||||||
desc.samplerate = rate;
|
|
||||||
desc.samples = frames;
|
|
||||||
desc.channels = format_channels;
|
|
||||||
|
|
||||||
void *encoded = qoa_encode((short *)pcm_data.ptr(), &desc, &qoa_len);
|
|
||||||
if (encoded) {
|
|
||||||
dst_data.resize(qoa_len);
|
|
||||||
memcpy(dst_data.ptrw(), encoded, qoa_len);
|
|
||||||
QOA_FREE(encoded);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
dst_data = pcm_data;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ref<AudioStreamWAV> sample;
|
Ref<AudioStreamWAV> sample;
|
||||||
sample.instantiate();
|
sample.instantiate();
|
||||||
sample->set_data(dst_data);
|
sample->set_data(dst_data);
|
||||||
|
|||||||
@@ -31,9 +31,6 @@
|
|||||||
#ifndef AUDIO_STREAM_WAV_H
|
#ifndef AUDIO_STREAM_WAV_H
|
||||||
#define AUDIO_STREAM_WAV_H
|
#define AUDIO_STREAM_WAV_H
|
||||||
|
|
||||||
#define QOA_IMPLEMENTATION
|
|
||||||
#define QOA_NO_STDIO
|
|
||||||
|
|
||||||
#include "servers/audio/audio_stream.h"
|
#include "servers/audio/audio_stream.h"
|
||||||
#include "thirdparty/misc/qoa.h"
|
#include "thirdparty/misc/qoa.h"
|
||||||
|
|
||||||
@@ -273,6 +270,34 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void _compress_qoa(const Vector<float> &p_data, Vector<uint8_t> &dst_data, qoa_desc *p_desc) {
|
||||||
|
uint32_t frames_len = (p_desc->samples + QOA_FRAME_LEN - 1) / QOA_FRAME_LEN * (QOA_LMS_LEN * 4 * p_desc->channels + 8);
|
||||||
|
uint32_t slices_len = (p_desc->samples + QOA_SLICE_LEN - 1) / QOA_SLICE_LEN * 8 * p_desc->channels;
|
||||||
|
dst_data.resize(8 + frames_len + slices_len);
|
||||||
|
|
||||||
|
for (uint32_t c = 0; c < p_desc->channels; c++) {
|
||||||
|
memset(p_desc->lms[c].history, 0, sizeof(p_desc->lms[c].history));
|
||||||
|
memset(p_desc->lms[c].weights, 0, sizeof(p_desc->lms[c].weights));
|
||||||
|
p_desc->lms[c].weights[2] = -(1 << 13);
|
||||||
|
p_desc->lms[c].weights[3] = (1 << 14);
|
||||||
|
}
|
||||||
|
|
||||||
|
LocalVector<int16_t> data16;
|
||||||
|
data16.resize(QOA_FRAME_LEN * p_desc->channels);
|
||||||
|
|
||||||
|
uint8_t *dst_ptr = dst_data.ptrw();
|
||||||
|
dst_ptr += qoa_encode_header(p_desc, dst_data.ptrw());
|
||||||
|
|
||||||
|
uint32_t frame_len = QOA_FRAME_LEN;
|
||||||
|
for (uint32_t s = 0; s < p_desc->samples; s += frame_len) {
|
||||||
|
frame_len = MIN(frame_len, p_desc->samples - s);
|
||||||
|
for (uint32_t i = 0; i < frame_len * p_desc->channels; i++) {
|
||||||
|
data16[i] = CLAMP(p_data[s * p_desc->channels + i] * 32767.0, -32768, 32767);
|
||||||
|
}
|
||||||
|
dst_ptr += qoa_encode_frame(data16.ptr(), p_desc, frame_len, dst_ptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
AudioStreamWAV();
|
AudioStreamWAV();
|
||||||
~AudioStreamWAV();
|
~AudioStreamWAV();
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -250,6 +250,12 @@ Ref<AudioStreamWAV> AudioEffectRecord::get_recording() const {
|
|||||||
w[i * 2 + 0] = rl[i];
|
w[i * 2 + 0] = rl[i];
|
||||||
w[i * 2 + 1] = rr[i];
|
w[i * 2 + 1] = rr[i];
|
||||||
}
|
}
|
||||||
|
} else if (dst_format == AudioStreamWAV::FORMAT_QOA) {
|
||||||
|
qoa_desc desc = {};
|
||||||
|
desc.samples = current_instance->recording_data.size() / 2;
|
||||||
|
desc.samplerate = AudioServer::get_singleton()->get_mix_rate();
|
||||||
|
desc.channels = 2;
|
||||||
|
AudioStreamWAV::_compress_qoa(current_instance->recording_data, dst_data, &desc);
|
||||||
} else {
|
} else {
|
||||||
ERR_PRINT("Format not implemented.");
|
ERR_PRINT("Format not implemented.");
|
||||||
}
|
}
|
||||||
|
|||||||
4
thirdparty/README.md
vendored
4
thirdparty/README.md
vendored
@@ -716,8 +716,8 @@ Collection of single-file libraries used in Godot components.
|
|||||||
* License: MIT
|
* License: MIT
|
||||||
- `qoa.h`
|
- `qoa.h`
|
||||||
* Upstream: https://github.com/phoboslab/qoa
|
* Upstream: https://github.com/phoboslab/qoa
|
||||||
* Version: git (e0c69447d4d3945c3c92ac1751e4cdc9803a8303, 2024)
|
* Version: git (a2d927f8ce78a85e903676a33e0f956e53b89f7d, 2024)
|
||||||
* Modifications: Added a few modifiers to comply with C++ nature.
|
* Modifications: Added implementation through `qoa.c`.
|
||||||
* License: MIT
|
* License: MIT
|
||||||
- `r128.{c,h}`
|
- `r128.{c,h}`
|
||||||
* Upstream: https://github.com/fahickman/r128
|
* Upstream: https://github.com/fahickman/r128
|
||||||
|
|||||||
53
thirdparty/misc/patches/qoa-min-fix.patch
vendored
53
thirdparty/misc/patches/qoa-min-fix.patch
vendored
@@ -1,53 +0,0 @@
|
|||||||
diff --git a/qoa.h b/qoa.h
|
|
||||||
index cfed266bef..23612bb0bf 100644
|
|
||||||
--- a/qoa.h
|
|
||||||
+++ b/qoa.h
|
|
||||||
@@ -140,14 +140,14 @@ typedef struct {
|
|
||||||
#endif
|
|
||||||
} qoa_desc;
|
|
||||||
|
|
||||||
-unsigned int qoa_encode_header(qoa_desc *qoa, unsigned char *bytes);
|
|
||||||
-unsigned int qoa_encode_frame(const short *sample_data, qoa_desc *qoa, unsigned int frame_len, unsigned char *bytes);
|
|
||||||
-void *qoa_encode(const short *sample_data, qoa_desc *qoa, unsigned int *out_len);
|
|
||||||
+inline unsigned int qoa_encode_header(qoa_desc *qoa, unsigned char *bytes);
|
|
||||||
+inline unsigned int qoa_encode_frame(const short *sample_data, qoa_desc *qoa, unsigned int frame_len, unsigned char *bytes);
|
|
||||||
+inline void *qoa_encode(const short *sample_data, qoa_desc *qoa, unsigned int *out_len);
|
|
||||||
|
|
||||||
-unsigned int qoa_max_frame_size(qoa_desc *qoa);
|
|
||||||
-unsigned int qoa_decode_header(const unsigned char *bytes, int size, qoa_desc *qoa);
|
|
||||||
-unsigned int qoa_decode_frame(const unsigned char *bytes, unsigned int size, qoa_desc *qoa, short *sample_data, unsigned int *frame_len);
|
|
||||||
-short *qoa_decode(const unsigned char *bytes, int size, qoa_desc *file);
|
|
||||||
+inline unsigned int qoa_max_frame_size(qoa_desc *qoa);
|
|
||||||
+inline unsigned int qoa_decode_header(const unsigned char *bytes, int size, qoa_desc *qoa);
|
|
||||||
+inline unsigned int qoa_decode_frame(const unsigned char *bytes, unsigned int size, qoa_desc *qoa, short *sample_data, unsigned int *frame_len);
|
|
||||||
+inline short *qoa_decode(const unsigned char *bytes, int size, qoa_desc *file);
|
|
||||||
|
|
||||||
#ifndef QOA_NO_STDIO
|
|
||||||
|
|
||||||
@@ -395,7 +395,7 @@ unsigned int qoa_encode_frame(const short *sample_data, qoa_desc *qoa, unsigned
|
|
||||||
qoa_uint64_t best_error = -1;
|
|
||||||
#endif
|
|
||||||
qoa_uint64_t best_slice = 0;
|
|
||||||
- qoa_lms_t best_lms;
|
|
||||||
+ qoa_lms_t best_lms = {};
|
|
||||||
int best_scalefactor = 0;
|
|
||||||
|
|
||||||
for (int sfi = 0; sfi < 16; sfi++) {
|
|
||||||
@@ -500,7 +500,7 @@ void *qoa_encode(const short *sample_data, qoa_desc *qoa, unsigned int *out_len)
|
|
||||||
num_frames * QOA_LMS_LEN * 4 * qoa->channels + /* 4 * 4 bytes lms state per channel */
|
|
||||||
num_slices * 8 * qoa->channels; /* 8 byte slices */
|
|
||||||
|
|
||||||
- unsigned char *bytes = QOA_MALLOC(encoded_size);
|
|
||||||
+ unsigned char *bytes = (unsigned char *)QOA_MALLOC(encoded_size);
|
|
||||||
|
|
||||||
for (unsigned int c = 0; c < qoa->channels; c++) {
|
|
||||||
/* Set the initial LMS weights to {0, 0, -1, 2}. This helps with the
|
|
||||||
@@ -655,7 +655,7 @@ short *qoa_decode(const unsigned char *bytes, int size, qoa_desc *qoa) {
|
|
||||||
|
|
||||||
/* Calculate the required size of the sample buffer and allocate */
|
|
||||||
int total_samples = qoa->samples * qoa->channels;
|
|
||||||
- short *sample_data = QOA_MALLOC(total_samples * sizeof(short));
|
|
||||||
+ short *sample_data = (short *)QOA_MALLOC(total_samples * sizeof(short));
|
|
||||||
|
|
||||||
unsigned int sample_index = 0;
|
|
||||||
unsigned int frame_len;
|
|
||||||
4
thirdparty/misc/qoa.c
vendored
Normal file
4
thirdparty/misc/qoa.c
vendored
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
#define QOA_IMPLEMENTATION
|
||||||
|
#define QOA_NO_STDIO
|
||||||
|
|
||||||
|
#include "qoa.h"
|
||||||
24
thirdparty/misc/qoa.h
vendored
24
thirdparty/misc/qoa.h
vendored
@@ -140,14 +140,14 @@ typedef struct {
|
|||||||
#endif
|
#endif
|
||||||
} qoa_desc;
|
} qoa_desc;
|
||||||
|
|
||||||
inline unsigned int qoa_encode_header(qoa_desc *qoa, unsigned char *bytes);
|
unsigned int qoa_encode_header(qoa_desc *qoa, unsigned char *bytes);
|
||||||
inline unsigned int qoa_encode_frame(const short *sample_data, qoa_desc *qoa, unsigned int frame_len, unsigned char *bytes);
|
unsigned int qoa_encode_frame(const short *sample_data, qoa_desc *qoa, unsigned int frame_len, unsigned char *bytes);
|
||||||
inline void *qoa_encode(const short *sample_data, qoa_desc *qoa, unsigned int *out_len);
|
void *qoa_encode(const short *sample_data, qoa_desc *qoa, unsigned int *out_len);
|
||||||
|
|
||||||
inline unsigned int qoa_max_frame_size(qoa_desc *qoa);
|
unsigned int qoa_max_frame_size(qoa_desc *qoa);
|
||||||
inline unsigned int qoa_decode_header(const unsigned char *bytes, int size, qoa_desc *qoa);
|
unsigned int qoa_decode_header(const unsigned char *bytes, int size, qoa_desc *qoa);
|
||||||
inline unsigned int qoa_decode_frame(const unsigned char *bytes, unsigned int size, qoa_desc *qoa, short *sample_data, unsigned int *frame_len);
|
unsigned int qoa_decode_frame(const unsigned char *bytes, unsigned int size, qoa_desc *qoa, short *sample_data, unsigned int *frame_len);
|
||||||
inline short *qoa_decode(const unsigned char *bytes, int size, qoa_desc *file);
|
short *qoa_decode(const unsigned char *bytes, int size, qoa_desc *file);
|
||||||
|
|
||||||
#ifndef QOA_NO_STDIO
|
#ifndef QOA_NO_STDIO
|
||||||
|
|
||||||
@@ -395,7 +395,7 @@ unsigned int qoa_encode_frame(const short *sample_data, qoa_desc *qoa, unsigned
|
|||||||
qoa_uint64_t best_error = -1;
|
qoa_uint64_t best_error = -1;
|
||||||
#endif
|
#endif
|
||||||
qoa_uint64_t best_slice = 0;
|
qoa_uint64_t best_slice = 0;
|
||||||
qoa_lms_t best_lms = {};
|
qoa_lms_t best_lms;
|
||||||
int best_scalefactor = 0;
|
int best_scalefactor = 0;
|
||||||
|
|
||||||
for (int sfi = 0; sfi < 16; sfi++) {
|
for (int sfi = 0; sfi < 16; sfi++) {
|
||||||
@@ -500,7 +500,7 @@ void *qoa_encode(const short *sample_data, qoa_desc *qoa, unsigned int *out_len)
|
|||||||
num_frames * QOA_LMS_LEN * 4 * qoa->channels + /* 4 * 4 bytes lms state per channel */
|
num_frames * QOA_LMS_LEN * 4 * qoa->channels + /* 4 * 4 bytes lms state per channel */
|
||||||
num_slices * 8 * qoa->channels; /* 8 byte slices */
|
num_slices * 8 * qoa->channels; /* 8 byte slices */
|
||||||
|
|
||||||
unsigned char *bytes = (unsigned char *)QOA_MALLOC(encoded_size);
|
unsigned char *bytes = QOA_MALLOC(encoded_size);
|
||||||
|
|
||||||
for (unsigned int c = 0; c < qoa->channels; c++) {
|
for (unsigned int c = 0; c < qoa->channels; c++) {
|
||||||
/* Set the initial LMS weights to {0, 0, -1, 2}. This helps with the
|
/* Set the initial LMS weights to {0, 0, -1, 2}. This helps with the
|
||||||
@@ -626,12 +626,14 @@ unsigned int qoa_decode_frame(const unsigned char *bytes, unsigned int size, qoa
|
|||||||
qoa_uint64_t slice = qoa_read_u64(bytes, &p);
|
qoa_uint64_t slice = qoa_read_u64(bytes, &p);
|
||||||
|
|
||||||
int scalefactor = (slice >> 60) & 0xf;
|
int scalefactor = (slice >> 60) & 0xf;
|
||||||
|
slice <<= 4;
|
||||||
|
|
||||||
int slice_start = sample_index * channels + c;
|
int slice_start = sample_index * channels + c;
|
||||||
int slice_end = qoa_clamp(sample_index + QOA_SLICE_LEN, 0, samples) * channels + c;
|
int slice_end = qoa_clamp(sample_index + QOA_SLICE_LEN, 0, samples) * channels + c;
|
||||||
|
|
||||||
for (int si = slice_start; si < slice_end; si += channels) {
|
for (int si = slice_start; si < slice_end; si += channels) {
|
||||||
int predicted = qoa_lms_predict(&qoa->lms[c]);
|
int predicted = qoa_lms_predict(&qoa->lms[c]);
|
||||||
int quantized = (slice >> 57) & 0x7;
|
int quantized = (slice >> 61) & 0x7;
|
||||||
int dequantized = qoa_dequant_tab[scalefactor][quantized];
|
int dequantized = qoa_dequant_tab[scalefactor][quantized];
|
||||||
int reconstructed = qoa_clamp_s16(predicted + dequantized);
|
int reconstructed = qoa_clamp_s16(predicted + dequantized);
|
||||||
|
|
||||||
@@ -655,7 +657,7 @@ short *qoa_decode(const unsigned char *bytes, int size, qoa_desc *qoa) {
|
|||||||
|
|
||||||
/* Calculate the required size of the sample buffer and allocate */
|
/* Calculate the required size of the sample buffer and allocate */
|
||||||
int total_samples = qoa->samples * qoa->channels;
|
int total_samples = qoa->samples * qoa->channels;
|
||||||
short *sample_data = (short *)QOA_MALLOC(total_samples * sizeof(short));
|
short *sample_data = QOA_MALLOC(total_samples * sizeof(short));
|
||||||
|
|
||||||
unsigned int sample_index = 0;
|
unsigned int sample_index = 0;
|
||||||
unsigned int frame_len;
|
unsigned int frame_len;
|
||||||
|
|||||||
Reference in New Issue
Block a user