tracktion-engine 3.0-10-g034fdde4aa5
Tracktion Engine — High level data model for audio applications

« « « Anklang Documentation
Loading...
Searching...
No Matches
tracktion_ClipEffects.h
Go to the documentation of this file.
1 /*
2 ,--. ,--. ,--. ,--.
3 ,-' '-.,--.--.,--,--.,---.| |,-.,-' '-.`--' ,---. ,--,--, Copyright 2024
4 '-. .-'| .--' ,-. | .--'| /'-. .-',--.| .-. || \ Tracktion Software
5 | | | | \ '-' \ `--.| \ \ | | | |' '-' '| || | Corporation
6 `---' `--' `--`--'`---'`--'`--' `---' `--' `---' `--''--' www.tracktion.com
7
8 Tracktion Engine uses a GPL/commercial licence - see LICENCE.md for details.
9*/
10
11namespace tracktion { inline namespace engine
12{
13
14//==============================================================================
18{
19public:
20 enum class EffectType
21 {
22 none,
23 volume,
24 fadeInOut,
25 tapeStartStop,
26 stepVolume,
27 pitchShift,
28 warpTime,
29 normalise,
30 makeMono,
31 reverse,
32 invert,
33 filter,
34 firstEffect = volume,
35 lastEffect = filter
36 };
37
38 static juce::ValueTree create (EffectType);
39 static ClipEffect* create (const juce::ValueTree&, ClipEffects&);
40
41 static void createEffectAndAddToValueTree (Edit&, juce::ValueTree parent,
42 ClipEffect::EffectType, int index);
43
44 virtual void initialise() {}
45
46 static juce::String getTypeDisplayName (EffectType);
47 static void addEffectsToMenu (juce::PopupMenu&);
48
50
51 EffectType getType() const;
52
53 struct ClipEffectRenderJob;
54
59 virtual juce::ReferenceCountedObjectPtr<ClipEffectRenderJob> createRenderJob (const AudioFile& sourceFile, double sourceLength) = 0;
60
62 virtual bool hasProperties() { return false; }
63 virtual void propertiesButtonPressed (SelectionManager&) {}
64
66 virtual void sourceChanged() {}
67
72 HashCode getHash() const;
73
74 AudioFile getSourceFile() const;
75 AudioFile getDestinationFile() const;
76
77 bool isUsingFile (const AudioFile&) const;
78
79 virtual void flushStateToValueTree() {}
80
81 juce::UndoManager& getUndoManager();
82 AudioClipBase& getClip();
83
84 Edit& edit;
85 juce::ValueTree state;
86 ClipEffects& clipEffects;
87
88protected:
89 virtual HashCode getIndividualHash() const;
90 void valueTreeChanged() override;
91
92private:
93 friend class ClipEffects;
94 mutable AudioFile destinationFile;
95
96 void invalidateDestination();
97
99};
100
101//==============================================================================
104class ClipEffects : public ValueTreeObjectList<ClipEffect>,
105 private juce::Timer
106{
107public:
108 static juce::ValueTree create()
109 {
110 return juce::ValueTree (IDs::EFFECTS);
111 }
112
113 //==============================================================================
115 ~ClipEffects() override;
116
117 void flushStateToValueTree()
118 {
119 for (auto ce : objects)
120 ce->flushStateToValueTree();
121 }
122
123 ClipEffect* getClipEffect (const juce::ValueTree& v)
124 {
125 for (auto ce : objects)
126 if (ce->state == v)
127 return ce;
128
129 return {};
130 }
131
133 HashCode getHash() const
134 {
135 if (cachedHash == hashNeedsRecaching)
136 if (auto ce = objects.getLast())
137 cachedHash = ce->getHash();
138
139 return cachedHash;
140 }
141
146 {
147 return getCachedClipProperties().effectsRange.getStart();
148 }
149
154 {
155 return getCachedClipProperties().effectsRange.getLength();
156 }
157
161 TimeRange getEffectsRange() const
162 {
163 return getCachedClipProperties().effectsRange;
164 }
165
171 {
172 return getCachedClipProperties().speedRatio;
173 }
174
175 bool isUsingFile (const AudioFile& af)
176 {
177 for (auto ce : objects)
178 if (ce->isUsingFile (af))
179 return true;
180
181 return false;
182 }
183
184 void notifyListenersOfRenderCompletion()
185 {
186 listeners.call (&Listener::renderComplete);
187 }
188
189 RenderManager::Job::Ptr createRenderJob (const AudioFile& destFile, const AudioFile& sourceFile) const;
190
191 bool isSuitableType (const juce::ValueTree& v) const override
192 {
193 return v.hasType (IDs::EFFECT);
194 }
195
196 ClipEffect* createNewObject (const juce::ValueTree& v) override
197 {
198 auto ce = ClipEffect::create (v, *this);
199 jassert (ce != nullptr);
200 listeners.call (&Listener::effectAdded, ce);
201 return ce;
202 }
203
204 void deleteObject (ClipEffect* ce) override
205 {
206 listeners.call (&Listener::effectRemoved, ce);
207 jassert (ce != nullptr);
208 delete ce;
209 }
210
211 void newObjectAdded (ClipEffect*) override
212 {
213 invalidateAllEffects();
214 }
215
216 void objectRemoved (ClipEffect*) override
217 {
218 invalidateAllEffects();
219 }
220
221 void objectOrderChanged() override
222 {
223 invalidateAllEffects();
224 effectChanged();
225 listeners.call (&Listener::effectsReordered);
226 }
227
228 struct Listener
229 {
230 virtual ~Listener() {}
231 virtual void effectChanged() {}
232 virtual void effectAdded (ClipEffect*) {}
233 virtual void effectRemoved (ClipEffect*) {}
234 virtual void effectsReordered() {}
235 virtual void renderComplete() {}
236 };
237
238 void addListener (Listener* l) { listeners.add (l); }
239 void removeListener (Listener* l) { listeners.remove (l); }
240
242 {
243 RenderInhibitor (ClipEffects& o) : effects (o) { ++effects.renderInhibitors; }
244 ~RenderInhibitor() { --effects.renderInhibitors; }
245
246 private:
247 ClipEffects& effects;
249 };
250
251 AudioClipBase& clip;
252 juce::ValueTree state;
253
254private:
255 enum { hashNeedsRecaching = -1 };
256
257 struct CachedClipProperties
258 {
259 CachedClipProperties (const ClipEffects& ce)
260 {
261 auto& c = ce.clip;
262 speedRatio = c.getSpeedRatio();
263
264 if (c.getAutoTempo())
265 {
266 // need to find the tempo changes between the source start and how long the result will be
267 auto info = AudioFile (c.edit.engine, c.getOriginalFile()).getInfo();
268 auto sourceTempo = c.getLoopInfo().getBpm (info);
269 speedRatio = c.edit.tempoSequence.getTempoAt (c.getPosition().time.getStart()).getBpm() / sourceTempo;
270 }
271
272 if (c.isLooping())
273 effectsRange = { c.getLoopStart(), c.getLoopStart() + c.getLoopLength() };
274 else
275 effectsRange = { TimePosition(), c.getSourceLength() / speedRatio };
276 }
277
278 TimeRange effectsRange;
279 double speedRatio = 1.0;
280 };
281
282 struct ClipPropertyWatcher;
283 friend class ClipEffect;
284
286 std::unique_ptr<ClipPropertyWatcher> clipPropertyWatcher;
287 mutable std::unique_ptr<CachedClipProperties> cachedClipProperties;
288 mutable HashCode cachedHash = hashNeedsRecaching;
289
290 int renderInhibitors = 0;
291
292 const CachedClipProperties& getCachedClipProperties() const
293 {
294 if (cachedClipProperties == nullptr)
295 cachedClipProperties = std::make_unique<CachedClipProperties> (*this);
296
297 return *cachedClipProperties;
298 }
299
300 void invalidateAllEffects()
301 {
302 cachedHash = hashNeedsRecaching;
303
304 for (auto ce : objects)
305 ce->invalidateDestination();
306 }
307
308 void effectChanged()
309 {
310 clip.cancelCurrentRender();
311 startTimer (500);
312 }
313
314 void timerCallback() override
315 {
316 if (renderInhibitors > 0)
317 return;
318
319 invalidateAllEffects();
320 listeners.call (&Listener::effectChanged);
321 stopTimer();
322 }
323
326};
327
328//==============================================================================
339
340//==============================================================================
343struct VolumeEffect : public ClipEffect,
344 private juce::Timer
345{
347 juce::ReferenceCountedObjectPtr<ClipEffectRenderJob> createRenderJob (const AudioFile& sourceFile, double sourceLength) override;
348
349 void initialise() override
350 {
351 if (plugin != nullptr)
352 for (auto ap : plugin->getAutomatableParameters())
353 ap->updateStream();
354 }
355
356 bool hasProperties() override;
357 void propertiesButtonPressed (SelectionManager&) override;
358 HashCode getIndividualHash() const override;
359
360 void valueTreePropertyChanged (juce::ValueTree&, const juce::Identifier&) override;
361 void valueTreeChanged() override;
362 void timerCallback() override;
363
366
368};
369
370//==============================================================================
374{
376
377 void setFadeIn (TimeDuration);
378 void setFadeOut (TimeDuration);
379
380 juce::ReferenceCountedObjectPtr<ClipEffectRenderJob> createRenderJob (const AudioFile& sourceFile, double sourceLength) override;
381
382 juce::CachedValue<TimeDuration> fadeIn, fadeOut;
383 juce::CachedValue<AudioFadeCurve::Type> fadeInType, fadeOutType;
384
385protected:
386 HashCode getIndividualHash() const override;
387
389};
390
391//==============================================================================
395 public Selectable
396{
398 ~StepVolumeEffect() override;
399
400 int getMaxNumNotes();
401
402 juce::ReferenceCountedObjectPtr<ClipEffectRenderJob> createRenderJob (const AudioFile& sourceFile, double sourceLength) override;
403
404 bool hasProperties() override;
405 void propertiesButtonPressed (SelectionManager&) override;
406
408
409 //==============================================================================
410 struct Pattern
411 {
413 Pattern (const Pattern& other) noexcept;
414
415 bool getNote (int index) const noexcept;
416 void setNote (int index, bool value);
417
418 juce::BigInteger getPattern() const noexcept;
419 void setPattern (const juce::BigInteger&) noexcept;
420
421 void clear();
422 int getNumNotes() const;
423
424 void shiftChannel (bool toTheRight);
425 void toggleAtInterval (int interval);
426 void randomiseChannel();
427
428 StepVolumeEffect& effect;
429 juce::ValueTree state;
430
431 private:
432 Pattern& operator= (const Pattern&) = delete;
434 };
435
439
440protected:
441 HashCode getIndividualHash() const override;
442
444};
445
446//==============================================================================
450 private juce::Timer
451{
453
454 void initialise() override;
455
456 juce::ReferenceCountedObjectPtr<ClipEffectRenderJob> createRenderJob (const AudioFile& sourceFile, double sourceLength) override;
457
458 bool hasProperties() override;
459 void propertiesButtonPressed (SelectionManager&) override;
460 HashCode getIndividualHash() const override;
461
462 void valueTreePropertyChanged (juce::ValueTree&, const juce::Identifier&) override;
463 void valueTreeChanged() override;
464 void timerCallback() override;
465
468
470};
471
472//==============================================================================
476{
478
480
481 HashCode getIndividualHash() const override;
482 void sourceChanged() override;
483
484 WarpTimeManager::Ptr warpTimeManager;
486
487 void editFinishedLoading();
488
490};
491
492//==============================================================================
495struct PluginEffect : public ClipEffect,
497 private juce::Timer
498{
500
502
503 void initialise() override
504 {
505 if (plugin != nullptr)
506 for (auto ap : plugin->getAutomatableParameters())
507 ap->updateStream();
508 }
509
510 void flushStateToValueTree() override;
511 bool hasProperties() override;
512 void propertiesButtonPressed (SelectionManager&) override;
513 HashCode getIndividualHash() const override;
514
515 void valueTreePropertyChanged (juce::ValueTree&, const juce::Identifier&) override;
516 void valueTreeChanged() override;
517
518 void timerCallback() override;
519 void curveHasChanged (AutomatableParameter&) override;
520
521 Plugin::Ptr plugin;
523 std::unique_ptr<PluginUnloadInhibitor> pluginUnloadInhibitor;
524 juce::CachedValue<int> currentCurve;
525 mutable juce::CachedValue<juce::int64> lastHash;
526
528};
529
530//==============================================================================
534 public Selectable
535{
537 ~NormaliseEffect() override;
538
539 juce::ReferenceCountedObjectPtr<ClipEffectRenderJob> createRenderJob (const AudioFile& sourceFile, double sourceLength) override;
540
541 bool hasProperties() override;
542 void propertiesButtonPressed (SelectionManager&) override;
544
545 juce::CachedValue<double> maxLevelDB;
546
547private:
548 struct NormaliseRenderJob;
549
551};
552
553//==============================================================================
557 public Selectable
558{
559 enum SrcChannels
560 {
561 chLR = 0,
562 chL = 1,
563 chR = 2
564 };
565
567 ~MakeMonoEffect() override;
568
570
571 bool hasProperties() override;
572 void propertiesButtonPressed (SelectionManager&) override;
574
575 juce::CachedValue<int> channels;
576
577private:
578 struct MakeMonoRenderJob;
579
581};
582
583//==============================================================================
596
597//==============================================================================
610
611}} // namespace tracktion { inline namespace engine
ElementType getLast() const noexcept
void call(Callback &&callback)
void stopTimer() noexcept
void startTimer(int intervalInMilliseconds) noexcept
Base class for Clips that produce some kind of audio e.g.
HashCode getHash() const
Returns the hash for this effect.
virtual juce::ReferenceCountedObjectPtr< ClipEffectRenderJob > createRenderJob(const AudioFile &sourceFile, double sourceLength)=0
Subclasses should return a job that can render the source.
virtual void sourceChanged()
Callback to indicate the destination file has changed.
virtual bool hasProperties()
Return true here to show a properties button in the editor and enable the propertiesButtonPressed cal...
TimeDuration getEffectsLength() const
Returns the length of the effect.
TimePosition getEffectsStartTime() const
Returns the start position in the file that the effect should apply to.
TimeRange getEffectsRange() const
Returns the range of the file that the effect should apply to.
double getSpeedRatioEstimate() const
Returns the speed ratio of the clip or an estimate of this if the clip is auto tempo.
HashCode getHash() const
Returns the hash for this set of effects.
The Tracktion Edit class!
Base class for things that can be selected, and whose properties can appear in the properties panel.
Manages a list of items that are currently selected.
T is_pointer_v
#define JUCE_LEAK_DETECTOR(OwnerClass)
#define jassert(expression)
#define JUCE_DECLARE_NON_COPYABLE(className)
#define JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(className)
#define JUCE_DECLARE_WEAK_REFERENCEABLE(Class)
RangeType< TimePosition > TimeRange
A RangeType based on real time (i.e.
Represents a duration in real-life time.
Represents a position in real-life time.
juce::ReferenceCountedObjectPtr< ClipEffectRenderJob > createRenderJob(const AudioFile &sourceFile, double sourceLength) override
Subclasses should return a job that can render the source.
juce::ReferenceCountedObjectPtr< ClipEffect::ClipEffectRenderJob > createRenderJob(const AudioFile &, double sourceLength) override
Subclasses should return a job that can render the source.
bool hasProperties() override
Return true here to show a properties button in the editor and enable the propertiesButtonPressed cal...
juce::ReferenceCountedObjectPtr< ClipEffectRenderJob > createRenderJob(const AudioFile &, double sourceLength) override
Subclasses should return a job that can render the source.
juce::String getSelectableDescription() override
Subclasses must return a description of what they are.
juce::ReferenceCountedObjectPtr< ClipEffectRenderJob > createRenderJob(const AudioFile &sourceFile, double sourceLength) override
Subclasses should return a job that can render the source.
bool hasProperties() override
Return true here to show a properties button in the editor and enable the propertiesButtonPressed cal...
juce::String getSelectableDescription() override
Subclasses must return a description of what they are.
bool hasProperties() override
Return true here to show a properties button in the editor and enable the propertiesButtonPressed cal...
juce::ReferenceCountedObjectPtr< ClipEffectRenderJob > createRenderJob(const AudioFile &sourceFile, double sourceLength) override
Subclasses should return a job that can render the source.
void curveHasChanged(AutomatableParameter &) override
Called when the automation curve has changed, point time, value or curve.
bool hasProperties() override
Return true here to show a properties button in the editor and enable the propertiesButtonPressed cal...
juce::ReferenceCountedObjectPtr< ClipEffectRenderJob > createRenderJob(const AudioFile &, double sourceLength) override
Subclasses should return a job that can render the source.
juce::ReferenceCountedObjectPtr< ClipEffectRenderJob > createRenderJob(const AudioFile &, double sourceLength) override
Subclasses should return a job that can render the source.
juce::ReferenceCountedObjectPtr< ClipEffectRenderJob > createRenderJob(const AudioFile &sourceFile, double sourceLength) override
Subclasses should return a job that can render the source.
juce::String getSelectableDescription() override
Subclasses must return a description of what they are.
bool hasProperties() override
Return true here to show a properties button in the editor and enable the propertiesButtonPressed cal...
juce::ReferenceCountedObjectPtr< ClipEffectRenderJob > createRenderJob(const AudioFile &sourceFile, double sourceLength) override
Subclasses should return a job that can render the source.
bool hasProperties() override
Return true here to show a properties button in the editor and enable the propertiesButtonPressed cal...
void sourceChanged() override
Callback to indicate the destination file has changed.
juce::ReferenceCountedObjectPtr< ClipEffectRenderJob > createRenderJob(const AudioFile &, double sourceLength) override
Subclasses should return a job that can render the source.