Anklang-0.3.0.dev797+g4e3241f3 anklang-0.3.0.dev797+g4e3241f3
ASE — Anklang Sound Engine (C++)

« « « Anklang Documentation
Loading...
Searching...
No Matches
track.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 "track.hh"
5#include "project.hh"
6#include "clip.hh"
7#include "server.hh"
8#include "main.hh"
9#include "serialize.hh"
10#include "jsonipc/jsonipc.hh"
11#include "internal.hh"
12
13namespace te = tracktion::engine;
14
15namespace Ase {
16
17// == TrackStateListener ==
19 TrackImpl &asetrack_;
20 juce::ValueTree track_state_;
21 juce::ValueTree volume_plugin_state_;
22 te::LevelMeasurer::Client meter_client_;
23 te::LevelMeasurer *measurer_ = nullptr;
24 FastMemory::Block telemetry_block_;
25public:
26 struct Telemetry {
27 float dbspl0 = -100.0f;
28 float dbspl1 = -100.0f;
29 } &telemetry;
30 TrackStateListener (TrackImpl &asetrack) :
31 asetrack_ (asetrack), track_state_ (asetrack_.track_->state),
32 telemetry_block_ (SERVER->telemem_allocate (sizeof (Telemetry))),
33 telemetry (*new (telemetry_block_.block_start) Telemetry{})
34 {
35 track_state_.addListener (this);
36 if (auto t = asetrack_.track_.get()) {
37 if (auto at = dynamic_cast<te::AudioTrack *> (t)) {
38 if (auto lmp = at->getLevelMeterPlugin()) {
39 measurer_ = &lmp->measurer;
40 measurer_->addClient (meter_client_);
41 }
42 if (auto vol = at->getVolumePlugin()) {
43 volume_plugin_state_ = vol->state;
44 volume_plugin_state_.addListener (this);
45 }
46 }
47 }
48 }
49 ~TrackStateListener() override
50 {
51 if (volume_plugin_state_.isValid())
52 volume_plugin_state_.removeListener (this);
53 if (measurer_)
54 measurer_->removeClient (meter_client_);
55 track_state_.removeListener (this);
56 SERVER->telemem_release (telemetry_block_);
57 }
59 get_levels()
60 {
61 if (!measurer_)
62 return { -100.0f, -100.0f };
63 te::DbTimePair left = meter_client_.getAndClearAudioLevel (0);
64 te::DbTimePair right = meter_client_.getAndClearAudioLevel (1);
65 return { left.dB, right.dB };
66 }
67 void
68 valueTreePropertyChanged (juce::ValueTree &tree, const juce::Identifier &property) override
69 {
70 if (tree == track_state_) {
71 if (property == tracktion::engine::IDs::name)
72 asetrack_.emit_notify ("name");
73 if (property == tracktion::engine::IDs::mute)
74 asetrack_.emit_notify ("muted");
75 if (property == tracktion::engine::IDs::solo)
76 asetrack_.emit_notify ("solo");
77 }
78 if (tree == volume_plugin_state_) {
79 if (property == tracktion::engine::IDs::volume)
80 asetrack_.emit_notify ("volume");
81 if (property == tracktion::engine::IDs::pan)
82 asetrack_.emit_notify ("pan");
83 }
84 asetrack_.update_telemetry();
85 }
86 void valueTreeChildAdded (juce::ValueTree&, juce::ValueTree&) override {}
87 void valueTreeChildRemoved (juce::ValueTree&, juce::ValueTree&, int) override {}
88 void valueTreeParentChanged (juce::ValueTree&) override {}
89 void valueTreeChildOrderChanged (juce::ValueTree&, int, int) override {}
90};
91
92// == TrackImpl ==
93static std::string
94trkn_track_type (tracktion::Track &track)
95{
96 if (dynamic_cast<te::FolderTrack*> (&track))
97 return "Folder";
98 if (dynamic_cast<te::AudioTrack*> (&track))
99 return "Audio/Midi";
100 if (track.isTempoTrack())
101 return "Tempo";
102 if (track.isMarkerTrack())
103 return "Marker";
104 if (track.isChordTrack())
105 return "Chord";
106 if (track.isArrangerTrack())
107 return "Arranger";
108 if (track.isMasterTrack())
109 return "Master";
110 return "Unknown";
111}
112
113TrackImplP
114TrackImpl::from_trkn (tracktion::Track &t)
115{
116 TrackImpl *track = SelectableHandle::find_selectable_handle<TrackImpl> (t);
117 if (track)
118 return shared_ptr_cast<TrackImpl> (track);
119 TrackImplP trackp = TrackImpl::make_shared (t);
120 return trackp;
121}
122
123TrackImpl::TrackImpl (tracktion::Track &track) :
124 project_ (SelectableHandle::find_selectable_handle<ProjectImpl> (track.edit)),
125 track_ (&track), te_type_ (trkn_track_type (track))
126{
127 state_listener_ = std::make_unique<TrackStateListener> (*this);
128 update_telemetry();
129}
130
131TrackImpl::TrackImpl (ProjectImpl &project, bool masterflag) :
132 project_ (&project)
133{
134 gadget_flags (masterflag ? MASTER_TRACK : 0);
135}
136
137TrackImpl::~TrackImpl()
138{
139 state_listener_ = nullptr;
140 assert_return (_parent() == nullptr);
141}
142
143String
144TrackImpl::name() const
145{
146 if (auto trackp = track_.get())
147 return trackp->getName().toStdString();
148 return "";
149}
150
151void
152TrackImpl::name (const std::string &n)
153{
154 if (auto trackp = track_.get())
155 trackp->setName (juce::String (n));
156}
157
158ProjectImpl*
159TrackImpl::project () const
160{
161 return static_cast<ProjectImpl*> (_parent());
162}
163
164String
165TrackImpl::fallback_name() const
166{
167 if (is_master())
168 return "Master";
169 if (auto project_ = project()) {
170 ssize_t i = project_->track_index (*this);
171 return string_format ("Track %u", i >= 0 ? i + 1 : i);
172 }
173 return DeviceImpl::fallback_name();
174}
175
176void
180
181void
187
188void
194
195void
196TrackImpl::midi_channel (int32 midichannel)
197{
198 midichannel = CLAMP (midichannel, 0, 16);
199 return_unless (midichannel != midi_channel_);
200 midi_channel_ = midichannel;
201 emit_notify ("midi_channel");
202}
203
204bool
206{
207 if (auto t = track_.get())
208 return t->isMuted (false);
209 return false;
210}
211
212void
214{
215 if (auto t = track_.get())
216 t->setMute (muted);
217}
218
219bool
221{
222 if (auto t = track_.get())
223 return t->isSolo (false);
224 return false;
225}
226
227void
229{
230 if (auto t = track_.get())
231 t->setSolo (solo);
232}
233
234bool
236{
237 if (auto t = track_.get())
238 return t->isMasterTrack();
239 return false;
240}
241
242double
244{
245 if (auto t = track_.get())
246 if (auto at = dynamic_cast<te::AudioTrack*> (t))
247 if (auto vol = at->getVolumePlugin())
248 return vol->getVolumeDb();
249 return 0.0;
250}
251
252void
254{
255 if (auto t = track_.get())
256 if (auto at = dynamic_cast<te::AudioTrack*> (t))
257 if (auto vol = at->getVolumePlugin())
258 vol->setVolumeDb (db);
259}
260
261double
263{
264 if (auto t = track_.get())
265 if (auto at = dynamic_cast<te::AudioTrack*> (t))
266 if (auto vol = at->getVolumePlugin())
267 return vol->getPan();
268 return 0.0;
269}
270
271void
273{
274 if (auto t = track_.get())
275 if (auto at = dynamic_cast<te::AudioTrack*> (t))
276 if (auto vol = at->getVolumePlugin())
277 vol->setPan (pan);
278}
279
280ClipS
282{
283 ClipS clips;
284 if (auto t = track_.get())
285 if (auto ct = dynamic_cast<te::ClipTrack*> (t))
286 for (auto *clip : ct->getClips())
287 if (auto clipimpl = ClipImpl::from_trkn (*clip))
288 clips.push_back (clipimpl);
289 return clips;
290}
291
293TrackImpl::clip_index (const ClipImpl &clip) const
294{
295 if (auto t = track_.get())
296 if (auto ct = dynamic_cast<te::ClipTrack *> (t)) {
297 auto &clips = ct->getClips();
298 for (int i = 0; i < clips.size(); i++)
299 if (clips[i] == clip.clip_.get())
300 return i;
301 }
302 return -1;
303}
304
305int
306TrackImpl::clip_succession (const ClipImpl &clip) const
307{
308 ssize_t idx = clip_index (clip);
309 if (idx < 0)
310 return NONE;
311 if (auto t = track_.get())
312 if (auto ct = dynamic_cast<te::ClipTrack *> (t)) {
313 auto &clips = ct->getClips();
314 if (idx + 1 < clips.size())
315 return idx + 1;
316 }
317 return NONE;
318}
319
320DeviceP
322{
323 return nullptr;
324}
325
326MonitorP
327TrackImpl::create_monitor (int32 ochannel)
328{
329 return nullptr;
330}
331
332TelemetryFieldS
334{
335 TelemetryFieldS v;
336 return_unless (state_listener_, v);
337 auto &t = state_listener_->telemetry;
338 v.push_back (telemetry_field ("dbspl0", &t.dbspl0));
339 v.push_back (telemetry_field ("dbspl1", &t.dbspl1));
340 return v;
341}
342
343void
344TrackImpl::update_telemetry()
345{
346 return_unless (state_listener_);
347 auto &t = state_listener_->telemetry;
348 auto [left, right] = state_listener_->get_levels();
349 t.dbspl0 = left;
350 t.dbspl1 = right;
351}
352
353DeviceInfo
355{
356 return {};
357}
358
359// == TrackImpl::ClipScout ==
360TrackImpl::ClipScout::ClipScout() noexcept
361{
362 // PRNG initialization goes here
363}
364
366void
368{
369 indices_ = indices;
370}
371
373int
375{
376 if (previous >= 0 && previous < indices_.size()) {
377 last_ = previous;
378 return indices_[last_];
379 }
380 return NONE;
381}
382
384void
386{
387 last_ = -1;
388}
389
391void
393{
394 indices_ = other.indices_;
395}
396
397ClipImplP
398TrackImpl::create_midi_clip (const String &name, double start, double length)
399{
400 if (auto t = track_.get()) {
401 if (auto at = dynamic_cast<tracktion::AudioTrack *> (t)) {
402 const tracktion::TimeRange range (tracktion::TimePosition::fromSeconds (start), tracktion::TimeDuration::fromSeconds (length));
403 auto clip = at->insertMIDIClip (juce::String (name), range, nullptr);
404 if (clip)
405 return ClipImpl::from_trkn (*clip);
406 else
407 warning ("insertMIDIClip returned null");
408 }
409 else
410 warning ("dynamic_cast<AudioTrack*> failed for track type: %s", trkn_track_type (*t).c_str());
411 }
412 else
413 warning ("track_.get() returned null");
414 return nullptr;
415}
416
417ClipImplP
418TrackImpl::create_audio_clip (const String &name, double start, double length)
419{
420 if (auto t = track_.get()) {
421 if (auto ct = dynamic_cast<tracktion::ClipTrack *> (t)) {
422 const tracktion::TimeRange range (tracktion::TimePosition::fromSeconds (start), tracktion::TimeDuration::fromSeconds (length));
423 auto clip = ct->insertNewClip (tracktion::TrackItem::Type::wave, juce::String (name), range, nullptr);
424 if (clip)
425 return ClipImpl::from_trkn (*clip);
426 else
427 warning ("insertNewClip returned null");
428 }
429 else
430 warning ("dynamic_cast<ClipTrack*> failed for track type: %s", trkn_track_type (*t).c_str());
431 }
432 else
433 warning ("track_.get() returned null");
434 return nullptr;
435}
436
437} // Ase
bool is_active() override
Check whether this is the active synthesis engine project.
Definition device.hh:20
void _deactivate() override
Stop processing the corresponding AudioProcessor.
Definition device.cc:27
void _activate() override
Add AudioProcessor to the Engine and start processing.
Definition device.cc:20
void emit_notify(const String &detail) override
Emit notify:detail, multiple notifications maybe coalesced if a CoalesceNotifies instance exists.
Definition object.cc:164
GadgetImpl * _parent() const override
Retrieve parent container.
Definition gadget.hh:30
MIDI clip playback succession generator.
Definition track.hh:61
int advance(int previous)
Determine clip succession.
Definition track.cc:374
void reset()
Reset state (history), preserves succession order.
Definition track.cc:385
void setup(const std::vector< int > &indices)
Setup clip succession order.
Definition track.cc:367
void update(const ClipScout &other)
Assign new succession order, preserves history.
Definition track.cc:392
Ase::Track implementation.
Definition track.hh:11
double volume() const override
Get track volume in dB.
Definition track.cc:243
double pan() const override
Get track pan (-1.0 to 1.0).
Definition track.cc:262
ClipS launcher_clips() override
Retrieve the list of clips that can be directly played.
Definition track.cc:281
bool is_muted() const override
Check if track is muted.
Definition track.cc:205
void _activate() override
Add AudioProcessor to the Engine and start processing.
Definition track.cc:182
void serialize(WritNode &xs) override
Serialize members and childern.
Definition track.cc:177
void set_muted(bool muted) override
Set track muted state.
Definition track.cc:213
void _deactivate() override
Stop processing the corresponding AudioProcessor.
Definition track.cc:189
bool is_master() const override
Flag set on the main output track.
Definition track.cc:235
DeviceP access_device() override
Retrieve Device handle for this track.
Definition track.cc:321
DeviceInfo device_info() override
Describe this Device type.
Definition track.cc:354
TelemetryFieldS telemetry() const override
Create signal monitor for an output channel.
Definition track.cc:333
bool is_solo() const override
Check if track is soloed.
Definition track.cc:220
int32 midi_channel() const override
Midi channel assigned to this track, 0 uses internal per-track channel.
Definition track.hh:46
void set_solo(bool solo) override
Set track solo state.
Definition track.cc:228
One entry in a Writ serialization document.
Definition serialize.hh:24
bool isValid() const noexcept
void addListener(Listener *listener)
void removeListener(Listener *listener)
#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 CLAMP(v, mi, ma)
Yield v clamped to [mi … ma].
Definition internal.hh:60
T left(T... args)
The Anklang C++ API namespace.
Definition api.hh:9
std::string string_format(const char *format, const Args &...args) __attribute__((__format__(__printf__
Format a string similar to sprintf(3) with support for std::string and std::ostringstream convertible...
int32_t int32
A 32-bit signed integer.
Definition cxxaux.hh:28
std::string String
Convenience alias for std::string.
Definition cxxaux.hh:35
RangeType< TimePosition > TimeRange
Reference for an allocated memory block.
Definition memory.hh:90
typedef ssize_t