Initial commit - V1.0
This commit is contained in:
commit
e6e9744529
9
Makefile
Normal file
9
Makefile
Normal file
@ -0,0 +1,9 @@
|
||||
all:
|
||||
make apex_mix
|
||||
make apex_mix_lfe
|
||||
|
||||
apex_mix:
|
||||
gcc -o apex_mix main.c wav_convert.c
|
||||
|
||||
apex_mix_lfe:
|
||||
gcc -o apex_mix_lfe -DLFE_ENABLE main.c wav_convert.c
|
||||
363
main.c
Normal file
363
main.c
Normal file
@ -0,0 +1,363 @@
|
||||
#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;
|
||||
}
|
||||
118
wav_convert.c
Normal file
118
wav_convert.c
Normal file
@ -0,0 +1,118 @@
|
||||
#include "wav_convert.h"
|
||||
|
||||
typedef union wav_u
|
||||
{
|
||||
uint8_t u8[4];
|
||||
uint16_t u16[2];
|
||||
uint32_t u32;
|
||||
} wav_u;
|
||||
|
||||
uint32_t endian_swap32(uint32_t in)
|
||||
{
|
||||
wav_u un;
|
||||
uint8_t u8[4];
|
||||
|
||||
un.u32 = in;
|
||||
for (int i = 0; i < 4; ++i)
|
||||
{
|
||||
u8[i] = un.u8[3 - i];
|
||||
}
|
||||
|
||||
for (int i = 0; i < 4; ++i)
|
||||
{
|
||||
un.u8[i] = u8[i];
|
||||
}
|
||||
|
||||
return un.u32;
|
||||
}
|
||||
|
||||
uint16_t endian_swap16(uint16_t in)
|
||||
{
|
||||
wav_u un;
|
||||
uint8_t u8[2];
|
||||
|
||||
un.u16[0] = in;
|
||||
for (int i = 0; i < 2; ++i)
|
||||
{
|
||||
u8[i] = un.u8[1 - i];
|
||||
}
|
||||
|
||||
for (int i = 0; i < 2; ++i)
|
||||
{
|
||||
un.u8[i] = u8[i];
|
||||
}
|
||||
|
||||
return un.u16[0];
|
||||
}
|
||||
|
||||
void wavtoh32(uint8_t* in, uint32_t* out, uint8_t is_be)
|
||||
{
|
||||
wav_u un;
|
||||
for (int i = 0; i < 4; ++i)
|
||||
{
|
||||
un.u8[i] = in[i];
|
||||
}
|
||||
|
||||
if (0 == is_be)
|
||||
{
|
||||
*out = un.u32;
|
||||
}
|
||||
else
|
||||
{
|
||||
*out = endian_swap32(un.u32);
|
||||
}
|
||||
}
|
||||
|
||||
void wavtoh16(uint8_t* in, uint16_t* out, uint8_t is_be)
|
||||
{
|
||||
wav_u un;
|
||||
for (int i = 0; i < 2; ++i)
|
||||
{
|
||||
un.u8[i] = in[i];
|
||||
}
|
||||
|
||||
if (0 == is_be)
|
||||
{
|
||||
*out = un.u16[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
*out = endian_swap16(un.u16[0]);
|
||||
}
|
||||
}
|
||||
|
||||
void htowav32(uint32_t* in, uint8_t* out, uint8_t is_be)
|
||||
{
|
||||
wav_u un;
|
||||
if (0 == is_be)
|
||||
{
|
||||
un.u32 = *in;
|
||||
}
|
||||
else
|
||||
{
|
||||
un.u32 = endian_swap32(*in);
|
||||
}
|
||||
|
||||
for (int i = 0; i < 4; ++i)
|
||||
{
|
||||
out[i] = un.u8[i];
|
||||
}
|
||||
}
|
||||
|
||||
void htowav16(uint16_t* in, uint8_t* out, uint8_t is_be)
|
||||
{
|
||||
wav_u un;
|
||||
if (0 == is_be)
|
||||
{
|
||||
un.u16[0] = *in;
|
||||
}
|
||||
else
|
||||
{
|
||||
un.u16[0] = endian_swap16(*in);
|
||||
}
|
||||
|
||||
for (int i = 0; i < 2; ++i)
|
||||
{
|
||||
out[i] = un.u8[i];
|
||||
}
|
||||
}
|
||||
12
wav_convert.h
Normal file
12
wav_convert.h
Normal file
@ -0,0 +1,12 @@
|
||||
#ifndef WAV_CONVERT_H_
|
||||
#define WAV_CONVERT_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
void wavtoh32(uint8_t* in, uint32_t* out, uint8_t is_be);
|
||||
void wavtoh16(uint8_t* in, uint16_t* out, uint8_t is_be);
|
||||
|
||||
void htowav32(uint32_t* in, uint8_t* out, uint8_t is_be);
|
||||
void htowav16(uint16_t* in, uint8_t* out, uint8_t is_be);
|
||||
|
||||
#endif // WAV_CONVERT_H_
|
||||
Loading…
Reference in New Issue
Block a user