Signed-off-by: falkTX <falktx@falktx.com>tags/23.02
@@ -1 +1 @@ | |||
Subproject commit 8eb504d3eb6b4f9984503bedfbd3c02b7cb63d2b | |||
Subproject commit 207e0ae8720faa4db6f34192d83a0ee3b85b832a |
@@ -1,78 +1,101 @@ | |||
{ | |||
"version": "2.1", | |||
"version": "2.1.1", | |||
"zoom": 1.0, | |||
"modules": [ | |||
{ | |||
"id": 2799203590388841, | |||
"id": 8712245256622475, | |||
"plugin": "Cardinal", | |||
"model": "TextEditor", | |||
"version": "2.0", | |||
"params": [], | |||
"leftModuleId": 4, | |||
"leftModuleId": 1202678850202654, | |||
"data": { | |||
"filepath": "", | |||
"lang": "None", | |||
"etext": "Welcome to Cardinal!\n\nThis is the mini variant\nIt has 2 audio ports, 5 CV ports, plus MIDI\n\nThe most relevant modules for host\nintegration are in this default patch\n\nHave fun!\n\n", | |||
"width": 23 | |||
}, | |||
"pos": [ | |||
42, | |||
0 | |||
] | |||
}, | |||
{ | |||
"id": 2, | |||
"plugin": "Cardinal", | |||
"model": "HostMIDI", | |||
"version": "2.0", | |||
"params": [], | |||
"leftModuleId": 7249509538355161, | |||
"rightModuleId": 3, | |||
"data": { | |||
"pwRange": 0.0, | |||
"smooth": false, | |||
"channels": 1, | |||
"polyMode": 0, | |||
"lastPitch": 8192, | |||
"lastMod": 0, | |||
"inputChannel": 0, | |||
"outputChannel": 0 | |||
"etext": "Welcome to Cardinal!\n\nThis is the mini variant\nIt has 2 audio ports, 5 CV ports, plus MIDI\n\nThe most relevant modules for host\nintegration are in this default patch\n\nA basic VCO + ADSR + VCA is\nthe default patch\n\nHave fun!\n\n", | |||
"width": 19 | |||
}, | |||
"pos": [ | |||
16, | |||
58, | |||
0 | |||
] | |||
}, | |||
{ | |||
"id": 3, | |||
"plugin": "Cardinal", | |||
"model": "HostTime", | |||
"id": 5726895899473528, | |||
"plugin": "Fundamental", | |||
"model": "ADSR", | |||
"version": "2.0", | |||
"params": [], | |||
"leftModuleId": 2, | |||
"rightModuleId": 4, | |||
"params": [ | |||
{ | |||
"value": 0.5, | |||
"id": 0 | |||
}, | |||
{ | |||
"value": 0.5, | |||
"id": 1 | |||
}, | |||
{ | |||
"value": 0.5, | |||
"id": 2 | |||
}, | |||
{ | |||
"value": 0.5, | |||
"id": 3 | |||
}, | |||
{ | |||
"value": 0.0, | |||
"id": 4 | |||
}, | |||
{ | |||
"value": 0.0, | |||
"id": 5 | |||
}, | |||
{ | |||
"value": 0.0, | |||
"id": 6 | |||
}, | |||
{ | |||
"value": 0.0, | |||
"id": 7 | |||
}, | |||
{ | |||
"value": 0.0, | |||
"id": 8 | |||
} | |||
], | |||
"leftModuleId": 8601159184541723, | |||
"rightModuleId": 4828178296911509, | |||
"pos": [ | |||
25, | |||
18, | |||
0 | |||
] | |||
}, | |||
{ | |||
"id": 4, | |||
"plugin": "Cardinal", | |||
"model": "HostParameters", | |||
"id": 4828178296911509, | |||
"plugin": "Fundamental", | |||
"model": "VCA-1", | |||
"version": "2.0", | |||
"params": [], | |||
"leftModuleId": 3, | |||
"rightModuleId": 2799203590388841, | |||
"params": [ | |||
{ | |||
"value": 1.0, | |||
"id": 0 | |||
}, | |||
{ | |||
"value": 1.0, | |||
"id": 1 | |||
} | |||
], | |||
"leftModuleId": 5726895899473528, | |||
"rightModuleId": 1, | |||
"pos": [ | |||
33, | |||
27, | |||
0 | |||
] | |||
}, | |||
{ | |||
"id": 7249509538355161, | |||
"plugin": "Cardinal", | |||
"model": "HostCV", | |||
"id": 8601159184541723, | |||
"plugin": "Fundamental", | |||
"model": "VCO", | |||
"version": "2.0", | |||
"params": [ | |||
{ | |||
@@ -80,7 +103,7 @@ | |||
"id": 0 | |||
}, | |||
{ | |||
"value": 0.0, | |||
"value": 1.0, | |||
"id": 1 | |||
}, | |||
{ | |||
@@ -90,30 +113,171 @@ | |||
{ | |||
"value": 0.0, | |||
"id": 3 | |||
}, | |||
{ | |||
"value": 0.0, | |||
"id": 4 | |||
}, | |||
{ | |||
"value": 0.5, | |||
"id": 5 | |||
}, | |||
{ | |||
"value": 0.0, | |||
"id": 6 | |||
}, | |||
{ | |||
"value": 0.0, | |||
"id": 7 | |||
} | |||
], | |||
"leftModuleId": 3606136179759592, | |||
"rightModuleId": 2, | |||
"leftModuleId": 2, | |||
"rightModuleId": 5726895899473528, | |||
"pos": [ | |||
8, | |||
9, | |||
0 | |||
] | |||
}, | |||
{ | |||
"id": 3606136179759592, | |||
"id": 1, | |||
"plugin": "Cardinal", | |||
"model": "HostAudio2", | |||
"version": "2.0", | |||
"params": [ | |||
{ | |||
"value": 0.79432821273803711, | |||
"id": 0 | |||
} | |||
], | |||
"leftModuleId": 4828178296911509, | |||
"rightModuleId": 4, | |||
"data": { | |||
"dcFilter": true | |||
}, | |||
"pos": [ | |||
30, | |||
0 | |||
] | |||
}, | |||
{ | |||
"id": 2, | |||
"plugin": "Cardinal", | |||
"model": "HostMIDI", | |||
"version": "2.0", | |||
"params": [], | |||
"rightModuleId": 7249509538355161, | |||
"rightModuleId": 8601159184541723, | |||
"data": { | |||
"dcFilter": false | |||
"pwRange": 0.0, | |||
"smooth": false, | |||
"channels": 1, | |||
"polyMode": 0, | |||
"lastPitch": 8192, | |||
"lastMod": 0, | |||
"inputChannel": 0, | |||
"outputChannel": 0 | |||
}, | |||
"pos": [ | |||
0, | |||
0 | |||
] | |||
}, | |||
{ | |||
"id": 4, | |||
"plugin": "Cardinal", | |||
"model": "HostParameters", | |||
"version": "2.0", | |||
"params": [], | |||
"leftModuleId": 1, | |||
"rightModuleId": 1202678850202654, | |||
"data": { | |||
"smooth": true | |||
}, | |||
"pos": [ | |||
38, | |||
0 | |||
] | |||
}, | |||
{ | |||
"id": 1202678850202654, | |||
"plugin": "Cardinal", | |||
"model": "HostParametersMap", | |||
"version": "2.0", | |||
"params": [], | |||
"leftModuleId": 4, | |||
"rightModuleId": 8712245256622475, | |||
"data": { | |||
"maps": [ | |||
{ | |||
"hostParamId": 255, | |||
"inverted": false, | |||
"smooth": true, | |||
"moduleId": -1, | |||
"paramId": 0 | |||
} | |||
] | |||
}, | |||
"pos": [ | |||
47, | |||
0 | |||
] | |||
} | |||
], | |||
"cables": [] | |||
"cables": [ | |||
{ | |||
"id": 5155876120487880, | |||
"outputModuleId": 2, | |||
"outputId": 1, | |||
"inputModuleId": 5726895899473528, | |||
"inputId": 4, | |||
"color": "#ff9352" | |||
}, | |||
{ | |||
"id": 781753834216137, | |||
"outputModuleId": 2, | |||
"outputId": 6, | |||
"inputModuleId": 5726895899473528, | |||
"inputId": 5, | |||
"color": "#ffd452" | |||
}, | |||
{ | |||
"id": 3464471860196875, | |||
"outputModuleId": 5726895899473528, | |||
"outputId": 0, | |||
"inputModuleId": 4828178296911509, | |||
"inputId": 0, | |||
"color": "#e8ff52" | |||
}, | |||
{ | |||
"id": 739552540616113, | |||
"outputModuleId": 4828178296911509, | |||
"outputId": 0, | |||
"inputModuleId": 1, | |||
"inputId": 0, | |||
"color": "#52beff" | |||
}, | |||
{ | |||
"id": 6701970185765111, | |||
"outputModuleId": 2, | |||
"outputId": 0, | |||
"inputModuleId": 8601159184541723, | |||
"inputId": 0, | |||
"color": "#ff5252" | |||
}, | |||
{ | |||
"id": 6959800657121782, | |||
"outputModuleId": 2, | |||
"outputId": 2, | |||
"inputModuleId": 8601159184541723, | |||
"inputId": 1, | |||
"color": "#52ff7d" | |||
}, | |||
{ | |||
"id": 1598271319373837, | |||
"outputModuleId": 8601159184541723, | |||
"outputId": 0, | |||
"inputModuleId": 4828178296911509, | |||
"inputId": 1, | |||
"color": "#a8ff52" | |||
} | |||
] | |||
} |
@@ -222,25 +222,51 @@ struct HostAudio2 : HostAudio<2> { | |||
valueR = 0.0f; | |||
} | |||
const uint32_t j = internalDataFrame++; | |||
internalDataBufferL[j] = valueL; | |||
internalDataBufferR[j] = valueR; | |||
if (pcontext->variant == kCardinalVariantMini) | |||
{ | |||
const uint32_t j = internalDataFrame++; | |||
internalDataBufferL[j] = valueL; | |||
internalDataBufferR[j] = valueR; | |||
if (internalDataFrame == 4) | |||
{ | |||
internalDataFrame = 0; | |||
if (resetMeters) | |||
gainMeterL = gainMeterR = 0.0f; | |||
if (internalDataFrame == 128) | |||
gainMeterL = std::max(gainMeterL, d_findMaxNormalizedFloat<4>(internalDataBufferL)); | |||
if (in2connected) | |||
gainMeterR = std::max(gainMeterR, d_findMaxNormalizedFloat<4>(internalDataBufferR)); | |||
else | |||
gainMeterR = gainMeterL; | |||
resetMeters = false; | |||
} | |||
} | |||
else | |||
{ | |||
internalDataFrame = 0; | |||
const uint32_t j = internalDataFrame++; | |||
internalDataBufferL[j] = valueL; | |||
internalDataBufferR[j] = valueR; | |||
if (resetMeters) | |||
gainMeterL = gainMeterR = 0.0f; | |||
if (internalDataFrame == 128) | |||
{ | |||
internalDataFrame = 0; | |||
if (resetMeters) | |||
gainMeterL = gainMeterR = 0.0f; | |||
gainMeterL = std::max(gainMeterL, d_findMaxNormalizedFloat128(internalDataBufferL)); | |||
gainMeterL = std::max(gainMeterL, d_findMaxNormalizedFloat128(internalDataBufferL)); | |||
if (in2connected) | |||
gainMeterR = std::max(gainMeterR, d_findMaxNormalizedFloat128(internalDataBufferR)); | |||
else | |||
gainMeterR = gainMeterL; | |||
if (in2connected) | |||
gainMeterR = std::max(gainMeterR, d_findMaxNormalizedFloat128(internalDataBufferR)); | |||
else | |||
gainMeterR = gainMeterL; | |||
resetMeters = false; | |||
resetMeters = false; | |||
} | |||
} | |||
#endif | |||
} | |||
@@ -52,6 +52,37 @@ extern Model* modelTextEditor; | |||
extern std::vector<Model*> hostTerminalModels; | |||
/* | |||
* Find the highest absolute and normalized value within a float array. | |||
*/ | |||
template<std::size_t size> | |||
static inline | |||
float d_findMaxNormalizedFloat(const float floats[size]) | |||
{ | |||
static constexpr const float kEmptyFloats[size] = {}; | |||
if (std::memcmp(floats, kEmptyFloats, sizeof(float)*size) == 0) | |||
return 0.f; | |||
float tmp, maxf2 = std::abs(floats[0]); | |||
for (std::size_t i=1; i<size; ++i) | |||
{ | |||
if (!std::isfinite(floats[i])) | |||
__builtin_unreachable(); | |||
tmp = std::abs(floats[i]); | |||
if (tmp > maxf2) | |||
maxf2 = tmp; | |||
} | |||
if (maxf2 > 1.f) | |||
maxf2 = 1.f; | |||
return maxf2; | |||
} | |||
/* | |||
* Find the highest absolute and normalized value within a float array. | |||
*/ | |||
@@ -61,7 +92,7 @@ float d_findMaxNormalizedFloat128(const float floats[128]) | |||
static constexpr const float kEmptyFloats[128] = {}; | |||
if (std::memcmp(floats, kEmptyFloats, sizeof(float)*128) == 0) | |||
return 0.0f; | |||
return 0.f; | |||
float tmp, maxf2 = std::abs(floats[0]); | |||
@@ -76,8 +107,8 @@ float d_findMaxNormalizedFloat128(const float floats[128]) | |||
maxf2 = tmp; | |||
} | |||
if (maxf2 > 1.0f) | |||
maxf2 = 1.0f; | |||
if (maxf2 > 1.f) | |||
maxf2 = 1.f; | |||
return maxf2; | |||
} |
@@ -311,9 +311,12 @@ endif | |||
PLUGIN_FILES += $(filter-out Fundamental/src/plugin.cpp,$(wildcard Fundamental/src/*.cpp)) | |||
PLUGIN_FILES += Fundamental/src/dr_wav.c | |||
MINIPLUGIN_FILES += Fundamental/src/ADSR.cpp | |||
MINIPLUGIN_FILES += Fundamental/src/LFO.cpp | |||
MINIPLUGIN_FILES += Fundamental/src/Noise.cpp | |||
MINIPLUGIN_FILES += Fundamental/src/Random.cpp | |||
MINIPLUGIN_FILES += Fundamental/src/Scope.cpp | |||
MINIPLUGIN_FILES += Fundamental/src/VCA-1.cpp | |||
MINIPLUGIN_FILES += Fundamental/src/VCF.cpp | |||
MINIPLUGIN_FILES += Fundamental/src/VCMixer.cpp | |||
MINIPLUGIN_FILES += Fundamental/src/VCO.cpp | |||
@@ -209,13 +209,16 @@ static void initStatic__Fundamental() | |||
const StaticPluginLoader spl(p, "Fundamental"); | |||
if (spl.ok()) | |||
{ | |||
p->addModel(modelADSR); | |||
p->addModel(modelLFO); | |||
p->addModel(modelNoise); | |||
p->addModel(modelRandom); | |||
p->addModel(modelScope); | |||
p->addModel(modelVCA_1); | |||
p->addModel(modelVCF); | |||
p->addModel(modelVCMixer); | |||
p->addModel(modelVCO); | |||
spl.removeModule("8vert"); | |||
spl.removeModule("ADSR"); | |||
spl.removeModule("Delay"); | |||
spl.removeModule("LFO2"); | |||
spl.removeModule("Merge"); | |||
@@ -226,14 +229,11 @@ static void initStatic__Fundamental() | |||
spl.removeModule("Pulses"); | |||
spl.removeModule("Quantizer"); | |||
spl.removeModule("SEQ3"); | |||
spl.removeModule("Scope"); | |||
spl.removeModule("SequentialSwitch1"); | |||
spl.removeModule("SequentialSwitch2"); | |||
spl.removeModule("Split"); | |||
spl.removeModule("Sum"); | |||
spl.removeModule("VCA"); | |||
spl.removeModule("VCA-1"); | |||
spl.removeModule("VCO"); | |||
spl.removeModule("VCO2"); | |||
} | |||
} | |||
@@ -16,4 +16,4 @@ | |||
*/ | |||
#define CARDINAL_COMMON_UI_ONLY | |||
#include "CardinalCommon.cpp" | |||
#include "../CardinalCommon.cpp" |
@@ -39,8 +39,8 @@ | |||
#define DISTRHO_UI_FILE_BROWSER 1 | |||
#define DISTRHO_UI_USE_NANOVG 1 | |||
#define DISTRHO_UI_USER_RESIZABLE 1 | |||
#define DISTRHO_UI_DEFAULT_WIDTH 1228 | |||
#define DISTRHO_UI_DEFAULT_HEIGHT 666 | |||
#define DISTRHO_UI_DEFAULT_WIDTH 1000 | |||
#define DISTRHO_UI_DEFAULT_HEIGHT 600 | |||
#define DISTRHO_PLUGIN_IS_SYNTH 0 | |||
#define DISTRHO_PLUGIN_NUM_INPUTS CARDINAL_NUM_AUDIO_INPUTS | |||
#define DISTRHO_PLUGIN_NUM_OUTPUTS CARDINAL_NUM_AUDIO_OUTPUTS | |||
@@ -52,7 +52,7 @@ | |||
static const constexpr uint kCardinalStateBaseCount = 3; // patch, screenshot, comment | |||
#ifndef HEADLESS | |||
#if CARDINAL_VARIANT_MINI || !defined(HEADLESS) | |||
# include "extra/ScopedValueSetter.hpp" | |||
# include "WindowParameters.hpp" | |||
static const constexpr uint kCardinalStateCount = kCardinalStateBaseCount + 2; // moduleInfos, windowSize | |||
@@ -163,7 +163,7 @@ class CardinalPlugin : public CardinalBasePlugin | |||
struct { | |||
String comment; | |||
String screenshot; | |||
#ifndef HEADLESS | |||
#if CARDINAL_VARIANT_MINI || !defined(HEADLESS) | |||
String windowSize; | |||
#endif | |||
} fState; | |||
@@ -172,7 +172,7 @@ class CardinalPlugin : public CardinalBasePlugin | |||
bool fWasBypassed; | |||
MidiEvent bypassMidiEvents[16]; | |||
#ifndef HEADLESS | |||
#if CARDINAL_VARIANT_MINI || !defined(HEADLESS) | |||
// real values, not VCV interpreted ones | |||
float fWindowParameters[kWindowParameterCount]; | |||
#endif | |||
@@ -191,7 +191,7 @@ public: | |||
fNextExpectedFrame(0), | |||
fWasBypassed(false) | |||
{ | |||
#ifndef HEADLESS | |||
#if CARDINAL_VARIANT_MINI || !defined(HEADLESS) | |||
fWindowParameters[kWindowParameterShowTooltips] = 1.0f; | |||
fWindowParameters[kWindowParameterCableOpacity] = 50.0f; | |||
fWindowParameters[kWindowParameterCableTension] = 75.0f; | |||
@@ -290,7 +290,7 @@ public: | |||
context->patch->clear(); | |||
// do a little dance to prevent context scene deletion from saving to temp dir | |||
#ifndef HEADLESS | |||
#if CARDINAL_VARIANT_MINI || !defined(HEADLESS) | |||
const ScopedValueSetter<bool> svs(rack::settings::headless, true); | |||
#endif | |||
Engine_setAboutToClose(context->engine); | |||
@@ -419,6 +419,10 @@ protected: | |||
parameter.symbol += String(index + 1); | |||
parameter.unit = "v"; | |||
parameter.hints = kParameterIsAutomatable; | |||
#if CARDINAL_VARIANT_MINI | |||
// TODO is hidden | |||
// parameter.hints |= kParameterIsAutomatable; | |||
#endif | |||
parameter.ranges.def = 0.0f; | |||
parameter.ranges.min = 0.0f; | |||
parameter.ranges.max = 10.0f; | |||
@@ -431,7 +435,7 @@ protected: | |||
return; | |||
} | |||
#ifndef HEADLESS | |||
#if CARDINAL_VARIANT_MINI || !defined(HEADLESS) | |||
switch (index - kModuleParameters - 1) | |||
{ | |||
case kWindowParameterShowTooltips: | |||
@@ -610,7 +614,11 @@ protected: | |||
switch (index) | |||
{ | |||
case 0: | |||
#if CARDINAL_VARIANT_MINI | |||
state.hints = kStateIsHostWritable; | |||
#else | |||
state.hints = kStateIsBase64Blob; | |||
#endif | |||
#if DISTRHO_PLUGIN_WANT_DIRECT_ACCESS | |||
state.hints |= kStateIsOnlyForDSP; | |||
#endif | |||
@@ -620,11 +628,16 @@ protected: | |||
if (const long fileSize = std::ftell(f)) | |||
{ | |||
std::fseek(f, 0, SEEK_SET); | |||
char* const fileContent = new char[fileSize]; | |||
char* const fileContent = new char[fileSize+1]; | |||
if (std::fread(fileContent, fileSize, 1, f) == 1) | |||
{ | |||
fileContent[fileSize] = '\0'; | |||
#if CARDINAL_VARIANT_MINI | |||
state.defaultValue = fileContent; | |||
#else | |||
state.defaultValue = String::asBase64(fileContent, fileSize); | |||
#endif | |||
} | |||
delete[] fileContent; | |||
@@ -675,7 +688,7 @@ protected: | |||
if (index == kModuleParameters) | |||
return context->bypassed ? 1.0f : 0.0f; | |||
#ifndef HEADLESS | |||
#if CARDINAL_VARIANT_MINI || !defined(HEADLESS) | |||
// window related parameters | |||
index -= kModuleParameters + 1; | |||
@@ -702,7 +715,7 @@ protected: | |||
return; | |||
} | |||
#ifndef HEADLESS | |||
#if CARDINAL_VARIANT_MINI || !defined(HEADLESS) | |||
// window related parameters | |||
index -= kModuleParameters + 1; | |||
@@ -716,7 +729,7 @@ protected: | |||
String getState(const char* const key) const override | |||
{ | |||
#ifndef HEADLESS | |||
#if CARDINAL_VARIANT_MINI || !defined(HEADLESS) | |||
if (std::strcmp(key, "moduleInfos") == 0) | |||
{ | |||
json_t* const rootJ = json_object(); | |||
@@ -784,9 +797,12 @@ protected: | |||
context->patch->cleanAutosave(); | |||
// context->history->setSaved(); | |||
#if CARDINAL_VARIANT_MINI | |||
#else | |||
try { | |||
data = rack::system::archiveDirectory(fAutosavePath, 1); | |||
} DISTRHO_SAFE_EXCEPTION_RETURN("getState archiveDirectory", String()); | |||
#endif | |||
} | |||
return String::asBase64(data.data(), data.size()); | |||
@@ -797,10 +813,10 @@ protected: | |||
#if CARDINAL_VARIANT_MINI | |||
if (std::strcmp(key, "param") == 0) | |||
{ | |||
int64_t moduleId = 0; | |||
longlong moduleId = 0; | |||
int paramId = 0; | |||
float paramValue = 0.f; | |||
std::sscanf(value, "%lu:%d:%f", &moduleId, ¶mId, ¶mValue); | |||
std::sscanf(value, "%lld:%d:%f", &moduleId, ¶mId, ¶mValue); | |||
rack::engine::Module* const module = context->engine->getModule(moduleId); | |||
DISTRHO_SAFE_ASSERT_RETURN(module != nullptr,); | |||
@@ -810,7 +826,7 @@ protected: | |||
} | |||
#endif | |||
#ifndef HEADLESS | |||
#if CARDINAL_VARIANT_MINI || !defined(HEADLESS) | |||
if (std::strcmp(key, "moduleInfos") == 0) | |||
{ | |||
json_error_t error; | |||
@@ -869,6 +885,16 @@ protected: | |||
if (fAutosavePath.empty()) | |||
return; | |||
#if CARDINAL_VARIANT_MINI | |||
FILE* const f = std::fopen(rack::system::join(fAutosavePath, "patch.json").c_str(), "w"); | |||
DISTRHO_SAFE_ASSERT_RETURN(f != nullptr,); | |||
rack::system::removeRecursively(fAutosavePath); | |||
rack::system::createDirectories(fAutosavePath); | |||
std::fwrite(value, std::strlen(value)+1, 1, f); | |||
std::fclose(f); | |||
#else | |||
const std::vector<uint8_t> data(d_getChunkFromBase64String(value)); | |||
DISTRHO_SAFE_ASSERT_RETURN(data.size() >= 4,); | |||
@@ -892,6 +918,7 @@ protected: | |||
rack::system::unarchiveToDirectory(data, fAutosavePath); | |||
} DISTRHO_SAFE_EXCEPTION_RETURN("setState unarchiveToDirectory",); | |||
} | |||
#endif | |||
const ScopedContext sc(this); | |||
@@ -139,7 +139,7 @@ void sendParamChangeToRemote(RemoteDetails* const remote, int64_t moduleId, int | |||
{ | |||
#if CARDINAL_VARIANT_MINI | |||
char paramBuf[512] = {}; | |||
std::snprintf(paramBuf, sizeof(paramBuf), "%lu:%d:%f", moduleId, paramId, value); | |||
std::snprintf(paramBuf, sizeof(paramBuf), "%llu:%d:%f", (ulonglong)moduleId, paramId, value); | |||
static_cast<CardinalBaseUI*>(remote->handle)->setState("param", paramBuf); | |||
#elif defined(HAVE_LIBLO) | |||
const lo_address addr = lo_address_new_with_proto(LO_UDP, REMOTE_HOST, CARDINAL_DEFAULT_REMOTE_HOST_PORT); | |||
@@ -159,17 +159,23 @@ void sendFullPatchToRemote(RemoteDetails* const remote) | |||
context->engine->prepareSave(); | |||
context->patch->saveAutosave(); | |||
context->patch->cleanAutosave(); | |||
std::vector<uint8_t> data(rack::system::archiveDirectory(context->patch->autosavePath, 1)); | |||
std::vector<uint8_t> data; | |||
using namespace rack::system; | |||
#if CARDINAL_VARIANT_MINI | |||
try { | |||
data = readFile(join(context->patch->autosavePath, "patch.json")); | |||
} DISTRHO_SAFE_EXCEPTION_RETURN("sendFullPatchToRemote",); | |||
static_cast<CardinalBaseUI*>(remote->handle)->setState("patch", reinterpret_cast<const char*>(data.data())); | |||
#elif defined(HAVE_LIBLO) | |||
try { | |||
data = archiveDirectory(context->patch->autosavePath, 1); | |||
} DISTRHO_SAFE_EXCEPTION_RETURN("sendFullPatchToRemote",); | |||
DISTRHO_SAFE_ASSERT_RETURN(data.size() >= 4,); | |||
#if CARDINAL_VARIANT_MINI | |||
if (char* const patch = String::asBase64(data.data(), data.size()).getAndReleaseBuffer()) | |||
{ | |||
static_cast<CardinalBaseUI*>(remote->handle)->setState("patch", patch); | |||
std::free(patch); | |||
} | |||
#elif defined(HAVE_LIBLO) | |||
const lo_address addr = lo_address_new_with_proto(LO_UDP, REMOTE_HOST, CARDINAL_DEFAULT_REMOTE_HOST_PORT); | |||
DISTRHO_SAFE_ASSERT_RETURN(addr != nullptr,); | |||
@@ -180,7 +186,7 @@ void sendFullPatchToRemote(RemoteDetails* const remote) | |||
} | |||
lo_address_free(addr); | |||
#endif | |||
#endif | |||
} | |||
void sendScreenshotToRemote(RemoteDetails*, const char* const screenshot) | |||
@@ -298,7 +298,7 @@ class CardinalUI : public CardinalBaseUI, | |||
rack::math::Vec lastMousePos; | |||
WindowParameters windowParameters; | |||
int rateLimitStep = 0; | |||
#ifdef DISTRHO_OS_WASM | |||
#if defined(DISTRHO_OS_WASM) && ! CARDINAL_VARIANT_MINI | |||
int8_t counterForFirstIdlePoint = 0; | |||
#endif | |||
#ifdef DPF_RUNTIME_TESTING | |||
@@ -345,7 +345,7 @@ public: | |||
rack::contextSet(context); | |||
#if CARDINAL_VARIANT_MINI | |||
remoteUtils::connectToRemote(); | |||
DISTRHO_SAFE_ASSERT(remoteUtils::connectToRemote()); | |||
// create unique temporary path for this instance | |||
try { | |||
@@ -366,9 +366,17 @@ public: | |||
} | |||
} DISTRHO_SAFE_EXCEPTION("create unique temporary path"); | |||
const float sampleRate = getSampleRate(); | |||
const float sampleRate = 60; // fake audio running at 60 fps | |||
rack::settings::sampleRate = sampleRate; | |||
context->dataIns = new const float*[DISTRHO_PLUGIN_NUM_INPUTS]; | |||
context->dataOuts = new float*[DISTRHO_PLUGIN_NUM_OUTPUTS]; | |||
for (uint32_t i=0; i<DISTRHO_PLUGIN_NUM_INPUTS;++i) | |||
*const_cast<float**>(&context->dataIns[i]) = new float[1]; | |||
for (uint32_t i=0; i<DISTRHO_PLUGIN_NUM_OUTPUTS;++i) | |||
context->dataOuts[i] = new float[1]; | |||
context->bufferSize = 1; | |||
context->sampleRate = sampleRate; | |||
@@ -378,7 +386,7 @@ public: | |||
context->history = new rack::history::State; | |||
context->patch = new rack::patch::Manager; | |||
context->patch->autosavePath = fAutosavePath; | |||
context->patch->templatePath = context->patch->factoryTemplatePath = fInitializer->templatePath; | |||
context->patch->templatePath = context->patch->factoryTemplatePath = fInitializer->factoryTemplatePath; | |||
context->event = new rack::widget::EventState; | |||
context->scene = new rack::app::Scene; | |||
@@ -386,6 +394,7 @@ public: | |||
context->window = new rack::window::Window; | |||
context->patch->loadTemplate(); | |||
context->scene->rackScroll->reset(); | |||
Engine_setRemoteDetails(context->engine, remoteDetails); | |||
@@ -563,7 +572,7 @@ public: | |||
} | |||
#endif | |||
#ifdef DISTRHO_OS_WASM | |||
#if defined(DISTRHO_OS_WASM) && ! CARDINAL_VARIANT_MINI | |||
if (counterForFirstIdlePoint >= 0 && ++counterForFirstIdlePoint == 30) | |||
{ | |||
counterForFirstIdlePoint = -1; | |||
@@ -606,7 +615,11 @@ public: | |||
} | |||
#if CARDINAL_VARIANT_MINI | |||
context->engine->stepBlock(1); | |||
{ | |||
const ScopedContext sc(this); | |||
++context->processCounter; | |||
context->engine->stepBlock(1); | |||
} | |||
#endif | |||
if (windowParameters.rateLimit != 0 && ++rateLimitStep % (windowParameters.rateLimit * 2)) | |||
@@ -702,9 +715,23 @@ protected: | |||
*/ | |||
void parameterChanged(const uint32_t index, const float value) override | |||
{ | |||
// host mapped parameters + bypass | |||
if (index <= kModuleParameters) | |||
// host mapped parameters | |||
if (index < kModuleParameters) | |||
{ | |||
#if CARDINAL_VARIANT_MINI | |||
context->parameters[index] = value; | |||
#endif | |||
return; | |||
} | |||
// bypass | |||
if (index == kModuleParameters) | |||
{ | |||
#if CARDINAL_VARIANT_MINI | |||
context->bypassed = value > 0.5f; | |||
#endif | |||
return; | |||
} | |||
switch (index - kModuleParameters - 1) | |||
{ | |||
@@ -180,7 +180,7 @@ endif | |||
# FIXME | |||
ifeq ($(CARDINAL_VARIANT)$(CIBUILD)$(WASM),nativetruetrue) | |||
ifneq ($(STATIC_BUILD),true) | |||
ifneq ($(OLD_PATH),) | |||
STATIC_CARLA_PLUGIN_LIBS = -lsndfile -lopus -lFLAC -lvorbisenc -lvorbis -logg -lm | |||
endif | |||
endif | |||
@@ -380,6 +380,7 @@ LINK_FLAGS += -sLZ4=1 | |||
ifeq ($(CARDINAL_VARIANT),mini) | |||
LINK_FLAGS += --preload-file=../../bin/CardinalMini.lv2/resources@/resources | |||
# LINK_FLAGS += -sEXPORTED_RUNTIME_METHODS=FS,cwrap | |||
else | |||
LINK_FLAGS += --shell-file=../emscripten/shell.html | |||
ifneq ($(STATIC_BUILD),true) | |||
@@ -135,6 +135,7 @@ struct FileButton : MenuButton { | |||
patchUtils::loadTemplateDialog(); | |||
})); | |||
#if ! CARDINAL_VARIANT_MINI | |||
#ifndef DISTRHO_OS_WASM | |||
menu->addChild(createMenuItem("Open / Import...", RACK_MOD_CTRL_NAME "+O", []() { | |||
patchUtils::loadDialog(); | |||
@@ -164,6 +165,7 @@ struct FileButton : MenuButton { | |||
menu->addChild(createMenuItem("Save and download uncompressed", "", []() { | |||
patchUtils::saveAsDialogUncompressed(); | |||
})); | |||
#endif | |||
#endif | |||
menu->addChild(createMenuItem("Revert", RACK_MOD_CTRL_NAME "+" RACK_MOD_SHIFT_NAME "+O", []() { | |||
@@ -194,6 +196,7 @@ struct FileButton : MenuButton { | |||
} | |||
#endif | |||
#if ! CARDINAL_VARIANT_MINI | |||
#ifndef DISTRHO_OS_WASM | |||
menu->addChild(new ui::MenuSeparator); | |||
@@ -206,6 +209,7 @@ struct FileButton : MenuButton { | |||
patchUtils::saveAsDialogUncompressed(); | |||
})); | |||
#endif | |||
#endif | |||
#if ! CARDINAL_VARIANT_MINI | |||
if (!demoPatches.empty()) | |||
@@ -761,9 +765,14 @@ struct MeterLabel : ui::Label { | |||
// uiLastTime = time; | |||
// } | |||
#if CARDINAL_VARIANT_MINI | |||
text = string::f("%.1f fps", 1.0 / frameDurationAvg); | |||
#else | |||
double meterAverage = APP->engine->getMeterAverage(); | |||
double meterMax = APP->engine->getMeterMax(); | |||
text = string::f("%.1f fps %.1f%% avg %.1f%% max", 1.0 / frameDurationAvg, meterAverage * 100, meterMax * 100); | |||
#endif | |||
Label::step(); | |||
} | |||
}; | |||
@@ -795,9 +804,11 @@ struct MenuBar : widget::OpaqueWidget { | |||
viewButton->text = "View"; | |||
layout->addChild(viewButton); | |||
#if ! CARDINAL_VARIANT_MINI | |||
EngineButton* engineButton = new EngineButton; | |||
engineButton->text = "Engine"; | |||
layout->addChild(engineButton); | |||
#endif | |||
HelpButton* helpButton = new HelpButton; | |||
helpButton->text = "Help"; | |||
@@ -212,7 +212,11 @@ void Scene::step() { | |||
if (remoteDetails->autoDeploy) { | |||
const int actionIndex = APP->history->actionIndex; | |||
const double time = system::getTime(); | |||
if (internal->historyActionIndex != actionIndex && actionIndex > 0 && time - internal->lastSceneChangeTime >= 1.0) { | |||
if (internal->historyActionIndex == -1) { | |||
internal->historyActionIndex = actionIndex; | |||
internal->lastSceneChangeTime = time; | |||
} else if (internal->historyActionIndex != actionIndex && actionIndex > 0 && time - internal->lastSceneChangeTime >= 1.0) { | |||
const std::string& name(APP->history->actions[actionIndex - 1]->name); | |||
if (/*std::abs(internal->historyActionIndex = actionIndex) > 1 ||*/ name != "move knob") { | |||
printf("action '%s'\n", APP->history->actions[actionIndex - 1]->name.c_str()); | |||