11#if TRACKTION_ENABLE_ARA
15 #pragma warning (push, 0)
17 #pragma clang diagnostic push
18 #pragma clang diagnostic ignored "-Wnon-virtual-dtor"
19 #pragma clang diagnostic ignored "-Wreorder"
20 #pragma clang diagnostic ignored "-Wunsequenced"
21 #pragma clang diagnostic ignored "-Wint-to-pointer-cast"
22 #pragma clang diagnostic ignored "-Wunused-parameter"
23 #pragma clang diagnostic ignored "-Wconversion"
24 #pragma clang diagnostic ignored "-Woverloaded-virtual"
25 #pragma clang diagnostic ignored "-Wshadow"
26 #pragma clang diagnostic ignored "-Wgnu-zero-variadic-macro-arguments"
27 #if __clang_major__ >= 10
28 #pragma clang diagnostic ignored "-Wpragma-pack"
32#undef PRAGMA_ALIGN_SUPPORTED
33#undef VST_FORCE_DEPRECATED
34#define VST_FORCE_DEPRECATED 0
42#include "ARA_API/ARAVST3.h"
43#include "ARA_Library/Dispatch/ARAHostDispatch.h"
50 DEF_CLASS_IID (IMainFactory)
51 DEF_CLASS_IID (IPlugInEntryPoint)
52 DEF_CLASS_IID (IPlugInEntryPoint2)
58 #pragma clang diagnostic pop
61namespace tracktion {
inline namespace engine
66struct ARAClipPlayer :
private Selectable::Listener
68 #include "tracktion_MelodyneInstanceFactory.h"
69 #include "tracktion_ARAWrapperFunctions.h"
70 #include "tracktion_ARAWrapperInterfaces.h"
73 ARAClipPlayer (Edit& ed, MelodyneFileReader& o, AudioClipBase& c)
74 : Selectable::Listener (ed.tempoSequence), owner (o),
76 file (c.getAudioFile()),
79 TRACKTION_ASSERT_MESSAGE_THREAD
80 jassert (file.getFile().existsAsFile());
86 TRACKTION_ASSERT_MESSAGE_THREAD
88 contentAnalyserChecker =
nullptr;
89 modelUpdater =
nullptr;
90 contentUpdater =
nullptr;
93 if (
auto p = getPlugin())
95 p->hideWindowForShutdown();
97 if (
auto pi = p->getAudioPluginInstance())
98 pi->releaseResources();
101 if (
auto doc = getDocument())
103 if (doc->dci !=
nullptr)
106 const ScopedDocumentEditor sde (*
this,
false);
107 playbackRegionAndSource =
nullptr;
110 melodyneInstance =
nullptr;
116 Edit& getEdit() {
return edit; }
117 AudioClipBase& getClip() {
return clip; }
118 ExternalPlugin* getPlugin() {
return melodyneInstance !=
nullptr ? melodyneInstance->plugin.get() :
nullptr; }
119 const ARAFactory* getARAFactory()
const {
return melodyneInstance !=
nullptr ? melodyneInstance->factory :
nullptr; }
122 bool initialise (ARAClipPlayer* clipToClone)
124 TRACKTION_ASSERT_MESSAGE_THREAD
127 if (
auto doc = getDocument())
129 ExternalPlugin::Ptr p = MelodyneInstanceFactory::getInstance (edit.engine).createPlugin (edit);
131 if (p ==
nullptr || getDocument() ==
nullptr)
134 melodyneInstance.reset (MelodyneInstanceFactory::getInstance (edit.engine).createInstance (*p, doc->dcRef));
136 if (melodyneInstance ==
nullptr)
139 updateContent (clipToClone);
141 return playbackRegionAndSource !=
nullptr
142 && playbackRegionAndSource->playbackRegion !=
nullptr;
148 void contentHasChanged()
151 updateContent (
nullptr);
152 owner.sendChangeMessage();
155 void selectableObjectChanged (Selectable*)
override
157 if (
auto doc = getDocument())
159 if (doc->musicalContext !=
nullptr)
161 doc->beginEditing (
true);
162 doc->musicalContext->update();
163 doc->endEditing (
true);
168 void selectableObjectAboutToBeDeleted (Selectable*)
override {}
171 void updateContent (ARAClipPlayer* clipToClone)
174 TRACKTION_ASSERT_MESSAGE_THREAD
176 if (juce::MessageManager::getInstance()->isThisTheMessageThread()
177 && getEdit().getTransport().isAllowedToReallocate())
179 contentUpdater =
nullptr;
180 internalUpdateContent (clipToClone);
184 if (contentUpdater ==
nullptr)
190 if (! contentUpdater->isTimerRunning())
191 contentUpdater->startTimer (100);
201 const int midiChannel = 1;
204 if (
auto doc = getDocument())
206 const ARADocumentControllerInterface* dci = doc->dci;
207 ARADocumentControllerRef dcRef = doc->dcRef;
208 ARAAudioSourceRef audioSourceRef = playbackRegionAndSource->audioSource->audioSourceRef;
210 if (dci->isAudioSourceContentAvailable (dcRef, audioSourceRef, kARAContentTypeNotes))
212 ARAContentReaderRef contentReaderRef = dci->createAudioSourceContentReader (dcRef, audioSourceRef, kARAContentTypeNotes,
nullptr);
213 int numEvents = (
int) dci->getContentReaderEventCount (dcRef, contentReaderRef);
215 for (
int i = 0; i < numEvents; ++i)
217 if (
auto note =
static_cast<const ARAContentNote*
> (dci->getContentReaderDataForEvent (dcRef, contentReaderRef, i)))
219 if (note->pitchNumber != kARAInvalidPitchNumber)
222 note->startPosition);
225 note->startPosition + note->noteDuration);
230 dci->destroyContentReader (dcRef, contentReaderRef);
240 void setViewSelection()
242 if (playbackRegionAndSource !=
nullptr)
243 playbackRegionAndSource->setViewSelection();
247 void startProcessing() { TRACKTION_ASSERT_MESSAGE_THREAD
if (playbackRegionAndSource !=
nullptr) playbackRegionAndSource->enable(); }
248 void stopProcessing() { TRACKTION_ASSERT_MESSAGE_THREAD
if (playbackRegionAndSource !=
nullptr) playbackRegionAndSource->disable(); }
250 class ContentAnalyser
253 ContentAnalyser (
const ARAClipPlayer& p) : pimpl (p)
259 callBlocking ([
this] { updateAnalysingContent(); });
261 return analysingContent;
264 void updateAnalysingContent()
268 auto doc = pimpl.getDocument();
272 analysingContent =
false;
276 const ARADocumentControllerInterface* dci = doc->dci;
277 ARADocumentControllerRef dcRef = doc->dcRef;
278 ARAAudioSourceRef audioSourceRef =
nullptr;
280 if (pimpl.playbackRegionAndSource !=
nullptr)
281 if (pimpl.playbackRegionAndSource->audioSource !=
nullptr)
282 audioSourceRef = pimpl.playbackRegionAndSource->audioSource->audioSourceRef;
284 if (dci !=
nullptr && dcRef !=
nullptr && audioSourceRef !=
nullptr)
288 auto araFactory = pimpl.getARAFactory();
289 for (ARAContentType contentType : { kARAContentTypeBarSignatures, kARAContentTypeTempoEntries })
291 for (
int i = 0; i < (
int) araFactory->analyzeableContentTypesCount; i++)
293 if (araFactory->analyzeableContentTypes[i] == contentType)
295 typesBeingAnalyzed.push_back (contentType);
301 if (!typesBeingAnalyzed.empty())
302 dci->requestAudioSourceContentAnalysis (dcRef, audioSourceRef, (ARASize)typesBeingAnalyzed.size(), typesBeingAnalyzed.data());
307 analysingContent =
false;
308 for (ARAContentType contentType : typesBeingAnalyzed)
310 analysingContent = (dci->isAudioSourceContentAnalysisIncomplete (dcRef, audioSourceRef, contentType) != kARAFalse);
311 if (analysingContent)
317 analysingContent =
false;
322 const ARAClipPlayer& pimpl;
324 volatile bool analysingContent =
false;
325 bool firstCall =
true;
327 ContentAnalyser() =
delete;
331 friend class ContentAnalyser;
335 bool isAnalysingContent()
const
337 return contentAnalyserChecker->isAnalysing();
340 ARADocument* getDocument()
const;
344 MelodyneFileReader& owner;
346 const AudioFile file;
351 HashCode currentHashCode = 0;
354 struct ScopedDocumentEditor
356 ScopedDocumentEditor (ARAClipPlayer& o,
bool restartModelUpdaterLater)
357 : owner (o), restartTimerLater (restartModelUpdaterLater)
359 if (restartTimerLater)
360 owner.modelUpdater =
nullptr;
362 owner.getDocument()->beginEditing (
false);
365 ~ScopedDocumentEditor()
367 if (
auto doc = owner.getDocument())
369 doc->endEditing (
false);
371 if (restartTimerLater)
377 ARAClipPlayer& owner;
378 const bool restartTimerLater;
388 void recreateTrack (ARAClipPlayer* clipToClone)
391 TRACKTION_ASSERT_MESSAGE_THREAD
393 jassert (melodyneInstance !=
nullptr);
394 jassert (melodyneInstance->factory !=
nullptr);
395 jassert (melodyneInstance->extensionInstance !=
nullptr);
397 auto oldTrack = std::move (playbackRegionAndSource);
400 *melodyneInstance->extensionInstance,
402 clipToClone !=
nullptr ? clipToClone->playbackRegionAndSource.get() : nullptr);
404 if (oldTrack !=
nullptr)
406 const ScopedDocumentEditor sde (*
this,
false);
411 void internalUpdateContent (ARAClipPlayer* clipToClone)
414 TRACKTION_ASSERT_MESSAGE_THREAD
416 if (
auto doc = getDocument())
420 contentAnalyserChecker =
nullptr;
421 modelUpdater =
nullptr;
423 HashCode newHashCode = file.getHash()
424 ^ file.getFile().getLastModificationTime().toMilliseconds()
425 ^
static_cast<HashCode
> (clip.itemID.getRawID());
427 if (currentHashCode != newHashCode)
429 currentHashCode = newHashCode;
430 const ScopedDocumentEditor sde (*
this,
true);
432 recreateTrack (clipToClone);
436 if (playbackRegionAndSource !=
nullptr
437 && playbackRegionAndSource->playbackRegion !=
nullptr)
439 const ScopedDocumentEditor sde (*
this,
true);
440 playbackRegionAndSource->playbackRegion->updateRange();
446 if (contentAnalyserChecker ==
nullptr)
454 ContentUpdater (ARAClipPlayer& p) : owner (p) { startTimer (100); }
456 ARAClipPlayer& owner;
458 void timerCallback()
override
462 if (owner.getEdit().getTransport().isAllowedToReallocate())
464 owner.internalUpdateContent (
nullptr);
477 ModelUpdater (ARADocument& d) : document (d) { startTimer (3000); }
479 ARADocument& document;
481 void timerCallback()
override
484 if (document.dci !=
nullptr && document.dcRef !=
nullptr)
485 document.dci->notifyModelUpdates (document.dcRef);
494 ARAClipPlayer() =
delete;
499MelodyneFileReader::MelodyneFileReader (Edit& ed, AudioClipBase& clip)
501 TRACKTION_ASSERT_MESSAGE_THREAD
506 if (! player->initialise (
nullptr))
510MelodyneFileReader::MelodyneFileReader (Edit& ed, AudioClipBase& clip, MelodyneFileReader& other)
512 TRACKTION_ASSERT_MESSAGE_THREAD
515 if (other.player !=
nullptr)
519 if (! player->initialise (other.player.get()))
526MelodyneFileReader::~MelodyneFileReader()
528 TRACKTION_ASSERT_MESSAGE_THREAD
531 if (player !=
nullptr)
532 if (
auto plugin = player->getPlugin())
533 if (
auto pi = plugin->getAudioPluginInstance())
534 pi->setPlayHead (
nullptr);
536 auto toDestroy = std::move (player);
540void MelodyneFileReader::showPluginWindow()
542 if (player !=
nullptr)
543 player->setViewSelection();
545 if (
auto p = getPlugin())
546 p->showWindowExplicitly();
549void MelodyneFileReader::hidePluginWindow()
551 if (
auto p = getPlugin())
552 p->hideWindowForShutdown();
555ExternalPlugin* MelodyneFileReader::getPlugin()
558 return player->getPlugin();
564bool MelodyneFileReader::isAnalysingContent()
566 return player !=
nullptr && player->isAnalysingContent();
569void MelodyneFileReader::sourceClipChanged()
571 if (player !=
nullptr)
572 player->updateContent (
nullptr);
578 if (player !=
nullptr)
579 return player->getAnalysedMIDISequence();
584void MelodyneFileReader::cleanUpOnShutdown()
586 ARAClipPlayer::MelodyneInstanceFactory::shutdown();
590struct ARADocumentHolder::Pimpl
592 Pimpl (Edit& e) : edit (e) {}
596 TRACKTION_ASSERT_MESSAGE_THREAD
597 araDocument.reset (ARAClipPlayer::createDocument (edit));
599 if (araDocument !=
nullptr)
601 araDocument->beginRestoringState (edit.getARADocument().lastState);
605 if (
auto c =
dynamic_cast<AudioClipBase*
> (&i))
606 c->loadMelodyneState();
611 araDocument->endRestoringState();
621ARADocumentHolder::ARADocumentHolder (Edit& e,
const juce::ValueTree& v)
622 : edit (e), lastState (v)
626ARADocumentHolder::~ARADocumentHolder()
628 TRACKTION_ASSERT_MESSAGE_THREAD
633ARADocumentHolder::Pimpl* ARADocumentHolder::getPimpl()
635 if (pimpl ==
nullptr)
639 callBlocking ([
this]() { pimpl->initialise(); });
645void ARADocumentHolder::flushStateToValueTree()
647 TRACKTION_ASSERT_MESSAGE_THREAD
649 if (pimpl !=
nullptr)
650 if (pimpl->araDocument !=
nullptr)
651 pimpl->araDocument->flushStateToValueTree (lastState);
654ARAClipPlayer::ARADocument* ARAClipPlayer::getDocument()
const
656 if (
auto p = edit.getARADocument().getPimpl())
657 return p->araDocument.get();
667namespace tracktion {
inline namespace engine
674MelodyneFileReader::MelodyneFileReader (Edit&, AudioClipBase&, MelodyneFileReader&) {}
675MelodyneFileReader::~MelodyneFileReader() {}
677void MelodyneFileReader::cleanUpOnShutdown() {}
678ExternalPlugin* MelodyneFileReader::getPlugin() {
return {}; }
679void MelodyneFileReader::showPluginWindow() {}
680void MelodyneFileReader::hidePluginWindow() {}
681bool MelodyneFileReader::isAnalysingContent() {
return false; }
683void MelodyneFileReader::sourceClipChanged() {}
686ARADocumentHolder::~ARADocumentHolder() {}
687ARADocumentHolder::Pimpl* ARADocumentHolder::getPimpl() {
return {}; }
688void ARADocumentHolder::flushStateToValueTree() {}
MidiEventHolder * addEvent(const MidiMessage &newMessage, double timeAdjustment=0)
void updateMatchedPairs() noexcept
static MidiMessage noteOn(int channel, int noteNumber, float velocity) noexcept
static MidiMessage noteOff(int channel, int noteNumber, float velocity) noexcept
static String toHexString(IntegerType number)
Base class for Clips that produce some kind of audio e.g.
The Tracktion Edit class!
void ignoreUnused(Types &&...) noexcept
void visitAllTrackItems(const Edit &edit, std::function< bool(TrackItem &)> f)
Calls a function for all TrackItems in an Edit.
#define CRASH_TRACER
This macro adds the current location to a stack which gets logged if a crash happens.