Last active
December 17, 2019 21:14
-
-
Save cosmikwolf/8baf36993642ec1e641d183a9c502134 to your computer and use it in GitHub Desktop.
a small c program to perform downsampling on raw audio data
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <stdlib.h> | |
// Tenkai Kariya tenkai@zetaohm.com www.zetaohm.com 12/17/19 | |
// Usage: ./downsample_by2 inputfile.raw outputfile.raw | |
// downsample will take a raw input audio file and output | |
// an audio file that has been downsampled to half the | |
// sample rate. I.E. if you send audio with a 44100 sample rate, it will be | |
// reduced to 22050 | |
// with SOX installed on OS X, you can play the raw file with the following command | |
// specifying the correct sample rate and bit depth | |
// play -r 22500 -e floating-point -b 32 output.raw | |
// to create a raw audio file from a wav, you can use sox as well: | |
// sox hexsoc.wav --bits 32 --encoding floating-point tesst.raw | |
// code was compiled with the following command on os x 10.15.1 with xcode installed: | |
// gcc downsample_by2.c -o downsample_by2 | |
const float kaiser_smoothing_filter[] = {-0.01452123, -0.0155227, 0.01667252, 0.01800633, -0.01957209, -0.0214361, 0.02369253, 0.02647989, -0.03001054, -0.03462755, 0.04092347, 0.05001757, -0.06430831, -0.09003163, 0.15005272, 0.45015816, 0.45015816, 0.15005272, -0.09003163, -0.06430831, 0.05001757, 0.04092347, -0.03462755, -0.03001054, 0.02647989, 0.02369253, -0.0214361, -0.01957209, 0.01800633, 0.01667252, -0.0155227, -0.01452123}; | |
const int kaiser_smoothing_size = 32; | |
void decimate_by_2(float *audio_input, | |
size_t input_length, | |
float *audio_output); | |
void downsample_by_2(float *audio_input, | |
size_t input_length, | |
float *audio_output, | |
const float *iir_filter, | |
const int iir_size); | |
void convolve(const float Signal[/* SignalLen */], size_t SignalLen, | |
const float Kernel[/* KernelLen */], size_t KernelLen, | |
float Result[/* SignalLen + KernelLen - 1 */]); | |
int main(int argc, char *argv[]) | |
{ | |
if (argc == 3) | |
{ | |
printf("input file: %s\t output file: %s\n", argv[1], argv[2]); | |
} | |
else if (argc > 3) | |
{ | |
printf("Too many arguments supplied.\n"); | |
exit(1); | |
} | |
else | |
{ | |
printf("One argument expected.\n"); | |
exit(1); | |
} | |
printf("sizeof double: %lu\n", sizeof(double)); | |
printf("sizeof float: %lu\n", sizeof(float)); | |
FILE *in_file; | |
FILE *out_file; | |
in_file = fopen(argv[1], "r"); | |
if (in_file == NULL) | |
{ | |
printf("error opening %s", argv[1]); | |
exit(1); | |
} | |
fseek(in_file, 0L, SEEK_END); | |
int size_in_bytes = ftell(in_file); | |
rewind(in_file); | |
printf("file size is: %d \n", size_in_bytes); | |
int sample_count = size_in_bytes * 8 / 32; | |
float *input_buffer = malloc(sizeof(float) * sample_count); // convert bytes to 32 bit samples | |
float *output_buffer = malloc(sizeof(float) * sample_count + 32 - 1); // account for the convolution in the final output size | |
fread(input_buffer, 4 /*4 bytes per 32bit sample*/, sample_count, in_file); | |
fclose(in_file); | |
downsample_by_2(input_buffer, size_in_bytes, | |
output_buffer, | |
kaiser_smoothing_filter, | |
kaiser_smoothing_size); | |
// decimate_by_2(input_buffer, sample_count, output_buffer); | |
for (int i = 0; i < 10; i++) | |
{ | |
printf("%d:\t\t%20.18f\t\t%20.18f\n", i, input_buffer[i], output_buffer[i]); | |
} | |
out_file = fopen(argv[2], "wb"); | |
fwrite(output_buffer, sizeof(float), sample_count / 2 + 31 * sizeof(float), out_file); | |
fclose(out_file); | |
free(input_buffer); | |
free(output_buffer); | |
} | |
// 2:1 sample rate reduction | |
// passed output array should have half | |
// the size of the input array. | |
void decimate_by_2(float *audio_input, | |
size_t input_length, | |
float *audio_output) | |
{ | |
for (int i = 0; i < input_length / 2; i++) | |
{ | |
audio_output[i] = audio_input[i * 2]; | |
} | |
} | |
void downsample_by_2(float *audio_input, | |
size_t input_length, | |
float *audio_output, | |
const float *iir_filter, | |
const int iir_size) | |
{ | |
float *buffer = malloc(sizeof(float) * input_length); | |
printf("convolving....\n"); | |
convolve(audio_input, input_length, | |
iir_filter, iir_size, buffer); | |
printf("decimating....\n"); | |
input_length = input_length + 32 - 1; //account for convolution length | |
decimate_by_2(buffer, input_length, audio_output); | |
free(buffer); | |
printf("downsample complete....\n"); | |
} | |
// convolve function from: | |
// https://stackoverflow.com/questions/8424170/1d-linear-convolution-in-ansi-c-code | |
void convolve(const float Signal[/* SignalLen */], size_t SignalLen, | |
const float Kernel[/* KernelLen */], size_t KernelLen, | |
float Result[/* SignalLen + KernelLen - 1 */]) | |
{ | |
size_t n; | |
for (n = 0; n < SignalLen + KernelLen - 1; n++) | |
{ | |
size_t kmin, kmax, k; | |
Result[n] = 0; | |
kmin = (n >= KernelLen - 1) ? n - (KernelLen - 1) : 0; | |
kmax = (n < SignalLen - 1) ? n : SignalLen - 1; | |
for (k = kmin; k <= kmax; k++) | |
{ | |
Result[n] += Signal[k] * Kernel[n - k]; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment