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