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