Closed ghost closed 6 years ago
In the latest commit of my copy, I was able to add this feature. You'll notice that all the tests are only slightly different. I used a class called CStyleProcessor
that is used for compatibility, to minimize the amount of changes I had to make to the tests. They now all have a snippet of code sort of like this:
RtAudio::CStyleProcessor processor;
processor.setUserData( &mydata );
processor.setCallback( inout );
adc.setProcessor( processor );
I'm not planning on submitting a PR from my copy. There are too many breaking changes. But you could check it out as a proof-of-concept for the issue. Just note that in the commit I referenced, I haven't updated any of the Windows or Apple APIs.
I think the more interesting approach in the future (we'll probably open an "experimental" branch after the next release..) is to add a templated interface that can call anything that responds to the operator(), which would include functor classes (like your idea), lambdas, and regular callbacks.
@radarsat1 How exactly would you use the template class?
Do you mean using it like this?
template <typename Callable>
int callback(Callable c) {
c(inputBuffer, outputBuffer, frames, /* etc */ );
}
If that's what you mean, you could derive a Processor
class that uses templates.
Like this:
template <typename Callable>
class CallableProcessor final : public RtAudio::Processor {
Callable c;
public:
CallableProcessor(void) { }
CallablePocessor(const Callable &other) : c(other) { }
int process() {
c(getInputBuffer(),
getOutputBuffer(),
getFrames(),
/* etc */ );
}
};
And the reason you'd make it a derived class is to keep the implementation of all the APIs in the source file and not the header file.
If you want a lamda to be the callback, you could declare a function like this:
class RtAudio {
template <typename Callable>
void setProcessor(Callable c) {
CallableProcessor processor(c);
setProcessor(processor);
};
};
Example usage:
RtAudio dac;
dac.setProcessor([](void *inputBuffer, void *outputBuffer, /* etc */ ) {
memcpy(inputBuffer, outputBuffer, frames * sampleSize());
});
I successfully added a LadspaProcessor
class and others like the CompositeProcessor
class. This functionality allows the RtAudio library to combine LADSPA effects in a effects chain with relative ease.
I added a test program that is much like the duplex
program, except you choose a LADSPA effect and it's parameters and hear the audio in real-time.
I think it's a pretty cool feature that I think could be useful in the main library. I'll be in contact if you have anymore questions.
@radarsat1 closing this. I implemented this in GNU Guitar Core, which is based off of RtAudio. It's a pretty fun approach because the composite processor basically allows for the creation of a tree-like structure of audio effects. Thanks for the feedback!
In the call to
openStream
, a C-style callback function is used.While this is sufficient, I think there's a more scalable C++ solution.
How about using a base class kind of like this:
It may be set in the
RtAudio
class like:Client code can define base classes like this:
And use them like this:
A couple of built-in processors may be defined in later versions:
For backwards compatibility, you another one of these "built-in" processors may just contain a pointer and function, mimicking the old behavior.
Two
openStream
signatures will be defined. One will be identical to the existing one now, and it will create thisCallbackProcessor
using theRtAudioCallback
function and user data, and then call asetProcessor
function using theCallbackProcessor
. The secondopenStream
signature will not modify theRtAudioProcessor
member at all.