commit 29e9fe9a9f449a92a5426066d8ac00a698050ee7
parent e2e2b5507f683a6b62adbd984b62cdde0ed05c3d
Author: falkTX <falktx@falktx.com>
Date: Mon, 11 Jul 2022 17:55:13 +0100
Allow runtime buffer size changes in wasm/bridge modules
Signed-off-by: falkTX <falktx@falktx.com>
Diffstat:
4 files changed, 162 insertions(+), 13 deletions(-)
diff --git a/distrho/DistrhoStandaloneUtils.hpp b/distrho/DistrhoStandaloneUtils.hpp
@@ -36,6 +36,11 @@ START_NAMESPACE_DISTRHO
bool supportsAudioInput();
/**
+ Check if the current standalone supports dynamic buffer size changes.
+*/
+bool supportsBufferSizeChanges();
+
+/**
Check if the current standalone supports MIDI.
*/
bool supportsMIDI();
@@ -51,12 +56,22 @@ bool isAudioInputEnabled();
bool isMIDIEnabled();
/**
+ Get the current buffer size.
+*/
+uint32_t getBufferSize();
+
+/**
Request permissions to use audio input.
Only valid to call if audio input is supported but not currently enabled.
*/
bool requestAudioInput();
/**
+ Request change to a new buffer size.
+*/
+bool requestBufferSizeChange(uint32_t newBufferSize);
+
+/**
Request permissions to use MIDI.
Only valid to call if MIDI is supported but not currently enabled.
*/
diff --git a/distrho/src/jackbridge/JackBridge.cpp b/distrho/src/jackbridge/JackBridge.cpp
@@ -1185,7 +1185,13 @@ bool jackbridge_set_buffer_size_callback(jack_client_t* client, JackBufferSizeCa
#elif defined(JACKBRIDGE_DIRECT)
return (jack_set_buffer_size_callback(client, bufsize_callback, arg) == 0);
#else
- if (usingRealJACK && getBridgeInstance().set_buffer_size_callback_ptr != nullptr)
+ if (usingNativeBridge)
+ {
+ nativeBridge->bufferSizeCallback = bufsize_callback;
+ nativeBridge->jackBufferSizeArg = arg;
+ return true;
+ }
+ if (getBridgeInstance().set_buffer_size_callback_ptr != nullptr)
{
# ifdef __WINE__
WineBridge::getInstance().set_bufsize(bufsize_callback);
@@ -1371,9 +1377,10 @@ bool jackbridge_set_buffer_size(jack_client_t* client, jack_nframes_t nframes)
#elif defined(JACKBRIDGE_DIRECT)
return jack_set_buffer_size(client, nframes);
#else
- if (usingRealJACK)
- if (getBridgeInstance().set_buffer_size_ptr != nullptr)
- return getBridgeInstance().set_buffer_size_ptr(client, nframes);
+ if (usingNativeBridge)
+ return nativeBridge->requestBufferSizeChange(nframes);
+ if (getBridgeInstance().set_buffer_size_ptr != nullptr)
+ return getBridgeInstance().set_buffer_size_ptr(client, nframes);
#endif
return false;
}
@@ -2257,6 +2264,15 @@ bool supportsAudioInput()
return true;
}
+bool supportsBufferSizeChanges()
+{
+#if !(defined(JACKBRIDGE_DUMMY) || defined(JACKBRIDGE_DIRECT))
+ if (usingNativeBridge)
+ return nativeBridge->supportsBufferSizeChanges();
+#endif
+ return false;
+}
+
bool supportsMIDI()
{
#if defined(JACKBRIDGE_DUMMY)
@@ -2290,6 +2306,15 @@ bool isMIDIEnabled()
return true;
}
+uint32_t getBufferSize()
+{
+#if !(defined(JACKBRIDGE_DUMMY) || defined(JACKBRIDGE_DIRECT))
+ if (usingNativeBridge)
+ return nativeBridge->getBufferSize();
+#endif
+ return 0;
+}
+
bool requestAudioInput()
{
#if !(defined(JACKBRIDGE_DUMMY) || defined(JACKBRIDGE_DIRECT))
@@ -2299,6 +2324,15 @@ bool requestAudioInput()
return false;
}
+bool requestBufferSizeChange(const uint32_t newBufferSize)
+{
+#if !(defined(JACKBRIDGE_DUMMY) || defined(JACKBRIDGE_DIRECT))
+ if (usingNativeBridge)
+ return nativeBridge->requestBufferSizeChange(newBufferSize);
+#endif
+ return false;
+}
+
bool requestMIDI()
{
#if !(defined(JACKBRIDGE_DUMMY) || defined(JACKBRIDGE_DIRECT))
diff --git a/distrho/src/jackbridge/NativeBridge.hpp b/distrho/src/jackbridge/NativeBridge.hpp
@@ -36,7 +36,9 @@ struct NativeBridge {
// JACK callbacks
JackProcessCallback jackProcessCallback = nullptr;
+ JackBufferSizeCallback bufferSizeCallback = nullptr;
void* jackProcessArg = nullptr;
+ void* jackBufferSizeArg = nullptr;
// Runtime buffers
enum PortMask {
@@ -85,11 +87,18 @@ struct NativeBridge {
#endif
}
+ virtual bool supportsBufferSizeChanges() const { return false; }
virtual bool supportsMIDI() const { return false; }
virtual bool isMIDIEnabled() const { return false; }
virtual bool requestAudioInput() { return false; }
+ virtual bool requestBufferSizeChange(uint32_t) { return false; }
virtual bool requestMIDI() { return false; }
+ uint32_t getBufferSize() const noexcept
+ {
+ return bufferSize;
+ }
+
uint32_t getEventCount()
{
#if DISTRHO_PLUGIN_WANT_MIDI_INPUT
diff --git a/distrho/src/jackbridge/WebBridge.hpp b/distrho/src/jackbridge/WebBridge.hpp
@@ -114,7 +114,7 @@ struct WebBridge : NativeBridge {
return false;
}
- bufferSize = 512;
+ bufferSize = 2048;
sampleRate = EM_ASM_INT_V({
var WAB = Module['WebAudioBridge'];
return WAB.audioContext.sampleRate;
@@ -212,15 +212,24 @@ struct WebBridge : NativeBridge {
// we need to use this weird awkward way for objects, otherwise build fails
constraints['audio'] = true;
constraints['video'] = false;
- constraints['latency'] = 0;
- constraints['sampleSize'] = 24;
- constraints['mandatory'] = {};
- constraints['mandatory']['autoGainControl'] = false;
- constraints['mandatory']['echoCancellation'] = false;
- constraints['mandatory']['noiseSuppression'] = false;
- constraints['mandatory']['channelCount'] = numInputs;
+ constraints['autoGainControl'] = {};
+ constraints['autoGainControl']['exact'] = false;
+ constraints['echoCancellation'] = {};
+ constraints['echoCancellation']['exact'] = false;
+ constraints['noiseSuppression'] = {};
+ constraints['noiseSuppression']['exact'] = false;
+ constraints['channelCount'] = {};
+ constraints['channelCount']['min'] = 0;
+ constraints['channelCount']['ideal'] = numInputs;
+ constraints['latency'] = {};
+ constraints['latency']['min'] = 0;
+ constraints['latency']['ideal'] = 0;
+ constraints['sampleSize'] = {};
+ constraints['sampleSize']['min'] = 8;
+ constraints['sampleSize']['max'] = 32;
+ constraints['sampleSize']['ideal'] = 16;
// old property for chrome
- constraints['mandatory']['googAutoGainControl'] = false;
+ constraints['googAutoGainControl'] = false;
var success = function(stream) {
WAB.captureStreamNode = WAB.audioContext['createMediaStreamSource'](stream);
@@ -239,6 +248,88 @@ struct WebBridge : NativeBridge {
return true;
}
+ bool supportsBufferSizeChanges() const override
+ {
+ return true;
+ }
+
+ bool requestBufferSizeChange(const uint32_t newBufferSize) override
+ {
+ // try to create new processor first
+ bool success = EM_ASM_INT({
+ var numInputs = $0;
+ var numOutputs = $1;
+ var newBufferSize = $2;
+ var WAB = Module['WebAudioBridge'];
+
+ try {
+ WAB.newProcessor = WAB.audioContext['createScriptProcessor'](newBufferSize, numInputs, numOutputs);
+ } catch (e) {
+ return 0;
+ }
+
+ // got new processor, disconnect old one
+ WAB.processor['disconnect'](WAB.audioContext['destination']);
+
+ if (WAB.captureStreamNode)
+ WAB.captureStreamNode.disconnect(WAB.processor);
+
+ return 1;
+ }, DISTRHO_PLUGIN_NUM_INPUTS, DISTRHO_PLUGIN_NUM_OUTPUTS, newBufferSize) != 0;
+
+ if (!success)
+ return false;
+
+ bufferSize = newBufferSize;
+ freeBuffers();
+ allocBuffers();
+
+ if (bufferSizeCallback != nullptr)
+ bufferSizeCallback(newBufferSize, jackBufferSizeArg);
+
+ EM_ASM({
+ var numInputs = $0;
+ var numOutputs = $1;
+ var bufferSize = $2;
+ var WAB = Module['WebAudioBridge'];
+
+ // store the new processor
+ delete WAB.processor;
+ WAB.processor = WAB.newProcessor;
+ delete WAB.newProcessor;
+
+ // setup new processor the same way as old one
+ WAB.processor['onaudioprocess'] = function (e) {
+ // var timestamp = performance.now();
+ for (var i = 0; i < numInputs; ++i) {
+ var buffer = e['inputBuffer']['getChannelData'](i);
+ for (var j = 0; j < bufferSize; ++j) {
+ // setValue($3 + ((bufferSize * i) + j) * 4, buffer[j], 'float');
+ HEAPF32[$3 + (((bufferSize * i) + j) << 2) >> 2] = buffer[j];
+ }
+ }
+ dynCall('vi', $4, [$5]);
+ for (var i = 0; i < numOutputs; ++i) {
+ var buffer = e['outputBuffer']['getChannelData'](i);
+ var offset = bufferSize * (numInputs + i);
+ for (var j = 0; j < bufferSize; ++j) {
+ buffer[j] = HEAPF32[$3 + ((offset + j) << 2) >> 2];
+ }
+ }
+ };
+
+ // connect to output
+ WAB.processor['connect'](WAB.audioContext['destination']);
+
+ // and input, if available
+ if (WAB.captureStreamNode)
+ WAB.captureStreamNode.connect(WAB.processor);
+
+ }, DISTRHO_PLUGIN_NUM_INPUTS, DISTRHO_PLUGIN_NUM_OUTPUTS, bufferSize, audioBufferStorage, WebAudioCallback, this);
+
+ return true;
+ }
+
bool supportsMIDI() const override
{
#if DISTRHO_PLUGIN_WANT_MIDI_INPUT || DISTRHO_PLUGIN_WANT_MIDI_OUTPUT