#include #include #include #include #include "wav_convert.h" typedef struct wav_data { uint8_t is_be; // Endianess uint16_t data_fmt; // Format Type uint16_t channel_count; // Ammount of Channels uint32_t sample_rate; // Samples per second uint16_t bits_per_sample; // Bits Per Sample uint32_t sample_count; // Samples In File } wav_data; int read_header(FILE* file, wav_data* header) { uint8_t arr[4]; uint8_t riff[4] = {'R', 'I', 'F', 'F'}; uint8_t rifx[4] = {'R', 'I', 'F', 'X'}; uint8_t wave[4] = {'W', 'A', 'V', 'E'}; uint8_t fmt[4] = {'f', 'm', 't', ' '}; uint8_t data[4] = {'d', 'a', 't', 'a'}; uint32_t u32; uint16_t u16; if ((NULL == file) || (NULL == header)) { return -1; } fseek(file, 0, SEEK_SET); fread(arr, sizeof(uint8_t), 4, file); // Detect RIFF/RIFX if (0 == strncmp(arr, riff, 4)) { header->is_be = 0; } else if (0 == strncmp(arr, rifx, 4)) { header->is_be = 1; } else { printf("RIFF/RIFX\n"); return -1; } // File Size Dummy Read fread(arr, sizeof(uint8_t), 4, file); // WAVE fread(arr, sizeof(uint8_t), 4, file); if (0 != strncmp(arr, wave, 4)) { printf("WAVE\n"); return -1; } // fmt fread(arr, sizeof(uint8_t), 4, file); if (0 != strncmp(arr, fmt, 4)) { printf("fmt\n"); return -1; } // Subchunk 1 Size fread(arr, sizeof(uint8_t), 4, file); wavtoh32(arr, &u32, header->is_be); if (16 != u32) { printf("fmt Size != 16\n"); } // Data Format fread(arr, sizeof(uint8_t), 2, file); wavtoh16(arr, &u16, header->is_be); header->data_fmt = u16; // Channel Count fread(arr, sizeof(uint8_t), 2, file); wavtoh16(arr, &u16, header->is_be); header->channel_count = u16; // Sample Rate fread(arr, sizeof(uint8_t), 4, file); wavtoh32(arr, &u32, header->is_be); header->sample_rate = u32; // Byte Rate Dummy Read fread(arr, sizeof(uint8_t), 4, file); // Block Align Dummy Read fread(arr, sizeof(uint8_t), 2, file); // Bits Per Sample fread(arr, sizeof(uint8_t), 2, file); wavtoh16(arr, &u16, header->is_be); header->bits_per_sample = u16; // data fread(arr, sizeof(uint8_t), 4, file); if (0 != strncmp(arr, data, 4)) { printf("data\n"); return -1; } // Sample Count Read fread(arr, sizeof(uint8_t), 4, file); wavtoh32(arr, &u32, header->is_be); header->sample_count = u32; u32 = header->channel_count; u32 *= header->bits_per_sample; u32 /= 8; header->sample_count /= u32; return 0; } void write_header(FILE* file, wav_data* header) { uint8_t arr[4]; uint32_t u32; uint16_t u16; if ((NULL == file) || (NULL == header)) { return; } // RIFF strncpy(arr, "RIFF", 4); fwrite(arr, sizeof(uint8_t), 4, file); // File Size u32 = header->sample_count; u32 *= header->channel_count; u32 *= header->bits_per_sample; u32 /= 8; u32 += 36; htowav32(&u32, arr, 0); fwrite(arr, sizeof(uint8_t), 4, file); // WAVE strncpy(arr, "WAVE", 4); fwrite(arr, sizeof(uint8_t), 4, file); // fmt strncpy(arr, "fmt ", 4); fwrite(arr, sizeof(uint8_t), 4, file); // fmt Size u32 = 16; htowav32(&u32, arr, 0); fwrite(arr, sizeof(uint8_t), 4, file); // Format Type u16 = header->data_fmt; htowav16(&u16, arr, 0); fwrite(arr, sizeof(uint8_t), 2, file); // Channel Count u16 = header->channel_count; htowav16(&u16, arr, 0); fwrite(arr, sizeof(uint8_t), 2, file); // Sample Rate u32 = header->sample_rate; htowav32(&u32, arr, 0); fwrite(arr, sizeof(uint8_t), 4, file); // Byte Rate u32 = header->sample_rate; u32 *= header->channel_count; u32 *= header->bits_per_sample; u32 /= 8; htowav32(&u32, arr, 0); fwrite(arr, sizeof(uint8_t), 4, file); // Block Align u16 = header->channel_count; u16 *= header->bits_per_sample; u16 /= 8; htowav16(&u16, arr, 0); fwrite(arr, sizeof(uint8_t), 2, file); // Bits Per Sample u16 = header->bits_per_sample; htowav16(&u16, arr, 0); fwrite(arr, sizeof(uint8_t), 2, file); // data strncpy(arr, "data", 4); fwrite(arr, sizeof(uint8_t), 4, file); // data Size u32 = header->sample_count; u32 *= header->channel_count; u32 *= header->bits_per_sample; u32 /= 8; htowav32(&u32, arr, 0); fwrite(arr, sizeof(uint8_t), 4, file); } void print_header(wav_data* header) { if (NULL == header) { return; } if (0 == header->is_be) { printf("LE\n"); } else { printf("BE\n"); } printf("Format: %u\n", header->data_fmt); printf("Channels: %u\n", header->channel_count); printf("Sample Rate: %lu\n", header->sample_rate); printf("Bits: %u\n", header->bits_per_sample); printf("Samples: %lu\n", header->sample_count); } void usage(const char* name) { printf("Usage:\n"); printf("\t%s [input] [output] \n", name); } void process_sample(FILE* in, FILE* out, wav_data* header, float volume) { union u32tof { uint32_t u32; float f; } un; uint8_t u8[4]; float src[8]; float dst[2]; for (int i = 0; i < 8; ++i) { src[i] = 0; } for (int i = 0; i < header->channel_count; ++i) { fread(u8, sizeof(uint8_t), 4, in); wavtoh32(u8, &un.u32, header->is_be); src[i] = un.f; } #ifdef LFE_ENABLE // With LFE dst[0] = src[0] + 0.7071 * src[2] + 0.7071 * src[3] + 0.7071 * src[4] + 0.7071 * src[6]; dst[1] = src[1] + 0.7071 * src[2] + 0.7071 * src[3] + 0.7071 * src[5] + 0.7071 * src[7]; #else // Without LFE dst[0] = src[0] + 0.7071 * src[2] + 0.7071 * src[4] + 0.7071 * src[6]; dst[1] = src[1] + 0.7071 * src[2] + 0.7071 * src[5] + 0.7071 * src[7]; #endif dst[0] *= volume; dst[1] *= volume; for (int i = 0; i < 2; ++i) { // CLIPPING if (dst[i] > 0.975) { dst[i] = 0.975; } if (dst[i] < -0.975) { dst[i] = -0.975; } un.f = dst[i]; htowav32(&un.u32, u8, 0); fwrite(u8, sizeof(uint8_t), 4, out); } } int main(int argc, char** argv) { FILE *in_file; FILE *out_file; wav_data in_header; wav_data out_header; float volume = 1.0f; if (argc < 3) { usage(argv[0]); return -1; } in_file = fopen(argv[1], "rb"); if (NULL == in_file) { printf("Input File\n"); return -1; } if (0 != read_header(in_file, &in_header)) { fclose(in_file); printf("Header\n"); return -1; } // 1 is PCM, 3 is float if ((in_header.data_fmt != 3) || (in_header.bits_per_sample != 32) || ((in_header.channel_count != 8) && (in_header.channel_count != 2))) { printf("Weird Header\n"); print_header(&in_header); fclose(in_file); return -1; } out_file = fopen(argv[2], "wb"); if (NULL == out_file) { fclose(in_file); printf("Output File\n"); return -1; } if (argc > 3) { volume = atof(argv[3]); if (0.0 == volume) { volume = 1.0; } } out_header = in_header; out_header.channel_count = 2; out_header.is_be = 0; write_header(out_file, &out_header); // Do processing for (uint32_t u32 = 0; u32 < in_header.sample_count; ++u32) { process_sample(in_file, out_file, &in_header, volume); } fclose(in_file); fclose(out_file); return 0; }