Dummy backend, revise small things
[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 0;
278 }
279
280 std::string
281 DummyAudioBackend::midi_option () const
282 {
283         return ""; // TODO
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 _samples_per_period * 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                 pthread_attr_destroy (&attr);
428                 return -1;
429         }
430         pthread_attr_destroy (&attr);
431
432         _threads.push_back (thread_id);
433         return 0;
434 }
435
436 int
437 DummyAudioBackend::join_process_threads ()
438 {
439         int rv = 0;
440
441         for (std::vector<pthread_t>::const_iterator i = _threads.begin (); i != _threads.end (); ++i)
442         {
443                 void *status;
444                 if (pthread_join (*i, &status)) {
445                         PBD::error << _("AudioEngine: cannot terminate process thread.") << endmsg;
446                         rv -= 1;
447                 }
448         }
449         _threads.clear ();
450         return rv;
451 }
452
453 bool
454 DummyAudioBackend::in_process_thread ()
455 {
456         for (std::vector<pthread_t>::const_iterator i = _threads.begin (); i != _threads.end (); ++i)
457         {
458                 if (pthread_equal (*i, pthread_self ()) != 0) {
459                         return true;
460                 }
461         }
462         return false;
463 }
464
465 uint32_t
466 DummyAudioBackend::process_thread_count ()
467 {
468         return _threads.size ();
469 }
470
471 void
472 DummyAudioBackend::update_latencies ()
473 {
474 }
475
476 /* PORTENGINE API */
477
478 void*
479 DummyAudioBackend::private_handle () const
480 {
481         return NULL;
482 }
483
484 const std::string&
485 DummyAudioBackend::my_name () const
486 {
487         return _instance_name;
488 }
489
490 bool
491 DummyAudioBackend::available () const
492 {
493         return true;
494 }
495
496 uint32_t
497 DummyAudioBackend::port_name_size () const
498 {
499         return 256;
500 }
501
502 int
503 DummyAudioBackend::set_port_name (PortEngine::PortHandle port, const std::string& name)
504 {
505         if (!valid_port (port)) {
506                 PBD::error << _("DummyBackend::set_port_name: Invalid Port(s)") << endmsg;
507                 return -1;
508         }
509         return static_cast<DummyPort*>(port)->set_name (_instance_name + ":" + name);
510 }
511
512 std::string
513 DummyAudioBackend::get_port_name (PortEngine::PortHandle port) const
514 {
515         if (!valid_port (port)) {
516                 PBD::error << _("DummyBackend::get_port_name: Invalid Port(s)") << endmsg;
517                 return std::string ();
518         }
519         return static_cast<DummyPort*>(port)->name ();
520 }
521
522 PortEngine::PortHandle
523 DummyAudioBackend::get_port_by_name (const std::string& name) const
524 {
525         PortHandle port = (PortHandle) find_port (name);
526         return port;
527 }
528
529 int
530 DummyAudioBackend::get_ports (
531                 const std::string& port_name_pattern,
532                 DataType type, PortFlags flags,
533                 std::vector<std::string>& port_names) const
534 {
535         int rv = 0;
536         regex_t port_regex;
537         bool use_regexp = false;
538         if (port_name_pattern.size () > 0) {
539                 if (!regcomp (&port_regex, port_name_pattern.c_str (), REG_EXTENDED|REG_NOSUB)) {
540                         use_regexp = true;
541                 }
542         }
543         for (size_t i = 0; i < _ports.size (); ++i) {
544                 DummyPort* port = _ports[i];
545                 if ((port->type () == type) && (port->flags () & flags)) {
546                         if (!use_regexp || !regexec (&port_regex, port->name ().c_str (), 0, NULL, 0)) {
547                                 port_names.push_back (port->name ());
548                                 ++rv;
549                         }
550                 }
551         }
552         if (use_regexp) {
553                 regfree (&port_regex);
554         }
555         return rv;
556 }
557
558 DataType
559 DummyAudioBackend::port_data_type (PortEngine::PortHandle port) const
560 {
561         if (!valid_port (port)) {
562                 return DataType::NIL;
563         }
564         return static_cast<DummyPort*>(port)->type ();
565 }
566
567 PortEngine::PortHandle
568 DummyAudioBackend::register_port (
569                 const std::string& name,
570                 ARDOUR::DataType type,
571                 ARDOUR::PortFlags flags)
572 {
573         if (name.size () == 0) { return 0; }
574         if (flags & IsPhysical) { return 0; }
575         return add_port (_instance_name + ":" + name, type, flags);
576 }
577
578 PortEngine::PortHandle
579 DummyAudioBackend::add_port (
580                 const std::string& name,
581                 ARDOUR::DataType type,
582                 ARDOUR::PortFlags flags)
583 {
584         assert(name.size ());
585         if (find_port (name)) {
586                 PBD::error << _("DummyBackend::register_port: Port already exists:")
587                                 << " (" << name << ")" << endmsg;
588                 return 0;
589         }
590         DummyPort* port = NULL;
591         switch (type) {
592                 case DataType::AUDIO:
593                         port = new DummyAudioPort (*this, name, flags);
594                         break;
595                 case DataType::MIDI:
596                         port = new DummyMidiPort (*this, name, flags);
597                         break;
598                 default:
599                         PBD::error << _("DummyBackend::register_port: Invalid Data Type.") << endmsg;
600                         return 0;
601         }
602
603         _ports.push_back (port);
604
605         return port;
606 }
607
608 void
609 DummyAudioBackend::unregister_port (PortEngine::PortHandle port_handle)
610 {
611         if (!valid_port (port_handle)) {
612                 PBD::error << _("DummyBackend::unregister_port: Invalid Port.") << endmsg;
613         }
614         DummyPort* port = static_cast<DummyPort*>(port_handle);
615         std::vector<DummyPort*>::iterator i = std::find (_ports.begin (), _ports.end (), static_cast<DummyPort*>(port_handle));
616         if (i == _ports.end ()) {
617                 PBD::error << _("DummyBackend::unregister_port: Failed to find port") << endmsg;
618                 return;
619         }
620         disconnect_all(port_handle);
621         _ports.erase (i);
622         delete port;
623 }
624
625 int
626 DummyAudioBackend::register_system_ports()
627 {
628         LatencyRange lr;
629
630         const int a_ins = _n_inputs > 0 ? _n_inputs : 8;
631         const int a_out = _n_outputs > 0 ? _n_outputs : 8;
632         const int m_ins = _n_midi_inputs > 0 ? _n_midi_inputs : 2;
633         const int m_out = _n_midi_outputs > 0 ? _n_midi_outputs : 2;
634
635         /* audio ports */
636         lr.min = lr.max = _samples_per_period + _systemic_input_latency;
637         for (int i = 1; i <= a_ins; ++i) {
638                 char tmp[64];
639                 snprintf(tmp, sizeof(tmp), "system:capture_%d", i);
640                 PortHandle p = add_port(std::string(tmp), DataType::AUDIO, static_cast<PortFlags>(IsOutput | IsPhysical | IsTerminal));
641                 if (!p) return -1;
642                 set_latency_range (p, false, lr);
643         }
644
645         lr.min = lr.max = _samples_per_period + _systemic_output_latency;
646         for (int i = 1; i <= a_out; ++i) {
647                 char tmp[64];
648                 snprintf(tmp, sizeof(tmp), "system:playback_%d", i);
649                 PortHandle p = add_port(std::string(tmp), DataType::AUDIO, static_cast<PortFlags>(IsInput | IsPhysical | IsTerminal));
650                 if (!p) return -1;
651                 set_latency_range (p, false, lr);
652         }
653
654         /* midi ports */
655         lr.min = lr.max = _samples_per_period + _systemic_input_latency;
656         for (int i = 1; i <= m_ins; ++i) {
657                 char tmp[64];
658                 snprintf(tmp, sizeof(tmp), "system:midi_capture_%d", i);
659                 PortHandle p = add_port(std::string(tmp), DataType::MIDI, static_cast<PortFlags>(IsOutput | IsPhysical | IsTerminal));
660                 if (!p) return -1;
661                 set_latency_range (p, false, lr);
662         }
663
664         lr.min = lr.max = _samples_per_period + _systemic_output_latency;
665         for (int i = 1; i <= m_out; ++i) {
666                 char tmp[64];
667                 snprintf(tmp, sizeof(tmp), "system:midi_playback_%d", i);
668                 PortHandle p = add_port(std::string(tmp), DataType::MIDI, static_cast<PortFlags>(IsInput | IsPhysical | IsTerminal));
669                 if (!p) return -1;
670                 set_latency_range (p, false, lr);
671         }
672
673         return 0;
674 }
675
676 void
677 DummyAudioBackend::unregister_system_ports()
678 {
679         size_t i = 0;
680         while (i <  _ports.size ()) {
681                 DummyPort* port = _ports[i];
682                 if (port->is_physical () && port->is_terminal ()) {
683                         port->disconnect_all ();
684                         _ports.erase (_ports.begin() + i);
685                 } else {
686                         ++i;
687                 }
688         }
689 }
690
691 int
692 DummyAudioBackend::connect (const std::string& src, const std::string& dst)
693 {
694         DummyPort* src_port = find_port (src);
695         DummyPort* dst_port = find_port (dst);
696
697         if (!src_port) {
698                 PBD::error << _("DummyBackend::connect: Invalid Source port:")
699                                 << " (" << src <<")" << endmsg;
700                 return -1;
701         }
702         if (!dst_port) {
703                 PBD::error << _("DummyBackend::connect: Invalid Destination port:")
704                         << " (" << dst <<")" << endmsg;
705                 return -1;
706         }
707         return src_port->connect (dst_port);
708 }
709
710 int
711 DummyAudioBackend::disconnect (const std::string& src, const std::string& dst)
712 {
713         DummyPort* src_port = find_port (src);
714         DummyPort* dst_port = find_port (dst);
715
716         if (!src_port || !dst_port) {
717                 PBD::error << _("DummyBackend::disconnect: Invalid Port(s)") << endmsg;
718                 return -1;
719         }
720         return src_port->disconnect (dst_port);
721 }
722
723 int
724 DummyAudioBackend::connect (PortEngine::PortHandle src, const std::string& dst)
725 {
726         DummyPort* dst_port = find_port (dst);
727         if (!valid_port (src)) {
728                 PBD::error << _("DummyBackend::connect: Invalid Source Port Handle") << endmsg;
729                 return -1;
730         }
731         if (!dst_port) {
732                 PBD::error << _("DummyBackend::connect: Invalid Destination Port")
733                         << " (" << dst << ")" << endmsg;
734                 return -1;
735         }
736         return static_cast<DummyPort*>(src)->connect (dst_port);
737 }
738
739 int
740 DummyAudioBackend::disconnect (PortEngine::PortHandle src, const std::string& dst)
741 {
742         DummyPort* dst_port = find_port (dst);
743         if (!valid_port (src) || !dst_port) {
744                 PBD::error << _("DummyBackend::disconnect: Invalid Port(s)") << endmsg;
745                 return -1;
746         }
747         return static_cast<DummyPort*>(src)->disconnect (dst_port);
748 }
749
750 int
751 DummyAudioBackend::disconnect_all (PortEngine::PortHandle port)
752 {
753         if (!valid_port (port)) {
754                 PBD::error << _("DummyBackend::disconnect_all: Invalid Port") << endmsg;
755                 return -1;
756         }
757         static_cast<DummyPort*>(port)->disconnect_all ();
758         return 0;
759 }
760
761 bool
762 DummyAudioBackend::connected (PortEngine::PortHandle port, bool /* process_callback_safe*/)
763 {
764         if (!valid_port (port)) {
765                 PBD::error << _("DummyBackend::disconnect_all: Invalid Port") << endmsg;
766                 return false;
767         }
768         return static_cast<DummyPort*>(port)->is_connected ();
769 }
770
771 bool
772 DummyAudioBackend::connected_to (PortEngine::PortHandle src, const std::string& dst, bool /*process_callback_safe*/)
773 {
774         DummyPort* dst_port = find_port (dst);
775         if (!valid_port (src) || !dst_port) {
776                 PBD::error << _("DummyBackend::connected_to: Invalid Port") << endmsg;
777                 return false;
778         }
779         return static_cast<DummyPort*>(src)->is_connected (dst_port);
780 }
781
782 bool
783 DummyAudioBackend::physically_connected (PortEngine::PortHandle port, bool /*process_callback_safe*/)
784 {
785         if (!valid_port (port)) {
786                 PBD::error << _("DummyBackend::physically_connected: Invalid Port") << endmsg;
787                 return false;
788         }
789         return static_cast<DummyPort*>(port)->is_physically_connected ();
790 }
791
792 int
793 DummyAudioBackend::get_connections (PortEngine::PortHandle port, std::vector<std::string>& names, bool /*process_callback_safe*/)
794 {
795         if (!valid_port (port)) {
796                 PBD::error << _("DummyBackend::get_connections: Invalid Port") << endmsg;
797                 return -1;
798         }
799
800         assert (0 == names.size ());
801
802         const std::vector<DummyPort*>& connected_ports = static_cast<DummyPort*>(port)->get_connections ();
803
804         for (std::vector<DummyPort*>::const_iterator i = connected_ports.begin (); i != connected_ports.end (); ++i) {
805                 names.push_back ((*i)->name ());
806         }
807
808         return (int)names.size ();
809 }
810
811 /* MIDI */
812 int
813 DummyAudioBackend::midi_event_get (
814                 pframes_t& timestamp,
815                 size_t& size, uint8_t** buf, void* port_buffer,
816                 uint32_t event_index)
817 {
818         assert (buf && port_buffer);
819         DummyMidiBuffer& source = * static_cast<DummyMidiBuffer*>(port_buffer);
820         if (event_index >= source.size ()) {
821                 return -1;
822         }
823         DummyMidiEvent * const event = source[event_index].get ();
824
825         timestamp = event->timestamp ();
826         size = event->size ();
827         *buf = event->data ();
828         return 0;
829 }
830
831 int
832 DummyAudioBackend::midi_event_put (
833                 void* port_buffer,
834                 pframes_t timestamp,
835                 const uint8_t* buffer, size_t size)
836 {
837         assert (buffer && port_buffer);
838         DummyMidiBuffer& dst = * static_cast<DummyMidiBuffer*>(port_buffer);
839         if (dst.size () && (pframes_t)dst.back ()->timestamp () > timestamp) {
840                 fprintf (stderr, "DummyMidiBuffer: it's too late for this event.\n");
841                 return -1;
842         }
843         dst.push_back (boost::shared_ptr<DummyMidiEvent>(new DummyMidiEvent (timestamp, buffer, size)));
844         return 0;
845 }
846
847 uint32_t
848 DummyAudioBackend::get_midi_event_count (void* port_buffer)
849 {
850         assert (port_buffer);
851         return static_cast<DummyMidiBuffer*>(port_buffer)->size ();
852 }
853
854 void
855 DummyAudioBackend::midi_clear (void* port_buffer)
856 {
857         assert (port_buffer);
858         DummyMidiBuffer * buf = static_cast<DummyMidiBuffer*>(port_buffer);
859         assert (buf);
860         buf->clear ();
861 }
862
863 /* Monitoring */
864
865 bool
866 DummyAudioBackend::can_monitor_input () const
867 {
868         return false;
869 }
870
871 int
872 DummyAudioBackend::request_input_monitoring (PortEngine::PortHandle, bool)
873 {
874         return -1;
875 }
876
877 int
878 DummyAudioBackend::ensure_input_monitoring (PortEngine::PortHandle, bool)
879 {
880         return -1;
881 }
882
883 bool
884 DummyAudioBackend::monitoring_input (PortEngine::PortHandle)
885 {
886         return false;
887 }
888
889 /* Latency management */
890
891 void
892 DummyAudioBackend::set_latency_range (PortEngine::PortHandle port, bool for_playback, LatencyRange latency_range)
893 {
894         if (!valid_port (port)) {
895                 PBD::error << _("DummyPort::set_latency_range (): invalid port.") << endmsg;
896         }
897         static_cast<DummyPort*>(port)->set_latency_range (latency_range, for_playback);
898 }
899
900 LatencyRange
901 DummyAudioBackend::get_latency_range (PortEngine::PortHandle port, bool for_playback)
902 {
903         if (!valid_port (port)) {
904                 PBD::error << _("DummyPort::get_latency_range (): invalid port.") << endmsg;
905                 LatencyRange r;
906                 r.min = 0;
907                 r.max = 0;
908                 return r;
909         }
910         return static_cast<DummyPort*>(port)->latency_range (for_playback);
911 }
912
913 /* Discovering physical ports */
914
915 bool
916 DummyAudioBackend::port_is_physical (PortEngine::PortHandle port) const
917 {
918         if (!valid_port (port)) {
919                 PBD::error << _("DummyPort::port_is_physical (): invalid port.") << endmsg;
920                 return false;
921         }
922         return static_cast<DummyPort*>(port)->is_physical ();
923 }
924
925 void
926 DummyAudioBackend::get_physical_outputs (DataType type, std::vector<std::string>& port_names)
927 {
928         for (size_t i = 0; i < _ports.size (); ++i) {
929                 DummyPort* port = _ports[i];
930                 if ((port->type () == type) && port->is_input () && port->is_physical ()) {
931                         port_names.push_back (port->name ());
932                 }
933         }
934 }
935
936 void
937 DummyAudioBackend::get_physical_inputs (DataType type, std::vector<std::string>& port_names)
938 {
939         for (size_t i = 0; i < _ports.size (); ++i) {
940                 DummyPort* port = _ports[i];
941                 if ((port->type () == type) && port->is_output () && port->is_physical ()) {
942                         port_names.push_back (port->name ());
943                 }
944         }
945 }
946
947 ChanCount
948 DummyAudioBackend::n_physical_outputs () const
949 {
950         int n_midi = 0;
951         int n_audio = 0;
952         for (size_t i = 0; i < _ports.size (); ++i) {
953                 DummyPort* port = _ports[i];
954                 if (port->is_output () && port->is_physical ()) {
955                         switch (port->type ()) {
956                                 case DataType::AUDIO: ++n_audio; break;
957                                 case DataType::MIDI: ++n_midi; break;
958                                 default: break;
959                         }
960                 }
961         }
962         ChanCount cc;
963         cc.set (DataType::AUDIO, n_audio);
964         cc.set (DataType::MIDI, n_midi);
965         return cc;
966 }
967
968 ChanCount
969 DummyAudioBackend::n_physical_inputs () const
970 {
971         int n_midi = 0;
972         int n_audio = 0;
973         for (size_t i = 0; i < _ports.size (); ++i) {
974                 DummyPort* port = _ports[i];
975                 if (port->is_input () && port->is_physical ()) {
976                         switch (port->type ()) {
977                                 case DataType::AUDIO: ++n_audio; break;
978                                 case DataType::MIDI: ++n_midi; break;
979                                 default: break;
980                         }
981                 }
982         }
983         ChanCount cc;
984         cc.set (DataType::AUDIO, n_audio);
985         cc.set (DataType::MIDI, n_midi);
986         return cc;
987 }
988
989 /* Getting access to the data buffer for a port */
990
991 void*
992 DummyAudioBackend::get_buffer (PortEngine::PortHandle port, pframes_t nframes)
993 {
994         assert (port);
995         assert (valid_port (port));
996         return static_cast<DummyPort*>(port)->get_buffer (nframes);
997 }
998
999 /* Engine Process */
1000 void *
1001 DummyAudioBackend::main_process_thread ()
1002 {
1003         AudioEngine::thread_init_callback (this);
1004         _running = true;
1005         _processed_samples = 0;
1006
1007         uint64_t clock1, clock2;
1008         clock1 = g_get_monotonic_time();
1009         while (_running) {
1010                 if (engine.process_callback (_samples_per_period)) {
1011                         return 0;
1012                 }
1013                 _processed_samples += _samples_per_period;
1014                 if (!_freewheeling) {
1015                         clock2 = g_get_monotonic_time();
1016                         const int64_t elapsed_time = clock2 - clock1;
1017                         const int64_t nomial_time = 1e6 * _samples_per_period / _samplerate;
1018                         _dsp_load = elapsed_time / (float) nomial_time;
1019                         if (elapsed_time < nomial_time) {
1020                                 Glib::usleep (nomial_time - elapsed_time);
1021                         } else {
1022                                 Glib::usleep (100); // don't hog cpu
1023                         }
1024                 } else {
1025                         _dsp_load = 1.0;
1026                         Glib::usleep (100); // don't hog cpu
1027                 }
1028                 clock1 = g_get_monotonic_time();
1029
1030                 if (!pthread_mutex_trylock (&_port_callback_mutex)) {
1031                         while (!_port_connection_queue.empty ()) {
1032                                 PortConnectData *c = _port_connection_queue.back ();
1033                                 manager.connect_callback (c->a, c->b, c->c);
1034                                 _port_connection_queue.pop_back ();
1035                                 delete c;
1036                         }
1037                         pthread_mutex_unlock (&_port_callback_mutex);
1038                 }
1039
1040         }
1041         _running = false;
1042         return 0;
1043 }
1044
1045
1046 /******************************************************************************/
1047
1048 static boost::shared_ptr<DummyAudioBackend> _instance;
1049
1050 static boost::shared_ptr<AudioBackend> backend_factory (AudioEngine& e);
1051 static int instantiate (const std::string& arg1, const std::string& /* arg2 */);
1052 static int deinstantiate ();
1053 static bool already_configured ();
1054
1055 static ARDOUR::AudioBackendInfo _descriptor = {
1056         "Dummy",
1057         instantiate,
1058         deinstantiate,
1059         backend_factory,
1060         already_configured,
1061 };
1062
1063 static boost::shared_ptr<AudioBackend>
1064 backend_factory (AudioEngine& e)
1065 {
1066         if (!_instance) {
1067                 _instance.reset (new DummyAudioBackend (e, _descriptor));
1068         }
1069         return _instance;
1070 }
1071
1072 static int
1073 instantiate (const std::string& arg1, const std::string& /* arg2 */)
1074 {
1075         s_instance_name = arg1;
1076         return 0;
1077 }
1078
1079 static int
1080 deinstantiate ()
1081 {
1082         _instance.reset ();
1083         return 0;
1084 }
1085
1086 static bool
1087 already_configured ()
1088 {
1089         return false;
1090 }
1091
1092 extern "C" ARDOURBACKEND_API ARDOUR::AudioBackendInfo* descriptor ()
1093 {
1094         return &_descriptor;
1095 }
1096
1097
1098 /******************************************************************************/
1099 DummyPort::DummyPort (DummyAudioBackend &b, const std::string& name, PortFlags flags)
1100         : _dummy_backend (b)
1101         , _name  (name)
1102         , _flags (flags)
1103 {
1104         _capture_latency_range.min = 0;
1105         _capture_latency_range.max = 0;
1106         _playback_latency_range.min = 0;
1107         _playback_latency_range.max = 0;
1108 }
1109
1110 DummyPort::~DummyPort () {
1111         disconnect_all ();
1112 }
1113
1114
1115 int DummyPort::connect (DummyPort *port)
1116 {
1117         if (!port) {
1118                 PBD::error << _("DummyPort::connect (): invalid (null) port") << endmsg;
1119                 return -1;
1120         }
1121
1122         if (type () != port->type ()) {
1123                 PBD::error << _("DummyPort::connect (): wrong port-type") << endmsg;
1124                 return -1;
1125         }
1126
1127         if (is_output () && port->is_output ()) {
1128                 PBD::error << _("DummyPort::connect (): cannot inter-connect output ports.") << endmsg;
1129                 return -1;
1130         }
1131
1132         if (is_input () && port->is_input ()) {
1133                 PBD::error << _("DummyPort::connect (): cannot inter-connect input ports.") << endmsg;
1134                 return -1;
1135         }
1136
1137         if (this == port) {
1138                 PBD::error << _("DummyPort::connect (): cannot self-connect ports.") << endmsg;
1139                 return -1;
1140         }
1141
1142         if (is_connected (port)) {
1143 #if 0 // don't bother to warn about this for now. just ignore it
1144                 PBD::error << _("DummyPort::connect (): ports are already connected:")
1145                         << " (" << name () << ") -> (" << port->name () << ")"
1146                         << endmsg;
1147 #endif
1148                 return -1;
1149         }
1150
1151         _connect (port, true);
1152         return 0;
1153 }
1154
1155
1156 void DummyPort::_connect (DummyPort *port, bool callback)
1157 {
1158         _connections.push_back (port);
1159         if (callback) {
1160                 port->_connect (this, false);
1161                 _dummy_backend.port_connect_callback (name(),  port->name(), true);
1162         }
1163 }
1164
1165 int DummyPort::disconnect (DummyPort *port)
1166 {
1167         if (!port) {
1168                 PBD::error << _("DummyPort::disconnect (): invalid (null) port") << endmsg;
1169                 return -1;
1170         }
1171
1172         if (!is_connected (port)) {
1173                 PBD::error << _("DummyPort::disconnect (): ports are not connected:")
1174                         << " (" << name () << ") -> (" << port->name () << ")"
1175                         << endmsg;
1176                 return -1;
1177         }
1178         _disconnect (port, true);
1179         return 0;
1180 }
1181
1182 void DummyPort::_disconnect (DummyPort *port, bool callback)
1183 {
1184         std::vector<DummyPort*>::iterator it = std::find (_connections.begin (), _connections.end (), port);
1185
1186         assert (it != _connections.end ());
1187
1188         _connections.erase (it);
1189
1190         if (callback) {
1191                 port->_disconnect (this, false);
1192                 _dummy_backend.port_connect_callback (name(),  port->name(), false);
1193         }
1194 }
1195
1196
1197 void DummyPort::disconnect_all ()
1198 {
1199         while (!_connections.empty ()) {
1200                 _connections.back ()->_disconnect (this, false);
1201                 _dummy_backend.port_connect_callback (name(),  _connections.back ()->name(), false);
1202                 _connections.pop_back ();
1203         }
1204 }
1205
1206 bool
1207 DummyPort::is_connected (const DummyPort *port) const
1208 {
1209         return std::find (_connections.begin (), _connections.end (), port) != _connections.end ();
1210 }
1211
1212 bool DummyPort::is_physically_connected () const
1213 {
1214         for (std::vector<DummyPort*>::const_iterator it = _connections.begin (); it != _connections.end (); ++it) {
1215                 if ((*it)->is_physical ()) {
1216                         return true;
1217                 }
1218         }
1219         return false;
1220 }
1221
1222 /******************************************************************************/
1223
1224 DummyAudioPort::DummyAudioPort (DummyAudioBackend &b, const std::string& name, PortFlags flags)
1225         : DummyPort (b, name, flags)
1226 {
1227         memset (_buffer, 0, sizeof (_buffer));
1228 }
1229
1230 DummyAudioPort::~DummyAudioPort () { }
1231
1232 void* DummyAudioPort::get_buffer (pframes_t n_samples)
1233 {
1234         if (is_input ()) {
1235                 std::vector<DummyPort*>::const_iterator it = get_connections ().begin ();
1236                 if (it == get_connections ().end ()) {
1237                         memset (_buffer, 0, n_samples * sizeof (Sample));
1238                 } else {
1239                         DummyAudioPort const * source = static_cast<const DummyAudioPort*>(*it);
1240                         assert (source && source->is_output ());
1241                         memcpy (_buffer, source->const_buffer (), n_samples * sizeof (Sample));
1242                         while (++it != get_connections ().end ()) {
1243                                 source = static_cast<const DummyAudioPort*>(*it);
1244                                 assert (source && source->is_output ());
1245                                 Sample* dst = buffer ();
1246                                 const Sample* src = source->const_buffer ();
1247                                 for (uint32_t s = 0; s < n_samples; ++s, ++dst, ++src) {
1248                                         *dst += *src;
1249                                 }
1250                         }
1251                 }
1252         } else if (is_output () && is_physical () && is_terminal()) {
1253                 memset (_buffer, 0, n_samples * sizeof (Sample));
1254         }
1255         return _buffer;
1256 }
1257
1258
1259 DummyMidiPort::DummyMidiPort (DummyAudioBackend &b, const std::string& name, PortFlags flags)
1260         : DummyPort (b, name, flags)
1261 {
1262         _buffer.clear ();
1263 }
1264
1265 DummyMidiPort::~DummyMidiPort () { }
1266
1267 void* DummyMidiPort::get_buffer (pframes_t /* nframes */)
1268 {
1269         if (is_input ()) {
1270                 _buffer.clear ();
1271                 for (std::vector<DummyPort*>::const_iterator i = get_connections ().begin ();
1272                                 i != get_connections ().end ();
1273                                 ++i) {
1274                         const DummyMidiBuffer src = static_cast<const DummyMidiPort*>(*i)->const_buffer ();
1275                         for (DummyMidiBuffer::const_iterator it = src.begin (); it != src.end (); ++it) {
1276                                 _buffer.push_back (boost::shared_ptr<DummyMidiEvent>(new DummyMidiEvent (**it)));
1277                         }
1278                 }
1279                 std::sort (_buffer.begin (), _buffer.end ());
1280         } else if (is_output () && is_physical () && is_terminal()) {
1281                 _buffer.clear ();
1282         }
1283         return &_buffer;
1284 }
1285
1286 DummyMidiEvent::DummyMidiEvent (const pframes_t timestamp, const uint8_t* data, size_t size)
1287         : _size (size)
1288         , _timestamp (timestamp)
1289         , _data (0)
1290 {
1291         if (size > 0) {
1292                 _data = (uint8_t*) malloc (size);
1293          memcpy (_data, data, size);
1294         }
1295 }
1296
1297 DummyMidiEvent::DummyMidiEvent (const DummyMidiEvent& other)
1298         : _size (other.size ())
1299         , _timestamp (other.timestamp ())
1300         , _data (0)
1301 {
1302         if (other.size () && other.const_data ()) {
1303                 _data = (uint8_t*) malloc (other.size ());
1304                 memcpy (_data, other.const_data (), other.size ());
1305         }
1306 };
1307
1308 DummyMidiEvent::~DummyMidiEvent () {
1309         free (_data);
1310 };