public
Last active

Converts a sample segment, defined by a zero crossing, into a half-sin window.

  • Download Gist
Zero-shape
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208
/* 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;
}

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.