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

pa_hostapi_skeleton.c (28260B)


      1 /*
      2  * $Id$
      3  * Portable Audio I/O Library skeleton implementation
      4  * demonstrates how to use the common functions to implement support
      5  * for a host API
      6  *
      7  * Based on the Open Source API proposed by Ross Bencina
      8  * Copyright (c) 1999-2002 Ross Bencina, Phil Burk
      9  *
     10  * Permission is hereby granted, free of charge, to any person obtaining
     11  * a copy of this software and associated documentation files
     12  * (the "Software"), to deal in the Software without restriction,
     13  * including without limitation the rights to use, copy, modify, merge,
     14  * publish, distribute, sublicense, and/or sell copies of the Software,
     15  * and to permit persons to whom the Software is furnished to do so,
     16  * subject to the following conditions:
     17  *
     18  * The above copyright notice and this permission notice shall be
     19  * included in all copies or substantial portions of the Software.
     20  *
     21  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
     22  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     23  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
     24  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
     25  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
     26  * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
     27  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     28  */
     29 
     30 /*
     31  * The text above constitutes the entire PortAudio license; however, 
     32  * the PortAudio community also makes the following non-binding requests:
     33  *
     34  * Any person wishing to distribute modifications to the Software is
     35  * requested to send the modifications to the original developer so that
     36  * they can be incorporated into the canonical version. It is also 
     37  * requested that these non-binding requests be included along with the 
     38  * license above.
     39  */
     40 
     41 /** @file
     42  @ingroup common_src
     43 
     44  @brief Skeleton implementation of support for a host API.
     45 
     46  This file is provided as a starting point for implementing support for
     47  a new host API. It provides examples of how the common code can be used.
     48 
     49  @note IMPLEMENT ME comments are used to indicate functionality
     50  which much be customised for each implementation.
     51 */
     52 
     53 
     54 #include <string.h> /* strlen() */
     55 
     56 #include "pa_util.h"
     57 #include "pa_allocation.h"
     58 #include "pa_hostapi.h"
     59 #include "pa_stream.h"
     60 #include "pa_cpuload.h"
     61 #include "pa_process.h"
     62 
     63 
     64 /* prototypes for functions declared in this file */
     65 
     66 #ifdef __cplusplus
     67 extern "C"
     68 {
     69 #endif /* __cplusplus */
     70 
     71 PaError PaSkeleton_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );
     72 
     73 #ifdef __cplusplus
     74 }
     75 #endif /* __cplusplus */
     76 
     77 
     78 static void Terminate( struct PaUtilHostApiRepresentation *hostApi );
     79 static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,
     80                                   const PaStreamParameters *inputParameters,
     81                                   const PaStreamParameters *outputParameters,
     82                                   double sampleRate );
     83 static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
     84                            PaStream** s,
     85                            const PaStreamParameters *inputParameters,
     86                            const PaStreamParameters *outputParameters,
     87                            double sampleRate,
     88                            unsigned long framesPerBuffer,
     89                            PaStreamFlags streamFlags,
     90                            PaStreamCallback *streamCallback,
     91                            void *userData );
     92 static PaError CloseStream( PaStream* stream );
     93 static PaError StartStream( PaStream *stream );
     94 static PaError StopStream( PaStream *stream );
     95 static PaError AbortStream( PaStream *stream );
     96 static PaError IsStreamStopped( PaStream *s );
     97 static PaError IsStreamActive( PaStream *stream );
     98 static PaTime GetStreamTime( PaStream *stream );
     99 static double GetStreamCpuLoad( PaStream* stream );
    100 static PaError ReadStream( PaStream* stream, void *buffer, unsigned long frames );
    101 static PaError WriteStream( PaStream* stream, const void *buffer, unsigned long frames );
    102 static signed long GetStreamReadAvailable( PaStream* stream );
    103 static signed long GetStreamWriteAvailable( PaStream* stream );
    104 
    105 
    106 /* IMPLEMENT ME: a macro like the following one should be used for reporting
    107  host errors */
    108 #define PA_SKELETON_SET_LAST_HOST_ERROR( errorCode, errorText ) \
    109     PaUtil_SetLastHostErrorInfo( paInDevelopment, errorCode, errorText )
    110 
    111 /* PaSkeletonHostApiRepresentation - host api datastructure specific to this implementation */
    112 
    113 typedef struct
    114 {
    115     PaUtilHostApiRepresentation inheritedHostApiRep;
    116     PaUtilStreamInterface callbackStreamInterface;
    117     PaUtilStreamInterface blockingStreamInterface;
    118 
    119     PaUtilAllocationGroup *allocations;
    120 
    121     /* implementation specific data goes here */
    122 }
    123 PaSkeletonHostApiRepresentation;  /* IMPLEMENT ME: rename this */
    124 
    125 
    126 PaError PaSkeleton_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex )
    127 {
    128     PaError result = paNoError;
    129     int i, deviceCount;
    130     PaSkeletonHostApiRepresentation *skeletonHostApi;
    131     PaDeviceInfo *deviceInfoArray;
    132 
    133     skeletonHostApi = (PaSkeletonHostApiRepresentation*)PaUtil_AllocateMemory( sizeof(PaSkeletonHostApiRepresentation) );
    134     if( !skeletonHostApi )
    135     {
    136         result = paInsufficientMemory;
    137         goto error;
    138     }
    139 
    140     skeletonHostApi->allocations = PaUtil_CreateAllocationGroup();
    141     if( !skeletonHostApi->allocations )
    142     {
    143         result = paInsufficientMemory;
    144         goto error;
    145     }
    146 
    147     *hostApi = &skeletonHostApi->inheritedHostApiRep;
    148     (*hostApi)->info.structVersion = 1;
    149     (*hostApi)->info.type = paInDevelopment;            /* IMPLEMENT ME: change to correct type id */
    150     (*hostApi)->info.name = "skeleton implementation";  /* IMPLEMENT ME: change to correct name */
    151 
    152     (*hostApi)->info.defaultInputDevice = paNoDevice;  /* IMPLEMENT ME */
    153     (*hostApi)->info.defaultOutputDevice = paNoDevice; /* IMPLEMENT ME */
    154 
    155     (*hostApi)->info.deviceCount = 0;  
    156 
    157     deviceCount = 0; /* IMPLEMENT ME */
    158     
    159     if( deviceCount > 0 )
    160     {
    161         (*hostApi)->deviceInfos = (PaDeviceInfo**)PaUtil_GroupAllocateMemory(
    162                 skeletonHostApi->allocations, sizeof(PaDeviceInfo*) * deviceCount );
    163         if( !(*hostApi)->deviceInfos )
    164         {
    165             result = paInsufficientMemory;
    166             goto error;
    167         }
    168 
    169         /* allocate all device info structs in a contiguous block */
    170         deviceInfoArray = (PaDeviceInfo*)PaUtil_GroupAllocateMemory(
    171                 skeletonHostApi->allocations, sizeof(PaDeviceInfo) * deviceCount );
    172         if( !deviceInfoArray )
    173         {
    174             result = paInsufficientMemory;
    175             goto error;
    176         }
    177 
    178         for( i=0; i < deviceCount; ++i )
    179         {
    180             PaDeviceInfo *deviceInfo = &deviceInfoArray[i];
    181             deviceInfo->structVersion = 2;
    182             deviceInfo->hostApi = hostApiIndex;
    183             deviceInfo->name = 0; /* IMPLEMENT ME: allocate block and copy name eg:
    184                 deviceName = (char*)PaUtil_GroupAllocateMemory( skeletonHostApi->allocations, strlen(srcName) + 1 );
    185                 if( !deviceName )
    186                 {
    187                     result = paInsufficientMemory;
    188                     goto error;
    189                 }
    190                 strcpy( deviceName, srcName );
    191                 deviceInfo->name = deviceName;
    192             */
    193 
    194             deviceInfo->maxInputChannels = 0;  /* IMPLEMENT ME */
    195             deviceInfo->maxOutputChannels = 0;  /* IMPLEMENT ME */
    196             
    197             deviceInfo->defaultLowInputLatency = 0.;  /* IMPLEMENT ME */
    198             deviceInfo->defaultLowOutputLatency = 0.;  /* IMPLEMENT ME */
    199             deviceInfo->defaultHighInputLatency = 0.;  /* IMPLEMENT ME */
    200             deviceInfo->defaultHighOutputLatency = 0.;  /* IMPLEMENT ME */  
    201 
    202             deviceInfo->defaultSampleRate = 0.; /* IMPLEMENT ME */
    203             
    204             (*hostApi)->deviceInfos[i] = deviceInfo;
    205             ++(*hostApi)->info.deviceCount;
    206         }
    207     }
    208 
    209     (*hostApi)->Terminate = Terminate;
    210     (*hostApi)->OpenStream = OpenStream;
    211     (*hostApi)->IsFormatSupported = IsFormatSupported;
    212 
    213     PaUtil_InitializeStreamInterface( &skeletonHostApi->callbackStreamInterface, CloseStream, StartStream,
    214                                       StopStream, AbortStream, IsStreamStopped, IsStreamActive,
    215                                       GetStreamTime, GetStreamCpuLoad,
    216                                       PaUtil_DummyRead, PaUtil_DummyWrite,
    217                                       PaUtil_DummyGetReadAvailable, PaUtil_DummyGetWriteAvailable );
    218 
    219     PaUtil_InitializeStreamInterface( &skeletonHostApi->blockingStreamInterface, CloseStream, StartStream,
    220                                       StopStream, AbortStream, IsStreamStopped, IsStreamActive,
    221                                       GetStreamTime, PaUtil_DummyGetCpuLoad,
    222                                       ReadStream, WriteStream, GetStreamReadAvailable, GetStreamWriteAvailable );
    223 
    224     return result;
    225 
    226 error:
    227     if( skeletonHostApi )
    228     {
    229         if( skeletonHostApi->allocations )
    230         {
    231             PaUtil_FreeAllAllocations( skeletonHostApi->allocations );
    232             PaUtil_DestroyAllocationGroup( skeletonHostApi->allocations );
    233         }
    234                 
    235         PaUtil_FreeMemory( skeletonHostApi );
    236     }
    237     return result;
    238 }
    239 
    240 
    241 static void Terminate( struct PaUtilHostApiRepresentation *hostApi )
    242 {
    243     PaSkeletonHostApiRepresentation *skeletonHostApi = (PaSkeletonHostApiRepresentation*)hostApi;
    244 
    245     /*
    246         IMPLEMENT ME:
    247             - clean up any resources not handled by the allocation group
    248     */
    249 
    250     if( skeletonHostApi->allocations )
    251     {
    252         PaUtil_FreeAllAllocations( skeletonHostApi->allocations );
    253         PaUtil_DestroyAllocationGroup( skeletonHostApi->allocations );
    254     }
    255 
    256     PaUtil_FreeMemory( skeletonHostApi );
    257 }
    258 
    259 
    260 static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,
    261                                   const PaStreamParameters *inputParameters,
    262                                   const PaStreamParameters *outputParameters,
    263                                   double sampleRate )
    264 {
    265     int inputChannelCount, outputChannelCount;
    266     PaSampleFormat inputSampleFormat, outputSampleFormat;
    267     
    268     if( inputParameters )
    269     {
    270         inputChannelCount = inputParameters->channelCount;
    271         inputSampleFormat = inputParameters->sampleFormat;
    272 
    273         /* all standard sample formats are supported by the buffer adapter,
    274             this implementation doesn't support any custom sample formats */
    275         if( inputSampleFormat & paCustomFormat )
    276             return paSampleFormatNotSupported;
    277             
    278         /* unless alternate device specification is supported, reject the use of
    279             paUseHostApiSpecificDeviceSpecification */
    280 
    281         if( inputParameters->device == paUseHostApiSpecificDeviceSpecification )
    282             return paInvalidDevice;
    283 
    284         /* check that input device can support inputChannelCount */
    285         if( inputChannelCount > hostApi->deviceInfos[ inputParameters->device ]->maxInputChannels )
    286             return paInvalidChannelCount;
    287 
    288         /* validate inputStreamInfo */
    289         if( inputParameters->hostApiSpecificStreamInfo )
    290             return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
    291     }
    292     else
    293     {
    294         inputChannelCount = 0;
    295     }
    296 
    297     if( outputParameters )
    298     {
    299         outputChannelCount = outputParameters->channelCount;
    300         outputSampleFormat = outputParameters->sampleFormat;
    301 
    302         /* all standard sample formats are supported by the buffer adapter,
    303             this implementation doesn't support any custom sample formats */
    304         if( outputSampleFormat & paCustomFormat )
    305             return paSampleFormatNotSupported;
    306             
    307         /* unless alternate device specification is supported, reject the use of
    308             paUseHostApiSpecificDeviceSpecification */
    309 
    310         if( outputParameters->device == paUseHostApiSpecificDeviceSpecification )
    311             return paInvalidDevice;
    312 
    313         /* check that output device can support outputChannelCount */
    314         if( outputChannelCount > hostApi->deviceInfos[ outputParameters->device ]->maxOutputChannels )
    315             return paInvalidChannelCount;
    316 
    317         /* validate outputStreamInfo */
    318         if( outputParameters->hostApiSpecificStreamInfo )
    319             return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
    320     }
    321     else
    322     {
    323         outputChannelCount = 0;
    324     }
    325     
    326     /*
    327         IMPLEMENT ME:
    328 
    329             - if a full duplex stream is requested, check that the combination
    330                 of input and output parameters is supported if necessary
    331 
    332             - check that the device supports sampleRate
    333 
    334         Because the buffer adapter handles conversion between all standard
    335         sample formats, the following checks are only required if paCustomFormat
    336         is implemented, or under some other unusual conditions.
    337 
    338             - check that input device can support inputSampleFormat, or that
    339                 we have the capability to convert from inputSampleFormat to
    340                 a native format
    341 
    342             - check that output device can support outputSampleFormat, or that
    343                 we have the capability to convert from outputSampleFormat to
    344                 a native format
    345     */
    346 
    347 
    348     /* suppress unused variable warnings */
    349     (void) sampleRate;
    350 
    351     return paFormatIsSupported;
    352 }
    353 
    354 /* PaSkeletonStream - a stream data structure specifically for this implementation */
    355 
    356 typedef struct PaSkeletonStream
    357 { /* IMPLEMENT ME: rename this */
    358     PaUtilStreamRepresentation streamRepresentation;
    359     PaUtilCpuLoadMeasurer cpuLoadMeasurer;
    360     PaUtilBufferProcessor bufferProcessor;
    361 
    362     /* IMPLEMENT ME:
    363             - implementation specific data goes here
    364     */
    365     unsigned long framesPerHostCallback; /* just an example */
    366 }
    367 PaSkeletonStream;
    368 
    369 /* see pa_hostapi.h for a list of validity guarantees made about OpenStream parameters */
    370 
    371 static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
    372                            PaStream** s,
    373                            const PaStreamParameters *inputParameters,
    374                            const PaStreamParameters *outputParameters,
    375                            double sampleRate,
    376                            unsigned long framesPerBuffer,
    377                            PaStreamFlags streamFlags,
    378                            PaStreamCallback *streamCallback,
    379                            void *userData )
    380 {
    381     PaError result = paNoError;
    382     PaSkeletonHostApiRepresentation *skeletonHostApi = (PaSkeletonHostApiRepresentation*)hostApi;
    383     PaSkeletonStream *stream = 0;
    384     unsigned long framesPerHostBuffer = framesPerBuffer; /* these may not be equivalent for all implementations */
    385     int inputChannelCount, outputChannelCount;
    386     PaSampleFormat inputSampleFormat, outputSampleFormat;
    387     PaSampleFormat hostInputSampleFormat, hostOutputSampleFormat;
    388 
    389 
    390     if( inputParameters )
    391     {
    392         inputChannelCount = inputParameters->channelCount;
    393         inputSampleFormat = inputParameters->sampleFormat;
    394 
    395         /* unless alternate device specification is supported, reject the use of
    396             paUseHostApiSpecificDeviceSpecification */
    397 
    398         if( inputParameters->device == paUseHostApiSpecificDeviceSpecification )
    399             return paInvalidDevice;
    400 
    401         /* check that input device can support inputChannelCount */
    402         if( inputChannelCount > hostApi->deviceInfos[ inputParameters->device ]->maxInputChannels )
    403             return paInvalidChannelCount;
    404 
    405         /* validate inputStreamInfo */
    406         if( inputParameters->hostApiSpecificStreamInfo )
    407             return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
    408 
    409         /* IMPLEMENT ME - establish which  host formats are available */
    410         hostInputSampleFormat =
    411             PaUtil_SelectClosestAvailableFormat( paInt16 /* native formats */, inputSampleFormat );
    412     }
    413     else
    414     {
    415         inputChannelCount = 0;
    416         inputSampleFormat = hostInputSampleFormat = paInt16; /* Surpress 'uninitialised var' warnings. */
    417     }
    418 
    419     if( outputParameters )
    420     {
    421         outputChannelCount = outputParameters->channelCount;
    422         outputSampleFormat = outputParameters->sampleFormat;
    423         
    424         /* unless alternate device specification is supported, reject the use of
    425             paUseHostApiSpecificDeviceSpecification */
    426 
    427         if( outputParameters->device == paUseHostApiSpecificDeviceSpecification )
    428             return paInvalidDevice;
    429 
    430         /* check that output device can support inputChannelCount */
    431         if( outputChannelCount > hostApi->deviceInfos[ outputParameters->device ]->maxOutputChannels )
    432             return paInvalidChannelCount;
    433 
    434         /* validate outputStreamInfo */
    435         if( outputParameters->hostApiSpecificStreamInfo )
    436             return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
    437 
    438         /* IMPLEMENT ME - establish which  host formats are available */
    439         hostOutputSampleFormat =
    440             PaUtil_SelectClosestAvailableFormat( paInt16 /* native formats */, outputSampleFormat );
    441     }
    442     else
    443     {
    444         outputChannelCount = 0;
    445         outputSampleFormat = hostOutputSampleFormat = paInt16; /* Surpress 'uninitialized var' warnings. */
    446     }
    447 
    448     /*
    449         IMPLEMENT ME:
    450 
    451         ( the following two checks are taken care of by PaUtil_InitializeBufferProcessor() FIXME - checks needed? )
    452 
    453             - check that input device can support inputSampleFormat, or that
    454                 we have the capability to convert from outputSampleFormat to
    455                 a native format
    456 
    457             - check that output device can support outputSampleFormat, or that
    458                 we have the capability to convert from outputSampleFormat to
    459                 a native format
    460 
    461             - if a full duplex stream is requested, check that the combination
    462                 of input and output parameters is supported
    463 
    464             - check that the device supports sampleRate
    465 
    466             - alter sampleRate to a close allowable rate if possible / necessary
    467 
    468             - validate suggestedInputLatency and suggestedOutputLatency parameters,
    469                 use default values where necessary
    470     */
    471 
    472 
    473 
    474 
    475     /* validate platform specific flags */
    476     if( (streamFlags & paPlatformSpecificFlags) != 0 )
    477         return paInvalidFlag; /* unexpected platform specific flag */
    478 
    479 
    480     stream = (PaSkeletonStream*)PaUtil_AllocateMemory( sizeof(PaSkeletonStream) );
    481     if( !stream )
    482     {
    483         result = paInsufficientMemory;
    484         goto error;
    485     }
    486 
    487     if( streamCallback )
    488     {
    489         PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation,
    490                                                &skeletonHostApi->callbackStreamInterface, streamCallback, userData );
    491     }
    492     else
    493     {
    494         PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation,
    495                                                &skeletonHostApi->blockingStreamInterface, streamCallback, userData );
    496     }
    497 
    498     PaUtil_InitializeCpuLoadMeasurer( &stream->cpuLoadMeasurer, sampleRate );
    499 
    500 
    501     /* we assume a fixed host buffer size in this example, but the buffer processor
    502         can also support bounded and unknown host buffer sizes by passing 
    503         paUtilBoundedHostBufferSize or paUtilUnknownHostBufferSize instead of
    504         paUtilFixedHostBufferSize below. */
    505         
    506     result =  PaUtil_InitializeBufferProcessor( &stream->bufferProcessor,
    507               inputChannelCount, inputSampleFormat, hostInputSampleFormat,
    508               outputChannelCount, outputSampleFormat, hostOutputSampleFormat,
    509               sampleRate, streamFlags, framesPerBuffer,
    510               framesPerHostBuffer, paUtilFixedHostBufferSize,
    511               streamCallback, userData );
    512     if( result != paNoError )
    513         goto error;
    514 
    515 
    516     /*
    517         IMPLEMENT ME: initialise the following fields with estimated or actual
    518         values.
    519     */
    520     stream->streamRepresentation.streamInfo.inputLatency =
    521             (PaTime)PaUtil_GetBufferProcessorInputLatencyFrames(&stream->bufferProcessor) / sampleRate; /* inputLatency is specified in _seconds_ */
    522     stream->streamRepresentation.streamInfo.outputLatency =
    523             (PaTime)PaUtil_GetBufferProcessorOutputLatencyFrames(&stream->bufferProcessor) / sampleRate; /* outputLatency is specified in _seconds_ */
    524     stream->streamRepresentation.streamInfo.sampleRate = sampleRate;
    525 
    526     
    527     /*
    528         IMPLEMENT ME:
    529             - additional stream setup + opening
    530     */
    531 
    532     stream->framesPerHostCallback = framesPerHostBuffer;
    533 
    534     *s = (PaStream*)stream;
    535 
    536     return result;
    537 
    538 error:
    539     if( stream )
    540         PaUtil_FreeMemory( stream );
    541 
    542     return result;
    543 }
    544 
    545 /*
    546     ExampleHostProcessingLoop() illustrates the kind of processing which may
    547     occur in a host implementation.
    548  
    549 */
    550 static void ExampleHostProcessingLoop( void *inputBuffer, void *outputBuffer, void *userData )
    551 {
    552     PaSkeletonStream *stream = (PaSkeletonStream*)userData;
    553     PaStreamCallbackTimeInfo timeInfo = {0,0,0}; /* IMPLEMENT ME */
    554     int callbackResult;
    555     unsigned long framesProcessed;
    556     
    557     PaUtil_BeginCpuLoadMeasurement( &stream->cpuLoadMeasurer );
    558     
    559     /*
    560         IMPLEMENT ME:
    561             - generate timing information
    562             - handle buffer slips
    563     */
    564 
    565     /*
    566         If you need to byte swap or shift inputBuffer to convert it into a
    567         portaudio format, do it here.
    568     */
    569 
    570 
    571 
    572     PaUtil_BeginBufferProcessing( &stream->bufferProcessor, &timeInfo, 0 /* IMPLEMENT ME: pass underflow/overflow flags when necessary */ );
    573 
    574     /*
    575         depending on whether the host buffers are interleaved, non-interleaved
    576         or a mixture, you will want to call PaUtil_SetInterleaved*Channels(),
    577         PaUtil_SetNonInterleaved*Channel() or PaUtil_Set*Channel() here.
    578     */
    579     
    580     PaUtil_SetInputFrameCount( &stream->bufferProcessor, 0 /* default to host buffer size */ );
    581     PaUtil_SetInterleavedInputChannels( &stream->bufferProcessor,
    582             0, /* first channel of inputBuffer is channel 0 */
    583             inputBuffer,
    584             0 ); /* 0 - use inputChannelCount passed to init buffer processor */
    585 
    586     PaUtil_SetOutputFrameCount( &stream->bufferProcessor, 0 /* default to host buffer size */ );
    587     PaUtil_SetInterleavedOutputChannels( &stream->bufferProcessor,
    588             0, /* first channel of outputBuffer is channel 0 */
    589             outputBuffer,
    590             0 ); /* 0 - use outputChannelCount passed to init buffer processor */
    591 
    592     /* you must pass a valid value of callback result to PaUtil_EndBufferProcessing()
    593         in general you would pass paContinue for normal operation, and
    594         paComplete to drain the buffer processor's internal output buffer.
    595         You can check whether the buffer processor's output buffer is empty
    596         using PaUtil_IsBufferProcessorOuputEmpty( bufferProcessor )
    597     */
    598     callbackResult = paContinue;
    599     framesProcessed = PaUtil_EndBufferProcessing( &stream->bufferProcessor, &callbackResult );
    600 
    601     
    602     /*
    603         If you need to byte swap or shift outputBuffer to convert it to
    604         host format, do it here.
    605     */
    606 
    607     PaUtil_EndCpuLoadMeasurement( &stream->cpuLoadMeasurer, framesProcessed );
    608 
    609 
    610     if( callbackResult == paContinue )
    611     {
    612         /* nothing special to do */
    613     }
    614     else if( callbackResult == paAbort )
    615     {
    616         /* IMPLEMENT ME - finish playback immediately  */
    617 
    618         /* once finished, call the finished callback */
    619         if( stream->streamRepresentation.streamFinishedCallback != 0 )
    620             stream->streamRepresentation.streamFinishedCallback( stream->streamRepresentation.userData );
    621     }
    622     else
    623     {
    624         /* User callback has asked us to stop with paComplete or other non-zero value */
    625 
    626         /* IMPLEMENT ME - finish playback once currently queued audio has completed  */
    627 
    628         /* once finished, call the finished callback */
    629         if( stream->streamRepresentation.streamFinishedCallback != 0 )
    630             stream->streamRepresentation.streamFinishedCallback( stream->streamRepresentation.userData );
    631     }
    632 }
    633 
    634 
    635 /*
    636     When CloseStream() is called, the multi-api layer ensures that
    637     the stream has already been stopped or aborted.
    638 */
    639 static PaError CloseStream( PaStream* s )
    640 {
    641     PaError result = paNoError;
    642     PaSkeletonStream *stream = (PaSkeletonStream*)s;
    643 
    644     /*
    645         IMPLEMENT ME:
    646             - additional stream closing + cleanup
    647     */
    648 
    649     PaUtil_TerminateBufferProcessor( &stream->bufferProcessor );
    650     PaUtil_TerminateStreamRepresentation( &stream->streamRepresentation );
    651     PaUtil_FreeMemory( stream );
    652 
    653     return result;
    654 }
    655 
    656 
    657 static PaError StartStream( PaStream *s )
    658 {
    659     PaError result = paNoError;
    660     PaSkeletonStream *stream = (PaSkeletonStream*)s;
    661 
    662     PaUtil_ResetBufferProcessor( &stream->bufferProcessor );
    663 
    664     /* IMPLEMENT ME, see portaudio.h for required behavior */
    665 
    666     /* suppress unused function warning. the code in ExampleHostProcessingLoop or
    667        something similar should be implemented to feed samples to and from the
    668        host after StartStream() is called.
    669     */
    670     (void) ExampleHostProcessingLoop;
    671 
    672     return result;
    673 }
    674 
    675 
    676 static PaError StopStream( PaStream *s )
    677 {
    678     PaError result = paNoError;
    679     PaSkeletonStream *stream = (PaSkeletonStream*)s;
    680 
    681     /* suppress unused variable warnings */
    682     (void) stream;
    683 
    684     /* IMPLEMENT ME, see portaudio.h for required behavior */
    685 
    686     return result;
    687 }
    688 
    689 
    690 static PaError AbortStream( PaStream *s )
    691 {
    692     PaError result = paNoError;
    693     PaSkeletonStream *stream = (PaSkeletonStream*)s;
    694 
    695     /* suppress unused variable warnings */
    696     (void) stream;
    697     
    698     /* IMPLEMENT ME, see portaudio.h for required behavior */
    699 
    700     return result;
    701 }
    702 
    703 
    704 static PaError IsStreamStopped( PaStream *s )
    705 {
    706     PaSkeletonStream *stream = (PaSkeletonStream*)s;
    707 
    708     /* suppress unused variable warnings */
    709     (void) stream;
    710     
    711     /* IMPLEMENT ME, see portaudio.h for required behavior */
    712 
    713     return 0;
    714 }
    715 
    716 
    717 static PaError IsStreamActive( PaStream *s )
    718 {
    719     PaSkeletonStream *stream = (PaSkeletonStream*)s;
    720 
    721     /* suppress unused variable warnings */
    722     (void) stream;
    723     
    724     /* IMPLEMENT ME, see portaudio.h for required behavior */
    725 
    726     return 0;
    727 }
    728 
    729 
    730 static PaTime GetStreamTime( PaStream *s )
    731 {
    732     PaSkeletonStream *stream = (PaSkeletonStream*)s;
    733 
    734     /* suppress unused variable warnings */
    735     (void) stream;
    736     
    737     /* IMPLEMENT ME, see portaudio.h for required behavior*/
    738 
    739     return 0;
    740 }
    741 
    742 
    743 static double GetStreamCpuLoad( PaStream* s )
    744 {
    745     PaSkeletonStream *stream = (PaSkeletonStream*)s;
    746 
    747     return PaUtil_GetCpuLoad( &stream->cpuLoadMeasurer );
    748 }
    749 
    750 
    751 /*
    752     As separate stream interfaces are used for blocking and callback
    753     streams, the following functions can be guaranteed to only be called
    754     for blocking streams.
    755 */
    756 
    757 static PaError ReadStream( PaStream* s,
    758                            void *buffer,
    759                            unsigned long frames )
    760 {
    761     PaSkeletonStream *stream = (PaSkeletonStream*)s;
    762 
    763     /* suppress unused variable warnings */
    764     (void) buffer;
    765     (void) frames;
    766     (void) stream;
    767     
    768     /* IMPLEMENT ME, see portaudio.h for required behavior*/
    769 
    770     return paNoError;
    771 }
    772 
    773 
    774 static PaError WriteStream( PaStream* s,
    775                             const void *buffer,
    776                             unsigned long frames )
    777 {
    778     PaSkeletonStream *stream = (PaSkeletonStream*)s;
    779 
    780     /* suppress unused variable warnings */
    781     (void) buffer;
    782     (void) frames;
    783     (void) stream;
    784     
    785     /* IMPLEMENT ME, see portaudio.h for required behavior*/
    786 
    787     return paNoError;
    788 }
    789 
    790 
    791 static signed long GetStreamReadAvailable( PaStream* s )
    792 {
    793     PaSkeletonStream *stream = (PaSkeletonStream*)s;
    794 
    795     /* suppress unused variable warnings */
    796     (void) stream;
    797     
    798     /* IMPLEMENT ME, see portaudio.h for required behavior*/
    799 
    800     return 0;
    801 }
    802 
    803 
    804 static signed long GetStreamWriteAvailable( PaStream* s )
    805 {
    806     PaSkeletonStream *stream = (PaSkeletonStream*)s;
    807 
    808     /* suppress unused variable warnings */
    809     (void) stream;
    810     
    811     /* IMPLEMENT ME, see portaudio.h for required behavior*/
    812 
    813     return 0;
    814 }
    815 
    816 
    817 
    818