Portaudio backend seems to be working. No extensive checks performed yet.
This commit is contained in:
parent
77b1848bb4
commit
64a268e277
@ -337,9 +337,9 @@ public:
|
|||||||
const auto &dtype_descr = dtypeDescr();
|
const auto &dtype_descr = dtypeDescr();
|
||||||
const auto dtype = dataType();
|
const auto dtype = dataType();
|
||||||
|
|
||||||
us neninchannels = this->neninchannels();
|
const us neninchannels = this->neninchannels();
|
||||||
us nenoutchannels = this->nenoutchannels();
|
const us nenoutchannels = this->nenoutchannels();
|
||||||
us sw = dtype_descr.sw;
|
const us sw = dtype_descr.sw;
|
||||||
if (nFrames != nFramesPerBlock) {
|
if (nFrames != nFramesPerBlock) {
|
||||||
cerr << "RtAudio backend error: nFrames does not match block size!"
|
cerr << "RtAudio backend error: nFrames does not match block size!"
|
||||||
<< endl;
|
<< endl;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
#define DEBUGTRACE_ENABLED
|
/* #define DEBUGTRACE_ENABLED */
|
||||||
#include "debugtrace.hpp"
|
#include "debugtrace.hpp"
|
||||||
#include "lasp_config.h"
|
#include "lasp_config.h"
|
||||||
|
|
||||||
@ -123,6 +123,10 @@ static int rawPaCallback(const void *inputBuffer, void *outputBuffer,
|
|||||||
class PortAudioDaq : public Daq {
|
class PortAudioDaq : public Daq {
|
||||||
bool _shouldPaTerminate = false;
|
bool _shouldPaTerminate = false;
|
||||||
PaStream *_stream = nullptr;
|
PaStream *_stream = nullptr;
|
||||||
|
std::atomic<StreamStatus::StreamError> _streamError =
|
||||||
|
StreamStatus::StreamError::noError;
|
||||||
|
InDaqCallback _incallback;
|
||||||
|
OutDaqCallback _outcallback;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
PortAudioDaq(const OurPaDeviceInfo &devinfo_gen,
|
PortAudioDaq(const OurPaDeviceInfo &devinfo_gen,
|
||||||
@ -211,11 +215,12 @@ PortAudioDaq::PortAudioDaq(const OurPaDeviceInfo &devinfo_gen,
|
|||||||
|
|
||||||
using Dtype = DataTypeDescriptor::DataType;
|
using Dtype = DataTypeDescriptor::DataType;
|
||||||
const Dtype dtype = dataType();
|
const Dtype dtype = dataType();
|
||||||
PaSampleFormat format;
|
// Sample format is bit flag
|
||||||
|
PaSampleFormat format = paNonInterleaved;
|
||||||
switch (dtype) {
|
switch (dtype) {
|
||||||
case Dtype::dtype_fl32:
|
case Dtype::dtype_fl32:
|
||||||
DEBUGTRACE_PRINT("Datatype float32");
|
DEBUGTRACE_PRINT("Datatype float32");
|
||||||
format = paFloat32;
|
format |= paFloat32;
|
||||||
break;
|
break;
|
||||||
case Dtype::dtype_fl64:
|
case Dtype::dtype_fl64:
|
||||||
DEBUGTRACE_PRINT("Datatype float64");
|
DEBUGTRACE_PRINT("Datatype float64");
|
||||||
@ -223,15 +228,15 @@ PortAudioDaq::PortAudioDaq(const OurPaDeviceInfo &devinfo_gen,
|
|||||||
break;
|
break;
|
||||||
case Dtype::dtype_int8:
|
case Dtype::dtype_int8:
|
||||||
DEBUGTRACE_PRINT("Datatype int8");
|
DEBUGTRACE_PRINT("Datatype int8");
|
||||||
format = paInt8;
|
format |= paInt8;
|
||||||
break;
|
break;
|
||||||
case Dtype::dtype_int16:
|
case Dtype::dtype_int16:
|
||||||
DEBUGTRACE_PRINT("Datatype int16");
|
DEBUGTRACE_PRINT("Datatype int16");
|
||||||
format = paInt16;
|
format |= paInt16;
|
||||||
break;
|
break;
|
||||||
case Dtype::dtype_int32:
|
case Dtype::dtype_int32:
|
||||||
DEBUGTRACE_PRINT("Datatype int32");
|
DEBUGTRACE_PRINT("Datatype int32");
|
||||||
format = paInt32;
|
format |= paInt32;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw rte("Invalid data type specified for DAQ stream.");
|
throw rte("Invalid data type specified for DAQ stream.");
|
||||||
@ -250,7 +255,7 @@ PortAudioDaq::PortAudioDaq(const OurPaDeviceInfo &devinfo_gen,
|
|||||||
.hostApiSpecificStreamInfo = nullptr}));
|
.hostApiSpecificStreamInfo = nullptr}));
|
||||||
}
|
}
|
||||||
if (nenoutchannels() > 0) {
|
if (nenoutchannels() > 0) {
|
||||||
instreamParams = std::make_unique<PaStreamParameters>(
|
outstreamParams = std::make_unique<PaStreamParameters>(
|
||||||
PaStreamParameters({.device = devindex,
|
PaStreamParameters({.device = devindex,
|
||||||
.channelCount = (int)nenoutchannels(),
|
.channelCount = (int)nenoutchannels(),
|
||||||
.sampleFormat = format,
|
.sampleFormat = format,
|
||||||
@ -279,6 +284,30 @@ void PortAudioDaq::start(InDaqCallback inCallback, OutDaqCallback outCallback) {
|
|||||||
if (Pa_IsStreamActive(_stream)) {
|
if (Pa_IsStreamActive(_stream)) {
|
||||||
throw rte("Stream is already running");
|
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);
|
PaError err = Pa_StartStream(_stream);
|
||||||
throwIfError(err);
|
throwIfError(err);
|
||||||
}
|
}
|
||||||
@ -293,6 +322,9 @@ void PortAudioDaq::stop() {
|
|||||||
}
|
}
|
||||||
Daq::StreamStatus PortAudioDaq::getStreamStatus() const {
|
Daq::StreamStatus PortAudioDaq::getStreamStatus() const {
|
||||||
Daq::StreamStatus status;
|
Daq::StreamStatus status;
|
||||||
|
// Copy over atomic flag.
|
||||||
|
status.errorType = _streamError;
|
||||||
|
// Check if stream is still running.
|
||||||
if (_stream) {
|
if (_stream) {
|
||||||
if (Pa_IsStreamActive(_stream)) {
|
if (Pa_IsStreamActive(_stream)) {
|
||||||
status.isRunning = true;
|
status.isRunning = true;
|
||||||
@ -329,6 +361,84 @@ int PortAudioDaq::memberPaCallback(const void *inputBuffer, void *outputBuffer,
|
|||||||
PaStreamCallbackFlags statusFlags) {
|
PaStreamCallbackFlags statusFlags) {
|
||||||
|
|
||||||
DEBUGTRACE_ENTER;
|
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;
|
return paContinue;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user