/*******************************************************************************************************************
Copyright (c) 2023 Cycling '74
The code that Max generates automatically and that end users are capable of
exporting and using, and any associated documentation files (the “Software”)
is a work of authorship for which Cycling '74 is the author and owner for
copyright purposes.
This Software is dual-licensed either under the terms of the Cycling '74
License for Max-Generated Code for Export, or alternatively under the terms
of the General Public License (GPL) Version 3. You may use the Software
according to either of these licenses as it is most appropriate for your
project on a case-by-case basis (proprietary or not).
A) Cycling '74 License for Max-Generated Code for Export
A license is hereby granted, free of charge, to any person obtaining a copy
of the Software (“Licensee”) to use, copy, modify, merge, publish, and
distribute copies of the Software, and to permit persons to whom the Software
is furnished to do so, subject to the following conditions:
The Software is licensed to Licensee for all uses that do not include the sale,
sublicensing, or commercial distribution of software that incorporates this
source code. This means that the Licensee is free to use this software for
educational, research, and prototyping purposes, to create musical or other
creative works with software that incorporates this source code, or any other
use that does not constitute selling software that makes use of this source
code. Commercial distribution also includes the packaging of free software with
other paid software, hardware, or software-provided commercial services.
For entities with UNDER $200k in annual revenue or funding, a license is hereby
granted, free of charge, for the sale, sublicensing, or commercial distribution
of software that incorporates this source code, for as long as the entity's
annual revenue remains below $200k annual revenue or funding.
For entities with OVER $200k in annual revenue or funding interested in the
sale, sublicensing, or commercial distribution of software that incorporates
this source code, please send inquiries to licensing@cycling74.com.
The above copyright notice and this license shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
Please see
https://support.cycling74.com/hc/en-us/articles/10730637742483-RNBO-Export-Licensing-FAQ
for additional information
B) General Public License Version 3 (GPLv3)
Details of the GPLv3 license can be found at: https://www.gnu.org/licenses/gpl-3.0.html
*******************************************************************************************************************/
#include "RNBO_Common.h"
#include "RNBO_AudioSignal.h"
namespace RNBO {
#define trunc(x) ((Int)(x))
#if defined(__GNUC__) || defined(__clang__)
#define RNBO_RESTRICT __restrict__
#elif defined(_MSC_VER)
#define RNBO_RESTRICT __restrict
#endif
#define FIXEDSIZEARRAYINIT(...) { }
class rnbomatic : public PatcherInterfaceImpl {
public:
rnbomatic()
{
}
~rnbomatic()
{
}
rnbomatic* getTopLevelPatcher() {
return this;
}
void cancelClockEvents()
{
getEngine()->flushClockEvents(this, 892732297, false);
getEngine()->flushClockEvents(this, 1935387534, false);
}
template <typename T> void listquicksort(T& arr, T& sortindices, Int l, Int h, bool ascending) {
if (l < h) {
Int p = (Int)(this->listpartition(arr, sortindices, l, h, ascending));
this->listquicksort(arr, sortindices, l, p - 1, ascending);
this->listquicksort(arr, sortindices, p + 1, h, ascending);
}
}
template <typename T> Int listpartition(T& arr, T& sortindices, Int l, Int h, bool ascending) {
number x = arr[(Index)h];
Int i = (Int)(l - 1);
for (Int j = (Int)(l); j <= h - 1; j++) {
bool asc = (bool)((bool)(ascending) && arr[(Index)j] <= x);
bool desc = (bool)((bool)(!(bool)(ascending)) && arr[(Index)j] >= x);
if ((bool)(asc) || (bool)(desc)) {
i++;
this->listswapelements(arr, i, j);
this->listswapelements(sortindices, i, j);
}
}
i++;
this->listswapelements(arr, i, h);
this->listswapelements(sortindices, i, h);
return i;
}
template <typename T> void listswapelements(T& arr, Int a, Int b) {
auto tmp = arr[(Index)a];
arr[(Index)a] = arr[(Index)b];
arr[(Index)b] = tmp;
}
number mstosamps(MillisecondTime ms) {
return ms * this->sr * 0.001;
}
number maximum(number x, number y) {
return (x < y ? y : x);
}
MillisecondTime currenttime() {
return this->_currentTime;
}
number tempo() {
return this->getTopLevelPatcher()->globaltransport_getTempo(this->currenttime());
}
number mstobeats(number ms) {
return ms * this->tempo() * 0.008 / (number)480;
}
MillisecondTime sampstoms(number samps) {
return samps * 1000 / this->sr;
}
Index getNumMidiInputPorts() const {
return 0;
}
void processMidiEvent(MillisecondTime , int , ConstByteArray , Index ) {}
Index getNumMidiOutputPorts() const {
return 0;
}
void process(
const SampleValue * const* inputs,
Index numInputs,
SampleValue * const* outputs,
Index numOutputs,
Index n
) {
this->vs = n;
this->updateTime(this->getEngine()->getCurrentTime());
SampleValue * out1 = (numOutputs >= 1 && outputs[0] ? outputs[0] : this->dummyBuffer);
SampleValue * out2 = (numOutputs >= 2 && outputs[1] ? outputs[1] : this->dummyBuffer);
const SampleValue * in1 = (numInputs >= 1 && inputs[0] ? inputs[0] : this->zeroBuffer);
const SampleValue * in2 = (numInputs >= 2 && inputs[1] ? inputs[1] : this->zeroBuffer);
this->signaladder_01_perform(in2, in1, out2, n);
this->signaladder_02_perform(in2, in1, out1, n);
this->stackprotect_perform(n);
this->globaltransport_advance();
this->audioProcessSampleCount += this->vs;
}
void prepareToProcess(number sampleRate, Index maxBlockSize, bool force) {
if (this->maxvs < maxBlockSize || !this->didAllocateSignals) {
this->globaltransport_tempo = resizeSignal(this->globaltransport_tempo, this->maxvs, maxBlockSize);
this->globaltransport_state = resizeSignal(this->globaltransport_state, this->maxvs, maxBlockSize);
this->zeroBuffer = resizeSignal(this->zeroBuffer, this->maxvs, maxBlockSize);
this->dummyBuffer = resizeSignal(this->dummyBuffer, this->maxvs, maxBlockSize);
this->didAllocateSignals = true;
}
const bool sampleRateChanged = sampleRate != this->sr;
const bool maxvsChanged = maxBlockSize != this->maxvs;
const bool forceDSPSetup = sampleRateChanged || maxvsChanged || force;
if (sampleRateChanged || maxvsChanged) {
this->vs = maxBlockSize;
this->maxvs = maxBlockSize;
this->sr = sampleRate;
this->invsr = 1 / sampleRate;
}
this->globaltransport_dspsetup(forceDSPSetup);
if (sampleRateChanged)
this->onSampleRateChanged(sampleRate);
}
void setProbingTarget(MessageTag id) {
switch (id) {
default:
{
this->setProbingIndex(-1);
break;
}
}
}
void setProbingIndex(ProbingIndex ) {}
Index getProbingChannels(MessageTag outletId) const {
RNBO_UNUSED(outletId);
return 0;
}
DataRef* getDataRef(DataRefIndex index) {
switch (index) {
default:
{
return nullptr;
}
}
}
DataRefIndex getNumDataRefs() const {
return 0;
}
void fillDataRef(DataRefIndex , DataRef& ) {}
void processDataViewUpdate(DataRefIndex , MillisecondTime ) {}
void initialize() {
this->assign_defaults();
this->setState();
this->initializeObjects();
this->allocateDataRefs();
this->startup();
}
Index getIsMuted() {
return this->isMuted;
}
void setIsMuted(Index v) {
this->isMuted = v;
}
Index getPatcherSerial() const {
return 0;
}
void getState(PatcherStateInterface& ) {}
void setState() {}
void getPreset(PatcherStateInterface& preset) {
preset["__presetid"] = "rnbo";
this->param_01_getPresetValue(getSubState(preset, "led1"));
}
void setPreset(MillisecondTime time, PatcherStateInterface& preset) {
this->updateTime(time);
this->param_01_setPresetValue(getSubState(preset, "led1"));
}
void processTempoEvent(MillisecondTime time, Tempo tempo) {
this->updateTime(time);
if (this->globaltransport_setTempo(this->_currentTime, tempo, false))
{}
}
void processTransportEvent(MillisecondTime time, TransportState state) {
this->updateTime(time);
if (this->globaltransport_setState(this->_currentTime, state, false)) {
this->metro_01_onTransportChanged(state);
}
}
void processBeatTimeEvent(MillisecondTime time, BeatTime beattime) {
this->updateTime(time);
if (this->globaltransport_setBeatTime(this->_currentTime, beattime, false)) {
this->metro_01_onBeatTimeChanged(beattime);
}
}
void onSampleRateChanged(double ) {}
void processTimeSignatureEvent(MillisecondTime time, int numerator, int denominator) {
this->updateTime(time);
if (this->globaltransport_setTimeSignature(this->_currentTime, numerator, denominator, false))
{}
}
void setParameterValue(ParameterIndex index, ParameterValue v, MillisecondTime time) {
this->updateTime(time);
switch (index) {
case 0:
{
this->param_01_value_set(v);
break;
}
}
}
void processParameterEvent(ParameterIndex index, ParameterValue value, MillisecondTime time) {
this->setParameterValue(index, value, time);
}
void processNormalizedParameterEvent(ParameterIndex index, ParameterValue value, MillisecondTime time) {
this->setParameterValueNormalized(index, value, time);
}
ParameterValue getParameterValue(ParameterIndex index) {
switch (index) {
case 0:
{
return this->param_01_value;
}
default:
{
return 0;
}
}
}
ParameterIndex getNumSignalInParameters() const {
return 0;
}
ParameterIndex getNumSignalOutParameters() const {
return 0;
}
ParameterIndex getNumParameters() const {
return 1;
}
ConstCharPointer getParameterName(ParameterIndex index) const {
switch (index) {
case 0:
{
return "led1";
}
default:
{
return "bogus";
}
}
}
ConstCharPointer getParameterId(ParameterIndex index) const {
switch (index) {
case 0:
{
return "led1";
}
default:
{
return "bogus";
}
}
}
void getParameterInfo(ParameterIndex index, ParameterInfo * info) const {
{
switch (index) {
case 0:
{
info->type = ParameterTypeNumber;
info->initialValue = 0;
info->min = 0;
info->max = 1;
info->exponent = 1;
info->steps = 0;
info->debug = false;
info->saveable = true;
info->transmittable = true;
info->initialized = true;
info->visible = true;
info->displayName = "";
info->unit = "";
info->ioType = IOTypeUndefined;
info->signalIndex = INVALID_INDEX;
break;
}
}
}
}
void sendParameter(ParameterIndex index, bool ignoreValue) {
this->getEngine()->notifyParameterValueChanged(index, (ignoreValue ? 0 : this->getParameterValue(index)), ignoreValue);
}
ParameterValue applyStepsToNormalizedParameterValue(ParameterValue normalizedValue, int steps) const {
if (steps == 1) {
if (normalizedValue > 0) {
normalizedValue = 1.;
}
} else {
ParameterValue oneStep = (number)1. / (steps - 1);
ParameterValue numberOfSteps = rnbo_fround(normalizedValue / oneStep * 1 / (number)1) * (number)1;
normalizedValue = numberOfSteps * oneStep;
}
return normalizedValue;
}
ParameterValue convertToNormalizedParameterValue(ParameterIndex index, ParameterValue value) const {
switch (index) {
case 0:
{
{
value = (value < 0 ? 0 : (value > 1 ? 1 : value));
ParameterValue normalizedValue = (value - 0) / (1 - 0);
return normalizedValue;
}
}
default:
{
return value;
}
}
}
ParameterValue convertFromNormalizedParameterValue(ParameterIndex index, ParameterValue value) const {
value = (value < 0 ? 0 : (value > 1 ? 1 : value));
switch (index) {
case 0:
{
{
value = (value < 0 ? 0 : (value > 1 ? 1 : value));
{
return 0 + value * (1 - 0);
}
}
}
default:
{
return value;
}
}
}
ParameterValue constrainParameterValue(ParameterIndex index, ParameterValue value) const {
switch (index) {
case 0:
{
return this->param_01_value_constrain(value);
}
default:
{
return value;
}
}
}
void scheduleParamInit(ParameterIndex index, Index order) {
this->paramInitIndices->push(index);
this->paramInitOrder->push(order);
}
void processParamInitEvents() {
this->listquicksort(
this->paramInitOrder,
this->paramInitIndices,
0,
(int)(this->paramInitOrder->length - 1),
true
);
for (Index i = 0; i < this->paramInitOrder->length; i++) {
this->getEngine()->scheduleParameterChange(
this->paramInitIndices[i],
this->getParameterValue(this->paramInitIndices[i]),
0
);
}
}
void processClockEvent(MillisecondTime time, ClockId index, bool hasValue, ParameterValue value) {
RNBO_UNUSED(value);
RNBO_UNUSED(hasValue);
this->updateTime(time);
switch (index) {
case 892732297:
{
this->loadmess_01_startupbang_bang();
break;
}
case 1935387534:
{
this->metro_01_tick_bang();
break;
}
}
}
void processOutletAtCurrentTime(EngineLink* , OutletIndex , ParameterValue ) {}
void processOutletEvent(
EngineLink* sender,
OutletIndex index,
ParameterValue value,
MillisecondTime time
) {
this->updateTime(time);
this->processOutletAtCurrentTime(sender, index, value);
}
void processNumMessage(MessageTag tag, MessageTag objectId, MillisecondTime time, number payload) {
this->updateTime(time);
switch (tag) {
case TAG("valin"):
{
if (TAG("toggle_obj-50") == objectId)
this->toggle_01_valin_set(payload);
break;
}
}
}
void processListMessage(MessageTag , MessageTag , MillisecondTime , const list& ) {}
void processBangMessage(MessageTag tag, MessageTag objectId, MillisecondTime time) {
this->updateTime(time);
switch (tag) {
case TAG("startupbang"):
{
if (TAG("loadmess_obj-48") == objectId)
this->loadmess_01_startupbang_bang();
break;
}
}
}
MessageTagInfo resolveTag(MessageTag tag) const {
switch (tag) {
case TAG("valout"):
{
return "valout";
}
case TAG("toggle_obj-50"):
{
return "toggle_obj-50";
}
case TAG("valin"):
{
return "valin";
}
case TAG("startupbang"):
{
return "startupbang";
}
case TAG("loadmess_obj-48"):
{
return "loadmess_obj-48";
}
}
return "";
}
MessageIndex getNumMessages() const {
return 0;
}
const MessageInfo& getMessageInfo(MessageIndex index) const {
switch (index) {
}
return NullMessageInfo;
}
protected:
void param_01_value_set(number v) {
v = this->param_01_value_constrain(v);
this->param_01_value = v;
this->sendParameter(0, false);
if (this->param_01_value != this->param_01_lastValue) {
this->getEngine()->presetTouched();
this->param_01_lastValue = this->param_01_value;
}
}
void toggle_01_valin_set(number v) {
this->toggle_01_value_number_set(v);
}
void loadmess_01_startupbang_bang() {
this->loadmess_01_message_bang();
}
void metro_01_tick_bang() {
this->metro_01_tickout_bang();
this->getEngine()->flushClockEvents(this, 1935387534, false);;
if ((bool)(this->metro_01_on)) {
{
this->getEngine()->scheduleClockEvent(this, 1935387534, this->metro_01_interval + this->_currentTime);;
}
}
}
number msToSamps(MillisecondTime ms, number sampleRate) {
return ms * sampleRate * 0.001;
}
MillisecondTime sampsToMs(SampleIndex samps) {
return samps * (this->invsr * 1000);
}
Index getMaxBlockSize() const {
return this->maxvs;
}
number getSampleRate() const {
return this->sr;
}
bool hasFixedVectorSize() const {
return false;
}
Index getNumInputChannels() const {
return 2;
}
Index getNumOutputChannels() const {
return 2;
}
void allocateDataRefs() {}
void initializeObjects() {}
void sendOutlet(OutletIndex index, ParameterValue value) {
this->getEngine()->sendOutlet(this, index, value);
}
void startup() {
this->updateTime(this->getEngine()->getCurrentTime());
this->getEngine()->scheduleClockEvent(this, 892732297, 0 + this->_currentTime);;
if ((bool)(this->metro_01_on))
this->metro_01_on_set(1);
{
this->scheduleParamInit(0, 0);
}
this->processParamInitEvents();
}
static number param_01_value_constrain(number v) {
v = (v > 1 ? 1 : (v < 0 ? 0 : v));
return v;
}
void toggle_01_output_set(number v) {
this->param_01_value_set(v);
}
void toggle_01_value_number_set(number v) {
this->toggle_01_value_number_setter(v);
v = this->toggle_01_value_number;
this->getEngine()->sendNumMessage(TAG("valout"), TAG("toggle_obj-50"), v, this->_currentTime);
this->toggle_01_output_set(v);
}
void metro_01_on_set(number v) {
this->metro_01_on = v;
this->getEngine()->flushClockEvents(this, 1935387534, false);;
if ((bool)(v)) {
{
this->getEngine()->scheduleClockEvent(this, 1935387534, 0 + this->_currentTime);;
}
}
}
void metro_01_interval_set(number v) {
this->metro_01_interval_setter(v);
v = this->metro_01_interval;
}
void loadmess_01_message_bang() {
list v = this->loadmess_01_message;
{
if (v->length > 1)
this->metro_01_interval_set(v[1]);
number converted = (v->length > 0 ? v[0] : 0);
this->metro_01_on_set(converted);
}
}
void toggle_01_value_bang_bang() {
number val = (this->toggle_01_value_number == 1 ? 0 : 1);
this->toggle_01_value_number_set(val);
}
void metro_01_tickout_bang() {
this->toggle_01_value_bang_bang();
}
void signaladder_01_perform(
const SampleValue * in1,
const SampleValue * in2,
SampleValue * out,
Index n
) {
Index i;
for (i = 0; i < n; i++) {
out[(Index)i] = in1[(Index)i] + in2[(Index)i];
}
}
void signaladder_02_perform(
const SampleValue * in1,
const SampleValue * in2,
SampleValue * out,
Index n
) {
Index i;
for (i = 0; i < n; i++) {
out[(Index)i] = in1[(Index)i] + in2[(Index)i];
}
}
void stackprotect_perform(Index n) {
RNBO_UNUSED(n);
auto __stackprotect_count = this->stackprotect_count;
__stackprotect_count = 0;
this->stackprotect_count = __stackprotect_count;
}
void toggle_01_value_number_setter(number v) {
this->toggle_01_value_number = (v != 0 ? 1 : 0);
}
void metro_01_interval_setter(number v) {
this->metro_01_interval = (v > 0 ? v : 0);
}
void param_01_getPresetValue(PatcherStateInterface& preset) {
preset["value"] = this->param_01_value;
}
void param_01_setPresetValue(PatcherStateInterface& preset) {
if ((bool)(stateIsEmpty(preset)))
return;
this->param_01_value_set(preset["value"]);
}
void toggle_01_getPresetValue(PatcherStateInterface& preset) {
preset["value"] = this->toggle_01_value_number;
}
void toggle_01_setPresetValue(PatcherStateInterface& preset) {
if ((bool)(stateIsEmpty(preset)))
return;
this->toggle_01_value_number_set(preset["value"]);
}
void metro_01_onTransportChanged(number ) {}
void metro_01_onBeatTimeChanged(number ) {}
Index globaltransport_getSampleOffset(MillisecondTime time) {
return this->mstosamps(this->maximum(0, time - this->getEngine()->getCurrentTime()));
}
number globaltransport_getTempoAtSample(SampleIndex sampleOffset) {
return (sampleOffset >= 0 && sampleOffset < this->vs ? this->globaltransport_tempo[(Index)sampleOffset] : this->globaltransport_lastTempo);
}
number globaltransport_getStateAtSample(SampleIndex sampleOffset) {
return (sampleOffset >= 0 && sampleOffset < this->vs ? this->globaltransport_state[(Index)sampleOffset] : this->globaltransport_lastState);
}
number globaltransport_getState(MillisecondTime time) {
return this->globaltransport_getStateAtSample(this->globaltransport_getSampleOffset(time));
}
number globaltransport_getBeatTime(MillisecondTime time) {
number i = 2;
while (i < this->globaltransport_beatTimeChanges->length && this->globaltransport_beatTimeChanges[(Index)(i + 1)] <= time) {
i += 2;
}
i -= 2;
number beatTimeBase = this->globaltransport_beatTimeChanges[(Index)i];
if (this->globaltransport_getState(time) == 0)
return beatTimeBase;
number beatTimeBaseMsTime = this->globaltransport_beatTimeChanges[(Index)(i + 1)];
number diff = time - beatTimeBaseMsTime;
return beatTimeBase + this->mstobeats(diff);
}
bool globaltransport_setTempo(MillisecondTime time, number tempo, bool notify) {
if ((bool)(notify)) {
this->processTempoEvent(time, tempo);
this->globaltransport_notify = true;
} else {
Index offset = (Index)(this->globaltransport_getSampleOffset(time));
if (this->globaltransport_getTempoAtSample(offset) != tempo) {
this->globaltransport_beatTimeChanges->push(this->globaltransport_getBeatTime(time));
this->globaltransport_beatTimeChanges->push(time);
fillSignal(this->globaltransport_tempo, this->vs, tempo, offset);
this->globaltransport_lastTempo = tempo;
this->globaltransport_tempoNeedsReset = true;
return true;
}
}
return false;
}
number globaltransport_getTempo(MillisecondTime time) {
return this->globaltransport_getTempoAtSample(this->globaltransport_getSampleOffset(time));
}
bool globaltransport_setState(MillisecondTime time, number state, bool notify) {
if ((bool)(notify)) {
this->processTransportEvent(time, TransportState(state));
this->globaltransport_notify = true;
} else {
Index offset = (Index)(this->globaltransport_getSampleOffset(time));
if (this->globaltransport_getStateAtSample(offset) != state) {
fillSignal(this->globaltransport_state, this->vs, state, offset);
this->globaltransport_lastState = TransportState(state);
this->globaltransport_stateNeedsReset = true;
if (state == 0) {
this->globaltransport_beatTimeChanges->push(this->globaltransport_getBeatTime(time));
this->globaltransport_beatTimeChanges->push(time);
}
return true;
}
}
return false;
}
bool globaltransport_setBeatTime(MillisecondTime time, number beattime, bool notify) {
if ((bool)(notify)) {
this->processBeatTimeEvent(time, beattime);
this->globaltransport_notify = true;
return false;
} else {
bool beatTimeHasChanged = false;
float oldBeatTime = (float)(this->globaltransport_getBeatTime(time));
float newBeatTime = (float)(beattime);
if (oldBeatTime != newBeatTime) {
beatTimeHasChanged = true;
}
this->globaltransport_beatTimeChanges->push(beattime);
this->globaltransport_beatTimeChanges->push(time);
return beatTimeHasChanged;
}
}
number globaltransport_getBeatTimeAtSample(SampleIndex sampleOffset) {
auto msOffset = this->sampstoms(sampleOffset);
return this->globaltransport_getBeatTime(this->getEngine()->getCurrentTime() + msOffset);
}
array<number, 2> globaltransport_getTimeSignature(MillisecondTime time) {
number i = 3;
while (i < this->globaltransport_timeSignatureChanges->length && this->globaltransport_timeSignatureChanges[(Index)(i + 2)] <= time) {
i += 3;
}
i -= 3;
return {
this->globaltransport_timeSignatureChanges[(Index)i],
this->globaltransport_timeSignatureChanges[(Index)(i + 1)]
};
}
array<number, 2> globaltransport_getTimeSignatureAtSample(SampleIndex sampleOffset) {
auto msOffset = this->sampstoms(sampleOffset);
return this->globaltransport_getTimeSignature(this->getEngine()->getCurrentTime() + msOffset);
}
bool globaltransport_setTimeSignature(MillisecondTime time, number numerator, number denominator, bool notify) {
if ((bool)(notify)) {
this->processTimeSignatureEvent(time, (int)(numerator), (int)(denominator));
this->globaltransport_notify = true;
} else {
array<number, 2> currentSig = this->globaltransport_getTimeSignature(time);
if (currentSig[0] != numerator || currentSig[1] != denominator) {
this->globaltransport_timeSignatureChanges->push(numerator);
this->globaltransport_timeSignatureChanges->push(denominator);
this->globaltransport_timeSignatureChanges->push(time);
return true;
}
}
return false;
}
void globaltransport_advance() {
if ((bool)(this->globaltransport_tempoNeedsReset)) {
fillSignal(this->globaltransport_tempo, this->vs, this->globaltransport_lastTempo);
this->globaltransport_tempoNeedsReset = false;
if ((bool)(this->globaltransport_notify)) {
this->getEngine()->sendTempoEvent(this->globaltransport_lastTempo);
}
}
if ((bool)(this->globaltransport_stateNeedsReset)) {
fillSignal(this->globaltransport_state, this->vs, this->globaltransport_lastState);
this->globaltransport_stateNeedsReset = false;
if ((bool)(this->globaltransport_notify)) {
this->getEngine()->sendTransportEvent(TransportState(this->globaltransport_lastState));
}
}
if (this->globaltransport_beatTimeChanges->length > 2) {
this->globaltransport_beatTimeChanges[0] = this->globaltransport_beatTimeChanges[(Index)(this->globaltransport_beatTimeChanges->length - 2)];
this->globaltransport_beatTimeChanges[1] = this->globaltransport_beatTimeChanges[(Index)(this->globaltransport_beatTimeChanges->length - 1)];
this->globaltransport_beatTimeChanges->length = 2;
if ((bool)(this->globaltransport_notify)) {
this->getEngine()->sendBeatTimeEvent(this->globaltransport_beatTimeChanges[0]);
}
}
if (this->globaltransport_timeSignatureChanges->length > 3) {
this->globaltransport_timeSignatureChanges[0] = this->globaltransport_timeSignatureChanges[(Index)(this->globaltransport_timeSignatureChanges->length - 3)];
this->globaltransport_timeSignatureChanges[1] = this->globaltransport_timeSignatureChanges[(Index)(this->globaltransport_timeSignatureChanges->length - 2)];
this->globaltransport_timeSignatureChanges[2] = this->globaltransport_timeSignatureChanges[(Index)(this->globaltransport_timeSignatureChanges->length - 1)];
this->globaltransport_timeSignatureChanges->length = 3;
if ((bool)(this->globaltransport_notify)) {
this->getEngine()->sendTimeSignatureEvent(
(int)(this->globaltransport_timeSignatureChanges[0]),
(int)(this->globaltransport_timeSignatureChanges[1])
);
}
}
this->globaltransport_notify = false;
}
void globaltransport_dspsetup(bool force) {
if ((bool)(this->globaltransport_setupDone) && (bool)(!(bool)(force)))
return;
fillSignal(this->globaltransport_tempo, this->vs, this->globaltransport_lastTempo);
this->globaltransport_tempoNeedsReset = false;
fillSignal(this->globaltransport_state, this->vs, this->globaltransport_lastState);
this->globaltransport_stateNeedsReset = false;
this->globaltransport_setupDone = true;
}
bool stackprotect_check() {
this->stackprotect_count++;
if (this->stackprotect_count > 128) {
console->log("STACK OVERFLOW DETECTED - stopped processing branch !");
return true;
}
return false;
}
void updateTime(MillisecondTime time) {
this->_currentTime = time;
this->sampleOffsetIntoNextAudioBuffer = (SampleIndex)(rnbo_fround(this->msToSamps(time - this->getEngine()->getCurrentTime(), this->sr)));
if (this->sampleOffsetIntoNextAudioBuffer >= (SampleIndex)(this->vs))
this->sampleOffsetIntoNextAudioBuffer = (SampleIndex)(this->vs) - 1;
if (this->sampleOffsetIntoNextAudioBuffer < 0)
this->sampleOffsetIntoNextAudioBuffer = 0;
}
void assign_defaults()
{
param_01_value = 0;
toggle_01_value_number = 0;
toggle_01_value_number_setter(toggle_01_value_number);
loadmess_01_message = { 1 };
metro_01_on = 0;
metro_01_interval = 1000;
metro_01_interval_setter(metro_01_interval);
_currentTime = 0;
audioProcessSampleCount = 0;
sampleOffsetIntoNextAudioBuffer = 0;
zeroBuffer = nullptr;
dummyBuffer = nullptr;
didAllocateSignals = 0;
vs = 0;
maxvs = 0;
sr = 44100;
invsr = 0.00002267573696;
param_01_lastValue = 0;
toggle_01_lastValue = 0;
globaltransport_tempo = nullptr;
globaltransport_tempoNeedsReset = false;
globaltransport_lastTempo = 120;
globaltransport_state = nullptr;
globaltransport_stateNeedsReset = false;
globaltransport_lastState = 0;
globaltransport_beatTimeChanges = { 0, 0 };
globaltransport_timeSignatureChanges = { 4, 4, 0 };
globaltransport_notify = false;
globaltransport_setupDone = false;
stackprotect_count = 0;
_voiceIndex = 0;
_noteNumber = 0;
isMuted = 1;
}
// member variables
number param_01_value;
number toggle_01_value_number;
list loadmess_01_message;
number metro_01_on;
number metro_01_interval;
MillisecondTime _currentTime;
SampleIndex audioProcessSampleCount;
SampleIndex sampleOffsetIntoNextAudioBuffer;
signal zeroBuffer;
signal dummyBuffer;
bool didAllocateSignals;
Index vs;
Index maxvs;
number sr;
number invsr;
number param_01_lastValue;
number toggle_01_lastValue;
signal globaltransport_tempo;
bool globaltransport_tempoNeedsReset;
number globaltransport_lastTempo;
signal globaltransport_state;
bool globaltransport_stateNeedsReset;
number globaltransport_lastState;
list globaltransport_beatTimeChanges;
list globaltransport_timeSignatureChanges;
bool globaltransport_notify;
bool globaltransport_setupDone;
number stackprotect_count;
Index _voiceIndex;
Int _noteNumber;
Index isMuted;
indexlist paramInitIndices;
indexlist paramInitOrder;
};
PatcherInterface* creaternbomatic()
{
return new rnbomatic();
}
#ifndef RNBO_NO_PATCHERFACTORY
extern "C" PatcherFactoryFunctionPtr GetPatcherFactoryFunction(PlatformInterface* platformInterface)
#else
extern "C" PatcherFactoryFunctionPtr rnbomaticFactoryFunction(PlatformInterface* platformInterface)
#endif
{
Platform::set(platformInterface);
return creaternbomatic;
}
} // end RNBO namespace