Last active
June 3, 2024 10:26
-
-
Save nickdowell/0383606ce76bc484c7037fc0c8ef2c64 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// fruitywav.cpp - extracts ogg files from FruityLoops .wav files | |
#include <cstdio> | |
#include <cstring> | |
#include <iostream> | |
#include <memory> | |
#include <stdint.h> | |
#include <sys/fcntl.h> | |
#include <sys/mman.h> | |
#include <sys/stat.h> | |
#include <unistd.h> | |
class FileMapping { | |
public: | |
FileMapping(const char *path) { | |
if ((fd = open(path, O_RDONLY)) != -1) | |
if (struct stat st; stat(path, &st) == 0) | |
if ((ptr = mmap(nullptr, (len = st.st_size), PROT_READ, | |
MAP_FILE | MAP_SHARED, fd, 0)) == MAP_FAILED) | |
ptr = nullptr; | |
} | |
~FileMapping() { close(); } | |
void close() { | |
if (ptr) | |
munmap(ptr, len); | |
if (fd != -1) | |
::close(fd); | |
fd = -1; | |
len = 0; | |
ptr = nullptr; | |
} | |
const void *data() { return ptr; } | |
size_t size() { return len; } | |
private: | |
size_t len; | |
int fd; | |
void *ptr{nullptr}; | |
}; | |
int16_t read_int16_le(const uint8_t *data) { | |
return (data[0] << 0) | (data[1] << 8); | |
} | |
int32_t read_int32_le(const uint8_t *data) { | |
return (data[0] << 0) | (data[1] << 8) | (data[2] << 16) | (data[3] << 24); | |
} | |
void process_file(const char *path) { | |
FileMapping mapping(path); | |
auto data = (const uint8_t *)mapping.data(); | |
if (!data) | |
return (void)fprintf(stderr, "Could not open file: %s\n", path); | |
if (memcmp(data, "RIFF", 4)) | |
return (void)fprintf(stderr, "Unsupported file type\n"); | |
bool isOgg = false; | |
auto fileSize = read_int32_le(data + 4); | |
auto end = data + fileSize - 8; | |
auto chunk = data + 12; | |
while (chunk < end) { | |
auto chunkSize = read_int32_le(chunk + 4); | |
if (!memcmp(chunk, "fmt ", 4)) { | |
int16_t format = read_int16_le(chunk + 8); | |
if (format == 0x674f || // WAVE_FORMAT_OGG_VORBIS_MODE_1 | |
format == 0x6750 || // WAVE_FORMAT_OGG_VORBIS_MODE_2 | |
format == 0x6751 || // WAVE_FORMAT_OGG_VORBIS_MODE_3 | |
format == 0x676f || // WAVE_FORMAT_OGG_VORBIS_MODE_1_PLUS | |
format == 0x6770 || // WAVE_FORMAT_OGG_VORBIS_MODE_2_PLUS | |
format == 0x6771) // WAVE_FORMAT_OGG_VORBIS_MODE_3_PLUS | |
isOgg = true; | |
} | |
if (isOgg && !memcmp(chunk, "data", 4)) { | |
char *outpath = strdup(path); | |
strcpy(outpath + strlen(path) - 4, ".ogg"); | |
printf("Extracting %s\n", outpath); | |
FILE *file = fopen(outpath, "wb"); | |
fwrite(chunk + 8, 1, chunkSize, file); | |
fclose(file); | |
free(outpath); | |
return; | |
} | |
chunk += 8 + ((chunkSize + 1) & ~1); | |
} | |
} | |
int main(int argc, char **argv) { | |
for (int i = 1; i < argc; i++) | |
process_file(argv[i]); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment