11namespace tracktion {
inline namespace engine
14namespace BezierHelpers
16 template<
typename Type>
22 jassert (curve >= -0.5 && curve <= 0.5);
24 const Type x1 = start.x;
25 const Type
y1 = start.y;
26 const Type x2 =
end.x;
27 const Type y2 =
end.y;
32 const Type run = x2 - x1;
33 const Type rise = y2 -
y1;
35 const Type xc = x1 + run / 2;
36 const Type yc =
y1 + rise / 2;
38 const Type x = xc - run / 2 * -c;
39 const Type y = yc + rise / 2 * -c;
44 const Type run = x2 - x1;
45 const Type rise =
y1 - y2;
47 const Type xc = x1 + run / 2;
48 const Type yc = y2 + rise / 2;
50 const Type x = xc - run / 2 * -c;
51 const Type y = yc - rise / 2 * -c;
56 template<
typename Type>
57 static Type getQuadraticYFromX (Type x, Type x1, Type y1, Type xb, Type yb, Type x2, Type y2)
60 if (x1 == x2 || y1 == y2)
67 const Type a = x1 - 2 * xb + x2;
68 const Type b = -2 * x1 + 2 * xb;
69 const Type c = x1 - x;
80 t = (-b +
std::sqrt (b * b - 4 * a * c)) / (2 * a);
82 if (t < 0.0f || t > 1.0f)
83 t = (-b -
std::sqrt (b * b - 4 * a * c)) / (2 * a);
87 const Type y = (
std::pow (1 - t, 2.0f) *
y1) + 2 * t * (1 - t) * yb +
std::pow (t, 2.0f) * y2;
91 template<
typename Type>
92 static Type getQuadraticYFromX (Type x,
97 return getQuadraticYFromX (x, startPoint.
x, startPoint.
y, controlPoint.
x, controlPoint.
y, endPoint.
x, endPoint.
y);
109 void updateStreamTime (
TimePosition editTime,
int numSamples)
override
111 using namespace ModifierCommon;
112 const double blockLength = numSamples / modifier.
getSampleRate();
116 const auto syncTypeThisBlock = getTypedParamValue<SyncType> (*modifier.syncTypeParam);
117 const auto rateTypeThisBlock = getTypedParamValue<RateType> (*modifier.rateTypeParam);
118 const auto rateThisBlock = modifier.rateParam->getCurrentValue();
120 if (rateTypeThisBlock == hertz)
122 auto durationPerPattern = 1.0f / rateThisBlock;
123 ramp.setDuration (durationPerPattern);
125 if (syncTypeThisBlock == transport)
128 modifier.setPhase (ramp.getProportion());
131 ramp.process ((
float) blockLength);
135 tempoSequence.
set (editTime);
136 const auto currentTempo = tempoSequence.
getTempo();
138 const auto proportionOfBar = ModifierCommon::getBarFraction (rateTypeThisBlock);
140 if (syncTypeThisBlock == transport)
143 const auto bars = (editTimeInBeats / currentTimeSig.numerator) * rateThisBlock;
145 if (rateTypeThisBlock >= fourBars && rateTypeThisBlock <= sixtyFourthD)
147 auto virtualBars =
std::max (0.0, bars / proportionOfBar);
148 modifier.setPhase ((
float)
std::fmod (virtualBars, 1.0f));
153 auto bpm = (currentTempo * rateThisBlock) / proportionOfBar;
154 auto secondsPerBeat = 60.0 / bpm;
155 auto secondsPerStep =
static_cast<float> (secondsPerBeat * currentTimeSig.numerator);
156 auto secondsPerPattern = secondsPerStep;
157 ramp.setDuration (secondsPerPattern);
159 modifier.setPhase (ramp.getProportion());
162 ramp.process ((
float) blockLength);
167 void resync (
double duration)
169 if (
juce::roundToInt (modifier.syncTypeParam->getCurrentValue()) == ModifierCommon::note)
171 ramp.setPosition (0.0f);
172 modifier.setPhase (0.0f);
175 ramp.process ((
float) duration);
188BreakpointOscillatorModifier::BreakpointOscillatorModifier (
Edit& e,
const juce::ValueTree& v)
191 auto um = &edit.getUndoManager();
193 numActivePoints.referTo (
state, IDs::numActivePoints, um, 4);
194 syncType.referTo (
state, IDs::syncType, um,
float (ModifierCommon::free));
195 rate.referTo (
state, IDs::rate, um, 1.0f);
196 rateType.referTo (
state, IDs::rateType, um,
float (ModifierCommon::bar));
197 depth.referTo (
state, IDs::depth, um, 1.0f);
198 bipolar.referTo (
state, IDs::bipolar, um);
199 stageZeroValue.referTo (
state, IDs::stageZeroValue, um, 0.0f);
200 stageOneValue.referTo (
state, IDs::stageOneValue, um, 1.0f);
201 stageOneTime.referTo (
state, IDs::stageOneTime, um, 0.25f);
202 stageOneCurve.referTo (
state, IDs::stageOneCurve, um, 0.0f);
203 stageTwoValue.referTo (
state, IDs::stageTwoValue, um, 0.5f);
204 stageTwoTime.referTo (
state, IDs::stageTwoTime, um, 0.5f);
205 stageTwoCurve.referTo (
state, IDs::stageTwoCurve, um, 0.0f);
206 stageThreeValue.referTo (
state, IDs::stageThreeValue, um, 0.5f);
207 stageThreeTime.referTo (
state, IDs::stageThreeTime, um, 0.75f);
208 stageThreeCurve.referTo (
state, IDs::stageThreeCurve, um, 0.0f);
209 stageFourValue.referTo (
state, IDs::stageFourValue, um, 0.0f);
210 stageFourTime.referTo (
state, IDs::stageFourTime, um, 1.0f);
211 stageFourCurve.referTo (
state, IDs::stageFourCurve, um, 0.0f);
218 addAutomatableParameter (p);
219 p->attachToCurrentValue (val);
228 valueRange.setSkewForCentre (centreVal);
230 addAutomatableParameter (p);
231 p->attachToCurrentValue (val);
236 using namespace ModifierCommon;
237 numActivePointsParam = addParam (
"numActivePoints",
TRANS(
"Num points"),{ 1.0f, 4.0f, 1.0f }, 2.5f, numActivePoints, {});
238 syncTypeParam = addDiscreteParam (
"syncType",
TRANS(
"Sync type"), { 0.0f, (
float) getSyncTypeChoices().
size() - 1 }, syncType, getSyncTypeChoices());
239 rateParam = addParam (
"rate",
TRANS(
"Rate"), { 0.01f, 50.0f }, 1.0f, rate, {});
240 rateTypeParam = addDiscreteParam (
"rateType",
TRANS(
"Rate Type"), { 0.0f, (
float) getRateTypeChoices().
size() - 1 }, rateType, getRateTypeChoices());
241 depthParam = addParam (
"depth",
TRANS(
"Depth"), { 0.0f, 1.0f }, 0.5f, depth, {});
242 bipolarParam = addDiscreteParam (
"biopolar",
TRANS(
"Bipoloar"), { 0.0f, 1.0f }, bipolar, {
NEEDS_TRANS(
"Uni-polar"),
NEEDS_TRANS(
"Bi-polar") });
244 stageZeroValueParam = addParam (
"stageZeroValue",
TRANS(
"Stage zero value"), { 0.0f, 1.0f }, 0.5f, stageZeroValue, {});
245 stageOneValueParam = addParam (
"stageOneValue",
TRANS(
"Stage one value"), { 0.0f, 1.0f }, 0.5f, stageOneValue, {});
246 stageOneTimeParam = addParam (
"stageOneTime",
TRANS(
"Stage one time"), { 0.0f, 1.0f }, 0.5f, stageOneTime, {});
247 stageOneCurveParam = addParam (
"stageOneCurve",
TRANS(
"Stage one curve"), { -0.5f, 0.5f }, 0.0f, stageOneCurve, {});
248 stageTwoValueParam = addParam (
"stageTwoValue",
TRANS(
"Stage two value"), { 0.0f, 1.0f }, 0.5f, stageTwoValue, {});
249 stageTwoTimeParam = addParam (
"stageTwoTime",
TRANS(
"Stage two time"), { 0.0f, 1.0f }, 0.5f, stageTwoTime, {});
250 stageTwoCurveParam = addParam (
"stageTwoCurve",
TRANS(
"Stage two curve"), { -0.5f, 0.5f }, 0.0f, stageTwoCurve, {});
251 stageThreeValueParam = addParam (
"stageThreeValue",
TRANS(
"Stage three value"), { 0.0f, 1.0f }, 0.5f, stageThreeValue, {});
252 stageThreeTimeParam = addParam (
"stageThreeTime",
TRANS(
"Stage three time"), { 0.0f, 1.0f }, 0.5f, stageThreeTime, {});
253 stageThreeCurveParam = addParam (
"stageThreeCurve",
TRANS(
"Stage three curve"), { -0.5f, 0.5f }, 0.0f, stageThreeCurve, {});
254 stageFourValueParam = addParam (
"stageFourValue",
TRANS(
"Stage four value"), { 0.0f, 1.0f }, 0.5f, stageFourValue, {});
255 stageFourTimeParam = addParam (
"stageFourTime",
TRANS(
"Stage four time"), { 0.0f, 1.0f }, 0.5f, stageFourTime, {});
256 stageFourCurveParam = addParam (
"stageFourCurve",
TRANS(
"Stage four curve"), { -0.5f, 0.5f }, 0.0f, stageFourCurve, {});
258 changedTimer.setCallback ([
this]
260 changedTimer.stopTimer();
267BreakpointOscillatorModifier::~BreakpointOscillatorModifier()
270 notifyListenersOfDeletion();
274 for (
auto p : getAutomatableParameters())
275 p->detachFromCurrentValue();
277 deleteAutomatableParameters();
328 breakpointOscillatorModifierID (bom.
itemID)
332bool BreakpointOscillatorModifier::Assignment::isForModifierSource (
const ModifierSource& source)
const
335 return mod->itemID == breakpointOscillatorModifierID;
340BreakpointOscillatorModifier::Ptr BreakpointOscillatorModifier::Assignment::getModifier()
const
342 if (
auto mod = findModifierTypeForID<BreakpointOscillatorModifier> (edit, breakpointOscillatorModifierID))
349BreakpointOscillatorModifier::Stage BreakpointOscillatorModifier::getStage (
int index)
const
354 case 0:
return { stageZeroValueParam.get() };
355 case 1:
return { stageOneValueParam.get(), stageOneTimeParam.get(), stageOneCurveParam.get() };
356 case 2:
return { stageTwoValueParam.get(), stageTwoTimeParam.get(), stageTwoCurveParam.get() };
357 case 3:
return { stageThreeValueParam.get(), stageThreeTimeParam.get(), stageThreeCurveParam.get() };
358 case 4:
return { stageFourValueParam.get(), stageFourTimeParam.get(), stageFourCurveParam.get() };
365 auto getVal = [] (
auto& p) ->
float {
return p->getCurrentValue(); };
368 { getVal (stageZeroValueParam), 0.0f, 0.0f },
369 { getVal (stageOneValueParam), getVal (stageOneTimeParam), getVal (stageOneCurveParam) },
370 { getVal (stageTwoValueParam), getVal (stageTwoTimeParam), getVal (stageTwoCurveParam) },
371 { getVal (stageThreeValueParam), getVal (stageThreeTimeParam), getVal (stageThreeCurveParam) },
372 { getVal (stageFourValueParam), getVal (stageFourTimeParam), getVal (stageFourCurveParam) }
378 const auto sections = getAllSections();
380 jassert (numPoints < sections.size());
382 for (
size_t i = 1; i <= numPoints; ++i)
383 if (sections[i].time > time)
386 auto dummyEndSection = sections[numPoints];
387 dummyEndSection.time = 1.0f;
392namespace BreakpointInterpolation
394 constexpr float linearInterpolate (
float x1,
float y1,
float x2,
float y2,
float x)
396 return (y1 * (x2 - x) + y2 * (x - x1)) / (x2 - x1);
399 template<
typename Type>
400 static Type quadraticInterpolate (Type x,
405 auto cp = BezierHelpers::getQuadraticControlPoint (startPoint, endPoint, curve);
406 return BezierHelpers::getQuadraticYFromX (x, startPoint, cp, endPoint);
410void BreakpointOscillatorModifier::setPhase (
float newPhase)
420 using namespace BreakpointInterpolation;
425 float timeForPhase = totalTime * newPhase;
427 auto surroundingSections = getSectionsSurrounding (timeForPhase);
428 auto& s1 = surroundingSections.first;
429 auto& s2 = surroundingSections.second;
430 const float curve = s2.curve;
432 float newValue = 0.0f;
435 newValue = linearInterpolate (s1.time, s1.value, s2.time, s2.value, timeForPhase);
437 newValue = quadraticInterpolate (timeForPhase, { s1.time, s1.value }, { s2.time, s2.value }, curve);
441 newValue = newValue * depthParam->getCurrentValue();
444 newValue = (newValue * 2.0f) - 1.0f;
450void BreakpointOscillatorModifier::valueTreeChanged()
int size() const noexcept
void startTimerHz(int timerFrequencyHz) noexcept
bool isTimerRunning() const noexcept
void addListener(Listener *listener)
void removeListener(Listener *listener)
void restoreChangedParametersFromState()
Restores the value of any explicitly set parameters.
void updateParameterStreams(TimePosition)
Updates all the parameter streams to their positions at this time.
AutomatableParameter::ModifierAssignment * createAssignment(const juce::ValueTree &) override
Must return a new ModifierAssignment for a given state.
void applyToBuffer(const PluginRenderContext &) override
Sub classes should implement this to process the Modifier.
float getTotalTime() const
Returns the total time for this envelope.
float getCurrentValue() override
Returns the current value of the modifier.
float getCurrentPhase() const noexcept
Returns the current phase between 0 & 1.
float getCurrentEnvelopeValue() const noexcept
Returns the envelope value before the bipolar and depth have been applied.
void initialise() override
Call this once after construction to connect it to the audio graph.
const EditItemID itemID
Every EditItem has an ID which is unique within the edit.
The Tracktion Edit class!
void removeModifierTimer(ModifierTimer &)
Removes a ModifierTimer previously added.
TempoSequence tempoSequence
The global TempoSequence of this Edit.
void addModifierTimer(ModifierTimer &)
Adds a ModifierTimer to be updated each block.
virtual void changed()
This should be called to send a change notification to any SelectableListeners that are registered wi...
#define TRANS(stringLiteral)
#define NEEDS_TRANS(stringLiteral)
Type jlimit(Type lowerLimit, Type upperLimit, Type valueToConstrain) noexcept
bool isPositiveAndNotGreaterThan(Type1 valueToTest, Type2 upperLimit) noexcept
bool isPositiveAndBelow(Type1 valueToTest, Type2 upperLimit) noexcept
int roundToInt(const FloatType value) noexcept
tempo::Sequence::Position createPosition(const TempoSequence &s)
Creates a Position to iterate over the given TempoSequence.
bool getBoolParamValue(const AutomatableParameter &ap)
Returns a bool version of an AutomatableParameter.
int getIntParamValue(const AutomatableParameter &ap)
Returns an int version of an AutomatableParameter.
constexpr double inBeats() const
Returns the position as a number of beats.
Represents a position in real-life time.
constexpr double inSeconds() const
Returns the TimePosition as a number of seconds.
A Sequence::Position is an iterator through a Sequence.
TimeSignature getTimeSignature() const
Returns the current TimeSignature of the Position.
BeatPosition getBeats() const
Returns the current beats of the Position.
void set(TimePosition)
Sets the Position to a new time.
double getTempo() const
Returns the current tempo of the Position.
Connects a modifier source to an AutomatableParameter.
Base class for objects which need to know about the global Edit time every block.
Bass class for parameter Modifiers.
juce::ValueTree state
Modifier internal state.
void setEditTime(TimePosition newEditTime)
Subclasses can call this to update the edit time of the current value.
double getSampleRate() const
Returns the sample rate the Modifier has been initialised with.
The context passed to plugin render methods to provide it with buffers to fill.
int bufferNumSamples
The number of samples to write into the audio buffer.
MidiMessageArray * bufferForMidiMessages
A buffer of MIDI events to process.
A ramp which goes between 0 and 1 over a set duration.