Browse Source

Allow runtime buffer size changes in wasm/bridge modules

Signed-off-by: falkTX <falktx@falktx.com>
pull/321/head
falkTX 3 years ago
parent
commit
29e9fe9a9f
Signed by: falkTX <falktx@falktx.com> GPG Key ID: CDBAA37ABC74FBA0
4 changed files with 162 additions and 13 deletions
  1. +15
    -0
      distrho/DistrhoStandaloneUtils.hpp
  2. +38
    -4
      distrho/src/jackbridge/JackBridge.cpp
  3. +9
    -0
      distrho/src/jackbridge/NativeBridge.hpp
  4. +100
    -9
      distrho/src/jackbridge/WebBridge.hpp

+ 15
- 0
distrho/DistrhoStandaloneUtils.hpp View File

@@ -35,6 +35,11 @@ START_NAMESPACE_DISTRHO
*/ */
bool supportsAudioInput(); bool supportsAudioInput();


/**
Check if the current standalone supports dynamic buffer size changes.
*/
bool supportsBufferSizeChanges();

/** /**
Check if the current standalone supports MIDI. Check if the current standalone supports MIDI.
*/ */
@@ -50,12 +55,22 @@ bool isAudioInputEnabled();
*/ */
bool isMIDIEnabled(); bool isMIDIEnabled();


/**
Get the current buffer size.
*/
uint32_t getBufferSize();

/** /**
Request permissions to use audio input. Request permissions to use audio input.
Only valid to call if audio input is supported but not currently enabled. Only valid to call if audio input is supported but not currently enabled.
*/ */
bool requestAudioInput(); bool requestAudioInput();


/**
Request change to a new buffer size.
*/
bool requestBufferSizeChange(uint32_t newBufferSize);

/** /**
Request permissions to use MIDI. Request permissions to use MIDI.
Only valid to call if MIDI is supported but not currently enabled. Only valid to call if MIDI is supported but not currently enabled.


+ 38
- 4
distrho/src/jackbridge/JackBridge.cpp View File

@@ -1185,7 +1185,13 @@ bool jackbridge_set_buffer_size_callback(jack_client_t* client, JackBufferSizeCa
#elif defined(JACKBRIDGE_DIRECT) #elif defined(JACKBRIDGE_DIRECT)
return (jack_set_buffer_size_callback(client, bufsize_callback, arg) == 0); return (jack_set_buffer_size_callback(client, bufsize_callback, arg) == 0);
#else #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__ # ifdef __WINE__
WineBridge::getInstance().set_bufsize(bufsize_callback); 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) #elif defined(JACKBRIDGE_DIRECT)
return jack_set_buffer_size(client, nframes); return jack_set_buffer_size(client, nframes);
#else #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 #endif
return false; return false;
} }
@@ -2257,6 +2264,15 @@ bool supportsAudioInput()
return true; return true;
} }


bool supportsBufferSizeChanges()
{
#if !(defined(JACKBRIDGE_DUMMY) || defined(JACKBRIDGE_DIRECT))
if (usingNativeBridge)
return nativeBridge->supportsBufferSizeChanges();
#endif
return false;
}

bool supportsMIDI() bool supportsMIDI()
{ {
#if defined(JACKBRIDGE_DUMMY) #if defined(JACKBRIDGE_DUMMY)
@@ -2290,6 +2306,15 @@ bool isMIDIEnabled()
return true; return true;
} }


uint32_t getBufferSize()
{
#if !(defined(JACKBRIDGE_DUMMY) || defined(JACKBRIDGE_DIRECT))
if (usingNativeBridge)
return nativeBridge->getBufferSize();
#endif
return 0;
}

bool requestAudioInput() bool requestAudioInput()
{ {
#if !(defined(JACKBRIDGE_DUMMY) || defined(JACKBRIDGE_DIRECT)) #if !(defined(JACKBRIDGE_DUMMY) || defined(JACKBRIDGE_DIRECT))
@@ -2299,6 +2324,15 @@ bool requestAudioInput()
return false; 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() bool requestMIDI()
{ {
#if !(defined(JACKBRIDGE_DUMMY) || defined(JACKBRIDGE_DIRECT)) #if !(defined(JACKBRIDGE_DUMMY) || defined(JACKBRIDGE_DIRECT))


+ 9
- 0
distrho/src/jackbridge/NativeBridge.hpp View File

@@ -36,7 +36,9 @@ struct NativeBridge {


// JACK callbacks // JACK callbacks
JackProcessCallback jackProcessCallback = nullptr; JackProcessCallback jackProcessCallback = nullptr;
JackBufferSizeCallback bufferSizeCallback = nullptr;
void* jackProcessArg = nullptr; void* jackProcessArg = nullptr;
void* jackBufferSizeArg = nullptr;


// Runtime buffers // Runtime buffers
enum PortMask { enum PortMask {
@@ -85,11 +87,18 @@ struct NativeBridge {
#endif #endif
} }


virtual bool supportsBufferSizeChanges() const { return false; }
virtual bool supportsMIDI() const { return false; } virtual bool supportsMIDI() const { return false; }
virtual bool isMIDIEnabled() const { return false; } virtual bool isMIDIEnabled() const { return false; }
virtual bool requestAudioInput() { return false; } virtual bool requestAudioInput() { return false; }
virtual bool requestBufferSizeChange(uint32_t) { return false; }
virtual bool requestMIDI() { return false; } virtual bool requestMIDI() { return false; }


uint32_t getBufferSize() const noexcept
{
return bufferSize;
}

uint32_t getEventCount() uint32_t getEventCount()
{ {
#if DISTRHO_PLUGIN_WANT_MIDI_INPUT #if DISTRHO_PLUGIN_WANT_MIDI_INPUT


+ 100
- 9
distrho/src/jackbridge/WebBridge.hpp View File

@@ -114,7 +114,7 @@ struct WebBridge : NativeBridge {
return false; return false;
} }


bufferSize = 512;
bufferSize = 2048;
sampleRate = EM_ASM_INT_V({ sampleRate = EM_ASM_INT_V({
var WAB = Module['WebAudioBridge']; var WAB = Module['WebAudioBridge'];
return WAB.audioContext.sampleRate; return WAB.audioContext.sampleRate;
@@ -212,15 +212,24 @@ struct WebBridge : NativeBridge {
// we need to use this weird awkward way for objects, otherwise build fails // we need to use this weird awkward way for objects, otherwise build fails
constraints['audio'] = true; constraints['audio'] = true;
constraints['video'] = false; 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 // old property for chrome
constraints['mandatory']['googAutoGainControl'] = false;
constraints['googAutoGainControl'] = false;


var success = function(stream) { var success = function(stream) {
WAB.captureStreamNode = WAB.audioContext['createMediaStreamSource'](stream); WAB.captureStreamNode = WAB.audioContext['createMediaStreamSource'](stream);
@@ -239,6 +248,88 @@ struct WebBridge : NativeBridge {
return true; 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 bool supportsMIDI() const override
{ {
#if DISTRHO_PLUGIN_WANT_MIDI_INPUT || DISTRHO_PLUGIN_WANT_MIDI_OUTPUT #if DISTRHO_PLUGIN_WANT_MIDI_INPUT || DISTRHO_PLUGIN_WANT_MIDI_OUTPUT


Loading…
Cancel
Save