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