| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,68 @@ | ||
| /* | ||
| ============================================================================== | ||
| FloatParameter.h | ||
| Created: 3 Jul 2015 3:53:57pm | ||
| Author: Karl | ||
| ============================================================================== | ||
| */ | ||
|
|
||
| #ifndef FLOATPARAMETER_H_INCLUDED | ||
| #define FLOATPARAMETER_H_INCLUDED | ||
|
|
||
| #include "../JuceLibraryCode/JuceHeader.h" | ||
|
|
||
| class FloatParameter : public AudioProcessorParameter | ||
| { | ||
| public: | ||
|
|
||
| FloatParameter (float defaultParameterValue, const String& paramName) | ||
| : defaultValue (defaultParameterValue), | ||
| value (defaultParameterValue), | ||
| name (paramName) | ||
| { | ||
| } | ||
|
|
||
| float getValue() const override | ||
| { | ||
| return value; | ||
| } | ||
|
|
||
| void setValue (float newValue) override | ||
| { | ||
| value = newValue; | ||
| } | ||
|
|
||
| float getDefaultValue() const override | ||
| { | ||
| return defaultValue; | ||
| } | ||
|
|
||
| String getName (int maximumStringLength) const override | ||
| { | ||
| return name; | ||
| } | ||
|
|
||
| void setName (String n) | ||
| { | ||
| name = n; | ||
| } | ||
|
|
||
| String getLabel() const override | ||
| { | ||
| return String(); | ||
| } | ||
|
|
||
| float getValueForText (const String& text) const override | ||
| { | ||
| return text.getFloatValue(); | ||
| } | ||
|
|
||
| private: | ||
| float defaultValue, value; | ||
| String name; | ||
| }; | ||
|
|
||
|
|
||
| #endif // FLOATPARAMETER_H_INCLUDED |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,322 @@ | ||
| /* | ||
| ============================================================================== | ||
| This is an automatically generated GUI class created by the Introjucer! | ||
| Be careful when adding custom code to these files, as only the code within | ||
| the "//[xyz]" and "//[/xyz]" sections will be retained when the file is loaded | ||
| and re-saved. | ||
| Created with Introjucer version: 3.1.1 | ||
| ------------------------------------------------------------------------------ | ||
| The Introjucer is part of the JUCE library - "Jules' Utility Class Extensions" | ||
| Copyright 2004-13 by Raw Material Software Ltd. | ||
| ============================================================================== | ||
| */ | ||
|
|
||
| //[Headers] You can add your own extra header files here... | ||
| //[/Headers] | ||
|
|
||
| #include "MainComponent.h" | ||
|
|
||
|
|
||
| //[MiscUserDefs] You can add your own user definitions and misc code here... | ||
| //[/MiscUserDefs] | ||
|
|
||
| //============================================================================== | ||
| MainComponent::MainComponent (PureDataAudioProcessor& processor) | ||
| : PureDataAudioProcessorEditor(processor) | ||
| { | ||
| //[Constructor_pre] You can add your own custom stuff here.. | ||
| //[/Constructor_pre] | ||
|
|
||
| addAndMakeVisible (sendSlider1 = new SendSlider (1, processor)); | ||
| addAndMakeVisible (sendSlider2 = new SendSlider (2, processor)); | ||
| addAndMakeVisible (sendSlider5 = new SendSlider (3, processor)); | ||
| addAndMakeVisible (sendSlider6 = new SendSlider (4, processor)); | ||
| addAndMakeVisible (sendSlider7 = new SendSlider (5, processor)); | ||
| addAndMakeVisible (sendSlider3 = new SendSlider (6, processor)); | ||
| addAndMakeVisible (sendSlider4 = new SendSlider (7, processor)); | ||
| addAndMakeVisible (sendSlider8 = new SendSlider (8, processor)); | ||
| addAndMakeVisible (sendSlider9 = new SendSlider (9, processor)); | ||
| addAndMakeVisible (sendSlider10 = new SendSlider (10, processor)); | ||
| addAndMakeVisible (findButton = new TextButton ("new button")); | ||
| findButton->setButtonText (TRANS("Find patch...")); | ||
| findButton->addListener (this); | ||
| findButton->setColour (TextButton::buttonColourId, Colour (0xffadadad)); | ||
| findButton->setColour (TextButton::buttonOnColourId, Colour (0xff727272)); | ||
|
|
||
| addAndMakeVisible (pathField = new Label ("new label", | ||
| String::empty)); | ||
| pathField->setFont (Font (15.00f, Font::plain)); | ||
| pathField->setJustificationType (Justification::centred); | ||
| pathField->setEditable (false, false, false); | ||
| pathField->setColour (Label::backgroundColourId, Colour (0x21000000)); | ||
| pathField->setColour (Label::textColourId, Colour (0xffbcbcbc)); | ||
| pathField->setColour (TextEditor::textColourId, Colours::black); | ||
| pathField->setColour (TextEditor::backgroundColourId, Colour (0x00000000)); | ||
|
|
||
| addAndMakeVisible (reloadButton = new TextButton ("new button")); | ||
| reloadButton->setTooltip (TRANS("Reload the pd patch file.")); | ||
| reloadButton->setButtonText (TRANS("Reload")); | ||
| reloadButton->addListener (this); | ||
| reloadButton->setColour (TextButton::buttonColourId, Colour (0xffadadad)); | ||
| reloadButton->setColour (TextButton::buttonOnColourId, Colour (0xff727272)); | ||
|
|
||
| addAndMakeVisible (editButton = new TextButton ("new button")); | ||
| editButton->setTooltip (TRANS("Opens PD editor if existent.")); | ||
| editButton->setButtonText (TRANS("Edit")); | ||
| editButton->addListener (this); | ||
| editButton->setColour (TextButton::buttonColourId, Colour (0xffadadad)); | ||
| editButton->setColour (TextButton::buttonOnColourId, Colour (0xff727272)); | ||
|
|
||
| addAndMakeVisible (statusField = new Label ("new label", | ||
| String::empty)); | ||
| statusField->setFont (Font (11.00f, Font::plain)); | ||
| statusField->setJustificationType (Justification::centred); | ||
| statusField->setEditable (false, false, false); | ||
| statusField->setColour (Label::backgroundColourId, Colour (0x00000000)); | ||
| statusField->setColour (Label::textColourId, Colour (0xbcbcbcbc)); | ||
| 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 (label2 = 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)); | ||
|
|
||
|
|
||
| //[UserPreSize] | ||
| //[/UserPreSize] | ||
|
|
||
| setSize (500, 385); | ||
|
|
||
|
|
||
| //[Constructor] You can add your own custom stuff here.. | ||
| PureDataAudioProcessor& p = (PureDataAudioProcessor&) processor; | ||
| pathField->setText(p.getPatchFile().getFileName(), dontSendNotification); | ||
|
|
||
| startTimer(25); | ||
|
|
||
| //[/Constructor] | ||
| } | ||
|
|
||
| MainComponent::~MainComponent() | ||
| { | ||
| //[Destructor_pre]. You can add your own custom destruction code here.. | ||
| //[/Destructor_pre] | ||
|
|
||
| sendSlider1 = nullptr; | ||
| sendSlider2 = nullptr; | ||
| sendSlider5 = nullptr; | ||
| sendSlider6 = nullptr; | ||
| sendSlider7 = nullptr; | ||
| sendSlider3 = nullptr; | ||
| sendSlider4 = nullptr; | ||
| sendSlider8 = nullptr; | ||
| sendSlider9 = nullptr; | ||
| sendSlider10 = nullptr; | ||
| findButton = nullptr; | ||
| pathField = nullptr; | ||
| reloadButton = nullptr; | ||
| editButton = nullptr; | ||
| statusField = nullptr; | ||
| label = nullptr; | ||
| label2 = nullptr; | ||
|
|
||
|
|
||
| //[Destructor]. You can add your own custom destruction code here.. | ||
| //[/Destructor] | ||
| } | ||
|
|
||
| //============================================================================== | ||
| void MainComponent::paint (Graphics& g) | ||
| { | ||
| //[UserPrePaint] Add your own custom painting code here.. | ||
| //[/UserPrePaint] | ||
|
|
||
| g.fillAll (Colour (0xff303030)); | ||
|
|
||
| //[UserPaint] Add your own custom painting code here.. | ||
| //[/UserPaint] | ||
| } | ||
|
|
||
| void MainComponent::resized() | ||
| { | ||
| //[UserPreResize] Add your own custom resize code here.. | ||
| //[/UserPreResize] | ||
|
|
||
| sendSlider1->setBounds (9, 122, 98, 120); | ||
| sendSlider2->setBounds (101, 122, 98, 120); | ||
| sendSlider5->setBounds (197, 122, 98, 120); | ||
| sendSlider6->setBounds (293, 122, 98, 120); | ||
| sendSlider7->setBounds (389, 122, 98, 120); | ||
| sendSlider3->setBounds (9, 246, 98, 120); | ||
| sendSlider4->setBounds (101, 246, 98, 120); | ||
| 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); | ||
| //[UserResized] Add your own custom resize handling here.. | ||
|
|
||
| //[/UserResized] | ||
| } | ||
|
|
||
| void MainComponent::buttonClicked (Button* buttonThatWasClicked) | ||
| { | ||
| //[UserbuttonClicked_Pre] | ||
| PureDataAudioProcessor& p = (PureDataAudioProcessor&) processor; | ||
| //[/UserbuttonClicked_Pre] | ||
|
|
||
| if (buttonThatWasClicked == findButton) | ||
| { | ||
| //[UserButtonCode_findButton] -- add your button handler code here.. | ||
| FileChooser fc ("Choose a pd file to open...", | ||
| File::getCurrentWorkingDirectory(), | ||
| "*", | ||
| true); | ||
|
|
||
| if (fc.browseForFileToOpen()) | ||
| { | ||
| pathField->setText(fc.getResult().getFileName(), dontSendNotification); | ||
| p.setPatchFile(fc.getResult()); | ||
| p.reloadPatch(NULL); | ||
| } | ||
| //[/UserButtonCode_findButton] | ||
| } | ||
| else if (buttonThatWasClicked == reloadButton) | ||
| { | ||
| //[UserButtonCode_reloadButton] -- add your button handler code here.. | ||
| p.reloadPatch(NULL); | ||
| //[/UserButtonCode_reloadButton] | ||
| } | ||
| else if (buttonThatWasClicked == editButton) | ||
| { | ||
| //[UserButtonCode_editButton] -- add your button handler code here.. | ||
| p.getPatchFile().startAsProcess(); | ||
| //[/UserButtonCode_editButton] | ||
| } | ||
|
|
||
| //[UserbuttonClicked_Post] | ||
| //[/UserbuttonClicked_Post] | ||
| } | ||
|
|
||
|
|
||
|
|
||
| //[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); | ||
| } | ||
| //[/MiscUserCode] | ||
|
|
||
|
|
||
| //============================================================================== | ||
| #if 0 | ||
| /* -- Introjucer information section -- | ||
|
|
||
| This is where the Introjucer stores the metadata that describe this GUI layout, so | ||
| make changes in here at your peril! | ||
|
|
||
| BEGIN_JUCER_METADATA | ||
|
|
||
| <JUCER_COMPONENT documentType="Component" className="MainComponent" componentName="" | ||
| parentClasses="public PureDataAudioProcessorEditor, public Timer" | ||
| constructorParams="PureDataAudioProcessor& processor" variableInitialisers="PureDataAudioProcessorEditor(processor)" | ||
| snapPixels="8" snapActive="1" snapShown="1" overlayOpacity="0.330" | ||
| fixedSize="1" initialWidth="500" initialHeight="385"> | ||
| <BACKGROUND backgroundColour="ff303030"/> | ||
| <JUCERCOMP name="" id="bc71a9946298412f" memberName="sendSlider1" virtualName="" | ||
| explicitFocusOrder="0" pos="9 122 98 120" sourceFile="SendSlider.cpp" | ||
| constructorParams="1, processor"/> | ||
| <JUCERCOMP name="" id="2cbea2ce044e5daa" memberName="sendSlider2" virtualName="" | ||
| explicitFocusOrder="0" pos="101 122 98 120" sourceFile="SendSlider.cpp" | ||
| constructorParams="2, processor"/> | ||
| <JUCERCOMP name="" id="e8e479a7b178aed7" memberName="sendSlider5" virtualName="" | ||
| explicitFocusOrder="0" pos="197 122 98 120" sourceFile="SendSlider.cpp" | ||
| constructorParams="3, processor"/> | ||
| <JUCERCOMP name="" id="8371429f476dadb8" memberName="sendSlider6" virtualName="" | ||
| explicitFocusOrder="0" pos="293 122 98 120" sourceFile="SendSlider.cpp" | ||
| constructorParams="4, processor"/> | ||
| <JUCERCOMP name="" id="6a6f5c3c175c8eea" memberName="sendSlider7" virtualName="" | ||
| explicitFocusOrder="0" pos="389 122 98 120" sourceFile="SendSlider.cpp" | ||
| constructorParams="5, processor"/> | ||
| <JUCERCOMP name="" id="b743230df56fafcb" memberName="sendSlider3" virtualName="" | ||
| explicitFocusOrder="0" pos="9 246 98 120" sourceFile="SendSlider.cpp" | ||
| constructorParams="6, processor"/> | ||
| <JUCERCOMP name="" id="488c56ced9555a30" memberName="sendSlider4" virtualName="" | ||
| explicitFocusOrder="0" pos="101 246 98 120" sourceFile="SendSlider.cpp" | ||
| constructorParams="7, processor"/> | ||
| <JUCERCOMP name="" id="9f9f04d1bb5763fc" memberName="sendSlider8" virtualName="" | ||
| explicitFocusOrder="0" pos="197 246 98 120" sourceFile="SendSlider.cpp" | ||
| constructorParams="8, processor"/> | ||
| <JUCERCOMP name="" id="c4f70e09d260381f" memberName="sendSlider9" virtualName="" | ||
| explicitFocusOrder="0" pos="293 246 98 120" sourceFile="SendSlider.cpp" | ||
| constructorParams="9, processor"/> | ||
| <JUCERCOMP name="" id="4fe4af228a7dcf41" memberName="sendSlider10" virtualName="" | ||
| 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" | ||
| 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" | ||
| 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." | ||
| 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." | ||
| 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" | ||
| 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="" | ||
| explicitFocusOrder="0" pos="22 16 170 32" textCol="ffffffff" | ||
| 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" | ||
| 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"/> | ||
| </JUCER_COMPONENT> | ||
|
|
||
| END_JUCER_METADATA | ||
| */ | ||
| #endif | ||
|
|
||
|
|
||
| //[EndFile] You can add extra defines here... | ||
| //[/EndFile] |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,91 @@ | ||
| /* | ||
| ============================================================================== | ||
| This is an automatically generated GUI class created by the Introjucer! | ||
| Be careful when adding custom code to these files, as only the code within | ||
| the "//[xyz]" and "//[/xyz]" sections will be retained when the file is loaded | ||
| and re-saved. | ||
| Created with Introjucer version: 3.1.1 | ||
| ------------------------------------------------------------------------------ | ||
| The Introjucer is part of the JUCE library - "Jules' Utility Class Extensions" | ||
| Copyright 2004-13 by Raw Material Software Ltd. | ||
| ============================================================================== | ||
| */ | ||
|
|
||
| #ifndef __JUCE_HEADER_9002020A4DD09B20__ | ||
| #define __JUCE_HEADER_9002020A4DD09B20__ | ||
|
|
||
| //[Headers] -- You can add your own extra header files here -- | ||
| #include "JuceHeader.h" | ||
| #include "PluginProcessor.h" | ||
| #include "PluginEditor.h" | ||
| //[/Headers] | ||
|
|
||
| #include "SendSlider.h" | ||
|
|
||
|
|
||
| //============================================================================== | ||
| /** | ||
| //[Comments] | ||
| An auto-generated component, created by the Introjucer. | ||
| Describe your class and how it works here! | ||
| //[/Comments] | ||
| */ | ||
| class MainComponent : public PureDataAudioProcessorEditor, | ||
| public Timer, | ||
| public ButtonListener | ||
| { | ||
| public: | ||
| //============================================================================== | ||
| MainComponent (PureDataAudioProcessor& processor); | ||
| ~MainComponent(); | ||
|
|
||
| //============================================================================== | ||
| //[UserMethods] -- You can add your own custom methods in this section. | ||
| //[/UserMethods] | ||
|
|
||
| void paint (Graphics& g); | ||
| void resized(); | ||
| void buttonClicked (Button* buttonThatWasClicked); | ||
|
|
||
|
|
||
|
|
||
| private: | ||
| //[UserVariables] -- You can add your own custom variables in this section. | ||
| void timerCallback(); | ||
| //[/UserVariables] | ||
|
|
||
| //============================================================================== | ||
| ScopedPointer<SendSlider> sendSlider1; | ||
| ScopedPointer<SendSlider> sendSlider2; | ||
| ScopedPointer<SendSlider> sendSlider5; | ||
| ScopedPointer<SendSlider> sendSlider6; | ||
| ScopedPointer<SendSlider> sendSlider7; | ||
| ScopedPointer<SendSlider> sendSlider3; | ||
| ScopedPointer<SendSlider> sendSlider4; | ||
| ScopedPointer<SendSlider> sendSlider8; | ||
| ScopedPointer<SendSlider> sendSlider9; | ||
| ScopedPointer<SendSlider> sendSlider10; | ||
| ScopedPointer<TextButton> findButton; | ||
| ScopedPointer<Label> pathField; | ||
| ScopedPointer<TextButton> reloadButton; | ||
| ScopedPointer<TextButton> editButton; | ||
| ScopedPointer<Label> statusField; | ||
| ScopedPointer<Label> label; | ||
| ScopedPointer<Label> label2; | ||
|
|
||
|
|
||
| //============================================================================== | ||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MainComponent) | ||
| }; | ||
|
|
||
| //[EndFile] You can add extra defines here... | ||
| //[/EndFile] | ||
|
|
||
| #endif // __JUCE_HEADER_9002020A4DD09B20__ |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,35 @@ | ||
| /* | ||
| * Copyright (c) 2012 Dan Wilcox <danomatika@gmail.com> | ||
| * | ||
| * BSD Simplified License. | ||
| * For information on usage and redistribution, and for a DISCLAIMER OF ALL | ||
| * WARRANTIES, see the file, "LICENSE.txt," in this distribution. | ||
| * | ||
| * See https://github.com/libpd/libpd for documentation | ||
| * | ||
| * This file was originally written for the ofxPd openFrameworks addon: | ||
| * https://github.com/danomatika/ofxPd | ||
| * | ||
| */ | ||
| #pragma once | ||
|
|
||
| namespace pd { | ||
|
|
||
| /// a pd midi receiver base class | ||
| class PdMidiReceiver { | ||
|
|
||
| public: | ||
|
|
||
| /// midi | ||
| virtual void receiveNoteOn(const int channel, const int pitch, const int velocity) {} | ||
| virtual void receiveControlChange(const int channel, const int controller, const int value) {} | ||
| virtual void receiveProgramChange(const int channel, const int value) {} // note: pgm value is 1-128 | ||
| virtual void receivePitchBend(const int channel, const int value) {} | ||
| virtual void receiveAftertouch(const int channel, const int value) {} | ||
| virtual void receivePolyAftertouch(const int channel, const int pitch, const int value) {} | ||
|
|
||
| /// raw midi byte | ||
| virtual void receiveMidiByte(const int port, const int byte) {} | ||
| }; | ||
|
|
||
| } // namespace |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| /* | ||
| * Copyright (c) 2012 Dan Wilcox <danomatika@gmail.com> | ||
| * | ||
| * BSD Simplified License. | ||
| * For information on usage and redistribution, and for a DISCLAIMER OF ALL | ||
| * WARRANTIES, see the file, "LICENSE.txt," in this distribution. | ||
| * | ||
| * See https://github.com/libpd/libpd for documentation | ||
| * | ||
| * This file was originally written for the ofxPd openFrameworks addon: | ||
| * https://github.com/danomatika/ofxPd | ||
| * | ||
| */ | ||
| #pragma once | ||
|
|
||
| #include "PdTypes.hpp" | ||
|
|
||
| namespace pd { | ||
|
|
||
| /// a pd message receiver base class | ||
| class PdReceiver { | ||
|
|
||
| public: | ||
|
|
||
| virtual void print(const std::string& message) {}; | ||
|
|
||
| /// messages | ||
| virtual void receiveBang(const std::string& dest) {} | ||
| virtual void receiveFloat(const std::string& dest, float num) {} | ||
| virtual void receiveSymbol(const std::string& dest, const std::string& symbol) {} | ||
| virtual void receiveList(const std::string& dest, const List& list) {} | ||
| virtual void receiveMessage(const std::string& dest, const std::string& msg, const List& list) {} | ||
| }; | ||
|
|
||
| } // namespace |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,196 @@ | ||
| /* | ||
| * Copyright (c) 2012 Dan Wilcox <danomatika@gmail.com> | ||
| * | ||
| * BSD Simplified License. | ||
| * For information on usage and redistribution, and for a DISCLAIMER OF ALL | ||
| * WARRANTIES, see the file, "LICENSE.txt," in this distribution. | ||
| * | ||
| * See https://github.com/libpd/libpd for documentation | ||
| * | ||
| * This file was originally written for the ofxPd openFrameworks addon: | ||
| * https://github.com/danomatika/ofxPd | ||
| * | ||
| */ | ||
| #include "PdTypes.hpp" | ||
|
|
||
| #include <iostream> | ||
| #include <sstream> | ||
|
|
||
| namespace pd { | ||
|
|
||
| /// PATCH | ||
| //---------------------------------------------------------- | ||
| Patch::Patch() : _handle(NULL), _dollarZero(0), _dollarZeroStr("0"), | ||
| _filename(""), _path("") {} | ||
|
|
||
| Patch::Patch(const std::string& filename, const std::string& path) : | ||
| _handle(NULL), _dollarZero(0), _dollarZeroStr("0"), | ||
| _filename(filename), _path(path) {} | ||
|
|
||
| Patch::Patch(void* handle, int dollarZero, const std::string& filename, const std::string& path) : | ||
| _handle(handle), _dollarZero(dollarZero), _filename(filename), _path(path) { | ||
| std::stringstream itoa; | ||
| itoa << dollarZero; | ||
| _dollarZeroStr = itoa.str(); | ||
| } | ||
|
|
||
| bool Patch::isValid() const { | ||
| if(_handle == NULL) | ||
| return false; | ||
| return true; | ||
| } | ||
|
|
||
| void Patch::clear() { | ||
| _handle = NULL; | ||
| _dollarZero = 0; | ||
| _dollarZeroStr = "0"; | ||
| } | ||
|
|
||
| Patch::Patch(const Patch& from) { | ||
| _handle = from._handle; | ||
| _dollarZero = from._dollarZero; | ||
| _dollarZeroStr = from._dollarZeroStr; | ||
| _filename = from._filename; | ||
| _path = from._path; | ||
| } | ||
|
|
||
| void Patch::operator=(const Patch& from) { | ||
| _handle = from._handle; | ||
| _dollarZero = from._dollarZero; | ||
| _dollarZeroStr = from._dollarZeroStr; | ||
| _filename = from._filename; | ||
| _path = from._path; | ||
| } | ||
|
|
||
| std::ostream& operator<<(std::ostream& os, const Patch& from) { | ||
| return os << "Patch: \"" << from.filename() << "\" $0: " << from.dollarZeroStr() | ||
| << " valid: " << from.isValid(); | ||
| } | ||
|
|
||
| /// LIST | ||
| //---------------------------------------------------------- | ||
| List::List() {} | ||
|
|
||
| bool List::isFloat(const unsigned int index) const { | ||
| if(index < objects.size()) | ||
| if(objects[index].type == List::FLOAT) | ||
| return true; | ||
| return false; | ||
| } | ||
|
|
||
| bool List::isSymbol(const unsigned int index) const { | ||
| if(index < objects.size()) | ||
| if(objects[index].type == List::SYMBOL) | ||
| return true; | ||
| return false; | ||
| } | ||
|
|
||
| //---------------------------------------------------------- | ||
| float List::getFloat(const unsigned int index) const { | ||
| if(!isFloat(index)) { | ||
| std::cerr << "Pd: List: object " << index << " is not a float" << std::endl; | ||
| return 0; | ||
| } | ||
| return objects[index].value; | ||
| } | ||
|
|
||
| std::string List::getSymbol(const unsigned int index) const { | ||
| if(!isSymbol(index)) { | ||
| std::cerr << "Pd: List: object " << index << " is not a symbol" << std::endl; | ||
| return ""; | ||
| } | ||
| return objects[index].symbol; | ||
| } | ||
|
|
||
| //---------------------------------------------------------- | ||
| void List::addFloat(const float num) { | ||
| MsgObject o; | ||
| o.type = List::FLOAT; | ||
| o.value = num; | ||
| objects.push_back(o); | ||
| typeString += 'f'; | ||
| } | ||
|
|
||
| void List::addSymbol(const std::string& symbol) { | ||
| MsgObject o; | ||
| o.type = List::SYMBOL; | ||
| o.symbol = symbol; | ||
| objects.push_back(o); | ||
| typeString += 's'; | ||
| } | ||
|
|
||
| List& List::operator<<(const bool var) { | ||
| addFloat((float) var); | ||
| return *this; | ||
| } | ||
|
|
||
| List& List::operator<<(const int var) { | ||
| addFloat((float) var); | ||
| return *this; | ||
| } | ||
|
|
||
| List& List::operator<<(const float var) { | ||
| addFloat((float) var); | ||
| return *this; | ||
| } | ||
|
|
||
| List& List::operator<<(const double var) { | ||
| addFloat((float) var); | ||
| return *this; | ||
| } | ||
|
|
||
| List& List::operator<<(const char var) { | ||
| std::string s; | ||
| s = var; | ||
| addSymbol(s); | ||
| return *this; | ||
| } | ||
|
|
||
| List& List::operator<<(const char* var) { | ||
| addSymbol((std::string) var); | ||
| return *this; | ||
| } | ||
|
|
||
| List& List::operator<<(const std::string& var) { | ||
| addSymbol((std::string) var); | ||
| return *this; | ||
| } | ||
|
|
||
| //---------------------------------------------------------- | ||
| const unsigned int List::len() const { | ||
| return (unsigned int) objects.size(); | ||
| } | ||
|
|
||
| const std::string& List::types() const { | ||
| return typeString; | ||
| } | ||
|
|
||
| void List::clear() { | ||
| typeString = ""; | ||
| objects.clear(); | ||
| } | ||
|
|
||
| std::string List::toString() const { | ||
|
|
||
| std::string line; | ||
| std::stringstream itoa; | ||
|
|
||
| for(int i = 0; i < objects.size(); ++i) { | ||
| if(isFloat(i)) { | ||
| itoa << getFloat(i); | ||
| line += itoa.str(); | ||
| itoa.str(""); | ||
| } | ||
| else | ||
| line += getSymbol(i); | ||
| line += " "; | ||
| } | ||
|
|
||
| return line; | ||
| } | ||
|
|
||
| std::ostream& operator<<(std::ostream& os, const List& from) { | ||
| return os << from.toString(); | ||
| } | ||
|
|
||
| } // namespace |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,306 @@ | ||
| /* | ||
| * Copyright (c) 2012 Dan Wilcox <danomatika@gmail.com> | ||
| * | ||
| * BSD Simplified License. | ||
| * For information on usage and redistribution, and for a DISCLAIMER OF ALL | ||
| * WARRANTIES, see the file, "LICENSE.txt," in this distribution. | ||
| * | ||
| * See https://github.com/libpd/libpd for documentation | ||
| * | ||
| * This file was originally written for the ofxPd openFrameworks addon: | ||
| * https://github.com/danomatika/ofxPd | ||
| * | ||
| */ | ||
| #pragma once | ||
|
|
||
| #include <string> | ||
| #include <vector> | ||
|
|
||
| namespace pd { | ||
|
|
||
| /// \section Pd Patch | ||
|
|
||
| /// a pd patch | ||
| /// | ||
| /// if you use the copy constructor/operator, keep in mind the libpd void* pointer | ||
| /// patch handle is copied and problems can arise if one object is used to close | ||
| /// a patch that other copies may be referring to | ||
| class Patch { | ||
|
|
||
| public: | ||
|
|
||
| Patch(); | ||
| Patch(const std::string& filename, const std::string& path); | ||
| Patch(void* handle, int dollarZero, const std::string& filename, const std::string& path); | ||
|
|
||
| /// data access | ||
| void* handle() const {return _handle;} | ||
| int dollarZero() const {return _dollarZero;} | ||
| std::string filename() const {return _filename;} | ||
| std::string path() const {return _path;} | ||
|
|
||
| /// get dollarZero as a string | ||
| std::string dollarZeroStr() const {return _dollarZeroStr;} | ||
|
|
||
| /// is the patch pointer valid? | ||
| bool isValid() const; | ||
|
|
||
| /// clear patch pointer and dollar zero (does not close patch!) | ||
| /// | ||
| /// note: does not clear filename and path so the object can be reused | ||
| // for opening multiple instances | ||
| void clear(); | ||
|
|
||
| /// copy constructor | ||
| Patch(const Patch& from); | ||
|
|
||
| /// copy operator | ||
| void operator=(const Patch& from); | ||
|
|
||
| /// print to ostream | ||
| friend std::ostream& operator<<(std::ostream& os, const Patch& from); | ||
|
|
||
| private: | ||
|
|
||
| void* _handle; //< patch handle pointer | ||
| int _dollarZero; //< the unique patch id, ie $0 | ||
| std::string _dollarZeroStr; //< $0 as a string | ||
|
|
||
| std::string _filename; //< filename | ||
| std::string _path; //< full path | ||
| }; | ||
|
|
||
| /// \section Pd stream interface message objects | ||
|
|
||
| /// bang event | ||
| struct Bang { | ||
|
|
||
| const std::string dest; //< dest receiver name | ||
|
|
||
| explicit Bang(const std::string& dest) : dest(dest) {} | ||
| }; | ||
|
|
||
| /// float value | ||
| struct Float { | ||
|
|
||
| const std::string dest; //< dest receiver name | ||
| const float num; //< the float value | ||
|
|
||
| Float(const std::string& dest, const float num) : | ||
| dest(dest), num(num) {} | ||
| }; | ||
|
|
||
| /// symbol value | ||
| struct Symbol { | ||
|
|
||
| const std::string dest; //< dest receiver name | ||
| const std::string symbol; //< the symbol value | ||
|
|
||
| Symbol(const std::string& dest, const std::string& symbol) : | ||
| dest(dest), symbol(symbol) {} | ||
| }; | ||
|
|
||
| /// a compound message containing floats and symbols | ||
| class List { | ||
|
|
||
| public: | ||
|
|
||
| List(); | ||
|
|
||
| /// \section Read | ||
|
|
||
| /// check type | ||
| bool isFloat(const unsigned int index) const; | ||
| bool isSymbol(const unsigned int index) const; | ||
|
|
||
| /// get item as type | ||
| float getFloat(const unsigned int index) const; | ||
| std::string getSymbol(const unsigned int index) const; | ||
|
|
||
| /// \section Write | ||
|
|
||
| /// add elements to the list | ||
| /// | ||
| /// List list; | ||
| /// list.addSymbol("hello"); | ||
| /// list.addFloat(1.23); | ||
| /// | ||
| void addFloat(const float num); | ||
| void addSymbol(const std::string& symbol); | ||
|
|
||
| /// \section Write Stream Interface | ||
|
|
||
| /// list << "hello" << 1.23; | ||
|
|
||
| /// add a float to the message | ||
| List& operator<<(const bool var); | ||
| List& operator<<(const int var); | ||
| List& operator<<(const float var); | ||
| List& operator<<(const double var); | ||
|
|
||
| /// add a symbol to the message | ||
| List& operator<<(const char var); | ||
| List& operator<<(const char* var); | ||
| List& operator<<(const std::string& var); | ||
|
|
||
| /// \section Util | ||
|
|
||
| const unsigned int len() const; //< number of items | ||
| const std::string& types() const; //< OSC style type string ie "fsfs" | ||
| void clear(); //< clear all objects | ||
|
|
||
| /// get list as a string | ||
| std::string toString() const; | ||
|
|
||
| /// print to ostream | ||
| friend std::ostream& operator<<(std::ostream& os, const List& from); | ||
|
|
||
| private: | ||
|
|
||
| std::string typeString; //< OSC style type string | ||
|
|
||
| // object type | ||
| enum MsgType { | ||
| FLOAT, | ||
| SYMBOL | ||
| }; | ||
|
|
||
| // object wrapper | ||
| struct MsgObject { | ||
| MsgType type; | ||
| float value; | ||
| std::string symbol; | ||
| }; | ||
|
|
||
| std::vector<MsgObject> objects; //< list objects | ||
| }; | ||
|
|
||
| /// start a compound message | ||
| struct StartMessage { | ||
| explicit StartMessage() {} | ||
| }; | ||
|
|
||
| /// finish a compound message as a list | ||
| struct FinishList { | ||
|
|
||
| const std::string dest; //< dest receiver name | ||
|
|
||
| explicit FinishList(const std::string& dest) : dest(dest) {} | ||
| }; | ||
|
|
||
| /// finish a compound message as a typed message | ||
| struct FinishMessage { | ||
|
|
||
| const std::string dest; //< dest receiver name | ||
| const std::string msg; //< target msg at the dest | ||
|
|
||
| FinishMessage(const std::string& dest, const std::string& msg) : | ||
| dest(dest), msg(msg) {} | ||
| }; | ||
|
|
||
| /// /section Pd stream interface midi objects | ||
| /// ref: http://www.gweep.net/~prefect/eng/reference/protocol/midispec.html | ||
|
|
||
| /// send a note on event (set vel = 0 for noteoff) | ||
| struct NoteOn { | ||
|
|
||
| const int channel; //< channel (0 - 15 * dev#) | ||
| const int pitch; //< pitch (0 - 127) | ||
| const int velocity; //< velocity (0 - 127) | ||
|
|
||
| NoteOn(const int channel, const int pitch, const int velocity=64) : | ||
| channel(channel), pitch(pitch), velocity(velocity) {} | ||
| }; | ||
|
|
||
| /// change a control value aka send a CC message | ||
| struct ControlChange { | ||
|
|
||
| const int channel; //< channel (0 - 15 * dev#) | ||
| const int controller; //< controller (0 - 127) | ||
| const int value; //< value (0 - 127) | ||
|
|
||
| ControlChange(const int channel, const int controller, const int value) : | ||
| channel(channel), controller(controller), value(value) {} | ||
| }; | ||
|
|
||
| /// change a program value (ie an instrument) | ||
| struct ProgramChange { | ||
|
|
||
| const int channel; //< channel (0 - 15 * dev#) | ||
| const int value; //< value (0 - 127) | ||
|
|
||
| ProgramChange(const int channel, const int value) : | ||
| channel(channel), value(value) {} | ||
| }; | ||
|
|
||
| /// change the pitch bend value | ||
| struct PitchBend { | ||
|
|
||
| const int channel; //< channel (0 - 15 * dev#) | ||
| const int value; //< value (-8192 - 8192) | ||
|
|
||
| PitchBend(const int channel, const int value) : | ||
| channel(channel), value(value) {} | ||
| }; | ||
|
|
||
| /// change an aftertouch value | ||
| struct Aftertouch { | ||
|
|
||
| const int channel; //< channel (0 - 15 * dev#) | ||
| const int value; //< value (0 - 127) | ||
|
|
||
| Aftertouch(const int channel, const int value) : | ||
| channel(channel), value(value) {} | ||
| }; | ||
|
|
||
| /// change a poly aftertouch value | ||
| struct PolyAftertouch { | ||
|
|
||
| const int channel; //< channel (0 - 15 * dev#) | ||
| const int pitch; //< pitch (0 - 127) | ||
| const int value; //< value (0 - 127) | ||
|
|
||
| PolyAftertouch(const int channel, const int pitch, const int value) : | ||
| channel(channel), pitch(pitch), value(value) {} | ||
| }; | ||
|
|
||
| /// a raw midi byte | ||
| struct MidiByte { | ||
|
|
||
| const int port; //< raw portmidi port | ||
| //< see http://en.wikipedia.org/wiki/PortMidi | ||
| const unsigned char byte; //< the raw midi byte value | ||
|
|
||
| MidiByte(const int port, unsigned char byte) : port(port), byte(byte) {} | ||
| }; | ||
|
|
||
| /// start a raw midi byte stream | ||
| struct StartMidi { | ||
|
|
||
| const int port; //< raw portmidi port | ||
|
|
||
| explicit StartMidi(const int port=0) : port(port) {} | ||
| }; | ||
|
|
||
| /// start a raw sysex byte stream | ||
| struct StartSysex { | ||
|
|
||
| const int port; //< raw portmidi port | ||
|
|
||
| explicit StartSysex(const int port=0) : port(port) {} | ||
| }; | ||
|
|
||
| /// start a sys realtime byte stream | ||
| struct StartSysRealTime { | ||
|
|
||
| const int port; //< raw portmidi port | ||
|
|
||
| explicit StartSysRealTime(const int port=0) : port(port) {} | ||
| }; | ||
|
|
||
| /// finish a midi byte stream | ||
| struct Finish { | ||
| explicit Finish() {} | ||
| }; | ||
|
|
||
| } // namespace |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,108 @@ | ||
| /* | ||
| ============================================================================== | ||
| This is an automatically generated GUI class created by the Introjucer! | ||
| Be careful when adding custom code to these files, as only the code within | ||
| the "//[xyz]" and "//[/xyz]" sections will be retained when the file is loaded | ||
| and re-saved. | ||
| Created with Introjucer version: 3.1.1 | ||
| ------------------------------------------------------------------------------ | ||
| The Introjucer is part of the JUCE library - "Jules' Utility Class Extensions" | ||
| Copyright 2004-13 by Raw Material Software Ltd. | ||
| ============================================================================== | ||
| */ | ||
|
|
||
| //[Headers] You can add your own extra header files here... | ||
| //[/Headers] | ||
|
|
||
| #include "PluginEditor.h" | ||
|
|
||
|
|
||
| //[MiscUserDefs] You can add your own user definitions and misc code here... | ||
| //[/MiscUserDefs] | ||
|
|
||
| //============================================================================== | ||
| PureDataAudioProcessorEditor::PureDataAudioProcessorEditor (PureDataAudioProcessor& p) | ||
| : AudioProcessorEditor (p) | ||
| { | ||
| //[Constructor_pre] You can add your own custom stuff here.. | ||
| //[/Constructor_pre] | ||
|
|
||
|
|
||
| //[UserPreSize] | ||
| //[/UserPreSize] | ||
|
|
||
| setSize (600, 400); | ||
|
|
||
|
|
||
| //[Constructor] You can add your own custom stuff here.. | ||
| //[/Constructor] | ||
| } | ||
|
|
||
| PureDataAudioProcessorEditor::~PureDataAudioProcessorEditor() | ||
| { | ||
| //[Destructor_pre]. You can add your own custom destruction code here.. | ||
| //[/Destructor_pre] | ||
|
|
||
|
|
||
|
|
||
| //[Destructor]. You can add your own custom destruction code here.. | ||
| //[/Destructor] | ||
| } | ||
|
|
||
| //============================================================================== | ||
| void PureDataAudioProcessorEditor::paint (Graphics& g) | ||
| { | ||
| //[UserPrePaint] Add your own custom painting code here.. | ||
| //[/UserPrePaint] | ||
|
|
||
| g.fillAll (Colours::white); | ||
|
|
||
| //[UserPaint] Add your own custom painting code here.. | ||
| //[/UserPaint] | ||
| } | ||
|
|
||
| void PureDataAudioProcessorEditor::resized() | ||
| { | ||
| //[UserPreResize] Add your own custom resize code here.. | ||
| //[/UserPreResize] | ||
|
|
||
| //[UserResized] Add your own custom resize handling here.. | ||
| //[/UserResized] | ||
| } | ||
|
|
||
|
|
||
|
|
||
| //[MiscUserCode] You can add your own definitions of your custom methods or any other code here... | ||
| //[/MiscUserCode] | ||
|
|
||
|
|
||
| //============================================================================== | ||
| #if 0 | ||
| /* -- Introjucer information section -- | ||
|
|
||
| This is where the Introjucer stores the metadata that describe this GUI layout, so | ||
| make changes in here at your peril! | ||
|
|
||
| BEGIN_JUCER_METADATA | ||
|
|
||
| <JUCER_COMPONENT documentType="Component" className="PureDataAudioProcessorEditor" | ||
| componentName="" parentClasses="public AudioProcessorEditor" | ||
| constructorParams="PureDataAudioProcessor& p" variableInitialisers="AudioProcessorEditor (p)" | ||
| snapPixels="8" snapActive="1" snapShown="1" overlayOpacity="0.330" | ||
| fixedSize="0" initialWidth="600" initialHeight="400"> | ||
| <BACKGROUND backgroundColour="ffffffff"/> | ||
| </JUCER_COMPONENT> | ||
|
|
||
| END_JUCER_METADATA | ||
| */ | ||
| #endif | ||
|
|
||
|
|
||
| //[EndFile] You can add extra defines here... | ||
| //[/EndFile] |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,68 @@ | ||
| /* | ||
| ============================================================================== | ||
| This is an automatically generated GUI class created by the Introjucer! | ||
| Be careful when adding custom code to these files, as only the code within | ||
| the "//[xyz]" and "//[/xyz]" sections will be retained when the file is loaded | ||
| and re-saved. | ||
| Created with Introjucer version: 3.1.1 | ||
| ------------------------------------------------------------------------------ | ||
| The Introjucer is part of the JUCE library - "Jules' Utility Class Extensions" | ||
| Copyright 2004-13 by Raw Material Software Ltd. | ||
| ============================================================================== | ||
| */ | ||
|
|
||
| #ifndef __JUCE_HEADER_DFA254F056F7859__ | ||
| #define __JUCE_HEADER_DFA254F056F7859__ | ||
|
|
||
| //[Headers] -- You can add your own extra header files here -- | ||
| #include "JuceHeader.h" | ||
| #include "PluginProcessor.h" | ||
| //[/Headers] | ||
|
|
||
|
|
||
|
|
||
| //============================================================================== | ||
| /** | ||
| //[Comments] | ||
| An auto-generated component, created by the Introjucer. | ||
| Describe your class and how it works here! | ||
| //[/Comments] | ||
| */ | ||
| class PureDataAudioProcessorEditor : public AudioProcessorEditor | ||
| { | ||
| public: | ||
| //============================================================================== | ||
| PureDataAudioProcessorEditor (PureDataAudioProcessor& p); | ||
| ~PureDataAudioProcessorEditor(); | ||
|
|
||
| //============================================================================== | ||
| //[UserMethods] -- You can add your own custom methods in this section. | ||
| //[/UserMethods] | ||
|
|
||
| void paint (Graphics& g); | ||
| void resized(); | ||
|
|
||
|
|
||
|
|
||
| private: | ||
| //[UserVariables] -- You can add your own custom variables in this section. | ||
| //[/UserVariables] | ||
|
|
||
| //============================================================================== | ||
|
|
||
|
|
||
| //============================================================================== | ||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (PureDataAudioProcessorEditor) | ||
| }; | ||
|
|
||
| //[EndFile] You can add extra defines here... | ||
| //[/EndFile] | ||
|
|
||
| #endif // __JUCE_HEADER_DFA254F056F7859__ |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,375 @@ | ||
| /* | ||
| ============================================================================== | ||
| This file was auto-generated by the Introjucer! | ||
| It contains the basic framework code for a JUCE plugin processor. | ||
| ============================================================================== | ||
| */ | ||
| #include "PluginProcessor.h" | ||
| #include "MainComponent.h" | ||
|
|
||
| bool PureDataAudioProcessor::otherInstanceAlreadyRunning; | ||
|
|
||
| //============================================================================== | ||
| PureDataAudioProcessor::PureDataAudioProcessor() | ||
| { | ||
| for (int i=0; i<10; i++) { | ||
| FloatParameter* p = new FloatParameter (0.5, ("Param" + (String) (i+1)).toStdString()); | ||
| parameterList.add(p); | ||
| addParameter(p); | ||
| } | ||
|
|
||
| if(PureDataAudioProcessor::otherInstanceAlreadyRunning) { | ||
| isInstanceLocked = true; | ||
| } | ||
| PureDataAudioProcessor::otherInstanceAlreadyRunning = true; | ||
| } | ||
|
|
||
| PureDataAudioProcessor::~PureDataAudioProcessor() | ||
| { | ||
| pd = nullptr; | ||
|
|
||
| if (!isInstanceLocked) { | ||
| PureDataAudioProcessor::otherInstanceAlreadyRunning = false; | ||
| } | ||
| } | ||
|
|
||
| //============================================================================== | ||
| void PureDataAudioProcessor::setParameterName(int index, String name) | ||
| { | ||
| FloatParameter* p = parameterList.getUnchecked(index); | ||
| p->setName(name); | ||
| } | ||
|
|
||
|
|
||
| const String PureDataAudioProcessor::getName() const | ||
| { | ||
| return JucePlugin_Name; | ||
| } | ||
|
|
||
| const String PureDataAudioProcessor::getInputChannelName (int channelIndex) const | ||
| { | ||
| return String (channelIndex + 1); | ||
| } | ||
|
|
||
| const String PureDataAudioProcessor::getOutputChannelName (int channelIndex) const | ||
| { | ||
| return String (channelIndex + 1); | ||
| } | ||
|
|
||
| bool PureDataAudioProcessor::isInputChannelStereoPair (int index) const | ||
| { | ||
| return true; | ||
| } | ||
|
|
||
| bool PureDataAudioProcessor::isOutputChannelStereoPair (int index) const | ||
| { | ||
| return true; | ||
| } | ||
|
|
||
| bool PureDataAudioProcessor::acceptsMidi() const | ||
| { | ||
| #if JucePlugin_WantsMidiInput | ||
| return true; | ||
| #else | ||
| return false; | ||
| #endif | ||
| } | ||
|
|
||
| bool PureDataAudioProcessor::producesMidi() const | ||
| { | ||
| #if JucePlugin_ProducesMidiOutput | ||
| return true; | ||
| #else | ||
| return false; | ||
| #endif | ||
| } | ||
|
|
||
| bool PureDataAudioProcessor::silenceInProducesSilenceOut() const | ||
| { | ||
| return false; | ||
| } | ||
|
|
||
| double PureDataAudioProcessor::getTailLengthSeconds() const | ||
| { | ||
| return 0.0; | ||
| } | ||
|
|
||
| int PureDataAudioProcessor::getNumPrograms() | ||
| { | ||
| return 1; // NB: some hosts don't cope very well if you tell them there are 0 programs, | ||
| // so this should be at least 1, even if you're not really implementing programs. | ||
| } | ||
|
|
||
| int PureDataAudioProcessor::getCurrentProgram() | ||
| { | ||
| return 0; | ||
| } | ||
|
|
||
| void PureDataAudioProcessor::setCurrentProgram (int index) | ||
| { | ||
| } | ||
|
|
||
| const String PureDataAudioProcessor::getProgramName (int index) | ||
| { | ||
| return String(); | ||
| } | ||
|
|
||
| void PureDataAudioProcessor::changeProgramName (int index, const String& newName) | ||
| { | ||
| } | ||
|
|
||
| //============================================================================== | ||
| void PureDataAudioProcessor::prepareToPlay (double sampleRate, int samplesPerBlock) | ||
| { | ||
| // Use this method as the place to do any pre-playback | ||
| // initialisation that you need.. | ||
| reloadPatch(sampleRate); | ||
|
|
||
| pos = 0; | ||
| } | ||
|
|
||
| void PureDataAudioProcessor::releaseResources() | ||
| { | ||
| // When playback stops, you can use this as an opportunity to free up any | ||
| // spare memory, etc. | ||
| if (pd != nullptr) | ||
| { | ||
| pd->computeAudio (false); | ||
| pd->closePatch (patch); | ||
| } | ||
|
|
||
| pd = nullptr; | ||
| pdInBuffer.free(); | ||
| pdOutBuffer.free(); | ||
| } | ||
|
|
||
|
|
||
| void PureDataAudioProcessor::processBlock (AudioSampleBuffer& buffer, MidiBuffer& midiMessages) | ||
| { | ||
| if (isInstanceLocked) { | ||
| 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 = getNumInputChannels(); i < getNumOutputChannels(); ++i) | ||
| buffer.clear (i, 0, buffer.getNumSamples()); | ||
|
|
||
| int numChannels = jmin (getNumInputChannels(), getNumOutputChannels()); | ||
| int len = buffer.getNumSamples(); | ||
| int idx = 0; | ||
|
|
||
| for (int i=0; i<parameterList.size(); i++) { | ||
| FloatParameter* parameter = parameterList[i]; | ||
| pd->sendFloat(parameter->getName(300).toStdString(), parameter->getValue()); | ||
| } | ||
|
|
||
| MidiMessage message; | ||
| MidiBuffer::Iterator it (midiMessages); | ||
| int samplePosition = buffer.getNumSamples(); | ||
|
|
||
| while (it.getNextEvent (message, samplePosition)) | ||
| { | ||
| if (message.isNoteOn (true)) { | ||
| pd->sendNoteOn (message.getChannel(), message.getNoteNumber(), message.getVelocity()); | ||
| } | ||
| if (message.isNoteOff (true)) { | ||
| pd->sendNoteOn (message.getChannel(), message.getNoteNumber(), 0); | ||
| } | ||
| } | ||
|
|
||
| while (len > 0) | ||
| { | ||
| int max = jmin (len, pd->blockSize()); | ||
|
|
||
| /* interleave audio */ | ||
| { | ||
| float* dstBuffer = pdInBuffer.getData(); | ||
| for (int i = 0; i < max; ++i) | ||
| { | ||
| for (int channelIndex = 0; channelIndex < numChannels; ++channelIndex) | ||
| *dstBuffer++ = buffer.getReadPointer(channelIndex) [idx + i]; | ||
| } | ||
| } | ||
|
|
||
| pd->processFloat (1, pdInBuffer.getData(), pdOutBuffer.getData()); | ||
|
|
||
| /* write-back */ | ||
| { | ||
| const float* srcBuffer = pdOutBuffer.getData(); | ||
| for (int i = 0; i < max; ++i) | ||
| { | ||
| for (int channelIndex = 0; channelIndex < numChannels; ++channelIndex) | ||
| buffer.getWritePointer (channelIndex) [idx + i] = *srcBuffer++; | ||
| } | ||
| } | ||
|
|
||
| idx += max; | ||
| len -= max; | ||
| } | ||
| } | ||
|
|
||
| //============================================================================== | ||
| bool PureDataAudioProcessor::hasEditor() const | ||
| { | ||
| return true; // (change this to false if you choose to not supply an editor) | ||
| } | ||
|
|
||
| AudioProcessorEditor* PureDataAudioProcessor::createEditor() | ||
| { | ||
| return new MainComponent(*this); | ||
| } | ||
|
|
||
| //============================================================================== | ||
| void PureDataAudioProcessor::getStateInformation (MemoryBlock& destData) | ||
| { | ||
| // You should use this method to store your parameters in the memory block. | ||
| // You could do that either as raw data, or use the XML or ValueTree classes | ||
| // as intermediaries to make it easy to save and load complex data. | ||
|
|
||
| // STORE / SAVE | ||
|
|
||
| XmlElement xml(getName()); | ||
|
|
||
| // patchfile | ||
| XmlElement* patchfileElement = new XmlElement("patchfile"); | ||
| patchfileElement->setAttribute("path", patchfile.getParentDirectory().getFullPathName()); | ||
| patchfileElement->setAttribute("fullpath", patchfile.getFullPathName()); | ||
| patchfileElement->setAttribute("filename", patchfile.getFileName()); | ||
| xml.addChildElement(patchfileElement); | ||
|
|
||
| // parameters | ||
| XmlElement* parameterListElement = new XmlElement("parameterList"); | ||
|
|
||
| for(size_t i = 0; i < parameterList.size(); ++i) { | ||
|
|
||
| XmlElement* parameterElement = new XmlElement("parameter"); | ||
| FloatParameter* parameter = parameterList[i]; | ||
| parameterElement->setAttribute("index", (int) parameter->getParameterIndex()); | ||
| parameterElement->setAttribute("name", parameter->getName(256)); | ||
| parameterElement->setAttribute("value", (double) parameter->getValue()); | ||
|
|
||
| parameterListElement->addChildElement(parameterElement); | ||
| } | ||
| xml.addChildElement(parameterListElement); | ||
|
|
||
| MemoryOutputStream stream; | ||
| xml.writeToStream(stream, ""); | ||
| //std::cout << "save [" << stream.toString() << "] " << std::endl; | ||
|
|
||
| copyXmlToBinary(xml, destData); | ||
| } | ||
|
|
||
| void PureDataAudioProcessor::setStateInformation (const void* data, int sizeInBytes) | ||
| { | ||
| // You should use this method to restore your parameters from this memory block, | ||
| // whose contents will have been created by the getStateInformation() call. | ||
|
|
||
| // RESTORE / LOAD | ||
|
|
||
| ScopedPointer<XmlElement> xml(getXmlFromBinary(data, sizeInBytes)); | ||
| if(xml != 0 && xml->hasTagName(getName())) { | ||
|
|
||
| MemoryOutputStream stream; | ||
| xml->writeToStream(stream, "<?xml version=\"1.0\"?>"); | ||
| //std::cout << "load [" << stream.toString() << "] " << std::endl; | ||
|
|
||
| forEachXmlChildElement (*xml, child) | ||
| { | ||
| 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; | ||
| } | ||
| } | ||
|
|
||
| if(child->hasTagName("parameterList")) { | ||
| forEachXmlChildElement (*child, parameterElement) { | ||
|
|
||
| //std::cout << "loading param " << parameterElement->getStringAttribute("name"); | ||
| //std::cout << "[" << parameterElement->getIntAttribute("index") << "]: "; | ||
| //std::cout << parameterElement->getDoubleAttribute("value") << std::endl; | ||
|
|
||
| setParameter(parameterElement->getIntAttribute("index"), (float) parameterElement->getDoubleAttribute("value")); | ||
| setParameterName(parameterElement->getIntAttribute("index"), parameterElement->getStringAttribute("name")); | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
||
| void PureDataAudioProcessor::reloadPatch (double sampleRate) | ||
| { | ||
| if (isInstanceLocked) { | ||
| status = "Currently only one simultaneous instance of this plugin is allowed"; | ||
| return; | ||
| } | ||
|
|
||
| if (sampleRate) { | ||
| cachedSampleRate = sampleRate; | ||
| } else { | ||
| sampleRate = cachedSampleRate; | ||
| } | ||
|
|
||
| if (pd) { | ||
| pd->computeAudio(false); | ||
| pd->closePatch(patch); | ||
| } | ||
|
|
||
| pd = new pd::PdBase; | ||
| pd->init (getNumInputChannels(), getNumOutputChannels(), sampleRate); | ||
|
|
||
| int numChannels = jmin (getNumInputChannels(), getNumOutputChannels()); | ||
| pdInBuffer.calloc (pd->blockSize() * numChannels); | ||
| pdOutBuffer.calloc (pd->blockSize() * numChannels); | ||
|
|
||
|
|
||
| if (!patchfile.exists()) { | ||
|
|
||
| if (patchfile.getFullPathName().toStdString() != "") { | ||
| status = "File does not exist"; | ||
| } | ||
|
|
||
| return; | ||
| } | ||
|
|
||
| if (patchfile.isDirectory()) { | ||
| status = "You selected a directory"; | ||
| return; | ||
| } | ||
|
|
||
| patch = pd->openPatch (patchfile.getFileName().toStdString(), patchfile.getParentDirectory().getFullPathName().toStdString()); | ||
|
|
||
| if (patch.isValid()) { | ||
| pd->computeAudio (true); | ||
| status = "Patch loaded successfully"; | ||
| } else { | ||
| status = "Selected patch is not valid, sorry"; | ||
| } | ||
|
|
||
| } | ||
|
|
||
| void PureDataAudioProcessor::setPatchFile(File file) | ||
| { | ||
| patchfile = file; | ||
| } | ||
|
|
||
| File PureDataAudioProcessor::getPatchFile() | ||
| { | ||
| return patchfile; | ||
| } | ||
|
|
||
| //============================================================================== | ||
| // This creates new instances of the plugin.. | ||
| AudioProcessor* JUCE_CALLTYPE createPluginFilter() | ||
| { | ||
| return new PureDataAudioProcessor(); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,96 @@ | ||
| /* | ||
| ============================================================================== | ||
| This file was auto-generated by the Introjucer! | ||
| It contains the basic framework code for a JUCE plugin processor. | ||
| ============================================================================== | ||
| */ | ||
|
|
||
| #ifndef PLUGINPROCESSOR_H_INCLUDED | ||
| #define PLUGINPROCESSOR_H_INCLUDED | ||
|
|
||
| #include "PdBase.hpp" | ||
| #include "../JuceLibraryCode/JuceHeader.h" | ||
| #include "FloatParameter.h" | ||
|
|
||
|
|
||
| //============================================================================== | ||
| /** | ||
| */ | ||
| class PureDataAudioProcessor : public AudioProcessor | ||
| { | ||
| public: | ||
| //============================================================================== | ||
| PureDataAudioProcessor(); | ||
| ~PureDataAudioProcessor(); | ||
|
|
||
| void setParameterName(int index, String name); | ||
|
|
||
| //============================================================================== | ||
| void prepareToPlay (double sampleRate, int samplesPerBlock) override; | ||
| void releaseResources() override; | ||
|
|
||
| void processBlock (AudioSampleBuffer&, MidiBuffer&) override; | ||
|
|
||
| //============================================================================== | ||
| AudioProcessorEditor* createEditor() override; | ||
| bool hasEditor() const override; | ||
|
|
||
| //============================================================================== | ||
| const String getName() const override; | ||
|
|
||
| const String getInputChannelName (int channelIndex) const override; | ||
| const String getOutputChannelName (int channelIndex) const override; | ||
| bool isInputChannelStereoPair (int index) const override; | ||
| bool isOutputChannelStereoPair (int index) const override; | ||
|
|
||
| bool acceptsMidi() const override; | ||
| bool producesMidi() const override; | ||
| bool silenceInProducesSilenceOut() const override; | ||
| double getTailLengthSeconds() const override; | ||
|
|
||
| //============================================================================== | ||
| int getNumPrograms() override; | ||
| int getCurrentProgram() override; | ||
| void setCurrentProgram (int index) override; | ||
| const String getProgramName (int index) override; | ||
| void changeProgramName (int index, const String& newName) override; | ||
|
|
||
| //============================================================================== | ||
| void getStateInformation (MemoryBlock& destData) override; | ||
| void setStateInformation (const void* data, int sizeInBytes) override; | ||
|
|
||
| void reloadPatch(double sampleRate); | ||
| void setPatchFile(File file); | ||
| File getPatchFile(); | ||
|
|
||
| String status = "Select a pure data patch file..."; | ||
| static bool otherInstanceAlreadyRunning; | ||
| bool isInstanceLocked = false; | ||
|
|
||
| private: | ||
| 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; | ||
|
|
||
| File patchfile; | ||
|
|
||
| pd::Patch patch; | ||
| HeapBlock<float> pdInBuffer, pdOutBuffer; | ||
| double cachedSampleRate; | ||
| //============================================================================== | ||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (PureDataAudioProcessor) | ||
| }; | ||
|
|
||
|
|
||
| #endif // PLUGINPROCESSOR_H_INCLUDED |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,187 @@ | ||
| /* | ||
| ============================================================================== | ||
| This is an automatically generated GUI class created by the Introjucer! | ||
| Be careful when adding custom code to these files, as only the code within | ||
| the "//[xyz]" and "//[/xyz]" sections will be retained when the file is loaded | ||
| and re-saved. | ||
| Created with Introjucer version: 3.1.1 | ||
| ------------------------------------------------------------------------------ | ||
| The Introjucer is part of the JUCE library - "Jules' Utility Class Extensions" | ||
| Copyright 2004-13 by Raw Material Software Ltd. | ||
| ============================================================================== | ||
| */ | ||
|
|
||
| //[Headers] You can add your own extra header files here... | ||
| #include "PluginProcessor.h" | ||
| //[/Headers] | ||
|
|
||
| #include "SendSlider.h" | ||
|
|
||
|
|
||
| //[MiscUserDefs] You can add your own user definitions and misc code here... | ||
| //[/MiscUserDefs] | ||
|
|
||
| //============================================================================== | ||
| SendSlider::SendSlider (int index, AudioProcessor& processor) | ||
| : index(index), | ||
| processor(processor) | ||
| { | ||
| //[Constructor_pre] You can add your own custom stuff here.. | ||
| //[/Constructor_pre] | ||
|
|
||
| addAndMakeVisible (slider = new Slider ("slider")); | ||
| slider->setRange (0, 1, 0); | ||
| slider->setSliderStyle (Slider::RotaryVerticalDrag); | ||
| slider->setTextBoxStyle (Slider::TextBoxBelow, false, 80, 20); | ||
| 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->addListener (this); | ||
|
|
||
| addAndMakeVisible (label = new Label ("label", | ||
| TRANS("Label"))); | ||
| label->setTooltip (TRANS("Click to set the name of the corresponding Pure Data receive port.")); | ||
| label->setFont (Font (15.00f, Font::plain)); | ||
| label->setJustificationType (Justification::centred); | ||
| label->setEditable (true, true, false); | ||
| label->setColour (Label::backgroundColourId, Colour (0x00404040)); | ||
| label->setColour (Label::textColourId, Colour (0xffc4c4c4)); | ||
| label->setColour (TextEditor::textColourId, Colour (0xffe9e9e9)); | ||
| label->setColour (TextEditor::backgroundColourId, Colour (0x00343434)); | ||
| label->addListener (this); | ||
|
|
||
|
|
||
| //[UserPreSize] | ||
| //[/UserPreSize] | ||
|
|
||
| setSize (100, 130); | ||
|
|
||
|
|
||
| //[Constructor] You can add your own custom stuff here.. | ||
| PureDataAudioProcessor& p = (PureDataAudioProcessor&) processor; | ||
| String labelText(p.getParameterName(index-1)); | ||
| label->setText(labelText, dontSendNotification); | ||
|
|
||
| startTimer(25); | ||
| //[/Constructor] | ||
| } | ||
|
|
||
| SendSlider::~SendSlider() | ||
| { | ||
| //[Destructor_pre]. You can add your own custom destruction code here.. | ||
| //[/Destructor_pre] | ||
|
|
||
| slider = nullptr; | ||
| label = nullptr; | ||
|
|
||
|
|
||
| //[Destructor]. You can add your own custom destruction code here.. | ||
| //[/Destructor] | ||
| } | ||
|
|
||
| //============================================================================== | ||
| void SendSlider::paint (Graphics& g) | ||
| { | ||
| //[UserPrePaint] Add your own custom painting code here.. | ||
| //[/UserPrePaint] | ||
|
|
||
| //[UserPaint] Add your own custom painting code here.. | ||
| //[/UserPaint] | ||
| } | ||
|
|
||
| void SendSlider::resized() | ||
| { | ||
| //[UserPreResize] Add your own custom resize code here.. | ||
| //[/UserPreResize] | ||
|
|
||
| slider->setBounds (14, 35, 71, 80); | ||
| label->setBounds (-4, 5, 104, 24); | ||
| //[UserResized] Add your own custom resize handling here.. | ||
| //[/UserResized] | ||
| } | ||
|
|
||
| void SendSlider::sliderValueChanged (Slider* sliderThatWasMoved) | ||
| { | ||
| //[UsersliderValueChanged_Pre] | ||
| //[/UsersliderValueChanged_Pre] | ||
|
|
||
| if (sliderThatWasMoved == slider) | ||
| { | ||
| //[UserSliderCode_slider] -- add your slider handling code here.. | ||
| processor.setParameterNotifyingHost(index-1, sliderThatWasMoved->getValue()); | ||
| //[/UserSliderCode_slider] | ||
| } | ||
|
|
||
| //[UsersliderValueChanged_Post] | ||
| //[/UsersliderValueChanged_Post] | ||
| } | ||
|
|
||
| void SendSlider::labelTextChanged (Label* labelThatHasChanged) | ||
| { | ||
| //[UserlabelTextChanged_Pre] | ||
| //[/UserlabelTextChanged_Pre] | ||
|
|
||
| if (labelThatHasChanged == label) | ||
| { | ||
| //[UserLabelCode_label] -- add your label text handling code here.. | ||
| PureDataAudioProcessor& p = (PureDataAudioProcessor&) processor; | ||
| p.setParameterName(index-1, labelThatHasChanged->getTextValue().toString()); | ||
| //[/UserLabelCode_label] | ||
| } | ||
|
|
||
| //[UserlabelTextChanged_Post] | ||
| //[/UserlabelTextChanged_Post] | ||
| } | ||
|
|
||
|
|
||
|
|
||
| //[MiscUserCode] You can add your own definitions of your custom methods or any other code here... | ||
| void SendSlider::timerCallback() | ||
| { | ||
| slider->setValue(processor.getParameter(index-1), NotificationType::dontSendNotification); | ||
| } | ||
| //[/MiscUserCode] | ||
|
|
||
|
|
||
| //============================================================================== | ||
| #if 0 | ||
| /* -- Introjucer information section -- | ||
|
|
||
| This is where the Introjucer stores the metadata that describe this GUI layout, so | ||
| make changes in here at your peril! | ||
|
|
||
| BEGIN_JUCER_METADATA | ||
|
|
||
| <JUCER_COMPONENT documentType="Component" className="SendSlider" componentName="" | ||
| parentClasses="public Component, public Timer" constructorParams="int index, AudioProcessor& 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" | ||
| 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"/> | ||
| </JUCER_COMPONENT> | ||
|
|
||
| END_JUCER_METADATA | ||
| */ | ||
| #endif | ||
|
|
||
|
|
||
| //[EndFile] You can add extra defines here... | ||
| //[/EndFile] |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,77 @@ | ||
| /* | ||
| ============================================================================== | ||
| This is an automatically generated GUI class created by the Introjucer! | ||
| Be careful when adding custom code to these files, as only the code within | ||
| the "//[xyz]" and "//[/xyz]" sections will be retained when the file is loaded | ||
| and re-saved. | ||
| Created with Introjucer version: 3.1.1 | ||
| ------------------------------------------------------------------------------ | ||
| The Introjucer is part of the JUCE library - "Jules' Utility Class Extensions" | ||
| Copyright 2004-13 by Raw Material Software Ltd. | ||
| ============================================================================== | ||
| */ | ||
|
|
||
| #ifndef __JUCE_HEADER_E639DC74856C943A__ | ||
| #define __JUCE_HEADER_E639DC74856C943A__ | ||
|
|
||
| //[Headers] -- You can add your own extra header files here -- | ||
| #include "JuceHeader.h" | ||
| //[/Headers] | ||
|
|
||
|
|
||
|
|
||
| //============================================================================== | ||
| /** | ||
| //[Comments] | ||
| An auto-generated component, created by the Introjucer. | ||
| Describe your class and how it works here! | ||
| //[/Comments] | ||
| */ | ||
| class SendSlider : public Component, | ||
| public Timer, | ||
| public SliderListener, | ||
| public LabelListener | ||
| { | ||
| public: | ||
| //============================================================================== | ||
| SendSlider (int index, AudioProcessor& processor); | ||
| ~SendSlider(); | ||
|
|
||
| //============================================================================== | ||
| //[UserMethods] -- You can add your own custom methods in this section. | ||
| void timerCallback(); | ||
| //[/UserMethods] | ||
|
|
||
| void paint (Graphics& g); | ||
| void resized(); | ||
| void sliderValueChanged (Slider* sliderThatWasMoved); | ||
| void labelTextChanged (Label* labelThatHasChanged); | ||
|
|
||
|
|
||
|
|
||
| private: | ||
| //[UserVariables] -- You can add your own custom variables in this section. | ||
| int index; | ||
| AudioProcessor& processor; | ||
| //[/UserVariables] | ||
|
|
||
| //============================================================================== | ||
| ScopedPointer<Slider> slider; | ||
| ScopedPointer<Label> label; | ||
|
|
||
|
|
||
| //============================================================================== | ||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (SendSlider) | ||
| }; | ||
|
|
||
| //[EndFile] You can add extra defines here... | ||
| //[/EndFile] | ||
|
|
||
| #endif // __JUCE_HEADER_E639DC74856C943A__ |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,101 @@ | ||
| /* | ||
| * Copyright (c) 2012 Peter Brinkmann (peter.brinkmann@gmail.com) | ||
| * | ||
| * For information on usage and redistribution, and for a DISCLAIMER OF ALL | ||
| * WARRANTIES, see the file, "LICENSE.txt," in this distribution. | ||
| */ | ||
|
|
||
| #include "ringbuffer.h" | ||
|
|
||
| #include <stdarg.h> | ||
| #include <stdlib.h> | ||
| #include <string.h> | ||
|
|
||
| ring_buffer *rb_create(int size) { | ||
| if (size & 0xff) return NULL; // size must be a multiple of 256 | ||
| ring_buffer *buffer = malloc(sizeof(ring_buffer)); | ||
| if (!buffer) return NULL; | ||
| buffer->buf_ptr = calloc(size, sizeof(char)); | ||
| if (!buffer->buf_ptr) { | ||
| free(buffer); | ||
| return NULL; | ||
| } | ||
| buffer->size = size; | ||
| buffer->write_idx = 0; | ||
| buffer->read_idx = 0; | ||
| return buffer; | ||
| } | ||
|
|
||
| void rb_free(ring_buffer *buffer) { | ||
| free(buffer->buf_ptr); | ||
| free(buffer); | ||
| } | ||
|
|
||
| int rb_available_to_write(ring_buffer *buffer) { | ||
| if (buffer) { | ||
| // Note: The largest possible result is buffer->size - 1 because | ||
| // we adopt the convention that read_idx == write_idx means that the | ||
| // buffer is empty. | ||
| int read_idx = __sync_fetch_and_or(&(buffer->read_idx), 0); | ||
| int write_idx = __sync_fetch_and_or(&(buffer->write_idx), 0); | ||
| return (buffer->size + read_idx - write_idx - 1) % buffer->size; | ||
| } else { | ||
| return 0; | ||
| } | ||
| } | ||
|
|
||
| int rb_available_to_read(ring_buffer *buffer) { | ||
| if (buffer) { | ||
| int read_idx = __sync_fetch_and_or(&(buffer->read_idx), 0); | ||
| int write_idx = __sync_fetch_and_or(&(buffer->write_idx), 0); | ||
| return (buffer->size + write_idx - read_idx) % buffer->size; | ||
| } else { | ||
| return 0; | ||
| } | ||
| } | ||
|
|
||
| int rb_write_to_buffer(ring_buffer *buffer, int n, ...) { | ||
| if (!buffer) return -1; | ||
| int write_idx = buffer->write_idx; // No need for sync in writer thread. | ||
| int available = rb_available_to_write(buffer); | ||
| va_list args; | ||
| va_start(args, n); | ||
| int i; | ||
| for (i = 0; i < n; ++i) { | ||
| const char* src = va_arg(args, const char*); | ||
| int len = va_arg(args, int); | ||
| available -= len; | ||
| if (len < 0 || available < 0) return -1; | ||
| if (write_idx + len <= buffer->size) { | ||
| memcpy(buffer->buf_ptr + write_idx, src, len); | ||
| } else { | ||
| int d = buffer->size - write_idx; | ||
| memcpy(buffer->buf_ptr + write_idx, src, d); | ||
| memcpy(buffer->buf_ptr, src + d, len - d); | ||
| } | ||
| write_idx = (write_idx + len) % buffer->size; | ||
| } | ||
| va_end(args); | ||
| __sync_val_compare_and_swap(&(buffer->write_idx), buffer->write_idx, | ||
| write_idx); // Includes memory barrier. | ||
| return 0; | ||
| } | ||
|
|
||
| int rb_read_from_buffer(ring_buffer *buffer, char *dest, int len) { | ||
| if (len == 0) return 0; | ||
| if (!buffer || len < 0 || len > rb_available_to_read(buffer)) return -1; | ||
| // Note that rb_available_to_read also serves as a memory barrier, and so any | ||
| // writes to buffer->buf_ptr that precede the update of buffer->write_idx are | ||
| // visible to us now. | ||
| int read_idx = buffer->read_idx; // No need for sync in reader thread. | ||
| if (read_idx + len <= buffer->size) { | ||
| memcpy(dest, buffer->buf_ptr + read_idx, len); | ||
| } else { | ||
| int d = buffer->size - read_idx; | ||
| memcpy(dest, buffer->buf_ptr + read_idx, d); | ||
| memcpy(dest + d, buffer->buf_ptr, len - d); | ||
| } | ||
| __sync_val_compare_and_swap(&(buffer->read_idx), buffer->read_idx, | ||
| (read_idx + len) % buffer->size); // Includes memory barrier. | ||
| return 0; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,46 @@ | ||
| /* | ||
| * Copyright (c) 2012 Peter Brinkmann (peter.brinkmann@gmail.com) | ||
| * | ||
| * For information on usage and redistribution, and for a DISCLAIMER OF ALL | ||
| * WARRANTIES, see the file, "LICENSE.txt," in this distribution. | ||
| */ | ||
|
|
||
| #ifndef __OPENSL_RING_BUFFER_H__ | ||
| #define __OPENSL_RING_BUFFER_H__ | ||
|
|
||
| // Simple lock-free ring buffer implementation for one writer thread and one | ||
| // consumer thread. | ||
| typedef struct ring_buffer { | ||
| int size; | ||
| char *buf_ptr; | ||
| int write_idx; | ||
| int read_idx; | ||
| } ring_buffer; | ||
|
|
||
| // Creates a ring buffer (returns NULL on failure). | ||
| ring_buffer *rb_create(int size); | ||
|
|
||
| // Deletes a ring buffer. | ||
| void rb_free(ring_buffer *buffer); | ||
|
|
||
| // Returns the number of bytes that can currently be written; safe to be called | ||
| // from any thread. | ||
| int rb_available_to_write(ring_buffer *buffer); | ||
|
|
||
| // Returns the number of bytes that can currently be read; safe to be called | ||
| // from any thread. | ||
| int rb_available_to_read(ring_buffer *buffer); | ||
|
|
||
| // Writes bytes from n sources to the ring buffer (if the ring buffer has | ||
| // enough space). The varargs are pairs of type (const char*, int) giving a | ||
| // pointer to a buffer and the number of bytes to be copied. Only to be called | ||
| // from a single writer thread. | ||
| // Returns 0 on success. | ||
| int rb_write_to_buffer(ring_buffer *buffer, int n, ...); | ||
|
|
||
| // Reads the given number of bytes fromthe ring buffer to dest if the ring | ||
| // buffer has enough data. Only to be called from a single reader thread. | ||
| // Returns 0 on success. | ||
| int rb_read_from_buffer(ring_buffer *buffer, char *dest, int len); | ||
|
|
||
| #endif |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,92 @@ | ||
| #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; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,34 @@ | ||
| #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; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| #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; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,57 @@ | ||
| #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; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,48 @@ | ||
| /* | ||
| * Copyright (c) 2013 Dan Wilcox (danomatika@gmail.com) & | ||
| * Peter Brinkmann (peter.brinkmann@gmail.com) | ||
| * | ||
| * For information on usage and redistribution, and for a DISCLAIMER OF ALL | ||
| * WARRANTIES, see the file, "LICENSE.txt," in this distribution. | ||
| */ | ||
|
|
||
| #include "z_print_util.h" | ||
|
|
||
| #include <stdlib.h> | ||
| #include <string.h> | ||
|
|
||
| t_libpd_printhook libpd_concatenated_printhook = NULL; | ||
|
|
||
| #define PRINT_LINE_SIZE 2048 | ||
|
|
||
| void libpd_set_concatenated_printhook(const t_libpd_printhook hook) { | ||
| libpd_concatenated_printhook = hook; | ||
| } | ||
|
|
||
| void libpd_print_concatenator(const char *s) { | ||
| if (!libpd_concatenated_printhook) return; | ||
|
|
||
| static char concatenated_print_line[PRINT_LINE_SIZE]; | ||
| static int len_line = 0; | ||
| concatenated_print_line[len_line] = '\0'; | ||
|
|
||
| int len = (int) strlen(s); | ||
| while (len_line + len >= PRINT_LINE_SIZE) { | ||
| int d = PRINT_LINE_SIZE - 1 - len_line; | ||
| strncat(concatenated_print_line, s, d); | ||
| libpd_concatenated_printhook(concatenated_print_line); | ||
| s += d; | ||
| len -= d; | ||
| len_line = 0; | ||
| concatenated_print_line[0] = '\0'; | ||
| } | ||
|
|
||
| strncat(concatenated_print_line, s, len); | ||
| len_line += len; | ||
|
|
||
| if (len_line > 0 && concatenated_print_line[len_line - 1] == '\n') { | ||
| concatenated_print_line[len_line - 1] = '\0'; | ||
| libpd_concatenated_printhook(concatenated_print_line); | ||
| len_line = 0; | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,45 @@ | ||
| /* | ||
| * Copyright (c) 2013 Dan Wilcox (danomatika@gmail.com) & | ||
| * Peter Brinkmann (peter.brinkmann@gmail.com) | ||
| * | ||
| * For information on usage and redistribution, and for a DISCLAIMER OF ALL | ||
| * WARRANTIES, see the file, "LICENSE.txt," in this distribution. | ||
| */ | ||
|
|
||
| #ifndef __Z_PRINT_UTIL_H__ | ||
| #define __Z_PRINT_UTIL_H__ | ||
|
|
||
| #include "z_libpd.h" | ||
|
|
||
| #ifdef __cplusplus | ||
| extern "C" | ||
| { | ||
| #endif | ||
|
|
||
| // Concatenate print messages into single lines before returning them to a print hook. | ||
| // ie "hello 123" is sent in 1 part -> "hello 123" | ||
| // | ||
| // For comparison, the default behavior returns individual words and spaces. | ||
| // ie "hello 123" is sent in 3 parts -> "hello", " ", "123" | ||
|
|
||
| // Assign the pointer to your print handler. | ||
| EXTERN void libpd_set_concatenated_printhook(const t_libpd_printhook hook); | ||
|
|
||
| // Assign this function pointer to libpd_printhook or libpd_queued_printhook, | ||
| // depending on whether you're using queued messages, to intercept and | ||
| // concatenate print messages: | ||
| // | ||
| // libpd_set_printhook(libpd_print_concatenator); | ||
| // libpd_set_concatenated_printhook(your_print_handler); | ||
| // | ||
| // Note: The char pointer argument is only good for the duration of the print | ||
| // callback; if you intend to use the argument after the callback has | ||
| // returned, you need to make a defensive copy. | ||
| // | ||
| void libpd_print_concatenator(const char *s); | ||
|
|
||
| #ifdef __cplusplus | ||
| } | ||
| #endif | ||
|
|
||
| #endif |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,42 @@ | ||
| /* | ||
| * Copyright (c) 2012 Peter Brinkmann (peter.brinkmann@gmail.com) | ||
| * | ||
| * For information on usage and redistribution, and for a DISCLAIMER OF ALL | ||
| * WARRANTIES, see the file, "LICENSE.txt," in this distribution. | ||
| */ | ||
|
|
||
| #ifndef __Z_QUEUED_H__ | ||
| #define __Z_QUEUED_H__ | ||
|
|
||
| #include "z_libpd.h" | ||
|
|
||
| #ifdef __cplusplus | ||
| extern "C" | ||
| { | ||
| #endif | ||
|
|
||
| EXTERN void libpd_set_queued_printhook(const t_libpd_printhook hook); | ||
| EXTERN void libpd_set_queued_banghook(const t_libpd_banghook hook); | ||
| EXTERN void libpd_set_queued_floathook(const t_libpd_floathook hook); | ||
| EXTERN void libpd_set_queued_symbolhook(const t_libpd_symbolhook hook); | ||
| EXTERN void libpd_set_queued_listhook(const t_libpd_listhook hook); | ||
| EXTERN void libpd_set_queued_messagehook(const t_libpd_messagehook hook); | ||
|
|
||
| EXTERN void libpd_set_queued_noteonhook(const t_libpd_noteonhook hook); | ||
| EXTERN void libpd_set_queued_controlchangehook(const t_libpd_controlchangehook hook); | ||
| EXTERN void libpd_set_queued_programchangehook(const t_libpd_programchangehook hook); | ||
| EXTERN void libpd_set_queued_pitchbendhook(const t_libpd_pitchbendhook hook); | ||
| EXTERN void libpd_set_queued_aftertouchhook(const t_libpd_aftertouchhook hook); | ||
| EXTERN void libpd_set_queued_polyaftertouchhook(const t_libpd_polyaftertouchhook hook); | ||
| EXTERN void libpd_set_queued_midibytehook(const t_libpd_midibytehook hook); | ||
|
|
||
| int libpd_queued_init(); | ||
| void libpd_queued_release(); | ||
| void libpd_queued_receive_pd_messages(); | ||
| void libpd_queued_receive_midi_messages(); | ||
|
|
||
| #ifdef __cplusplus | ||
| } | ||
| #endif | ||
|
|
||
| #endif |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,109 @@ | ||
|
|
||
| dofile("../../../scripts/make-project.lua") | ||
|
|
||
| package = make_juce_vst_project("PdPulpFX") | ||
|
|
||
| package.buildoptions = { | ||
| package.buildoptions, | ||
| "-Wno-unused", | ||
| "-Wno-unused-parameter", | ||
| "-Wno-parentheses", | ||
| "-Wno-switch" | ||
| } | ||
|
|
||
| package.defines = { | ||
| package.defines, | ||
| "PULP_SYNTH=0", | ||
| "USEAPI_DUMMY", | ||
| "PD", | ||
| "HAVE_LIBDL", | ||
| "HAVE_UNISTD_H", | ||
| "HAVE_ALLOCA_H", | ||
| "_LARGEFILE64_SOURCE" | ||
| } | ||
|
|
||
| package.includepaths = { | ||
| package.includepaths, | ||
| "../Source", | ||
| "../JuceLibraryCode", | ||
| "../libpd/libpd_wrapper", | ||
| "../libpd/pure-data/src" | ||
| } | ||
|
|
||
| package.files = { | ||
| matchfiles ( | ||
| "../Source/*.c", | ||
| "../Source/*.cpp", | ||
| "../libpd/pure-data/src/g_canvas.c", | ||
| "../libpd/pure-data/src/g_graph.c", | ||
| "../libpd/pure-data/src/g_text.c", | ||
| "../libpd/pure-data/src/g_rtext.c", | ||
| "../libpd/pure-data/src/g_array.c", | ||
| "../libpd/pure-data/src/g_template.c", | ||
| "../libpd/pure-data/src/g_io.c", | ||
| "../libpd/pure-data/src/g_scalar.c", | ||
| "../libpd/pure-data/src/g_traversal.c", | ||
| "../libpd/pure-data/src/g_guiconnect.c", | ||
| "../libpd/pure-data/src/g_readwrite.c", | ||
| "../libpd/pure-data/src/g_editor.c", | ||
| "../libpd/pure-data/src/g_all_guis.c", | ||
| "../libpd/pure-data/src/g_bang.c", | ||
| "../libpd/pure-data/src/g_hdial.c", | ||
| "../libpd/pure-data/src/g_hslider.c", | ||
| "../libpd/pure-data/src/g_mycanvas.c", | ||
| "../libpd/pure-data/src/g_numbox.c", | ||
| "../libpd/pure-data/src/g_toggle.c", | ||
| "../libpd/pure-data/src/g_vdial.c", | ||
| "../libpd/pure-data/src/g_vslider.c", | ||
| "../libpd/pure-data/src/g_vumeter.c", | ||
| "../libpd/pure-data/src/m_pd.c", | ||
| "../libpd/pure-data/src/m_class.c", | ||
| "../libpd/pure-data/src/m_obj.c", | ||
| "../libpd/pure-data/src/m_atom.c", | ||
| "../libpd/pure-data/src/m_memory.c", | ||
| "../libpd/pure-data/src/m_binbuf.c", | ||
| "../libpd/pure-data/src/m_conf.c", | ||
| "../libpd/pure-data/src/m_glob.c", | ||
| "../libpd/pure-data/src/m_sched.c", | ||
| "../libpd/pure-data/src/s_main.c", | ||
| "../libpd/pure-data/src/s_inter.c", | ||
| "../libpd/pure-data/src/s_file.c", | ||
| "../libpd/pure-data/src/s_print.c", | ||
| "../libpd/pure-data/src/s_loader.c", | ||
| "../libpd/pure-data/src/s_path.c", | ||
| "../libpd/pure-data/src/s_audio.c", | ||
| "../libpd/pure-data/src/s_audio_dummy.c", | ||
| "../libpd/pure-data/src/s_utf8.c", | ||
| "../libpd/pure-data/src/s_audio_paring.c", | ||
| "../libpd/pure-data/src/d_ugen.c", | ||
| "../libpd/pure-data/src/d_ctl.c", | ||
| "../libpd/pure-data/src/d_arithmetic.c", | ||
| "../libpd/pure-data/src/d_osc.c", | ||
| "../libpd/pure-data/src/d_filter.c", | ||
| "../libpd/pure-data/src/d_dac.c", | ||
| "../libpd/pure-data/src/d_misc.c", | ||
| "../libpd/pure-data/src/d_math.c", | ||
| "../libpd/pure-data/src/d_fft.c", | ||
| "../libpd/pure-data/src/d_fft_fftsg.c", | ||
| "../libpd/pure-data/src/d_array.c", | ||
| "../libpd/pure-data/src/d_global.c", | ||
| "../libpd/pure-data/src/d_delay.c", | ||
| "../libpd/pure-data/src/d_resample.c", | ||
| "../libpd/pure-data/src/d_soundfile.c", | ||
| "../libpd/pure-data/src/x_arithmetic.c", | ||
| "../libpd/pure-data/src/x_connective.c", | ||
| "../libpd/pure-data/src/x_interface.c", | ||
| "../libpd/pure-data/src/x_midi.c", | ||
| "../libpd/pure-data/src/x_misc.c", | ||
| "../libpd/pure-data/src/x_time.c", | ||
| "../libpd/pure-data/src/x_acoustics.c", | ||
| "../libpd/pure-data/src/x_net.c", | ||
| "../libpd/pure-data/src/x_text.c", | ||
| "../libpd/pure-data/src/x_gui.c", | ||
| "../libpd/pure-data/src/x_list.c", | ||
| "../libpd/pure-data/src/x_array.c", | ||
| "../libpd/pure-data/src/x_scalar.c", | ||
| "../libpd/libpd_wrapper/*.c", | ||
| "../../../libs/juce-plugin/JucePluginMain.cpp" | ||
| ) | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,109 @@ | ||
|
|
||
| dofile("../../../scripts/make-project.lua") | ||
|
|
||
| package = make_juce_vst_project("PdPulp") | ||
|
|
||
| package.buildoptions = { | ||
| package.buildoptions, | ||
| "-Wno-unused", | ||
| "-Wno-unused-parameter", | ||
| "-Wno-parentheses", | ||
| "-Wno-switch" | ||
| } | ||
|
|
||
| package.defines = { | ||
| package.defines, | ||
| "PULP_SYNTH=1", | ||
| "USEAPI_DUMMY", | ||
| "PD", | ||
| "HAVE_LIBDL", | ||
| "HAVE_UNISTD_H", | ||
| "HAVE_ALLOCA_H", | ||
| "_LARGEFILE64_SOURCE" | ||
| } | ||
|
|
||
| package.includepaths = { | ||
| package.includepaths, | ||
| "../Source", | ||
| "../JuceLibraryCode", | ||
| "../libpd/libpd_wrapper", | ||
| "../libpd/pure-data/src" | ||
| } | ||
|
|
||
| package.files = { | ||
| matchfiles ( | ||
| "../Source/*.c", | ||
| "../Source/*.cpp", | ||
| "../libpd/pure-data/src/g_canvas.c", | ||
| "../libpd/pure-data/src/g_graph.c", | ||
| "../libpd/pure-data/src/g_text.c", | ||
| "../libpd/pure-data/src/g_rtext.c", | ||
| "../libpd/pure-data/src/g_array.c", | ||
| "../libpd/pure-data/src/g_template.c", | ||
| "../libpd/pure-data/src/g_io.c", | ||
| "../libpd/pure-data/src/g_scalar.c", | ||
| "../libpd/pure-data/src/g_traversal.c", | ||
| "../libpd/pure-data/src/g_guiconnect.c", | ||
| "../libpd/pure-data/src/g_readwrite.c", | ||
| "../libpd/pure-data/src/g_editor.c", | ||
| "../libpd/pure-data/src/g_all_guis.c", | ||
| "../libpd/pure-data/src/g_bang.c", | ||
| "../libpd/pure-data/src/g_hdial.c", | ||
| "../libpd/pure-data/src/g_hslider.c", | ||
| "../libpd/pure-data/src/g_mycanvas.c", | ||
| "../libpd/pure-data/src/g_numbox.c", | ||
| "../libpd/pure-data/src/g_toggle.c", | ||
| "../libpd/pure-data/src/g_vdial.c", | ||
| "../libpd/pure-data/src/g_vslider.c", | ||
| "../libpd/pure-data/src/g_vumeter.c", | ||
| "../libpd/pure-data/src/m_pd.c", | ||
| "../libpd/pure-data/src/m_class.c", | ||
| "../libpd/pure-data/src/m_obj.c", | ||
| "../libpd/pure-data/src/m_atom.c", | ||
| "../libpd/pure-data/src/m_memory.c", | ||
| "../libpd/pure-data/src/m_binbuf.c", | ||
| "../libpd/pure-data/src/m_conf.c", | ||
| "../libpd/pure-data/src/m_glob.c", | ||
| "../libpd/pure-data/src/m_sched.c", | ||
| "../libpd/pure-data/src/s_main.c", | ||
| "../libpd/pure-data/src/s_inter.c", | ||
| "../libpd/pure-data/src/s_file.c", | ||
| "../libpd/pure-data/src/s_print.c", | ||
| "../libpd/pure-data/src/s_loader.c", | ||
| "../libpd/pure-data/src/s_path.c", | ||
| "../libpd/pure-data/src/s_audio.c", | ||
| "../libpd/pure-data/src/s_audio_dummy.c", | ||
| "../libpd/pure-data/src/s_utf8.c", | ||
| "../libpd/pure-data/src/s_audio_paring.c", | ||
| "../libpd/pure-data/src/d_ugen.c", | ||
| "../libpd/pure-data/src/d_ctl.c", | ||
| "../libpd/pure-data/src/d_arithmetic.c", | ||
| "../libpd/pure-data/src/d_osc.c", | ||
| "../libpd/pure-data/src/d_filter.c", | ||
| "../libpd/pure-data/src/d_dac.c", | ||
| "../libpd/pure-data/src/d_misc.c", | ||
| "../libpd/pure-data/src/d_math.c", | ||
| "../libpd/pure-data/src/d_fft.c", | ||
| "../libpd/pure-data/src/d_fft_fftsg.c", | ||
| "../libpd/pure-data/src/d_array.c", | ||
| "../libpd/pure-data/src/d_global.c", | ||
| "../libpd/pure-data/src/d_delay.c", | ||
| "../libpd/pure-data/src/d_resample.c", | ||
| "../libpd/pure-data/src/d_soundfile.c", | ||
| "../libpd/pure-data/src/x_arithmetic.c", | ||
| "../libpd/pure-data/src/x_connective.c", | ||
| "../libpd/pure-data/src/x_interface.c", | ||
| "../libpd/pure-data/src/x_midi.c", | ||
| "../libpd/pure-data/src/x_misc.c", | ||
| "../libpd/pure-data/src/x_time.c", | ||
| "../libpd/pure-data/src/x_acoustics.c", | ||
| "../libpd/pure-data/src/x_net.c", | ||
| "../libpd/pure-data/src/x_text.c", | ||
| "../libpd/pure-data/src/x_gui.c", | ||
| "../libpd/pure-data/src/x_list.c", | ||
| "../libpd/pure-data/src/x_array.c", | ||
| "../libpd/pure-data/src/x_scalar.c", | ||
| "../libpd/libpd_wrapper/*.c", | ||
| "../../../libs/juce-plugin/JucePluginMain.cpp" | ||
| ) | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,71 @@ | ||
| /* Copyright (c) 1997-2010 Miller Puckette and others. | ||
| * For information on usage and redistribution, and for a DISCLAIMER OF ALL | ||
| * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ | ||
|
|
||
| #include "m_pd.h" | ||
| #include "s_stuff.h" | ||
| #include "z_libpd.h" | ||
| #include "z_hooks.h" | ||
|
|
||
| #define CLAMP(x, low, high) ((x > high) ? high : ((x < low) ? low : x)) | ||
| #define CLAMP4BIT(x) CLAMP(x, 0, 0x0f) | ||
| #define CLAMP7BIT(x) CLAMP(x, 0, 0x7f) | ||
| #define CLAMP8BIT(x) CLAMP(x, 0, 0xff) | ||
| #define CLAMP12BIT(x) CLAMP(x, 0, 0x0fff) | ||
| #define CLAMP14BIT(x) CLAMP(x, 0, 0x3fff) | ||
|
|
||
| #define CHANNEL ((CLAMP12BIT(port) << 4) | CLAMP4BIT(channel)) | ||
|
|
||
| void outmidi_noteon(int port, int channel, int pitch, int velo) { | ||
| if (libpd_noteonhook) | ||
| libpd_noteonhook(CHANNEL, CLAMP7BIT(pitch), CLAMP7BIT(velo)); | ||
| } | ||
|
|
||
| void outmidi_controlchange(int port, int channel, int ctl, int value) { | ||
| if (libpd_controlchangehook) | ||
| libpd_controlchangehook(CHANNEL, CLAMP7BIT(ctl), CLAMP7BIT(value)); | ||
| } | ||
|
|
||
| void outmidi_programchange(int port, int channel, int value) { | ||
| if (libpd_programchangehook) | ||
| libpd_programchangehook(CHANNEL, CLAMP7BIT(value)); | ||
| } | ||
|
|
||
| void outmidi_pitchbend(int port, int channel, int value) { | ||
| if (libpd_pitchbendhook) | ||
| libpd_pitchbendhook(CHANNEL, CLAMP14BIT(value) - 8192); // remove offset | ||
| } | ||
|
|
||
| void outmidi_aftertouch(int port, int channel, int value) { | ||
| if (libpd_aftertouchhook) | ||
| libpd_aftertouchhook(CHANNEL, CLAMP7BIT(value)); | ||
| } | ||
|
|
||
| void outmidi_polyaftertouch(int port, int channel, int pitch, int value) { | ||
| if (libpd_polyaftertouchhook) | ||
| libpd_polyaftertouchhook(CHANNEL, CLAMP7BIT(pitch), CLAMP7BIT(value)); | ||
| } | ||
|
|
||
| void outmidi_byte(int port, int value) { | ||
| if (libpd_midibytehook) | ||
| libpd_midibytehook(CLAMP12BIT(port), CLAMP8BIT(value)); | ||
| } | ||
|
|
||
| // The rest is not relevant to libpd. | ||
| void sys_get_midi_apis(char *buf) {} | ||
| void sys_listmididevs(void) {} | ||
| void sys_get_midi_params(int *pnmidiindev, int *pmidiindev, | ||
| int *pnmidioutdev, int *pmidioutdev) {} | ||
| void sys_open_midi(int nmidiindev, int *midiindev, | ||
| int nmidioutdev, int *midioutdev, int enable) {} | ||
| void sys_close_midi() {} | ||
| void sys_reopen_midi(void) {} | ||
| void sys_initmidiqueue(void) {} | ||
| void sys_pollmidiqueue(void) {} | ||
| void sys_setmiditimediff(double inbuftime, double outbuftime) {} | ||
| void glob_midi_setapi(void *dummy, t_floatarg f) {} | ||
| void glob_midi_properties(t_pd *dummy, t_floatarg flongform) {} | ||
| void glob_midi_dialog(t_pd *dummy, t_symbol *s, int argc, t_atom *argv) {} | ||
| int sys_mididevnametonumber(int output, const char *name) { return 0; } | ||
| void sys_mididevnumbertoname(int output, int devno, char *name, int namesize) {} | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,101 @@ | ||
| /* | ||
| * Copyright (c) 2012 Peter Brinkmann (peter.brinkmann@gmail.com) | ||
| * | ||
| * For information on usage and redistribution, and for a DISCLAIMER OF ALL | ||
| * WARRANTIES, see the file, "LICENSE.txt," in this distribution. | ||
| */ | ||
|
|
||
| #include "ringbuffer.h" | ||
|
|
||
| #include <stdarg.h> | ||
| #include <stdlib.h> | ||
| #include <string.h> | ||
|
|
||
| ring_buffer *rb_create(int size) { | ||
| if (size & 0xff) return NULL; // size must be a multiple of 256 | ||
| ring_buffer *buffer = malloc(sizeof(ring_buffer)); | ||
| if (!buffer) return NULL; | ||
| buffer->buf_ptr = calloc(size, sizeof(char)); | ||
| if (!buffer->buf_ptr) { | ||
| free(buffer); | ||
| return NULL; | ||
| } | ||
| buffer->size = size; | ||
| buffer->write_idx = 0; | ||
| buffer->read_idx = 0; | ||
| return buffer; | ||
| } | ||
|
|
||
| void rb_free(ring_buffer *buffer) { | ||
| free(buffer->buf_ptr); | ||
| free(buffer); | ||
| } | ||
|
|
||
| int rb_available_to_write(ring_buffer *buffer) { | ||
| if (buffer) { | ||
| // Note: The largest possible result is buffer->size - 1 because | ||
| // we adopt the convention that read_idx == write_idx means that the | ||
| // buffer is empty. | ||
| int read_idx = __sync_fetch_and_or(&(buffer->read_idx), 0); | ||
| int write_idx = __sync_fetch_and_or(&(buffer->write_idx), 0); | ||
| return (buffer->size + read_idx - write_idx - 1) % buffer->size; | ||
| } else { | ||
| return 0; | ||
| } | ||
| } | ||
|
|
||
| int rb_available_to_read(ring_buffer *buffer) { | ||
| if (buffer) { | ||
| int read_idx = __sync_fetch_and_or(&(buffer->read_idx), 0); | ||
| int write_idx = __sync_fetch_and_or(&(buffer->write_idx), 0); | ||
| return (buffer->size + write_idx - read_idx) % buffer->size; | ||
| } else { | ||
| return 0; | ||
| } | ||
| } | ||
|
|
||
| int rb_write_to_buffer(ring_buffer *buffer, int n, ...) { | ||
| if (!buffer) return -1; | ||
| int write_idx = buffer->write_idx; // No need for sync in writer thread. | ||
| int available = rb_available_to_write(buffer); | ||
| va_list args; | ||
| va_start(args, n); | ||
| int i; | ||
| for (i = 0; i < n; ++i) { | ||
| const char* src = va_arg(args, const char*); | ||
| int len = va_arg(args, int); | ||
| available -= len; | ||
| if (len < 0 || available < 0) return -1; | ||
| if (write_idx + len <= buffer->size) { | ||
| memcpy(buffer->buf_ptr + write_idx, src, len); | ||
| } else { | ||
| int d = buffer->size - write_idx; | ||
| memcpy(buffer->buf_ptr + write_idx, src, d); | ||
| memcpy(buffer->buf_ptr, src + d, len - d); | ||
| } | ||
| write_idx = (write_idx + len) % buffer->size; | ||
| } | ||
| va_end(args); | ||
| __sync_val_compare_and_swap(&(buffer->write_idx), buffer->write_idx, | ||
| write_idx); // Includes memory barrier. | ||
| return 0; | ||
| } | ||
|
|
||
| int rb_read_from_buffer(ring_buffer *buffer, char *dest, int len) { | ||
| if (len == 0) return 0; | ||
| if (!buffer || len < 0 || len > rb_available_to_read(buffer)) return -1; | ||
| // Note that rb_available_to_read also serves as a memory barrier, and so any | ||
| // writes to buffer->buf_ptr that precede the update of buffer->write_idx are | ||
| // visible to us now. | ||
| int read_idx = buffer->read_idx; // No need for sync in reader thread. | ||
| if (read_idx + len <= buffer->size) { | ||
| memcpy(dest, buffer->buf_ptr + read_idx, len); | ||
| } else { | ||
| int d = buffer->size - read_idx; | ||
| memcpy(dest, buffer->buf_ptr + read_idx, d); | ||
| memcpy(dest + d, buffer->buf_ptr, len - d); | ||
| } | ||
| __sync_val_compare_and_swap(&(buffer->read_idx), buffer->read_idx, | ||
| (read_idx + len) % buffer->size); // Includes memory barrier. | ||
| return 0; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,46 @@ | ||
| /* | ||
| * Copyright (c) 2012 Peter Brinkmann (peter.brinkmann@gmail.com) | ||
| * | ||
| * For information on usage and redistribution, and for a DISCLAIMER OF ALL | ||
| * WARRANTIES, see the file, "LICENSE.txt," in this distribution. | ||
| */ | ||
|
|
||
| #ifndef __OPENSL_RING_BUFFER_H__ | ||
| #define __OPENSL_RING_BUFFER_H__ | ||
|
|
||
| // Simple lock-free ring buffer implementation for one writer thread and one | ||
| // consumer thread. | ||
| typedef struct ring_buffer { | ||
| int size; | ||
| char *buf_ptr; | ||
| int write_idx; | ||
| int read_idx; | ||
| } ring_buffer; | ||
|
|
||
| // Creates a ring buffer (returns NULL on failure). | ||
| ring_buffer *rb_create(int size); | ||
|
|
||
| // Deletes a ring buffer. | ||
| void rb_free(ring_buffer *buffer); | ||
|
|
||
| // Returns the number of bytes that can currently be written; safe to be called | ||
| // from any thread. | ||
| int rb_available_to_write(ring_buffer *buffer); | ||
|
|
||
| // Returns the number of bytes that can currently be read; safe to be called | ||
| // from any thread. | ||
| int rb_available_to_read(ring_buffer *buffer); | ||
|
|
||
| // Writes bytes from n sources to the ring buffer (if the ring buffer has | ||
| // enough space). The varargs are pairs of type (const char*, int) giving a | ||
| // pointer to a buffer and the number of bytes to be copied. Only to be called | ||
| // from a single writer thread. | ||
| // Returns 0 on success. | ||
| int rb_write_to_buffer(ring_buffer *buffer, int n, ...); | ||
|
|
||
| // Reads the given number of bytes fromthe ring buffer to dest if the ring | ||
| // buffer has enough data. Only to be called from a single reader thread. | ||
| // Returns 0 on success. | ||
| int rb_read_from_buffer(ring_buffer *buffer, char *dest, int len); | ||
|
|
||
| #endif |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,48 @@ | ||
| /* | ||
| * Copyright (c) 2013 Dan Wilcox (danomatika@gmail.com) & | ||
| * Peter Brinkmann (peter.brinkmann@gmail.com) | ||
| * | ||
| * For information on usage and redistribution, and for a DISCLAIMER OF ALL | ||
| * WARRANTIES, see the file, "LICENSE.txt," in this distribution. | ||
| */ | ||
|
|
||
| #include "z_print_util.h" | ||
|
|
||
| #include <stdlib.h> | ||
| #include <string.h> | ||
|
|
||
| t_libpd_printhook libpd_concatenated_printhook = NULL; | ||
|
|
||
| #define PRINT_LINE_SIZE 2048 | ||
|
|
||
| void libpd_set_concatenated_printhook(const t_libpd_printhook hook) { | ||
| libpd_concatenated_printhook = hook; | ||
| } | ||
|
|
||
| void libpd_print_concatenator(const char *s) { | ||
| if (!libpd_concatenated_printhook) return; | ||
|
|
||
| static char concatenated_print_line[PRINT_LINE_SIZE]; | ||
| static int len_line = 0; | ||
| concatenated_print_line[len_line] = '\0'; | ||
|
|
||
| int len = (int) strlen(s); | ||
| while (len_line + len >= PRINT_LINE_SIZE) { | ||
| int d = PRINT_LINE_SIZE - 1 - len_line; | ||
| strncat(concatenated_print_line, s, d); | ||
| libpd_concatenated_printhook(concatenated_print_line); | ||
| s += d; | ||
| len -= d; | ||
| len_line = 0; | ||
| concatenated_print_line[0] = '\0'; | ||
| } | ||
|
|
||
| strncat(concatenated_print_line, s, len); | ||
| len_line += len; | ||
|
|
||
| if (len_line > 0 && concatenated_print_line[len_line - 1] == '\n') { | ||
| concatenated_print_line[len_line - 1] = '\0'; | ||
| libpd_concatenated_printhook(concatenated_print_line); | ||
| len_line = 0; | ||
| } | ||
| } |