Anklang-0.3.0.dev886+g785567a1 anklang-0.3.0.dev886+g785567a1
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
87 valueTreeChildAdded (juce::ValueTree &parent, juce::ValueTree &child) override
88 {
89 if (parent == track_state_ && te::Clip::isClipState (child))
90 asetrack_.emit_notify ("launcher_clips");
91 }
92 void
93 valueTreeChildRemoved (juce::ValueTree &parent, juce::ValueTree &child, int) override
94 {
95 if (parent == track_state_ && te::Clip::isClipState (child))
96 asetrack_.emit_notify ("launcher_clips");
97 }
98 void valueTreeParentChanged (juce::ValueTree&) override {}
99 void valueTreeChildOrderChanged (juce::ValueTree&, int, int) override {}
100};
101
102// == TrackImpl ==
103static std::string
104trkn_track_type (tracktion::Track &track)
105{
106 if (dynamic_cast<te::FolderTrack*> (&track))
107 return "Folder";
108 if (dynamic_cast<te::AudioTrack*> (&track))
109 return "Audio/Midi";
110 if (track.isTempoTrack())
111 return "Tempo";
112 if (track.isMarkerTrack())
113 return "Marker";
114 if (track.isChordTrack())
115 return "Chord";
116 if (track.isArrangerTrack())
117 return "Arranger";
118 if (track.isMasterTrack())
119 return "Master";
120 return "Unknown";
121}
122
123TrackImplP
124TrackImpl::from_trkn (tracktion::Track &t)
125{
126 TrackImpl *track = find_ase_obj<TrackImpl> (t);
127 if (track)
128 return shared_ptr_cast<TrackImpl> (track);
129 TrackImplP trackp = TrackImpl::make_shared (t);
130 return trackp;
131}
132
133TrackImpl::TrackImpl (tracktion::Track &track) :
134 project_ (find_ase_obj<ProjectImpl> (track.edit)),
135 track_ (&track), te_type_ (trkn_track_type (track))
136{
137 register_ase_obj (this, track);
138 state_listener_ = std::make_unique<TrackStateListener> (*this);
139 update_telemetry();
140}
141
142TrackImpl::TrackImpl (ProjectImpl &project, bool masterflag) :
143 project_ (&project)
144{
145 gadget_flags (masterflag ? MASTER_TRACK : 0);
146}
147
148TrackImpl::~TrackImpl()
149{
150 unregister_ase_obj (this, track_.get());
151 state_listener_ = nullptr;
152 assert_return (_parent() == nullptr);
153}
154
155String
156TrackImpl::name() const
157{
158 if (auto trackp = track_.get())
159 return trackp->getName().toStdString();
160 return "";
161}
162
163void
164TrackImpl::name (const std::string &n)
165{
166 if (auto trackp = track_.get())
167 trackp->setName (juce::String (n));
168}
169
170ProjectImpl*
171TrackImpl::project () const
172{
173 return project_;
174}
175
176String
177TrackImpl::fallback_name() const
178{
179 if (is_master())
180 return "Master";
181 if (auto project_ = project()) {
182 ssize_t i = project_->track_index (*this);
183 return string_format ("Track %u", i >= 0 ? i + 1 : i);
184 }
185 return DeviceImpl::fallback_name();
186}
187
188void
192
193void
199
200void
206
207void
208TrackImpl::midi_channel (int32 midichannel)
209{
210 midichannel = CLAMP (midichannel, 0, 16);
211 return_unless (midichannel != midi_channel_);
212 midi_channel_ = midichannel;
213 emit_notify ("midi_channel");
214}
215
216bool
218{
219 if (auto t = track_.get())
220 return t->isMuted (false);
221 return false;
222}
223
224void
226{
227 if (auto t = track_.get())
228 t->setMute (muted);
229}
230
231bool
233{
234 if (auto t = track_.get())
235 return t->isSolo (false);
236 return false;
237}
238
239void
241{
242 if (auto t = track_.get())
243 t->setSolo (solo);
244}
245
246bool
248{
249 if (auto t = track_.get())
250 return t->isMasterTrack();
251 return false;
252}
253
254double
256{
257 if (auto t = track_.get())
258 if (auto at = dynamic_cast<te::AudioTrack*> (t))
259 if (auto vol = at->getVolumePlugin())
260 return vol->getVolumeDb();
261 return 0.0;
262}
263
264void
266{
267 if (auto t = track_.get())
268 if (auto at = dynamic_cast<te::AudioTrack*> (t))
269 if (auto vol = at->getVolumePlugin())
270 vol->setVolumeDb (db);
271}
272
273double
275{
276 if (auto t = track_.get())
277 if (auto at = dynamic_cast<te::AudioTrack*> (t))
278 if (auto vol = at->getVolumePlugin())
279 return vol->getPan();
280 return 0.0;
281}
282
283void
285{
286 if (auto t = track_.get())
287 if (auto at = dynamic_cast<te::AudioTrack*> (t))
288 if (auto vol = at->getVolumePlugin())
289 vol->setPan (pan);
290}
291
292ClipS
294{
295 ClipS clips;
296 if (auto t = track_.get())
297 if (auto ct = dynamic_cast<te::ClipTrack*> (t))
298 for (auto *clip : ct->getClips())
299 if (dynamic_cast<te::MidiClip*> (clip))
300 if (auto clipimpl = ClipImpl::from_trkn (*clip))
301 clips.push_back (clipimpl);
302 return clips;
303}
304
306TrackImpl::clip_index (const ClipImpl &clip) const
307{
308 if (auto t = track_.get())
309 if (auto ct = dynamic_cast<te::ClipTrack *> (t)) {
310 auto &clips = ct->getClips();
311 for (int i = 0; i < clips.size(); i++)
312 if (clips[i] == clip.clip_.get())
313 return i;
314 }
315 return -1;
316}
317
318int
319TrackImpl::clip_succession (const ClipImpl &clip) const
320{
321 ssize_t idx = clip_index (clip);
322 if (idx < 0)
323 return NONE;
324 if (auto t = track_.get())
325 if (auto ct = dynamic_cast<te::ClipTrack *> (t)) {
326 auto &clips = ct->getClips();
327 if (idx + 1 < clips.size())
328 return idx + 1;
329 }
330 return NONE;
331}
332
333DeviceP
335{
336 return nullptr;
337}
338
339MonitorP
340TrackImpl::create_monitor (int32 ochannel)
341{
342 return nullptr;
343}
344
345TelemetryFieldS
347{
348 TelemetryFieldS v;
349 return_unless (state_listener_, v);
350 auto &t = state_listener_->telemetry;
351 v.push_back (telemetry_field ("dbspl0", &t.dbspl0));
352 v.push_back (telemetry_field ("dbspl1", &t.dbspl1));
353 return v;
354}
355
356void
357TrackImpl::update_telemetry()
358{
359 return_unless (state_listener_);
360 auto &t = state_listener_->telemetry;
361 auto [left, right] = state_listener_->get_levels();
362 t.dbspl0 = left;
363 t.dbspl1 = right;
364}
365
366DeviceInfo
368{
369 return {};
370}
371
372void
374{
376 auto *track = track_.get();
377 if (track) {
378 // Remove from edit's track list
379 track_->edit.deleteTrack (track);
380 // Clear references
382 state_listener_ = nullptr;
383 }
385}
386
387// == TrackImpl::ClipScout ==
388TrackImpl::ClipScout::ClipScout() noexcept
389{
390 // PRNG initialization goes here
391}
392
394void
396{
397 indices_ = indices;
398}
399
401int
403{
404 if (previous >= 0 && previous < indices_.size()) {
405 last_ = previous;
406 return indices_[last_];
407 }
408 return NONE;
409}
410
412void
414{
415 last_ = -1;
416}
417
419void
421{
422 indices_ = other.indices_;
423}
424
425ClipP
426TrackImpl::create_midi_clip (const String &name, double start, double length)
427{
428 if (auto t = track_.get()) {
429 if (auto at = dynamic_cast<tracktion::AudioTrack *> (t)) {
430 const tracktion::TimeRange range (tracktion::TimePosition::fromSeconds (start), tracktion::TimeDuration::fromSeconds (length));
431 auto clip = at->insertMIDIClip (juce::String (name), range, nullptr);
432 if (clip)
433 return ClipImpl::from_trkn (*clip);
434 else
435 warning ("insertMIDIClip returned null");
436 }
437 else
438 warning ("dynamic_cast<AudioTrack*> failed for track type: %s", trkn_track_type (*t).c_str());
439 }
440 else
441 warning ("track_.get() returned null");
442 return nullptr;
443}
444
445ClipP
446TrackImpl::create_audio_clip (const String &name, double start, double length)
447{
448 if (auto t = track_.get()) {
449 if (auto ct = dynamic_cast<tracktion::ClipTrack *> (t)) {
450 const tracktion::TimeRange range (tracktion::TimePosition::fromSeconds (start), tracktion::TimeDuration::fromSeconds (length));
451 auto clip = ct->insertNewClip (tracktion::TrackItem::Type::wave, juce::String (name), range, nullptr);
452 if (clip)
453 return ClipImpl::from_trkn (*clip);
454 else
455 warning ("insertNewClip returned null");
456 }
457 else
458 warning ("dynamic_cast<ClipTrack*> failed for track type: %s", trkn_track_type (*t).c_str());
459 }
460 else
461 warning ("track_.get() returned null");
462 return nullptr;
463}
464
465} // Ase
T c_str(T... args)
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
void remove_self() override
Remove self from parent container.
Definition gadget.cc:167
Mimick tracktion::engine::SafeSelectable<> for tracktion::Selectable descendants.
Definition trkn-utils.hh:27
MIDI clip playback succession generator.
Definition track.hh:62
int advance(int previous)
Determine clip succession.
Definition track.cc:402
void reset()
Reset state (history), preserves succession order.
Definition track.cc:413
void setup(const std::vector< int > &indices)
Setup clip succession order.
Definition track.cc:395
void update(const ClipScout &other)
Assign new succession order, preserves history.
Definition track.cc:420
Ase::Track implementation.
Definition track.hh:11
double volume() const override
Get track volume in dB.
Definition track.cc:255
double pan() const override
Get track pan (-1.0 to 1.0).
Definition track.cc:274
ClipS launcher_clips() override
Retrieve the list of clips that can be directly played.
Definition track.cc:293
bool is_muted() const override
Check if track is muted.
Definition track.cc:217
void _activate() override
Add AudioProcessor to the Engine and start processing.
Definition track.cc:194
void serialize(WritNode &xs) override
Serialize members and childern.
Definition track.cc:189
void set_muted(bool muted) override
Set track muted state.
Definition track.cc:225
void _deactivate() override
Stop processing the corresponding AudioProcessor.
Definition track.cc:201
ClipP create_audio_clip(const String &name, double start, double length) override
Create a new audio clip on this track.
Definition track.cc:446
bool is_master() const override
Flag set on the main output track.
Definition track.cc:247
DeviceP access_device() override
Retrieve Device handle for this track.
Definition track.cc:334
DeviceInfo device_info() override
Describe this Device type.
Definition track.cc:367
TelemetryFieldS telemetry() const override
Create signal monitor for an output channel.
Definition track.cc:346
ClipP create_midi_clip(const String &name, double start, double length) override
Create a new MIDI clip on this track.
Definition track.cc:426
bool is_solo() const override
Check if track is soloed.
Definition track.cc:232
int32 midi_channel() const override
Midi channel assigned to this track, 0 uses internal per-track channel.
Definition track.hh:47
void set_solo(bool solo) override
Set track solo state.
Definition track.cc:240
void remove_self() override
Remove self from parent container.
Definition track.cc:373
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:8
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
void register_ase_obj(VirtualBase *ase_impl, tracktion::Selectable &selectable)
Helper: register AseImpl with a tracktion Selectable via ase_obj_.
Definition trkn-utils.cc:62
AseType * find_ase_obj(tracktion::Selectable &selectable)
Helper: lookup AseType from tracktion Selectable via ase_obj_.
Definition trkn-utils.hh:53
std::string String
Convenience alias for std::string.
Definition cxxaux.hh:35
void unregister_ase_obj(VirtualBase *ase_impl, tracktion::Selectable *selectable)
Helper: unregister AseImpl from a tracktion Selectable (selectable may be nullptr)
Definition trkn-utils.cc:70
RangeType< TimePosition > TimeRange
Reference for an allocated memory block.
Definition memory.hh:90
typedef ssize_t