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