Ejemplo n.º 1
0
PaError CloseAudioStream( PABLIO_Stream *aStream )
{
    PaError err;
    int bytesEmpty;
    int byteSize = aStream->outFIFO.bufferSize;

    /* If we are writing data, make sure we play everything written. */
    if( byteSize > 0 )
    {
        bytesEmpty = RingBuffer_GetWriteAvailable( &aStream->outFIFO );
        while( bytesEmpty < byteSize )
        {
            NPa_Sleep( 10 ); /* MSP */
            bytesEmpty = RingBuffer_GetWriteAvailable( &aStream->outFIFO );
        }
    }

    err = Pa_StopStream( aStream->stream );
    if( err != paNoError ) goto error;
    err = Pa_CloseStream( aStream->stream );
    if( err != paNoError ) goto error;
    Pa_Terminate();

error:
    PABLIO_TermFIFO( &aStream->inFIFO );
    PABLIO_TermFIFO( &aStream->outFIFO );
    free( aStream );
    return err;
}
Ejemplo n.º 2
0
void waitUntilBlioWriteBufferIsFlushed( PaMacBlio *blio )
{
    if( blio->outputRingBuffer.buffer ) {
       long avail = RingBuffer_GetWriteAvailable( &blio->outputRingBuffer );
       while( avail != blio->outputRingBuffer.bufferSize ) {
          if( avail == 0 )
             Pa_Sleep( PA_MAC_BLIO_BUSY_WAIT_SLEEP_INTERVAL );
          avail = RingBuffer_GetWriteAvailable( &blio->outputRingBuffer );
       }
    }
}
Ejemplo n.º 3
0
/***************************************************************************
** Get address of region(s) to which we can write data.
** If the region is contiguous, size2 will be zero.
** If non-contiguous, size2 will be the size of second region.
** Returns room available to be written or numBytes, whichever is smaller.
*/
long RingBuffer_GetWriteRegions( RingBuffer *rbuf, long numBytes,
                                 void **dataPtr1, long *sizePtr1,
                                 void **dataPtr2, long *sizePtr2 )
{
    long   index;
    long   available = RingBuffer_GetWriteAvailable( rbuf );
    if( numBytes > available ) numBytes = available;
    /* Check to see if write is not contiguous. */
    index = rbuf->writeIndex & rbuf->smallMask;
    if( (index + numBytes) > rbuf->bufferSize )
    {
        /* Write data in two blocks that wrap the buffer. */
        long   firstHalf = rbuf->bufferSize - index;
        *dataPtr1 = &rbuf->buffer[index];
        *sizePtr1 = firstHalf;
        *dataPtr2 = &rbuf->buffer[0];
        *sizePtr2 = numBytes - firstHalf;
    }
    else
    {
        *dataPtr1 = &rbuf->buffer[index];
        *sizePtr1 = numBytes;
        *dataPtr2 = NULL;
        *sizePtr2 = 0;
    }
    return numBytes;
}
Ejemplo n.º 4
0
/*
 * this is the BlioCallback function. It expects to recieve a PaMacBlio Object
 * pointer as userData.
 *
 */
int BlioCallback( const void *input, void *output, unsigned long frameCount,
	const PaStreamCallbackTimeInfo* timeInfo,
        PaStreamCallbackFlags statusFlags,
        void *userData )
{
   PaMacBlio *blio = (PaMacBlio*)userData;
   long avail;
   long toRead;
   long toWrite;

   /* set flags returned by OS: */
   OSAtomicOr32( statusFlags, &blio->statusFlags ) ;

   /* --- Handle Input Buffer --- */
   if( blio->inChan ) {
      avail = RingBuffer_GetWriteAvailable( &blio->inputRingBuffer );

      /* check for underflow */
      if( avail < frameCount * blio->inputSampleSize * blio->inChan )
         OSAtomicOr32( paInputOverflow, &blio->statusFlags );

      toRead = MIN( avail, frameCount * blio->inputSampleSize * blio->inChan );

      /* copy the data */
      /*printf( "reading %d\n", toRead );*/
      assert( toRead == RingBuffer_Write( &blio->inputRingBuffer, input, toRead ) );
#ifdef PA_MAC__BLIO_MUTEX
      /* Priority inversion. See notes below. */
      blioSetIsInputEmpty( blio, false );
#endif
   }


   /* --- Handle Output Buffer --- */
   if( blio->outChan ) {
      avail = RingBuffer_GetReadAvailable( &blio->outputRingBuffer );

      /* check for underflow */
      if( avail < frameCount * blio->outputSampleSize * blio->outChan )
         OSAtomicOr32( paOutputUnderflow, &blio->statusFlags );

      toWrite = MIN( avail, frameCount * blio->outputSampleSize * blio->outChan );

      if( toWrite != frameCount * blio->outputSampleSize * blio->outChan )
         bzero( ((char *)output)+toWrite,
                frameCount * blio->outputSampleSize * blio->outChan - toWrite );
      /* copy the data */
      /*printf( "writing %d\n", toWrite );*/
      assert( toWrite == RingBuffer_Read( &blio->outputRingBuffer, output, toWrite ) );
#ifdef PA_MAC__BLIO_MUTEX
      /* We have a priority inversion here. However, we will only have to
         wait if this was true and is now false, which means we've got
         some room in the buffer.
         Hopefully problems will be minimized. */
      blioSetIsOutputFull( blio, false );
#endif
   }

   return paContinue;
}
Ejemplo n.º 5
0
signed long GetStreamWriteAvailable( PaStream* stream )
{
    PaMacBlio *blio = & ((PaMacCoreStream*)stream) -> blio;
    VVDBUG(("GetStreamWriteAvailable()\n"));

    return RingBuffer_GetWriteAvailable( &blio->outputRingBuffer )
                         / ( blio->outputSampleSize * blio->outChan );
}
Ejemplo n.º 6
0
PaError WriteStream( PaStream* stream,
                            const void *buffer,
                            unsigned long frames )
{
    PaMacBlio *blio = & ((PaMacCoreStream*)stream) -> blio;
    char *cbuf = (char *) buffer;
    PaError ret = paNoError;
    VVDBUG(("WriteStream()\n"));

    while( frames > 0 ) {
       long avail = 0;
       long toWrite;

       do {
          avail = RingBuffer_GetWriteAvailable( &blio->outputRingBuffer );
/*
          printf( "Write Buffer is %%%g full: %ld of %ld.\n",
                  100 - 100 * (float)avail / (float) blio->outputRingBuffer.bufferSize,
                  avail, blio->outputRingBuffer.bufferSize );
*/
          if( avail == 0 ) {
#ifdef PA_MAC_BLIO_MUTEX
             /*block while full*/
             ret = UNIX_ERR( pthread_mutex_lock( &blio->outputMutex ) );
             if( ret )
                return ret;
             while( blio->isOutputFull ) {
                ret = UNIX_ERR( pthread_cond_wait( &blio->outputCond, &blio->outputMutex ) );
                if( ret )
                   return ret;
             }
             ret = UNIX_ERR( pthread_mutex_unlock( &blio->outputMutex ) );
             if( ret )
                return ret;
#else
             Pa_Sleep( PA_MAC_BLIO_BUSY_WAIT_SLEEP_INTERVAL );
#endif
          }
       } while( avail == 0 );

       toWrite = MIN( avail, frames * blio->outputSampleSize * blio->outChan );
       toWrite -= toWrite % blio->outputSampleSize * blio->outChan ;
       RingBuffer_Write( &blio->outputRingBuffer, (void *)cbuf, toWrite );
       cbuf += toWrite;
       frames -= toWrite / ( blio->outputSampleSize * blio->outChan );

#ifdef PA_MAC_BLIO_MUTEX
       if( toWrite == avail ) {
          /* we just filled up the buffer, so we need to mark it as filled. */
          ret = blioSetIsOutputFull( blio, true );
          if( ret )
             return ret;
          /* of course, in the meantime, we may have emptied the buffer, so
             so check for that, too, to avoid a race condition. */
          if( RingBuffer_GetWriteAvailable( &blio->outputRingBuffer ) ) {
             blioSetIsOutputFull( blio, false );
             if( ret )
                return ret;
          }
       }
#endif
    }

    /*   Report either paNoError or paOutputUnderflowed. */
    /*   may also want to report other errors, but this is non-standard. */
    ret = blio->statusFlags & paOutputUnderflow;

    /* report underflow only once: */
    if( ret ) {
      OSAtomicAnd32( ~paOutputUnderflow, &blio->statusFlags );
      ret = paOutputUnderflowed;
    }

    return ret;
}
Ejemplo n.º 7
0
/************************************************************
 * Opens a PortAudio stream with default characteristics.
 * Allocates PABLIO_Stream structure.
 *
 * flags parameter can be an ORed combination of:
 *    PABLIO_READ, PABLIO_WRITE, or PABLIO_READ_WRITE
 */
PaError OpenAudioStream( PABLIO_Stream **rwblPtr, double sampleRate,
                         PaSampleFormat format, int inchannels,
                         int outchannels, int framesperbuf, int nbuffers,
                         int indeviceno, int outdeviceno) /* MSP */
{
    long   bytesPerSample;
    long   doRead = 0;
    long   doWrite = 0;
    PaError err;
    PABLIO_Stream *aStream;
    long   minNumBuffers; 
    long   numFrames;

//#ifdef PA19
//    PaStreamParameters instreamparams, outstreamparams;  /* MSP */
//#endif

    /* fprintf(stderr,
        "open %lf fmt %d flags %d ch: %d fperbuf: %d nbuf: %d devs: %d %d\n",
           sampleRate, format, flags, nchannels,
           framesperbuf, nbuffers, indeviceno, outdeviceno); */

    if (indeviceno < 0)  /* MSP... */
    {

//#ifdef PA19
//        indeviceno = Pa_GetDefaultInputDevice();
//#else
        indeviceno = Pa_GetDefaultInputDeviceID();
//#endif
        fprintf(stderr, "using default input device number: %d\n", indeviceno);
    }
    if (outdeviceno < 0)
    {

//#ifdef PA19
//        outdeviceno = Pa_GetDefaultOutputDevice();
//#else
        outdeviceno = Pa_GetDefaultOutputDeviceID();
//#endif
        fprintf(stderr, "using default output device number: %d\n", outdeviceno);
    }
    /* fprintf(stderr, "nchan %d, flags %d, bufs %d, framesperbuf %d\n",
            nchannels, flags, nbuffers, framesperbuf); */
        /* ...MSP */

    /* Allocate PABLIO_Stream structure for caller. */
    aStream = (PABLIO_Stream *) malloc( sizeof(PABLIO_Stream) );
    if( aStream == NULL ) return paInsufficientMemory;
    memset( aStream, 0, sizeof(PABLIO_Stream) );

    /* Determine size of a sample. */
    bytesPerSample = Pa_GetSampleSize( format );
    if( bytesPerSample < 0 )
    {
        fprintf(stderr, "error bytes per sample: %i\n", bytesPerSample);	
		err = (PaError) bytesPerSample;
        goto error;
    }
    aStream->insamplesPerFrame = inchannels;  /* MSP */
    aStream->inbytesPerFrame = bytesPerSample * aStream->insamplesPerFrame;
    aStream->outsamplesPerFrame = outchannels;
    aStream->outbytesPerFrame = bytesPerSample * aStream->outsamplesPerFrame;

    /* Initialize PortAudio  */
    err = Pa_Initialize();
    if( err != paNoError ) goto error;


//#ifdef PA19
//    numFrames = nbuffers * framesperbuf; /* ...MSP */

//    instreamparams.device = indeviceno;   /* MSP... */
//    instreamparams.channelCount = inchannels;
//    instreamparams.sampleFormat = format;
//    instreamparams.suggestedLatency = nbuffers*framesperbuf/sampleRate;
//    instreamparams.hostApiSpecificStreamInfo = 0;
    
//    outstreamparams.device = outdeviceno;
//    outstreamparams.channelCount = outchannels;
//    outstreamparams.sampleFormat = format;
//    outstreamparams.suggestedLatency = nbuffers*framesperbuf/sampleRate;
//   outstreamparams.hostApiSpecificStreamInfo = 0;  /* ... MSP */

//#else
/* Warning: numFrames must be larger than amount of data processed per
  interrupt inside PA to prevent glitches. */  /* MSP */
    minNumBuffers = Pa_GetMinNumBuffers(framesperbuf, sampleRate);
    if (minNumBuffers > nbuffers)
        fprintf(stderr, "warning: number of buffers %d less than recommended minimum %d\n",  (int)nbuffers, (int)minNumBuffers);
//#endif

    numFrames = nbuffers * framesperbuf;
    /* fprintf(stderr, "numFrames %d\n", numFrames); */
    /* Initialize Ring Buffers */
    doRead = (inchannels != 0);
    doWrite = (outchannels != 0);
    if(doRead)
    {
        err = PABLIO_InitFIFO( &aStream->inFIFO, numFrames, aStream->inbytesPerFrame );
        if( err != paNoError )
		{
			fprintf(stderr, "error doRead PABLIO_InitFIFO \n");
			goto error;
		}
    }
    if(doWrite)
    {
        long numBytes;
        err = PABLIO_InitFIFO( &aStream->outFIFO, numFrames, aStream->outbytesPerFrame );
        if( err != paNoError ) {
			fprintf(stderr, "error doWrite PABLIO_InitFIFO \n");
			goto error;
			}
        /* Make Write FIFO appear full initially. */
        numBytes = RingBuffer_GetWriteAvailable( &aStream->outFIFO );
        RingBuffer_AdvanceWriteIndex( &aStream->outFIFO, numBytes );
    }

    /* Open a PortAudio stream that we will use to communicate with the underlying
     * audio drivers. */

//#ifdef PA19
 //   err = Pa_OpenStream(
//              &aStream->stream,
//              (doRead ? &instreamparams : 0),  /* MSP */
//              (doWrite ? &outstreamparams : 0),  /* MSP */
//             sampleRate,
 //             framesperbuf,  /* MSP */
 //             paNoFlag,      /* MSP -- portaudio will clip for us */
 //             blockingIOCallback,
//              aStream );
//#else
 //   err = Pa_OpenStream(
 //             &aStream->stream,
//              (doRead ? indeviceno : paNoDevice),  /* MSP */
//              (doRead ? aStream->insamplesPerFrame : 0 ),
//              format,
//              NULL,
//              (doWrite ? outdeviceno : paNoDevice),  /* MSP */
//              (doWrite ? aStream->outsamplesPerFrame : 0 ),
//              format,
//              NULL,
//              sampleRate,
//              framesperbuf,  /* MSP */
//              nbuffers,      /* MSP */
//              paNoFlag,      /* MSP -- portaudio will clip for us */
//              blockingIOCallback,
//              aStream );
// #endif
PortAudioStream   *stream;
err = Pa_OpenDefaultStream( 
	stream, 
	0,
	2, 
	paFloat32, 
	44100,  
	256, 
	0,  
	blockingIOCallback, 
	stream );


    if( err != paNoError ){
		fprintf(stderr, "error Pa_OpenStream \n");
		goto error;
	}
	
    err = Pa_StartStream( aStream->stream );
    if( err != paNoError )      /* MSP */
    {
        fprintf(stderr, "Pa_StartStream failed; closing audio stream...\n");
        CloseAudioStream( aStream );
        goto error;
    }

    *rwblPtr = aStream;
    return paNoError;

error:
    *rwblPtr = NULL;
    return err;
}
Ejemplo n.º 8
0
/************************************************************
 * Return the number of frames that could be written to the stream without
 * having to wait.
 */
long GetAudioStreamWriteable( PABLIO_Stream *aStream )
{
    int bytesEmpty = RingBuffer_GetWriteAvailable( &aStream->outFIFO );
    return bytesEmpty / aStream->outbytesPerFrame;
}