From 637c93b6948f31e39c58fb92391961687fe092ef Mon Sep 17 00:00:00 2001 From: bnnm Date: Sun, 21 Jul 2024 18:22:42 +0200 Subject: [PATCH] cleanup: cli utils --- cli/CMakeLists.txt | 4 +- cli/Makefile | 4 +- cli/Makefile.autotools.am | 4 +- cli/vgmstream123.c | 3 +- cli/vgmstream_cli.c | 83 +++------------- cli/vgmstream_cli.vcxproj | 4 + cli/vgmstream_cli.vcxproj.filters | 12 +++ cli/wav_utils.c | 152 ++++++++++++++++++++++++++++++ cli/wav_utils.h | 28 ++++++ src/util/reader.c | 25 +++++ src/util/reader_put.h | 13 +-- src/util/samples_ops.c | 63 ------------- src/util/samples_ops.h | 9 -- 13 files changed, 247 insertions(+), 157 deletions(-) create mode 100644 cli/wav_utils.c create mode 100644 cli/wav_utils.h delete mode 100644 src/util/samples_ops.c delete mode 100644 src/util/samples_ops.h diff --git a/cli/CMakeLists.txt b/cli/CMakeLists.txt index 3bd0fd60..937658a0 100644 --- a/cli/CMakeLists.txt +++ b/cli/CMakeLists.txt @@ -1,7 +1,7 @@ # CLI add_executable(vgmstream_cli - vgmstream_cli.c) + vgmstream_cli.c wav_utils.c) set_target_properties(vgmstream_cli PROPERTIES PREFIX "" @@ -67,7 +67,7 @@ if(NOT WIN32 AND BUILD_V123) # vgmstream123 add_executable(vgmstream123 - vgmstream123.c) + vgmstream123.c wav_utils.c) # Link to the vgmstream library as well as libao target_link_libraries(vgmstream123 diff --git a/cli/Makefile b/cli/Makefile index 066d43f2..50a0a335 100644 --- a/cli/Makefile +++ b/cli/Makefile @@ -41,11 +41,11 @@ export CFLAGS LDFLAGS ### targets vgmstream_cli: libvgmstream.a $(TARGET_EXT_LIBS) - $(CC) $(CFLAGS) vgmstream_cli.c $(LDFLAGS) -o $(OUTPUT_CLI) + $(CC) $(CFLAGS) vgmstream_cli.c wav_utils.c $(LDFLAGS) -o $(OUTPUT_CLI) $(STRIP) $(OUTPUT_CLI) vgmstream123: libvgmstream.a $(TARGET_EXT_LIBS) - $(CC) $(CFLAGS) $(LIBAO_INC) vgmstream123.c $(LDFLAGS) $(LIBAO_LIB) -o $(OUTPUT_123) + $(CC) $(CFLAGS) $(LIBAO_INC) vgmstream123.c wav_utils.c $(LDFLAGS) $(LIBAO_LIB) -o $(OUTPUT_123) $(STRIP) $(OUTPUT_123) api_example: libvgmstream.a $(TARGET_EXT_LIBS) diff --git a/cli/Makefile.autotools.am b/cli/Makefile.autotools.am index ca51eea5..9ff02a49 100644 --- a/cli/Makefile.autotools.am +++ b/cli/Makefile.autotools.am @@ -9,8 +9,8 @@ endif AM_CFLAGS = -DVGMSTREAM_VERSION_AUTO -DVGM_LOG_OUTPUT -I$(top_builddir) -I$(top_srcdir) -I$(top_srcdir)/ext_includes/ $(AO_CFLAGS) AM_MAKEFLAGS = -f Makefile.autotools -vgmstream_cli_SOURCES = vgmstream_cli.c +vgmstream_cli_SOURCES = vgmstream_cli.c wav_utils.c vgmstream_cli_LDADD = ../src/libvgmstream.la -vgmstream123_SOURCES = vgmstream123.c +vgmstream123_SOURCES = vgmstream123.c wav_utils.c vgmstream123_LDADD = ../src/libvgmstream.la $(AO_LIBS) diff --git a/cli/vgmstream123.c b/cli/vgmstream123.c index 191a7bb2..da47cc1c 100644 --- a/cli/vgmstream123.c +++ b/cli/vgmstream123.c @@ -39,7 +39,6 @@ #include "../src/vgmstream.h" #include "../src/api.h" -#include "../src/util/samples_ops.h" #include "../version.h" #ifndef VGMSTREAM_VERSION @@ -397,7 +396,7 @@ static int play_vgmstream(const char* filename, song_settings_t* cfg) { render_vgmstream(buffer, to_do, vgmstream); #if LITTLE_ENDIAN_OUTPUT - swap_samples_le(buffer, output_channels * to_do); + swap_samples_le(buffer, output_channels * to_do, 0); #endif if (verbose && !out_filename) { diff --git a/cli/vgmstream_cli.c b/cli/vgmstream_cli.c index f5ed813d..60f49b2c 100644 --- a/cli/vgmstream_cli.c +++ b/cli/vgmstream_cli.c @@ -4,10 +4,10 @@ #define POSIXLY_CORRECT #include +#include "wav_utils.h" #include "../src/vgmstream.h" #include "../src/api.h" #include "../src/util.h" -#include "../src/util/samples_ops.h" //todo use <>? #ifdef HAVE_JSON #include "jansson/jansson.h" @@ -48,8 +48,6 @@ //extern int optind, opterr, optopt; -static size_t make_wav_header(uint8_t* buf, size_t buf_size, int32_t sample_count, int32_t sample_rate, int channels, int smpl_chunk, int32_t loop_start, int32_t loop_end); - static void usage(const char* progname, int is_help) { fprintf(is_help ? stdout : stderr, APP_INFO "\n" @@ -901,7 +899,7 @@ static int write_file(VGMSTREAM* vgmstream, cli_config* cfg) { render_vgmstream(buf, to_get, vgmstream); - swap_samples_le(buf, channels * to_get); /* change to WAV (LE) endian if PC is Big Endian */ + swap_samples_le(buf, channels * to_get, 0); fwrite(buf, sizeof(sample_t), to_get * channels, outfile); /* should write infinitely until program kill */ } @@ -912,10 +910,16 @@ static int write_file(VGMSTREAM* vgmstream, cli_config* cfg) { uint8_t wav_buf[0x100]; size_t bytes_done; - bytes_done = make_wav_header(wav_buf,0x100, - len_samples, vgmstream->sample_rate, channels, - cfg->write_lwav, cfg->lwav_loop_start, cfg->lwav_loop_end); + wav_header_t wav = { + .sample_count = len_samples, + .sample_rate = vgmstream->sample_rate, + .channels = channels, + .write_smpl_chunk = cfg->write_lwav, + .loop_start = cfg->lwav_loop_start, + .loop_end = cfg->lwav_loop_end + }; + bytes_done = wav_make_header(wav_buf, 0x100, &wav); fwrite(wav_buf, sizeof(uint8_t), bytes_done, outfile); } @@ -929,7 +933,7 @@ static int write_file(VGMSTREAM* vgmstream, cli_config* cfg) { render_vgmstream(buf, to_get, vgmstream); if (!cfg->decode_only) { - swap_samples_le(buf, channels * to_get); /* change to WAV (LE) endian if PC is Big Endian */ + swap_samples_le(buf, channels * to_get, 0); fwrite(buf, sizeof(sample_t), to_get * channels, outfile); } } @@ -1020,66 +1024,3 @@ static void print_json_info(VGMSTREAM* vgm, cli_config* cfg) { json_decref(final_object); } #endif - -static void make_smpl_chunk(uint8_t* buf, int32_t loop_start, int32_t loop_end) { - int i; - - memcpy(buf+0, "smpl", 0x04); /* header */ - put_s32le(buf+0x04, 0x3c); /* size */ - - for (i = 0; i < 7; i++) - put_s32le(buf+0x08 + i * 0x04, 0); - - put_s32le(buf+0x24, 1); - - for (i = 0; i < 3; i++) - put_s32le(buf+0x28 + i * 0x04, 0); - - put_s32le(buf+0x34, loop_start); - put_s32le(buf+0x38, loop_end); - put_s32le(buf+0x3C, 0); - put_s32le(buf+0x40, 0); -} - -/* make a RIFF header for .wav */ -static size_t make_wav_header(uint8_t* buf, size_t buf_size, int32_t sample_count, int32_t sample_rate, int channels, int smpl_chunk, int32_t loop_start, int32_t loop_end) { - size_t data_size, header_size; - - data_size = sample_count * channels * sizeof(sample_t); - header_size = 0x2c; - if (smpl_chunk && loop_end) - header_size += 0x3c+ 0x08; - - if (header_size > buf_size) - goto fail; - - memcpy(buf+0x00, "RIFF", 0x04); /* RIFF header */ - put_u32le(buf+0x04, (int32_t)(header_size - 0x08 + data_size)); /* size of RIFF */ - - memcpy(buf+0x08, "WAVE", 4); /* WAVE header */ - - memcpy(buf+0x0c, "fmt ", 0x04); /* WAVE fmt chunk */ - put_s32le(buf+0x10, 0x10); /* size of WAVE fmt chunk */ - put_s16le(buf+0x14, 0x0001); /* codec PCM */ - put_s16le(buf+0x16, channels); /* channel count */ - put_s32le(buf+0x18, sample_rate); /* sample rate */ - put_s32le(buf+0x1c, sample_rate * channels * sizeof(sample_t)); /* bytes per second */ - put_s16le(buf+0x20, (int16_t)(channels * sizeof(sample_t))); /* block align */ - put_s16le(buf+0x22, sizeof(sample_t) * 8); /* significant bits per sample */ - - if (smpl_chunk && loop_end) { - make_smpl_chunk(buf+0x24, loop_start, loop_end); - memcpy(buf+0x24+0x3c+0x08, "data", 0x04); /* WAVE data chunk */ - put_u32le(buf+0x28+0x3c+0x08, (int32_t)data_size); /* size of WAVE data chunk */ - } - else { - memcpy(buf+0x24, "data", 0x04); /* WAVE data chunk */ - put_s32le(buf+0x28, (int32_t)data_size); /* size of WAVE data chunk */ - } - - /* could try to add channel_layout, but would need to write WAVEFORMATEXTENSIBLE (maybe only if arg flag?) */ - - return header_size; -fail: - return 0; -} diff --git a/cli/vgmstream_cli.vcxproj b/cli/vgmstream_cli.vcxproj index 4027b453..65db446f 100644 --- a/cli/vgmstream_cli.vcxproj +++ b/cli/vgmstream_cli.vcxproj @@ -103,8 +103,12 @@ true + + + + diff --git a/cli/vgmstream_cli.vcxproj.filters b/cli/vgmstream_cli.vcxproj.filters index 57e5973a..06cfb34d 100644 --- a/cli/vgmstream_cli.vcxproj.filters +++ b/cli/vgmstream_cli.vcxproj.filters @@ -1,6 +1,10 @@  + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx @@ -14,9 +18,17 @@ rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav + + + Header Files + + Source Files + + Source Files + \ No newline at end of file diff --git a/cli/wav_utils.c b/cli/wav_utils.c new file mode 100644 index 00000000..6bf056c3 --- /dev/null +++ b/cli/wav_utils.c @@ -0,0 +1,152 @@ +#include "wav_utils.h" +#include "../src/util/reader_put.h" + +static int make_riff_chunk(uint8_t* buf, wav_header_t* wav, uint32_t header_size, uint32_t data_size) { + + put_data (buf+0x00, "RIFF", 0x04); + put_u32le(buf+0x04, header_size - 0x08 + data_size); + + put_data (buf+0x08, "WAVE", 0x04); + + return 0x08 + 0x04; +} + +static int make_fmt_chunk(uint8_t* buf, wav_header_t* wav) { + + int codec = wav->is_float ? 0x0003 : 0x0001; /* PCM */ + int bytes_per_second = wav->sample_rate * wav->channels * wav->sample_size; + int16_t block_align = wav->channels * wav->sample_size; + int bits_per_sample = wav->sample_size * 8; + + put_data (buf + 0x00, "fmt ", 0x04); + put_u32le(buf + 0x04, 0x10); + + put_s16le(buf + 0x08, codec); + put_s16le(buf + 0x0a, wav->channels); + put_s32le(buf + 0x0c, wav->sample_rate); + put_s32le(buf + 0x10, bytes_per_second); + put_s16le(buf + 0x14, block_align); + put_s16le(buf + 0x16, bits_per_sample); + + return 0x08 + 0x10; +} + +/* see riff.c */ +static int make_smpl_chunk(uint8_t* buf, wav_header_t* wav) { + + put_data (buf + 0x00, "smpl", 0x04); + put_s32le(buf + 0x04, 0x3c); + + for (int i = 0; i < 7; i++) { + put_s32le(buf + 0x08 + i * 0x04, 0); + } + + put_s32le(buf + 0x24, 1); + + for (int i = 0; i < 3; i++) { + put_s32le(buf + 0x28 + i * 0x04, 0); + } + + put_s32le(buf + 0x34, wav->loop_start); + put_s32le(buf + 0x38, wav->loop_end); + put_s32le(buf + 0x3C, 0); + put_s32le(buf + 0x40, 0); + + return 0x08 + 0x3c; +} + +static int make_data_chunk(uint8_t* buf, wav_header_t* wav, uint32_t data_size) { + + put_data (buf + 0x00, "data", 0x04); + put_u32le(buf + 0x04, data_size); + + return 0x08; +} + +/* make a RIFF header for .wav */ +size_t wav_make_header(uint8_t* buf, size_t buf_size, wav_header_t* wav) { + size_t header_size; + + /* RIFF + fmt + smpl + data */ + header_size = 0x08 + 0x04; + header_size += 0x08 + 0x10; + if (wav->write_smpl_chunk && wav->loop_end) + header_size += 0x08 + 0x3c; + header_size += 0x08; + + if (header_size > buf_size) + return 0; + + if (!wav->sample_size) + wav->sample_size = sizeof(short); + if (wav->sample_size <= 0 || wav->sample_size >= 4) + return 0; + + size_t data_size = wav->sample_count * wav->channels * wav->sample_size; + int size; + + size = make_riff_chunk(buf, wav, header_size, data_size); + buf += size; + + size = make_fmt_chunk(buf, wav); + buf += size; + + if (wav->write_smpl_chunk && wav->loop_end) { + size = make_smpl_chunk(buf, wav); + buf += size; + } + + size = make_data_chunk(buf, wav, data_size); + buf += size; + + /* could try to add channel_layout but would need WAVEFORMATEXTENSIBLE */ + + return header_size; +} + +#if 0 +void swap_samples_le(sample_t *buf, int count) { + /* Windows can't be BE... I think */ +#if !defined(_WIN32) +#if !defined(__BYTE_ORDER__) || __BYTE_ORDER__ != __ORDER_LITTLE_ENDIAN__ + for (int i = 0; i < count; i++) { + /* 16b sample in memory: aabb where aa=MSB, bb=LSB */ + uint8_t b0 = buf[i] & 0xff; + uint8_t b1 = buf[i] >> 8; + uint8_t *p = (uint8_t*)&(buf[i]); + /* 16b sample in buffer: bbaa where bb=LSB, aa=MSB */ + p[0] = b0; + p[1] = b1; + /* when endianness is LE, buffer has bbaa already so this function can be skipped */ + } +#endif +#endif +} +#endif + + +static inline void swap_value(uint8_t* buf, int sample_size) { + for (int i = 0; i < sample_size / 2; i++) { + char temp = buf[i]; + buf[i] = buf[sample_size - i - 1]; + buf[sample_size - i - 1] = temp; + } +} + +/* when endianness is LE buffer is correct already and this function can be skipped */ +void swap_samples_le(void* samples, int samples_len, int sample_size) { + /* Windows can't be BE... I think */ +#if !defined(_WIN32) +#if !defined(__BYTE_ORDER__) || __BYTE_ORDER__ != __ORDER_LITTLE_ENDIAN__ + if (!sample_size) + sample_size = sizeof(short); + + /* 16b sample in memory is AABB where AA=MSB, BB=LSB, swap to BBAA */ + + uint8_t* buf = samples; + for (int i = 0; i < samples_len; i += sample_size) { + swap_value(buf + i, sample_size); + } +#endif +#endif +} diff --git a/cli/wav_utils.h b/cli/wav_utils.h new file mode 100644 index 00000000..eaab7abb --- /dev/null +++ b/cli/wav_utils.h @@ -0,0 +1,28 @@ +#ifndef _WAV_UTILS_H_ +#define _WAV_UTILS_H_ + +#include +#include + +typedef struct { + bool is_float; + int sample_size; + + int32_t sample_count; + int32_t sample_rate; + int channels; + + bool write_smpl_chunk; + int32_t loop_start; + int32_t loop_end; +} wav_header_t; + +/* make a RIFF header for .wav; returns final RIFF size or 0 if buffer is too small */ +size_t wav_make_header(uint8_t* buf, size_t buf_size, wav_header_t* wav); + +/* swap big endian samples to little endian. Does nothing if machine is already LE. + * Used when writting .WAV files, where samples in memory/buf may be BE while RIFF + * is expected to have LE samples. */ +void swap_samples_le(void* samples, int samples_len, int sample_size); + +#endif diff --git a/src/util/reader.c b/src/util/reader.c index 2b9af394..34148567 100644 --- a/src/util/reader.c +++ b/src/util/reader.c @@ -1,3 +1,4 @@ +#include // memcpy #include "reader_put.h" #include "reader_text.h" #include "reader_sf.h" @@ -31,6 +32,30 @@ void put_u32be(uint8_t* buf, uint32_t v) { buf[3] = (uint8_t)((v >> 0) & 0xFF); } +void put_s8(uint8_t* buf, int8_t v) { + put_u8(buf, v); +} + +void put_s16le(uint8_t* buf, int16_t v) { + put_u16le(buf, v); +} + +void put_s32le(uint8_t* buf, int32_t v) { + put_u32le(buf, v); +} + +void put_s16be(uint8_t* buf, int16_t v) { + put_u16be(buf, v); +} + +void put_s32be(uint8_t* buf, int32_t v) { + put_u32be(buf, v); +} + +void put_data(uint8_t* buf, void* v, int v_size) { + memcpy (buf, v, v_size); +} + /* **************************************************** */ size_t read_line(char* buf, int buf_size, off_t offset, STREAMFILE* sf, int* p_line_ok) { diff --git a/src/util/reader_put.h b/src/util/reader_put.h index 98799c63..04611146 100644 --- a/src/util/reader_put.h +++ b/src/util/reader_put.h @@ -9,11 +9,12 @@ void put_u32le(uint8_t* buf, uint32_t v); void put_u16be(uint8_t* buf, uint16_t v); void put_u32be(uint8_t* buf, uint32_t v); -/* alias of the above */ //TODO: improve -#define put_s8 put_u8 -#define put_s16le put_u16le -#define put_s32le put_u32le -#define put_s16be put_u16be -#define put_s32be put_u32be +void put_s8(uint8_t* buf, int8_t v); +void put_s16le(uint8_t* buf, int16_t v); +void put_s32le(uint8_t* buf, int32_t v); +void put_s16be(uint8_t* buf, int16_t v); +void put_s32be(uint8_t* buf, int32_t v); + +void put_data(uint8_t* buf, void* v, int v_size); #endif diff --git a/src/util/samples_ops.c b/src/util/samples_ops.c deleted file mode 100644 index b4e09cad..00000000 --- a/src/util/samples_ops.c +++ /dev/null @@ -1,63 +0,0 @@ -#include "samples_ops.h" - - -void swap_samples_le(sample_t *buf, int count) { - /* Windows can't be BE... I think */ -#if !defined(_WIN32) -#if !defined(__BYTE_ORDER__) || __BYTE_ORDER__ != __ORDER_LITTLE_ENDIAN__ - int i; - for (i = 0; i < count; i++) { - /* 16b sample in memory: aabb where aa=MSB, bb=LSB */ - uint8_t b0 = buf[i] & 0xff; - uint8_t b1 = buf[i] >> 8; - uint8_t *p = (uint8_t*)&(buf[i]); - /* 16b sample in buffer: bbaa where bb=LSB, aa=MSB */ - p[0] = b0; - p[1] = b1; - /* when endianness is LE, buffer has bbaa already so this function can be skipped */ - } -#endif -#endif -} - - -/* unused */ -/* -void interleave_channel(sample_t * outbuffer, sample_t * inbuffer, int32_t sample_count, int channel_count, int channel_number) { - int32_t insample,outsample; - - if (channel_count==1) { - memcpy(outbuffer,inbuffer,sizeof(sample)*sample_count); - return; - } - - for (insample=0,outsample=channel_number;insample