Merge branch 'mingw-updates' of https://github.com/mojofunk/ardour into cairocanvas
[ardour.git] / libs / backends / dummy / dummy_audiobackend.cc
1 /*
2  * Copyright (C) 2014 Robin Gareus <robin@gareus.org>
3  * Copyright (C) 2013 Paul Davis
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18  */
19
20 #include <sys/time.h>
21 #include <regex.h>
22
23 #include <glibmm.h>
24
25 #include "dummy_audiobackend.h"
26 #include "pbd/error.h"
27 #include "i18n.h"
28
29 using namespace ARDOUR;
30
31 static std::string s_instance_name;
32 size_t DummyAudioBackend::_max_buffer_size = 8192;
33
34 DummyAudioBackend::DummyAudioBackend (AudioEngine& e, AudioBackendInfo& info)
35         : AudioBackend (e, info)
36         , _running (false)
37         , _freewheeling (false)
38         , _samplerate (48000)
39         , _samples_per_period (1024)
40         , _dsp_load (0)
41         , _n_inputs (0)
42         , _n_outputs (0)
43         , _n_midi_inputs (0)
44         , _n_midi_outputs (0)
45         , _systemic_input_latency (0)
46         , _systemic_output_latency (0)
47         , _processed_samples (0)
48 {
49         _instance_name = s_instance_name;
50 }
51
52 DummyAudioBackend::~DummyAudioBackend ()
53 {
54 }
55
56 /* AUDIOBACKEND API */
57
58 std::string
59 DummyAudioBackend::name () const
60 {
61         return X_("Dummy");
62 }
63
64 bool
65 DummyAudioBackend::is_realtime () const
66 {
67         return false;
68 }
69
70 std::vector<AudioBackend::DeviceStatus>
71 DummyAudioBackend::enumerate_devices () const
72 {
73         std::vector<AudioBackend::DeviceStatus> s;
74         s.push_back (DeviceStatus (_("Dummy"), true));
75         return s;
76 }
77
78 std::vector<float>
79 DummyAudioBackend::available_sample_rates (const std::string&) const
80 {
81         std::vector<float> sr;
82         sr.push_back (8000.0);
83         sr.push_back (22050.0);
84         sr.push_back (24000.0);
85         sr.push_back (44100.0);
86         sr.push_back (48000.0);
87         sr.push_back (88200.0);
88         sr.push_back (96000.0);
89         sr.push_back (176400.0);
90         sr.push_back (192000.0);
91         return sr;
92 }
93
94 std::vector<uint32_t>
95 DummyAudioBackend::available_buffer_sizes (const std::string&) const
96 {
97         std::vector<uint32_t> bs;
98         bs.push_back (4);
99         bs.push_back (8);
100         bs.push_back (16);
101         bs.push_back (32);
102         bs.push_back (64);
103         bs.push_back (128);
104         bs.push_back (256);
105         bs.push_back (512);
106         bs.push_back (1024);
107         bs.push_back (2048);
108         bs.push_back (4096);
109         bs.push_back (8192);
110         return bs;
111 }
112
113 uint32_t
114 DummyAudioBackend::available_input_channel_count (const std::string&) const
115 {
116         return 128;
117 }
118
119 uint32_t
120 DummyAudioBackend::available_output_channel_count (const std::string&) const
121 {
122         return 128;
123 }
124
125 bool
126 DummyAudioBackend::can_change_sample_rate_when_running () const
127 {
128         return true;
129 }
130
131 bool
132 DummyAudioBackend::can_change_buffer_size_when_running () const
133 {
134         return true;
135 }
136
137 int
138 DummyAudioBackend::set_device_name (const std::string&)
139 {
140         return 0;
141 }
142
143 int
144 DummyAudioBackend::set_sample_rate (float sr)
145 {
146         if (sr <= 0) { return -1; }
147         _samplerate = sr;
148         engine.sample_rate_change (sr);
149         return 0;
150 }
151
152 int
153 DummyAudioBackend::set_buffer_size (uint32_t bs)
154 {
155         if (bs <= 0 || bs >= _max_buffer_size) {
156                 return -1;
157         }
158         _samples_per_period = bs;
159         engine.buffer_size_change (bs);
160         return 0;
161 }
162
163 int
164 DummyAudioBackend::set_interleaved (bool yn)
165 {
166         if (!yn) { return 0; }
167         return -1;
168 }
169
170 int
171 DummyAudioBackend::set_input_channels (uint32_t cc)
172 {
173         _n_inputs = cc;
174         return 0;
175 }
176
177 int
178 DummyAudioBackend::set_output_channels (uint32_t cc)
179 {
180         _n_outputs = cc;
181         return 0;
182 }
183
184 int
185 DummyAudioBackend::set_systemic_input_latency (uint32_t sl)
186 {
187         _systemic_input_latency = sl;
188         return 0;
189 }
190
191 int
192 DummyAudioBackend::set_systemic_output_latency (uint32_t sl)
193 {
194         _systemic_output_latency = sl;
195         return 0;
196 }
197
198 /* Retrieving parameters */
199 std::string
200 DummyAudioBackend::device_name () const
201 {
202         return _("Dummy Device");
203 }
204
205 float
206 DummyAudioBackend::sample_rate () const
207 {
208         return _samplerate;
209 }
210
211 uint32_t
212 DummyAudioBackend::buffer_size () const
213 {
214         return _samples_per_period;
215 }
216
217 bool
218 DummyAudioBackend::interleaved () const
219 {
220         return false;
221 }
222
223 uint32_t
224 DummyAudioBackend::input_channels () const
225 {
226         return _n_inputs;
227 }
228
229 uint32_t
230 DummyAudioBackend::output_channels () const
231 {
232         return _n_outputs;
233 }
234
235 uint32_t
236 DummyAudioBackend::systemic_input_latency () const
237 {
238         return _systemic_input_latency;
239 }
240
241 uint32_t
242 DummyAudioBackend::systemic_output_latency () const
243 {
244         return _systemic_output_latency;
245 }
246
247 /* MIDI */
248 std::vector<std::string>
249 DummyAudioBackend::enumerate_midi_options () const
250 {
251         std::vector<std::string> m;
252         m.push_back (_("1 in, 1 out"));
253         m.push_back (_("2 in, 2 out"));
254         m.push_back (_("8 in, 8 out"));
255         return m;
256 }
257
258 int
259 DummyAudioBackend::set_midi_option (const std::string& opt)
260 {
261         if (opt == _("1 in, 1 out")) {
262                 _n_midi_inputs = _n_midi_outputs = 1;
263         }
264         else if (opt == _("2 in, 2 out")) {
265                 _n_midi_inputs = _n_midi_outputs = 2;
266         }
267         else if (opt == _("8 in, 8 out")) {
268                 _n_midi_inputs = _n_midi_outputs = 8;
269         }
270         else {
271                 _n_midi_inputs = _n_midi_outputs = 0;
272         }
273         return -1;
274 }
275
276 std::string
277 DummyAudioBackend::midi_option () const
278 {
279         return "";
280 }
281
282 /* State Control */
283
284 static void * pthread_process (void *arg)
285 {
286         DummyAudioBackend *d = static_cast<DummyAudioBackend *>(arg);
287         d->main_process_thread ();
288         pthread_exit (0);
289         return 0;
290 }
291
292 int
293 DummyAudioBackend::_start (bool /*for_latency_measurement*/)
294 {
295         if (_running) {
296                 PBD::error << _("DummyAudioBackend: already active.") << endmsg;
297                 return -1;
298         }
299
300         if (_ports.size()) {
301                 PBD::warning << _("DummyAudioBackend: recovering from unclean shutdown, port registry is not empty.") << endmsg;
302                 _ports.clear();
303         }
304
305         if (register_system_ports()) {
306                 PBD::error << _("DummyAudioBackend: failed to register system ports.") << endmsg;
307                 return -1;
308         }
309
310         if (engine.reestablish_ports ()) {
311                 PBD::error << _("DummyAudioBackend: Could not re-establish ports.") << endmsg;
312                 stop ();
313                 return -1;
314         }
315
316         engine.reconnect_ports ();
317
318         if (pthread_create (&_main_thread, NULL, pthread_process, this)) {
319                 PBD::error << _("DummyAudioBackend: cannot start.") << endmsg;
320         }
321
322         int timeout = 5000;
323         while (!_running && --timeout > 0) { Glib::usleep (1000); }
324
325         if (timeout == 0 || !_running) {
326                 PBD::error << _("DummyAudioBackend: failed to start process thread.") << endmsg;
327                 return -1;
328         }
329
330         return 0;
331 }
332
333 int
334 DummyAudioBackend::stop ()
335 {
336         void *status;
337         if (!_running) {
338                 return -1;
339         }
340
341         _running = false;
342         if (pthread_join (_main_thread, &status)) {
343                 PBD::error << _("DummyAudioBackend: failed to terminate.") << endmsg;
344                 return -1;
345         }
346         unregister_system_ports();
347         return 0;
348 }
349
350 int
351 DummyAudioBackend::freewheel (bool onoff)
352 {
353         if (onoff == _freewheeling) {
354                 return 0;
355         }
356         _freewheeling = onoff;
357         engine.freewheel_callback (onoff);
358         return 0;
359 }
360
361 float
362 DummyAudioBackend::dsp_load () const
363 {
364         return 100.f * _dsp_load;
365 }
366
367 size_t
368 DummyAudioBackend::raw_buffer_size (DataType t)
369 {
370         switch (t) {
371                 case DataType::AUDIO:
372                         return _max_buffer_size * sizeof(Sample);
373                 case DataType::MIDI:
374                         return _max_buffer_size; // XXX not really limited
375         }
376         return 0;
377 }
378
379 /* Process time */
380 pframes_t
381 DummyAudioBackend::sample_time ()
382 {
383         return _processed_samples;
384 }
385
386 pframes_t
387 DummyAudioBackend::sample_time_at_cycle_start ()
388 {
389         return _processed_samples;
390 }
391
392 pframes_t
393 DummyAudioBackend::samples_since_cycle_start ()
394 {
395         return 0;
396 }
397
398
399 void *
400 DummyAudioBackend::dummy_process_thread (void *arg)
401 {
402         ThreadData* td = reinterpret_cast<ThreadData*> (arg);
403         boost::function<void ()> f = td->f;
404         delete td;
405         f ();
406         return 0;
407 }
408
409 int
410 DummyAudioBackend::create_process_thread (boost::function<void()> func)
411 {
412         pthread_t thread_id;
413         pthread_attr_t attr;
414         size_t stacksize = 100000;
415
416         pthread_attr_init (&attr);
417         pthread_attr_setstacksize (&attr, stacksize);
418         ThreadData* td = new ThreadData (this, func, stacksize);
419
420         if (pthread_create (&thread_id, &attr, dummy_process_thread, td)) {
421                 PBD::error << _("AudioEngine: cannot create process thread.") << endmsg;
422                 return -1;
423         }
424
425         _threads.push_back (thread_id);
426         return 0;
427 }
428
429 int
430 DummyAudioBackend::join_process_threads ()
431 {
432         int rv = 0;
433
434         for (std::vector<pthread_t>::const_iterator i = _threads.begin (); i != _threads.end (); ++i)
435         {
436                 void *status;
437                 if (pthread_join (*i, &status)) {
438                         PBD::error << _("AudioEngine: cannot terminate process thread.") << endmsg;
439                         rv -= 1;
440                 }
441         }
442         _threads.clear ();
443         return rv;
444 }
445
446 bool
447 DummyAudioBackend::in_process_thread ()
448 {
449         for (std::vector<pthread_t>::const_iterator i = _threads.begin (); i != _threads.end (); ++i)
450         {
451                 if (pthread_equal (*i, pthread_self ()) != 0) {
452                         return true;
453                 }
454         }
455         return false;
456 }
457
458 uint32_t
459 DummyAudioBackend::process_thread_count ()
460 {
461         return _threads.size ();
462 }
463
464 void
465 DummyAudioBackend::update_latencies ()
466 {
467 }
468
469 /* PORTENGINE API */
470
471 void*
472 DummyAudioBackend::private_handle () const
473 {
474         return NULL;
475 }
476
477 const std::string&
478 DummyAudioBackend::my_name () const
479 {
480         return _instance_name;
481 }
482
483 bool
484 DummyAudioBackend::available () const
485 {
486         return true;
487 }
488
489 uint32_t
490 DummyAudioBackend::port_name_size () const
491 {
492         return 256;
493 }
494
495 int
496 DummyAudioBackend::set_port_name (PortEngine::PortHandle port, const std::string& name)
497 {
498         if (!valid_port (port)) {
499                 PBD::error << _("DummyBackend::set_port_name: Invalid Port(s)") << endmsg;
500                 return -1;
501         }
502         return static_cast<DummyPort*>(port)->set_name (_instance_name + ":" + name);
503 }
504
505 std::string
506 DummyAudioBackend::get_port_name (PortEngine::PortHandle port) const
507 {
508         if (!valid_port (port)) {
509                 PBD::error << _("DummyBackend::get_port_name: Invalid Port(s)") << endmsg;
510                 return std::string ();
511         }
512         return static_cast<DummyPort*>(port)->name ();
513 }
514
515 PortEngine::PortHandle
516 DummyAudioBackend::get_port_by_name (const std::string& name) const
517 {
518         PortHandle port = (PortHandle) find_port (name);
519         return port;
520 }
521
522 int
523 DummyAudioBackend::get_ports (
524                 const std::string& port_name_pattern,
525                 DataType type, PortFlags flags,
526                 std::vector<std::string>& port_names) const
527 {
528         int rv = 0;
529         regex_t port_regex;
530         bool use_regexp = false;
531         if (port_name_pattern.size () > 0) {
532                 if (!regcomp (&port_regex, port_name_pattern.c_str (), REG_EXTENDED|REG_NOSUB)) {
533                         use_regexp = true;
534                 }
535         }
536         for (size_t i = 0; i < _ports.size (); ++i) {
537                 DummyPort* port = _ports[i];
538                 if ((port->type () == type) && (port->flags () & flags)) {
539                         if (!use_regexp || !regexec (&port_regex, port->name ().c_str (), 0, NULL, 0)) {
540                                 port_names.push_back (port->name ());
541                                 ++rv;
542                         }
543                 }
544         }
545         if (use_regexp) {
546                 regfree (&port_regex);
547         }
548         return rv;
549 }
550
551 DataType
552 DummyAudioBackend::port_data_type (PortEngine::PortHandle port) const
553 {
554         if (!valid_port (port)) {
555                 return DataType::NIL;
556         }
557         return static_cast<DummyPort*>(port)->type ();
558 }
559
560 PortEngine::PortHandle
561 DummyAudioBackend::register_port (
562                 const std::string& name,
563                 ARDOUR::DataType type,
564                 ARDOUR::PortFlags flags)
565 {
566         if (name.size () == 0) { return 0; }
567         if (flags & IsPhysical) { return 0; }
568         return add_port (_instance_name + ":" + name, type, flags);
569 }
570
571 PortEngine::PortHandle
572 DummyAudioBackend::add_port (
573                 const std::string& name,
574                 ARDOUR::DataType type,
575                 ARDOUR::PortFlags flags)
576 {
577         assert(name.size ());
578         if (find_port (name)) {
579                 PBD::error << _("DummyBackend::register_port: Port already exists:")
580                                 << " (" << name << ")" << endmsg;
581                 return 0;
582         }
583         DummyPort* port = NULL;
584         switch (type) {
585                 case DataType::AUDIO:
586                         port = new DummyAudioPort (name, flags);
587                         break;
588                 case DataType::MIDI:
589                         port = new DummyMidiPort (name, flags);
590                         break;
591                 default:
592                         PBD::error << _("DummyBackend::register_port: Invalid Data Type.") << endmsg;
593                         return 0;
594         }
595
596         _ports.push_back (port);
597
598         return port;
599 }
600
601 void
602 DummyAudioBackend::unregister_port (PortEngine::PortHandle port_handle)
603 {
604         if (!valid_port (port_handle)) {
605                 PBD::error << _("DummyBackend::unregister_port: Invalid Port.") << endmsg;
606         }
607         DummyPort* port = static_cast<DummyPort*>(port_handle);
608         std::vector<DummyPort*>::iterator i = std::find (_ports.begin (), _ports.end (), static_cast<DummyPort*>(port_handle));
609         if (i == _ports.end ()) {
610                 PBD::error << _("DummyBackend::unregister_port: Failed to find port") << endmsg;
611                 return;
612         }
613         disconnect_all(port_handle);
614         _ports.erase (i);
615         delete port;
616 }
617
618 int
619 DummyAudioBackend::register_system_ports()
620 {
621         LatencyRange lr;
622
623         const int a_ins = _n_inputs > 0 ? _n_inputs : 8;
624         const int a_out = _n_outputs > 0 ? _n_outputs : 8;
625         const int m_ins = _n_midi_inputs > 0 ? _n_midi_inputs : 2;
626         const int m_out = _n_midi_outputs > 0 ? _n_midi_outputs : 2;
627
628         /* audio ports */
629         lr.min = lr.max = _samples_per_period + _systemic_input_latency;
630         for (int i = 1; i <= a_ins; ++i) {
631                 char tmp[64];
632                 snprintf(tmp, sizeof(tmp), "system:capture_%d", i);
633                 PortHandle p = add_port(std::string(tmp), DataType::AUDIO, static_cast<PortFlags>(IsOutput | IsPhysical | IsTerminal));
634                 if (!p) return -1;
635                 set_latency_range (p, false, lr);
636         }
637
638         lr.min = lr.max = _samples_per_period + _systemic_output_latency;
639         for (int i = 1; i <= a_out; ++i) {
640                 char tmp[64];
641                 snprintf(tmp, sizeof(tmp), "system:playback_%d", i);
642                 PortHandle p = add_port(std::string(tmp), DataType::AUDIO, static_cast<PortFlags>(IsInput | IsPhysical | IsTerminal));
643                 if (!p) return -1;
644                 set_latency_range (p, false, lr);
645         }
646
647         /* midi ports */
648         lr.min = lr.max = _samples_per_period + _systemic_input_latency;
649         for (int i = 1; i <= m_ins; ++i) {
650                 char tmp[64];
651                 snprintf(tmp, sizeof(tmp), "system:midi_capture_%d", i);
652                 PortHandle p = add_port(std::string(tmp), DataType::MIDI, static_cast<PortFlags>(IsOutput | IsPhysical | IsTerminal));
653                 if (!p) return -1;
654                 set_latency_range (p, false, lr);
655         }
656
657         lr.min = lr.max = _samples_per_period + _systemic_output_latency;
658         for (int i = 1; i <= m_out; ++i) {
659                 char tmp[64];
660                 snprintf(tmp, sizeof(tmp), "system:midi_playback_%d", i);
661                 PortHandle p = add_port(std::string(tmp), DataType::MIDI, static_cast<PortFlags>(IsInput | IsPhysical | IsTerminal));
662                 if (!p) return -1;
663                 set_latency_range (p, false, lr);
664         }
665
666         return 0;
667 }
668
669 void
670 DummyAudioBackend::unregister_system_ports()
671 {
672         size_t i = 0;
673         while (i <  _ports.size ()) {
674                 DummyPort* port = _ports[i];
675                 if (port->is_physical () && port->is_terminal ()) {
676                         port->disconnect_all ();
677                         _ports.erase (_ports.begin() + i);
678                 } else {
679                         ++i;
680                 }
681         }
682 }
683
684 int
685 DummyAudioBackend::connect (const std::string& src, const std::string& dst)
686 {
687         DummyPort* src_port = find_port (src);
688         DummyPort* dst_port = find_port (dst);
689
690         if (!src_port) {
691                 PBD::error << _("DummyBackend::connect: Invalid Source port:")
692                                 << " (" << src <<")" << endmsg;
693                 return -1;
694         }
695         if (!dst_port) {
696                 PBD::error << _("DummyBackend::connect: Invalid Destination port:")
697                         << " (" << dst <<")" << endmsg;
698                 return -1;
699         }
700         return src_port->connect (dst_port);
701 }
702
703 int
704 DummyAudioBackend::disconnect (const std::string& src, const std::string& dst)
705 {
706         DummyPort* src_port = find_port (src);
707         DummyPort* dst_port = find_port (dst);
708
709         if (!src_port || !dst_port) {
710                 PBD::error << _("DummyBackend::disconnect: Invalid Port(s)") << endmsg;
711                 return -1;
712         }
713         return src_port->disconnect (dst_port);
714 }
715
716 int
717 DummyAudioBackend::connect (PortEngine::PortHandle src, const std::string& dst)
718 {
719         DummyPort* dst_port = find_port (dst);
720         if (!valid_port (src)) {
721                 PBD::error << _("DummyBackend::connect: Invalid Source Port Handle") << endmsg;
722                 return -1;
723         }
724         if (!dst_port) {
725                 PBD::error << _("DummyBackend::connect: Invalid Destination Port")
726                         << " (" << dst << ")" << endmsg;
727                 return -1;
728         }
729         return static_cast<DummyPort*>(src)->connect (dst_port);
730 }
731
732 int
733 DummyAudioBackend::disconnect (PortEngine::PortHandle src, const std::string& dst)
734 {
735         DummyPort* dst_port = find_port (dst);
736         if (!valid_port (src) || !dst_port) {
737                 PBD::error << _("DummyBackend::disconnect: Invalid Port(s)") << endmsg;
738                 return -1;
739         }
740         return static_cast<DummyPort*>(src)->disconnect (dst_port);
741 }
742
743 int
744 DummyAudioBackend::disconnect_all (PortEngine::PortHandle port)
745 {
746         if (!valid_port (port)) {
747                 PBD::error << _("DummyBackend::disconnect_all: Invalid Port") << endmsg;
748                 return -1;
749         }
750         static_cast<DummyPort*>(port)->disconnect_all ();
751         return 0;
752 }
753
754 bool
755 DummyAudioBackend::connected (PortEngine::PortHandle port, bool /* process_callback_safe*/)
756 {
757         if (!valid_port (port)) {
758                 PBD::error << _("DummyBackend::disconnect_all: Invalid Port") << endmsg;
759                 return false;
760         }
761         return static_cast<DummyPort*>(port)->is_connected ();
762 }
763
764 bool
765 DummyAudioBackend::connected_to (PortEngine::PortHandle src, const std::string& dst, bool /*process_callback_safe*/)
766 {
767         DummyPort* dst_port = find_port (dst);
768         if (!valid_port (src) || !dst_port) {
769                 PBD::error << _("DummyBackend::connected_to: Invalid Port") << endmsg;
770                 return false;
771         }
772         return static_cast<DummyPort*>(src)->is_connected (dst_port);
773 }
774
775 bool
776 DummyAudioBackend::physically_connected (PortEngine::PortHandle port, bool /*process_callback_safe*/)
777 {
778         if (!valid_port (port)) {
779                 PBD::error << _("DummyBackend::physically_connected: Invalid Port") << endmsg;
780                 return false;
781         }
782         return static_cast<DummyPort*>(port)->is_physically_connected ();
783 }
784
785 int
786 DummyAudioBackend::get_connections (PortEngine::PortHandle port, std::vector<std::string>& names, bool /*process_callback_safe*/)
787 {
788         if (!valid_port (port)) {
789                 PBD::error << _("DummyBackend::get_connections: Invalid Port") << endmsg;
790                 return -1;
791         }
792
793         assert (0 == names.size ());
794
795         const std::vector<DummyPort*>& connected_ports = static_cast<DummyPort*>(port)->get_connections ();
796
797         for (std::vector<DummyPort*>::const_iterator i = connected_ports.begin (); i != connected_ports.end (); ++i) {
798                 names.push_back ((*i)->name ());
799         }
800
801         return (int)names.size ();
802 }
803
804 /* MIDI */
805 int
806 DummyAudioBackend::midi_event_get (
807                 pframes_t& timestamp,
808                 size_t& size, uint8_t** buf, void* port_buffer,
809                 uint32_t event_index)
810 {
811         assert (buf && port_buffer);
812         DummyMidiBuffer& source = * static_cast<DummyMidiBuffer*>(port_buffer);
813         if (event_index >= source.size ()) {
814                 return -1;
815         }
816         DummyMidiEvent * const event = source[event_index].get ();
817
818         timestamp = event->timestamp ();
819         size = event->size ();
820         *buf = event->data ();
821         return 0;
822 }
823
824 int
825 DummyAudioBackend::midi_event_put (
826                 void* port_buffer,
827                 pframes_t timestamp,
828                 const uint8_t* buffer, size_t size)
829 {
830         assert (buffer && port_buffer);
831         DummyMidiBuffer& dst = * static_cast<DummyMidiBuffer*>(port_buffer);
832         if (dst.size () && (pframes_t)dst.back ()->timestamp () > timestamp) {
833                 fprintf (stderr, "DummyMidiBuffer: it's too late for this event.\n");
834                 return -1;
835         }
836         dst.push_back (boost::shared_ptr<DummyMidiEvent>(new DummyMidiEvent (timestamp, buffer, size)));
837         return 0;
838 }
839
840 uint32_t
841 DummyAudioBackend::get_midi_event_count (void* port_buffer)
842 {
843         assert (port_buffer && _running);
844         return static_cast<DummyMidiBuffer*>(port_buffer)->size ();
845 }
846
847 void
848 DummyAudioBackend::midi_clear (void* port_buffer)
849 {
850         assert (port_buffer && _running);
851         DummyMidiBuffer * buf = static_cast<DummyMidiBuffer*>(port_buffer);
852         assert (buf);
853         buf->clear ();
854 }
855
856 /* Monitoring */
857
858 bool
859 DummyAudioBackend::can_monitor_input () const
860 {
861         return false;
862 }
863
864 int
865 DummyAudioBackend::request_input_monitoring (PortEngine::PortHandle, bool)
866 {
867         return -1;
868 }
869
870 int
871 DummyAudioBackend::ensure_input_monitoring (PortEngine::PortHandle, bool)
872 {
873         return -1;
874 }
875
876 bool
877 DummyAudioBackend::monitoring_input (PortEngine::PortHandle)
878 {
879         return false;
880 }
881
882 /* Latency management */
883
884 void
885 DummyAudioBackend::set_latency_range (PortEngine::PortHandle port, bool for_playback, LatencyRange latency_range)
886 {
887         if (!valid_port (port)) {
888                 PBD::error << _("DummyPort::set_latency_range (): invalid port.") << endmsg;
889         }
890         static_cast<DummyPort*>(port)->set_latency_range (latency_range, for_playback);
891 }
892
893 LatencyRange
894 DummyAudioBackend::get_latency_range (PortEngine::PortHandle port, bool for_playback)
895 {
896         if (!valid_port (port)) {
897                 PBD::error << _("DummyPort::get_latency_range (): invalid port.") << endmsg;
898                 LatencyRange r;
899                 r.min = 0;
900                 r.max = 0;
901                 return r;
902         }
903         return static_cast<DummyPort*>(port)->latency_range (for_playback);
904 }
905
906 /* Discovering physical ports */
907
908 bool
909 DummyAudioBackend::port_is_physical (PortEngine::PortHandle port) const
910 {
911         if (!valid_port (port)) {
912                 PBD::error << _("DummyPort::port_is_physical (): invalid port.") << endmsg;
913                 return false;
914         }
915         return static_cast<DummyPort*>(port)->is_physical ();
916 }
917
918 void
919 DummyAudioBackend::get_physical_outputs (DataType type, std::vector<std::string>& port_names)
920 {
921         for (size_t i = 0; i < _ports.size (); ++i) {
922                 DummyPort* port = _ports[i];
923                 if ((port->type () == type) && port->is_output () && port->is_physical ()) {
924                         port_names.push_back (port->name ());
925                 }
926         }
927 }
928
929 void
930 DummyAudioBackend::get_physical_inputs (DataType type, std::vector<std::string>& port_names)
931 {
932         for (size_t i = 0; i < _ports.size (); ++i) {
933                 DummyPort* port = _ports[i];
934                 if ((port->type () == type) && port->is_input () && port->is_physical ()) {
935                         port_names.push_back (port->name ());
936                 }
937         }
938 }
939
940 ChanCount
941 DummyAudioBackend::n_physical_outputs () const
942 {
943         int n_midi = 0;
944         int n_audio = 0;
945         for (size_t i = 0; i < _ports.size (); ++i) {
946                 DummyPort* port = _ports[i];
947                 if (port->is_output () && port->is_physical ()) {
948                         switch (port->type ()) {
949                                 case DataType::AUDIO: ++n_audio; break;
950                                 case DataType::MIDI: ++n_midi; break;
951                                 default: break;
952                         }
953                 }
954         }
955         ChanCount cc;
956         cc.set (DataType::AUDIO, n_audio);
957         cc.set (DataType::MIDI, n_midi);
958         return cc;
959 }
960
961 ChanCount
962 DummyAudioBackend::n_physical_inputs () const
963 {
964         int n_midi = 0;
965         int n_audio = 0;
966         for (size_t i = 0; i < _ports.size (); ++i) {
967                 DummyPort* port = _ports[i];
968                 if (port->is_input () && port->is_physical ()) {
969                         switch (port->type ()) {
970                                 case DataType::AUDIO: ++n_audio; break;
971                                 case DataType::MIDI: ++n_midi; break;
972                                 default: break;
973                         }
974                 }
975         }
976         ChanCount cc;
977         cc.set (DataType::AUDIO, n_audio);
978         cc.set (DataType::MIDI, n_midi);
979         return cc;
980 }
981
982 /* Getting access to the data buffer for a port */
983
984 void*
985 DummyAudioBackend::get_buffer (PortEngine::PortHandle port, pframes_t nframes)
986 {
987         assert (port && _running);
988         assert (valid_port (port));
989         return static_cast<DummyPort*>(port)->get_buffer (nframes);
990 }
991
992 /* Engine Process */
993 void *
994 DummyAudioBackend::main_process_thread ()
995 {
996         AudioEngine::thread_init_callback (this);
997         _running = true;
998         _processed_samples = 0;
999
1000         uint64_t clock1, clock2;
1001         clock1 = g_get_monotonic_time();
1002         while (_running) {
1003                 if (engine.process_callback (_samples_per_period)) {
1004                         return 0;
1005                 }
1006                 _processed_samples += _samples_per_period;
1007                 if (!_freewheeling) {
1008                         clock2 = g_get_monotonic_time();
1009                         const int64_t elapsed_time = clock2 - clock1;
1010                         const int64_t nomial_time = 1e6 * _samples_per_period / _samplerate;
1011                         _dsp_load = elapsed_time / (float) nomial_time;
1012                         if (elapsed_time < nomial_time) {
1013                                 Glib::usleep (nomial_time - elapsed_time);
1014                         } else {
1015                                 Glib::usleep (100); // don't hog cpu
1016                         }
1017                 } else {
1018                         _dsp_load = 1.0;
1019                         Glib::usleep (100); // don't hog cpu
1020                 }
1021                 clock1 = g_get_monotonic_time();
1022         }
1023         _running = false;
1024         return 0;
1025 }
1026
1027
1028 /******************************************************************************/
1029
1030 static boost::shared_ptr<DummyAudioBackend> _instance;
1031
1032 static boost::shared_ptr<AudioBackend> backend_factory (AudioEngine& e);
1033 static int instantiate (const std::string& arg1, const std::string& /* arg2 */);
1034 static int deinstantiate ();
1035 static bool already_configured ();
1036
1037 static ARDOUR::AudioBackendInfo _descriptor = {
1038         "Dummy",
1039         instantiate,
1040         deinstantiate,
1041         backend_factory,
1042         already_configured,
1043 };
1044
1045 static boost::shared_ptr<AudioBackend>
1046 backend_factory (AudioEngine& e)
1047 {
1048         if (!_instance) {
1049                 _instance.reset (new DummyAudioBackend (e, _descriptor));
1050         }
1051         return _instance;
1052 }
1053
1054 static int
1055 instantiate (const std::string& arg1, const std::string& /* arg2 */)
1056 {
1057         s_instance_name = arg1;
1058         return 0;
1059 }
1060
1061 static int
1062 deinstantiate ()
1063 {
1064         _instance.reset ();
1065         return 0;
1066 }
1067
1068 static bool
1069 already_configured ()
1070 {
1071         return false;
1072 }
1073
1074 extern "C" ARDOURBACKEND_API ARDOUR::AudioBackendInfo* descriptor ()
1075 {
1076         return &_descriptor;
1077 }
1078
1079
1080 /******************************************************************************/
1081 DummyPort::DummyPort (const std::string& name, PortFlags flags)
1082         : _name  (name)
1083         , _flags (flags)
1084 {
1085         _capture_latency_range.min = 0;
1086         _capture_latency_range.max = 0;
1087         _playback_latency_range.min = 0;
1088         _playback_latency_range.max = 0;
1089 }
1090
1091 DummyPort::~DummyPort () {
1092         disconnect_all ();
1093 }
1094
1095
1096 int DummyPort::connect (DummyPort *port)
1097 {
1098         if (!port) {
1099                 PBD::error << _("DummyPort::connect (): invalid (null) port") << endmsg;
1100                 return -1;
1101         }
1102
1103         if (type () != port->type ()) {
1104                 PBD::error << _("DummyPort::connect (): wrong port-type") << endmsg;
1105                 return -1;
1106         }
1107
1108         if (is_output () && port->is_output ()) {
1109                 PBD::error << _("DummyPort::connect (): cannot inter-connect output ports.") << endmsg;
1110                 return -1;
1111         }
1112
1113         if (is_input () && port->is_input ()) {
1114                 PBD::error << _("DummyPort::connect (): cannot inter-connect input ports.") << endmsg;
1115                 return -1;
1116         }
1117
1118         if (this == port) {
1119                 PBD::error << _("DummyPort::connect (): cannot self-connect ports.") << endmsg;
1120                 return -1;
1121         }
1122
1123         if (is_connected (port)) {
1124 #if 0 // don't bother to warn about this for now. just ignore it
1125                 PBD::error << _("DummyPort::connect (): ports are already connected:")
1126                         << " (" << name () << ") -> (" << port->name () << ")"
1127                         << endmsg;
1128 #endif
1129                 return -1;
1130         }
1131
1132         _connect (port, true);
1133         return 0;
1134 }
1135
1136
1137 void DummyPort::_connect (DummyPort *port, bool callback)
1138 {
1139         _connections.push_back (port);
1140         if (callback) {
1141                 port->_connect (this, false);
1142         }
1143 }
1144
1145 int DummyPort::disconnect (DummyPort *port)
1146 {
1147         if (!port) {
1148                 PBD::error << _("DummyPort::disconnect (): invalid (null) port") << endmsg;
1149                 return -1;
1150         }
1151
1152         if (!is_connected (port)) {
1153                 PBD::error << _("DummyPort::disconnect (): ports are not connected:")
1154                         << " (" << name () << ") -> (" << port->name () << ")"
1155                         << endmsg;
1156                 return -1;
1157         }
1158         _disconnect (port, true);
1159         return 0;
1160 }
1161
1162 void DummyPort::_disconnect (DummyPort *port, bool callback)
1163 {
1164         std::vector<DummyPort*>::iterator it = std::find (_connections.begin (), _connections.end (), port);
1165
1166         assert (it != _connections.end ());
1167
1168         _connections.erase (it);
1169
1170         if (callback) {
1171                 port->_disconnect (this, false);
1172         }
1173 }
1174
1175
1176 void DummyPort::disconnect_all ()
1177 {
1178         while (!_connections.empty ()) {
1179                 _connections.back ()->_disconnect (this, false);
1180                 _connections.pop_back ();
1181         }
1182 }
1183
1184 bool
1185 DummyPort::is_connected (const DummyPort *port) const
1186 {
1187         return std::find (_connections.begin (), _connections.end (), port) != _connections.end ();
1188 }
1189
1190 bool DummyPort::is_physically_connected () const
1191 {
1192         for (std::vector<DummyPort*>::const_iterator it = _connections.begin (); it != _connections.end (); ++it) {
1193                 if ((*it)->is_physical ()) {
1194                         return true;
1195                 }
1196         }
1197         return false;
1198 }
1199
1200 /******************************************************************************/
1201
1202 DummyAudioPort::DummyAudioPort (const std::string& name, PortFlags flags)
1203         : DummyPort (name, flags)
1204 {
1205         memset (_buffer, 0, sizeof (_buffer));
1206 }
1207
1208 DummyAudioPort::~DummyAudioPort () { }
1209
1210 void* DummyAudioPort::get_buffer (pframes_t n_samples)
1211 {
1212         if (is_input ()) {
1213                 std::vector<DummyPort*>::const_iterator it = get_connections ().begin ();
1214                 if (it == get_connections ().end ()) {
1215                         memset (_buffer, 0, n_samples * sizeof (Sample));
1216                 } else {
1217                         DummyAudioPort const * source = static_cast<const DummyAudioPort*>(*it);
1218                         assert (source && source->is_output ());
1219                         memcpy (_buffer, source->const_buffer (), n_samples * sizeof (Sample));
1220                         while (++it != get_connections ().end ()) {
1221                                 source = static_cast<const DummyAudioPort*>(*it);
1222                                 assert (source && source->is_output ());
1223                                 Sample* dst = buffer ();
1224                                 const Sample* src = source->const_buffer ();
1225                                 for (uint32_t s = 0; s < n_samples; ++s, ++dst, ++src) {
1226                                         *dst += *src;
1227                                 }
1228                         }
1229                 }
1230         } else if (is_output () && is_physical () && is_terminal()) {
1231                 memset (_buffer, 0, n_samples * sizeof (Sample));
1232         }
1233         return _buffer;
1234 }
1235
1236
1237 DummyMidiPort::DummyMidiPort (const std::string& name, PortFlags flags)
1238         : DummyPort (name, flags)
1239 {
1240         _buffer.clear ();
1241 }
1242
1243 DummyMidiPort::~DummyMidiPort () { }
1244
1245 void* DummyMidiPort::get_buffer (pframes_t /* nframes */)
1246 {
1247         if (is_input ()) {
1248                 _buffer.clear ();
1249                 for (std::vector<DummyPort*>::const_iterator i = get_connections ().begin ();
1250                                 i != get_connections ().end ();
1251                                 ++i) {
1252                         const DummyMidiBuffer src = static_cast<const DummyMidiPort*>(*i)->const_buffer ();
1253                         for (DummyMidiBuffer::const_iterator it = src.begin (); it != src.end (); ++it) {
1254                                 _buffer.push_back (boost::shared_ptr<DummyMidiEvent>(new DummyMidiEvent (**it)));
1255                         }
1256                 }
1257                 std::sort (_buffer.begin (), _buffer.end ());
1258         } else if (is_output () && is_physical () && is_terminal()) {
1259                 _buffer.clear ();
1260         }
1261         return &_buffer;
1262 }
1263
1264 DummyMidiEvent::DummyMidiEvent (const pframes_t timestamp, const uint8_t* data, size_t size)
1265         : _size (size)
1266         , _timestamp (timestamp)
1267         , _data (0)
1268 {
1269         if (size > 0) {
1270                 _data = (uint8_t*) malloc (size);
1271          memcpy (_data, data, size);
1272         }
1273 }
1274
1275 DummyMidiEvent::DummyMidiEvent (const DummyMidiEvent& other)
1276         : _size (other.size ())
1277         , _timestamp (other.timestamp ())
1278         , _data (0)
1279 {
1280         if (other.size () && other.const_data ()) {
1281                 _data = (uint8_t*) malloc (other.size ());
1282                 memcpy (_data, other.const_data (), other.size ());
1283         }
1284 };
1285
1286 DummyMidiEvent::~DummyMidiEvent () {
1287         free (_data);
1288 };