Skip to content

Commit

Permalink
Updates to sample-accurte event processing
Browse files Browse the repository at this point in the history
  • Loading branch information
jatinchowdhury18 committed Jun 24, 2022
1 parent d1b34a6 commit 9bb6a09
Show file tree
Hide file tree
Showing 3 changed files with 33 additions and 30 deletions.
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -119,10 +119,10 @@ are available
* `CLAP_MISBHEAVIOUR_HANDLER_LEVEL` can be set to `Terminate` or `Ignore` (default
is `Ignore`) to choose your behaviour for a misbehaving host.
* `CLAP_CHECKING_LEVEL` can be set to `None`, `Minimal`, or `Maximal` (default is
`Minimal`) to choose the error checking level for the plugin.
* `CLAP_SMALLEST_ALLOWED_BLOCK_SIZE` can be set to any integer value to choose the
smallest allowed block size for doing sample-accurate event processing. Setting the
value to `0` (the default value) will turn off sample-accurate event processing.
`Minimal`) to choose the level of sanity checks enabled for the plugin.
* `CLAP_EVENT_RESOLUTION_SAMPLES` can be set to any integer value to choose the
resolution (in samples) used by the wrapper for doing sample-accurate event processing.
Setting the value to `0` (the default value) will turn off sample-accurate event processing.

## Risks of using this library

Expand Down
11 changes: 6 additions & 5 deletions cmake/ClapTargetHelpers.cmake
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
function(clap_juce_extensions_plugin_internal)
set(oneValueArgs TARGET TARGET_PATH PLUGIN_NAME IS_JUCER DO_COPY CLAP_MANUAL_URL CLAP_SUPPORT_URL CLAP_MISBEHAVIOUR_HANDLER_LEVEL CLAP_CHECKING_LEVEL CLAP_SMALLEST_ALLOWED_BLOCK_SIZE)
set(oneValueArgs TARGET TARGET_PATH PLUGIN_NAME IS_JUCER DO_COPY CLAP_MANUAL_URL CLAP_SUPPORT_URL CLAP_MISBEHAVIOUR_HANDLER_LEVEL CLAP_CHECKING_LEVEL CLAP_EVENT_RESOLUTION_SAMPLES)
set(multiValueArgs CLAP_ID CLAP_FEATURES)

cmake_parse_arguments(CJA "" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
Expand Down Expand Up @@ -31,11 +31,11 @@ function(clap_juce_extensions_plugin_internal)
message( STATUS "Setting Checking handler level to '${CJA_CLAP_CHECKING_LEVEL}'")
endif()

if ("${CJA_CLAP_SMALLEST_ALLOWED_BLOCK_SIZE}" STREQUAL "")
message( STATUS "Setting smallest allowed block size to 0 (no sample-accurate automation)")
set(CJA_CLAP_SMALLEST_ALLOWED_BLOCK_SIZE 0)
if ("${CJA_CLAP_EVENT_RESOLUTION_SAMPLES}" STREQUAL "")
message( STATUS "Setting event resolution to 0 samples (no sample-accurate automation)")
set(CJA_CLAP_EVENT_RESOLUTION_SAMPLES 0)
else()
message( STATUS "Setting smallest allowed block size to ${CJA_CLAP_SMALLEST_ALLOWED_BLOCK_SIZE}")
message( STATUS "Setting event resolution to ${CJA_CLAP_EVENT_RESOLUTION_SAMPLES} samples")
endif()

# we need the list of features as comma separated quoted strings
Expand Down Expand Up @@ -92,6 +92,7 @@ function(clap_juce_extensions_plugin_internal)
CLAP_SUPPORT_URL="${CJA_CLAP_SUPPORT_URL}"
CLAP_MISBEHAVIOUR_HANDLER_LEVEL=${CJA_CLAP_MISBEHAVIOUR_HANDLER_LEVEL}
CLAP_CHECKING_LEVEL=${CJA_CLAP_CHECKING_LEVEL}
CLAP_EVENT_RESOLUTION_SAMPLES=${CJA_CLAP_EVENT_RESOLUTION_SAMPLES}
)

if(${CJA_IS_JUCER})
Expand Down
44 changes: 23 additions & 21 deletions src/wrapper/clap-juce-wrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -113,8 +113,8 @@ JUCE_BEGIN_IGNORE_WARNINGS_MSVC(4996) // allow strncpy
#define CLAP_CHECKING_LEVEL "Minimal"
#endif

#if !defined(CLAP_SMALLEST_ALLOWED_BLOCK_SIZE)
#define CLAP_SMALLEST_ALLOWED_BLOCK_SIZE 0 // sample-accurate events are off by default
#if !defined(CLAP_EVENT_RESOLUTION_SAMPLES)
#define CLAP_EVENT_RESOLUTION_SAMPLES 0 // sample-accurate events are off by default
#endif

// This is useful for debugging overrides
Expand Down Expand Up @@ -830,12 +830,25 @@ class ClapJuceWrapper : public clap::helpers::Plugin<
int currentEvent = 0;
int nextEventTime = numSamples;

if (numEvents > 0)
if (numEvents > 0) // load first event
{
auto event = events->get(events, 0);
nextEventTime = (int)event->time;
}

auto processEvent = [&](int sampleOffset) {
auto event = events->get(events, (uint32_t)currentEvent);
process_clap_event(event, sampleOffset);

currentEvent++;
nextEventTime = (currentEvent < numEvents)
? (int)events->get(events, (uint32_t)currentEvent)->time
: numSamples;
};

while (nextEventTime == 0) // process events with timestamp 0
processEvent(0);

/*
* OK so here is what JUCE expects in its audio buffer. It *always* uses input as output
* buffer so we need to create a buffer where each channel is the channel of the associated
Expand All @@ -848,7 +861,7 @@ class ClapJuceWrapper : public clap::helpers::Plugin<
for (int n = 0; n < numSamples;)
{
auto getSamplesToProcess = [&]() {
if (CLAP_SMALLEST_ALLOWED_BLOCK_SIZE <= 0)
if (CLAP_EVENT_RESOLUTION_SAMPLES <= 0)
{
// Sample-accurate events are turned off, so just process the whole block!
return numSamples;
Expand All @@ -858,25 +871,17 @@ class ClapJuceWrapper : public clap::helpers::Plugin<
// How many samples should we process at a time?
// In the spirit of sample-accurate events, we want to process a batch of
// samples until we hit the next event, but we don't want to have a batch
// smaller than the `CLAP_SMALLEST_ALLOWED_BLOCK_SIZE`. If there's no more
// smaller than the `CLAP_EVENT_RESOLUTION_SAMPLES`. If there's no more
// events, just process the rest of the block!
return (numSamples - n >= CLAP_SMALLEST_ALLOWED_BLOCK_SIZE)
? juce::jmax(nextEventTime - n, CLAP_SMALLEST_ALLOWED_BLOCK_SIZE)
return (numSamples - n >= CLAP_EVENT_RESOLUTION_SAMPLES)
? juce::jmax(nextEventTime - n, CLAP_EVENT_RESOLUTION_SAMPLES)
: (numSamples - n);
}
};

const auto numSamplesToProcess = getSamplesToProcess();
while (nextEventTime < n + numSamplesToProcess && currentEvent < numEvents)
{
auto event = events->get(events, (uint32_t)currentEvent);
process_clap_event(event, n);

currentEvent++;
nextEventTime = (currentEvent < numEvents)
? (int)events->get(events, (uint32_t)currentEvent)->time
: numSamples;
}
processEvent(n);

uint32_t outputChannels = 0;
for (uint32_t idx = 0; idx < process->audio_outputs_count && outputChannels < maxBuses;
Expand Down Expand Up @@ -949,11 +954,8 @@ class ClapJuceWrapper : public clap::helpers::Plugin<
}

// process any leftover events
for (; currentEvent < numEvents; ++currentEvent)
{
auto event = events->get(events, (uint32_t)currentEvent);
process_clap_event(event, 0);
}
while (currentEvent < numEvents)
processEvent(numSamples);

return CLAP_PROCESS_CONTINUE;
}
Expand Down

0 comments on commit 9bb6a09

Please sign in to comment.