From a35110c70666e7471fffd6baf8eb1dc8b744f0f3 Mon Sep 17 00:00:00 2001 From: Luciano Iam Date: Wed, 28 Sep 2022 23:09:50 +0200 Subject: [PATCH] Support WavPack in st_audiofile --- external/st_audiofile/src/st_audiofile.c | 77 +++++++++++++++++++ external/st_audiofile/src/st_audiofile.h | 3 + .../st_audiofile/src/st_audiofile_common.c | 3 + external/st_audiofile/src/st_audiofile_libs.h | 1 + 4 files changed, 84 insertions(+) diff --git a/external/st_audiofile/src/st_audiofile.c b/external/st_audiofile/src/st_audiofile.c index 0659c3e7..2d3cc578 100644 --- a/external/st_audiofile/src/st_audiofile.c +++ b/external/st_audiofile/src/st_audiofile.c @@ -17,12 +17,14 @@ struct st_audio_file { AIFF_Ref aiff; drmp3 *mp3; stb_vorbis* ogg; + WavpackContext* wv; }; union { struct { uint32_t channels; float sample_rate; uint64_t frames; } aiff; struct { uint64_t frames; } mp3; struct { uint32_t channels; float sample_rate; uint64_t frames; } ogg; + struct { uint32_t channels; float sample_rate; uint64_t frames; int bitrate; int mode; } wv; } cache; union { @@ -173,6 +175,25 @@ static st_audio_file* st_generic_open_file(const void* filename, int widepath) } } + // Try WV + { + af->wv = +#if defined(_WIN32) + WavpackOpenFileInput((const char*)filename, NULL, OPEN_FILE_UTF8, 0); +#else + WavpackOpenFileInput((const char*)filename, NULL, 0, 0); +#endif + if (af->wv) { + af->cache.wv.channels = (uint32_t)WavpackGetNumChannels(af->wv); + af->cache.wv.sample_rate = (float)WavpackGetSampleRate(af->wv); + af->cache.wv.frames = (uint64_t)WavpackGetNumSamples64(af->wv); + af->cache.wv.bitrate = WavpackGetBitsPerSample(af->wv); + af->cache.wv.mode = WavpackGetMode(af->wv); + af->type = st_audio_file_wv; + return af; + } + } + free(af); return NULL; } @@ -278,6 +299,17 @@ st_audio_file* st_open_memory(const void* memory, size_t length) } } + // Try WV + { + af->wv = + WavpackOpenRawDecoder((void*)memory, (int32_t)length, NULL, 0, + WAVPACK_MEMORY_ASSUMED_VERSION, NULL, 0, 0); + if (af->wv) { + af->type = st_audio_file_wv; + return af; + } + } + free(af); return NULL; } @@ -315,6 +347,9 @@ void st_close(st_audio_file* af) drmp3_uninit(af->mp3); free(af->mp3); break; + case st_audio_file_wv: + WavpackCloseFile(af->wv); + break; } free(af); @@ -345,6 +380,9 @@ uint32_t st_get_channels(st_audio_file* af) case st_audio_file_mp3: channels = af->mp3->channels; break; + case st_audio_file_wv: + channels = af->cache.wv.channels; + break; } return channels; @@ -370,6 +408,9 @@ float st_get_sample_rate(st_audio_file* af) case st_audio_file_mp3: sample_rate = af->mp3->sampleRate; break; + case st_audio_file_wv: + sample_rate = af->cache.wv.sample_rate; + break; } return sample_rate; @@ -395,6 +436,9 @@ uint64_t st_get_frame_count(st_audio_file* af) case st_audio_file_mp3: frames = af->cache.mp3.frames; break; + case st_audio_file_wv: + frames = af->cache.wv.frames; + break; } return frames; @@ -420,6 +464,9 @@ bool st_seek(st_audio_file* af, uint64_t frame) case st_audio_file_mp3: success = drmp3_seek_to_pcm_frame(af->mp3, frame); break; + case st_audio_file_wv: + success = WavpackSeekSample64(af->wv, (int64_t)frame); + break; } return success; @@ -449,6 +496,24 @@ uint64_t st_read_s16(st_audio_file* af, int16_t* buffer, uint64_t count) case st_audio_file_mp3: count = drmp3_read_pcm_frames_s16(af->mp3, count, buffer); break; + case st_audio_file_wv: + { + int32_t* buf_i32 = (int32_t*)malloc(4 * count); + if (!buf_i32) { + return 0; + } + count = WavpackUnpackSamples(af->wv, buf_i32, (uint32_t)count); + if (af->cache.wv.mode & MODE_FLOAT) { + drwav_f32_to_s16((drwav_int16*)buffer, (float*)buf_i32, (size_t)count); + } else { + int d = af->cache.wv.bitrate - 16; + for (uint64_t i = 0; i < count; i++) { + buffer[i] = (int16_t)(buf_i32[i] >> d); + } + } + free(buf_i32); + } + break; } return count; @@ -478,6 +543,18 @@ uint64_t st_read_f32(st_audio_file* af, float* buffer, uint64_t count) case st_audio_file_mp3: count = drmp3_read_pcm_frames_f32(af->mp3, count, buffer); break; + case st_audio_file_wv: + count = WavpackUnpackSamples(af->wv, (int32_t*)buffer, (uint32_t)count); + if (!(af->cache.wv.mode & MODE_FLOAT)) { + if (af->cache.wv.bitrate < 32) { + int d = 32 - af->cache.wv.bitrate; + for (uint64_t i = 0; i < count; i++) { + ((int32_t*)buffer)[i] <<= d; + } + } + drwav_s32_to_f32(buffer, (drwav_int32*)buffer, (size_t)count); + } + break; } return count; diff --git a/external/st_audiofile/src/st_audiofile.h b/external/st_audiofile/src/st_audiofile.h index f4f7d252..6822cd0e 100644 --- a/external/st_audiofile/src/st_audiofile.h +++ b/external/st_audiofile/src/st_audiofile.h @@ -19,6 +19,8 @@ #include #endif +#define WAVPACK_MEMORY_ASSUMED_VERSION 5 + #ifdef __cplusplus extern "C" { #endif @@ -31,6 +33,7 @@ typedef enum st_audio_file_type { st_audio_file_aiff, st_audio_file_ogg, st_audio_file_mp3, + st_audio_file_wv, st_audio_file_other, } st_audio_file_type; diff --git a/external/st_audiofile/src/st_audiofile_common.c b/external/st_audiofile/src/st_audiofile_common.c index c3e14297..0ab77bc4 100644 --- a/external/st_audiofile/src/st_audiofile_common.c +++ b/external/st_audiofile/src/st_audiofile_common.c @@ -32,6 +32,9 @@ const char* st_type_string(int type) case st_audio_file_mp3: type_string = "MP3"; break; + case st_audio_file_wv: + type_string = "WV"; + break; case st_audio_file_other: type_string = "other"; break; diff --git a/external/st_audiofile/src/st_audiofile_libs.h b/external/st_audiofile/src/st_audiofile_libs.h index 67aacaba..f60b9f6b 100644 --- a/external/st_audiofile/src/st_audiofile_libs.h +++ b/external/st_audiofile/src/st_audiofile_libs.h @@ -15,6 +15,7 @@ #endif #include "stb_vorbis.c" #include "libaiff/libaiff.h" +#include "wavpack.h" #if defined(_WIN32) #include