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