Skip to content

Instantly share code, notes, and snippets.

@nickdowell
Last active June 3, 2024 10:26
Show Gist options
  • Save nickdowell/0383606ce76bc484c7037fc0c8ef2c64 to your computer and use it in GitHub Desktop.
Save nickdowell/0383606ce76bc484c7037fc0c8ef2c64 to your computer and use it in GitHub Desktop.
// 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