Skip to content

Instantly share code, notes, and snippets.

@jacobjoaquin
Created December 13, 2010 16:02
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jacobjoaquin/739142 to your computer and use it in GitHub Desktop.
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.
/* 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