From 9f5ad14d7e337efc2d3d001bd8dea0da325cd097 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Fri, 3 Apr 2020 04:07:30 +0200 Subject: [PATCH] Support the WT file format --- src/WaveEdit.hpp | 14 +++++ src/bank.cpp | 138 +++++++++++++++++++++++++++++++++++++++++++++++ src/ui.cpp | 6 +-- src/util.cpp | 42 +++++++++++++++ 4 files changed, 197 insertions(+), 3 deletions(-) diff --git a/src/WaveEdit.hpp b/src/WaveEdit.hpp index ba8a469..ff6075f 100644 --- a/src/WaveEdit.hpp +++ b/src/WaveEdit.hpp @@ -112,6 +112,14 @@ float *loadAudio(const char *filename, int *length); std::string stringf(const char *format, ...); /** Truncates a string if needed, inserting ellipses (...), to be no greater than `maxLen` characters */ void ellipsize(char *str, int maxLen); +/** Writes a 32-bit integer in little endian order */ +size_t fwriteLE32(uint32_t x, FILE *f); +/** Writes a 16-bit integer in little endian order */ +size_t fwriteLE16(uint16_t x, FILE *f); +/** Reads a 32-bit integer in little endian order */ +size_t freadLE32(uint32_t *x, FILE *f); +/** Reads a 16-bit integer in little endian order */ +size_t freadLE16(uint16_t *x, FILE *f); unsigned char *base64_encode(const unsigned char *src, size_t len, size_t *out_len); unsigned char *base64_decode(const unsigned char *src, size_t len, size_t *out_len); @@ -198,6 +206,12 @@ struct Bank { /** WAV file with BANK_LEN * WAVE_LEN samples */ void saveWAV(const char *filename); void loadWAV(const char *filename); + /** WT file with BANK_LEN banks of WAVE_LEN samples each */ + void saveWT(const char *filename); + void loadWT(const char *filename); + /** Automatic format determined according to file name */ + void saveAuto(const char *filename); + void loadAuto(const char *filename); /** Saves each wave to its own file in a directory */ void saveWaves(const char *dirname); }; diff --git a/src/bank.cpp b/src/bank.cpp index d634b2d..7b6520c 100644 --- a/src/bank.cpp +++ b/src/bank.cpp @@ -2,6 +2,9 @@ #include #include +#if defined(_WIN32) +#define strcasecmp _stricmp +#endif void Bank::clear() { // The lazy way @@ -118,3 +121,138 @@ void Bank::saveWaves(const char *dirname) { waves[b].saveWAV(filename); } } + + +void Bank::saveWT(const char *filename) +{ + FILE *f = fopen(filename, "wb"); + if (!f) + return; + + fputs("vawt", f); + fwriteLE32(WAVE_LEN, f); + fwriteLE16(BANK_LEN, f); + fwriteLE16(0, f); + + for (int i = 0; i < BANK_LEN; i++) { + for (int j = 0; j < WAVE_LEN; j++) { + union { uint32_t i; float f; } u; + u.f = waves[i].postSamples[j]; + fwriteLE32(u.i, f); + } + } + + fclose(f); +} + + +void Bank::loadWT(const char *filename) +{ + FILE *f = fopen(filename, "rb"); + if (!f) + return; + + char magic[4]; + memset(magic, 0, 4); + fread(magic, 4, 1, f); + + if (memcmp(magic, "vawt", 4) != 0) { + fclose(f); + return; + } + + uint32_t waveLen = 0; + uint16_t fileBankLen = 0; + uint16_t flags = 0; + + freadLE32(&waveLen, f); + freadLE16(&fileBankLen, f); + freadLE16(&flags, f); + + if (waveLen > 1024) { + fclose(f); + return; + } + + uint32_t bankLen = fileBankLen; + if (bankLen > BANK_LEN) + bankLen = BANK_LEN; + + clear(); + + std::vector rawSamples(waveLen * bankLen); + + if (flags & 4) { + for (uint32_t i = 0; i < waveLen * bankLen; ++i) { + int16_t sample = 0; + freadLE16((uint16_t *)&sample, f); + rawSamples[i] = sample / 32768.0f; + } + } + else { + for (uint32_t i = 0; i < waveLen * bankLen; ++i) { + union { uint32_t i; float f; } u; + u.i = 0; + freadLE32(&u.i, f); + rawSamples[i] = u.f; + } + } + + for (uint32_t i = 0; i < bankLen; i++) { + const float *src = &rawSamples[waveLen * i]; + float *dst = waves[i].samples; + if (waveLen == WAVE_LEN) + memcpy(dst, src, WAVE_LEN * sizeof(float)); + else + resample(src, waveLen, dst, WAVE_LEN, (double)WAVE_LEN/waveLen); + waves[i].commitSamples(); + } + + fclose(f); +} + + +enum BankFileFormat { + BANK_FORMAT_WAV, + BANK_FORMAT_WT, +}; + + +static int getFormatByFilename(const char *filename) +{ + size_t len = strlen(filename); + if (len > 4 && strcasecmp(filename + len - 4, ".wav") == 0) + return BANK_FORMAT_WAV; + else if (len > 3 && strcasecmp(filename + len - 3, ".wt") == 0) + return BANK_FORMAT_WT; + else + return -1; +} + + +void Bank::saveAuto(const char *filename) +{ + switch (getFormatByFilename(filename)) { + default: + case BANK_FORMAT_WAV: + saveWAV(filename); + break; + case BANK_FORMAT_WT: + saveWT(filename); + break; + } +} + + +void Bank::loadAuto(const char *filename) +{ + switch (getFormatByFilename(filename)) { + default: + case BANK_FORMAT_WAV: + loadWAV(filename); + break; + case BANK_FORMAT_WT: + loadWT(filename); + break; + } +} diff --git a/src/ui.cpp b/src/ui.cpp index 21b3f11..1ae93bd 100644 --- a/src/ui.cpp +++ b/src/ui.cpp @@ -158,7 +158,7 @@ static void menuOpenBank() { char *path = osdialog_file(OSDIALOG_OPEN, dir, NULL, NULL); if (path) { showCurrentBankPage(); - currentBank.loadWAV(path); + currentBank.loadAuto(path); snprintf(lastFilename, sizeof(lastFilename), "%s", path); historyPush(); free(path); @@ -170,7 +170,7 @@ static void menuSaveBankAs() { char *dir = getLastDir(); char *path = osdialog_file(OSDIALOG_SAVE, dir, "Untitled.wav", NULL); if (path) { - currentBank.saveWAV(path); + currentBank.saveAuto(path); snprintf(lastFilename, sizeof(lastFilename), "%s", path); free(path); } @@ -179,7 +179,7 @@ static void menuSaveBankAs() { static void menuSaveBank() { if (lastFilename[0] != '\0') - currentBank.saveWAV(lastFilename); + currentBank.saveAuto(lastFilename); else menuSaveBankAs(); } diff --git a/src/util.cpp b/src/util.cpp index 7c91bb0..03d5df6 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -2,6 +2,8 @@ #include #include #include +#include +#include #if defined(_WIN32) #include @@ -90,6 +92,46 @@ void ellipsize(char *str, int maxLen) { } +size_t fwriteLE32(uint32_t x, FILE *f) +{ + uint8_t b[4]; + b[0] = x & 0xff; + b[1] = (x >> 8) & 0xff; + b[2] = (x >> 16) & 0xff; + b[3] = x >> 24; + return fwrite(b, 4, 1, f); +} + + +size_t fwriteLE16(uint16_t x, FILE *f) +{ + uint8_t b[2]; + b[0] = x & 0xff; + b[1] = x >> 8; + return fwrite(b, 2, 1, f); +} + + +size_t freadLE32(uint32_t *x, FILE *f) +{ + uint8_t b[4]; + if (fread(b, 4, 1, f) != 1) + return 0; + *x = b[0] | (b[1] << 8) | (b[2] << 16) | (b[3] << 24); + return 1; +} + + +size_t freadLE16(uint16_t *x, FILE *f) +{ + uint8_t b[2]; + if (fread(b, 2, 1, f) != 1) + return 0; + *x = b[0] | (b[1] << 8); + return 1; +} + + /* This base64 implementation: