Portaudio backend seems to be working. No extensive checks performed yet.

This commit is contained in:
Anne de Jong 2023-06-15 09:48:45 +02:00
parent 77b1848bb4
commit 64a268e277
2 changed files with 120 additions and 10 deletions

View File

@ -337,9 +337,9 @@ public:
const auto &dtype_descr = dtypeDescr();
const auto dtype = dataType();
us neninchannels = this->neninchannels();
us nenoutchannels = this->nenoutchannels();
us sw = dtype_descr.sw;
const us neninchannels = this->neninchannels();
const us nenoutchannels = this->nenoutchannels();
const us sw = dtype_descr.sw;
if (nFrames != nFramesPerBlock) {
cerr << "RtAudio backend error: nFrames does not match block size!"
<< endl;

View File

@ -1,4 +1,4 @@
#define DEBUGTRACE_ENABLED
/* #define DEBUGTRACE_ENABLED */
#include "debugtrace.hpp"
#include "lasp_config.h"
@ -123,6 +123,10 @@ static int rawPaCallback(const void *inputBuffer, void *outputBuffer,
class PortAudioDaq : public Daq {
bool _shouldPaTerminate = false;
PaStream *_stream = nullptr;
std::atomic<StreamStatus::StreamError> _streamError =
StreamStatus::StreamError::noError;
InDaqCallback _incallback;
OutDaqCallback _outcallback;
public:
PortAudioDaq(const OurPaDeviceInfo &devinfo_gen,
@ -211,11 +215,12 @@ PortAudioDaq::PortAudioDaq(const OurPaDeviceInfo &devinfo_gen,
using Dtype = DataTypeDescriptor::DataType;
const Dtype dtype = dataType();
PaSampleFormat format;
// Sample format is bit flag
PaSampleFormat format = paNonInterleaved;
switch (dtype) {
case Dtype::dtype_fl32:
DEBUGTRACE_PRINT("Datatype float32");
format = paFloat32;
format |= paFloat32;
break;
case Dtype::dtype_fl64:
DEBUGTRACE_PRINT("Datatype float64");
@ -223,15 +228,15 @@ PortAudioDaq::PortAudioDaq(const OurPaDeviceInfo &devinfo_gen,
break;
case Dtype::dtype_int8:
DEBUGTRACE_PRINT("Datatype int8");
format = paInt8;
format |= paInt8;
break;
case Dtype::dtype_int16:
DEBUGTRACE_PRINT("Datatype int16");
format = paInt16;
format |= paInt16;
break;
case Dtype::dtype_int32:
DEBUGTRACE_PRINT("Datatype int32");
format = paInt32;
format |= paInt32;
break;
default:
throw rte("Invalid data type specified for DAQ stream.");
@ -250,7 +255,7 @@ PortAudioDaq::PortAudioDaq(const OurPaDeviceInfo &devinfo_gen,
.hostApiSpecificStreamInfo = nullptr}));
}
if (nenoutchannels() > 0) {
instreamParams = std::make_unique<PaStreamParameters>(
outstreamParams = std::make_unique<PaStreamParameters>(
PaStreamParameters({.device = devindex,
.channelCount = (int)nenoutchannels(),
.sampleFormat = format,
@ -279,6 +284,30 @@ void PortAudioDaq::start(InDaqCallback inCallback, OutDaqCallback outCallback) {
if (Pa_IsStreamActive(_stream)) {
throw rte("Stream is already running");
}
// Logical XOR
if (inCallback && outCallback) {
throw rte("Either input or output stream possible for RtAudio. "
"Stream duplex mode not provided.");
}
if (neninchannels() > 0) {
if (!inCallback) {
throw rte(
"Input callback given, but stream does not provide input data");
}
_incallback = inCallback;
}
if (nenoutchannels() > 0) {
if (!outCallback) {
throw rte(
"Output callback given, but stream does not provide output data");
}
_outcallback = outCallback;
}
PaError err = Pa_StartStream(_stream);
throwIfError(err);
}
@ -293,6 +322,9 @@ void PortAudioDaq::stop() {
}
Daq::StreamStatus PortAudioDaq::getStreamStatus() const {
Daq::StreamStatus status;
// Copy over atomic flag.
status.errorType = _streamError;
// Check if stream is still running.
if (_stream) {
if (Pa_IsStreamActive(_stream)) {
status.isRunning = true;
@ -329,6 +361,84 @@ int PortAudioDaq::memberPaCallback(const void *inputBuffer, void *outputBuffer,
PaStreamCallbackFlags statusFlags) {
DEBUGTRACE_ENTER;
typedef Daq::StreamStatus::StreamError se;
if (statusFlags & paPrimingOutput) {
// Initial output buffers generated. So nothing with input yet
return paContinue;
}
if ((statusFlags & paInputUnderflow) || (statusFlags & paInputOverflow)) {
_streamError = se::inputXRun;
return paAbort;
}
if ((statusFlags & paOutputUnderflow) || (statusFlags & paOutputOverflow)) {
_streamError = se::outputXRun;
return paAbort;
}
if (framesPerBuffer != framesPerBlock()) {
cerr << "Logic error: expected a block size of: " << framesPerBlock()
<< endl;
_streamError = se::logicError;
return paAbort;
}
const us neninchannels = this->neninchannels();
const us nenoutchannels = this->nenoutchannels();
const auto &dtype_descr = dtypeDescr();
const auto dtype = dataType();
const us sw = dtype_descr.sw;
if (inputBuffer) {
assert(_incallback);
std::vector<byte_t *> ptrs;
ptrs.reserve(neninchannels);
const us ch_min = getLowestEnabledInChannel();
const us ch_max = getHighestEnabledInChannel();
assert(ch_min < ninchannels);
assert(ch_max < ninchannels);
/// Only pass on the pointers of the channels we want. inputBuffer is
/// noninterleaved, as specified in PortAudioDaq constructor.
for (us ch = ch_min; ch <= ch_max; ch++) {
if (inchannel_config.at(ch).enabled) {
byte_t *ch_ptr =
reinterpret_cast<byte_t **>(const_cast<void *>(inputBuffer))[ch];
ptrs.push_back(ch_ptr);
}
}
DaqData d{framesPerBuffer, neninchannels, dtype};
d.copyInFromRaw(ptrs);
_incallback(d);
}
if (outputBuffer) {
assert(_outcallback);
std::vector<byte_t *> ptrs;
ptrs.reserve(nenoutchannels);
/* outCallback */
const us ch_min = getLowestEnabledOutChannel();
const us ch_max = getHighestEnabledOutChannel();
assert(ch_min < noutchannels);
assert(ch_max < noutchannels);
/// Only pass on the pointers of the channels we want
for (us ch = ch_min; ch <= ch_max; ch++) {
if (outchannel_config.at(ch).enabled) {
byte_t *ch_ptr = reinterpret_cast<byte_t **>(outputBuffer)[ch];
ptrs.push_back(ch_ptr);
}
}
DaqData d{framesPerBuffer, nenoutchannels, dtype};
_outcallback(d);
// Copy over the buffer
us j = 0;
for (auto ptr : ptrs) {
d.copyToRaw(j, ptr);
j++;
}
}
return paContinue;
}