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