Browse Source

Finish jucewrapper details, attempt at AU packaging

Signed-off-by: falkTX <falktx@falktx.com>
tags/22.03
falkTX 3 years ago
parent
commit
ef1d02bbc6
Signed by: falkTX <falktx@falktx.com> GPG Key ID: CDBAA37ABC74FBA0
5 changed files with 486 additions and 91 deletions
  1. +11
    -1
      .github/workflows/build.yml
  2. +1
    -1
      dpf
  3. +90
    -1
      jucewrapper/CMakeLists.txt
  4. +383
    -85
      jucewrapper/CardinalWrapper.cpp
  5. +1
    -3
      src/Makefile.cardinal.mk

+ 11
- 1
.github/workflows/build.yml View File

@@ -336,11 +336,21 @@ jobs:
- name: Build extra dependencies - name: Build extra dependencies
run: | run: |
./deps/PawPaw/bootstrap-cardinal.sh macos-universal ./deps/PawPaw/bootstrap-cardinal.sh macos-universal
- name: Build macOS universal
- name: Build macOS universal (base)
run: | run: |
pushd deps/PawPaw; source local.env macos-universal; popd pushd deps/PawPaw; source local.env macos-universal; popd
make features make features
make NOOPT=true WITH_LTO=true -j $(sysctl -n hw.logicalcpu) make NOOPT=true WITH_LTO=true -j $(sysctl -n hw.logicalcpu)
- name: Build macOS universal (AU using juce)
run: |
pushd deps/PawPaw; source local.env macos-universal; popd
git clone --depth=1 -b master https://github.com/juce-framework/JUCE.git jucewrapper/JUCE
mkdir jucewrapper/build
pushd jucewrapper/build; cmake .. && make -j $(sysctl -n hw.logicalcpu); popd
mv jucewrapper/build/*_artefacts/AU/*.component bin/
- name: Build macOS universal (packaging)
run: |
pushd deps/PawPaw; source local.env macos-universal; popd
./dpf/utils/package-osx-bundles.sh ./dpf/utils/package-osx-bundles.sh
- name: Set sha8 (non-release) - name: Set sha8 (non-release)
if: startsWith(github.ref, 'refs/tags/') != true if: startsWith(github.ref, 'refs/tags/') != true


+ 1
- 1
dpf

@@ -1 +1 @@
Subproject commit 21330021cea0854dc6f21a0c718e0e3692dc441f
Subproject commit 215fc2317efe822abf5eb545f422eedbb473693d

+ 90
- 1
jucewrapper/CMakeLists.txt View File

@@ -49,6 +49,9 @@ set_property(TARGET zita_resampler PROPERTY IMPORTED_LOCATION "${PROJECT_SOURCE_
add_library(sCardinalFX STATIC IMPORTED) add_library(sCardinalFX STATIC IMPORTED)
set_property(TARGET sCardinalFX PROPERTY IMPORTED_LOCATION "${PROJECT_SOURCE_DIR}/../bin/CardinalFX.a") set_property(TARGET sCardinalFX PROPERTY IMPORTED_LOCATION "${PROJECT_SOURCE_DIR}/../bin/CardinalFX.a")


add_library(sCardinalSynth STATIC IMPORTED)
set_property(TARGET sCardinalSynth PROPERTY IMPORTED_LOCATION "${PROJECT_SOURCE_DIR}/../bin/CardinalSynth.a")

add_library(sPlugins STATIC IMPORTED) add_library(sPlugins STATIC IMPORTED)
set_property(TARGET sPlugins PROPERTY IMPORTED_LOCATION "${PROJECT_SOURCE_DIR}/../plugins/plugins.a") set_property(TARGET sPlugins PROPERTY IMPORTED_LOCATION "${PROJECT_SOURCE_DIR}/../plugins/plugins.a")


@@ -110,7 +113,7 @@ juce_add_plugin(CardinalFX
COMPANY_WEBSITE "https://github.com/DISTRHO/Cardinal" COMPANY_WEBSITE "https://github.com/DISTRHO/Cardinal"
DESCRIPTION "Virtual modular synthesizer plugin" DESCRIPTION "Virtual modular synthesizer plugin"
EDITOR_WANTS_KEYBOARD_FOCUS TRUE EDITOR_WANTS_KEYBOARD_FOCUS TRUE
FORMATS Standalone AU
FORMATS Standalone VST3 AU
IS_MIDI_EFFECT FALSE IS_MIDI_EFFECT FALSE
IS_SYNTH FALSE IS_SYNTH FALSE
NEEDS_MIDI_INPUT TRUE NEEDS_MIDI_INPUT TRUE
@@ -130,6 +133,7 @@ target_include_directories(CardinalFX


target_compile_definitions(CardinalFX target_compile_definitions(CardinalFX
PUBLIC PUBLIC
JucePlugin_PreferredChannelConfigurations={2,2}
JUCE_CHECK_MEMORY_LEAKS=0 JUCE_CHECK_MEMORY_LEAKS=0
JUCE_DISABLE_NATIVE_FILECHOOSERS=0 JUCE_DISABLE_NATIVE_FILECHOOSERS=0
JUCE_DISPLAY_SPLASH_SCREEN=0 JUCE_DISPLAY_SPLASH_SCREEN=0
@@ -188,3 +192,88 @@ target_link_libraries(CardinalFX
juce::juce_recommended_warning_flags) juce::juce_recommended_warning_flags)


# Synth variant # Synth variant

juce_add_plugin(CardinalSynth
AU_MAIN_TYPE kAudioUnitType_Generator
COMPANY_COPYRIGHT "GPL-3.0-or-later"
COMPANY_NAME "DISTRHO"
COMPANY_WEBSITE "https://github.com/DISTRHO/Cardinal"
DESCRIPTION "Virtual modular synthesizer plugin"
EDITOR_WANTS_KEYBOARD_FOCUS TRUE
FORMATS Standalone VST3 AU
IS_MIDI_EFFECT FALSE
IS_SYNTH TRUE
NEEDS_MIDI_INPUT TRUE
NEEDS_MIDI_OUTPUT TRUE
PLUGIN_CODE DcnS
PLUGIN_MANUFACTURER_CODE Dstr
PRODUCT_NAME "CardinalSynth")

target_sources(CardinalSynth
PRIVATE
CardinalWrapper.cpp)

target_include_directories(CardinalSynth
PRIVATE
../dpf/distrho
../src/CardinalSynth)

target_compile_definitions(CardinalSynth
PUBLIC
JucePlugin_PreferredChannelConfigurations={0,2}
JUCE_CHECK_MEMORY_LEAKS=0
JUCE_DISABLE_NATIVE_FILECHOOSERS=0
JUCE_DISPLAY_SPLASH_SCREEN=0
JUCE_MODAL_LOOPS_PERMITTED=0
JUCE_USE_CURL=0
JUCE_USE_FLAC=0
JUCE_USE_OGGVORBIS=0
JUCE_USE_XINERAMA=0
JUCE_VST3_CAN_REPLACE_VST2=0
JUCE_ALSA=1
JUCE_DIRECTSOUND=0
JUCE_JACK=1
JUCE_WASAPI=0
JUCE_WEB_BROWSER=0)

target_link_libraries(CardinalSynth
PRIVATE
juce::juce_audio_utils
${STATIC_LIBS_START}
sCardinalSynth
sPlugins
sRack
carla_host_plugin
carla_engine_plugin
carla_plugin
native_plugins
audio_decoder
jackbridge
lilv
rtmempool
sfzero
water
zita_resampler
dgl
libarchive
libjansson
libquickjs
libsamplerate
libspeexdsp
libzstd
${STATIC_LIBS_END}
${GL_LIBRARIES}
${DBUS_LIBRARIES}
-L${LIBLO_LIBRARY_DIRS}
${LIBLO_LIBRARIES}
${SNDFILE_LIBRARIES}
${X11_LIBRARIES}
${XCURSOR_LIBRARIES}
${XEXT_LIBRARIES}
${XRANDR_LIBRARIES}
${EXTRA_LIBS}
-lmagic
PUBLIC
juce::juce_recommended_config_flags
juce::juce_recommended_lto_flags
juce::juce_recommended_warning_flags)

+ 383
- 85
jucewrapper/CardinalWrapper.cpp View File

@@ -23,39 +23,55 @@


START_NAMESPACE_DISTRHO START_NAMESPACE_DISTRHO


#if 0
// --------------------------------------------------------------------------------------------------------------------


// -----------------------------------------------------------------------------------------------------------

class ParameterForDPF : public juce::AudioProcessorParameter
class ParameterFromDPF : public juce::AudioProcessorParameter
{ {
PluginExporter& plugin; PluginExporter& plugin;
const ParameterEnumerationValues& enumValues;
const ParameterRanges& ranges;
const uint32_t hints;
const uint index; const uint index;
bool* const updatedPtr;
mutable juce::StringArray dpfValueStrings;


public: public:
ParameterForDPF(PluginExporter& plugin_, const uint index_)
ParameterFromDPF(PluginExporter& plugin_, const uint index_, bool* const updatedPtr_)
: plugin(plugin_), : plugin(plugin_),
index(index_) {}
enumValues(plugin_.getParameterEnumValues(index_)),
ranges(plugin_.getParameterRanges(index_)),
hints(plugin_.getParameterHints(index_)),
index(index_),
updatedPtr(updatedPtr_) {}

void setValueNotifyingHostFromDPF(const float newValue)
{
setValueNotifyingHost(ranges.getNormalizedValue(newValue));
*updatedPtr = false;
}


protected: protected:
float getValue() const override float getValue() const override
{ {
return plugin.getParameterRanges(index).getNormalizedValue(plugin.getParameterValue(index));
return ranges.getNormalizedValue(plugin.getParameterValue(index));
} }


void setValue(const float newValue) override void setValue(const float newValue) override
{ {
plugin.setParameterValue(index, plugin.getParameterRanges(index).getUnnormalizedValue(newValue));
*updatedPtr = true;
plugin.setParameterValue(index, ranges.getUnnormalizedValue(newValue));
} }


float getDefaultValue() const override float getDefaultValue() const override
{ {
return plugin.getParameterDefault(index);
return ranges.getNormalizedValue(plugin.getParameterDefault(index));
} }


juce::String getName(int) const override
juce::String getName(const int maximumStringLength) const override
{ {
return plugin.getParameterName(index).buffer();
DISTRHO_SAFE_ASSERT_RETURN(maximumStringLength > 0, {});

return juce::String(plugin.getParameterName(index).buffer(), static_cast<size_t>(maximumStringLength));
} }


juce::String getLabel() const override juce::String getLabel() const override
@@ -63,55 +79,214 @@ protected:
return plugin.getParameterUnit(index).buffer(); return plugin.getParameterUnit(index).buffer();
} }


float getValueForText(const juce::String& text) const override
int getNumSteps() const override
{ {
return 0.0f;
}
};
#endif
if (hints & kParameterIsBoolean)
return 2;


// -----------------------------------------------------------------------------------------------------------
if (enumValues.restrictedMode)
return enumValues.count;


class CardinalWrapperProcessor : public juce::AudioProcessor
{
friend class CardinalWrapperEditor;
if (hints & kParameterIsInteger)
return ranges.max - ranges.min;


PluginExporter plugin;
TimePosition timePosition;
return juce::AudioProcessorParameter::getNumSteps();
}


static bool writeMidi(void* ptr, const MidiEvent& midiEvent)
bool isDiscrete() const override
{ {
if (hints & (kParameterIsBoolean|kParameterIsInteger))
return true;

if (enumValues.restrictedMode)
return true;

return false; return false;
} }


static bool requestParameterValueChange(void* ptr, uint32_t index, float value)
bool isBoolean() const override
{ {
return false;
return (hints & kParameterIsBoolean) != 0x0;
} }


static bool updateStateValue(void* ptr, const char* key, const char* value)
juce::String getText(const float normalizedValue, const int maximumStringLength) const override
{ {
return false;
DISTRHO_SAFE_ASSERT_RETURN(maximumStringLength > 0, {});

float value = ranges.getUnnormalizedValue(normalizedValue);

if (hints & kParameterIsBoolean)
{
const float midRange = ranges.min + (ranges.max - ranges.min) * 0.5f;
value = value > midRange ? ranges.max : ranges.min;
}
else if (hints & kParameterIsInteger)
{
value = std::round(value);
}

if (enumValues.restrictedMode)
{
for (uint32_t i=0; i < enumValues.count; ++i)
{
if (d_isEqual(enumValues.values[i].value, value))
return juce::String(enumValues.values[i].label, static_cast<size_t>(maximumStringLength));
}
}

juce::String text;
if (hints & kParameterIsInteger)
text = juce::String(static_cast<int>(value));
else
text = juce::String(value);

return juce::String(text.toRawUTF8(), static_cast<size_t>(maximumStringLength));
}

float getValueForText(const juce::String& text) const override
{
if (enumValues.restrictedMode)
{
for (uint32_t i=0; i < enumValues.count; ++i)
{
if (text == enumValues.values[i].label.buffer())
return ranges.getNormalizedValue(enumValues.values[i].value);
}
}

float value;
if (hints & kParameterIsInteger)
value = std::atoi(text.toRawUTF8());
else
value = std::atof(text.toRawUTF8());

return ranges.getFixedAndNormalizedValue(value);
}

bool isAutomatable() const override
{
return (hints & kParameterIsAutomatable) != 0x0;
}

juce::String getCurrentValueAsText() const override
{
const float value = plugin.getParameterValue(index);

if (enumValues.restrictedMode)
{
for (uint32_t i=0; i < enumValues.count; ++i)
{
if (d_isEqual(enumValues.values[i].value, value))
return juce::String(enumValues.values[i].label);
}
}

if (hints & kParameterIsInteger)
return juce::String(static_cast<int>(value));

return juce::String(value);
}

juce::StringArray getAllValueStrings() const override
{
if (dpfValueStrings.size() != 0)
return dpfValueStrings;

if (enumValues.restrictedMode)
{
for (uint32_t i=0; i < enumValues.count; ++i)
dpfValueStrings.add(enumValues.values[i].label.buffer());

return dpfValueStrings;
}

if (hints & kParameterIsBoolean)
{
if (hints & kParameterIsInteger)
{
dpfValueStrings.add(juce::String(static_cast<int>(ranges.min)));
dpfValueStrings.add(juce::String(static_cast<int>(ranges.max)));
}
else
{
dpfValueStrings.add(juce::String(ranges.min));
dpfValueStrings.add(juce::String(ranges.max));
}
}
else if (hints & kParameterIsInteger)
{
const int imin = static_cast<int>(ranges.min);
const int imax = static_cast<int>(ranges.max);

for (int i=imin; i<=imax; ++i)
dpfValueStrings.add(juce::String(i));
}

return dpfValueStrings;
} }
};

// --------------------------------------------------------------------------------------------------------------------

// unused in cardinal
static constexpr const requestParameterValueChangeFunc nullRequestParameterValueChangeFunc = nullptr;

// only needed for headless builds, which this wrapper never builds for
static constexpr const updateStateValueFunc nullUpdateStateValueFunc = nullptr;

// DSP/processor implementation
class CardinalWrapperProcessor : public juce::AudioProcessor
{
friend class CardinalWrapperEditor;

PluginExporter plugin;
MidiEvent midiEvents[kMaxMidiEvents];
TimePosition timePosition;
const uint32_t parameterCount;

juce::AudioProcessorParameter* bypassParameter;
juce::MidiBuffer* currentMidiMessages;
bool* updatedParameters;


public: public:
CardinalWrapperProcessor() CardinalWrapperProcessor()
: plugin(this, writeMidi, requestParameterValueChange, updateStateValue)
: plugin(this, writeMidiFunc, nullRequestParameterValueChangeFunc, nullUpdateStateValueFunc),
parameterCount(plugin.getParameterCount()),
bypassParameter(nullptr),
currentMidiMessages(nullptr),
updatedParameters(nullptr)
{ {
if (const double sampleRate = getSampleRate()) if (const double sampleRate = getSampleRate())
plugin.setSampleRate(sampleRate); plugin.setSampleRate(sampleRate);


if (const int blockSize = getBlockSize())
plugin.setBufferSize(blockSize);
if (const int samplesPerBlock = getBlockSize())
if (samplesPerBlock > 0)
plugin.setBufferSize(static_cast<uint32_t>(samplesPerBlock));

getBypassParameter();

if (parameterCount != 0)
{
updatedParameters = new bool[parameterCount];
std::memset(updatedParameters, 0, sizeof(bool)*parameterCount);

for (uint i=0; i<parameterCount; ++i)
{
ParameterFromDPF* const param = new ParameterFromDPF(plugin, i, updatedParameters + i);
addParameter(param);


// for (uint i=0; i<plugin.getParameterCount(); ++i)
// addParameter(new ParameterForDPF(plugin, i));
if (plugin.getParameterDesignation(i) == kParameterDesignationBypass)
bypassParameter = param;
}
}
} }


~CardinalWrapperProcessor() override ~CardinalWrapperProcessor() override
{ {
delete[] updatedParameters;
} }


protected:
const juce::String getName() const override const juce::String getName() const override
{ {
return plugin.getName(); return plugin.getName();
@@ -122,11 +297,13 @@ public:
return juce::StringArray(plugin.getLabel()); return juce::StringArray(plugin.getLabel());
} }


void prepareToPlay(double sampleRate, int samplesPerBlock) override
void prepareToPlay(const double sampleRate, const int samplesPerBlock) override
{ {
DISTRHO_SAFE_ASSERT_RETURN(samplesPerBlock > 0,);

plugin.deactivateIfNeeded(); plugin.deactivateIfNeeded();
plugin.setSampleRate(sampleRate); plugin.setSampleRate(sampleRate);
plugin.setBufferSize(samplesPerBlock);
plugin.setBufferSize(static_cast<uint32_t>(samplesPerBlock));
plugin.activate(); plugin.activate();
} }


@@ -137,8 +314,33 @@ public:


void processBlock(juce::AudioBuffer<float>& buffer, juce::MidiBuffer& midiMessages) override void processBlock(juce::AudioBuffer<float>& buffer, juce::MidiBuffer& midiMessages) override
{ {
const int numSamples = buffer.getNumSamples();
DISTRHO_SAFE_ASSERT_INT_RETURN(numSamples > 0, numSamples, midiMessages.clear());

uint32_t midiEventCount = 0;

for (const juce::MidiMessageMetadata midiMessage : midiMessages)
{
DISTRHO_SAFE_ASSERT_CONTINUE(midiMessage.numBytes > 0);
DISTRHO_SAFE_ASSERT_CONTINUE(midiMessage.samplePosition >= 0);

if (midiMessage.numBytes > static_cast<int>(MidiEvent::kDataSize))
continue;

MidiEvent& midiEvent(midiEvents[midiEventCount++]);

midiEvent.frame = static_cast<uint32_t>(midiMessage.samplePosition);
midiEvent.size = (static_cast<uint8_t>(midiMessage.numBytes));
std::memcpy(midiEvent.data, midiMessage.data, midiEvent.size);

if (midiEventCount == kMaxMidiEvents)
break;
}

midiMessages.clear(); midiMessages.clear();


const juce::ScopedValueSetter<juce::MidiBuffer*> cvs(currentMidiMessages, &midiMessages, nullptr);

juce::AudioPlayHead* const playhead = getPlayHead(); juce::AudioPlayHead* const playhead = getPlayHead();
juce::AudioPlayHead::CurrentPositionInfo posInfo; juce::AudioPlayHead::CurrentPositionInfo posInfo;


@@ -151,7 +353,7 @@ public:
timePosition.bbt.ticksPerBeat = 1920.0; timePosition.bbt.ticksPerBeat = 1920.0;


if (posInfo.timeInSamples >= 0) if (posInfo.timeInSamples >= 0)
timePosition.frame = posInfo.timeInSamples;
timePosition.frame = static_cast<uint64_t>(posInfo.timeInSamples);
else else
timePosition.frame = 0; timePosition.frame = 0;


@@ -188,9 +390,6 @@ public:


plugin.setTimePosition(timePosition); plugin.setTimePosition(timePosition);


const int numSamples = buffer.getNumSamples();
DISTRHO_SAFE_ASSERT_INT_RETURN(numSamples > 0, numSamples,);

DISTRHO_SAFE_ASSERT_RETURN(buffer.getNumChannels() == 2,); DISTRHO_SAFE_ASSERT_RETURN(buffer.getNumChannels() == 2,);


const float* audioBufferIn[2]; const float* audioBufferIn[2];
@@ -200,9 +399,12 @@ public:
audioBufferOut[0] = buffer.getWritePointer(0); audioBufferOut[0] = buffer.getWritePointer(0);
audioBufferOut[1] = buffer.getWritePointer(1); audioBufferOut[1] = buffer.getWritePointer(1);


plugin.run(audioBufferIn, audioBufferOut, numSamples, nullptr, 0);
plugin.run(audioBufferIn, audioBufferOut, static_cast<uint32_t>(numSamples), midiEvents, midiEventCount);
} }


// fix compiler warning
void processBlock(juce::AudioBuffer<double>&, juce::MidiBuffer&) override {}

double getTailLengthSeconds() const override double getTailLengthSeconds() const override
{ {
return 0.0; return 0.0;
@@ -218,6 +420,11 @@ public:
return true; return true;
} }


juce::AudioProcessorParameter* getBypassParameter() const override
{
return nullptr;
}

juce::AudioProcessorEditor* createEditor() override; juce::AudioProcessorEditor* createEditor() override;


bool hasEditor() const override bool hasEditor() const override
@@ -227,7 +434,7 @@ public:


int getNumPrograms() override int getNumPrograms() override
{ {
return 0;
return 1;
} }


int getCurrentProgram() override int getCurrentProgram() override
@@ -241,7 +448,7 @@ public:


const juce::String getProgramName(int) override const juce::String getProgramName(int) override
{ {
return {};
return "Default";
} }


void changeProgramName(int, const juce::String&) override void changeProgramName(int, const juce::String&) override
@@ -250,50 +457,80 @@ public:


void getStateInformation(juce::MemoryBlock& destData) override void getStateInformation(juce::MemoryBlock& destData) override
{ {
juce::XmlElement xmlState("CardinalState");

for (uint32_t i=0; i<parameterCount; ++i)
xmlState.setAttribute(plugin.getParameterSymbol(i).buffer(), plugin.getParameterValue(i));

for (uint32_t i=0, stateCount=plugin.getStateCount(); i<stateCount; ++i)
{
const String& key(plugin.getStateKey(i));
xmlState.setAttribute(key.buffer(), plugin.getStateValue(key).buffer());
}

copyXmlToBinary(xmlState, destData);
} }


void setStateInformation(const void* data, int sizeInBytes) override
void setStateInformation(const void* const data, const int sizeInBytes) override
{ {
}
};
std::unique_ptr<juce::XmlElement> xmlState(getXmlFromBinary(data, sizeInBytes));
DISTRHO_SAFE_ASSERT_RETURN(xmlState.get() != nullptr,);


// -----------------------------------------------------------------------------------------------------------
const juce::Array<juce::AudioProcessorParameter*>& parameters(getParameters());


class CardinalWrapperEditor : public juce::AudioProcessorEditor,
private juce::Timer
{
UIExporter* ui;
void* const dspPtr;
for (uint32_t i=0; i<parameterCount; ++i)
{
const double value = xmlState->getDoubleAttribute(plugin.getParameterSymbol(i).buffer(),
plugin.getParameterDefault(i));
const float normalizedValue = plugin.getParameterRanges(i).getFixedAndNormalizedValue(value);
parameters.getUnchecked(static_cast<int>(i))->setValueNotifyingHost(normalizedValue);
}


static void editParamFunc(void* ptr, uint32_t rindex, bool started) {}
static void setParamFunc(void* ptr, uint32_t rindex, float value) {}
static void setStateFunc(void* ptr, const char* key, const char* value) {}
static void sendNoteFunc(void* ptr, uint8_t channel, uint8_t note, uint8_t velo) {}
for (uint32_t i=0, stateCount=plugin.getStateCount(); i<stateCount; ++i)
{
const String& key(plugin.getStateKey(i));
const juce::String value = xmlState->getStringAttribute(key.buffer(),
plugin.getStateDefaultValue(i).buffer());
plugin.setState(key, value.toRawUTF8());
}
}


static void setSizeFunc(void* ptr, uint width, uint height)
private:
static bool writeMidiFunc(void* const ptr, const MidiEvent& midiEvent)
{ {
CardinalWrapperEditor* const editor = static_cast<CardinalWrapperEditor*>(ptr);
DISTRHO_SAFE_ASSERT_RETURN(editor != nullptr,);
CardinalWrapperProcessor* const processor = static_cast<CardinalWrapperProcessor*>(ptr);
DISTRHO_SAFE_ASSERT_RETURN(processor != nullptr, false);


#ifdef DISTRHO_OS_MAC
UIExporter* const ui = editor->ui;
DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr,);
const uint8_t* const data = midiEvent.size > MidiEvent::kDataSize ? midiEvent.dataExt : midiEvent.data;
return processor->currentMidiMessages->addEvent(data,
static_cast<int>(midiEvent.size),
static_cast<int>(midiEvent.frame));
}
};


const double scaleFactor = ui->getScaleFactor();
width /= scaleFactor;
height /= scaleFactor;
#endif
// --------------------------------------------------------------------------------------------------------------------


editor->setSize(width, height);
}
// unused in cardinal
static constexpr const sendNoteFunc nullSendNoteFunc = nullptr;

// unwanted, juce file dialogs are ugly
static constexpr const fileRequestFunc nullFileRequestFunc = nullptr;

// UI/editor implementation
class CardinalWrapperEditor : public juce::AudioProcessorEditor,
private juce::Timer
{
CardinalWrapperProcessor& cardinalProcessor;


static bool fileRequestFunc(void* ptr, const char* key) { return false; }
UIExporter* ui;
void* const dspPtr;


public: public:
CardinalWrapperEditor(CardinalWrapperProcessor& cardinalProcessor)
: juce::AudioProcessorEditor(cardinalProcessor),
CardinalWrapperEditor(CardinalWrapperProcessor& cardinalProc)
: juce::AudioProcessorEditor(cardinalProc),
cardinalProcessor(cardinalProc),
ui(nullptr), ui(nullptr),
dspPtr(cardinalProcessor.plugin.getInstancePointer())
dspPtr(cardinalProc.plugin.getInstancePointer())
{ {
setOpaque(true); setOpaque(true);
setResizable(true, false); setResizable(true, false);
@@ -309,8 +546,21 @@ public:
delete ui; delete ui;
} }


protected:
void timerCallback() override void timerCallback() override
{ {
if (ui == nullptr)
return;

for (uint32_t i=0; i<cardinalProcessor.parameterCount; ++i)
{
if (cardinalProcessor.updatedParameters[i])
{
cardinalProcessor.updatedParameters[i] = false;
ui->parameterChanged(i, cardinalProcessor.plugin.getParameterValue(i));
}
}

repaint(); repaint();
} }


@@ -318,30 +568,27 @@ public:
{ {
if (ui == nullptr) if (ui == nullptr)
{ {
auto peer = getPeer();
d_stdout("peer is %p", peer);
juce::ComponentPeer* const peer = getPeer();
DISTRHO_SAFE_ASSERT_RETURN(peer != nullptr,);


auto handle = peer->getNativeHandle();
d_stdout("handle is %p", handle);

auto proc = getAudioProcessor();
d_stdout("proc is %p", proc);
void* const nativeHandle = peer->getNativeHandle();
DISTRHO_SAFE_ASSERT_RETURN(nativeHandle != nullptr,);


ui = new UIExporter(this, ui = new UIExporter(this,
(uintptr_t)handle,
proc->getSampleRate(),
(uintptr_t)nativeHandle,
cardinalProcessor.getSampleRate(),
editParamFunc, editParamFunc,
setParamFunc, setParamFunc,
setStateFunc, setStateFunc,
sendNoteFunc,
nullSendNoteFunc,
setSizeFunc, setSizeFunc,
fileRequestFunc,
nullFileRequestFunc,
nullptr, // bundlePath nullptr, // bundlePath
dspPtr, dspPtr,
0.0 // scaleFactor 0.0 // scaleFactor
); );


if (getAudioProcessor()->wrapperType == juce::AudioProcessor::wrapperType_Standalone)
if (cardinalProcessor.wrapperType == juce::AudioProcessor::wrapperType_Standalone)
{ {
const double scaleFactor = ui->getScaleFactor(); const double scaleFactor = ui->getScaleFactor();
ui->setWindowOffset(4 * scaleFactor, 30 * scaleFactor); ui->setWindowOffset(4 * scaleFactor, 30 * scaleFactor);
@@ -350,6 +597,57 @@ public:


ui->plugin_idle(); ui->plugin_idle();
} }

private:
static void editParamFunc(void* const ptr, const uint32_t index, const bool started)
{
CardinalWrapperEditor* const editor = static_cast<CardinalWrapperEditor*>(ptr);
DISTRHO_SAFE_ASSERT_RETURN(editor != nullptr,);

CardinalWrapperProcessor& cardinalProcessor(editor->cardinalProcessor);

if (started)
cardinalProcessor.getParameters().getUnchecked(static_cast<int>(index))->beginChangeGesture();
else
cardinalProcessor.getParameters().getUnchecked(static_cast<int>(index))->endChangeGesture();
}

static void setParamFunc(void* const ptr, const uint32_t index, const float value)
{
CardinalWrapperEditor* const editor = static_cast<CardinalWrapperEditor*>(ptr);
DISTRHO_SAFE_ASSERT_RETURN(editor != nullptr,);

CardinalWrapperProcessor& cardinalProcessor(editor->cardinalProcessor);
const juce::Array<juce::AudioProcessorParameter*>& parameters(cardinalProcessor.getParameters());
juce::AudioProcessorParameter* const parameter = parameters.getUnchecked(static_cast<int>(index));
static_cast<ParameterFromDPF*>(parameter)->setValueNotifyingHostFromDPF(value);
}

static void setStateFunc(void* const ptr, const char* const key, const char* const value)
{
CardinalWrapperEditor* const editor = static_cast<CardinalWrapperEditor*>(ptr);
DISTRHO_SAFE_ASSERT_RETURN(editor != nullptr,);

CardinalWrapperProcessor& cardinalProcessor(editor->cardinalProcessor);
cardinalProcessor.plugin.setState(key, value);
}

static void setSizeFunc(void* const ptr, uint width, uint height)
{
CardinalWrapperEditor* const editor = static_cast<CardinalWrapperEditor*>(ptr);
DISTRHO_SAFE_ASSERT_RETURN(editor != nullptr,);

#ifdef DISTRHO_OS_MAC
UIExporter* const ui = editor->ui;
DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr,);

const double scaleFactor = ui->getScaleFactor();
width /= scaleFactor;
height /= scaleFactor;
#endif

editor->setSize(static_cast<int>(width), static_cast<int>(height));
}
}; };


juce::AudioProcessorEditor* CardinalWrapperProcessor::createEditor() juce::AudioProcessorEditor* CardinalWrapperProcessor::createEditor()
@@ -357,11 +655,11 @@ juce::AudioProcessorEditor* CardinalWrapperProcessor::createEditor()
return new CardinalWrapperEditor(*this); return new CardinalWrapperEditor(*this);
} }


// -----------------------------------------------------------------------------------------------------------
// --------------------------------------------------------------------------------------------------------------------


END_NAMESPACE_DISTRHO END_NAMESPACE_DISTRHO


// -----------------------------------------------------------------------------------------------------------
// --------------------------------------------------------------------------------------------------------------------


juce::AudioProcessor* createPluginFilter() juce::AudioProcessor* createPluginFilter()
{ {
@@ -371,4 +669,4 @@ juce::AudioProcessor* createPluginFilter()
return new DISTRHO_NAMESPACE::CardinalWrapperProcessor; return new DISTRHO_NAMESPACE::CardinalWrapperProcessor;
} }


// -----------------------------------------------------------------------------------------------------------
// --------------------------------------------------------------------------------------------------------------------

+ 1
- 3
src/Makefile.cardinal.mk View File

@@ -257,10 +257,8 @@ BUILD_CXX_FLAGS += -DCARDINAL_PLUGIN_PREFIX='"$(PREFIX)"'


ifeq ($(CARDINAL_VARIANT),main) ifeq ($(CARDINAL_VARIANT),main)
all: jack lv2 vst3 all: jack lv2 vst3
else ifeq ($(CARDINAL_VARIANT),fx)
all: lv2 vst2 vst3 static
else else
all: lv2 vst2 vst3
all: lv2 vst2 vst3 static
endif endif


CORE_RESOURCES = $(subst ../Rack/res/,,$(wildcard ../Rack/res/ComponentLibrary/*.svg ../Rack/res/fonts/*.ttf)) CORE_RESOURCES = $(subst ../Rack/res/,,$(wildcard ../Rack/res/ComponentLibrary/*.svg ../Rack/res/fonts/*.ttf))


Loading…
Cancel
Save