@@ -25,8 +25,8 @@ | |||
namespace ProjectInfo | |||
{ | |||
const char* const projectName = "Pd Pulp"; | |||
const char* const versionString = "1.0.0"; | |||
const int versionNumber = 0x10000; | |||
const char* const versionString = "0.2.1"; | |||
const int versionNumber = 0x201; | |||
} | |||
#endif | |||
@@ -40,7 +40,7 @@ | |||
#endif | |||
#ifndef JucePlugin_Desc | |||
#define JucePlugin_Desc "a pure data audio plugin runtime environment" | |||
#define JucePlugin_Desc "an audio plugin runtime environment for pure data" | |||
#endif | |||
#ifndef JucePlugin_Manufacturer | |||
#define JucePlugin_Manufacturer "Audiosalt" | |||
@@ -64,13 +64,13 @@ | |||
#define JucePlugin_EditorRequiresKeyboardFocus 1 | |||
#endif | |||
#ifndef JucePlugin_Version | |||
#define JucePlugin_Version 1.0.0 | |||
#define JucePlugin_Version 0.2.1 | |||
#endif | |||
#ifndef JucePlugin_VersionCode | |||
#define JucePlugin_VersionCode 0x10000 | |||
#define JucePlugin_VersionCode 0x201 | |||
#endif | |||
#ifndef JucePlugin_VersionString | |||
#define JucePlugin_VersionString "1.0.0" | |||
#define JucePlugin_VersionString "0.2.1" | |||
#endif | |||
#ifndef JucePlugin_VSTUniqueID | |||
#define JucePlugin_VSTUniqueID JucePlugin_PluginCode | |||
@@ -12,6 +12,7 @@ | |||
#define FLOATPARAMETER_H_INCLUDED | |||
#include "../JuceLibraryCode/JuceHeader.h" | |||
#include "SliderConfig.h" | |||
class FloatParameter : public AudioProcessorParameter | |||
{ | |||
@@ -59,9 +60,15 @@ public: | |||
return text.getFloatValue(); | |||
} | |||
SliderConfig* getSliderConfig () | |||
{ | |||
return &sliderConfig; | |||
} | |||
private: | |||
float defaultValue, value; | |||
String name; | |||
SliderConfig sliderConfig; | |||
}; | |||
@@ -7,12 +7,12 @@ | |||
the "//[xyz]" and "//[/xyz]" sections will be retained when the file is loaded | |||
and re-saved. | |||
Created with Introjucer version: 3.1.1 | |||
Created with Introjucer version: 3.2.0 | |||
------------------------------------------------------------------------------ | |||
The Introjucer is part of the JUCE library - "Jules' Utility Class Extensions" | |||
Copyright 2004-13 by Raw Material Software Ltd. | |||
Copyright (c) 2015 - ROLI Ltd. | |||
============================================================================== | |||
*/ | |||
@@ -28,7 +28,7 @@ | |||
//============================================================================== | |||
MainComponent::MainComponent (PureDataAudioProcessor& processor) | |||
: PureDataAudioProcessorEditor(processor) | |||
: PureDataAudioProcessorEditor(processor), p(&processor) | |||
{ | |||
//[Constructor_pre] You can add your own custom stuff here.. | |||
//[/Constructor_pre] | |||
@@ -83,23 +83,43 @@ MainComponent::MainComponent (PureDataAudioProcessor& processor) | |||
statusField->setColour (TextEditor::textColourId, Colours::black); | |||
statusField->setColour (TextEditor::backgroundColourId, Colour (0x00000000)); | |||
addAndMakeVisible (label = new Label ("new label", | |||
TRANS("PD Pulp"))); | |||
label->setFont (Font ("DIN Alternate", 29.20f, Font::bold)); | |||
label->setJustificationType (Justification::topLeft); | |||
label->setEditable (false, false, false); | |||
label->setColour (Label::textColourId, Colours::white); | |||
label->setColour (TextEditor::textColourId, Colours::black); | |||
label->setColour (TextEditor::backgroundColourId, Colour (0x00000000)); | |||
addAndMakeVisible (title = new Label ("new label", | |||
TRANS("Pd Pulp"))); | |||
title->setFont (Font ("DIN Alternate", 29.20f, Font::bold)); | |||
title->setJustificationType (Justification::topLeft); | |||
title->setEditable (false, false, false); | |||
title->setColour (Label::textColourId, Colours::white); | |||
title->setColour (TextEditor::textColourId, Colours::black); | |||
title->setColour (TextEditor::backgroundColourId, Colour (0x00000000)); | |||
addAndMakeVisible (label2 = new Label ("new label", | |||
addAndMakeVisible (slogan = new Label ("new label", | |||
TRANS("a pure data audio plugin runtime environment"))); | |||
label2->setFont (Font (14.00f, Font::italic)); | |||
label2->setJustificationType (Justification::bottomRight); | |||
label2->setEditable (false, false, false); | |||
label2->setColour (Label::textColourId, Colour (0x94ffffff)); | |||
label2->setColour (TextEditor::textColourId, Colours::black); | |||
label2->setColour (TextEditor::backgroundColourId, Colour (0x00000000)); | |||
slogan->setFont (Font (14.00f, Font::italic)); | |||
slogan->setJustificationType (Justification::bottomRight); | |||
slogan->setEditable (false, false, false); | |||
slogan->setColour (Label::textColourId, Colour (0x94ffffff)); | |||
slogan->setColour (TextEditor::textColourId, Colours::black); | |||
slogan->setColour (TextEditor::backgroundColourId, Colour (0x00000000)); | |||
addAndMakeVisible (version = new Label ("new label", | |||
TRANS("v0.0.0"))); | |||
version->setFont (Font (10.00f, Font::italic)); | |||
version->setJustificationType (Justification::bottomRight); | |||
version->setEditable (false, false, false); | |||
version->setColour (Label::textColourId, Colour (0x46ffffff)); | |||
version->setColour (TextEditor::textColourId, Colours::black); | |||
version->setColour (TextEditor::backgroundColourId, Colour (0x00000000)); | |||
addAndMakeVisible (libraryLink = new HyperlinkButton (TRANS("Patch Library"), | |||
URL ("http://patchstorage.com/platform/pd-pulp/"))); | |||
libraryLink->setTooltip (TRANS("http://patchstorage.com/platform/pd-pulp/")); | |||
libraryLink->setColour (HyperlinkButton::textColourId, Colour (0x53ffffff)); | |||
addAndMakeVisible (libraryLink2 = new HyperlinkButton (TRANS("Wiki"), | |||
URL ("https://github.com/logsol/Pd-Pulp/wiki"))); | |||
libraryLink2->setTooltip (TRANS("https://github.com/logsol/Pd-Pulp/wiki")); | |||
libraryLink2->setButtonText (TRANS("Wiki")); | |||
libraryLink2->setColour (HyperlinkButton::textColourId, Colour (0x53ffffff)); | |||
//[UserPreSize] | |||
@@ -109,11 +129,16 @@ MainComponent::MainComponent (PureDataAudioProcessor& processor) | |||
//[Constructor] You can add your own custom stuff here.. | |||
PureDataAudioProcessor& p = (PureDataAudioProcessor&) processor; | |||
pathField->setText(p.getPatchFile().getFileName(), dontSendNotification); | |||
startTimer(25); | |||
String versionStr; | |||
versionStr << "v" << JucePlugin_VersionString; | |||
version->setText(versionStr, dontSendNotification); | |||
pathField->setText(p->getPatchFile().getFileName(), dontSendNotification); | |||
title->setText(p->getName(), dontSendNotification); | |||
slogan->setText(JucePlugin_Desc, dontSendNotification); | |||
startTimer(25); | |||
//[/Constructor] | |||
} | |||
@@ -137,8 +162,11 @@ MainComponent::~MainComponent() | |||
reloadButton = nullptr; | |||
editButton = nullptr; | |||
statusField = nullptr; | |||
label = nullptr; | |||
label2 = nullptr; | |||
title = nullptr; | |||
slogan = nullptr; | |||
version = nullptr; | |||
libraryLink = nullptr; | |||
libraryLink2 = nullptr; | |||
//[Destructor]. You can add your own custom destruction code here.. | |||
@@ -172,13 +200,16 @@ void MainComponent::resized() | |||
sendSlider8->setBounds (197, 246, 98, 120); | |||
sendSlider9->setBounds (293, 246, 98, 120); | |||
sendSlider10->setBounds (389, 246, 98, 120); | |||
findButton->setBounds (368, 56, 104, 24); | |||
pathField->setBounds (24, 56, 328, 24); | |||
reloadButton->setBounds (352, 90, 64, 20); | |||
editButton->setBounds (424, 90, 48, 20); | |||
statusField->setBounds (25, 91, 311, 17); | |||
label->setBounds (22, 16, 170, 32); | |||
label2->setBounds (168, 24, 304, 16); | |||
findButton->setBounds (358, 60, 120, 24); | |||
pathField->setBounds (24, 60, 312, 24); | |||
reloadButton->setBounds (358, 90, 64, 20); | |||
editButton->setBounds (430, 90, 48, 20); | |||
statusField->setBounds (25, 95, 311, 17); | |||
title->setBounds (22, 16, 170, 32); | |||
slogan->setBounds (168, 19, 304, 16); | |||
version->setBounds (425, 33, 46, 16); | |||
libraryLink->setBounds (369, 34, 64, 16); | |||
libraryLink2->setBounds (336, 34, 27, 16); | |||
//[UserResized] Add your own custom resize handling here.. | |||
//[/UserResized] | |||
@@ -202,14 +233,15 @@ void MainComponent::buttonClicked (Button* buttonThatWasClicked) | |||
{ | |||
pathField->setText(fc.getResult().getFileName(), dontSendNotification); | |||
p.setPatchFile(fc.getResult()); | |||
p.reloadPatch(NULL); | |||
p.reloadPatch(0.0); | |||
p.setParameterDefaults(); | |||
} | |||
//[/UserButtonCode_findButton] | |||
} | |||
else if (buttonThatWasClicked == reloadButton) | |||
{ | |||
//[UserButtonCode_reloadButton] -- add your button handler code here.. | |||
p.reloadPatch(NULL); | |||
p.reloadPatch(0.0); | |||
//[/UserButtonCode_reloadButton] | |||
} | |||
else if (buttonThatWasClicked == editButton) | |||
@@ -228,8 +260,7 @@ void MainComponent::buttonClicked (Button* buttonThatWasClicked) | |||
//[MiscUserCode] You can add your own definitions of your custom methods or any other code here... | |||
void MainComponent::timerCallback() | |||
{ | |||
PureDataAudioProcessor& p = (PureDataAudioProcessor&) processor; | |||
statusField->setText(p.status, dontSendNotification); | |||
statusField->setText(p->status, dontSendNotification); | |||
} | |||
//[/MiscUserCode] | |||
@@ -245,7 +276,7 @@ BEGIN_JUCER_METADATA | |||
<JUCER_COMPONENT documentType="Component" className="MainComponent" componentName="" | |||
parentClasses="public PureDataAudioProcessorEditor, public Timer" | |||
constructorParams="PureDataAudioProcessor& processor" variableInitialisers="PureDataAudioProcessorEditor(processor)" | |||
constructorParams="PureDataAudioProcessor& processor" variableInitialisers="PureDataAudioProcessorEditor(processor), p(&processor)" | |||
snapPixels="8" snapActive="1" snapShown="1" overlayOpacity="0.330" | |||
fixedSize="1" initialWidth="500" initialHeight="385"> | |||
<BACKGROUND backgroundColour="ff303030"/> | |||
@@ -280,37 +311,50 @@ BEGIN_JUCER_METADATA | |||
explicitFocusOrder="0" pos="389 246 98 120" sourceFile="SendSlider.cpp" | |||
constructorParams="10, processor"/> | |||
<TEXTBUTTON name="new button" id="1e5168d1e5fff12c" memberName="findButton" | |||
virtualName="" explicitFocusOrder="0" pos="368 56 104 24" bgColOff="ffadadad" | |||
virtualName="" explicitFocusOrder="0" pos="358 60 120 24" bgColOff="ffadadad" | |||
bgColOn="ff727272" buttonText="Find patch..." connectedEdges="0" | |||
needsCallback="1" radioGroupId="0"/> | |||
<LABEL name="new label" id="90c1e98cfe7db5e9" memberName="pathField" | |||
virtualName="" explicitFocusOrder="0" pos="24 56 328 24" bkgCol="21000000" | |||
virtualName="" explicitFocusOrder="0" pos="24 60 312 24" bkgCol="21000000" | |||
textCol="ffbcbcbc" edTextCol="ff000000" edBkgCol="0" labelText="" | |||
editableSingleClick="0" editableDoubleClick="0" focusDiscardsChanges="0" | |||
fontname="Default font" fontsize="15" bold="0" italic="0" justification="36"/> | |||
<TEXTBUTTON name="new button" id="46837e8b39cdf5ab" memberName="reloadButton" | |||
virtualName="" explicitFocusOrder="0" pos="352 90 64 20" tooltip="Reload the pd patch file." | |||
virtualName="" explicitFocusOrder="0" pos="358 90 64 20" tooltip="Reload the pd patch file." | |||
bgColOff="ffadadad" bgColOn="ff727272" buttonText="Reload" connectedEdges="0" | |||
needsCallback="1" radioGroupId="0"/> | |||
<TEXTBUTTON name="new button" id="fe82abb32a3951b0" memberName="editButton" | |||
virtualName="" explicitFocusOrder="0" pos="424 90 48 20" tooltip="Opens PD editor if existent." | |||
virtualName="" explicitFocusOrder="0" pos="430 90 48 20" tooltip="Opens PD editor if existent." | |||
bgColOff="ffadadad" bgColOn="ff727272" buttonText="Edit" connectedEdges="0" | |||
needsCallback="1" radioGroupId="0"/> | |||
<LABEL name="new label" id="90ee85fe76c3c3e8" memberName="statusField" | |||
virtualName="" explicitFocusOrder="0" pos="25 91 311 17" bkgCol="0" | |||
virtualName="" explicitFocusOrder="0" pos="25 95 311 17" bkgCol="0" | |||
textCol="bcbcbcbc" edTextCol="ff000000" edBkgCol="0" labelText="" | |||
editableSingleClick="0" editableDoubleClick="0" focusDiscardsChanges="0" | |||
fontname="Default font" fontsize="11" bold="0" italic="0" justification="36"/> | |||
<LABEL name="new label" id="4f92306c17723f92" memberName="label" virtualName="" | |||
<LABEL name="new label" id="4f92306c17723f92" memberName="title" virtualName="" | |||
explicitFocusOrder="0" pos="22 16 170 32" textCol="ffffffff" | |||
edTextCol="ff000000" edBkgCol="0" labelText="PD Pulp" editableSingleClick="0" | |||
edTextCol="ff000000" edBkgCol="0" labelText="Pd Pulp" editableSingleClick="0" | |||
editableDoubleClick="0" focusDiscardsChanges="0" fontname="DIN Alternate" | |||
fontsize="29.199999999999999289" bold="1" italic="0" justification="9"/> | |||
<LABEL name="new label" id="eb75ff4acec7a7ab" memberName="label2" virtualName="" | |||
explicitFocusOrder="0" pos="168 24 304 16" textCol="94ffffff" | |||
<LABEL name="new label" id="eb75ff4acec7a7ab" memberName="slogan" virtualName="" | |||
explicitFocusOrder="0" pos="168 19 304 16" textCol="94ffffff" | |||
edTextCol="ff000000" edBkgCol="0" labelText="a pure data audio plugin runtime environment" | |||
editableSingleClick="0" editableDoubleClick="0" focusDiscardsChanges="0" | |||
fontname="Default font" fontsize="14" bold="0" italic="1" justification="18"/> | |||
<LABEL name="new label" id="4479dbe59f1893ef" memberName="version" virtualName="" | |||
explicitFocusOrder="0" pos="425 33 46 16" textCol="46ffffff" | |||
edTextCol="ff000000" edBkgCol="0" labelText="v0.0.0" editableSingleClick="0" | |||
editableDoubleClick="0" focusDiscardsChanges="0" fontname="Default font" | |||
fontsize="10" bold="0" italic="1" justification="18"/> | |||
<HYPERLINKBUTTON name="Patch Library" id="7cd34084675dc20f" memberName="libraryLink" | |||
virtualName="" explicitFocusOrder="0" pos="369 34 64 16" tooltip="http://patchstorage.com/platform/pd-pulp/" | |||
textCol="53ffffff" buttonText="Patch Library" connectedEdges="0" | |||
needsCallback="0" radioGroupId="0" url="http://patchstorage.com/platform/pd-pulp/"/> | |||
<HYPERLINKBUTTON name="Patch Library" id="6742fabf4e69a8c8" memberName="libraryLink2" | |||
virtualName="" explicitFocusOrder="0" pos="336 34 27 16" tooltip="https://github.com/logsol/Pd-Pulp/wiki" | |||
textCol="53ffffff" buttonText="Wiki" connectedEdges="0" needsCallback="0" | |||
radioGroupId="0" url="https://github.com/logsol/Pd-Pulp/wiki"/> | |||
</JUCER_COMPONENT> | |||
END_JUCER_METADATA | |||
@@ -7,12 +7,12 @@ | |||
the "//[xyz]" and "//[/xyz]" sections will be retained when the file is loaded | |||
and re-saved. | |||
Created with Introjucer version: 3.1.1 | |||
Created with Introjucer version: 3.2.0 | |||
------------------------------------------------------------------------------ | |||
The Introjucer is part of the JUCE library - "Jules' Utility Class Extensions" | |||
Copyright 2004-13 by Raw Material Software Ltd. | |||
Copyright (c) 2015 - ROLI Ltd. | |||
============================================================================== | |||
*/ | |||
@@ -59,6 +59,7 @@ public: | |||
private: | |||
//[UserVariables] -- You can add your own custom variables in this section. | |||
void timerCallback(); | |||
PureDataAudioProcessor* p; | |||
//[/UserVariables] | |||
//============================================================================== | |||
@@ -77,8 +78,11 @@ private: | |||
ScopedPointer<TextButton> reloadButton; | |||
ScopedPointer<TextButton> editButton; | |||
ScopedPointer<Label> statusField; | |||
ScopedPointer<Label> label; | |||
ScopedPointer<Label> label2; | |||
ScopedPointer<Label> title; | |||
ScopedPointer<Label> slogan; | |||
ScopedPointer<Label> version; | |||
ScopedPointer<HyperlinkButton> libraryLink; | |||
ScopedPointer<HyperlinkButton> libraryLink2; | |||
//============================================================================== | |||
@@ -13,7 +13,7 @@ | |||
bool PureDataAudioProcessor::otherInstanceAlreadyRunning; | |||
//============================================================================== | |||
PureDataAudioProcessor::PureDataAudioProcessor() | |||
PureDataAudioProcessor::PureDataAudioProcessor() : receiver(¶meterList, this) | |||
{ | |||
for (int i=0; i<10; i++) { | |||
FloatParameter* p = new FloatParameter (0.5, ("Param" + (String) (i+1)).toStdString()); | |||
@@ -25,6 +25,7 @@ PureDataAudioProcessor::PureDataAudioProcessor() | |||
isInstanceLocked = true; | |||
} | |||
PureDataAudioProcessor::otherInstanceAlreadyRunning = true; | |||
cachedSampleRate = getSampleRate(); | |||
} | |||
PureDataAudioProcessor::~PureDataAudioProcessor() | |||
@@ -153,10 +154,24 @@ void PureDataAudioProcessor::processBlock (AudioSampleBuffer& buffer, MidiBuffer | |||
return; | |||
} | |||
// In case we have more outputs than inputs, this code clears any output channels that didn't contain input data, (because these aren't guaranteed to be empty - they may contain garbage). | |||
// I've added this to avoid people getting screaming feedback when they first compile the plugin, but obviously you don't need to this code if your algorithm already fills all the output channels. | |||
for (int i = getTotalNumInputChannels(); i < getTotalNumOutputChannels(); ++i) | |||
pd->receiveMessages(); | |||
// Send host info messages | |||
{ | |||
AudioPlayHead::CurrentPositionInfo info; | |||
getPlayHead()->getCurrentPosition(info); | |||
if (positionInfo.isPlaying != info.isPlaying) { | |||
pd->sendMessage("hostIsPlaying", info.isPlaying ? "true" : "false"); | |||
} | |||
if (positionInfo.bpm != info.bpm) { | |||
pd->sendFloat("hostBpm", (float) info.bpm); | |||
} | |||
positionInfo = info; | |||
} | |||
for (int i = getTotalNumInputChannels(); i < getTotalNumOutputChannels(); ++i) { | |||
buffer.clear (i, 0, buffer.getNumSamples()); | |||
} | |||
int numChannels = jmin (getTotalNumInputChannels(), getTotalNumOutputChannels()); | |||
int len = buffer.getNumSamples(); | |||
@@ -232,7 +247,7 @@ void PureDataAudioProcessor::getStateInformation (MemoryBlock& destData) | |||
// STORE / SAVE | |||
XmlElement xml(getName()); | |||
XmlElement xml(getName().replace(" ", "-")); | |||
// patchfile | |||
XmlElement* patchfileElement = new XmlElement("patchfile"); | |||
@@ -271,7 +286,7 @@ void PureDataAudioProcessor::setStateInformation (const void* data, int sizeInBy | |||
// RESTORE / LOAD | |||
ScopedPointer<XmlElement> xml(getXmlFromBinary(data, sizeInBytes)); | |||
if(xml != 0 && xml->hasTagName(getName())) { | |||
if(xml != 0 && xml->hasTagName(getName().replace(" ", "-"))) { | |||
MemoryOutputStream stream; | |||
xml->writeToStream(stream, "<?xml version=\"1.0\"?>"); | |||
@@ -279,15 +294,12 @@ void PureDataAudioProcessor::setStateInformation (const void* data, int sizeInBy | |||
forEachXmlChildElement (*xml, child) | |||
{ | |||
std::cout << " - load : " << child->getTagName() << std::endl; | |||
//std::cout << " - load : " << child->getTagName() << std::endl; | |||
if(child->hasTagName("patchfile")) { | |||
File path(child->getStringAttribute ("fullpath")); | |||
if (path.exists()) { | |||
patchfile = path; // creates a copy | |||
reloadPatch(NULL); | |||
} else { | |||
// Todo add exclamation mark or something | |||
std::cout << "cant find " << child->getStringAttribute("fullpath") << std::endl; | |||
} | |||
} | |||
@@ -306,6 +318,14 @@ void PureDataAudioProcessor::setStateInformation (const void* data, int sizeInBy | |||
} | |||
} | |||
void PureDataAudioProcessor::setParameterDefaults() | |||
{ | |||
for(size_t i = 0; i < parameterList.size(); i++) { | |||
SliderConfig* sc = getParameterList().getUnchecked(i)->getSliderConfig(); | |||
setParameterNotifyingHost(i, sc->defaultValue); | |||
} | |||
} | |||
void PureDataAudioProcessor::reloadPatch (double sampleRate) | |||
{ | |||
if (isInstanceLocked) { | |||
@@ -313,6 +333,8 @@ void PureDataAudioProcessor::reloadPatch (double sampleRate) | |||
return; | |||
} | |||
resetSliderConfigs(); | |||
if (sampleRate) { | |||
cachedSampleRate = sampleRate; | |||
} else { | |||
@@ -331,13 +353,22 @@ void PureDataAudioProcessor::reloadPatch (double sampleRate) | |||
pdInBuffer.calloc (pd->blockSize() * numChannels); | |||
pdOutBuffer.calloc (pd->blockSize() * numChannels); | |||
// subscribe before openpatch, to be ready at loadbang time | |||
pd->setReceiver(&receiver); | |||
pd->unsubscribeAll(); | |||
for (int i=1; i <= parameterList.size(); i++) { | |||
String identifier; | |||
identifier << receiver.paramIdentifier << i; | |||
pd->subscribe(identifier.toStdString()); | |||
} | |||
if (!patchfile.exists()) { | |||
if (patchfile.getFullPathName().toStdString() != "") { | |||
status = "File does not exist"; | |||
} | |||
// else keeps select patch message | |||
return; | |||
} | |||
@@ -350,13 +381,32 @@ void PureDataAudioProcessor::reloadPatch (double sampleRate) | |||
if (patch.isValid()) { | |||
pd->computeAudio (true); | |||
status = "Patch loaded successfully"; | |||
if(!patchLoadError) { | |||
status = "Patch loaded successfully"; | |||
} | |||
patchLoadError = false; | |||
} else { | |||
status = "Selected patch is not valid, sorry"; | |||
status = "Selected patch is not valid"; | |||
} | |||
} | |||
void PureDataAudioProcessor::resetSliderConfigs() | |||
{ | |||
SliderConfig def; | |||
for (int i=0; i < parameterList.size(); i++) { | |||
FloatParameter* p = parameterList.getUnchecked(i); | |||
SliderConfig* s = p->getSliderConfig(); | |||
s->max = def.max; | |||
s->min = def.min; | |||
s->defaultValue = def.defaultValue; | |||
s->name = def.name + std::to_string(i+1); | |||
s->dirty = def.dirty; | |||
} | |||
} | |||
void PureDataAudioProcessor::setPatchFile(File file) | |||
{ | |||
patchfile = file; | |||
@@ -367,6 +417,11 @@ File PureDataAudioProcessor::getPatchFile() | |||
return patchfile; | |||
} | |||
Array<FloatParameter*> PureDataAudioProcessor::getParameterList() | |||
{ | |||
return parameterList; | |||
} | |||
//============================================================================== | |||
// This creates new instances of the plugin.. | |||
AudioProcessor* JUCE_CALLTYPE createPluginFilter() | |||
@@ -12,6 +12,7 @@ | |||
#define PLUGINPROCESSOR_H_INCLUDED | |||
#include "PdBase.hpp" | |||
#include "Receiver.h" | |||
#include "../JuceLibraryCode/JuceHeader.h" | |||
#include "FloatParameter.h" | |||
@@ -65,24 +66,24 @@ public: | |||
void reloadPatch(double sampleRate); | |||
void setPatchFile(File file); | |||
File getPatchFile(); | |||
void setParameterDefaults(); | |||
Array<FloatParameter*> getParameterList(); | |||
String status = "Select a pure data patch file..."; | |||
static bool otherInstanceAlreadyRunning; | |||
bool isInstanceLocked = false; | |||
Receiver receiver; | |||
bool patchLoadError = false; | |||
private: | |||
void resetSliderConfigs(); | |||
ScopedPointer<pd::PdBase> pd; | |||
int pos; | |||
Array<FloatParameter*> parameterList; | |||
AudioProcessorParameter* freq; | |||
AudioProcessorParameter* volume; | |||
AudioProcessorParameter* del_delay; | |||
AudioProcessorParameter* del_feedback; | |||
AudioProcessorParameter* del_mode_rate; | |||
AudioProcessorParameter* del_mode_depth; | |||
Array<FloatParameter*> parameterList; // no owned array because values are already owned by parent processor | |||
AudioPlayHead::CurrentPositionInfo positionInfo; | |||
File patchfile; | |||
pd::Patch patch; | |||
@@ -0,0 +1,98 @@ | |||
/* | |||
============================================================================== | |||
Receiver.cpp | |||
Created: 21 Aug 2015 3:45:37pm | |||
Author: Karl | |||
============================================================================== | |||
*/ | |||
#include "Receiver.h" | |||
#include "PluginProcessor.h" | |||
Receiver::Receiver(Array<FloatParameter*>* pList, PureDataAudioProcessor* processor) : parameterList(pList), processor(processor) | |||
{ | |||
} | |||
Receiver::~Receiver() | |||
{ | |||
} | |||
void Receiver::setErrorMessage(std::string msg) | |||
{ | |||
processor->patchLoadError = true; | |||
processor->status = msg; | |||
} | |||
void Receiver::receiveMessage(const std::string& dest, const std::string& msg, const pd::List& list) | |||
{ | |||
// Note: only pdpulp_p1 through pdpulp_p10 messages have been subscribed to | |||
String id = dest; | |||
id = id.replace(paramIdentifier, ""); | |||
int index = std::stoi(id.toStdString()); | |||
index--; // remap param number | |||
FloatParameter* p = parameterList->getUnchecked(index); | |||
SliderConfig* s = p->getSliderConfig(); | |||
bool isDirty = false; | |||
if (msg.length() > 0) { | |||
s->name = msg; | |||
isDirty = true; | |||
} | |||
SliderConfig defaults; | |||
float def = defaults.defaultValue, | |||
max = defaults.max, | |||
min = defaults.min, | |||
step = defaults.stepSize; | |||
for (int i=0; i<list.len(); i++) { | |||
if (list.isFloat(i)) { | |||
float v = list.getFloat(i); | |||
switch (i) { | |||
case 0: | |||
def = v; | |||
isDirty = true; | |||
break; | |||
case 1: | |||
max = v; | |||
isDirty = true; | |||
break; | |||
case 2: | |||
min = v; | |||
isDirty = true; | |||
break; | |||
case 3: | |||
step = v; | |||
isDirty = true; | |||
break; | |||
} | |||
} | |||
} | |||
// validate | |||
if (!(min < max)) { | |||
setErrorMessage("Param Error: min value must be higher than max value (" + dest + ", " + msg + ")"); | |||
return; | |||
} | |||
if (!(def < max) && !(def > min)) { | |||
setErrorMessage("Param Error: default value must be between min and max value (" + dest + ", " + msg + ")"); | |||
return; | |||
} | |||
s->stepSize = step; | |||
s->defaultValue = def; | |||
s->min = min; | |||
s->max = max; | |||
s->dirty = isDirty; | |||
} |
@@ -0,0 +1,44 @@ | |||
/* | |||
============================================================================== | |||
Receiver.h | |||
Created: 21 Aug 2015 3:45:37pm | |||
Author: Karl | |||
============================================================================== | |||
*/ | |||
#ifndef RECEIVER_H_INCLUDED | |||
#define RECEIVER_H_INCLUDED | |||
#include <iostream> | |||
#include "PdReceiver.hpp" | |||
#include "PdTypes.hpp" | |||
#include "../JuceLibraryCode/JuceHeader.h" | |||
#include "FloatParameter.h" | |||
//resolve circular dependency | |||
class PureDataAudioProcessor; | |||
class Receiver : public pd::PdReceiver { | |||
public: | |||
Receiver(Array<FloatParameter*>* pList, PureDataAudioProcessor* processor); | |||
virtual ~Receiver(); | |||
void receiveMessage(const std::string& dest, const std::string& msg, const pd::List& list); | |||
const String paramIdentifier = "pdpulp_p"; | |||
private: | |||
Array<FloatParameter*>* parameterList; | |||
PureDataAudioProcessor* processor; | |||
void setErrorMessage(std::string msg); | |||
}; | |||
#endif // RECEIVER_H_INCLUDED | |||
@@ -7,12 +7,12 @@ | |||
the "//[xyz]" and "//[/xyz]" sections will be retained when the file is loaded | |||
and re-saved. | |||
Created with Introjucer version: 3.1.1 | |||
Created with Introjucer version: 4.1.0 | |||
------------------------------------------------------------------------------ | |||
The Introjucer is part of the JUCE library - "Jules' Utility Class Extensions" | |||
Copyright 2004-13 by Raw Material Software Ltd. | |||
Copyright (c) 2015 - ROLI Ltd. | |||
============================================================================== | |||
*/ | |||
@@ -28,7 +28,7 @@ | |||
//[/MiscUserDefs] | |||
//============================================================================== | |||
SendSlider::SendSlider (int index, AudioProcessor& processor) | |||
SendSlider::SendSlider (int index, PureDataAudioProcessor& processor) | |||
: index(index), | |||
processor(processor) | |||
{ | |||
@@ -42,7 +42,10 @@ SendSlider::SendSlider (int index, AudioProcessor& processor) | |||
slider->setColour (Slider::thumbColourId, Colour (0xff5c5c5c)); | |||
slider->setColour (Slider::rotarySliderFillColourId, Colour (0x7fdddddd)); | |||
slider->setColour (Slider::rotarySliderOutlineColourId, Colour (0x66e6e6e6)); | |||
slider->setColour (Slider::textBoxHighlightColourId, Colour (0x40a6a6a6)); | |||
slider->setColour (Slider::textBoxTextColourId, Colour (0xffc1c1c1)); | |||
slider->setColour (Slider::textBoxBackgroundColourId, Colour (0x1effffff)); | |||
slider->setColour (Slider::textBoxHighlightColourId, Colour (0x4ba6a6a6)); | |||
slider->setColour (Slider::textBoxOutlineColourId, Colour (0x00808080)); | |||
slider->addListener (this); | |||
addAndMakeVisible (label = new Label ("label", | |||
@@ -55,6 +58,7 @@ SendSlider::SendSlider (int index, AudioProcessor& processor) | |||
label->setColour (Label::textColourId, Colour (0xffc4c4c4)); | |||
label->setColour (TextEditor::textColourId, Colour (0xffe9e9e9)); | |||
label->setColour (TextEditor::backgroundColourId, Colour (0x00343434)); | |||
label->setColour (TextEditor::highlightColourId, Colour (0x61ffffff)); | |||
label->addListener (this); | |||
@@ -68,7 +72,12 @@ SendSlider::SendSlider (int index, AudioProcessor& processor) | |||
PureDataAudioProcessor& p = (PureDataAudioProcessor&) processor; | |||
String labelText(p.getParameterName(index-1)); | |||
label->setText(labelText, dontSendNotification); | |||
SliderConfig* sc = processor.getParameterList().getUnchecked(index-1)->getSliderConfig(); | |||
slider->setDoubleClickReturnValue(true, sc->defaultValue); | |||
slider->setRange(sc->min, sc->max, sc->stepSize); | |||
slider->setValue(sc->defaultValue); | |||
startTimer(25); | |||
//[/Constructor] | |||
} | |||
@@ -146,7 +155,21 @@ void SendSlider::labelTextChanged (Label* labelThatHasChanged) | |||
void SendSlider::timerCallback() | |||
{ | |||
slider->setValue(processor.getParameter(index-1), NotificationType::dontSendNotification); | |||
SliderConfig* sc = processor.getParameterList().getUnchecked(index-1)->getSliderConfig(); | |||
if (sc->dirty) { | |||
slider->setRange(sc->min, sc->max, sc->stepSize); | |||
slider->setName(sc->name); | |||
slider->setValue(sc->defaultValue, NotificationType::dontSendNotification); | |||
slider->setDoubleClickReturnValue(true, sc->defaultValue); | |||
label->setText(sc->name, NotificationType::dontSendNotification); | |||
processor.setParameterName(index-1, sc->name); | |||
sc->dirty = false; | |||
} | |||
} | |||
//[/MiscUserCode] | |||
@@ -160,22 +183,23 @@ void SendSlider::timerCallback() | |||
BEGIN_JUCER_METADATA | |||
<JUCER_COMPONENT documentType="Component" className="SendSlider" componentName="" | |||
parentClasses="public Component, public Timer" constructorParams="int index, AudioProcessor& processor" | |||
parentClasses="public Component, public Timer" constructorParams="int index, PureDataAudioProcessor& processor" | |||
variableInitialisers="index(index), processor(processor)" | |||
snapPixels="8" snapActive="1" snapShown="1" overlayOpacity="0.330" | |||
fixedSize="1" initialWidth="100" initialHeight="130"> | |||
<BACKGROUND backgroundColour="ffffff"/> | |||
<SLIDER name="slider" id="a814494a82a416fe" memberName="slider" virtualName="" | |||
explicitFocusOrder="0" pos="14 35 71 80" thumbcol="ff5c5c5c" | |||
rotarysliderfill="7fdddddd" rotaryslideroutline="66e6e6e6" textboxhighlight="40a6a6a6" | |||
rotarysliderfill="7fdddddd" rotaryslideroutline="66e6e6e6" textboxtext="ffc1c1c1" | |||
textboxbkgd="1effffff" textboxhighlight="4ba6a6a6" textboxoutline="808080" | |||
min="0" max="1" int="0" style="RotaryVerticalDrag" textBoxPos="TextBoxBelow" | |||
textBoxEditable="1" textBoxWidth="80" textBoxHeight="20" skewFactor="1"/> | |||
<LABEL name="label" id="6f4900c890043ea2" memberName="label" virtualName="" | |||
explicitFocusOrder="0" pos="-4 5 104 24" tooltip="Click to set the name of the corresponding Pure Data receive port." | |||
bkgCol="404040" textCol="ffc4c4c4" edTextCol="ffe9e9e9" edBkgCol="343434" | |||
labelText="Label" editableSingleClick="1" editableDoubleClick="1" | |||
focusDiscardsChanges="0" fontname="Default font" fontsize="15" | |||
bold="0" italic="0" justification="36"/> | |||
hiliteCol="61ffffff" labelText="Label" editableSingleClick="1" | |||
editableDoubleClick="1" focusDiscardsChanges="0" fontname="Default font" | |||
fontsize="15" bold="0" italic="0" justification="36"/> | |||
</JUCER_COMPONENT> | |||
END_JUCER_METADATA | |||
@@ -7,12 +7,12 @@ | |||
the "//[xyz]" and "//[/xyz]" sections will be retained when the file is loaded | |||
and re-saved. | |||
Created with Introjucer version: 3.1.1 | |||
Created with Introjucer version: 3.2.0 | |||
------------------------------------------------------------------------------ | |||
The Introjucer is part of the JUCE library - "Jules' Utility Class Extensions" | |||
Copyright 2004-13 by Raw Material Software Ltd. | |||
Copyright (c) 2015 - ROLI Ltd. | |||
============================================================================== | |||
*/ | |||
@@ -22,6 +22,7 @@ | |||
//[Headers] -- You can add your own extra header files here -- | |||
#include "JuceHeader.h" | |||
#include "PluginProcessor.h" | |||
//[/Headers] | |||
@@ -41,12 +42,12 @@ class SendSlider : public Component, | |||
{ | |||
public: | |||
//============================================================================== | |||
SendSlider (int index, AudioProcessor& processor); | |||
SendSlider (int index, PureDataAudioProcessor& processor); | |||
~SendSlider(); | |||
//============================================================================== | |||
//[UserMethods] -- You can add your own custom methods in this section. | |||
void timerCallback(); | |||
void timerCallback() override; | |||
//[/UserMethods] | |||
void paint (Graphics& g); | |||
@@ -59,7 +60,7 @@ public: | |||
private: | |||
//[UserVariables] -- You can add your own custom variables in this section. | |||
int index; | |||
AudioProcessor& processor; | |||
PureDataAudioProcessor& processor; | |||
//[/UserVariables] | |||
//============================================================================== | |||
@@ -0,0 +1,30 @@ | |||
/* | |||
============================================================================== | |||
SliderConfigMessage.h | |||
Created: 22 Aug 2015 3:06:59pm | |||
Author: Karl | |||
============================================================================== | |||
*/ | |||
#ifndef SLIDERCONFIGMESSAGE_H_INCLUDED | |||
#define SLIDERCONFIGMESSAGE_H_INCLUDED | |||
#include "../JuceLibraryCode/JuceHeader.h" | |||
class SliderConfig { | |||
public: | |||
std::string name = "Param"; | |||
float defaultValue = 0.5; | |||
float max = 1; | |||
float min = 0; | |||
float stepSize = 0.0; | |||
bool dirty = false; | |||
}; | |||
#endif // SLIDERCONFIGMESSAGE_H_INCLUDED |
@@ -1,92 +0,0 @@ | |||
#N canvas 611 141 490 657 10; | |||
#X floatatom 66 97 0 0 0 0 - - -; | |||
#X obj 34 56 notein; | |||
#X floatatom 307 83 0 0 0 0 - - -; | |||
#X obj 34 245 mtof; | |||
#X obj 34 271 phasor~; | |||
#X obj 243 627 dac~; | |||
#X obj 243 576 *~; | |||
#X floatatom 92 100 5 0 0 0 - - -, f 5; | |||
#X obj 184 106 vsl 15 128 0 10 0 0 empty empty Q 0 -9 0 10 -262144 | |||
-1 -1 0 1; | |||
#X obj 138 106 vsl 15 128 0 127 0 0 empty empty F 0 -9 0 10 -262144 | |||
-1 -1 8000 1; | |||
#X obj 138 245 mtof; | |||
#X msg 44 306 clear; | |||
#X msg 185 292 \$1 50; | |||
#X floatatom 137 355 5 0 0 0 - - -, f 5; | |||
#X obj 34 360 vcf~; | |||
#X obj 137 313 line; | |||
#X obj 185 313 line; | |||
#X msg 137 291 \$1 50; | |||
#X floatatom 185 355 5 0 0 0 - - -, f 5; | |||
#X obj 346 320 pack; | |||
#X obj 307 105 moses 1; | |||
#X obj 307 346 line~; | |||
#X obj 307 320 pack; | |||
#X obj 270 105 vsl 15 128 0 1000 0 0 empty empty A 0 -9 0 10 -262144 | |||
-1 -1 254 1; | |||
#X obj 228 104 vsl 15 128 0 1000 0 0 empty empty D 0 -9 0 10 -262144 | |||
-1 -1 254 1; | |||
#X obj 346 291 / 127; | |||
#X floatatom 305 152 5 0 0 0 - - -, f 5; | |||
#X floatatom 345 151 5 0 0 0 - - -, f 5; | |||
#X obj 34 220 clip 0 127; | |||
#X floatatom 42 97 0 0 0 0 - - -; | |||
#X obj 138 51 * 127; | |||
#X obj 138 24 r Cutoff; | |||
#X msg 202 263 4; | |||
#X obj 188 241 loadbang; | |||
#X msg 199 50 64, f 2; | |||
#X obj 199 25 loadbang; | |||
#X msg 228 50 40, f 2; | |||
#X msg 270 50 40, f 2; | |||
#X obj 49 125 r Pitch; | |||
#X obj 49 147 * 24; | |||
#X obj 49 167 - 12; | |||
#X obj 34 191 +; | |||
#X connect 1 0 29 0; | |||
#X connect 1 0 41 0; | |||
#X connect 1 1 0 0; | |||
#X connect 1 1 2 0; | |||
#X connect 1 2 7 0; | |||
#X connect 2 0 20 0; | |||
#X connect 3 0 4 0; | |||
#X connect 4 0 14 0; | |||
#X connect 6 0 5 0; | |||
#X connect 6 0 5 1; | |||
#X connect 9 0 10 0; | |||
#X connect 10 0 17 0; | |||
#X connect 11 0 14 0; | |||
#X connect 12 0 16 0; | |||
#X connect 14 0 6 0; | |||
#X connect 15 0 13 0; | |||
#X connect 15 0 14 1; | |||
#X connect 16 0 14 2; | |||
#X connect 16 0 18 0; | |||
#X connect 17 0 15 0; | |||
#X connect 19 0 21 0; | |||
#X connect 20 0 26 0; | |||
#X connect 20 1 27 0; | |||
#X connect 21 0 6 1; | |||
#X connect 22 0 21 0; | |||
#X connect 23 0 19 1; | |||
#X connect 24 0 22 1; | |||
#X connect 25 0 19 0; | |||
#X connect 26 0 22 0; | |||
#X connect 27 0 25 0; | |||
#X connect 28 0 3 0; | |||
#X connect 30 0 9 0; | |||
#X connect 31 0 30 0; | |||
#X connect 32 0 12 0; | |||
#X connect 33 0 32 0; | |||
#X connect 34 0 9 0; | |||
#X connect 35 0 34 0; | |||
#X connect 35 0 36 0; | |||
#X connect 35 0 37 0; | |||
#X connect 36 0 24 0; | |||
#X connect 37 0 23 0; | |||
#X connect 38 0 39 0; | |||
#X connect 39 0 40 0; | |||
#X connect 40 0 41 1; | |||
#X connect 41 0 28 0; |
@@ -1,34 +0,0 @@ | |||
#N canvas 691 58 428 399 10; | |||
#X obj 78 125 dac~; | |||
#X obj 10 111 *~ 1; | |||
#X obj 15 20 osc~ 440; | |||
#X obj 15 39 *~ 0.2; | |||
#X obj 90 19 adc~ 1; | |||
#X obj 89 65 *~ 1; | |||
#X obj 30 74 r left; | |||
#X obj 87 152 loadbang; | |||
#X obj 87 174 metro 1000; | |||
#X obj 87 195 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 0 | |||
1; | |||
#X obj 87 239 realtime; | |||
#X obj 86 294 print PD_RUNS; | |||
#X obj 87 216 sel 0; | |||
#X obj 132 217 sel 1; | |||
#X floatatom 214 193 5 0 0 0 - - -, f 5; | |||
#X obj 258 132 r pitch; | |||
#X connect 1 0 0 0; | |||
#X connect 2 0 3 0; | |||
#X connect 3 0 1 0; | |||
#X connect 3 0 0 1; | |||
#X connect 4 0 5 0; | |||
#X connect 5 0 0 0; | |||
#X connect 5 0 0 1; | |||
#X connect 6 0 1 1; | |||
#X connect 7 0 8 0; | |||
#X connect 8 0 9 0; | |||
#X connect 9 0 12 0; | |||
#X connect 9 0 13 0; | |||
#X connect 12 0 10 0; | |||
#X connect 13 0 10 1; | |||
#X connect 14 0 2 0; | |||
#X connect 15 0 14 0; |
@@ -1,16 +0,0 @@ | |||
#N canvas 294 144 684 574 10; | |||
#X obj 172 306 dac~; | |||
#X obj 109 139 osc~ 440; | |||
#X floatatom 156 89 5 0 0 0 - - -, f 5; | |||
#X obj 109 196 *~ 0.5; | |||
#X floatatom 292 179 5 0 0 0 - - -, f 5; | |||
#X obj 201 119 r volume; | |||
#X obj 206 55 r freq; | |||
#X obj 400 112 notein; | |||
#X connect 1 0 3 0; | |||
#X connect 2 0 1 0; | |||
#X connect 3 0 0 1; | |||
#X connect 3 0 0 0; | |||
#X connect 4 0 3 1; | |||
#X connect 5 0 4 0; | |||
#X connect 6 0 2 0; |
@@ -1,57 +0,0 @@ | |||
#N canvas 4 23 470 456 10; | |||
#X obj 84 409 dac~; | |||
#X obj 94 36 osc~ 440; | |||
#X floatatom 141 90 5 0 0 0 - - -; | |||
#X obj 18 166 *~ 0.5; | |||
#X floatatom 201 152 5 0 0 0 - - -; | |||
#X obj 201 126 r volume; | |||
#X obj 175 37 r freq; | |||
#X obj 222 228 mono-tape-echo; | |||
#X obj 483 32 notein; | |||
#X text 531 33 MIDI note \, velocity \, MIDI channel; | |||
#X obj 484 60 mtof; | |||
#X text 563 163 off; | |||
#X floatatom 519 216 0 0 0 0 - - -; | |||
#X obj 519 321 noteout; | |||
#X obj 519 295 makenote 64 250; | |||
#X obj 519 242 metro 500; | |||
#X msg 519 189 1; | |||
#X msg 551 189 0; | |||
#X text 519 166 on; | |||
#X msg 519 269 60; | |||
#X text 568 110 outputs work similarly. They all take an optional channel | |||
as creation argument \, and ctlin takes a control number and a channel. | |||
You get inlets to change them in any case. IF you specify no channel | |||
\, it's channel 1; | |||
#X obj 521 134 print freq; | |||
#X obj 538 401 print note?; | |||
#X obj 514 167 print note-IN; | |||
#X obj 725 195 midiin; | |||
#X floatatom 725 226 0 0 0 0 - - -; | |||
#X floatatom 756 226 0 0 0 0 - - -; | |||
#X obj 709 290 print in1; | |||
#X obj 785 291 print in2; | |||
#X connect 1 0 3 0; | |||
#X connect 2 0 1 0; | |||
#X connect 3 0 7 0; | |||
#X connect 4 0 3 1; | |||
#X connect 5 0 4 0; | |||
#X connect 6 0 2 0; | |||
#X connect 7 0 0 0; | |||
#X connect 7 0 0 1; | |||
#X connect 8 0 10 0; | |||
#X connect 8 0 23 0; | |||
#X connect 10 0 2 0; | |||
#X connect 10 0 21 0; | |||
#X connect 12 0 15 0; | |||
#X connect 14 0 13 0; | |||
#X connect 14 0 22 0; | |||
#X connect 14 1 13 1; | |||
#X connect 15 0 19 0; | |||
#X connect 16 0 12 0; | |||
#X connect 17 0 12 0; | |||
#X connect 19 0 14 0; | |||
#X connect 24 0 25 0; | |||
#X connect 24 1 26 0; | |||
#X connect 25 0 27 0; | |||
#X connect 26 0 28 0; |