/* * Wavetable1.c * Wavetable1 * * Fill a table with values describing a waveform * Then synthesize a tone by reading cyclically through that table * Use simple truncation of calculated sample index * to find the sample value (not as accurate as interpolation) * * Created by Christopher Dobrian on Tue Jan 20 2004. * */ #include #include #include "portaudio.h" #define SAMPLE_RATE (44100.) #define TABLE_LENGTH 1024 #define BUFFER_SIZE 256 #define TWOPI (6.283185307179586) #define NUM_SECONDS (4.) #define FREQUENCY (440.) #define MAX_AMP (0.5) typedef struct { float frequency; float amplitude; float phase; float *wavetable; float n; } wave; // data to pass to callback function const float oneoversr = 1./SAMPLE_RATE; // fill a table with one cycle of a sine waveform void filltable( float *table, unsigned long length); // This routine will be called by the PortAudio engine when audio is needed. static int sineCallback( void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, PaTimestamp outTime, void *userData ); int main(void); void filltable( float *table, unsigned long length) { unsigned long i; const float twopioverlength = 8.*atan(1.)/length; // or TWOPI/length for ( i = 0; i < length; i++) *(table++) = sin(i*twopioverlength); return; } static int sineCallback( void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, PaTimestamp outTime, void *userData ) { /* Cast data passed through stream to the format of the local structure. */ wave *data = (wave*)userData; // float *in = (float*)inputBuffer; // input buffer only needed for input float *out = (float*)outputBuffer; unsigned int i; // a counter float y; // temp variable for output sample for( i = 0 ; i < framesPerBuffer ; i++ ) { y = data->amplitude*(data->wavetable[(int)data->n]); data->n += data->frequency*TABLE_LENGTH*oneoversr; // increment the wave's counter while ( data->n > TABLE_LENGTH) data->n -= TABLE_LENGTH; // keep it in range *out++ = y; /* left channel */ *out++ = y; /* right channel*/ } return 0; } int main(void) { PortAudioStream *stream; PaError err; wave wave1; // my data structure float table1[TABLE_LENGTH]; // wavetable filltable( table1, TABLE_LENGTH); printf("PortAudio: Sine Wave, %.2f Hz.\n", FREQUENCY); // Initialize data for use by callback. wave1.frequency = FREQUENCY; wave1.amplitude = MAX_AMP; wave1.phase = 0.; wave1.wavetable = table1; wave1.n = 0. + wave1.phase*TABLE_LENGTH; // Initialize library before making any other calls. err = Pa_Initialize(); if( err != paNoError ) goto error; // Open an audio I/O stream. err = Pa_OpenDefaultStream( &stream, 0, /* no input channels */ 2, /* stereo output */ paFloat32, /* 32 bit floating point output */ SAMPLE_RATE, BUFFER_SIZE, /* frames per buffer */ 0, /* number of buffers, if zero then use default minimum */ sineCallback, &wave1 ); if( err != paNoError ) goto error; err = Pa_StartStream( stream ); if( err != paNoError ) goto error; // Sleep for several seconds. Pa_Sleep(NUM_SECONDS*1000.); err = Pa_StopStream( stream ); if( err != paNoError ) goto error; err = Pa_CloseStream( stream ); if( err != paNoError ) goto error; Pa_Terminate(); printf("Finished.\n"); return err; error: Pa_Terminate(); fprintf( stderr, "An error occured while using the portaudio stream.\n" ); fprintf( stderr, "Error number: %d\n", err ); fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); return err; }