mirror of
https://github.com/thestk/stk
synced 2026-01-14 05:21:53 +00:00
Version 4.3.0
This commit is contained in:
committed by
Stephen Sinclair
parent
2cbce2d8bd
commit
27d9b79dc7
125
src/RtWvIn.cpp
125
src/RtWvIn.cpp
@@ -3,62 +3,98 @@
|
||||
\brief STK realtime audio (blocking) input class.
|
||||
|
||||
This class provides a simplified interface to RtAudio for realtime
|
||||
audio input. It is a protected subclass of WvIn. Because this
|
||||
class makes use of RtAudio's blocking output routines, its
|
||||
performance is less robust on systems where the audio API is
|
||||
callback-based (Macintosh CoreAudio and Windows ASIO).
|
||||
audio input. It is a subclass of WvIn. This class makes use of
|
||||
RtAudio's callback functionality by creating a large ring-buffer
|
||||
from which data is read. This class should not be used when
|
||||
low-latency is desired.
|
||||
|
||||
RtWvIn supports multi-channel data in interleaved format. It is
|
||||
important to distinguish the tick() methods, which return samples
|
||||
produced by averaging across sample frames, from the tickFrame()
|
||||
methods, which return references or pointers to multi-channel
|
||||
sample frames.
|
||||
RtWvIn supports multi-channel data in both interleaved and
|
||||
non-interleaved formats. It is important to distinguish the
|
||||
tick() methods, which return samples produced by averaging across
|
||||
sample frames, from the tickFrame() methods, which return
|
||||
references or pointers to multi-channel sample frames.
|
||||
|
||||
by Perry R. Cook and Gary P. Scavone, 1995 - 2005.
|
||||
by Perry R. Cook and Gary P. Scavone, 1995 - 2007.
|
||||
*/
|
||||
/***************************************************/
|
||||
|
||||
#include "RtWvIn.h"
|
||||
|
||||
RtWvIn :: RtWvIn( unsigned int nChannels, StkFloat sampleRate, int device, int bufferFrames, int nBuffers )
|
||||
: stopped_( true ), bufferIndex_( 0 )
|
||||
// This function is automatically called by RtAudio to supply input audio data.
|
||||
int read( void *outputBuffer, void *inputBuffer, unsigned int nBufferFrames,
|
||||
double streamTime, RtAudioStreamStatus status, void *dataPointer )
|
||||
{
|
||||
int size = bufferFrames;
|
||||
( (RtWvIn *) dataPointer )->fillBuffer( inputBuffer, nBufferFrames );
|
||||
return 0;
|
||||
}
|
||||
|
||||
// This function does not block. If the user does not read the buffer
|
||||
// data fast enough, unread data will be overwritten (data overrun).
|
||||
void RtWvIn :: fillBuffer( void *buffer, unsigned int nFrames )
|
||||
{
|
||||
StkFloat *samples = (StkFloat *) buffer;
|
||||
unsigned int counter, iStart, nSamples = nFrames * data_.channels();
|
||||
|
||||
while ( nSamples > 0 ) {
|
||||
|
||||
// I'm assuming that both the RtAudio and StkFrames buffers
|
||||
// contain interleaved data.
|
||||
iStart = writeIndex_ * data_.channels();
|
||||
counter = nSamples;
|
||||
|
||||
// Pre-increment write pointer and check bounds.
|
||||
writeIndex_ += nSamples / data_.channels();
|
||||
if ( writeIndex_ >= data_.frames() ) {
|
||||
writeIndex_ = 0;
|
||||
counter = data_.size() - iStart;
|
||||
}
|
||||
|
||||
// Copy data to the StkFrames container.
|
||||
for ( unsigned int i=0; i<counter; i++ )
|
||||
data_[iStart++] = *samples++;
|
||||
|
||||
nSamples -= counter;
|
||||
}
|
||||
|
||||
framesFilled_ += nFrames;
|
||||
if ( framesFilled_ > data_.frames() ) {
|
||||
framesFilled_ = data_.frames();
|
||||
errorString_ << "RtWvIn: audio buffer overrun!";
|
||||
handleError( StkError::WARNING );
|
||||
}
|
||||
}
|
||||
|
||||
RtWvIn :: RtWvIn( unsigned int nChannels, StkFloat sampleRate, int device, int bufferFrames, int nBuffers )
|
||||
: stopped_( true ), readIndex_( 0 ), writeIndex_( 0 ), framesFilled_( 0 )
|
||||
{
|
||||
// We'll let RtAudio deal with channel and sample rate limitations.
|
||||
RtAudio::StreamParameters parameters;
|
||||
parameters.deviceId = device;
|
||||
parameters.nChannels = nChannels;
|
||||
unsigned int size = bufferFrames;
|
||||
RtAudioFormat format = ( sizeof(StkFloat) == 8 ) ? RTAUDIO_FLOAT64 : RTAUDIO_FLOAT32;
|
||||
|
||||
adc_ = 0;
|
||||
try {
|
||||
adc_ = new RtAudio();
|
||||
adc_.openStream( NULL, ¶meters, format, (unsigned int)Stk::sampleRate(), &size, &read, (void *)this );
|
||||
}
|
||||
catch (RtError &error) {
|
||||
handleError( error.getMessageString(), StkError::AUDIO_SYSTEM );
|
||||
catch ( RtError &error ) {
|
||||
handleError( error.what(), StkError::AUDIO_SYSTEM );
|
||||
}
|
||||
|
||||
// Allocate the adc and get the buffer pointer.
|
||||
try {
|
||||
adc_->openStream( 0, 0, device, (int)nChannels, format,
|
||||
(int)sampleRate, &size, nBuffers );
|
||||
buffer_ = (StkFloat *) adc_->getStreamBuffer();
|
||||
}
|
||||
catch (RtError &error) {
|
||||
handleError( error.getMessageString(), StkError::AUDIO_SYSTEM );
|
||||
}
|
||||
|
||||
bufferFrames_ = size;
|
||||
data_.resize( size * nBuffers, nChannels );
|
||||
lastOutputs_.resize( 1, nChannels );
|
||||
}
|
||||
|
||||
RtWvIn :: ~RtWvIn()
|
||||
{
|
||||
if ( !stopped_ ) adc_->stopStream();
|
||||
adc_->closeStream();
|
||||
delete adc_;
|
||||
if ( !stopped_ ) adc_.stopStream();
|
||||
adc_.closeStream();
|
||||
}
|
||||
|
||||
void RtWvIn :: start()
|
||||
{
|
||||
if ( stopped_ ) {
|
||||
adc_->startStream();
|
||||
adc_.startStream();
|
||||
stopped_ = false;
|
||||
}
|
||||
}
|
||||
@@ -66,7 +102,7 @@ void RtWvIn :: start()
|
||||
void RtWvIn :: stop()
|
||||
{
|
||||
if ( !stopped_ ) {
|
||||
adc_->stopStream();
|
||||
adc_.stopStream();
|
||||
stopped_ = true;
|
||||
}
|
||||
}
|
||||
@@ -75,20 +111,15 @@ void RtWvIn :: computeFrame( void )
|
||||
{
|
||||
if ( stopped_ ) this->start();
|
||||
|
||||
if ( bufferIndex_ == 0) {
|
||||
try {
|
||||
adc_->tickStream();
|
||||
}
|
||||
catch (RtError &error) {
|
||||
handleError( error.getMessageString(), StkError::AUDIO_SYSTEM );
|
||||
}
|
||||
}
|
||||
// Block until at least one frame is available.
|
||||
while ( framesFilled_ == 0 )
|
||||
Stk::sleep( 1 );
|
||||
|
||||
long iBuffer = bufferIndex_ * lastOutputs_.size();
|
||||
for (unsigned int i=0; i<lastOutputs_.size(); i++)
|
||||
lastOutputs_[i] = buffer_[iBuffer++];
|
||||
for ( unsigned int i=0; i<lastOutputs_.size(); i++ )
|
||||
lastOutputs_[i] = data_( readIndex_, i );
|
||||
|
||||
bufferIndex_++;
|
||||
if ( bufferIndex_ >= bufferFrames_ )
|
||||
bufferIndex_ = 0;
|
||||
framesFilled_--;
|
||||
readIndex_++;
|
||||
if ( readIndex_ >= data_.frames() )
|
||||
readIndex_ = 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user