apex-mix/main.c
2022-07-07 19:51:37 +03:00

364 lines
7.1 KiB
C

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#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] <volume>\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;
}