Anklang 0.3.0-460-gc4ef46ba
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 "track.hh"
3#include "combo.hh"
4#include "project.hh"
5#include "nativedevice.hh"
6#include "clip.hh"
7#include "midilib.hh"
8#include "server.hh"
9#include "main.hh"
10#include "serialize.hh"
11#include "jsonipc/jsonipc.hh"
12#include "internal.hh"
13
14namespace Ase {
15
16// == TrackImpl ==
17TrackImpl::TrackImpl (ProjectImpl &project, bool masterflag)
18{
19 gadget_flags (masterflag ? MASTER_TRACK : 0);
20}
21
22TrackImpl::~TrackImpl()
23{
24 assert_return (_parent() == nullptr);
25}
26
27ProjectImpl*
28TrackImpl::project () const
29{
30 return static_cast<ProjectImpl*> (_parent());
31}
32
34TrackImpl::fallback_name () const
35{
36 if (is_master())
37 return "Master";
38 if (auto project_ = project())
39 {
40 ssize_t i = project_->track_index (*this);
41 return string_format ("Track %u", i >= 0 ? i + 1 : i);
42 }
43 return DeviceImpl::fallback_name();
44}
45
46void
48{
50 // save clips
51 if (xs.in_save())
52 for (auto &bclip : clips_)
53 {
54 ClipImplP clip = shared_ptr_cast<ClipImpl> (bclip);
55 if (!clip->needs_serialize())
56 continue;
57 WritNode xc = xs["clips"].push();
58 xc & *clip;
59 const int64 index = clip_index (*clip);
60 xc.front ("clip-index") << index;
61 }
62 // load clips
63 if (xs.in_load())
64 {
65 ClipS clips = launcher_clips(); // forces creation
66 for (auto &xc : xs["clips"].to_nodes())
67 {
68 int64 index = xc["clip-index"].as_int();
69 if (index < 0 || size_t (index) >= clips.size())
70 continue;
71 ClipImplP clip = shared_ptr_cast<ClipImpl> (clips[index]);
72 xc & *clip;
73 }
74 emit_notify ("launcher_clips");
75 }
76 // device chain
77 xs["chain"] & *dynamic_cast<Serializable*> (&*chain_); // always exists
78}
79
80void
82{
83 auto project = dynamic_cast<ProjectImpl*> (parent);
84 assert_return (!!parent == !!project);
86 if (project)
87 {
88 AudioEngine *engine = App.engine;
89 assert_return (!midi_prod_);
90 midi_prod_ = create_processor_device (*engine, "Ase::MidiLib::MidiProducerImpl", true);
91 assert_return (midi_prod_);
92 midi_prod_->_set_parent (this);
93 AudioProcessorP esource = midi_prod_->_audio_processor()->engine().get_event_source();
94 midi_prod_->_set_event_source (esource);
95 midi_prod_->_audio_processor()->connect_event_input (*esource);
96 assert_return (!chain_);
97 chain_ = create_processor_device (*engine, "Ase::AudioChain", true);
98 assert_return (chain_);
99 chain_->_set_parent (this);
100 chain_->_set_event_source (midi_prod_->_audio_processor());
101 }
102 else if (chain_)
103 {
104 midi_prod_->_disconnect_remove();
105 chain_->_disconnect_remove();
106 chain_->_set_parent (nullptr);
107 chain_ = nullptr;
108 midi_prod_->_set_parent (nullptr);
109 midi_prod_ = nullptr;
110 }
111 emit_notify ("project");
112}
113
114void
116{
119 midi_prod_->_activate();
120 chain_->_activate();
121}
122
123void
125{
127 chain_->_deactivate();
128 midi_prod_->_deactivate();
130}
131
132void
133TrackImpl::queue_cmd (CallbackS &queue, Cmd cmd, double arg)
134{
135 assert_return (midi_prod_);
137 auto func = [midi_iface, cmd, arg] () {
138 if (cmd == START)
139 midi_iface->start();
140 else if (cmd == STOP)
141 midi_iface->stop (arg);
142 };
143 queue.push_back (func);
144}
145
146void
147TrackImpl::queue_cmd (DCallbackS &queue, Cmd cmd)
148{
149 assert_return (midi_prod_);
150 MidiLib::MidiProducerIfaceP midi_iface = std::dynamic_pointer_cast<MidiLib::MidiProducerIface> (midi_prod_->_audio_processor());
151 auto func = [midi_iface, cmd] (const double arg) {
152 if (cmd == START)
153 midi_iface->start();
154 else if (cmd == STOP)
155 midi_iface->stop (arg);
156 };
157 queue.push_back (func);
158}
159
160void
161TrackImpl::midi_channel (int32 midichannel) // TODO: implement
162{
163 midichannel = CLAMP (midichannel, 0, 16);
164 return_unless (midichannel != midi_channel_);
165 midi_channel_ = midichannel;
166 emit_notify ("midi_channel");
167}
168
169static constexpr const uint MAX_LAUNCHER_CLIPS = 8;
170
171ClipS
173{
174 const uint max_clips = MAX_LAUNCHER_CLIPS;
175 if (clips_.size() < max_clips)
176 {
177 clips_.reserve (max_clips);
178 while (clips_.size() < max_clips)
179 clips_.push_back (ClipImpl::make_shared (*this));
180 update_clips();
181 }
182 return Aux::container_copy<ClipS> (clips_);
183}
184
186TrackImpl::clip_index (const ClipImpl &clip) const
187{
188 for (size_t i = 0; i < clips_.size(); i++)
189 if (clips_[i].get() == &clip)
190 return i;
191 return -1;
192}
193
194int
195TrackImpl::clip_succession (const ClipImpl &clip) const
196{
197 ssize_t index = clip_index (clip);
198 return_unless (index >= 0, NONE);
199 // advance clip
200 index += 1;
201 if (index >= clips_.size())
202 index = 0;
203 return clips_[index] ? index : NONE;
204}
205
206void
207TrackImpl::update_clips ()
208{
209 return_unless (midi_prod_);
210 MidiLib::MidiProducerIfaceP midi_iface = std::dynamic_pointer_cast<MidiLib::MidiProducerIface> (midi_prod_->_audio_processor());
211 MidiLib::MidiFeedP feedp = std::make_shared<MidiLib::MidiFeed>();
212 MidiLib::MidiFeed &feed = *feedp;
213 feed.generators.resize (clips_.size());
214 for (size_t i = 0; i < clips_.size(); i++)
215 feed.generators[i].setup (*clips_[i]);
216 std::vector<int> scout_indices (clips_.size());
217 for (size_t i = 0; i < clips_.size(); i++)
218 scout_indices[i] = clips_[i] ? clip_succession (*clips_[i]) : NONE;
219 feed.scout.setup (scout_indices);
220 auto job = [midi_iface, feedp] () mutable {
221 midi_iface->update_feed (feedp);
222 // swap MidiFeedP copy to defer dtor to user thread
223 };
224 midi_iface->engine().async_jobs += job;
225}
226
227DeviceP
229{
230 return chain_;
231}
232
233MonitorP
234TrackImpl::create_monitor (int32 ochannel) // TODO: implement
235{
236 return nullptr;
237}
238
239TelemetryFieldS
241{
243 Ase::AudioChain *audio_chain = dynamic_cast<Ase::AudioChain*> (&*chain_->_audio_processor());
244 AudioChain::ProbeArray *probes = audio_chain->run_probes (true);
245 TelemetryFieldS v;
246 assert_return (midi_prod, v);
247 const MidiLib::MidiProducerIface::Position *const position = midi_prod->position();
248 v.push_back (telemetry_field ("current_clip", &position->current));
249 v.push_back (telemetry_field ("current_tick", &position->tick));
250 v.push_back (telemetry_field ("next_clip", &position->next));
251 v.push_back (telemetry_field ("dbspl0", &(*probes)[0].dbspl));
252 v.push_back (telemetry_field ("dbspl1", &(*probes)[1].dbspl));
253 return v;
254}
255
258{
259 return {}; // TODO: DeviceInfo
260}
261
262AudioProcessorP
264{
265 return {}; // TODO: AudioProcessorP
266}
267
268void
269TrackImpl::_set_event_source (AudioProcessorP esource)
270{
271 // TODO: _set_event_source
272}
273
274// == TrackImpl::ClipScout ==
275TrackImpl::ClipScout::ClipScout() noexcept
276{
277 // PRNG initialization goes here
278}
279
281void
283{
284 indices_ = indices;
285}
286
288int
290{
291 if (previous >= 0 && previous < indices_.size())
292 {
293 last_ = previous;
294 return indices_[last_];
295 }
296 return NONE;
297}
298
300void
302{
303 last_ = -1;
304}
305
307void
309{
310 indices_ = other.indices_;
311}
312
313} // Ase
bool is_active() override
Check whether this is the active synthesis engine project.
Definition device.hh:21
void _deactivate() override
Stop processing the corresponding AudioProcessor.
Definition device.cc:28
void _activate() override
Add AudioProcessor to the Engine and start processing.
Definition device.cc:21
void _set_parent(GadgetImpl *parent) override
Assign parent container.
Definition device.cc:14
void emit_notify(const String &detail) override
Emit notify:detail, multiple notifications maybe coalesced if a CoalesceNotifies instance exists.
Definition object.cc:164
Base type for classes that have a Property.
Definition gadget.hh:12
GadgetImpl * _parent() const override
Retrieve parent container.
Definition gadget.hh:30
Interface for serializable objects with Reflink support.
Definition defs.hh:97
virtual void serialize(WritNode &xs)=0
Serialize members and childern.
Definition serialize.cc:379
MIDI clip playback succession generator.
Definition track.hh:47
int advance(int previous)
Determine clip succession.
Definition track.cc:289
void reset()
Reset state (history), preserves succession order.
Definition track.cc:301
void setup(const std::vector< int > &indices)
Setup clip succession order.
Definition track.cc:282
void update(const ClipScout &other)
Assign new succession order, preserves history.
Definition track.cc:308
ClipS launcher_clips() override
Retrieve the list of clips that can be directly played.
Definition track.cc:172
void _activate() override
Add AudioProcessor to the Engine and start processing.
Definition track.cc:115
void serialize(WritNode &xs) override
Serialize members and childern.
Definition track.cc:47
void _deactivate() override
Stop processing the corresponding AudioProcessor.
Definition track.cc:124
void _set_parent(GadgetImpl *parent) override
Assign parent container.
Definition track.cc:81
bool is_master() const override
Flag set on the main output track.
Definition track.hh:30
DeviceP access_device() override
Retrieve Device handle for this track.
Definition track.cc:228
DeviceInfo device_info() override
Describe this Device type.
Definition track.cc:257
TelemetryFieldS telemetry() const override
Create signal monitor for an output channel.
Definition track.cc:240
AudioProcessorP _audio_processor() const override
Retrieve the corresponding AudioProcessor.
Definition track.cc:263
int32 midi_channel() const override
Midi channel assigned to this track, 0 uses internal per-track channel.
Definition track.hh:31
One entry in a Writ serialization document.
Definition serialize.hh:24
WritNode push()
Append new WritNode for serializing arrays during in_save().
Definition serialize.cc:285
bool in_load() const
Return true during deserialization.
Definition serialize.hh:175
bool in_save() const
Return true during serialization.
Definition serialize.hh:181
WritNodeS to_nodes()
Create std::vector<WritNode> for serialized arrays during in_load().
Definition serialize.cc:270
#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:71
#define CLAMP(v, mi, ma)
Yield v clamped to [mi … ma].
Definition internal.hh:58
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
int64_t int64
A 64-bit unsigned integer, use PRI*64 in format strings.
Definition cxxaux.hh:29
std::string String
Convenience alias for std::string.
Definition cxxaux.hh:35
uint32_t uint
Provide 'uint' as convenience type.
Definition cxxaux.hh:18
Info for device types.
Definition api.hh:203
T push_back(T... args)
typedef ssize_t