cleanup: cli utils

This commit is contained in:
bnnm 2024-07-21 18:22:42 +02:00
parent f6b2c6fab3
commit 637c93b694
13 changed files with 247 additions and 157 deletions

View File

@ -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

View File

@ -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)

View File

@ -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)

View File

@ -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) {

View File

@ -4,10 +4,10 @@
#define POSIXLY_CORRECT
#include <getopt.h>
#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;
}

View File

@ -103,8 +103,12 @@
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="wav_utils.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="vgmstream_cli.c" />
<ClCompile Include="wav_utils.c" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\ext_libs\ext_libs.vcxproj">

View File

@ -1,6 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
</Filter>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
@ -14,9 +18,17 @@
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="wav_utils.h">
<Filter>Header Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClCompile Include="vgmstream_cli.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="wav_utils.c">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>

152
cli/wav_utils.c Normal file
View File

@ -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
}

28
cli/wav_utils.h Normal file
View File

@ -0,0 +1,28 @@
#ifndef _WAV_UTILS_H_
#define _WAV_UTILS_H_
#include <stdint.h>
#include <stdbool.h>
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

View File

@ -1,3 +1,4 @@
#include <string.h> // 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) {

View File

@ -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

View File

@ -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<sample_count;insample++,outsample+=channel_count) {
outbuffer[outsample]=inbuffer[insample];
}
}
*/
/* failed attempt at interleave in place */
/*
void interleave_stereo(sample_t * buffer, int32_t sample_count) {
int32_t tomove, belongs;
sample_t moving,temp;
tomove = sample_count;
moving = buffer[tomove];
do {
if (tomove<sample_count)
belongs = tomove*2;
else
belongs = (tomove-sample_count)*2+1;
temp = buffer[belongs];
buffer[belongs] = moving;
moving = temp;
tomove = belongs;
} while (tomove != sample_count);
}
*/

View File

@ -1,9 +0,0 @@
#ifndef _SAMPLES_OPS_H
#define _SAMPLES_OPS_H
#include "../streamtypes.h"
/* swap samples in machine endianness to little endian (useful to write .wav) */
void swap_samples_le(sample_t* buf, int count);
#endif