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