kopia lustrzana https://github.com/jameshball/osci-render
Move envelope to MidiComponent and get parameters working
rodzic
5047979ff4
commit
6d08a00b33
|
@ -100,9 +100,6 @@ MainComponent::MainComponent(OscirenderAudioProcessor& p, OscirenderAudioProcess
|
|||
frequencyLabel.setText(juce::String(roundedFrequency) + "Hz", juce::dontSendNotification);
|
||||
}
|
||||
);
|
||||
|
||||
addAndMakeVisible(envelope);
|
||||
envelope.setEnv(audioProcessor.adsrEnv);
|
||||
}
|
||||
|
||||
MainComponent::~MainComponent() {
|
||||
|
@ -147,7 +144,6 @@ void MainComponent::resized() {
|
|||
bounds.removeFromTop(padding);
|
||||
openOscilloscope.setBounds(bounds.removeFromBottom(buttonHeight).withSizeKeepingCentre(160, buttonHeight));
|
||||
bounds.removeFromBottom(padding);
|
||||
envelope.setBounds(bounds.removeFromTop(200));
|
||||
auto minDim = juce::jmin(bounds.getWidth(), bounds.getHeight());
|
||||
visualiser.setBounds(bounds.withSizeKeepingCentre(minDim, minDim));
|
||||
}
|
||||
|
|
|
@ -33,8 +33,6 @@ private:
|
|||
VisualiserComponent visualiser{2, audioProcessor};
|
||||
juce::TextButton openOscilloscope{"Open Oscilloscope"};
|
||||
|
||||
EnvelopeContainerComponent envelope;
|
||||
|
||||
juce::Label frequencyLabel;
|
||||
int callbackIndex = -1;
|
||||
|
||||
|
|
|
@ -10,12 +10,50 @@ MidiComponent::MidiComponent(OscirenderAudioProcessor& p, OscirenderAudioProcess
|
|||
midiToggle.onClick = [this]() {
|
||||
audioProcessor.midiEnabled->setBoolValueNotifyingHost(midiToggle.getToggleState());
|
||||
};
|
||||
|
||||
addAndMakeVisible(envelope);
|
||||
envelope.setAdsrMode(true);
|
||||
envelope.setEnv(audioProcessor.adsrEnv);
|
||||
envelope.addListener(&audioProcessor);
|
||||
|
||||
audioProcessor.attack->addListener(this);
|
||||
audioProcessor.decay->addListener(this);
|
||||
audioProcessor.sustain->addListener(this);
|
||||
audioProcessor.release->addListener(this);
|
||||
}
|
||||
|
||||
MidiComponent::~MidiComponent() {
|
||||
envelope.removeListener(&audioProcessor);
|
||||
audioProcessor.attack->removeListener(this);
|
||||
audioProcessor.decay->removeListener(this);
|
||||
audioProcessor.sustain->removeListener(this);
|
||||
audioProcessor.release->removeListener(this);
|
||||
}
|
||||
|
||||
void MidiComponent::parameterValueChanged(int parameterIndex, float newValue) {
|
||||
triggerAsyncUpdate();
|
||||
}
|
||||
|
||||
void MidiComponent::parameterGestureChanged(int parameterIndex, bool gestureIsStarting) {}
|
||||
|
||||
void MidiComponent::handleAsyncUpdate() {
|
||||
DBG("MidiComponent::handleAsyncUpdate");
|
||||
Env newEnv = Env::adsr(
|
||||
audioProcessor.attack->getValueUnnormalised(),
|
||||
audioProcessor.decay->getValueUnnormalised(),
|
||||
audioProcessor.sustain->getValueUnnormalised(),
|
||||
audioProcessor.release->getValueUnnormalised(),
|
||||
1.0,
|
||||
std::vector<EnvCurve>{ audioProcessor.attackShape->getValueUnnormalised(), audioProcessor.decayShape->getValueUnnormalised(), audioProcessor.releaseShape->getValueUnnormalised() }
|
||||
);
|
||||
|
||||
envelope.setEnv(newEnv);
|
||||
}
|
||||
|
||||
void MidiComponent::resized() {
|
||||
auto area = getLocalBounds().reduced(5);
|
||||
midiToggle.setBounds(area.removeFromTop(50));
|
||||
envelope.setBounds(area.removeFromTop(200));
|
||||
keyboard.setBounds(area.removeFromBottom(100));
|
||||
}
|
||||
|
||||
|
|
|
@ -4,9 +4,14 @@
|
|||
#include "PluginProcessor.h"
|
||||
|
||||
class OscirenderAudioProcessorEditor;
|
||||
class MidiComponent : public juce::Component {
|
||||
class MidiComponent : public juce::Component, public juce::AudioProcessorParameter::Listener, public juce::AsyncUpdater {
|
||||
public:
|
||||
MidiComponent(OscirenderAudioProcessor&, OscirenderAudioProcessorEditor&);
|
||||
~MidiComponent() override;
|
||||
|
||||
void parameterValueChanged(int parameterIndex, float newValue) override;
|
||||
void parameterGestureChanged(int parameterIndex, bool gestureIsStarting) override;
|
||||
void handleAsyncUpdate() override;
|
||||
|
||||
void resized() override;
|
||||
void paint(juce::Graphics& g) override;
|
||||
|
@ -18,5 +23,7 @@ private:
|
|||
juce::MidiKeyboardState keyboardState;
|
||||
juce::MidiKeyboardComponent keyboard{keyboardState, juce::MidiKeyboardComponent::horizontalKeyboard};
|
||||
|
||||
EnvelopeContainerComponent envelope;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(MidiComponent)
|
||||
};
|
|
@ -141,6 +141,11 @@ OscirenderAudioProcessor::OscirenderAudioProcessor()
|
|||
addParameter(parameter);
|
||||
}
|
||||
|
||||
addParameter(attack);
|
||||
addParameter(decay);
|
||||
addParameter(sustain);
|
||||
addParameter(release);
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
synth.addVoice(new ShapeVoice(*this));
|
||||
}
|
||||
|
@ -694,6 +699,39 @@ void OscirenderAudioProcessor::parameterValueChanged(int parameterIndex, float n
|
|||
|
||||
void OscirenderAudioProcessor::parameterGestureChanged(int parameterIndex, bool gestureIsStarting) {}
|
||||
|
||||
void OscirenderAudioProcessor::envelopeChanged(EnvelopeComponent* changedEnvelope) {
|
||||
Env env = changedEnvelope->getEnv();
|
||||
std::vector<double> levels = env.getLevels();
|
||||
std::vector<double> times = env.getTimes();
|
||||
EnvCurveList curves = env.getCurves();
|
||||
|
||||
if (levels.size() == 4 && times.size() == 3 && curves.size() == 3) {
|
||||
this->adsrEnv = env;
|
||||
if (attack->getValueUnnormalised() != times[0]) {
|
||||
attack->setUnnormalisedValueNotifyingHost(times[0]);
|
||||
}
|
||||
if (decay->getValueUnnormalised() != times[1]) {
|
||||
decay->setUnnormalisedValueNotifyingHost(times[1]);
|
||||
}
|
||||
if (sustain->getValueUnnormalised() != levels[2]) {
|
||||
sustain->setUnnormalisedValueNotifyingHost(levels[2]);
|
||||
}
|
||||
if (release->getValueUnnormalised() != times[2]) {
|
||||
release->setUnnormalisedValueNotifyingHost(times[2]);
|
||||
}
|
||||
if (attackShape->getValueUnnormalised() != curves[0].getCurve()) {
|
||||
attackShape->setUnnormalisedValueNotifyingHost(curves[0].getCurve());
|
||||
}
|
||||
if (decayShape->getValueUnnormalised() != curves[1].getCurve()) {
|
||||
decayShape->setUnnormalisedValueNotifyingHost(curves[1].getCurve());
|
||||
}
|
||||
if (releaseShape->getValueUnnormalised() != curves[2].getCurve()) {
|
||||
releaseShape->setUnnormalisedValueNotifyingHost(curves[2].getCurve());
|
||||
}
|
||||
DBG("adsr changed");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//==============================================================================
|
||||
// This creates new instances of the plugin..
|
||||
|
|
|
@ -22,11 +22,12 @@
|
|||
#include "audio/PerspectiveEffect.h"
|
||||
#include "obj/ObjectServer.h"
|
||||
#include "UGen/Env.h"
|
||||
#include "UGen/ugen_JuceEnvelopeComponent.h"
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
*/
|
||||
class OscirenderAudioProcessor : public juce::AudioProcessor, juce::AudioProcessorParameter::Listener
|
||||
class OscirenderAudioProcessor : public juce::AudioProcessor, juce::AudioProcessorParameter::Listener, public EnvelopeComponentListener
|
||||
#if JucePlugin_Enable_ARA
|
||||
, public juce::AudioProcessorARAExtension
|
||||
#endif
|
||||
|
@ -65,6 +66,7 @@ public:
|
|||
void consumerRead(std::shared_ptr<BufferConsumer> consumer);
|
||||
void parameterValueChanged(int parameterIndex, float newValue) override;
|
||||
void parameterGestureChanged(int parameterIndex, bool gestureIsStarting) override;
|
||||
void envelopeChanged(EnvelopeComponent* changedEnvelope) override;
|
||||
|
||||
int VERSION_HINT = 1;
|
||||
|
||||
|
@ -193,7 +195,23 @@ public:
|
|||
std::atomic<bool> objectServerRendering = false;
|
||||
juce::ChangeBroadcaster fileChangeBroadcaster;
|
||||
|
||||
Env adsrEnv = Env::adsr(0.1, 0.1, 0.1, 0.1, 0.1);
|
||||
FloatParameter* attack = new FloatParameter("Attack", "attack", VERSION_HINT, 0.1, 0.0, 1.0);
|
||||
FloatParameter* attackLevel = new FloatParameter("Attack Level", "attackLevel", VERSION_HINT, 1.0, 0.0, 1.0);
|
||||
FloatParameter* decay = new FloatParameter("Decay", "decay", VERSION_HINT, 0.1, 0.0, 1.0);
|
||||
FloatParameter* sustain = new FloatParameter("Sustain", "sustain", VERSION_HINT, 0.1, 0.0, 1.0);
|
||||
FloatParameter* release = new FloatParameter("Release", "release", VERSION_HINT, 0.1, 0.0, 1.0);
|
||||
FloatParameter* attackShape = new FloatParameter("Attack Shape", "attackShape", VERSION_HINT, 0.0, 0.0, 1.0);
|
||||
FloatParameter* decayShape = new FloatParameter("Decay Shape", "decayShape", VERSION_HINT, 0.0, 0.0, 1.0);
|
||||
FloatParameter* releaseShape = new FloatParameter("Release Shape", "releaseShape", VERSION_HINT, 0.0, 0.0, 1.0);
|
||||
|
||||
Env adsrEnv = Env::adsr(
|
||||
attack->getValueUnnormalised(),
|
||||
decay->getValueUnnormalised(),
|
||||
sustain->getValueUnnormalised(),
|
||||
release->getValueUnnormalised(),
|
||||
1.0,
|
||||
std::vector<EnvCurve>{ attackShape->getValueUnnormalised(), decayShape->getValueUnnormalised(), releaseShape->getValueUnnormalised() }
|
||||
);
|
||||
|
||||
private:
|
||||
juce::SpinLock consumerLock;
|
||||
|
|
|
@ -52,6 +52,48 @@ Env::Env(std::vector<double> levels,
|
|||
{
|
||||
}
|
||||
|
||||
Env& Env::operator=(Env const& other) throw() {
|
||||
if (this != &other) {
|
||||
levels_ = other.levels_;
|
||||
times_ = other.times_;
|
||||
curves_ = other.curves_;
|
||||
releaseNode_ = other.releaseNode_;
|
||||
loopNode_ = other.loopNode_;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool Env::operator==(const Env& other) const throw() {
|
||||
// approximate comparison
|
||||
bool levelsEqual = true;
|
||||
for (int i = 0; i < levels_.size(); i++) {
|
||||
if (std::abs(levels_[i] - other.levels_[i]) > 0.001) {
|
||||
levelsEqual = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// approximate comparison
|
||||
bool timesEqual = true;
|
||||
for (int i = 0; i < times_.size(); i++) {
|
||||
if (std::abs(times_[i] - other.times_[i]) > 0.001) {
|
||||
timesEqual = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// approximate comparison
|
||||
bool curvesEqual = true;
|
||||
for (int i = 0; i < curves_.size(); i++) {
|
||||
if (std::abs(curves_[i].getCurve() - other.curves_[i].getCurve()) > 0.001) {
|
||||
curvesEqual = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return levelsEqual && timesEqual && curvesEqual;
|
||||
}
|
||||
|
||||
Env::~Env() throw() {}
|
||||
|
||||
double Env::duration() const throw() {
|
||||
|
@ -272,11 +314,11 @@ Env Env::adsr(const double attackTime,
|
|||
const double sustainLevel,
|
||||
const double releaseTime,
|
||||
const double level,
|
||||
EnvCurve const& curve) throw()
|
||||
EnvCurveList const& curves) throw()
|
||||
{
|
||||
return Env({ 0.0, level, (level * sustainLevel), 0.0 },
|
||||
{ attackTime, decayTime, releaseTime },
|
||||
curve, 2);
|
||||
curves, 2);
|
||||
}
|
||||
|
||||
Env Env::asr(const double attackTime,
|
||||
|
|
|
@ -84,6 +84,7 @@ public:
|
|||
|
||||
Env(Env const& copy) throw();
|
||||
Env& operator= (Env const& other) throw();
|
||||
bool operator== (const Env& other) const throw();
|
||||
|
||||
~Env() throw();
|
||||
|
||||
|
@ -133,14 +134,14 @@ public:
|
|||
@param sustainLevel The level of the sustain portion as a ratio of the peak level.
|
||||
@param releaseTime The duration of the release portion.
|
||||
@param level The peak level of the envelope.
|
||||
@param curve The curvature of the envelope.
|
||||
@param curves The curves of the envelope.
|
||||
@return The Env envelope specification. */
|
||||
static Env adsr(const double attackTime = 0.01,
|
||||
const double decayTime = 0.3,
|
||||
const double sustainLevel = 0.5,
|
||||
const double releaseTime = 1.0,
|
||||
const double level = 1.0,
|
||||
EnvCurve const& curve = -4.0) throw();
|
||||
EnvCurveList const& curves = -4.0) throw();
|
||||
|
||||
/** Creates a new envelope specification which is shaped like traditional analog attack-sustain-release (asr) envelopes.
|
||||
@param attackTime The duration of the attack portion.
|
||||
|
|
|
@ -69,6 +69,10 @@ EnvCurveList& EnvCurveList::operator= (EnvCurveList const& other) throw()
|
|||
return *this;
|
||||
}
|
||||
|
||||
bool EnvCurveList::operator==(EnvCurveList const& other) const throw() {
|
||||
return data == other.data;
|
||||
}
|
||||
|
||||
EnvCurve& EnvCurveList::operator[] (const int index) throw() {
|
||||
return data[index % size()];
|
||||
}
|
||||
|
|
|
@ -121,6 +121,7 @@ public:
|
|||
|
||||
EnvCurveList(EnvCurveList const& copy) throw();
|
||||
EnvCurveList& operator= (EnvCurveList const& other) throw();
|
||||
bool operator== (EnvCurveList const& other) const throw();
|
||||
|
||||
|
||||
/// @} <!-- end Construction and destruction ------------------------------------------- -->
|
||||
|
|
|
@ -107,19 +107,31 @@ EnvelopeComponent* EnvelopeHandleComponent::getParentComponent() const
|
|||
|
||||
void EnvelopeHandleComponent::updateTimeAndValue()
|
||||
{
|
||||
bool envChanged = false;
|
||||
|
||||
if (shouldLockTime)
|
||||
{
|
||||
setTopLeftPosition(getParentComponent()->convertDomainToPixels(time),
|
||||
getY());
|
||||
}
|
||||
else time = getParentComponent()->convertPixelsToDomain(getX());
|
||||
else {
|
||||
envChanged = true;
|
||||
time = getParentComponent()->convertPixelsToDomain(getX());
|
||||
}
|
||||
|
||||
if (shouldLockValue)
|
||||
{
|
||||
setTopLeftPosition(getX(),
|
||||
getParentComponent()->convertValueToPixels(value));
|
||||
}
|
||||
else value = getParentComponent()->convertPixelsToValue(getY());
|
||||
else {
|
||||
envChanged = true;
|
||||
value = getParentComponent()->convertPixelsToValue(getY());
|
||||
}
|
||||
|
||||
if (envChanged == true) {
|
||||
((EnvelopeComponent*)getParentComponent())->sendChangeMessage();
|
||||
}
|
||||
|
||||
#ifdef MYDEBUG
|
||||
printf("MyEnvelopeHandleComponent::updateTimeAndValue(%f, %f)\n", time, value);
|
||||
|
@ -303,7 +315,6 @@ void EnvelopeHandleComponent::mouseDrag(const juce::MouseEvent& e)
|
|||
|
||||
updateLegend();
|
||||
getParentComponent()->repaint();
|
||||
getParentComponent()->sendChangeMessage();
|
||||
|
||||
if(lastX == getX() && lastY == getY()) {
|
||||
setMousePositionToThisHandle();
|
||||
|
@ -1045,6 +1056,14 @@ EnvelopeHandleComponent* EnvelopeComponent::addHandle(double newDomain, double n
|
|||
handle->setTimeAndValue(newDomain, newValue, 0.0);
|
||||
handle->setCurve(curve);
|
||||
handles.insert(i, handle);
|
||||
if (adsrMode) {
|
||||
if (i == 0) {
|
||||
handle->lockTime(0);
|
||||
}
|
||||
if (i == 0 || i == 3) {
|
||||
handle->lockValue(0);
|
||||
}
|
||||
}
|
||||
// sendChangeMessage();
|
||||
return handle;
|
||||
}
|
||||
|
@ -1165,6 +1184,14 @@ bool EnvelopeComponent::getAllowNodeEditing() const
|
|||
return allowNodeEditing;
|
||||
}
|
||||
|
||||
void EnvelopeComponent::setAdsrMode(const bool adsrMode) {
|
||||
this->adsrMode = adsrMode;
|
||||
}
|
||||
|
||||
bool EnvelopeComponent::getAdsrMode() const {
|
||||
return adsrMode;
|
||||
}
|
||||
|
||||
void EnvelopeComponent::setReleaseNode(EnvelopeHandleComponent* thisHandle)
|
||||
{
|
||||
setReleaseNode(handles.indexOf(thisHandle));
|
||||
|
@ -1237,24 +1264,42 @@ Env EnvelopeComponent::getEnv() const
|
|||
|
||||
void EnvelopeComponent::setEnv(Env const& env)
|
||||
{
|
||||
clear();
|
||||
|
||||
double time = 0.0;
|
||||
|
||||
std::vector<double> levels = env.getLevels();
|
||||
std::vector<double> times = env.getTimes();
|
||||
const EnvCurveList& curves = env.getCurves();
|
||||
|
||||
EnvelopeHandleComponent* handle = addHandle(time, (double)levels[0], EnvCurve::Linear);
|
||||
quantiseHandle(handle);
|
||||
if (env.getLevels().size() == handles.size()) {
|
||||
double time = 0.0;
|
||||
|
||||
for(int i = 0; i < times.size(); i++)
|
||||
{
|
||||
time += times[i];
|
||||
handle = addHandle(time, (double)levels[i+1], curves[i]);
|
||||
std::vector<double> levels = env.getLevels();
|
||||
std::vector<double> times = env.getTimes();
|
||||
const EnvCurveList& curves = env.getCurves();
|
||||
|
||||
for (int i = 0; i < handles.size(); i++) {
|
||||
EnvelopeHandleComponent* handle = handles.getUnchecked(i);
|
||||
handle->setTimeAndValue(time, (double)levels[i], 0.0);
|
||||
handle->setCurve(curves[i]);
|
||||
quantiseHandle(handle);
|
||||
if (i < times.size()) {
|
||||
time += times[i];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
clear();
|
||||
|
||||
double time = 0.0;
|
||||
|
||||
std::vector<double> levels = env.getLevels();
|
||||
std::vector<double> times = env.getTimes();
|
||||
const EnvCurveList& curves = env.getCurves();
|
||||
|
||||
EnvelopeHandleComponent* handle = addHandle(time, (double)levels[0], EnvCurve::Linear);
|
||||
quantiseHandle(handle);
|
||||
|
||||
for(int i = 0; i < times.size(); i++)
|
||||
{
|
||||
time += times[i];
|
||||
handle = addHandle(time, (double)levels[i+1], curves[i]);
|
||||
quantiseHandle(handle);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
releaseNode = env.getReleaseNode();
|
||||
loopNode = env.getLoopNode();
|
||||
}
|
||||
|
|
|
@ -215,6 +215,9 @@ public:
|
|||
bool getAllowCurveEditing() const;
|
||||
void setAllowNodeEditing(const bool flag);
|
||||
bool getAllowNodeEditing() const;
|
||||
void setAdsrMode(const bool adsrMode);
|
||||
bool getAdsrMode() const;
|
||||
|
||||
|
||||
double convertPixelsToDomain(int pixelsX, int pixelsXMax = -1) const;
|
||||
double convertPixelsToValue(int pixelsY, int pixelsYMax = -1) const;
|
||||
|
@ -258,6 +261,7 @@ private:
|
|||
|
||||
bool allowCurveEditing = false;
|
||||
bool allowNodeEditing = false;
|
||||
bool adsrMode = false;
|
||||
|
||||
juce::Colour colours[NumEnvColours];
|
||||
};
|
||||
|
@ -345,6 +349,7 @@ public:
|
|||
bool getAllowCurveEditing() const { return envelope->getAllowCurveEditing(); }
|
||||
void setAllowNodeEditing(const bool flag) { envelope->setAllowNodeEditing(flag); }
|
||||
bool getAllowNodeEditing() const { return envelope->getAllowNodeEditing(); }
|
||||
void setAdsrMode(const bool adsrMode) { envelope->setAdsrMode(adsrMode); }
|
||||
|
||||
|
||||
private:
|
||||
|
|
Ładowanie…
Reference in New Issue