Created
December 13, 2010 16:02
-
-
Save jacobjoaquin/739142 to your computer and use it in GitHub Desktop.
Converts a sample segment, defined by a zero crossing, into a half-sin window.
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
/* zero_shape.c | |
* Jacob Joaquin <jacobjoaquin@gmail.com> | |
* csoundblog.com | |
* | |
* Converts a segment, defined by a zero crossing, into a half-sin window. | |
* Written as an exercise to understand various audio programming conecpts | |
* from The Audio Audio Programming Book, edited by Richard Bouland and | |
* Victor Lazzarini. | |
* | |
* Note. Not useful as a DSP processor. | |
* | |
* Usage: zero_shape input_file output_file | |
* | |
* License: | |
* GNU Lesser General Public License | |
* http://www.gnu.org/copyleft/lesser.html | |
* | |
* Requires libsndfile by Erik de Castro Lopo | |
* http://www.mega-nerd.com/libsndfile/ | |
* | |
* Visit The Audio Programming Book group @ Noisepages | |
* http://noisepages.com/groups/the-audio-programming-book/ | |
*/ | |
#include <math.h> | |
#include <sndfile.h> | |
#include <stdlib.h> | |
const float pi = 3.1415926535897931; | |
enum | |
{ | |
ARG_PROGRAM, | |
ARG_INFILE, | |
ARG_OUTFILE | |
}; | |
int main(int argc, char** argv) | |
{ | |
SNDFILE* in_file; /* Input file */ | |
SNDFILE* out_file; /* Output file */ | |
SF_INFO* in_info; /* Input file info */ | |
SF_INFO* out_info; /* Output file info */ | |
float* frame_buffer; /* Audio buffer */ | |
float* frame_ptr; /* Point to audio */ | |
unsigned int mask; /* Bit mask */ | |
sf_count_t sf_count; /* Frame counter */ | |
unsigned int nsamps; /* Number of frames in | |
sound file */ | |
const int table_size = 1 << 16; /* Size of table */ | |
float table_size_m1_inv = 1.0 / (table_size - 1); /* One over Table size | |
minus one */ | |
float* table; /* Stores precalculated | |
window */ | |
float* table_ptr = table; /* Point to table */ | |
unsigned int i; /* Iterator */ | |
/* Check args */ | |
if (argc != 3) | |
{ | |
printf("usage:\n\tzero_shape input_file output_file\n"); | |
return 1; | |
} | |
/* Open sound file for reading */ | |
in_info = (SF_INFO *) malloc(sizeof(SF_INFO)); | |
in_file = sf_open(argv[ARG_INFILE], SFM_READ, in_info); | |
if(!in_file) | |
{ | |
printf("Could not open in file.\n"); | |
exit(-1); | |
} | |
/* Validate file is AIFF or WAV */ | |
mask = in_info->format & SF_FORMAT_TYPEMASK; | |
if (!((mask & SF_FORMAT_AIFF) == SF_FORMAT_AIFF || | |
(mask & SF_FORMAT_WAV) == SF_FORMAT_WAV)) | |
{ | |
printf("Input file must be of type aiff or wav.\n"); | |
exit(-1); | |
} | |
/* Valide file is 16 or 24 bit */ | |
mask = in_info->format & SF_FORMAT_SUBMASK; | |
if (!((mask & SF_FORMAT_PCM_16) == SF_FORMAT_PCM_16 || | |
(mask & SF_FORMAT_PCM_24) == SF_FORMAT_PCM_24)) | |
{ | |
printf("Only 16 and 24 bit files supported.\n"); | |
exit(-1); | |
} | |
/* Validate mono */ | |
if (in_info->channels != 1) | |
{ | |
printf("Only mono files supported.\n"); | |
exit(-1); | |
} | |
/* File into */ | |
printf("Input file\n" | |
"----------\n"); | |
printf("sample rate = %d\n", in_info->samplerate); | |
printf("channels = %d\n", in_info->channels); | |
printf("frames = %d\n", (int) in_info->frames); | |
printf("format = %d\n", (int) in_info->format); | |
/* Read sound file into buffer */ | |
frame_buffer = (float *) malloc(sizeof(float) * in_info->frames); | |
sf_count = sf_readf_float(in_file, frame_buffer, in_info->frames); | |
if (sf_count != in_info->frames) | |
{ | |
printf("Samples read does not match in file frames\n"); | |
exit(-1); | |
} | |
/* Generate half-sine window */ | |
table = (float *) malloc(sizeof(float) * table_size); | |
table_ptr = table; | |
for (i = 0; i < table_size; i++) | |
{ | |
*table_ptr++ = sin(i / (float) table_size * pi); | |
} | |
/* Process */ | |
nsamps = in_info->frames; | |
frame_ptr = frame_buffer; | |
do | |
{ | |
float max = 0.0; /* Max value */ | |
unsigned int are_equal; /* Polarity is same */ | |
unsigned int count = 1; /* Get size of segment */ | |
unsigned int polarity = *frame_ptr++ > 0.0; /* Polarity */ | |
unsigned int table_inc; /* Increment of table */ | |
unsigned int table_phase = 0; /* Phase of table */ | |
unsigned int tsamps = nsamps - 1; /* Frames left */ | |
/* Look ahead until next zero-crossing */ | |
do | |
{ | |
float sample = *frame_ptr++; | |
count++; | |
are_equal = (polarity == (sample > 0.0)); | |
if (are_equal) { | |
float sample_abs = fabs(sample); | |
max = sample_abs < max ? max : sample_abs; | |
} | |
} while (are_equal && --tsamps); /* Forward seek until zero-crossing | |
or end of buffer */ | |
frame_ptr -= count; /* Rewind */ | |
nsamps -= count; /* Update frames left */ | |
max = polarity ? max : max * -1.0; /* Absolute max to signed max */ | |
/* Table phase increment value */ | |
table_inc = (unsigned int) ((1.0 / (float) count) * (float) table_size); | |
/* Replace with window curve */ | |
do | |
{ | |
*frame_ptr++ = table[table_phase] * max; | |
table_phase += table_inc; | |
} while (--count); | |
} while (nsamps); | |
/* Clone properties of input file for output file */ | |
out_info = (SF_INFO *) malloc(sizeof(SF_INFO)); | |
out_info->samplerate = in_info->samplerate; | |
out_info->channels = in_info->channels; | |
out_info->format = in_info->format; | |
/* Create or overwrite input file */ | |
out_file = sf_open(argv[ARG_OUTFILE], SFM_WRITE, out_info); | |
if(!out_file) | |
{ | |
printf("Could not open out file.\n"); | |
exit(-1); | |
} | |
/* Write samples to output file */ | |
sf_count = sf_writef_float(out_file, frame_buffer, in_info->frames); | |
if (sf_count != in_info->frames) | |
{ | |
printf("Samples write does not match in file frames\n"); | |
exit(-1); | |
} | |
/* Clean up and return */ | |
free(in_info); | |
free(out_info); | |
free(frame_buffer); | |
free(table); | |
sf_close(in_file); | |
sf_close(out_file); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment