ALSA|Dummy Backend: do as jack does:
[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 #include <stdlib.h>
23
24 #include <glibmm.h>
25
26 #include "dummy_audiobackend.h"
27
28 #include "pbd/error.h"
29 #include "ardour/port_manager.h"
30 #include "i18n.h"
31
32 using namespace ARDOUR;
33
34 static std::string s_instance_name;
35 size_t DummyAudioBackend::_max_buffer_size = 8192;
36 std::vector<std::string> DummyAudioBackend::_midi_options;
37 std::vector<AudioBackend::DeviceStatus> DummyAudioBackend::_device_status;
38
39 DummyAudioBackend::DummyAudioBackend (AudioEngine& e, AudioBackendInfo& info)
40         : AudioBackend (e, info)
41         , _running (false)
42         , _freewheeling (false)
43         , _device ("")
44         , _samplerate (48000)
45         , _samples_per_period (1024)
46         , _dsp_load (0)
47         , _n_inputs (0)
48         , _n_outputs (0)
49         , _n_midi_inputs (0)
50         , _n_midi_outputs (0)
51         , _systemic_input_latency (0)
52         , _systemic_output_latency (0)
53         , _processed_samples (0)
54         , _port_change_flag (false)
55 {
56         _instance_name = s_instance_name;
57         pthread_mutex_init (&_port_callback_mutex, 0);
58 }
59
60 DummyAudioBackend::~DummyAudioBackend ()
61 {
62         pthread_mutex_destroy (&_port_callback_mutex);
63 }
64
65 /* AUDIOBACKEND API */
66
67 std::string
68 DummyAudioBackend::name () const
69 {
70         return X_("Dummy");
71 }
72
73 bool
74 DummyAudioBackend::is_realtime () const
75 {
76         return false;
77 }
78
79 std::vector<AudioBackend::DeviceStatus>
80 DummyAudioBackend::enumerate_devices () const
81 {
82         if (_device_status.empty()) {
83                 _device_status.push_back (DeviceStatus (_("Silence"), true));
84                 _device_status.push_back (DeviceStatus (_("Sine Wave"), true));
85                 _device_status.push_back (DeviceStatus (_("Uniform White Noise"), true));
86                 _device_status.push_back (DeviceStatus (_("Gaussian White Noise"), true));
87                 _device_status.push_back (DeviceStatus (_("Pink Noise"), true));
88                 _device_status.push_back (DeviceStatus (_("Pink Noise (low CPU)"), true));
89         }
90         return _device_status;
91 }
92
93 std::vector<float>
94 DummyAudioBackend::available_sample_rates (const std::string&) const
95 {
96         std::vector<float> sr;
97         sr.push_back (8000.0);
98         sr.push_back (22050.0);
99         sr.push_back (24000.0);
100         sr.push_back (44100.0);
101         sr.push_back (48000.0);
102         sr.push_back (88200.0);
103         sr.push_back (96000.0);
104         sr.push_back (176400.0);
105         sr.push_back (192000.0);
106         return sr;
107 }
108
109 std::vector<uint32_t>
110 DummyAudioBackend::available_buffer_sizes (const std::string&) const
111 {
112         std::vector<uint32_t> bs;
113         bs.push_back (4);
114         bs.push_back (8);
115         bs.push_back (16);
116         bs.push_back (32);
117         bs.push_back (64);
118         bs.push_back (128);
119         bs.push_back (256);
120         bs.push_back (512);
121         bs.push_back (1024);
122         bs.push_back (2048);
123         bs.push_back (4096);
124         bs.push_back (8192);
125         return bs;
126 }
127
128 uint32_t
129 DummyAudioBackend::available_input_channel_count (const std::string&) const
130 {
131         return 128;
132 }
133
134 uint32_t
135 DummyAudioBackend::available_output_channel_count (const std::string&) const
136 {
137         return 128;
138 }
139
140 bool
141 DummyAudioBackend::can_change_sample_rate_when_running () const
142 {
143         return true;
144 }
145
146 bool
147 DummyAudioBackend::can_change_buffer_size_when_running () const
148 {
149         return true;
150 }
151
152 int
153 DummyAudioBackend::set_device_name (const std::string& d)
154 {
155         _device = d;
156         return 0;
157 }
158
159 int
160 DummyAudioBackend::set_sample_rate (float sr)
161 {
162         if (sr <= 0) { return -1; }
163         _samplerate = sr;
164         engine.sample_rate_change (sr);
165         return 0;
166 }
167
168 int
169 DummyAudioBackend::set_buffer_size (uint32_t bs)
170 {
171         if (bs <= 0 || bs >= _max_buffer_size) {
172                 return -1;
173         }
174         _samples_per_period = bs;
175         engine.buffer_size_change (bs);
176         return 0;
177 }
178
179 int
180 DummyAudioBackend::set_interleaved (bool yn)
181 {
182         if (!yn) { return 0; }
183         return -1;
184 }
185
186 int
187 DummyAudioBackend::set_input_channels (uint32_t cc)
188 {
189         _n_inputs = cc;
190         return 0;
191 }
192
193 int
194 DummyAudioBackend::set_output_channels (uint32_t cc)
195 {
196         _n_outputs = cc;
197         return 0;
198 }
199
200 int
201 DummyAudioBackend::set_systemic_input_latency (uint32_t sl)
202 {
203         _systemic_input_latency = sl;
204         return 0;
205 }
206
207 int
208 DummyAudioBackend::set_systemic_output_latency (uint32_t sl)
209 {
210         _systemic_output_latency = sl;
211         return 0;
212 }
213
214 /* Retrieving parameters */
215 std::string
216 DummyAudioBackend::device_name () const
217 {
218         return _device;
219 }
220
221 float
222 DummyAudioBackend::sample_rate () const
223 {
224         return _samplerate;
225 }
226
227 uint32_t
228 DummyAudioBackend::buffer_size () const
229 {
230         return _samples_per_period;
231 }
232
233 bool
234 DummyAudioBackend::interleaved () const
235 {
236         return false;
237 }
238
239 uint32_t
240 DummyAudioBackend::input_channels () const
241 {
242         return _n_inputs;
243 }
244
245 uint32_t
246 DummyAudioBackend::output_channels () const
247 {
248         return _n_outputs;
249 }
250
251 uint32_t
252 DummyAudioBackend::systemic_input_latency () const
253 {
254         return _systemic_input_latency;
255 }
256
257 uint32_t
258 DummyAudioBackend::systemic_output_latency () const
259 {
260         return _systemic_output_latency;
261 }
262
263
264 /* MIDI */
265 std::vector<std::string>
266 DummyAudioBackend::enumerate_midi_options () const
267 {
268         if (_midi_options.empty()) {
269                 _midi_options.push_back (_("1 in, 1 out"));
270                 _midi_options.push_back (_("2 in, 2 out"));
271                 _midi_options.push_back (_("8 in, 8 out"));
272         }
273         return _midi_options;
274 }
275
276 int
277 DummyAudioBackend::set_midi_option (const std::string& opt)
278 {
279         if (opt == _("1 in, 1 out")) {
280                 _n_midi_inputs = _n_midi_outputs = 1;
281         }
282         else if (opt == _("2 in, 2 out")) {
283                 _n_midi_inputs = _n_midi_outputs = 2;
284         }
285         else if (opt == _("8 in, 8 out")) {
286                 _n_midi_inputs = _n_midi_outputs = 8;
287         }
288         else {
289                 _n_midi_inputs = _n_midi_outputs = 0;
290         }
291         return 0;
292 }
293
294 std::string
295 DummyAudioBackend::midi_option () const
296 {
297         return ""; // TODO
298 }
299
300 /* State Control */
301
302 static void * pthread_process (void *arg)
303 {
304         DummyAudioBackend *d = static_cast<DummyAudioBackend *>(arg);
305         d->main_process_thread ();
306         pthread_exit (0);
307         return 0;
308 }
309
310 int
311 DummyAudioBackend::_start (bool /*for_latency_measurement*/)
312 {
313         if (_running) {
314                 PBD::error << _("DummyAudioBackend: already active.") << endmsg;
315                 return -1;
316         }
317
318         if (_ports.size()) {
319                 PBD::warning << _("DummyAudioBackend: recovering from unclean shutdown, port registry is not empty.") << endmsg;
320                 for (std::vector<DummyPort*>::const_iterator it = _ports.begin (); it != _ports.end (); ++it) {
321                         PBD::info << _("DummyAudioBackend: port '") << (*it)->name () << "' exists." << endmsg;
322                 }
323                 _system_inputs.clear();
324                 _ports.clear();
325         }
326
327         if (register_system_ports()) {
328                 PBD::error << _("DummyAudioBackend: failed to register system ports.") << endmsg;
329                 return -1;
330         }
331
332         engine.sample_rate_change (_samplerate);
333         engine.buffer_size_change (_samples_per_period);
334
335         if (engine.reestablish_ports ()) {
336                 PBD::error << _("DummyAudioBackend: Could not re-establish ports.") << endmsg;
337                 stop ();
338                 return -1;
339         }
340
341         engine.reconnect_ports ();
342         _port_change_flag = false;
343
344         if (pthread_create (&_main_thread, NULL, pthread_process, this)) {
345                 PBD::error << _("DummyAudioBackend: cannot start.") << endmsg;
346         }
347
348         int timeout = 5000;
349         while (!_running && --timeout > 0) { Glib::usleep (1000); }
350
351         if (timeout == 0 || !_running) {
352                 PBD::error << _("DummyAudioBackend: failed to start process thread.") << endmsg;
353                 return -1;
354         }
355
356         return 0;
357 }
358
359 int
360 DummyAudioBackend::stop ()
361 {
362         void *status;
363         if (!_running) {
364                 return 0;
365         }
366
367         _running = false;
368         if (pthread_join (_main_thread, &status)) {
369                 PBD::error << _("DummyAudioBackend: failed to terminate.") << endmsg;
370                 return -1;
371         }
372         unregister_ports();
373         return 0;
374 }
375
376 int
377 DummyAudioBackend::freewheel (bool onoff)
378 {
379         if (onoff == _freewheeling) {
380                 return 0;
381         }
382         _freewheeling = onoff;
383         engine.freewheel_callback (onoff);
384         return 0;
385 }
386
387 float
388 DummyAudioBackend::dsp_load () const
389 {
390         return 100.f * _dsp_load;
391 }
392
393 size_t
394 DummyAudioBackend::raw_buffer_size (DataType t)
395 {
396         switch (t) {
397                 case DataType::AUDIO:
398                         return _samples_per_period * sizeof(Sample);
399                 case DataType::MIDI:
400                         return _max_buffer_size; // XXX not really limited
401         }
402         return 0;
403 }
404
405 /* Process time */
406 pframes_t
407 DummyAudioBackend::sample_time ()
408 {
409         return _processed_samples;
410 }
411
412 pframes_t
413 DummyAudioBackend::sample_time_at_cycle_start ()
414 {
415         return _processed_samples;
416 }
417
418 pframes_t
419 DummyAudioBackend::samples_since_cycle_start ()
420 {
421         return 0;
422 }
423
424
425 void *
426 DummyAudioBackend::dummy_process_thread (void *arg)
427 {
428         ThreadData* td = reinterpret_cast<ThreadData*> (arg);
429         boost::function<void ()> f = td->f;
430         delete td;
431         f ();
432         return 0;
433 }
434
435 int
436 DummyAudioBackend::create_process_thread (boost::function<void()> func)
437 {
438         pthread_t thread_id;
439         pthread_attr_t attr;
440         size_t stacksize = 100000;
441
442         pthread_attr_init (&attr);
443         pthread_attr_setstacksize (&attr, stacksize);
444         ThreadData* td = new ThreadData (this, func, stacksize);
445
446         if (pthread_create (&thread_id, &attr, dummy_process_thread, td)) {
447                 PBD::error << _("AudioEngine: cannot create process thread.") << endmsg;
448                 pthread_attr_destroy (&attr);
449                 return -1;
450         }
451         pthread_attr_destroy (&attr);
452
453         _threads.push_back (thread_id);
454         return 0;
455 }
456
457 int
458 DummyAudioBackend::join_process_threads ()
459 {
460         int rv = 0;
461
462         for (std::vector<pthread_t>::const_iterator i = _threads.begin (); i != _threads.end (); ++i)
463         {
464                 void *status;
465                 if (pthread_join (*i, &status)) {
466                         PBD::error << _("AudioEngine: cannot terminate process thread.") << endmsg;
467                         rv -= 1;
468                 }
469         }
470         _threads.clear ();
471         return rv;
472 }
473
474 bool
475 DummyAudioBackend::in_process_thread ()
476 {
477         for (std::vector<pthread_t>::const_iterator i = _threads.begin (); i != _threads.end (); ++i)
478         {
479                 if (pthread_equal (*i, pthread_self ()) != 0) {
480                         return true;
481                 }
482         }
483         return false;
484 }
485
486 uint32_t
487 DummyAudioBackend::process_thread_count ()
488 {
489         return _threads.size ();
490 }
491
492 void
493 DummyAudioBackend::update_latencies ()
494 {
495         // trigger latency callback in RT thread (locked graph)
496         port_connect_add_remove_callback();
497 }
498
499 /* PORTENGINE API */
500
501 void*
502 DummyAudioBackend::private_handle () const
503 {
504         return NULL;
505 }
506
507 const std::string&
508 DummyAudioBackend::my_name () const
509 {
510         return _instance_name;
511 }
512
513 bool
514 DummyAudioBackend::available () const
515 {
516         return true;
517 }
518
519 uint32_t
520 DummyAudioBackend::port_name_size () const
521 {
522         return 256;
523 }
524
525 int
526 DummyAudioBackend::set_port_name (PortEngine::PortHandle port, const std::string& name)
527 {
528         if (!valid_port (port)) {
529                 PBD::error << _("DummyBackend::set_port_name: Invalid Port(s)") << endmsg;
530                 return -1;
531         }
532         return static_cast<DummyPort*>(port)->set_name (_instance_name + ":" + name);
533 }
534
535 std::string
536 DummyAudioBackend::get_port_name (PortEngine::PortHandle port) const
537 {
538         if (!valid_port (port)) {
539                 PBD::error << _("DummyBackend::get_port_name: Invalid Port(s)") << endmsg;
540                 return std::string ();
541         }
542         return static_cast<DummyPort*>(port)->name ();
543 }
544
545 PortEngine::PortHandle
546 DummyAudioBackend::get_port_by_name (const std::string& name) const
547 {
548         PortHandle port = (PortHandle) find_port (name);
549         return port;
550 }
551
552 int
553 DummyAudioBackend::get_ports (
554                 const std::string& port_name_pattern,
555                 DataType type, PortFlags flags,
556                 std::vector<std::string>& port_names) const
557 {
558         int rv = 0;
559         regex_t port_regex;
560         bool use_regexp = false;
561         if (port_name_pattern.size () > 0) {
562                 if (!regcomp (&port_regex, port_name_pattern.c_str (), REG_EXTENDED|REG_NOSUB)) {
563                         use_regexp = true;
564                 }
565         }
566         for (size_t i = 0; i < _ports.size (); ++i) {
567                 DummyPort* port = _ports[i];
568                 if ((port->type () == type) && (port->flags () & flags)) {
569                         if (!use_regexp || !regexec (&port_regex, port->name ().c_str (), 0, NULL, 0)) {
570                                 port_names.push_back (port->name ());
571                                 ++rv;
572                         }
573                 }
574         }
575         if (use_regexp) {
576                 regfree (&port_regex);
577         }
578         return rv;
579 }
580
581 DataType
582 DummyAudioBackend::port_data_type (PortEngine::PortHandle port) const
583 {
584         if (!valid_port (port)) {
585                 return DataType::NIL;
586         }
587         return static_cast<DummyPort*>(port)->type ();
588 }
589
590 PortEngine::PortHandle
591 DummyAudioBackend::register_port (
592                 const std::string& name,
593                 ARDOUR::DataType type,
594                 ARDOUR::PortFlags flags)
595 {
596         if (name.size () == 0) { return 0; }
597         if (flags & IsPhysical) { return 0; }
598         return add_port (_instance_name + ":" + name, type, flags);
599 }
600
601 PortEngine::PortHandle
602 DummyAudioBackend::add_port (
603                 const std::string& name,
604                 ARDOUR::DataType type,
605                 ARDOUR::PortFlags flags)
606 {
607         assert(name.size ());
608         if (find_port (name)) {
609                 PBD::error << _("DummyBackend::register_port: Port already exists:")
610                                 << " (" << name << ")" << endmsg;
611                 return 0;
612         }
613         DummyPort* port = NULL;
614         switch (type) {
615                 case DataType::AUDIO:
616                         port = new DummyAudioPort (*this, name, flags);
617                         break;
618                 case DataType::MIDI:
619                         port = new DummyMidiPort (*this, name, flags);
620                         break;
621                 default:
622                         PBD::error << _("DummyBackend::register_port: Invalid Data Type.") << endmsg;
623                         return 0;
624         }
625
626         _ports.push_back (port);
627
628         return port;
629 }
630
631 void
632 DummyAudioBackend::unregister_port (PortEngine::PortHandle port_handle)
633 {
634         if (!valid_port (port_handle)) {
635                 PBD::error << _("DummyBackend::unregister_port: Invalid Port.") << endmsg;
636         }
637         DummyPort* port = static_cast<DummyPort*>(port_handle);
638         std::vector<DummyPort*>::iterator i = std::find (_ports.begin (), _ports.end (), static_cast<DummyPort*>(port_handle));
639         if (i == _ports.end ()) {
640                 PBD::error << _("DummyBackend::unregister_port: Failed to find port") << endmsg;
641                 return;
642         }
643         disconnect_all(port_handle);
644         _ports.erase (i);
645         delete port;
646 }
647
648 int
649 DummyAudioBackend::register_system_ports()
650 {
651         LatencyRange lr;
652         enum DummyAudioPort::GeneratorType gt;
653         if (_device == _("Uniform White Noise")) {
654                 gt = DummyAudioPort::UniformWhiteNoise;
655         } else if (_device == _("Gaussian White Noise")) {
656                 gt = DummyAudioPort::GaussianWhiteNoise;
657         } else if (_device == _("Pink Noise")) {
658                 gt = DummyAudioPort::PinkNoise;
659         } else if (_device == _("Pink Noise (low CPU)")) {
660                 gt = DummyAudioPort::PonyNoise;
661         } else if (_device == _("Sine Wave")) {
662                 gt = DummyAudioPort::SineWave;
663         } else {
664                 gt = DummyAudioPort::Silence;
665         }
666
667         const int a_ins = _n_inputs > 0 ? _n_inputs : 8;
668         const int a_out = _n_outputs > 0 ? _n_outputs : 8;
669         const int m_ins = _n_midi_inputs > 0 ? _n_midi_inputs : 2;
670         const int m_out = _n_midi_outputs > 0 ? _n_midi_outputs : 2;
671
672         /* audio ports */
673         lr.min = lr.max = _samples_per_period + _systemic_input_latency;
674         for (int i = 1; i <= a_ins; ++i) {
675                 char tmp[64];
676                 snprintf(tmp, sizeof(tmp), "system:capture_%d", i);
677                 PortHandle p = add_port(std::string(tmp), DataType::AUDIO, static_cast<PortFlags>(IsOutput | IsPhysical | IsTerminal));
678                 if (!p) return -1;
679                 set_latency_range (p, false, lr);
680                 _system_inputs.push_back (static_cast<DummyAudioPort*>(p));
681                 static_cast<DummyAudioPort*>(p)->setup_generator (gt, _samplerate);
682         }
683
684         lr.min = lr.max = _samples_per_period + _systemic_output_latency;
685         for (int i = 1; i <= a_out; ++i) {
686                 char tmp[64];
687                 snprintf(tmp, sizeof(tmp), "system:playback_%d", i);
688                 PortHandle p = add_port(std::string(tmp), DataType::AUDIO, static_cast<PortFlags>(IsInput | IsPhysical | IsTerminal));
689                 if (!p) return -1;
690                 set_latency_range (p, true, lr);
691         }
692
693         /* midi ports */
694         lr.min = lr.max = _samples_per_period + _systemic_input_latency;
695         for (int i = 1; i <= m_ins; ++i) {
696                 char tmp[64];
697                 snprintf(tmp, sizeof(tmp), "system:midi_capture_%d", i);
698                 PortHandle p = add_port(std::string(tmp), DataType::MIDI, static_cast<PortFlags>(IsOutput | IsPhysical | IsTerminal));
699                 if (!p) return -1;
700                 set_latency_range (p, false, lr);
701         }
702
703         lr.min = lr.max = _samples_per_period + _systemic_output_latency;
704         for (int i = 1; i <= m_out; ++i) {
705                 char tmp[64];
706                 snprintf(tmp, sizeof(tmp), "system:midi_playback_%d", i);
707                 PortHandle p = add_port(std::string(tmp), DataType::MIDI, static_cast<PortFlags>(IsInput | IsPhysical | IsTerminal));
708                 if (!p) return -1;
709                 set_latency_range (p, true, lr);
710         }
711         return 0;
712 }
713
714 void
715 DummyAudioBackend::unregister_ports (bool system_only)
716 {
717         size_t i = 0;
718         _system_inputs.clear();
719         while (i <  _ports.size ()) {
720                 DummyPort* port = _ports[i];
721                 if (! system_only || (port->is_physical () && port->is_terminal ())) {
722                         port->disconnect_all ();
723                         delete port;
724                         _ports.erase (_ports.begin() + i);
725                 } else {
726                         ++i;
727                 }
728         }
729 }
730
731 int
732 DummyAudioBackend::connect (const std::string& src, const std::string& dst)
733 {
734         DummyPort* src_port = find_port (src);
735         DummyPort* dst_port = find_port (dst);
736
737         if (!src_port) {
738                 PBD::error << _("DummyBackend::connect: Invalid Source port:")
739                                 << " (" << src <<")" << endmsg;
740                 return -1;
741         }
742         if (!dst_port) {
743                 PBD::error << _("DummyBackend::connect: Invalid Destination port:")
744                         << " (" << dst <<")" << endmsg;
745                 return -1;
746         }
747         return src_port->connect (dst_port);
748 }
749
750 int
751 DummyAudioBackend::disconnect (const std::string& src, const std::string& dst)
752 {
753         DummyPort* src_port = find_port (src);
754         DummyPort* dst_port = find_port (dst);
755
756         if (!src_port || !dst_port) {
757                 PBD::error << _("DummyBackend::disconnect: Invalid Port(s)") << endmsg;
758                 return -1;
759         }
760         return src_port->disconnect (dst_port);
761 }
762
763 int
764 DummyAudioBackend::connect (PortEngine::PortHandle src, const std::string& dst)
765 {
766         DummyPort* dst_port = find_port (dst);
767         if (!valid_port (src)) {
768                 PBD::error << _("DummyBackend::connect: Invalid Source Port Handle") << endmsg;
769                 return -1;
770         }
771         if (!dst_port) {
772                 PBD::error << _("DummyBackend::connect: Invalid Destination Port")
773                         << " (" << dst << ")" << endmsg;
774                 return -1;
775         }
776         return static_cast<DummyPort*>(src)->connect (dst_port);
777 }
778
779 int
780 DummyAudioBackend::disconnect (PortEngine::PortHandle src, const std::string& dst)
781 {
782         DummyPort* dst_port = find_port (dst);
783         if (!valid_port (src) || !dst_port) {
784                 PBD::error << _("DummyBackend::disconnect: Invalid Port(s)") << endmsg;
785                 return -1;
786         }
787         return static_cast<DummyPort*>(src)->disconnect (dst_port);
788 }
789
790 int
791 DummyAudioBackend::disconnect_all (PortEngine::PortHandle port)
792 {
793         if (!valid_port (port)) {
794                 PBD::error << _("DummyBackend::disconnect_all: Invalid Port") << endmsg;
795                 return -1;
796         }
797         static_cast<DummyPort*>(port)->disconnect_all ();
798         return 0;
799 }
800
801 bool
802 DummyAudioBackend::connected (PortEngine::PortHandle port, bool /* process_callback_safe*/)
803 {
804         if (!valid_port (port)) {
805                 PBD::error << _("DummyBackend::disconnect_all: Invalid Port") << endmsg;
806                 return false;
807         }
808         return static_cast<DummyPort*>(port)->is_connected ();
809 }
810
811 bool
812 DummyAudioBackend::connected_to (PortEngine::PortHandle src, const std::string& dst, bool /*process_callback_safe*/)
813 {
814         DummyPort* dst_port = find_port (dst);
815         if (!valid_port (src) || !dst_port) {
816                 PBD::error << _("DummyBackend::connected_to: Invalid Port") << endmsg;
817                 return false;
818         }
819         return static_cast<DummyPort*>(src)->is_connected (dst_port);
820 }
821
822 bool
823 DummyAudioBackend::physically_connected (PortEngine::PortHandle port, bool /*process_callback_safe*/)
824 {
825         if (!valid_port (port)) {
826                 PBD::error << _("DummyBackend::physically_connected: Invalid Port") << endmsg;
827                 return false;
828         }
829         return static_cast<DummyPort*>(port)->is_physically_connected ();
830 }
831
832 int
833 DummyAudioBackend::get_connections (PortEngine::PortHandle port, std::vector<std::string>& names, bool /*process_callback_safe*/)
834 {
835         if (!valid_port (port)) {
836                 PBD::error << _("DummyBackend::get_connections: Invalid Port") << endmsg;
837                 return -1;
838         }
839
840         assert (0 == names.size ());
841
842         const std::vector<DummyPort*>& connected_ports = static_cast<DummyPort*>(port)->get_connections ();
843
844         for (std::vector<DummyPort*>::const_iterator i = connected_ports.begin (); i != connected_ports.end (); ++i) {
845                 names.push_back ((*i)->name ());
846         }
847
848         return (int)names.size ();
849 }
850
851 /* MIDI */
852 int
853 DummyAudioBackend::midi_event_get (
854                 pframes_t& timestamp,
855                 size_t& size, uint8_t** buf, void* port_buffer,
856                 uint32_t event_index)
857 {
858         assert (buf && port_buffer);
859         DummyMidiBuffer& source = * static_cast<DummyMidiBuffer*>(port_buffer);
860         if (event_index >= source.size ()) {
861                 return -1;
862         }
863         DummyMidiEvent * const event = source[event_index].get ();
864
865         timestamp = event->timestamp ();
866         size = event->size ();
867         *buf = event->data ();
868         return 0;
869 }
870
871 int
872 DummyAudioBackend::midi_event_put (
873                 void* port_buffer,
874                 pframes_t timestamp,
875                 const uint8_t* buffer, size_t size)
876 {
877         assert (buffer && port_buffer);
878         DummyMidiBuffer& dst = * static_cast<DummyMidiBuffer*>(port_buffer);
879         if (dst.size () && (pframes_t)dst.back ()->timestamp () > timestamp) {
880                 fprintf (stderr, "DummyMidiBuffer: it's too late for this event.\n");
881                 return -1;
882         }
883         dst.push_back (boost::shared_ptr<DummyMidiEvent>(new DummyMidiEvent (timestamp, buffer, size)));
884         return 0;
885 }
886
887 uint32_t
888 DummyAudioBackend::get_midi_event_count (void* port_buffer)
889 {
890         assert (port_buffer);
891         return static_cast<DummyMidiBuffer*>(port_buffer)->size ();
892 }
893
894 void
895 DummyAudioBackend::midi_clear (void* port_buffer)
896 {
897         assert (port_buffer);
898         DummyMidiBuffer * buf = static_cast<DummyMidiBuffer*>(port_buffer);
899         assert (buf);
900         buf->clear ();
901 }
902
903 /* Monitoring */
904
905 bool
906 DummyAudioBackend::can_monitor_input () const
907 {
908         return false;
909 }
910
911 int
912 DummyAudioBackend::request_input_monitoring (PortEngine::PortHandle, bool)
913 {
914         return -1;
915 }
916
917 int
918 DummyAudioBackend::ensure_input_monitoring (PortEngine::PortHandle, bool)
919 {
920         return -1;
921 }
922
923 bool
924 DummyAudioBackend::monitoring_input (PortEngine::PortHandle)
925 {
926         return false;
927 }
928
929 /* Latency management */
930
931 void
932 DummyAudioBackend::set_latency_range (PortEngine::PortHandle port, bool for_playback, LatencyRange latency_range)
933 {
934         if (!valid_port (port)) {
935                 PBD::error << _("DummyPort::set_latency_range (): invalid port.") << endmsg;
936         }
937         static_cast<DummyPort*>(port)->set_latency_range (latency_range, for_playback);
938 }
939
940 LatencyRange
941 DummyAudioBackend::get_latency_range (PortEngine::PortHandle port, bool for_playback)
942 {
943         if (!valid_port (port)) {
944                 PBD::error << _("DummyPort::get_latency_range (): invalid port.") << endmsg;
945                 LatencyRange r;
946                 r.min = 0;
947                 r.max = 0;
948                 return r;
949         }
950         return static_cast<DummyPort*>(port)->latency_range (for_playback);
951 }
952
953 /* Discovering physical ports */
954
955 bool
956 DummyAudioBackend::port_is_physical (PortEngine::PortHandle port) const
957 {
958         if (!valid_port (port)) {
959                 PBD::error << _("DummyPort::port_is_physical (): invalid port.") << endmsg;
960                 return false;
961         }
962         return static_cast<DummyPort*>(port)->is_physical ();
963 }
964
965 void
966 DummyAudioBackend::get_physical_outputs (DataType type, std::vector<std::string>& port_names)
967 {
968         for (size_t i = 0; i < _ports.size (); ++i) {
969                 DummyPort* port = _ports[i];
970                 if ((port->type () == type) && port->is_input () && port->is_physical ()) {
971                         port_names.push_back (port->name ());
972                 }
973         }
974 }
975
976 void
977 DummyAudioBackend::get_physical_inputs (DataType type, std::vector<std::string>& port_names)
978 {
979         for (size_t i = 0; i < _ports.size (); ++i) {
980                 DummyPort* port = _ports[i];
981                 if ((port->type () == type) && port->is_output () && port->is_physical ()) {
982                         port_names.push_back (port->name ());
983                 }
984         }
985 }
986
987 ChanCount
988 DummyAudioBackend::n_physical_outputs () const
989 {
990         int n_midi = 0;
991         int n_audio = 0;
992         for (size_t i = 0; i < _ports.size (); ++i) {
993                 DummyPort* port = _ports[i];
994                 if (port->is_output () && port->is_physical ()) {
995                         switch (port->type ()) {
996                                 case DataType::AUDIO: ++n_audio; break;
997                                 case DataType::MIDI: ++n_midi; break;
998                                 default: break;
999                         }
1000                 }
1001         }
1002         ChanCount cc;
1003         cc.set (DataType::AUDIO, n_audio);
1004         cc.set (DataType::MIDI, n_midi);
1005         return cc;
1006 }
1007
1008 ChanCount
1009 DummyAudioBackend::n_physical_inputs () const
1010 {
1011         int n_midi = 0;
1012         int n_audio = 0;
1013         for (size_t i = 0; i < _ports.size (); ++i) {
1014                 DummyPort* port = _ports[i];
1015                 if (port->is_input () && port->is_physical ()) {
1016                         switch (port->type ()) {
1017                                 case DataType::AUDIO: ++n_audio; break;
1018                                 case DataType::MIDI: ++n_midi; break;
1019                                 default: break;
1020                         }
1021                 }
1022         }
1023         ChanCount cc;
1024         cc.set (DataType::AUDIO, n_audio);
1025         cc.set (DataType::MIDI, n_midi);
1026         return cc;
1027 }
1028
1029 /* Getting access to the data buffer for a port */
1030
1031 void*
1032 DummyAudioBackend::get_buffer (PortEngine::PortHandle port, pframes_t nframes)
1033 {
1034         assert (port);
1035         assert (valid_port (port));
1036         return static_cast<DummyPort*>(port)->get_buffer (nframes);
1037 }
1038
1039 /* Engine Process */
1040 void *
1041 DummyAudioBackend::main_process_thread ()
1042 {
1043         AudioEngine::thread_init_callback (this);
1044         _running = true;
1045         _processed_samples = 0;
1046
1047         manager.registration_callback();
1048         manager.graph_order_callback();
1049
1050         uint64_t clock1, clock2;
1051         clock1 = g_get_monotonic_time();
1052         while (_running) {
1053
1054                 // re-set input buffers, generate on demand.
1055                 for (std::vector<DummyAudioPort*>::const_iterator it = _system_inputs.begin (); it != _system_inputs.end (); ++it) {
1056                         (*it)->next_period();
1057                 }
1058
1059                 if (engine.process_callback (_samples_per_period)) {
1060                         return 0;
1061                 }
1062                 _processed_samples += _samples_per_period;
1063                 if (!_freewheeling) {
1064                         clock2 = g_get_monotonic_time();
1065                         const int64_t elapsed_time = clock2 - clock1;
1066                         const int64_t nomial_time = 1e6 * _samples_per_period / _samplerate;
1067                         _dsp_load = elapsed_time / (float) nomial_time;
1068                         if (elapsed_time < nomial_time) {
1069                                 Glib::usleep (nomial_time - elapsed_time);
1070                         } else {
1071                                 Glib::usleep (100); // don't hog cpu
1072                         }
1073                 } else {
1074                         _dsp_load = 1.0;
1075                         Glib::usleep (100); // don't hog cpu
1076                 }
1077                 clock1 = g_get_monotonic_time();
1078
1079                 bool connections_changed = false;
1080                 bool ports_changed = false;
1081                 if (!pthread_mutex_trylock (&_port_callback_mutex)) {
1082                         if (_port_change_flag) {
1083                                 ports_changed = true;
1084                                 _port_change_flag = false;
1085                         }
1086                         if (!_port_connection_queue.empty ()) {
1087                                 connections_changed = true;
1088                         }
1089                         while (!_port_connection_queue.empty ()) {
1090                                 PortConnectData *c = _port_connection_queue.back ();
1091                                 manager.connect_callback (c->a, c->b, c->c);
1092                                 _port_connection_queue.pop_back ();
1093                                 delete c;
1094                         }
1095                         pthread_mutex_unlock (&_port_callback_mutex);
1096                 }
1097                 if (ports_changed) {
1098                         manager.registration_callback();
1099                 }
1100                 if (connections_changed) {
1101                         manager.graph_order_callback();
1102                 }
1103                 if (connections_changed || ports_changed) {
1104                         engine.latency_callback(false);
1105                         engine.latency_callback(true);
1106                 }
1107
1108         }
1109         _running = false;
1110         return 0;
1111 }
1112
1113
1114 /******************************************************************************/
1115
1116 static boost::shared_ptr<DummyAudioBackend> _instance;
1117
1118 static boost::shared_ptr<AudioBackend> backend_factory (AudioEngine& e);
1119 static int instantiate (const std::string& arg1, const std::string& /* arg2 */);
1120 static int deinstantiate ();
1121 static bool already_configured ();
1122
1123 static ARDOUR::AudioBackendInfo _descriptor = {
1124         "Dummy",
1125         instantiate,
1126         deinstantiate,
1127         backend_factory,
1128         already_configured,
1129 };
1130
1131 static boost::shared_ptr<AudioBackend>
1132 backend_factory (AudioEngine& e)
1133 {
1134         if (!_instance) {
1135                 _instance.reset (new DummyAudioBackend (e, _descriptor));
1136         }
1137         return _instance;
1138 }
1139
1140 static int
1141 instantiate (const std::string& arg1, const std::string& /* arg2 */)
1142 {
1143         s_instance_name = arg1;
1144         return 0;
1145 }
1146
1147 static int
1148 deinstantiate ()
1149 {
1150         _instance.reset ();
1151         return 0;
1152 }
1153
1154 static bool
1155 already_configured ()
1156 {
1157         return false;
1158 }
1159
1160 extern "C" ARDOURBACKEND_API ARDOUR::AudioBackendInfo* descriptor ()
1161 {
1162         return &_descriptor;
1163 }
1164
1165
1166 /******************************************************************************/
1167 DummyPort::DummyPort (DummyAudioBackend &b, const std::string& name, PortFlags flags)
1168         : _dummy_backend (b)
1169         , _name  (name)
1170         , _flags (flags)
1171 {
1172         _capture_latency_range.min = 0;
1173         _capture_latency_range.max = 0;
1174         _playback_latency_range.min = 0;
1175         _playback_latency_range.max = 0;
1176         _dummy_backend.port_connect_add_remove_callback();
1177 }
1178
1179 DummyPort::~DummyPort () {
1180         disconnect_all ();
1181         _dummy_backend.port_connect_add_remove_callback();
1182 }
1183
1184
1185 int DummyPort::connect (DummyPort *port)
1186 {
1187         if (!port) {
1188                 PBD::error << _("DummyPort::connect (): invalid (null) port") << endmsg;
1189                 return -1;
1190         }
1191
1192         if (type () != port->type ()) {
1193                 PBD::error << _("DummyPort::connect (): wrong port-type") << endmsg;
1194                 return -1;
1195         }
1196
1197         if (is_output () && port->is_output ()) {
1198                 PBD::error << _("DummyPort::connect (): cannot inter-connect output ports.") << endmsg;
1199                 return -1;
1200         }
1201
1202         if (is_input () && port->is_input ()) {
1203                 PBD::error << _("DummyPort::connect (): cannot inter-connect input ports.") << endmsg;
1204                 return -1;
1205         }
1206
1207         if (this == port) {
1208                 PBD::error << _("DummyPort::connect (): cannot self-connect ports.") << endmsg;
1209                 return -1;
1210         }
1211
1212         if (is_connected (port)) {
1213 #if 0 // don't bother to warn about this for now. just ignore it
1214                 PBD::error << _("DummyPort::connect (): ports are already connected:")
1215                         << " (" << name () << ") -> (" << port->name () << ")"
1216                         << endmsg;
1217 #endif
1218                 return -1;
1219         }
1220
1221         _connect (port, true);
1222         return 0;
1223 }
1224
1225
1226 void DummyPort::_connect (DummyPort *port, bool callback)
1227 {
1228         _connections.push_back (port);
1229         if (callback) {
1230                 port->_connect (this, false);
1231                 _dummy_backend.port_connect_callback (name(),  port->name(), true);
1232         }
1233 }
1234
1235 int DummyPort::disconnect (DummyPort *port)
1236 {
1237         if (!port) {
1238                 PBD::error << _("DummyPort::disconnect (): invalid (null) port") << endmsg;
1239                 return -1;
1240         }
1241
1242         if (!is_connected (port)) {
1243                 PBD::error << _("DummyPort::disconnect (): ports are not connected:")
1244                         << " (" << name () << ") -> (" << port->name () << ")"
1245                         << endmsg;
1246                 return -1;
1247         }
1248         _disconnect (port, true);
1249         return 0;
1250 }
1251
1252 void DummyPort::_disconnect (DummyPort *port, bool callback)
1253 {
1254         std::vector<DummyPort*>::iterator it = std::find (_connections.begin (), _connections.end (), port);
1255
1256         assert (it != _connections.end ());
1257
1258         _connections.erase (it);
1259
1260         if (callback) {
1261                 port->_disconnect (this, false);
1262                 _dummy_backend.port_connect_callback (name(),  port->name(), false);
1263         }
1264 }
1265
1266
1267 void DummyPort::disconnect_all ()
1268 {
1269         while (!_connections.empty ()) {
1270                 _connections.back ()->_disconnect (this, false);
1271                 _dummy_backend.port_connect_callback (name(),  _connections.back ()->name(), false);
1272                 _connections.pop_back ();
1273         }
1274 }
1275
1276 bool
1277 DummyPort::is_connected (const DummyPort *port) const
1278 {
1279         return std::find (_connections.begin (), _connections.end (), port) != _connections.end ();
1280 }
1281
1282 bool DummyPort::is_physically_connected () const
1283 {
1284         for (std::vector<DummyPort*>::const_iterator it = _connections.begin (); it != _connections.end (); ++it) {
1285                 if ((*it)->is_physical ()) {
1286                         return true;
1287                 }
1288         }
1289         return false;
1290 }
1291
1292 /******************************************************************************/
1293
1294 DummyAudioPort::DummyAudioPort (DummyAudioBackend &b, const std::string& name, PortFlags flags)
1295         : DummyPort (b, name, flags)
1296         , _gen_type (Silence)
1297         , _gen_cycle (false)
1298         , _b0 (0)
1299         , _b1 (0)
1300         , _b2 (0)
1301         , _b3 (0)
1302         , _b4 (0)
1303         , _b5 (0)
1304         , _b6 (0)
1305         , _wavetable (0)
1306         , _tbl_length (0)
1307         , _tbl_offset (0)
1308         , _pass (false)
1309         , _rn1 (0)
1310 {
1311         memset (_buffer, 0, sizeof (_buffer));
1312 }
1313
1314 DummyAudioPort::~DummyAudioPort () {
1315         free(_wavetable);
1316         _wavetable = 0;
1317 }
1318
1319 void DummyAudioPort::setup_generator (GeneratorType const g, float const samplerate)
1320 {
1321         _gen_type = g;
1322         _rseed = g_get_monotonic_time() % UINT_MAX;
1323
1324         switch (_gen_type) {
1325                 case PinkNoise:
1326                 case PonyNoise:
1327                 case UniformWhiteNoise:
1328                 case GaussianWhiteNoise:
1329                 case Silence:
1330                         break;
1331                 case SineWave:
1332                         {
1333                                 _tbl_length = 5 + randi() % (int)(samplerate / 20.f);
1334                                 _wavetable = (Sample*) malloc( _tbl_length * sizeof(Sample));
1335                                 for (uint32_t i = 0 ; i < _tbl_length; ++i) {
1336                                         _wavetable[i] = .12589f * sinf(2.0 * M_PI * (float)i / (float)_tbl_length);
1337                                 }
1338                         }
1339                         break;
1340         }
1341 }
1342
1343 inline uint32_t
1344 DummyAudioPort::randi ()
1345 {
1346         // 31bit Park-Miller-Carta Pseudo-Random Number Generator
1347         // http://www.firstpr.com.au/dsp/rand31/
1348         uint32_t hi, lo;
1349         lo = 16807 * (_rseed & 0xffff);
1350         hi = 16807 * (_rseed >> 16);
1351
1352         lo += (hi & 0x7fff) << 16;
1353         lo += hi >> 15;
1354 #if 1
1355         lo = (lo & 0x7fffffff) + (lo >> 31);
1356 #else
1357         if (lo > 0x7fffffff) { lo -= 0x7fffffff; }
1358 #endif
1359         return (_rseed = lo);
1360 }
1361
1362 inline float
1363 DummyAudioPort::randf ()
1364 {
1365         return (randi() / 1073741824.f) - 1.f;
1366 }
1367
1368 float DummyAudioPort::grandf ()
1369 {
1370         // Gaussian White Noise
1371         // http://www.musicdsp.org/archive.php?classid=0#109
1372         float x1, x2, r;
1373
1374         if (_pass) {
1375                 _pass = false;
1376                 return _rn1;
1377         }
1378
1379         do {
1380                 x1 = randf ();
1381                 x2 = randf ();
1382                 r = x1 * x1 + x2 * x2;
1383         } while ((r >= 1.0f) || (r < 1e-22f));
1384
1385         r = sqrtf (-2.f * logf (r) / r);
1386
1387         _pass = true;
1388         _rn1 = r * x2;
1389         return r * x1;
1390 }
1391
1392 void DummyAudioPort::generate (const pframes_t n_samples)
1393 {
1394         Glib::Threads::Mutex::Lock lm (generator_lock);
1395         if (_gen_cycle) {
1396                 return;
1397         }
1398
1399         switch (_gen_type) {
1400                 case Silence:
1401                         memset (_buffer, 0, n_samples * sizeof (Sample));
1402                         break;
1403                 case SineWave:
1404                         assert(_wavetable && _tbl_length > 0);
1405                         {
1406                                 pframes_t written = 0;
1407                                 while (written < n_samples) {
1408                                         const uint32_t remain = n_samples - written;
1409                                         const uint32_t to_copy = std::min(remain, _tbl_length - _tbl_offset);
1410                                         memcpy((void*)&_buffer[written],
1411                                                         (void*)&_wavetable[_tbl_offset],
1412                                                         to_copy * sizeof(Sample));
1413                                         written += to_copy;
1414                                         _tbl_offset = (_tbl_offset + to_copy) % _tbl_length;
1415                                 }
1416                         }
1417                         break;
1418                 case UniformWhiteNoise:
1419                         for (pframes_t i = 0 ; i < n_samples; ++i) {
1420                                 _buffer[i] = .158489f * randf();
1421                         }
1422                         break;
1423                 case GaussianWhiteNoise:
1424                         for (pframes_t i = 0 ; i < n_samples; ++i) {
1425                                 _buffer[i] = .089125f * grandf();
1426                         }
1427                         break;
1428                 case PinkNoise:
1429                         for (pframes_t i = 0 ; i < n_samples; ++i) {
1430                                 // Paul Kellet's refined method
1431                                 // http://www.musicdsp.org/files/pink.txt
1432                                 // NB. If 'white' consists of uniform random numbers,
1433                                 // the pink noise will have an almost gaussian distribution.
1434                                 const float white = .0498f * randf ();
1435                                 _b0 = .99886f * _b0 + white * .0555179f;
1436                                 _b1 = .99332f * _b1 + white * .0750759f;
1437                                 _b2 = .96900f * _b2 + white * .1538520f;
1438                                 _b3 = .86650f * _b3 + white * .3104856f;
1439                                 _b4 = .55000f * _b4 + white * .5329522f;
1440                                 _b5 = -.7616f * _b5 - white * .0168980f;
1441                                 _buffer[i] = _b0 + _b1 + _b2 + _b3 + _b4 + _b5 + _b6 + white * 0.5362;
1442                                 _b6 = white * 0.115926;
1443                         }
1444                         break;
1445                 case PonyNoise:
1446                         for (pframes_t i = 0 ; i < n_samples; ++i) {
1447                                 const float white = 0.0498f * randf ();
1448                                 // Paul Kellet's economy method
1449                                 // http://www.musicdsp.org/files/pink.txt
1450                                 _b0 = 0.99765 * _b0 + white * 0.0990460;
1451                                 _b1 = 0.96300 * _b1 + white * 0.2965164;
1452                                 _b2 = 0.57000 * _b2 + white * 1.0526913;
1453                                 _buffer[i] = _b0 + _b1 + _b2 + white * 0.1848;
1454                         }
1455                         break;
1456         }
1457         _gen_cycle = true;
1458 }
1459
1460 void* DummyAudioPort::get_buffer (pframes_t n_samples)
1461 {
1462         if (is_input ()) {
1463                 std::vector<DummyPort*>::const_iterator it = get_connections ().begin ();
1464                 if (it == get_connections ().end ()) {
1465                         memset (_buffer, 0, n_samples * sizeof (Sample));
1466                 } else {
1467                         DummyAudioPort * source = static_cast<DummyAudioPort*>(*it);
1468                         assert (source && source->is_output ());
1469                         if (source->is_physical() && source->is_terminal()) {
1470                                 source->get_buffer(n_samples); // generate signal.
1471                         }
1472                         memcpy (_buffer, source->const_buffer (), n_samples * sizeof (Sample));
1473                         while (++it != get_connections ().end ()) {
1474                                 source = static_cast<DummyAudioPort*>(*it);
1475                                 assert (source && source->is_output ());
1476                                 Sample* dst = buffer ();
1477                                 if (source->is_physical() && source->is_terminal()) {
1478                                         source->get_buffer(n_samples); // generate signal.
1479                                 }
1480                                 const Sample* src = source->const_buffer ();
1481                                 for (uint32_t s = 0; s < n_samples; ++s, ++dst, ++src) {
1482                                         *dst += *src;
1483                                 }
1484                         }
1485                 }
1486         } else if (is_output () && is_physical () && is_terminal()) {
1487                 if (!_gen_cycle) {
1488                         generate(n_samples);
1489                 }
1490         }
1491         return _buffer;
1492 }
1493
1494
1495 DummyMidiPort::DummyMidiPort (DummyAudioBackend &b, const std::string& name, PortFlags flags)
1496         : DummyPort (b, name, flags)
1497 {
1498         _buffer.clear ();
1499 }
1500
1501 DummyMidiPort::~DummyMidiPort () { }
1502
1503 struct MidiEventSorter {
1504         bool operator() (const boost::shared_ptr<DummyMidiEvent>& a, const boost::shared_ptr<DummyMidiEvent>& b) {
1505                 return *a < *b;
1506         }
1507 };
1508
1509 void* DummyMidiPort::get_buffer (pframes_t /* nframes */)
1510 {
1511         if (is_input ()) {
1512                 _buffer.clear ();
1513                 for (std::vector<DummyPort*>::const_iterator i = get_connections ().begin ();
1514                                 i != get_connections ().end ();
1515                                 ++i) {
1516                         const DummyMidiBuffer src = static_cast<const DummyMidiPort*>(*i)->const_buffer ();
1517                         for (DummyMidiBuffer::const_iterator it = src.begin (); it != src.end (); ++it) {
1518                                 _buffer.push_back (boost::shared_ptr<DummyMidiEvent>(new DummyMidiEvent (**it)));
1519                         }
1520                 }
1521                 std::sort (_buffer.begin (), _buffer.end (), MidiEventSorter());
1522         } else if (is_output () && is_physical () && is_terminal()) {
1523                 _buffer.clear ();
1524         }
1525         return &_buffer;
1526 }
1527
1528 DummyMidiEvent::DummyMidiEvent (const pframes_t timestamp, const uint8_t* data, size_t size)
1529         : _size (size)
1530         , _timestamp (timestamp)
1531         , _data (0)
1532 {
1533         if (size > 0) {
1534                 _data = (uint8_t*) malloc (size);
1535          memcpy (_data, data, size);
1536         }
1537 }
1538
1539 DummyMidiEvent::DummyMidiEvent (const DummyMidiEvent& other)
1540         : _size (other.size ())
1541         , _timestamp (other.timestamp ())
1542         , _data (0)
1543 {
1544         if (other.size () && other.const_data ()) {
1545                 _data = (uint8_t*) malloc (other.size ());
1546                 memcpy (_data, other.const_data (), other.size ());
1547         }
1548 };
1549
1550 DummyMidiEvent::~DummyMidiEvent () {
1551         free (_data);
1552 };