gearmulator

Emulation of classic VA synths of the late 90s/2000s that are based on Motorola 56300 family DSPs
Log | Files | Refs | Submodules | README | LICENSE

patest_stop.c (10796B)


      1 /** @file patest_stop.c
      2 	@ingroup test_src
      3 	@brief Test different ways of stopping audio.
      4 
      5 	Test the three ways of stopping audio:
      6 		- calling Pa_StopStream(),
      7 		- calling Pa_AbortStream(),
      8 		- and returning a 1 from the callback function.
      9 
     10 	A long latency is set up so that you can hear the difference.
     11 	Then a simple 8 note sequence is repeated twice.
     12 	The program will print what you should hear.
     13 
     14 	@author Phil Burk <philburk@softsynth.com>
     15 */
     16 /*
     17  * $Id$
     18  *
     19  * This program uses the PortAudio Portable Audio Library.
     20  * For more information see: http://www.portaudio.com
     21  * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
     22  *
     23  * Permission is hereby granted, free of charge, to any person obtaining
     24  * a copy of this software and associated documentation files
     25  * (the "Software"), to deal in the Software without restriction,
     26  * including without limitation the rights to use, copy, modify, merge,
     27  * publish, distribute, sublicense, and/or sell copies of the Software,
     28  * and to permit persons to whom the Software is furnished to do so,
     29  * subject to the following conditions:
     30  *
     31  * The above copyright notice and this permission notice shall be
     32  * included in all copies or substantial portions of the Software.
     33  *
     34  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
     35  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     36  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
     37  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
     38  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
     39  * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
     40  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     41  */
     42 
     43 /*
     44  * The text above constitutes the entire PortAudio license; however, 
     45  * the PortAudio community also makes the following non-binding requests:
     46  *
     47  * Any person wishing to distribute modifications to the Software is
     48  * requested to send the modifications to the original developer so that
     49  * they can be incorporated into the canonical version. It is also 
     50  * requested that these non-binding requests be included along with the 
     51  * license above.
     52  */
     53 #include <stdio.h>
     54 #include <math.h>
     55 #include "portaudio.h"
     56 
     57 #define OUTPUT_DEVICE       (Pa_GetDefaultOutputDevice())
     58 #define SLEEP_DUR           (200)
     59 #define SAMPLE_RATE         (44100)
     60 #define FRAMES_PER_BUFFER   (256)
     61 #define LATENCY_SECONDS     (3.f)
     62 #define FRAMES_PER_NOTE     (SAMPLE_RATE/2)
     63 #define MAX_REPEATS         (2)
     64 #define FUNDAMENTAL         (400.0f / SAMPLE_RATE)
     65 #define NOTE_0              (FUNDAMENTAL * 1.0f / 1.0f)
     66 #define NOTE_1              (FUNDAMENTAL * 5.0f / 4.0f)
     67 #define NOTE_2              (FUNDAMENTAL * 4.0f / 3.0f)
     68 #define NOTE_3              (FUNDAMENTAL * 3.0f / 2.0f)
     69 #define NOTE_4              (FUNDAMENTAL * 2.0f / 1.0f)
     70 #define MODE_FINISH    (0)
     71 #define MODE_STOP      (1)
     72 #define MODE_ABORT     (2)
     73 #ifndef M_PI
     74 #define M_PI  (3.14159265)
     75 #endif
     76 #define TABLE_SIZE   (400)
     77 
     78 typedef struct
     79 {
     80     float  waveform[TABLE_SIZE + 1]; /* Add one for guard point for interpolation. */
     81     float  phase_increment;
     82     float  phase;
     83     float *tune;
     84     int    notesPerTune;
     85     int    frameCounter;
     86     int    noteCounter;
     87     int    repeatCounter;
     88     PaTime outTime;
     89     int    stopMode;
     90     int    done;
     91 }
     92 paTestData;
     93 
     94 /************* Prototypes *****************************/
     95 int TestStopMode( paTestData *data );
     96 float LookupWaveform( paTestData *data, float phase );
     97 
     98 /******************************************************
     99  * Convert phase between 0.0 and 1.0 to waveform value 
    100  * using linear interpolation.
    101  */
    102 float LookupWaveform( paTestData *data, float phase )
    103 {
    104     float fIndex = phase*TABLE_SIZE;
    105     int   index = (int) fIndex;
    106     float fract = fIndex - index;
    107     float lo = data->waveform[index];
    108     float hi = data->waveform[index+1];
    109     float val = lo + fract*(hi-lo);
    110     return val;
    111 }
    112 
    113 /* This routine will be called by the PortAudio engine when audio is needed.
    114 ** It may called at interrupt level on some machines so don't do anything
    115 ** that could mess up the system like calling malloc() or free().
    116 */
    117 static int patestCallback( const void *inputBuffer, void *outputBuffer,
    118                             unsigned long framesPerBuffer,
    119                             const PaStreamCallbackTimeInfo* timeInfo,
    120                             PaStreamCallbackFlags statusFlags,
    121                             void *userData )
    122 {
    123     paTestData *data = (paTestData*)userData;
    124     float *out = (float*)outputBuffer;
    125     float value;
    126     unsigned int i = 0;
    127     int finished = paContinue;
    128 
    129     (void) inputBuffer;     /* Prevent unused variable warnings. */
    130     (void) timeInfo;
    131     (void) statusFlags;
    132 
    133 
    134     /* data->outTime = outTime; */
    135     
    136     if( !data->done )
    137     {
    138         for( i=0; i<framesPerBuffer; i++ )
    139         {
    140             /* Are we done with this note? */
    141             if( data->frameCounter >= FRAMES_PER_NOTE )
    142             {
    143                 data->noteCounter += 1;
    144                 data->frameCounter = 0;
    145                 /* Are we done with this tune? */
    146                 if( data->noteCounter >= data->notesPerTune )
    147                 {
    148                     data->noteCounter = 0;
    149                     data->repeatCounter += 1;
    150                     /* Are we totally done? */
    151                     if( data->repeatCounter >= MAX_REPEATS )
    152                     {
    153                         data->done = 1;
    154                         if( data->stopMode == MODE_FINISH )
    155                         {
    156                             finished = paComplete;
    157                             break;
    158                         }
    159                     }
    160                 }
    161                 data->phase_increment = data->tune[data->noteCounter];
    162             }
    163             value = LookupWaveform(data, data->phase);
    164             *out++ = value;  /* left */
    165             *out++ = value;  /* right */
    166             data->phase += data->phase_increment;
    167             if( data->phase >= 1.0f ) data->phase -= 1.0f;
    168 
    169             data->frameCounter += 1;
    170         }
    171     }
    172     /* zero remainder of final buffer */
    173     for( ; i<framesPerBuffer; i++ )
    174     {
    175         *out++ = 0; /* left */
    176         *out++ = 0; /* right */
    177     }
    178     return finished;
    179 }
    180 /*******************************************************************/
    181 int main(void);
    182 int main(void)
    183 {
    184     paTestData data;
    185     int i;
    186     float simpleTune[] = { NOTE_0, NOTE_1, NOTE_2, NOTE_3, NOTE_4, NOTE_3, NOTE_2, NOTE_1 };
    187     
    188     printf("PortAudio Test: play song and test stopping. ask for %f seconds latency\n", LATENCY_SECONDS );
    189     /* initialise sinusoidal wavetable */
    190     for( i=0; i<TABLE_SIZE; i++ )
    191     {
    192         data.waveform[i] = (float) (
    193                                (0.2 * sin( ((double)i/(double)TABLE_SIZE) * M_PI * 2. )) +
    194                                (0.2 * sin( ((double)(3*i)/(double)TABLE_SIZE) * M_PI * 2. )) +
    195                                (0.1 * sin( ((double)(5*i)/(double)TABLE_SIZE) * M_PI * 2. ))
    196                            );
    197     }
    198     data.waveform[TABLE_SIZE] = data.waveform[0]; /* Set guard point. */
    199     data.tune = &simpleTune[0];
    200     data.notesPerTune = sizeof(simpleTune) / sizeof(float);
    201 
    202     printf("Test MODE_FINISH - callback returns 1.\n");
    203     printf("Should hear entire %d note tune repeated twice.\n", data.notesPerTune);
    204     data.stopMode = MODE_FINISH;
    205     if( TestStopMode( &data ) != paNoError )
    206     {
    207         printf("Test of MODE_FINISH failed!\n");
    208         goto error;
    209     }
    210 
    211     printf("Test MODE_STOP - stop when song is done.\n");
    212     printf("Should hear entire %d note tune repeated twice.\n", data.notesPerTune);
    213     data.stopMode = MODE_STOP;
    214     if( TestStopMode( &data ) != paNoError )
    215     {
    216         printf("Test of MODE_STOP failed!\n");
    217         goto error;
    218     }
    219 
    220     printf("Test MODE_ABORT - abort immediately.\n");
    221     printf("Should hear last repetition cut short by %f seconds.\n", LATENCY_SECONDS);
    222     data.stopMode = MODE_ABORT;
    223     if( TestStopMode( &data ) != paNoError )
    224     {
    225         printf("Test of MODE_ABORT failed!\n");
    226         goto error;
    227     }
    228 
    229     return 0;
    230 
    231 error:
    232     return 1;
    233 }
    234 
    235 int TestStopMode( paTestData *data )
    236 {
    237     PaStreamParameters outputParameters;
    238     PaStream *stream;
    239     PaError err;
    240     
    241     data->done = 0;
    242     data->phase = 0.0;
    243     data->frameCounter = 0;
    244     data->noteCounter = 0;
    245     data->repeatCounter = 0;
    246     data->phase_increment = data->tune[data->noteCounter];
    247     
    248     err = Pa_Initialize();
    249     if( err != paNoError ) goto error;
    250 
    251     outputParameters.device = OUTPUT_DEVICE;
    252     if (outputParameters.device == paNoDevice) {
    253         fprintf(stderr,"Error: No default output device.\n");
    254         goto error;
    255     }
    256     outputParameters.channelCount = 2;          /* stereo output */
    257     outputParameters.sampleFormat = paFloat32;  /* 32 bit floating point output */
    258     outputParameters.suggestedLatency = LATENCY_SECONDS;
    259     outputParameters.hostApiSpecificStreamInfo = NULL;
    260     
    261     err = Pa_OpenStream(
    262               &stream,
    263               NULL, /* no input */
    264               &outputParameters,
    265               SAMPLE_RATE,
    266               FRAMES_PER_BUFFER,            /* frames per buffer */
    267               paClipOff,      /* we won't output out of range samples so don't bother clipping them */
    268               patestCallback,
    269               data );
    270     if( err != paNoError ) goto error;
    271 
    272     err = Pa_StartStream( stream );
    273     if( err != paNoError ) goto error;
    274 
    275     if( data->stopMode == MODE_FINISH )
    276     {
    277         while( ( err = Pa_IsStreamActive( stream ) ) == 1 )
    278         {
    279             /*printf("outTime = %g, note# = %d, repeat# = %d\n", data->outTime,
    280              data->noteCounter, data->repeatCounter  );
    281             fflush(stdout); */
    282             Pa_Sleep( SLEEP_DUR );
    283         }
    284         if( err < 0 ) goto error;
    285     }
    286     else
    287     {
    288         while( data->repeatCounter < MAX_REPEATS )
    289         {
    290             /*printf("outTime = %g, note# = %d, repeat# = %d\n", data->outTime,
    291              data->noteCounter, data->repeatCounter  );
    292             fflush(stdout); */
    293             Pa_Sleep( SLEEP_DUR );
    294         }
    295     }
    296 
    297     if( data->stopMode == MODE_ABORT )
    298     {
    299         printf("Call Pa_AbortStream()\n");
    300         err = Pa_AbortStream( stream );
    301     }
    302     else
    303     {
    304         printf("Call Pa_StopStream()\n");
    305         err = Pa_StopStream( stream );
    306     }
    307     if( err != paNoError ) goto error;
    308 
    309     printf("Call Pa_CloseStream()\n"); fflush(stdout);
    310     err = Pa_CloseStream( stream );
    311     if( err != paNoError ) goto error;
    312 
    313     Pa_Terminate();
    314     printf("Test finished.\n");
    315 
    316     return err;
    317 
    318 error:
    319     Pa_Terminate();
    320     fprintf( stderr, "An error occured while using the portaudio stream\n" );
    321     fprintf( stderr, "Error number: %d\n", err );
    322     fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
    323     return err;
    324 }