/* * makeaiff.c * compute a sound * write the int output to an aiff file * * Created by Christopher Dobrian on Tue Jan 19 2004. * */ #include #include #include #include #define SAMPLE_RATE (44100.0) #define NCHANS 2 #define BYTES_PER_SAMPLE 2 #define BUFSIZE 256 #define OUTPUT_FILENAME "toneoutput.aif" #define MAXAMP 32000 #define FREQUENCY (440.) #define DURATION (1.0) #define TWOPI (6.283185307179586) typedef int errormsg; errormsg openfilew( FILE *fp ); errormsg aiffheader( FILE *fp, unsigned long nsamples ); errormsg writestereodata( FILE *fp, unsigned long nsamples ); errormsg openfilew( FILE *fp ){ errormsg err; fp = fopen( OUTPUT_FILENAME, "w" ); if (fp == NULL) { fprintf( stderr, "Can't open file.\n" ); err = -1; } else { err = 0; } return err; } errormsg aiffheader( FILE *fp, unsigned long nsamples ){ /* * This code for writing header information for an aiff * is adapted from example source code provided in the web article * "Audio Interchange File Format: Creating aiff Audio Formatted files" * written by Paul Bourke, 1996, available on the web at * http://astronomy.swin.edu.au/~pbourke/dataformats/aiff/ */ errormsg err = 0; unsigned long ndatabytes, totalsize; ndatabytes = NCHANS * BYTES_PER_SAMPLE * nsamples; /* Write the Form chunk */ fprintf( fp, "FORM" ); totalsize = 4 + 8 + 18 + 8 + 8 + ndatabytes; // "aiff", Common Chunk, Data Chunk Header, Block and Offset, Data putc( (totalsize & 0xFF000000) >> 24, fp ); putc( (totalsize & 0x00FF0000) >> 16, fp ); putc( (totalsize & 0x0000FF00) >> 8, fp ); putc( (totalsize & 0x000000FF), fp ); fprintf( fp, "AIFF" ); /* Write the Common chunk */ fprintf( fp, "COMM" ); putc( 0, fp ); // 4 bytes telling the size of this common chunk (always 18) putc( 0, fp ); putc( 0, fp ); putc( 18, fp ); putc( 0, fp ); // 2 bytes telling the number of audio channels putc( NCHANS, fp ); putc( (nsamples & 0xFF000000) >> 24, fp ); // 4 bytes telling how many samples putc( (nsamples & 0x00FF0000) >> 16, fp ); putc( (nsamples & 0x0000FF00) >> 8, fp ); putc( (nsamples & 0x000000FF), fp ); putc( 0, fp ); // 2 bytes telling how many bits per sample putc( 16, fp ); putc( 0x40, fp ); // 10-byte SANE "extended" number telling the sampling rate (44100) putc( 0x0E, fp ); putc( 0xAC, fp ); putc( 0x44, fp ); putc( 0, fp ); putc( 0, fp ); putc( 0, fp ); putc( 0, fp ); putc( 0, fp ); putc( 0, fp ); /* Write the sound data chunk header */ fprintf( fp , "SSND" ); putc( (ndatabytes+8 & 0xff000000) >> 24, fp ); // 4 bytes telling data size (plus block and offset) putc( (ndatabytes+8 & 0x00ff0000) >> 16, fp ); putc( (ndatabytes+8 & 0x0000ff00) >> 8, fp ); putc( (ndatabytes+8 & 0x000000ff), fp ); putc( 0, fp ); // 4 bytes telling offset putc( 0, fp ); putc( 0, fp ); putc( 0, fp ); putc( 0, fp ); // 4 bytes telling block putc( 0, fp ); putc( 0, fp ); putc( 0, fp ); return err; } errormsg writestereodata( FILE *fp, unsigned long nsamples ){ errormsg err = 0; float amplitude = MAXAMP; float frequency = FREQUENCY; float phase = 0.; unsigned long n; // the current sample number float twopiFoverR = TWOPI*frequency/SAMPLE_RATE; short int y; // current sample value for( n = 0 ; n < nsamples ; n++ ) { y = (short int)amplitude*sin(twopiFoverR*n+phase); putc( ((y >> 8) & 0xFF), fp ); // left channel sample putc( (y & 0xFF), fp ); putc( ((y >> 8) & 0xFF), fp ); // right channel sample putc( (y & 0xFF), fp ); } return err; } int main(void) { FILE *fp; errormsg err; unsigned long nsamples; nsamples = (unsigned long)DURATION*SAMPLE_RATE; fp = fopen( OUTPUT_FILENAME, "w" ); if (fp == NULL) { fprintf( stderr, "Can't open file.\n" ); err = -1; } else { err = 0; } if (err) goto error; err = aiffheader( fp, nsamples ); if (err) goto error; err = writestereodata( fp, nsamples ); if (err) goto error; fclose( fp ); return 0; error: fprintf( stderr, "Error printing to file. Exiting.\n" ); return -1; }