Anklang 0.3.0-460-gc4ef46ba
ASE — Anklang Sound Engine (C++)

« « « Anklang Documentation
Loading...
Searching...
No Matches
nativedevice.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 "nativedevice.hh"
3#include "clapdevice.hh"
4#include "combo.hh"
5#include "project.hh"
6#include "jsonipc/jsonipc.hh"
7#include "serialize.hh"
8#include "internal.hh"
9
10namespace Ase {
11
12// == NativeDeviceImpl ==
13NativeDeviceImpl::NativeDeviceImpl (const String &aseid, AudioProcessor::StaticInfo static_info, AudioProcessorP aproc) :
14 proc_ (aproc), combo_ (std::dynamic_pointer_cast<AudioCombo> (aproc)), info_ (extract_info (aseid, static_info))
15{
16 assert_return (aproc != nullptr);
17}
18
19void
20NativeDeviceImpl::serialize (WritNode &xs)
21{
22 DeviceImpl::serialize (xs);
23 // save subdevices
24 if (combo_ && xs.in_save())
25 for (DeviceP subdevicep : list_devices())
26 {
27 WritNode xc = xs["devices"].push();
28 xc & *dynamic_cast<Serializable*> (&*subdevicep);
29 String uri = subdevicep->device_info().uri;
30 xc.front ("Device.URI") & uri;
31 }
32 // load subdevices
33 if (combo_ && xs.in_load())
34 for (auto &xc : xs["devices"].to_nodes())
35 {
36 String uri = xc["Device.URI"].as_string();
37 if (uri.empty())
38 continue;
39 auto load_subdevice = [&xc] (DeviceP subdevicep) {
40 xc & *dynamic_cast<Serializable*> (&*subdevicep);
41 };
42 DeviceP subdevicep = insert_device (uri, nullptr, load_subdevice);
43 }
44}
45
46PropertyS
47NativeDeviceImpl::access_properties ()
48{
49 return proc_->access_properties();
50}
51
52void
53NativeDeviceImpl::_set_event_source (AudioProcessorP esource)
54{
55 if (esource)
56 assert_return (esource->has_event_output());
57 AudioComboP combo = combo_;
58 return_unless (combo);
59 auto j = [combo, esource] () {
60 combo->set_event_source (esource);
61 };
62 proc_->engine().async_jobs += j;
63}
64
65void
66NativeDeviceImpl::remove_all_devices()
67{
68 while (children_.size())
69 remove_device (*children_.back());
70}
71
72void
73NativeDeviceImpl::_set_parent (GadgetImpl *parent)
74{
75 assert_warn (!is_active());
76 DeviceImpl::_set_parent (parent);
77}
78
79void
80NativeDeviceImpl::_activate ()
81{
82 assert_return (!is_active());
83 DeviceImpl::_activate();
84 for (auto &child : children_)
85 child->_activate();
86}
87
88void
89NativeDeviceImpl::_deactivate ()
90{
91 assert_return (is_active());
92 for (auto childit = children_.rbegin(); childit != children_.rend(); ++childit)
93 (*childit)->_deactivate();
94 DeviceImpl::_deactivate();
95}
96
97template<typename E> std::pair<std::shared_ptr<E>,ssize_t>
98find_shared_by_ref (const std::vector<std::shared_ptr<E> > &v, const E &e)
99{
100 for (size_t i = 0; i < v.size(); i++)
101 if (&e == &*v[i])
102 return std::make_pair (v[i], i);
103 return std::make_pair (std::shared_ptr<E>{}, -1);
104}
105
106void
107NativeDeviceImpl::remove_device (Device &sub)
108{
109 NativeDeviceP selfp = shared_ptr_cast<NativeDevice> (this);
110 assert_return (selfp);
111 assert_return (sub._parent() == this);
112 auto [subp, nth] = find_shared_by_ref (children_, sub);
113 DeviceP childp = subp;
114 assert_return (childp && nth >= 0);
115 children_.erase (children_.begin() + nth);
116 AudioProcessorP sproc = childp->_audio_processor();
117 if (sproc && combo_)
118 {
119 auto deferred_unparent = [selfp, childp] (void*) {
120 childp->_set_parent (nullptr); // selfp must still be alive here
121 };
122 std::shared_ptr<void> atjobdtor = { nullptr, deferred_unparent };
123 AudioComboP combop = combo_;
124 auto j = [combop, sproc, atjobdtor] () {
125 combop->remove (*sproc);
126 };
127 proc_->engine().async_jobs += j;
128 // once job is processed, dtor runs in mainthread
129 }
130 devices.notify();
131}
132
133DeviceP
134NativeDeviceImpl::insert_device (const String &uri, Device *sibling, const DeviceFunc &loader)
135{
136 DeviceP devicep;
137 AudioProcessorP siblingp = sibling ? sibling->_audio_processor() : nullptr;
138 if (combo_)
139 {
140 devicep = create_processor_device (proc_->engine(), uri, false);
141 return_unless (devicep, nullptr);
142 const ssize_t cpos = Aux::index_of (children_, [sibling] (const DeviceP &d) { return sibling == d.get(); });
143 children_.insert (cpos < 0 ? children_.end() : children_.begin() + cpos, devicep);
144 devicep->_set_parent (this);
145 if (loader)
146 loader (devicep);
147 AudioProcessorP sproc = devicep->_audio_processor();
148 return_unless (sproc, nullptr);
149 if (is_active())
150 devicep->_activate();
151 AudioComboP combo = combo_;
152 auto j = [combo, sproc, siblingp, cpos] () {
153 const size_t pos = siblingp ? combo->find_pos (*siblingp) : ~size_t (0);
154 combo->insert (sproc, pos);
155 assert_return (size_t (cpos) == pos);
156 };
157 proc_->engine().async_jobs += j;
158 }
159 devices.notify();
160 return devicep;
161}
162
163DeviceP
164NativeDeviceImpl::append_device (const String &uri)
165{
166 return insert_device (uri, nullptr, nullptr);
167}
168
169DeviceP
170NativeDeviceImpl::insert_device (const String &uri, Device &sibling)
171{
172 return insert_device (uri, &sibling, nullptr);
173}
174
175void
176NativeDeviceImpl::_disconnect_remove ()
177{
178 AudioProcessorP proc = proc_;
179 AudioEngine *engine = &proc->engine();
180 auto j = [proc] () {
181 proc->enable_engine_output (false);
182 proc->disconnect_ibuses();
183 proc->disconnect_obuses();
184 proc->disconnect_event_input();
185 // TODO: possibly merge with _set_parent(nullptr)
186 };
187 engine->async_jobs += j;
188 remove_all_devices();
189}
190
191DeviceP
192NativeDeviceImpl::create_native_device (AudioEngine &engine, const String &aseid)
193{
194 auto make_device = [] (const String &aseid, AudioProcessor::StaticInfo static_info, AudioProcessorP aproc) -> NativeDeviceP {
195 return NativeDeviceImpl::make_shared (aseid, static_info, aproc);
196 };
197 DeviceP devicep = AudioProcessor::registry_create (aseid, engine, make_device);
198 return_unless (devicep && devicep->_audio_processor(), nullptr);
199 return devicep;
200}
201
202// == NativeDevice ==
203DeviceInfoS
204NativeDevice::list_device_types ()
205{
206 DeviceInfoS iseq;
207 AudioProcessor::registry_foreach ([&iseq] (const String &aseid, AudioProcessor::StaticInfo static_info) {
208 AudioProcessorInfo pinfo;
209 static_info (pinfo);
210 DeviceInfo info;
211 info.uri = aseid;
212 info.name = pinfo.label;
213 info.category = pinfo.category;
214 info.description = pinfo.description;
215 info.website_url = pinfo.website_url;
216 info.creator_name = pinfo.creator_name;
217 info.creator_url = pinfo.creator_url;
218 if (!info.name.empty() && !info.category.empty())
219 iseq.push_back (info);
220 });
221 for (const DeviceInfo &info : ClapDeviceImpl::list_clap_plugins())
222 iseq.push_back (info);
223 return iseq;
224}
225
226DeviceP
227create_processor_device (AudioEngine &engine, const String &uri, bool engineproducer)
228{
229 DeviceP devicep;
230 if (string_startswith (uri, "CLAP:"))
231 devicep = ClapDeviceImpl::create_clap_device (engine, uri);
232 else // assume string_startswith (uri, "Ase:")
233 {
234 struct NativeDeviceImpl2 : NativeDeviceImpl {
235 using NativeDeviceImpl::create_native_device;
236 };
237 devicep = NativeDeviceImpl2::create_native_device (engine, uri);
238 }
239 return_unless (devicep, nullptr);
240 AudioProcessorP procp = devicep->_audio_processor();
241 if (procp) {
242 auto j = [procp,engineproducer] () {
243 procp->enable_engine_output (engineproducer);
244 };
245 engine.async_jobs += j;
246 }
247 return devicep;
248}
249
250} // Ase
JobQueue async_jobs
Executed asynchronously, may modify AudioProcessor objects.
Definition engine.hh:65
Interface to access Device instances.
Definition api.hh:214
virtual AudioProcessorP _audio_processor() const =0
Retrieve the corresponding AudioProcessor.
Base type for classes that have a Property.
Definition gadget.hh:12
virtual GadgetImpl * _parent() const =0
Retrieve parent container.
Interface for serializable objects with Reflink support.
Definition defs.hh:97
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
T empty(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:71
#define assert_warn(expr)
Issue an assertion warning if expr evaluates to false.
Definition internal.hh:33
T make_pair(T... args)
The Anklang C++ API namespace.
Definition api.hh:9
CString website_url
Website of/about this AudioProcessor.
Definition processor.hh:35
String creator_name
Name of the creator.
Definition api.hh:209
String name
Preferred user interface name.
Definition api.hh:205
String creator_url
Internet contact of the creator.
Definition api.hh:210
String uri
Unique identifier for de-/serialization.
Definition api.hh:204
CString description
Elaborate description for help dialogs.
Definition processor.hh:34
CString creator_url
Internet contact of the creator.
Definition processor.hh:37
String description
Elaborate description for help dialogs.
Definition api.hh:207
CString creator_name
Name of the creator.
Definition processor.hh:36
CString label
Preferred user interface name.
Definition processor.hh:30
std::string String
Convenience alias for std::string.
Definition cxxaux.hh:35
String category
Category to allow grouping for processors of similar function.
Definition api.hh:206
CString category
Category to allow grouping for processors of similar function.
Definition processor.hh:32
String website_url
Website of/about this Processor.
Definition api.hh:208
Detailed information and common properties of AudioProcessor subclasses.
Definition processor.hh:29
Info for device types.
Definition api.hh:203
T dynamic_pointer_cast(T... args)
typedef ssize_t