Anklang-0.3.0.dev712+gdc4e642f anklang-0.3.0.dev712+gdc4e642f
ASE — Anklang Sound Engine (C++)

« « « Anklang Documentation
Loading...
Searching...
No Matches
trkn.cc
Go to the documentation of this file.
1 // This Source Code Form is licensed MPL-2.0: http://mozilla.org/MPL/2.0
2#include "trkn/tracktion.hh" // PCH include must come first
3
4#include "trkn.hh"
5#include "platform.hh"
6#include "utils.hh"
7#include "main.hh"
8#include "project.hh"
9#include "internal.hh"
10
11namespace te = tracktion::engine;
12
13namespace Ase {
14
15void // see tracktion_engine.h
16trkn_tracktion_log_msg (const juce::String &msg)
17{
18 diag ("TRACKTION: %s", msg.toStdString());
19}
20
21void // see tracktion_engine.h
22trkn_tracktion_log_error (const juce::String &errmsg)
23{
24 // TRACKTION_LOG_ERROR is mostly used for IO or exec errors
25 warning ("TRACKTION: error: %s", errmsg.toStdString());
26}
27
29 bool nodevs = false;
30 bool autoInitialiseDeviceManager () override { return !nodevs; }
31};
32
35 ~TrknApp()
36 {
37 // juce keeps a global JUCEApplicationBase::appInstance around
39 }
40 TrknApp ()
41 {
42 // leave JUCEApplicationBase::createInstance unused
43 }
44 void
45 initialise (const juce::String &whatstring) override
46 {}
47 void
48 start_engine (std::unique_ptr<EngineBehaviour> engine_behaviour)
49 {
52 auto &deviceManager = engine->getDeviceManager();
53 // deviceManager.initialise (0, 2); // 0 inputs, 2 stereo outputs
54 if (engine->getEngineBehaviour().autoInitialiseDeviceManager())
55 deviceManager.rescanMidiDeviceList(); // run scan in 5ms instead of 4000ms
56 }
57 void
58 shutdown() override
59 {
60 engine = nullptr;
61 }
62 const juce::String
63 getApplicationName() override
64 {
65 return Ase::application_name();
66 }
67 const juce::String
68 getApplicationVersion() override
69 {
70 return Ase::ase_version();
71 }
72};
73static TrknApp *trkn_app = nullptr;
74
75void
76trkn_shutdown ()
77{
78 return_unless (trkn_app);
79 ProjectImpl::force_shutdown_all();
80 main_loop->iterate_pending();
81 trkn_app->shutdownApp();
82}
83
84struct AseLogger : public juce::Logger {
85 void
86 logMessage (const juce::String &msg) override
87 {
88 diag ("JUCE: %s", msg.toStdString());
89 }
90};
91
98bool
99trkn_init (int argc, char *argv[], bool nodevs)
100{
101 assert_return (!trkn_app && main_loop, false);
102 static AseLogger *logger = new AseLogger();
104 // juce requires a JUCEApplicationBase instance
105 trkn_app = new TrknApp();
106 if (!trkn_app->initialiseApp()) {
107 trkn_app->shutdownApp();
108 return false;
109 }
110 // create 1 tracktion engine and configure PCM / MIDI device scan
111 auto engine_behaviour = std::make_unique<EngineBehaviour>();
112 engine_behaviour->nodevs = nodevs;
113 trkn_app->start_engine (std::move (engine_behaviour));
114 // process tracktion setup callbacks
115 main_loop->iterate_pending();
116 return true;
117}
118
119tracktion::Engine*
120trkn_engine ()
121{
122 return trkn_app ? trkn_app->engine.get() : nullptr;
123}
124
126{
127public:
128 TransportListener (tracktion::TransportControl &tc)
129 : transport (tc)
130 {
131 transport.addChangeListener (this); // for ChangeListener
132 transport.addListener (this); // for TransportControl::Listener
133 Ase::printerr ("TransportListener attached.\n");
134 }
135 ~TransportListener() override
136 {
137 transport.removeListener (this);
138 transport.removeChangeListener (this);
139 Ase::printerr ("TransportListener detached.\n");
140 }
141 void
142 changeListenerCallback (juce::ChangeBroadcaster *source) override
143 {
144 if (source == &transport) {
145 transport_changed ("change");
146 }
147 }
148 void autoSaveNow () override {}
149 void setAllLevelMetersActive (bool become_inactive) override {}
150 void setVideoPosition (tracktion::TimePosition pos, bool force_jump) override {}
151 void recordingStarted (tracktion::SyncPoint start, std::optional<tracktion::TimeRange> punch_range) override {}
152 void recordingStopped (tracktion::SyncPoint sync_point, bool discard_recordings) override {}
153 void recordingAboutToStart (tracktion::InputDeviceInstance &device, tracktion::EditItemID target) override {}
154 void recordingAboutToStop (tracktion::InputDeviceInstance &device, tracktion::EditItemID target) override {}
155 void recordingFinished (tracktion::InputDeviceInstance &device, tracktion::EditItemID target,
156 const juce::ReferenceCountedArray<tracktion::Clip> &recording) override {}
157 void
158 playbackContextChanged () override
159 {
160 tracktion::EditPlaybackContext *context = transport.getCurrentPlaybackContext();
161 Ase::printerr ("PlaybackContextChanged: context=%p graph=%d playing=%d position=%.3fsecs\n", context,
162 context ? context->isPlaybackGraphAllocated() : 0,
163 context ? context->isPlaying() : 0,
164 context ? context->getPosition().inSeconds() : 0);
165 }
166 void
167 startVideo () override
168 {
169 transport_changed ("start-video");
170 if (ppt == LoopID::INVALID)
171 ppt = main_loop->add ([this] { this->poll_position(); return true; }, std::chrono::milliseconds (200));
172 }
173 void
174 stopVideo () override
175 {
176 transport_changed ("stop-video");
177 main_loop->cancel (&ppt);
178 }
179 void
180 transport_changed (const std::string &what)
181 {
182 auto position = transport.getPosition();
183 Ase::printerr ("Transport: playing=%d position=%.3fsecs (%s)\n",
184 transport.isPlaying(), position.inSeconds(), what.c_str());
185 }
186 void
187 poll_position()
188 {
189 transport_changed ("position");
190 }
191 private:
192 tracktion::TransportControl &transport;
193 LoopID ppt = LoopID::INVALID;
195};
196
198static std::unique_ptr<TransportListener> transport_listener;
199
200namespace EngineHelpers
201{
202tracktion::AudioTrack*
203getOrInsertAudioTrackAt (tracktion::Edit &edit, int index)
204{
205 edit.ensureNumberOfAudioTracks (index + 1);
206 return tracktion::getAudioTracks (edit)[index];
207}
208void
209removeAllClips (tracktion::AudioTrack &track)
210{
211 auto clips = track.getClips();
212
213 for (int i = clips.size(); --i >= 0;)
214 clips.getUnchecked (i)->removeFromParent();
215}
216tracktion::WaveAudioClip::Ptr
217loadAudioFileAsClip (tracktion::Edit &edit, const juce::File &file)
218{
219 // Find the first track and delete all clips from it
220 if (auto track = getOrInsertAudioTrackAt (edit, 0)) {
221 removeAllClips (*track);
222
223 // Add a new clip to this track
224 tracktion::AudioFile audioFile (edit.engine, file);
225
226 if (audioFile.isValid())
227 if (auto newClip = track->insertWaveClip (file.getFileNameWithoutExtension(), file,
228 { { {}, tracktion::TimeDuration::fromSeconds (audioFile.getLength()) }, {} }, false))
229 return newClip;
230 }
231
232 return {};
233}
234template<typename ClipType> typename ClipType::Ptr
235loopAroundClip (ClipType &clip)
236{
237 using namespace std::literals;
238 auto &transport = clip.edit.getTransport();
239 transport.setLoopRange (clip.getEditTimeRange());
240 transport.looping = true;
241 transport.setPosition (0s);
242 return clip;
243}
244} // EngineHelpers
245
246} // Ase
T c_str(T... args)
String getFileNameWithoutExtension() const
static void JUCE_CALLTYPE setCurrentLogger(Logger *newLogger) noexcept
T get(T... args)
#define assert_return(expr,...)
Return from the current function if expr is unmet and issue an assertion warning.
Definition internal.hh:29
#define return_unless(cond,...)
Return silently if cond does not evaluate to true with return value ...
Definition internal.hh:73
#define assert_return_unreached(...)
Return from the current function and issue an assertion warning.
Definition internal.hh:31
#define JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(className)
The Anklang C++ API namespace.
Definition api.hh:9
bool trkn_init(int argc, char *argv[], bool nodevs)
Setup tracktion and tracktion::engine.
Definition trkn.cc:99
String application_name()
Retrieve the localized program name intended for user display.
Definition platform.cc:832
const char * ase_version()
Provide a string containing the package version.
Definition platform.cc:803