fix jack startup on OSX (w/midi)
[ardour.git] / libs / backends / alsa / alsa_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 <regex.h>
21 #include <sys/mman.h>
22 #include <sys/time.h>
23
24 #include <glibmm.h>
25
26 #include "alsa_audiobackend.h"
27 #include "rt_thread.h"
28
29 #include "pbd/compose.h"
30 #include "pbd/error.h"
31 #include "pbd/file_utils.h"
32 #include "ardour/filesystem_paths.h"
33 #include "ardour/port_manager.h"
34 #include "ardouralsautil/devicelist.h"
35 #include "i18n.h"
36
37 using namespace ARDOUR;
38
39 static std::string s_instance_name;
40 size_t AlsaAudioBackend::_max_buffer_size = 8192;
41 std::vector<std::string> AlsaAudioBackend::_midi_options;
42 std::vector<AudioBackend::DeviceStatus> AlsaAudioBackend::_input_audio_device_status;
43 std::vector<AudioBackend::DeviceStatus> AlsaAudioBackend::_output_audio_device_status;
44 std::vector<AudioBackend::DeviceStatus> AlsaAudioBackend::_duplex_audio_device_status;
45 std::vector<AudioBackend::DeviceStatus> AlsaAudioBackend::_midi_device_status;
46
47 ALSADeviceInfo AlsaAudioBackend::_input_audio_device_info;
48 ALSADeviceInfo AlsaAudioBackend::_output_audio_device_info;
49
50 AlsaAudioBackend::AlsaAudioBackend (AudioEngine& e, AudioBackendInfo& info)
51         : AudioBackend (e, info)
52         , _pcmi (0)
53         , _run (false)
54         , _active (false)
55         , _freewheel (false)
56         , _freewheeling (false)
57         , _measure_latency (false)
58         , _last_process_start (0)
59         , _input_audio_device("")
60         , _output_audio_device("")
61         , _midi_driver_option(_("None"))
62         , _device_reservation(0)
63         , _samplerate (48000)
64         , _samples_per_period (1024)
65         , _periods_per_cycle (2)
66         , _n_inputs (0)
67         , _n_outputs (0)
68         , _systemic_audio_input_latency (0)
69         , _systemic_audio_output_latency (0)
70         , _dsp_load (0)
71         , _processed_samples (0)
72         , _port_change_flag (false)
73 {
74         _instance_name = s_instance_name;
75         pthread_mutex_init (&_port_callback_mutex, 0);
76         _input_audio_device_info.valid = false;
77         _output_audio_device_info.valid = false;
78 }
79
80 AlsaAudioBackend::~AlsaAudioBackend ()
81 {
82         pthread_mutex_destroy (&_port_callback_mutex);
83 }
84
85 /* AUDIOBACKEND API */
86
87 std::string
88 AlsaAudioBackend::name () const
89 {
90         return X_("ALSA");
91 }
92
93 bool
94 AlsaAudioBackend::is_realtime () const
95 {
96         return true;
97 }
98
99 std::vector<AudioBackend::DeviceStatus>
100 AlsaAudioBackend::enumerate_devices () const
101 {
102         _duplex_audio_device_status.clear();
103         std::map<std::string, std::string> devices;
104         get_alsa_audio_device_names(devices);
105         for (std::map<std::string, std::string>::const_iterator i = devices.begin (); i != devices.end(); ++i) {
106                 if (_input_audio_device == "") _input_audio_device = i->first;
107                 if (_output_audio_device == "") _output_audio_device = i->first;
108                 _duplex_audio_device_status.push_back (DeviceStatus (i->first, true));
109         }
110         return _duplex_audio_device_status;
111 }
112
113 std::vector<AudioBackend::DeviceStatus>
114 AlsaAudioBackend::enumerate_input_devices () const
115 {
116         _input_audio_device_status.clear();
117         std::map<std::string, std::string> devices;
118         get_alsa_audio_device_names(devices, HalfDuplexIn);
119         _input_audio_device_status.push_back (DeviceStatus (_("None"), true));
120         for (std::map<std::string, std::string>::const_iterator i = devices.begin (); i != devices.end(); ++i) {
121                 if (_input_audio_device == "") _input_audio_device = i->first;
122                 _input_audio_device_status.push_back (DeviceStatus (i->first, true));
123         }
124         return _input_audio_device_status;
125 }
126
127 std::vector<AudioBackend::DeviceStatus>
128 AlsaAudioBackend::enumerate_output_devices () const
129 {
130         _output_audio_device_status.clear();
131         std::map<std::string, std::string> devices;
132         get_alsa_audio_device_names(devices, HalfDuplexOut);
133         _output_audio_device_status.push_back (DeviceStatus (_("None"), true));
134         for (std::map<std::string, std::string>::const_iterator i = devices.begin (); i != devices.end(); ++i) {
135                 if (_output_audio_device == "") _output_audio_device = i->first;
136                 _output_audio_device_status.push_back (DeviceStatus (i->first, true));
137         }
138         return _output_audio_device_status;
139 }
140
141 void
142 AlsaAudioBackend::reservation_stdout (std::string d, size_t /* s */)
143 {
144   if (d.substr(0, 19) == "Acquired audio-card") {
145                 _reservation_succeeded = true;
146         }
147 }
148
149 void
150 AlsaAudioBackend::release_device()
151 {
152         _reservation_connection.drop_connections();
153         ARDOUR::SystemExec * tmp = _device_reservation;
154         _device_reservation = 0;
155         delete tmp;
156 }
157
158 bool
159 AlsaAudioBackend::acquire_device(const char* device_name)
160 {
161         /* This is  quick hack, ideally we'll link against libdbus and implement a dbus-listener
162          * that owns the device. here we try to get away by just requesting it and then block it...
163          * (pulseaudio periodically checks anyway)
164          *
165          * dbus-send --session --print-reply --type=method_call --dest=org.freedesktop.ReserveDevice1.Audio2 /org/freedesktop/ReserveDevice1/Audio2 org.freedesktop.ReserveDevice1.RequestRelease int32:4
166          * -> should not return  'boolean false'
167          */
168         int device_number = card_to_num(device_name);
169         if (device_number < 0) return false;
170
171         assert(_device_reservation == 0);
172         _reservation_succeeded = false;
173
174         std::string request_device_exe;
175         if (!PBD::find_file (
176                                 PBD::Searchpath(Glib::build_filename(ARDOUR::ardour_dll_directory(), "ardouralsautil")
177                                         + G_SEARCHPATH_SEPARATOR_S + ARDOUR::ardour_dll_directory()),
178                                 "ardour-request-device", request_device_exe))
179         {
180                 PBD::warning << "ardour-request-device binary was not found..'" << endmsg;
181                 return false;
182         }
183         else
184         {
185                 char **argp;
186                 char tmp[128];
187                 argp=(char**) calloc(5,sizeof(char*));
188                 argp[0] = strdup(request_device_exe.c_str());
189                 argp[1] = strdup("-P");
190                 snprintf(tmp, sizeof(tmp), "%d", getpid());
191                 argp[2] = strdup(tmp);
192                 snprintf(tmp, sizeof(tmp), "Audio%d", device_number);
193                 argp[3] = strdup(tmp);
194                 argp[4] = 0;
195
196                 _device_reservation = new ARDOUR::SystemExec(request_device_exe, argp);
197                 _device_reservation->ReadStdout.connect_same_thread (_reservation_connection, boost::bind (&AlsaAudioBackend::reservation_stdout, this, _1 ,_2));
198                 _device_reservation->Terminated.connect_same_thread (_reservation_connection, boost::bind (&AlsaAudioBackend::release_device, this));
199                 if (_device_reservation->start(0)) {
200                         PBD::warning << _("AlsaAudioBackend: Device Request failed.") << endmsg;
201                         release_device();
202                         return false;
203                 }
204         }
205         // wait to check if reservation suceeded.
206         int timeout = 500; // 5 sec
207         while (_device_reservation && !_reservation_succeeded && --timeout > 0) {
208                 Glib::usleep(10000);
209         }
210         if (timeout == 0 || !_reservation_succeeded) {
211                 PBD::warning << _("AlsaAudioBackend: Device Reservation failed.") << endmsg;
212                 release_device();
213                 return false;
214         }
215         return true;
216 }
217
218 std::vector<float>
219 AlsaAudioBackend::available_sample_rates (const std::string& input_device, const std::string& output_device) const
220 {
221         std::vector<float> sr;
222         if (input_device == _("None") && output_device == _("None")) {
223                 return sr;
224         }
225         else if (input_device == _("None")) {
226                 sr = available_sample_rates (output_device);
227         }
228         else if (output_device == _("None")) {
229                 sr = available_sample_rates (input_device);
230         } else {
231                 std::vector<float> sr_in =  available_sample_rates (input_device);
232                 std::vector<float> sr_out = available_sample_rates (output_device);
233                 std::set_intersection (sr_in.begin(), sr_in.end(), sr_out.begin(), sr_out.end(), std::back_inserter(sr));
234         }
235         return sr;
236 }
237
238 std::vector<float>
239 AlsaAudioBackend::available_sample_rates (const std::string& device) const
240 {
241         ALSADeviceInfo *nfo = NULL;
242         std::vector<float> sr;
243         if (device == _("None")) {
244                 return sr;
245         }
246         if (device == _input_audio_device && _input_audio_device_info.valid) {
247                 nfo = &_input_audio_device_info;
248         }
249         else if (device == _output_audio_device && _output_audio_device_info.valid) {
250                 nfo = &_output_audio_device_info;
251         }
252
253         static const float avail_rates [] = { 8000, 22050.0, 24000.0, 44100.0, 48000.0, 88200.0, 96000.0, 176400.0, 192000.0 };
254
255         for (size_t i = 0 ; i < sizeof(avail_rates) / sizeof(float); ++i) {
256                 if (!nfo || (avail_rates[i] >= nfo->min_rate && avail_rates[i] <= nfo->max_rate)) {
257                         sr.push_back (avail_rates[i]);
258                 }
259         }
260
261         return sr;
262 }
263
264 std::vector<uint32_t>
265 AlsaAudioBackend::available_buffer_sizes (const std::string& input_device, const std::string& output_device) const
266 {
267         std::vector<uint32_t> bs;
268         if (input_device == _("None") && output_device == _("None")) {
269                 return bs;
270         }
271         else if (input_device == _("None")) {
272                 bs = available_buffer_sizes (output_device);
273         }
274         else if (output_device == _("None")) {
275                 bs = available_buffer_sizes (input_device);
276         } else {
277                 std::vector<uint32_t> bs_in =  available_buffer_sizes (input_device);
278                 std::vector<uint32_t> bs_out = available_buffer_sizes (output_device);
279                 std::set_intersection (bs_in.begin(), bs_in.end(), bs_out.begin(), bs_out.end(), std::back_inserter(bs));
280         }
281         return bs;
282 }
283
284 std::vector<uint32_t>
285 AlsaAudioBackend::available_buffer_sizes (const std::string& device) const
286 {
287         ALSADeviceInfo *nfo = NULL;
288         std::vector<uint32_t> bs;
289         if (device == _("None")) {
290                 return bs;
291         }
292         if (device == _input_audio_device && _input_audio_device_info.valid) {
293                 nfo = &_input_audio_device_info;
294         }
295         else if (device == _output_audio_device && _output_audio_device_info.valid) {
296                 nfo = &_output_audio_device_info;
297         }
298
299         static const unsigned long avail_sizes [] = { 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192 };
300
301         for (size_t i = 0 ; i < sizeof(avail_sizes) / sizeof(unsigned long); ++i) {
302                 if (!nfo || (avail_sizes[i] >= nfo->min_size && avail_sizes[i] <= nfo->max_size)) {
303                         bs.push_back (avail_sizes[i]);
304                 }
305         }
306         return bs;
307 }
308
309 uint32_t
310 AlsaAudioBackend::available_input_channel_count (const std::string& device) const
311 {
312         if (device == _("None")) {
313                 return 0;
314         }
315         if (device == _input_audio_device && _input_audio_device_info.valid) {
316                 return _input_audio_device_info.max_channels;
317         }
318         return 128;
319 }
320
321 uint32_t
322 AlsaAudioBackend::available_output_channel_count (const std::string& device) const
323 {
324         if (device == _("None")) {
325                 return 0;
326         }
327         if (device == _output_audio_device && _output_audio_device_info.valid) {
328                 return _output_audio_device_info.max_channels;
329         }
330         return 128;
331 }
332
333 bool
334 AlsaAudioBackend::can_change_sample_rate_when_running () const
335 {
336         return false;
337 }
338
339 bool
340 AlsaAudioBackend::can_change_buffer_size_when_running () const
341 {
342         return false; // why not? :)
343 }
344
345 int
346 AlsaAudioBackend::set_input_device_name (const std::string& d)
347 {
348         if (_input_audio_device == d) {
349                 return 0;
350         }
351         _input_audio_device = d;
352
353         if (d == _("None")) {
354                 _input_audio_device_info.valid = false;
355                 return 0;
356         }
357         std::string alsa_device;
358         std::map<std::string, std::string> devices;
359
360         get_alsa_audio_device_names(devices, HalfDuplexIn);
361         for (std::map<std::string, std::string>::const_iterator i = devices.begin (); i != devices.end(); ++i) {
362                 if (i->first == d) {
363                         alsa_device = i->second;
364                         break;
365                 }
366         }
367         if (alsa_device == "") {
368                 _input_audio_device_info.valid = false;
369                 return 1;
370         }
371         /* device will be busy once used, hence cache the parameters */
372         /* return */ get_alsa_device_parameters (alsa_device.c_str(), true, &_input_audio_device_info);
373         return 0;
374 }
375
376 int
377 AlsaAudioBackend::set_output_device_name (const std::string& d)
378 {
379         if (_output_audio_device == d) {
380                 return 0;
381         }
382
383         _output_audio_device = d;
384
385         if (d == _("None")) {
386                 _output_audio_device_info.valid = false;
387                 return 0;
388         }
389         std::string alsa_device;
390         std::map<std::string, std::string> devices;
391
392         get_alsa_audio_device_names(devices, HalfDuplexOut);
393         for (std::map<std::string, std::string>::const_iterator i = devices.begin (); i != devices.end(); ++i) {
394                 if (i->first == d) {
395                         alsa_device = i->second;
396                         break;
397                 }
398         }
399         if (alsa_device == "") {
400                 _output_audio_device_info.valid = false;
401                 return 1;
402         }
403         /* return */ get_alsa_device_parameters (alsa_device.c_str(), true, &_output_audio_device_info);
404         return 0;
405 }
406
407 int
408 AlsaAudioBackend::set_device_name (const std::string& d)
409 {
410         int rv = 0;
411         rv |= set_input_device_name (d);
412         rv |= set_output_device_name (d);
413         return rv;
414 }
415
416 int
417 AlsaAudioBackend::set_sample_rate (float sr)
418 {
419         if (sr <= 0) { return -1; }
420         _samplerate = sr;
421         engine.sample_rate_change (sr);
422         return 0;
423 }
424
425 int
426 AlsaAudioBackend::set_buffer_size (uint32_t bs)
427 {
428         if (bs <= 0 || bs >= _max_buffer_size) {
429                 return -1;
430         }
431         if (_run) {
432                 return -1;
433         }
434         _samples_per_period = bs;
435         engine.buffer_size_change (bs);
436         return 0;
437 }
438
439 int
440 AlsaAudioBackend::set_interleaved (bool yn)
441 {
442         if (!yn) { return 0; }
443         return -1;
444 }
445
446 int
447 AlsaAudioBackend::set_input_channels (uint32_t cc)
448 {
449         _n_inputs = cc;
450         return 0;
451 }
452
453 int
454 AlsaAudioBackend::set_output_channels (uint32_t cc)
455 {
456         _n_outputs = cc;
457         return 0;
458 }
459
460 int
461 AlsaAudioBackend::set_systemic_input_latency (uint32_t sl)
462 {
463         _systemic_audio_input_latency = sl;
464         return 0;
465 }
466
467 int
468 AlsaAudioBackend::set_systemic_output_latency (uint32_t sl)
469 {
470         _systemic_audio_output_latency = sl;
471         return 0;
472 }
473
474 int
475 AlsaAudioBackend::set_systemic_midi_input_latency (std::string const device, uint32_t sl)
476 {
477         struct AlsaMidiDeviceInfo * nfo = midi_device_info(device);
478         if (!nfo) return -1;
479         nfo->systemic_input_latency = sl;
480         return 0;
481 }
482
483 int
484 AlsaAudioBackend::set_systemic_midi_output_latency (std::string const device, uint32_t sl)
485 {
486         struct AlsaMidiDeviceInfo * nfo = midi_device_info(device);
487         if (!nfo) return -1;
488         nfo->systemic_output_latency = sl;
489         return 0;
490 }
491
492 /* Retrieving parameters */
493 std::string
494 AlsaAudioBackend::device_name () const
495 {
496         if (_input_audio_device != _("None")) {
497                 return _input_audio_device;
498         }
499         if (_output_audio_device != _("None")) {
500                 return _output_audio_device;
501         }
502         return "";
503 }
504
505 std::string
506 AlsaAudioBackend::input_device_name () const
507 {
508         return _input_audio_device;
509 }
510
511 std::string
512 AlsaAudioBackend::output_device_name () const
513 {
514         return _output_audio_device;
515 }
516
517 float
518 AlsaAudioBackend::sample_rate () const
519 {
520         return _samplerate;
521 }
522
523 uint32_t
524 AlsaAudioBackend::buffer_size () const
525 {
526         return _samples_per_period;
527 }
528
529 bool
530 AlsaAudioBackend::interleaved () const
531 {
532         return false;
533 }
534
535 uint32_t
536 AlsaAudioBackend::input_channels () const
537 {
538         return _n_inputs;
539 }
540
541 uint32_t
542 AlsaAudioBackend::output_channels () const
543 {
544         return _n_outputs;
545 }
546
547 uint32_t
548 AlsaAudioBackend::systemic_input_latency () const
549 {
550         return _systemic_audio_input_latency;
551 }
552
553 uint32_t
554 AlsaAudioBackend::systemic_output_latency () const
555 {
556         return _systemic_audio_output_latency;
557 }
558
559 uint32_t
560 AlsaAudioBackend::systemic_midi_input_latency (std::string const device) const
561 {
562         struct AlsaMidiDeviceInfo * nfo = midi_device_info(device);
563         if (!nfo) return 0;
564         return nfo->systemic_input_latency;
565 }
566
567 uint32_t
568 AlsaAudioBackend::systemic_midi_output_latency (std::string const device) const
569 {
570         struct AlsaMidiDeviceInfo * nfo = midi_device_info(device);
571         if (!nfo) return 0;
572         return nfo->systemic_output_latency;
573 }
574
575 /* MIDI */
576 struct AlsaAudioBackend::AlsaMidiDeviceInfo *
577 AlsaAudioBackend::midi_device_info(std::string const name) const {
578         for (std::map<std::string, struct AlsaMidiDeviceInfo*>::const_iterator i = _midi_devices.begin (); i != _midi_devices.end(); ++i) {
579                 if (i->first == name) {
580                         return (i->second);
581                 }
582         }
583
584         assert(_midi_driver_option != _("None"));
585
586         std::map<std::string, std::string> devices;
587         if (_midi_driver_option == _("ALSA raw devices")) {
588                 get_alsa_rawmidi_device_names(devices);
589         } else {
590                 get_alsa_sequencer_names (devices);
591         }
592
593         for (std::map<std::string, std::string>::const_iterator i = devices.begin (); i != devices.end(); ++i) {
594                 if (i->first == name) {
595                         _midi_devices[name] = new AlsaMidiDeviceInfo();
596                         return _midi_devices[name];
597                 }
598         }
599         return 0;
600 }
601
602 std::vector<std::string>
603 AlsaAudioBackend::enumerate_midi_options () const
604 {
605         if (_midi_options.empty()) {
606                 _midi_options.push_back (_("ALSA raw devices"));
607                 _midi_options.push_back (_("ALSA sequencer"));
608                 _midi_options.push_back (_("None"));
609         }
610         return _midi_options;
611 }
612
613 std::vector<AudioBackend::DeviceStatus>
614 AlsaAudioBackend::enumerate_midi_devices () const
615 {
616         _midi_device_status.clear();
617         std::map<std::string, std::string> devices;
618
619         if (_midi_driver_option == _("ALSA raw devices")) {
620                 get_alsa_rawmidi_device_names (devices);
621         }
622         else if (_midi_driver_option == _("ALSA sequencer")) {
623                 get_alsa_sequencer_names (devices);
624         }
625
626         for (std::map<std::string, std::string>::const_iterator i = devices.begin (); i != devices.end(); ++i) {
627                 _midi_device_status.push_back (DeviceStatus (i->first, true));
628         }
629         return _midi_device_status;
630 }
631
632 int
633 AlsaAudioBackend::set_midi_option (const std::string& opt)
634 {
635         if (opt != _("None") && opt != _("ALSA raw devices") && opt != _("ALSA sequencer")) {
636                 return -1;
637         }
638         _midi_driver_option = opt;
639         return 0;
640 }
641
642 std::string
643 AlsaAudioBackend::midi_option () const
644 {
645         return _midi_driver_option;
646 }
647
648 int
649 AlsaAudioBackend::set_midi_device_enabled (std::string const device, bool enable)
650 {
651         struct AlsaMidiDeviceInfo * nfo = midi_device_info(device);
652         if (!nfo) return -1;
653         nfo->enabled = enable;
654         return 0;
655 }
656
657 bool
658 AlsaAudioBackend::midi_device_enabled (std::string const device) const
659 {
660         struct AlsaMidiDeviceInfo * nfo = midi_device_info(device);
661         if (!nfo) return false;
662         return nfo->enabled;
663 }
664
665 /* State Control */
666
667 static void * pthread_process (void *arg)
668 {
669         AlsaAudioBackend *d = static_cast<AlsaAudioBackend *>(arg);
670         d->main_process_thread ();
671         pthread_exit (0);
672         return 0;
673 }
674
675 int
676 AlsaAudioBackend::_start (bool for_latency_measurement)
677 {
678         if (!_active && _run) {
679                 // recover from 'halted', reap threads
680                 stop();
681         }
682
683         if (_active || _run) {
684                 PBD::error << _("AlsaAudioBackend: already active.") << endmsg;
685                 return -1;
686         }
687
688         if (_ports.size()) {
689                 PBD::warning << _("AlsaAudioBackend: recovering from unclean shutdown, port registry is not empty.") << endmsg;
690                 _system_inputs.clear();
691                 _system_outputs.clear();
692                 _system_midi_in.clear();
693                 _system_midi_out.clear();
694                 _ports.clear();
695         }
696
697         /* reset internal state */
698         _dsp_load = 0;
699         _freewheeling = false;
700         _freewheel = false;
701         _last_process_start = 0;
702
703         release_device();
704
705         assert(_rmidi_in.size() == 0);
706         assert(_rmidi_out.size() == 0);
707         assert(_pcmi == 0);
708
709         int duplex = 0;
710         std::string audio_device;
711         std::string alsa_device;
712         std::map<std::string, std::string> devices;
713
714         if (_input_audio_device == _("None") && _output_audio_device == _("None")) {
715                 PBD::error << _("AlsaAudioBackend: At least one of input or output device needs to be set.");
716                 return -1;
717         }
718
719         if (_input_audio_device != _output_audio_device) {
720                 if (_input_audio_device != _("None") && _output_audio_device != _("None")) {
721                         PBD::error << _("AlsaAudioBackend: Cannot use two different devices.");
722                         return -1;
723                 }
724                 if (_input_audio_device != _("None")) {
725                         get_alsa_audio_device_names(devices, HalfDuplexIn);
726                         audio_device = _input_audio_device;
727                         duplex = 1;
728                 } else {
729                         get_alsa_audio_device_names(devices, HalfDuplexOut);
730                         audio_device = _output_audio_device;
731                         duplex = 2;
732                 }
733         } else {
734                 get_alsa_audio_device_names(devices);
735                 audio_device = _input_audio_device;
736                 duplex = 3;
737         }
738
739         for (std::map<std::string, std::string>::const_iterator i = devices.begin (); i != devices.end(); ++i) {
740                 if (i->first == audio_device) {
741                         alsa_device = i->second;
742                         break;
743                 }
744         }
745         if (alsa_device == "") {
746                 PBD::error << _("AlsaAudioBackend: Cannot find configured device. Is it still connected?");
747                 return -1;
748         }
749
750         acquire_device(alsa_device.c_str());
751         _pcmi = new Alsa_pcmi (
752                         (duplex & 2) ? alsa_device.c_str() : NULL,
753                         (duplex & 1) ? alsa_device.c_str() : NULL,
754                         0, _samplerate, _samples_per_period, _periods_per_cycle, 0);
755         switch (_pcmi->state ()) {
756                 case 0: /* OK */ break;
757                 case -1: PBD::error << _("AlsaAudioBackend: failed to open device.") << endmsg; break;
758                 case -2: PBD::error << _("AlsaAudioBackend: failed to allocate parameters.") << endmsg; break;
759                 case -3: PBD::error << _("AlsaAudioBackend: cannot set requested sample rate.") << endmsg; break;
760                 case -4: PBD::error << _("AlsaAudioBackend: cannot set requested period size.") << endmsg; break;
761                 case -5: PBD::error << _("AlsaAudioBackend: cannot set requested number of periods.") << endmsg; break;
762                 case -6: PBD::error << _("AlsaAudioBackend: unsupported sample format.") << endmsg; break;
763                 default: PBD::error << _("AlsaAudioBackend: initialization failed.") << endmsg; break;
764         }
765         if (_pcmi->state ()) {
766                 delete _pcmi; _pcmi = 0;
767                 release_device();
768                 return -1;
769         }
770
771 #ifndef NDEBUG
772         _pcmi->printinfo ();
773 #endif
774
775         if (_n_outputs != _pcmi->nplay ()) {
776                 if (_n_outputs == 0) {
777                  _n_outputs = _pcmi->nplay ();
778                 } else {
779                  _n_outputs = std::min (_n_outputs, _pcmi->nplay ());
780                 }
781                 PBD::warning << _("AlsaAudioBackend: adjusted output channel count to match device.") << endmsg;
782         }
783
784         if (_n_inputs != _pcmi->ncapt ()) {
785                 if (_n_inputs == 0) {
786                  _n_inputs = _pcmi->ncapt ();
787                 } else {
788                  _n_inputs = std::min (_n_inputs, _pcmi->ncapt ());
789                 }
790                 PBD::warning << _("AlsaAudioBackend: adjusted input channel count to match device.") << endmsg;
791         }
792
793         if (_pcmi->fsize() != _samples_per_period) {
794                 _samples_per_period = _pcmi->fsize();
795                 PBD::warning << _("AlsaAudioBackend: samples per period does not match.") << endmsg;
796         }
797
798         if (_pcmi->fsamp() != _samplerate) {
799                 _samplerate = _pcmi->fsamp();
800                 engine.sample_rate_change (_samplerate);
801                 PBD::warning << _("AlsaAudioBackend: sample rate does not match.") << endmsg;
802         }
803
804         _measure_latency = for_latency_measurement;
805
806         register_system_midi_ports();
807
808         if (register_system_audio_ports()) {
809                 PBD::error << _("AlsaAudioBackend: failed to register system ports.") << endmsg;
810                 delete _pcmi; _pcmi = 0;
811                 release_device();
812                 return -1;
813         }
814
815         engine.sample_rate_change (_samplerate);
816         engine.buffer_size_change (_samples_per_period);
817
818         if (engine.reestablish_ports ()) {
819                 PBD::error << _("AlsaAudioBackend: Could not re-establish ports.") << endmsg;
820                 delete _pcmi; _pcmi = 0;
821                 release_device();
822                 return -1;
823         }
824
825         engine.reconnect_ports ();
826         _run = true;
827         _port_change_flag = false;
828
829         if (_realtime_pthread_create (SCHED_FIFO, -20, 100000,
830                                 &_main_thread, pthread_process, this))
831         {
832                 if (pthread_create (&_main_thread, NULL, pthread_process, this))
833                 {
834                         PBD::error << _("AlsaAudioBackend: failed to create process thread.") << endmsg;
835                         delete _pcmi; _pcmi = 0;
836                         release_device();
837                         _run = false;
838                         return -1;
839                 } else {
840                         PBD::warning << _("AlsaAudioBackend: cannot acquire realtime permissions.") << endmsg;
841                 }
842         }
843
844         int timeout = 5000;
845         while (!_active && --timeout > 0) { Glib::usleep (1000); }
846
847         if (timeout == 0 || !_active) {
848                 PBD::error << _("AlsaAudioBackend: failed to start process thread.") << endmsg;
849                 delete _pcmi; _pcmi = 0;
850                 release_device();
851                 _run = false;
852                 return -1;
853         }
854
855         return 0;
856 }
857
858 int
859 AlsaAudioBackend::stop ()
860 {
861         void *status;
862         if (!_run) {
863                 return 0;
864         }
865
866         _run = false;
867         if (pthread_join (_main_thread, &status)) {
868                 PBD::error << _("AlsaAudioBackend: failed to terminate.") << endmsg;
869                 return -1;
870         }
871
872         while (!_rmidi_out.empty ()) {
873                 AlsaMidiIO *m = _rmidi_out.back ();
874                 m->stop();
875                 _rmidi_out.pop_back ();
876                 delete m;
877         }
878         while (!_rmidi_in.empty ()) {
879                 AlsaMidiIO *m = _rmidi_in.back ();
880                 m->stop();
881                 _rmidi_in.pop_back ();
882                 delete m;
883         }
884
885         unregister_ports();
886         delete _pcmi; _pcmi = 0;
887         release_device();
888
889         return (_active == false) ? 0 : -1;
890 }
891
892 int
893 AlsaAudioBackend::freewheel (bool onoff)
894 {
895         _freewheeling = onoff;
896         return 0;
897 }
898
899 float
900 AlsaAudioBackend::dsp_load () const
901 {
902         return std::min(100.f, 100.f * _dsp_load);
903 }
904
905 size_t
906 AlsaAudioBackend::raw_buffer_size (DataType t)
907 {
908         switch (t) {
909                 case DataType::AUDIO:
910                         return _samples_per_period * sizeof(Sample);
911                 case DataType::MIDI:
912                         return _max_buffer_size; // XXX not really limited
913         }
914         return 0;
915 }
916
917 /* Process time */
918 framepos_t
919 AlsaAudioBackend::sample_time ()
920 {
921         return _processed_samples;
922 }
923
924 framepos_t
925 AlsaAudioBackend::sample_time_at_cycle_start ()
926 {
927         return _processed_samples;
928 }
929
930 pframes_t
931 AlsaAudioBackend::samples_since_cycle_start ()
932 {
933         if (!_active || !_run || _freewheeling || _freewheel) {
934                 return 0;
935         }
936         if (_last_process_start == 0) {
937                 return 0;
938         }
939
940         const int64_t elapsed_time_us = g_get_monotonic_time() - _last_process_start;
941         return std::max((pframes_t)0, (pframes_t)rint(1e-6 * elapsed_time_us * _samplerate));
942 }
943
944
945 void *
946 AlsaAudioBackend::alsa_process_thread (void *arg)
947 {
948         ThreadData* td = reinterpret_cast<ThreadData*> (arg);
949         boost::function<void ()> f = td->f;
950         delete td;
951         f ();
952         return 0;
953 }
954
955 int
956 AlsaAudioBackend::create_process_thread (boost::function<void()> func)
957 {
958         pthread_t thread_id;
959         pthread_attr_t attr;
960         size_t stacksize = 100000;
961
962         ThreadData* td = new ThreadData (this, func, stacksize);
963
964         if (_realtime_pthread_create (SCHED_FIFO, -21, stacksize,
965                                 &thread_id, alsa_process_thread, td)) {
966                 pthread_attr_init (&attr);
967                 pthread_attr_setstacksize (&attr, stacksize);
968                 if (pthread_create (&thread_id, &attr, alsa_process_thread, td)) {
969                         PBD::error << _("AudioEngine: cannot create process thread.") << endmsg;
970                         pthread_attr_destroy (&attr);
971                         return -1;
972                 }
973                 pthread_attr_destroy (&attr);
974         }
975
976         _threads.push_back (thread_id);
977         return 0;
978 }
979
980 int
981 AlsaAudioBackend::join_process_threads ()
982 {
983         int rv = 0;
984
985         for (std::vector<pthread_t>::const_iterator i = _threads.begin (); i != _threads.end (); ++i)
986         {
987                 void *status;
988                 if (pthread_join (*i, &status)) {
989                         PBD::error << _("AudioEngine: cannot terminate process thread.") << endmsg;
990                         rv -= 1;
991                 }
992         }
993         _threads.clear ();
994         return rv;
995 }
996
997 bool
998 AlsaAudioBackend::in_process_thread ()
999 {
1000         if (pthread_equal (_main_thread, pthread_self()) != 0) {
1001                 return true;
1002         }
1003
1004         for (std::vector<pthread_t>::const_iterator i = _threads.begin (); i != _threads.end (); ++i)
1005         {
1006                 if (pthread_equal (*i, pthread_self ()) != 0) {
1007                         return true;
1008                 }
1009         }
1010         return false;
1011 }
1012
1013 uint32_t
1014 AlsaAudioBackend::process_thread_count ()
1015 {
1016         return _threads.size ();
1017 }
1018
1019 void
1020 AlsaAudioBackend::update_latencies ()
1021 {
1022         // trigger latency callback in RT thread (locked graph)
1023         port_connect_add_remove_callback();
1024 }
1025
1026 /* PORTENGINE API */
1027
1028 void*
1029 AlsaAudioBackend::private_handle () const
1030 {
1031         return NULL;
1032 }
1033
1034 const std::string&
1035 AlsaAudioBackend::my_name () const
1036 {
1037         return _instance_name;
1038 }
1039
1040 bool
1041 AlsaAudioBackend::available () const
1042 {
1043         return _run && _active;
1044 }
1045
1046 uint32_t
1047 AlsaAudioBackend::port_name_size () const
1048 {
1049         return 256;
1050 }
1051
1052 int
1053 AlsaAudioBackend::set_port_name (PortEngine::PortHandle port, const std::string& name)
1054 {
1055         if (!valid_port (port)) {
1056                 PBD::error << _("AlsaBackend::set_port_name: Invalid Port(s)") << endmsg;
1057                 return -1;
1058         }
1059         return static_cast<AlsaPort*>(port)->set_name (_instance_name + ":" + name);
1060 }
1061
1062 std::string
1063 AlsaAudioBackend::get_port_name (PortEngine::PortHandle port) const
1064 {
1065         if (!valid_port (port)) {
1066                 PBD::error << _("AlsaBackend::get_port_name: Invalid Port(s)") << endmsg;
1067                 return std::string ();
1068         }
1069         return static_cast<AlsaPort*>(port)->name ();
1070 }
1071
1072 PortEngine::PortHandle
1073 AlsaAudioBackend::get_port_by_name (const std::string& name) const
1074 {
1075         PortHandle port = (PortHandle) find_port (name);
1076         return port;
1077 }
1078
1079 int
1080 AlsaAudioBackend::get_ports (
1081                 const std::string& port_name_pattern,
1082                 DataType type, PortFlags flags,
1083                 std::vector<std::string>& port_names) const
1084 {
1085         int rv = 0;
1086         regex_t port_regex;
1087         bool use_regexp = false;
1088         if (port_name_pattern.size () > 0) {
1089                 if (!regcomp (&port_regex, port_name_pattern.c_str (), REG_EXTENDED|REG_NOSUB)) {
1090                         use_regexp = true;
1091                 }
1092         }
1093         for (size_t i = 0; i < _ports.size (); ++i) {
1094                 AlsaPort* port = _ports[i];
1095                 if ((port->type () == type) && flags == (port->flags () & flags)) {
1096                         if (!use_regexp || !regexec (&port_regex, port->name ().c_str (), 0, NULL, 0)) {
1097                                 port_names.push_back (port->name ());
1098                                 ++rv;
1099                         }
1100                 }
1101         }
1102         if (use_regexp) {
1103                 regfree (&port_regex);
1104         }
1105         return rv;
1106 }
1107
1108 DataType
1109 AlsaAudioBackend::port_data_type (PortEngine::PortHandle port) const
1110 {
1111         if (!valid_port (port)) {
1112                 return DataType::NIL;
1113         }
1114         return static_cast<AlsaPort*>(port)->type ();
1115 }
1116
1117 PortEngine::PortHandle
1118 AlsaAudioBackend::register_port (
1119                 const std::string& name,
1120                 ARDOUR::DataType type,
1121                 ARDOUR::PortFlags flags)
1122 {
1123         if (name.size () == 0) { return 0; }
1124         if (flags & IsPhysical) { return 0; }
1125         return add_port (_instance_name + ":" + name, type, flags);
1126 }
1127
1128 PortEngine::PortHandle
1129 AlsaAudioBackend::add_port (
1130                 const std::string& name,
1131                 ARDOUR::DataType type,
1132                 ARDOUR::PortFlags flags)
1133 {
1134         assert(name.size ());
1135         if (find_port (name)) {
1136                 PBD::error << _("AlsaBackend::register_port: Port already exists:")
1137                                 << " (" << name << ")" << endmsg;
1138                 return 0;
1139         }
1140         AlsaPort* port = NULL;
1141         switch (type) {
1142                 case DataType::AUDIO:
1143                         port = new AlsaAudioPort (*this, name, flags);
1144                         break;
1145                 case DataType::MIDI:
1146                         port = new AlsaMidiPort (*this, name, flags);
1147                         break;
1148                 default:
1149                         PBD::error << _("AlsaBackend::register_port: Invalid Data Type.") << endmsg;
1150                         return 0;
1151         }
1152
1153         _ports.push_back (port);
1154
1155         return port;
1156 }
1157
1158 void
1159 AlsaAudioBackend::unregister_port (PortEngine::PortHandle port_handle)
1160 {
1161         if (!_run) {
1162                 return;
1163         }
1164         AlsaPort* port = static_cast<AlsaPort*>(port_handle);
1165         std::vector<AlsaPort*>::iterator i = std::find (_ports.begin (), _ports.end (), static_cast<AlsaPort*>(port_handle));
1166         if (i == _ports.end ()) {
1167                 PBD::error << _("AlsaBackend::unregister_port: Failed to find port") << endmsg;
1168                 return;
1169         }
1170         disconnect_all(port_handle);
1171         _ports.erase (i);
1172         delete port;
1173 }
1174
1175 int
1176 AlsaAudioBackend::register_system_audio_ports()
1177 {
1178         LatencyRange lr;
1179
1180         const int a_ins = _n_inputs;
1181         const int a_out = _n_outputs;
1182
1183         /* audio ports */
1184         lr.min = lr.max = (_measure_latency ? 0 : _systemic_audio_input_latency);
1185         for (int i = 1; i <= a_ins; ++i) {
1186                 char tmp[64];
1187                 snprintf(tmp, sizeof(tmp), "system:capture_%d", i);
1188                 PortHandle p = add_port(std::string(tmp), DataType::AUDIO, static_cast<PortFlags>(IsOutput | IsPhysical | IsTerminal));
1189                 if (!p) return -1;
1190                 set_latency_range (p, false, lr);
1191                 _system_inputs.push_back(static_cast<AlsaPort*>(p));
1192         }
1193
1194         lr.min = lr.max = (_measure_latency ? 0 : _systemic_audio_output_latency);
1195         for (int i = 1; i <= a_out; ++i) {
1196                 char tmp[64];
1197                 snprintf(tmp, sizeof(tmp), "system:playback_%d", i);
1198                 PortHandle p = add_port(std::string(tmp), DataType::AUDIO, static_cast<PortFlags>(IsInput | IsPhysical | IsTerminal));
1199                 if (!p) return -1;
1200                 set_latency_range (p, true, lr);
1201                 _system_outputs.push_back(static_cast<AlsaPort*>(p));
1202         }
1203         return 0;
1204 }
1205
1206 int
1207 AlsaAudioBackend::register_system_midi_ports()
1208 {
1209         std::map<std::string, std::string> devices;
1210         int midi_ins = 0;
1211         int midi_outs = 0;
1212
1213         if (_midi_driver_option == _("None")) {
1214                 return 0;
1215         } else if (_midi_driver_option == _("ALSA raw devices")) {
1216                 get_alsa_rawmidi_device_names(devices);
1217         } else {
1218                 get_alsa_sequencer_names (devices);
1219         }
1220
1221         for (std::map<std::string, std::string>::const_iterator i = devices.begin (); i != devices.end(); ++i) {
1222                 struct AlsaMidiDeviceInfo * nfo = midi_device_info(i->first);
1223                 if (!nfo) continue;
1224                 if (!nfo->enabled) continue;
1225
1226                 AlsaMidiOut *mout;
1227                 if (_midi_driver_option == _("ALSA raw devices")) {
1228                         mout = new AlsaRawMidiOut (i->second.c_str());
1229                 } else {
1230                         mout = new AlsaSeqMidiOut (i->second.c_str());
1231                 }
1232
1233                 if (mout->state ()) {
1234                         PBD::warning << string_compose (
1235                                         _("AlsaMidiOut: failed to open midi device '%1'."), i->second)
1236                                 << endmsg;
1237                         delete mout;
1238                 } else {
1239                         mout->setup_timing(_samples_per_period, _samplerate);
1240                         mout->sync_time (g_get_monotonic_time());
1241                         if (mout->start ()) {
1242                                 PBD::warning << string_compose (
1243                                                 _("AlsaMidiOut: failed to start midi device '%1'."), i->second)
1244                                         << endmsg;
1245                                 delete mout;
1246                         } else {
1247                                 char tmp[64];
1248                                 snprintf(tmp, sizeof(tmp), "system:midi_playback_%d", ++midi_ins);
1249                                 PortHandle p = add_port(std::string(tmp), DataType::MIDI, static_cast<PortFlags>(IsInput | IsPhysical | IsTerminal));
1250                                 if (!p) {
1251                                         mout->stop();
1252                                         delete mout;
1253                                 }
1254                                 LatencyRange lr;
1255                                 lr.min = lr.max = (_measure_latency ? 0 : nfo->systemic_output_latency);
1256                                 set_latency_range (p, false, lr);
1257                                 static_cast<AlsaMidiPort*>(p)->set_n_periods(2);
1258                                 _system_midi_out.push_back(static_cast<AlsaPort*>(p));
1259                                 _rmidi_out.push_back (mout);
1260                         }
1261                 }
1262
1263                 AlsaMidiIn *midin;
1264                 if (_midi_driver_option == _("ALSA raw devices")) {
1265                         midin = new AlsaRawMidiIn (i->second.c_str());
1266                 } else {
1267                         midin = new AlsaSeqMidiIn (i->second.c_str());
1268                 }
1269
1270                 if (midin->state ()) {
1271                         PBD::warning << string_compose (
1272                                         _("AlsaMidiIn: failed to open midi device '%1'."), i->second)
1273                                 << endmsg;
1274                         delete midin;
1275                 } else {
1276                         midin->setup_timing(_samples_per_period, _samplerate);
1277                         midin->sync_time (g_get_monotonic_time());
1278                         if (midin->start ()) {
1279                                 PBD::warning << string_compose (
1280                                                 _("AlsaMidiIn: failed to start midi device '%1'."), i->second)
1281                                         << endmsg;
1282                                 delete midin;
1283                         } else {
1284                                 char tmp[64];
1285                                 snprintf(tmp, sizeof(tmp), "system:midi_capture_%d", ++midi_outs);
1286                                 PortHandle p = add_port(std::string(tmp), DataType::MIDI, static_cast<PortFlags>(IsOutput | IsPhysical | IsTerminal));
1287                                 if (!p) {
1288                                         midin->stop();
1289                                         delete midin;
1290                                         continue;
1291                                 }
1292                                 LatencyRange lr;
1293                                 lr.min = lr.max = (_measure_latency ? 0 : nfo->systemic_input_latency);
1294                                 set_latency_range (p, false, lr);
1295                                 _system_midi_in.push_back(static_cast<AlsaPort*>(p));
1296                                 _rmidi_in.push_back (midin);
1297                         }
1298                 }
1299         }
1300         return 0;
1301 }
1302
1303 void
1304 AlsaAudioBackend::unregister_ports (bool system_only)
1305 {
1306         size_t i = 0;
1307         _system_inputs.clear();
1308         _system_outputs.clear();
1309         _system_midi_in.clear();
1310         _system_midi_out.clear();
1311         while (i <  _ports.size ()) {
1312                 AlsaPort* port = _ports[i];
1313                 if (! system_only || (port->is_physical () && port->is_terminal ())) {
1314                         port->disconnect_all ();
1315                         delete port;
1316                         _ports.erase (_ports.begin() + i);
1317                 } else {
1318                         ++i;
1319                 }
1320         }
1321 }
1322
1323 int
1324 AlsaAudioBackend::connect (const std::string& src, const std::string& dst)
1325 {
1326         AlsaPort* src_port = find_port (src);
1327         AlsaPort* dst_port = find_port (dst);
1328
1329         if (!src_port) {
1330                 PBD::error << _("AlsaBackend::connect: Invalid Source port:")
1331                                 << " (" << src <<")" << endmsg;
1332                 return -1;
1333         }
1334         if (!dst_port) {
1335                 PBD::error << _("AlsaBackend::connect: Invalid Destination port:")
1336                         << " (" << dst <<")" << endmsg;
1337                 return -1;
1338         }
1339         return src_port->connect (dst_port);
1340 }
1341
1342 int
1343 AlsaAudioBackend::disconnect (const std::string& src, const std::string& dst)
1344 {
1345         AlsaPort* src_port = find_port (src);
1346         AlsaPort* dst_port = find_port (dst);
1347
1348         if (!src_port || !dst_port) {
1349                 PBD::error << _("AlsaBackend::disconnect: Invalid Port(s)") << endmsg;
1350                 return -1;
1351         }
1352         return src_port->disconnect (dst_port);
1353 }
1354
1355 int
1356 AlsaAudioBackend::connect (PortEngine::PortHandle src, const std::string& dst)
1357 {
1358         AlsaPort* dst_port = find_port (dst);
1359         if (!valid_port (src)) {
1360                 PBD::error << _("AlsaBackend::connect: Invalid Source Port Handle") << endmsg;
1361                 return -1;
1362         }
1363         if (!dst_port) {
1364                 PBD::error << _("AlsaBackend::connect: Invalid Destination Port")
1365                         << " (" << dst << ")" << endmsg;
1366                 return -1;
1367         }
1368         return static_cast<AlsaPort*>(src)->connect (dst_port);
1369 }
1370
1371 int
1372 AlsaAudioBackend::disconnect (PortEngine::PortHandle src, const std::string& dst)
1373 {
1374         AlsaPort* dst_port = find_port (dst);
1375         if (!valid_port (src) || !dst_port) {
1376                 PBD::error << _("AlsaBackend::disconnect: Invalid Port(s)") << endmsg;
1377                 return -1;
1378         }
1379         return static_cast<AlsaPort*>(src)->disconnect (dst_port);
1380 }
1381
1382 int
1383 AlsaAudioBackend::disconnect_all (PortEngine::PortHandle port)
1384 {
1385         if (!valid_port (port)) {
1386                 PBD::error << _("AlsaBackend::disconnect_all: Invalid Port") << endmsg;
1387                 return -1;
1388         }
1389         static_cast<AlsaPort*>(port)->disconnect_all ();
1390         return 0;
1391 }
1392
1393 bool
1394 AlsaAudioBackend::connected (PortEngine::PortHandle port, bool /* process_callback_safe*/)
1395 {
1396         if (!valid_port (port)) {
1397                 PBD::error << _("AlsaBackend::disconnect_all: Invalid Port") << endmsg;
1398                 return false;
1399         }
1400         return static_cast<AlsaPort*>(port)->is_connected ();
1401 }
1402
1403 bool
1404 AlsaAudioBackend::connected_to (PortEngine::PortHandle src, const std::string& dst, bool /*process_callback_safe*/)
1405 {
1406         AlsaPort* dst_port = find_port (dst);
1407         if (!valid_port (src) || !dst_port) {
1408                 PBD::error << _("AlsaBackend::connected_to: Invalid Port") << endmsg;
1409                 return false;
1410         }
1411         return static_cast<AlsaPort*>(src)->is_connected (dst_port);
1412 }
1413
1414 bool
1415 AlsaAudioBackend::physically_connected (PortEngine::PortHandle port, bool /*process_callback_safe*/)
1416 {
1417         if (!valid_port (port)) {
1418                 PBD::error << _("AlsaBackend::physically_connected: Invalid Port") << endmsg;
1419                 return false;
1420         }
1421         return static_cast<AlsaPort*>(port)->is_physically_connected ();
1422 }
1423
1424 int
1425 AlsaAudioBackend::get_connections (PortEngine::PortHandle port, std::vector<std::string>& names, bool /*process_callback_safe*/)
1426 {
1427         if (!valid_port (port)) {
1428                 PBD::error << _("AlsaBackend::get_connections: Invalid Port") << endmsg;
1429                 return -1;
1430         }
1431
1432         assert (0 == names.size ());
1433
1434         const std::vector<AlsaPort*>& connected_ports = static_cast<AlsaPort*>(port)->get_connections ();
1435
1436         for (std::vector<AlsaPort*>::const_iterator i = connected_ports.begin (); i != connected_ports.end (); ++i) {
1437                 names.push_back ((*i)->name ());
1438         }
1439
1440         return (int)names.size ();
1441 }
1442
1443 /* MIDI */
1444 int
1445 AlsaAudioBackend::midi_event_get (
1446                 pframes_t& timestamp,
1447                 size_t& size, uint8_t** buf, void* port_buffer,
1448                 uint32_t event_index)
1449 {
1450         assert (buf && port_buffer);
1451         AlsaMidiBuffer& source = * static_cast<AlsaMidiBuffer*>(port_buffer);
1452         if (event_index >= source.size ()) {
1453                 return -1;
1454         }
1455         AlsaMidiEvent * const event = source[event_index].get ();
1456
1457         timestamp = event->timestamp ();
1458         size = event->size ();
1459         *buf = event->data ();
1460         return 0;
1461 }
1462
1463 int
1464 AlsaAudioBackend::midi_event_put (
1465                 void* port_buffer,
1466                 pframes_t timestamp,
1467                 const uint8_t* buffer, size_t size)
1468 {
1469         assert (buffer && port_buffer);
1470         AlsaMidiBuffer& dst = * static_cast<AlsaMidiBuffer*>(port_buffer);
1471         if (dst.size () && (pframes_t)dst.back ()->timestamp () > timestamp) {
1472 #ifndef NDEBUG
1473                 // nevermind, ::get_buffer() sorts events
1474                 fprintf (stderr, "AlsaMidiBuffer: it's too late for this event. %d > %d\n",
1475                                 (pframes_t)dst.back ()->timestamp (), timestamp);
1476 #endif
1477         }
1478         dst.push_back (boost::shared_ptr<AlsaMidiEvent>(new AlsaMidiEvent (timestamp, buffer, size)));
1479         return 0;
1480 }
1481
1482 uint32_t
1483 AlsaAudioBackend::get_midi_event_count (void* port_buffer)
1484 {
1485         assert (port_buffer);
1486         return static_cast<AlsaMidiBuffer*>(port_buffer)->size ();
1487 }
1488
1489 void
1490 AlsaAudioBackend::midi_clear (void* port_buffer)
1491 {
1492         assert (port_buffer);
1493         AlsaMidiBuffer * buf = static_cast<AlsaMidiBuffer*>(port_buffer);
1494         assert (buf);
1495         buf->clear ();
1496 }
1497
1498 /* Monitoring */
1499
1500 bool
1501 AlsaAudioBackend::can_monitor_input () const
1502 {
1503         return false;
1504 }
1505
1506 int
1507 AlsaAudioBackend::request_input_monitoring (PortEngine::PortHandle, bool)
1508 {
1509         return -1;
1510 }
1511
1512 int
1513 AlsaAudioBackend::ensure_input_monitoring (PortEngine::PortHandle, bool)
1514 {
1515         return -1;
1516 }
1517
1518 bool
1519 AlsaAudioBackend::monitoring_input (PortEngine::PortHandle)
1520 {
1521         return false;
1522 }
1523
1524 /* Latency management */
1525
1526 void
1527 AlsaAudioBackend::set_latency_range (PortEngine::PortHandle port, bool for_playback, LatencyRange latency_range)
1528 {
1529         if (!valid_port (port)) {
1530                 PBD::error << _("AlsaPort::set_latency_range (): invalid port.") << endmsg;
1531         }
1532         static_cast<AlsaPort*>(port)->set_latency_range (latency_range, for_playback);
1533 }
1534
1535 LatencyRange
1536 AlsaAudioBackend::get_latency_range (PortEngine::PortHandle port, bool for_playback)
1537 {
1538         LatencyRange r;
1539         if (!valid_port (port)) {
1540                 PBD::error << _("AlsaPort::get_latency_range (): invalid port.") << endmsg;
1541                 r.min = 0;
1542                 r.max = 0;
1543                 return r;
1544         }
1545         AlsaPort *p = static_cast<AlsaPort*>(port);
1546         assert(p);
1547
1548         r = p->latency_range (for_playback);
1549         if (p->is_physical() && p->is_terminal()) {
1550                 if (p->is_input() && for_playback) {
1551                         r.min += _samples_per_period;
1552                         r.max += _samples_per_period;
1553                 }
1554                 if (p->is_output() && !for_playback) {
1555                         r.min += _samples_per_period;
1556                         r.max += _samples_per_period;
1557                 }
1558         }
1559         return r;
1560 }
1561
1562 /* Discovering physical ports */
1563
1564 bool
1565 AlsaAudioBackend::port_is_physical (PortEngine::PortHandle port) const
1566 {
1567         if (!valid_port (port)) {
1568                 PBD::error << _("AlsaPort::port_is_physical (): invalid port.") << endmsg;
1569                 return false;
1570         }
1571         return static_cast<AlsaPort*>(port)->is_physical ();
1572 }
1573
1574 void
1575 AlsaAudioBackend::get_physical_outputs (DataType type, std::vector<std::string>& port_names)
1576 {
1577         for (size_t i = 0; i < _ports.size (); ++i) {
1578                 AlsaPort* port = _ports[i];
1579                 if ((port->type () == type) && port->is_input () && port->is_physical ()) {
1580                         port_names.push_back (port->name ());
1581                 }
1582         }
1583 }
1584
1585 void
1586 AlsaAudioBackend::get_physical_inputs (DataType type, std::vector<std::string>& port_names)
1587 {
1588         for (size_t i = 0; i < _ports.size (); ++i) {
1589                 AlsaPort* port = _ports[i];
1590                 if ((port->type () == type) && port->is_output () && port->is_physical ()) {
1591                         port_names.push_back (port->name ());
1592                 }
1593         }
1594 }
1595
1596 ChanCount
1597 AlsaAudioBackend::n_physical_outputs () const
1598 {
1599         int n_midi = 0;
1600         int n_audio = 0;
1601         for (size_t i = 0; i < _ports.size (); ++i) {
1602                 AlsaPort* port = _ports[i];
1603                 if (port->is_output () && port->is_physical ()) {
1604                         switch (port->type ()) {
1605                                 case DataType::AUDIO: ++n_audio; break;
1606                                 case DataType::MIDI: ++n_midi; break;
1607                                 default: break;
1608                         }
1609                 }
1610         }
1611         ChanCount cc;
1612         cc.set (DataType::AUDIO, n_audio);
1613         cc.set (DataType::MIDI, n_midi);
1614         return cc;
1615 }
1616
1617 ChanCount
1618 AlsaAudioBackend::n_physical_inputs () const
1619 {
1620         int n_midi = 0;
1621         int n_audio = 0;
1622         for (size_t i = 0; i < _ports.size (); ++i) {
1623                 AlsaPort* port = _ports[i];
1624                 if (port->is_input () && port->is_physical ()) {
1625                         switch (port->type ()) {
1626                                 case DataType::AUDIO: ++n_audio; break;
1627                                 case DataType::MIDI: ++n_midi; break;
1628                                 default: break;
1629                         }
1630                 }
1631         }
1632         ChanCount cc;
1633         cc.set (DataType::AUDIO, n_audio);
1634         cc.set (DataType::MIDI, n_midi);
1635         return cc;
1636 }
1637
1638 /* Getting access to the data buffer for a port */
1639
1640 void*
1641 AlsaAudioBackend::get_buffer (PortEngine::PortHandle port, pframes_t nframes)
1642 {
1643         assert (port);
1644         assert (valid_port (port));
1645         return static_cast<AlsaPort*>(port)->get_buffer (nframes);
1646 }
1647
1648 /* Engine Process */
1649 void *
1650 AlsaAudioBackend::main_process_thread ()
1651 {
1652         AudioEngine::thread_init_callback (this);
1653         _active = true;
1654         _processed_samples = 0;
1655
1656         uint64_t clock1, clock2;
1657         _pcmi->pcm_start ();
1658         int no_proc_errors = 0;
1659         const int bailout = 2 * _samplerate / _samples_per_period;
1660         const int64_t nominal_time = 1e6 * _samples_per_period / _samplerate;
1661
1662         manager.registration_callback();
1663         manager.graph_order_callback();
1664
1665         while (_run) {
1666                 long nr;
1667                 bool xrun = false;
1668
1669                 if (_freewheeling != _freewheel) {
1670                         _freewheel = _freewheeling;
1671                         engine.freewheel_callback (_freewheel);
1672                 }
1673
1674                 if (!_freewheel) {
1675                         nr = _pcmi->pcm_wait ();
1676
1677                         if (_pcmi->state () > 0) {
1678                                 ++no_proc_errors;
1679                                 xrun = true;
1680                         }
1681                         if (_pcmi->state () < 0) {
1682                                 PBD::error << _("AlsaAudioBackend: I/O error. Audio Process Terminated.") << endmsg;
1683                                 break;
1684                         }
1685                         if (no_proc_errors > bailout) {
1686                                 PBD::error
1687                                         << string_compose (
1688                                                         _("AlsaAudioBackend: Audio Process Terminated after %1 consecutive x-runs."),
1689                                                         no_proc_errors)
1690                                         << endmsg;
1691                                 break;
1692                         }
1693
1694                         while (nr >= (long)_samples_per_period && _freewheeling == _freewheel) {
1695                                 uint32_t i = 0;
1696                                 clock1 = g_get_monotonic_time();
1697                                 no_proc_errors = 0;
1698
1699                                 _pcmi->capt_init (_samples_per_period);
1700                                 for (std::vector<AlsaPort*>::const_iterator it = _system_inputs.begin (); it != _system_inputs.end (); ++it, ++i) {
1701                                         _pcmi->capt_chan (i, (float*)((*it)->get_buffer(_samples_per_period)), _samples_per_period);
1702                                 }
1703                                 _pcmi->capt_done (_samples_per_period);
1704
1705                                 /* de-queue incoming midi*/
1706                                 i = 0;
1707                                 for (std::vector<AlsaPort*>::const_iterator it = _system_midi_in.begin (); it != _system_midi_in.end (); ++it, ++i) {
1708                                         assert (_rmidi_in.size() > i);
1709                                         AlsaMidiIn *rm = _rmidi_in.at(i);
1710                                         void *bptr = (*it)->get_buffer(0);
1711                                         pframes_t time;
1712                                         uint8_t data[64]; // match MaxAlsaEventSize in alsa_rawmidi.cc
1713                                         size_t size = sizeof(data);
1714                                         midi_clear(bptr);
1715                                         while (rm->recv_event (time, data, size)) {
1716                                                 midi_event_put(bptr, time, data, size);
1717                                                 size = sizeof(data);
1718                                         }
1719                                         rm->sync_time (clock1);
1720                                 }
1721
1722                                 for (std::vector<AlsaPort*>::const_iterator it = _system_outputs.begin (); it != _system_outputs.end (); ++it) {
1723                                         memset ((*it)->get_buffer (_samples_per_period), 0, _samples_per_period * sizeof (Sample));
1724                                 }
1725
1726                                 /* call engine process callback */
1727                                 _last_process_start = g_get_monotonic_time();
1728                                 if (engine.process_callback (_samples_per_period)) {
1729                                         _pcmi->pcm_stop ();
1730                                         _active = false;
1731                                         return 0;
1732                                 }
1733
1734                                 for (std::vector<AlsaPort*>::iterator it = _system_midi_out.begin (); it != _system_midi_out.end (); ++it) {
1735                                         static_cast<AlsaMidiPort*>(*it)->next_period();
1736                                 }
1737
1738                                 /* queue outgoing midi */
1739                                 i = 0;
1740                                 for (std::vector<AlsaPort*>::const_iterator it = _system_midi_out.begin (); it != _system_midi_out.end (); ++it, ++i) {
1741                                         assert (_rmidi_out.size() > i);
1742                                         const AlsaMidiBuffer * src = static_cast<const AlsaMidiPort*>(*it)->const_buffer();
1743                                         AlsaMidiOut *rm = _rmidi_out.at(i);
1744                                         rm->sync_time (clock1);
1745                                         for (AlsaMidiBuffer::const_iterator mit = src->begin (); mit != src->end (); ++mit) {
1746                                                 rm->send_event ((*mit)->timestamp(), (*mit)->data(), (*mit)->size());
1747                                         }
1748                                 }
1749
1750                                 /* write back audio */
1751                                 i = 0;
1752                                 _pcmi->play_init (_samples_per_period);
1753                                 for (std::vector<AlsaPort*>::const_iterator it = _system_outputs.begin (); it != _system_outputs.end (); ++it, ++i) {
1754                                         _pcmi->play_chan (i, (const float*)(*it)->get_buffer (_samples_per_period), _samples_per_period);
1755                                 }
1756                                 for (; i < _pcmi->nplay (); ++i) {
1757                                         _pcmi->clear_chan (i, _samples_per_period);
1758                                 }
1759                                 _pcmi->play_done (_samples_per_period);
1760                                 nr -= _samples_per_period;
1761                                 _processed_samples += _samples_per_period;
1762
1763                                 /* calculate DSP load */
1764                                 clock2 = g_get_monotonic_time();
1765                                 const int64_t elapsed_time = clock2 - clock1;
1766                                 // low pass filter
1767                                 const float load = elapsed_time / (float) nominal_time;
1768                                 if (load > _dsp_load) {
1769                                         _dsp_load = load;
1770                                 } else {
1771                                         const float a = .2 * _samples_per_period / _samplerate;
1772                                         _dsp_load = _dsp_load + a * (load - _dsp_load) + 1e-12;
1773                                 }
1774                         }
1775
1776                         if (xrun && (_pcmi->capt_xrun() > 0 || _pcmi->play_xrun() > 0)) {
1777                                 engine.Xrun ();
1778 #if 0
1779                                 fprintf(stderr, "ALSA x-run read: %.2f ms, write: %.2f ms\n",
1780                                                 _pcmi->capt_xrun() * 1000.0, _pcmi->play_xrun() * 1000.0);
1781 #endif
1782                         }
1783                 } else {
1784                         // Freewheelin'
1785
1786                         // zero audio input buffers
1787                         for (std::vector<AlsaPort*>::const_iterator it = _system_inputs.begin (); it != _system_inputs.end (); ++it) {
1788                                 memset ((*it)->get_buffer (_samples_per_period), 0, _samples_per_period * sizeof (Sample));
1789                         }
1790
1791                         clock1 = g_get_monotonic_time();
1792                         uint32_t i = 0;
1793                         for (std::vector<AlsaPort*>::const_iterator it = _system_midi_in.begin (); it != _system_midi_in.end (); ++it, ++i) {
1794                                 static_cast<AlsaMidiBuffer*>((*it)->get_buffer(0))->clear ();
1795                                 AlsaMidiIn *rm = _rmidi_in.at(i);
1796                                 void *bptr = (*it)->get_buffer(0);
1797                                 midi_clear(bptr); // zero midi buffer
1798
1799                                 // TODO add an API call for this.
1800                                 pframes_t time;
1801                                 uint8_t data[64]; // match MaxAlsaEventSize in alsa_rawmidi.cc
1802                                 size_t size = sizeof(data);
1803                                 while (rm->recv_event (time, data, size)) {
1804                                         ; // discard midi-data from HW.
1805                                 }
1806                                 rm->sync_time (clock1);
1807                         }
1808
1809                         _last_process_start = 0;
1810                         if (engine.process_callback (_samples_per_period)) {
1811                                 _pcmi->pcm_stop ();
1812                                 _active = false;
1813                                 return 0;
1814                         }
1815
1816                         // drop all outgoing MIDI messages
1817                         for (std::vector<AlsaPort*>::const_iterator it = _system_midi_out.begin (); it != _system_midi_out.end (); ++it) {
1818                                         void *bptr = (*it)->get_buffer(0);
1819                                         midi_clear(bptr);
1820                         }
1821
1822                         _dsp_load = 1.0;
1823                         Glib::usleep (100); // don't hog cpu
1824                 }
1825
1826                 bool connections_changed = false;
1827                 bool ports_changed = false;
1828                 if (!pthread_mutex_trylock (&_port_callback_mutex)) {
1829                         if (_port_change_flag) {
1830                                 ports_changed = true;
1831                                 _port_change_flag = false;
1832                         }
1833                         if (!_port_connection_queue.empty ()) {
1834                                 connections_changed = true;
1835                         }
1836                         while (!_port_connection_queue.empty ()) {
1837                                 PortConnectData *c = _port_connection_queue.back ();
1838                                 manager.connect_callback (c->a, c->b, c->c);
1839                                 _port_connection_queue.pop_back ();
1840                                 delete c;
1841                         }
1842                         pthread_mutex_unlock (&_port_callback_mutex);
1843                 }
1844                 if (ports_changed) {
1845                         manager.registration_callback();
1846                 }
1847                 if (connections_changed) {
1848                         manager.graph_order_callback();
1849                 }
1850                 if (connections_changed || ports_changed) {
1851                         engine.latency_callback(false);
1852                         engine.latency_callback(true);
1853                 }
1854
1855         }
1856         _pcmi->pcm_stop ();
1857         _active = false;
1858         if (_run) {
1859                 engine.halted_callback("ALSA I/O error.");
1860         }
1861         return 0;
1862 }
1863
1864
1865 /******************************************************************************/
1866
1867 static boost::shared_ptr<AlsaAudioBackend> _instance;
1868
1869 static boost::shared_ptr<AudioBackend> backend_factory (AudioEngine& e);
1870 static int instantiate (const std::string& arg1, const std::string& /* arg2 */);
1871 static int deinstantiate ();
1872 static bool already_configured ();
1873 static bool available ();
1874
1875 static ARDOUR::AudioBackendInfo _descriptor = {
1876         "ALSA",
1877         instantiate,
1878         deinstantiate,
1879         backend_factory,
1880         already_configured,
1881         available
1882 };
1883
1884 static boost::shared_ptr<AudioBackend>
1885 backend_factory (AudioEngine& e)
1886 {
1887         if (!_instance) {
1888                 _instance.reset (new AlsaAudioBackend (e, _descriptor));
1889         }
1890         return _instance;
1891 }
1892
1893 static int
1894 instantiate (const std::string& arg1, const std::string& /* arg2 */)
1895 {
1896         s_instance_name = arg1;
1897         return 0;
1898 }
1899
1900 static int
1901 deinstantiate ()
1902 {
1903         _instance.reset ();
1904         return 0;
1905 }
1906
1907 static bool
1908 already_configured ()
1909 {
1910         return false;
1911 }
1912
1913 static bool
1914 available ()
1915 {
1916         return true;
1917 }
1918
1919 extern "C" ARDOURBACKEND_API ARDOUR::AudioBackendInfo* descriptor ()
1920 {
1921         return &_descriptor;
1922 }
1923
1924
1925 /******************************************************************************/
1926 AlsaPort::AlsaPort (AlsaAudioBackend &b, const std::string& name, PortFlags flags)
1927         : _alsa_backend (b)
1928         , _name  (name)
1929         , _flags (flags)
1930 {
1931         _capture_latency_range.min = 0;
1932         _capture_latency_range.max = 0;
1933         _playback_latency_range.min = 0;
1934         _playback_latency_range.max = 0;
1935 }
1936
1937 AlsaPort::~AlsaPort () {
1938         disconnect_all ();
1939 }
1940
1941
1942 int AlsaPort::connect (AlsaPort *port)
1943 {
1944         if (!port) {
1945                 PBD::error << _("AlsaPort::connect (): invalid (null) port") << endmsg;
1946                 return -1;
1947         }
1948
1949         if (type () != port->type ()) {
1950                 PBD::error << _("AlsaPort::connect (): wrong port-type") << endmsg;
1951                 return -1;
1952         }
1953
1954         if (is_output () && port->is_output ()) {
1955                 PBD::error << _("AlsaPort::connect (): cannot inter-connect output ports.") << endmsg;
1956                 return -1;
1957         }
1958
1959         if (is_input () && port->is_input ()) {
1960                 PBD::error << _("AlsaPort::connect (): cannot inter-connect input ports.") << endmsg;
1961                 return -1;
1962         }
1963
1964         if (this == port) {
1965                 PBD::error << _("AlsaPort::connect (): cannot self-connect ports.") << endmsg;
1966                 return -1;
1967         }
1968
1969         if (is_connected (port)) {
1970 #if 0 // don't bother to warn about this for now. just ignore it
1971                 PBD::error << _("AlsaPort::connect (): ports are already connected:")
1972                         << " (" << name () << ") -> (" << port->name () << ")"
1973                         << endmsg;
1974 #endif
1975                 return -1;
1976         }
1977
1978         _connect (port, true);
1979         return 0;
1980 }
1981
1982
1983 void AlsaPort::_connect (AlsaPort *port, bool callback)
1984 {
1985         _connections.push_back (port);
1986         if (callback) {
1987                 port->_connect (this, false);
1988                 _alsa_backend.port_connect_callback (name(),  port->name(), true);
1989         }
1990 }
1991
1992 int AlsaPort::disconnect (AlsaPort *port)
1993 {
1994         if (!port) {
1995                 PBD::error << _("AlsaPort::disconnect (): invalid (null) port") << endmsg;
1996                 return -1;
1997         }
1998
1999         if (!is_connected (port)) {
2000                 PBD::error << _("AlsaPort::disconnect (): ports are not connected:")
2001                         << " (" << name () << ") -> (" << port->name () << ")"
2002                         << endmsg;
2003                 return -1;
2004         }
2005         _disconnect (port, true);
2006         return 0;
2007 }
2008
2009 void AlsaPort::_disconnect (AlsaPort *port, bool callback)
2010 {
2011         std::vector<AlsaPort*>::iterator it = std::find (_connections.begin (), _connections.end (), port);
2012
2013         assert (it != _connections.end ());
2014
2015         _connections.erase (it);
2016
2017         if (callback) {
2018                 port->_disconnect (this, false);
2019                 _alsa_backend.port_connect_callback (name(),  port->name(), false);
2020         }
2021 }
2022
2023
2024 void AlsaPort::disconnect_all ()
2025 {
2026         while (!_connections.empty ()) {
2027                 _connections.back ()->_disconnect (this, false);
2028                 _alsa_backend.port_connect_callback (name(),  _connections.back ()->name(), false);
2029                 _connections.pop_back ();
2030         }
2031 }
2032
2033 bool
2034 AlsaPort::is_connected (const AlsaPort *port) const
2035 {
2036         return std::find (_connections.begin (), _connections.end (), port) != _connections.end ();
2037 }
2038
2039 bool AlsaPort::is_physically_connected () const
2040 {
2041         for (std::vector<AlsaPort*>::const_iterator it = _connections.begin (); it != _connections.end (); ++it) {
2042                 if ((*it)->is_physical ()) {
2043                         return true;
2044                 }
2045         }
2046         return false;
2047 }
2048
2049 /******************************************************************************/
2050
2051 AlsaAudioPort::AlsaAudioPort (AlsaAudioBackend &b, const std::string& name, PortFlags flags)
2052         : AlsaPort (b, name, flags)
2053 {
2054         memset (_buffer, 0, sizeof (_buffer));
2055         mlock(_buffer, sizeof (_buffer));
2056 }
2057
2058 AlsaAudioPort::~AlsaAudioPort () { }
2059
2060 void* AlsaAudioPort::get_buffer (pframes_t n_samples)
2061 {
2062         if (is_input ()) {
2063                 std::vector<AlsaPort*>::const_iterator it = get_connections ().begin ();
2064                 if (it == get_connections ().end ()) {
2065                         memset (_buffer, 0, n_samples * sizeof (Sample));
2066                 } else {
2067                         AlsaAudioPort const * source = static_cast<const AlsaAudioPort*>(*it);
2068                         assert (source && source->is_output ());
2069                         memcpy (_buffer, source->const_buffer (), n_samples * sizeof (Sample));
2070                         while (++it != get_connections ().end ()) {
2071                                 source = static_cast<const AlsaAudioPort*>(*it);
2072                                 assert (source && source->is_output ());
2073                                 Sample* dst = buffer ();
2074                                 const Sample* src = source->const_buffer ();
2075                                 for (uint32_t s = 0; s < n_samples; ++s, ++dst, ++src) {
2076                                         *dst += *src;
2077                                 }
2078                         }
2079                 }
2080         }
2081         return _buffer;
2082 }
2083
2084
2085 AlsaMidiPort::AlsaMidiPort (AlsaAudioBackend &b, const std::string& name, PortFlags flags)
2086         : AlsaPort (b, name, flags)
2087         , _n_periods (1)
2088         , _bufperiod (0)
2089 {
2090         _buffer[0].clear ();
2091         _buffer[1].clear ();
2092 }
2093
2094 AlsaMidiPort::~AlsaMidiPort () { }
2095
2096 struct MidiEventSorter {
2097         bool operator() (const boost::shared_ptr<AlsaMidiEvent>& a, const boost::shared_ptr<AlsaMidiEvent>& b) {
2098                 return *a < *b;
2099         }
2100 };
2101
2102 void* AlsaMidiPort::get_buffer (pframes_t /* nframes */)
2103 {
2104         if (is_input ()) {
2105                 (_buffer[_bufperiod]).clear ();
2106                 for (std::vector<AlsaPort*>::const_iterator i = get_connections ().begin ();
2107                                 i != get_connections ().end ();
2108                                 ++i) {
2109                         const AlsaMidiBuffer * src = static_cast<const AlsaMidiPort*>(*i)->const_buffer ();
2110                         for (AlsaMidiBuffer::const_iterator it = src->begin (); it != src->end (); ++it) {
2111                                 (_buffer[_bufperiod]).push_back (boost::shared_ptr<AlsaMidiEvent>(new AlsaMidiEvent (**it)));
2112                         }
2113                 }
2114                 std::sort ((_buffer[_bufperiod]).begin (), (_buffer[_bufperiod]).end (), MidiEventSorter());
2115         }
2116         return &(_buffer[_bufperiod]);
2117 }
2118
2119 AlsaMidiEvent::AlsaMidiEvent (const pframes_t timestamp, const uint8_t* data, size_t size)
2120         : _size (size)
2121         , _timestamp (timestamp)
2122         , _data (0)
2123 {
2124         if (size > 0) {
2125                 _data = (uint8_t*) malloc (size);
2126                 memcpy (_data, data, size);
2127         }
2128 }
2129
2130 AlsaMidiEvent::AlsaMidiEvent (const AlsaMidiEvent& other)
2131         : _size (other.size ())
2132         , _timestamp (other.timestamp ())
2133         , _data (0)
2134 {
2135         if (other.size () && other.const_data ()) {
2136                 _data = (uint8_t*) malloc (other.size ());
2137                 memcpy (_data, other.const_data (), other.size ());
2138         }
2139 };
2140
2141 AlsaMidiEvent::~AlsaMidiEvent () {
2142         free (_data);
2143 };