mirror of
https://github.com/ScrelliCopter/VGM-Tools
synced 2025-02-21 04:09:25 +11:00
get adpcm tools working on mac and somewhat unify the codebase
This commit is contained in:
@@ -1,14 +1,17 @@
|
||||
cmake_minimum_required(VERSION 3.15 FATAL_ERROR)
|
||||
project(dsptools LANGUAGES C)
|
||||
|
||||
set(COMMON "${CMAKE_SOURCE_DIR}/../common")
|
||||
|
||||
add_subdirectory(libdsptool)
|
||||
|
||||
set(HEADERS wave.h)
|
||||
set(SOURCES wavefile.c wave.c dspdecode.c)
|
||||
set(HEADERS ${COMMON}/wave.h ${COMMON}/endian.h)
|
||||
set(SOURCES ${COMMON}/wavefile.c ${COMMON}/wave.c dspdecode.c)
|
||||
|
||||
add_executable(dspdecode ${HEADERS} ${SOURCES})
|
||||
|
||||
set_property(TARGET dspdecode PROPERTY C_STANDARD 99)
|
||||
target_include_directories(dspdecode PRIVATE ${COMMON})
|
||||
target_link_libraries(dspdecode DspTool::DspTool)
|
||||
target_compile_options(dspdecode PRIVATE
|
||||
$<$<C_COMPILER_ID:AppleClang,Clang,GNU>:-Wall -Wextra -pedantic>
|
||||
|
||||
@@ -1,72 +0,0 @@
|
||||
#ifndef COMMON_H
|
||||
#define COMMON_H
|
||||
|
||||
#ifdef __APPLE__
|
||||
# include <machine/endian.h>
|
||||
#elif defined( __linux__ ) || defined( __CYGWIN__ ) || defined( __OpenBSD__ )
|
||||
# include <endian.h>
|
||||
#elif defined( __NetBSD__ ) || defined( __FreeBSD__ ) || defined( __DragonFly__ )
|
||||
# include <sys/endian.h>
|
||||
# ifdef __FreeBSD__
|
||||
# define LITTLE_ENDIAN _LITTLE_ENDIAN
|
||||
# define BIG_ENDIAN _BIG_ENDIAN
|
||||
# define BYTE_ORDER _BYTE_ORDER
|
||||
# endif
|
||||
#elif defined( _MSC_VER ) || defined( _WIN16 ) || defined( _WIN32 ) || defined( _WIN64 )
|
||||
# ifdef _MSC_VER
|
||||
# define LITTLE_ENDIAN 1234
|
||||
# define BIG_ENDIAN 4321
|
||||
# if defined( _M_IX86 ) || defined( _M_X64 ) || defined( _M_AMD64 ) || defined( _M_IA64 )
|
||||
# define BYTE_ORDER LITTLE_ENDIAN
|
||||
# elif defined( _M_PPC )
|
||||
// Probably not reliable but eh
|
||||
# define BYTE_ORDER BIG_ENDIAN
|
||||
# endif
|
||||
# elif defined( __GNUC__ )
|
||||
# include <sys/param.h>
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if !defined( BYTE_ORDER ) || !defined( LITTLE_ENDIAN ) || !defined( BIG_ENDIAN ) || \
|
||||
!( BYTE_ORDER == LITTLE_ENDIAN || BYTE_ORDER == BIG_ENDIAN )
|
||||
# error "Couldn't determine endianness or unsupported platform"
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# define swap32(X) _byteswap_ulong((X))
|
||||
# define swap16(X) _byteswap_ushort((X))
|
||||
#elif ( __GNUC__ == 4 && __GNUC_MINOR__ >= 8 ) || ( __GNUC__ > 4 )
|
||||
# pragma message("CLion penis")
|
||||
# define swap32(X) __builtin_bswap32((X))
|
||||
# define swap16(X) __builtin_bswap16((X))
|
||||
// Apparently smelly GCC 5 blows up on this test so this is done separately for Clang
|
||||
#elif defined( __has_builtin ) && __has_builtin( __builtin_bswap32 ) && __has_builtin( __builtin_bswap16 )
|
||||
# define swap32(X) __builtin_bswap32((X))
|
||||
# define swap16(X) __builtin_bswap16((X))
|
||||
#else
|
||||
static inline uint32_t swap32(uint32_t v)
|
||||
{
|
||||
return (v << 24U) | ((v << 8U) & 0x00FF0000U) | ((v >> 8U) & 0x0000FF00U) | (v >> 24U);
|
||||
}
|
||||
static inline uint16_t swap16(uint16_t v)
|
||||
{
|
||||
return (v << 8U) | (v >> 8U);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if BYTE_ORDER == LITTLE_ENDIAN
|
||||
# define SWAP_LE32(V) (V)
|
||||
# define SWAP_LE16(V) (V)
|
||||
# define SWAP_BE32(V) swap32((V))
|
||||
# define SWAP_BE16(V) swap16((V))
|
||||
#elif BYTE_ORDER == BIG_ENDIAN
|
||||
# define SWAP_LE32(V) swap32((V))
|
||||
# define SWAP_LE16(V) swap16((V))
|
||||
# define SWAP_BE32(V) (V)
|
||||
# define SWAP_BE16(V) (V)
|
||||
#endif
|
||||
|
||||
#define MIN(A, B) (((A) < (B)) ? (A) : (B))
|
||||
#define MAX(A, B) (((A) > (B)) ? (A) : (B))
|
||||
|
||||
#endif//COMMON_H
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
#include "dsptool.h"
|
||||
#include "wave.h"
|
||||
#include "common.h"
|
||||
#include "endian.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
@@ -3,14 +3,16 @@ project(DspTool LANGUAGES C)
|
||||
|
||||
option(BUILD_SHARED_LIBS "Build as a Shared Object or DLL" OFF)
|
||||
|
||||
set(HEADERS ../common.h dsptool.h)
|
||||
set(HEADERS dsptool.h ${COMMON}/util.h)
|
||||
set(SOURCES math.c decode.c encode.c)
|
||||
|
||||
add_library(DspTool ${HEADERS} ${SOURCES})
|
||||
add_library(DspTool::DspTool ALIAS DspTool)
|
||||
|
||||
target_include_directories(DspTool PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
set_property(TARGET DspTool PROPERTY C_STANDARD 99)
|
||||
target_include_directories(DspTool
|
||||
PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
PRIVATE ${COMMON})
|
||||
if (BUILD_SHARED_LIBS)
|
||||
target_compile_definitions(DspTool PRIVATE BUILD_SHARED)
|
||||
endif()
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* (c) 2017 Alex Barney (MIT) */
|
||||
|
||||
#include <stdint.h>
|
||||
#include "../common.h"
|
||||
#include "util.h"
|
||||
#include "dsptool.h"
|
||||
|
||||
static inline uint8_t GetHighNibble(uint8_t value)
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#include <math.h>
|
||||
#include <float.h>
|
||||
#include <string.h>
|
||||
#include "../common.h"
|
||||
#include "util.h"
|
||||
#include "dsptool.h"
|
||||
|
||||
/* Temporal Vector
|
||||
|
||||
149
dsptools/wave.c
149
dsptools/wave.c
@@ -1,149 +0,0 @@
|
||||
/* wave.c (c) 2023 a dinosaur (zlib) */
|
||||
|
||||
#include "wave.h"
|
||||
#include "common.h"
|
||||
|
||||
#define FOURCC_RIFF "RIFF"
|
||||
#define FOURCC_WAVE "WAVE"
|
||||
#define FOURCC_FORM "fmt "
|
||||
#define FOURCC_SAMP "smpl"
|
||||
#define FOURCC_DATA "data"
|
||||
|
||||
#define FORMAT_CHUNK_SIZE 16
|
||||
typedef struct
|
||||
{
|
||||
uint16_t format;
|
||||
uint16_t channels;
|
||||
uint32_t samplerate;
|
||||
uint32_t byterate;
|
||||
uint16_t alignment;
|
||||
uint16_t bitdepth;
|
||||
|
||||
} FormatChunk;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32_t id;
|
||||
uint32_t type;
|
||||
uint32_t loopstart;
|
||||
uint32_t loopend;
|
||||
uint32_t fraction;
|
||||
uint32_t playcount;
|
||||
|
||||
} SampleLoopChunk;
|
||||
|
||||
#define SMPL_CHUNK_HEAD_SIZE 24
|
||||
typedef struct
|
||||
{
|
||||
uint32_t manufacturer;
|
||||
uint32_t product;
|
||||
uint32_t samplePeriod;
|
||||
uint32_t midiUniNote;
|
||||
uint32_t midiPitchFrac;
|
||||
uint32_t smpteFormat;
|
||||
uint32_t smpteOffset;
|
||||
uint32_t sampleLoopCount;
|
||||
uint32_t sampleData;
|
||||
|
||||
} SamplerChunk;
|
||||
|
||||
static void writeFourcc(const WaveStreamCb* restrict cb, void* restrict user, const char fourcc[4])
|
||||
{
|
||||
cb->write(user, fourcc, 1, 4);
|
||||
}
|
||||
|
||||
static void writeU32le(const WaveStreamCb* restrict cb, void* restrict user, uint32_t v)
|
||||
{
|
||||
uint32_t tmp = SWAP_LE32(v);
|
||||
cb->write(user, &tmp, sizeof(uint32_t), 1);
|
||||
}
|
||||
|
||||
static void writeU16le(const WaveStreamCb* restrict cb, void* restrict user, uint16_t v)
|
||||
{
|
||||
uint16_t tmp = SWAP_LE16(v);
|
||||
cb->write(user, &tmp, sizeof(uint16_t), 1);
|
||||
}
|
||||
|
||||
void writeRiffChunk(const WaveStreamCb* restrict cb, void* restrict user, char fourcc[4], uint32_t size)
|
||||
{
|
||||
writeFourcc(cb, user, fourcc);
|
||||
writeU32le(cb, user, size);
|
||||
}
|
||||
|
||||
void writeFormatChunk(const WaveStreamCb* restrict cb, void* restrict user, const FormatChunk* fmt)
|
||||
{
|
||||
writeRiffChunk(cb, user, FOURCC_FORM, FORMAT_CHUNK_SIZE);
|
||||
writeU16le(cb, user, fmt->format);
|
||||
writeU16le(cb, user, fmt->channels);
|
||||
writeU32le(cb, user, fmt->samplerate);
|
||||
writeU32le(cb, user, fmt->byterate);
|
||||
writeU16le(cb, user, fmt->alignment);
|
||||
writeU16le(cb, user, fmt->bitdepth);
|
||||
}
|
||||
|
||||
static int waveWriteHeader(const WaveSpec* spec, size_t dataLen, const WaveStreamCb* cb, void* user)
|
||||
{
|
||||
if (!spec || !dataLen || dataLen >= UINT32_MAX || !cb || !cb->write)
|
||||
return 1;
|
||||
|
||||
if (spec->format != WAVE_FMT_PCM)
|
||||
return 1;
|
||||
if (spec->channels <= 0 || spec->channels >= INT16_MAX)
|
||||
return 1;
|
||||
if (spec->format == WAVE_FMT_PCM && (spec->bytedepth <= 0 || spec->bytedepth > 4))
|
||||
return 1;
|
||||
|
||||
// write riff container
|
||||
writeRiffChunk(cb, user, FOURCC_RIFF, sizeof(uint32_t) * 5 + FORMAT_CHUNK_SIZE + (uint32_t)dataLen);
|
||||
writeFourcc(cb, user, FOURCC_WAVE);
|
||||
|
||||
writeFormatChunk(cb, user, &(const FormatChunk)
|
||||
{
|
||||
.format = spec->format,
|
||||
.channels = (uint16_t)spec->channels,
|
||||
.samplerate = spec->rate,
|
||||
.byterate = spec->rate * spec->channels * spec->bytedepth,
|
||||
.alignment = (uint16_t)(spec->channels * spec->bytedepth),
|
||||
.bitdepth = (uint16_t)spec->bytedepth * 8
|
||||
});
|
||||
|
||||
// write data chunk
|
||||
writeFourcc(cb, user, FOURCC_DATA);
|
||||
writeU32le(cb, user, (uint32_t)dataLen);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int waveWrite(const WaveSpec* spec, const void* data, size_t dataLen, const WaveStreamCb* cb, void* user)
|
||||
{
|
||||
if (!data)
|
||||
return 1;
|
||||
|
||||
// Write RIFF/Wave header and raw interleaved samples
|
||||
int res = waveWriteHeader(spec, dataLen, cb, user);
|
||||
if (res)
|
||||
return res;
|
||||
//FIXME: not endian safe
|
||||
cb->write(user, data, 1, dataLen);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int waveWriteBlock(const WaveSpec* spec, const void* blocks[], size_t blockLen, const WaveStreamCb* cb, void* user)
|
||||
{
|
||||
if (!blocks)
|
||||
return 1;
|
||||
|
||||
// Write RIFF/Wave header to file
|
||||
int res = waveWriteHeader(spec, blockLen * spec->channels, cb, user);
|
||||
if (res)
|
||||
return res;
|
||||
|
||||
// Copy & interleave
|
||||
//FIXME: not endian safe
|
||||
for (size_t i = 0; i < blockLen / spec->bytedepth; ++i)
|
||||
for (int j = 0; j < spec->channels; ++j)
|
||||
cb->write(user, &((const char**)blocks)[j][i * spec->bytedepth], spec->bytedepth, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
#ifndef WAVE_H
|
||||
#define WAVE_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
typedef enum
|
||||
{
|
||||
WAVE_FMT_PCM = 0x0001,
|
||||
WAVE_FMT_IEEE_FLOAT = 0x0003,
|
||||
WAVE_FMT_ALAW = 0x0006,
|
||||
WAVE_FMT_MULAW = 0x0007,
|
||||
WAVE_FMT_EXTENSIBLE = 0xFFFE
|
||||
} WaveFormat;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
WaveFormat format;
|
||||
int channels;
|
||||
unsigned rate;
|
||||
int bytedepth;
|
||||
} WaveSpec;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
size_t (*read)(void* restrict user, void* restrict out, size_t size, size_t num);
|
||||
size_t (*write)(void* restrict user, const void* restrict src, size_t size, size_t num);
|
||||
void (*seek)(void* restrict user, int offset);
|
||||
size_t (*tell)(void* user);
|
||||
int (*eof)(void* user);
|
||||
} WaveStreamCb;
|
||||
|
||||
int waveWrite(const WaveSpec* spec, const void* data, size_t dataLen, const WaveStreamCb* cb, void* user);
|
||||
int waveWriteFile(const WaveSpec* spec, const void* data, size_t dataLen, const char* path);
|
||||
int waveWriteBlock(const WaveSpec* spec, const void* blocks[], size_t blockLen, const WaveStreamCb* cb, void* user);
|
||||
int waveWriteBlockFile(const WaveSpec* spec, const void* blocks[], size_t blockLen, const char* path);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif//WAVE_H
|
||||
@@ -1,57 +0,0 @@
|
||||
/* wavefile.c (c) 2023 a dinosaur (zlib) */
|
||||
|
||||
#include "wave.h"
|
||||
#include <stdio.h>
|
||||
|
||||
static size_t waveFileRead(void* restrict user, void* restrict out, size_t size, size_t num)
|
||||
{
|
||||
return fread(out, size, num, (FILE*)user);
|
||||
}
|
||||
|
||||
static size_t waveFileWrite(void* restrict user, const void* restrict src, size_t size, size_t num)
|
||||
{
|
||||
return fwrite(src, size, num, (FILE*)user);
|
||||
}
|
||||
|
||||
static void waveFileSeek(void* restrict user, int offset)
|
||||
{
|
||||
#ifndef _MSC_VER
|
||||
fseek((FILE*)user, (off_t)offset, SEEK_CUR);
|
||||
#else
|
||||
fseek((FILE*)user, (long)offset, SEEK_CUR);
|
||||
#endif
|
||||
}
|
||||
|
||||
static size_t waveFileTell(void* user)
|
||||
{
|
||||
return ftell((FILE*)user);
|
||||
}
|
||||
|
||||
static int waveFileEof(void* user)
|
||||
{
|
||||
return feof((FILE*)user) || ferror((FILE*)user);
|
||||
}
|
||||
|
||||
int waveWriteFile(const WaveSpec* spec, const void* data, size_t dataLen, const char* path)
|
||||
{
|
||||
FILE* file = fopen(path, "wb");
|
||||
if (!file)
|
||||
return 1;
|
||||
|
||||
const WaveStreamCb cb = { .write = waveFileWrite };
|
||||
int res = waveWrite(spec, data, dataLen, &cb, (void*)file);
|
||||
fclose(file);
|
||||
return res;
|
||||
}
|
||||
|
||||
int waveWriteBlockFile(const WaveSpec* spec, const void* blocks[], size_t blockLen, const char* path)
|
||||
{
|
||||
FILE* file = fopen(path, "wb");
|
||||
if (!file)
|
||||
return 1;
|
||||
|
||||
const WaveStreamCb cb = { .write = waveFileWrite };
|
||||
int res = waveWriteBlock(spec, blocks, blockLen, &cb, (void*)file);
|
||||
fclose(file);
|
||||
return res;
|
||||
}
|
||||
Reference in New Issue
Block a user