#include "media_converter.h" #include #include #include #define STB_IMAGE_IMPLEMENTATION #define STBI_ONLY_PNG #define STBI_NO_LINEAR #include "stb_image.h" #define QOI_IMPLEMENTATION #undef QOI_NO_STDIO #include "qoi.h" #define DR_MP3_IMPLEMENTATION #include "dr_mp3.h" MediaConverter::MediaConverter() { } int MediaConverter::ImageToQoi(const std::string &inputFileName, const std::string &outputFileName) { void *pixels = NULL; int w = 0; int h = 0; int channels = 0; if(!stbi_info(inputFileName.c_str(), &w, &h, &channels)) { return cErrorBadInputFileFormat; } // Force all odd encodings to be RGBA if(channels != 3) { channels = 4; } pixels = (void *)stbi_load(inputFileName.c_str(), &w, &h, NULL, channels); if (pixels != NULL) { qoi_desc desc; desc.channels = channels; desc.colorspace = QOI_SRGB; desc.width = w; desc.height = h; int encoded = qoi_write(outputFileName.c_str(), pixels, &desc); free(pixels); if (!encoded) { return cErrorCannotWriteOrEncodeOutputFile; } } else { return cErrorCannotDecodeInputFile; } return cSuccess; } void fwrite_u32_le(unsigned int v, FILE *fh) { unsigned char buf[sizeof(unsigned int)]; buf[0] = 0xff & (v ); buf[1] = 0xff & (v >> 8); buf[2] = 0xff & (v >> 16); buf[3] = 0xff & (v >> 24); (void) fwrite(buf, sizeof(unsigned int), 1, fh); } void fwrite_u16_le(unsigned short v, FILE *fh) { unsigned char buf[sizeof(unsigned short)]; buf[0] = 0xff & (v ); buf[1] = 0xff & (v >> 8); (void) fwrite(buf, sizeof(unsigned short), 1, fh); } int MediaConverter::WavWrite(const std::string &path, short *sample_data, MediaInfo &desc) { unsigned int data_size = desc.samples * desc.channels * sizeof(short); unsigned int samplerate = desc.samplerate; short bits_per_sample = 16; short channels = desc.channels; /* Lifted from https://www.jonolick.com/code.html - public domain Made endian agnostic using qoaconv_fwrite() */ FILE *fh = fopen(path.c_str(), "wb"); if (fh != NULL) { fwrite("RIFF", 1, 4, fh); fwrite_u32_le(data_size + 44 - 8, fh); fwrite("WAVEfmt \x10\x00\x00\x00\x01\x00", 1, 14, fh); fwrite_u16_le(channels, fh); fwrite_u32_le(samplerate, fh); fwrite_u32_le(channels * samplerate * bits_per_sample/8, fh); fwrite_u16_le(channels * bits_per_sample/8, fh); fwrite_u16_le(bits_per_sample, fh); fwrite("data", 1, 4, fh); fwrite_u32_le(data_size, fh); fwrite((void*)sample_data, data_size, 1, fh); fclose(fh); return data_size + 44 - 8; } return cErrorCannotWriteOrEncodeOutputFile; } short *MediaConverter::Mp3Read(const std::string &path, MediaInfo &desc) { drmp3_uint64 samples = 0; drmp3_config mp3 = { .channels = 2, .sampleRate = 44100 }; short* sample_data = drmp3_open_file_and_read_pcm_frames_s16(path.c_str(), &mp3, &samples, NULL); desc.samplerate = mp3.sampleRate; desc.channels = mp3.channels; desc.samples = samples; return sample_data; } int MediaConverter::Mp3ToWav(const std::string &inputFileName, const std::string &outputFileName) { MediaInfo media; short *sample_data = NULL; sample_data = Mp3Read(inputFileName, media); if (sample_data != NULL) { int bytes_written = WavWrite(outputFileName, sample_data, media); free(sample_data); if (bytes_written < 0) { return bytes_written; // error } } else { return cErrorBadInputFileFormat; } return cSuccess; } /* OGG TO WAV #define STB_VORBIS_HEADER_ONLY #include "stb_vorbis.c" #include #include // Function to read the entire contents of a file into memory unsigned char* read_entire_file(const char* filename, int* length) { FILE* f = fopen(filename, "rb"); if (!f) return NULL; fseek(f, 0, SEEK_END); long size = ftell(f); fseek(f, 0, SEEK_SET); unsigned char* buffer = (unsigned char*)malloc(size); if (!buffer) { fclose(f); return NULL; } fread(buffer, 1, size, f); fclose(f); if (length) *length = (int)size; return buffer; } int main(int argc, char** argv) { if (argc != 3) { printf("Usage: %s input.ogg output.wav\n", argv[0]); return 1; } const char* input_filename = argv[1]; const char* output_filename = argv[2]; int ogg_length; unsigned char* ogg_data = read_entire_file(input_filename, &ogg_length); if (!ogg_data) { printf("Failed to read input file %s\n", input_filename); return 1; } int channels, sample_rate; short* samples = stb_vorbis_decode_memory(ogg_data, ogg_length, &channels, &sample_rate); if (!samples) { printf("Failed to decode OGG file %s\n", input_filename); free(ogg_data); return 1; } // Write WAV file header FILE* wav_file = fopen(output_filename, "wb"); if (!wav_file) { printf("Failed to create output file %s\n", output_filename); free(ogg_data); free(samples); return 1; } fwrite("RIFF", 1, 4, wav_file); int total_size = 36 + channels * (sample_rate * sizeof(short)); fwrite(&total_size, 4, 1, wav_file); fwrite("WAVEfmt ", 1, 8, wav_file); int format_size = 16; fwrite(&format_size, 4, 1, wav_file); short format_type = 1; // PCM fwrite(&format_type, 2, 1, wav_file); fwrite(&channels, 2, 1, wav_file); fwrite(&sample_rate, 4, 1, wav_file); int byte_rate = sample_rate * channels * sizeof(short); fwrite(&byte_rate, 4, 1, wav_file); short block_align = channels * sizeof(short); fwrite(&block_align, 2, 1, wav_file); short bits_per_sample = 16; fwrite(&bits_per_sample, 2, 1, wav_file); fwrite("data", 1, 4, wav_file); int data_size = channels * (sample_rate * sizeof(short)); fwrite(&data_size, 4, 1, wav_file); // Write sample data fwrite(samples, sizeof(short), sample_rate * channels, wav_file); fclose(wav_file); free(ogg_data); free(samples); printf("Conversion complete. WAV file saved as %s\n", output_filename); return 0; } */