globally change all use of "frame" to refer to audio into "sample".
[ardour.git] / libs / backends / portaudio / portaudio_io.cc
1 /*
2  * Copyright (C) 2015 Robin Gareus <robin@gareus.org>
3  * Copyright (C) 2015 Tim Mayberry <mojofunk@gmail.com>
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 <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <assert.h>
24 #include <glibmm.h>
25
26 #include "portaudio_io.h"
27
28 #ifdef WITH_ASIO
29 #include "pa_asio.h"
30 #endif
31
32 #include "pbd/compose.h"
33
34 #include "ardour/audio_backend.h"
35
36 #include "debug.h"
37
38 #define INTERLEAVED_INPUT
39 #define INTERLEAVED_OUTPUT
40
41 using namespace PBD;
42 using namespace ARDOUR;
43
44 PortAudioIO::PortAudioIO ()
45         : _capture_channels (0)
46         , _playback_channels (0)
47         , _stream (0)
48         , _input_buffer (0)
49         , _output_buffer (0)
50         , _cur_sample_rate (0)
51         , _cur_input_latency (0)
52         , _cur_output_latency (0)
53         , _host_api_index(-1)
54 {
55 }
56
57 PortAudioIO::~PortAudioIO ()
58 {
59         close_stream();
60
61         pa_deinitialize ();
62         clear_device_lists ();
63
64         free (_input_buffer); _input_buffer = NULL;
65         free (_output_buffer); _output_buffer = NULL;
66 }
67
68 std::string
69 PortAudioIO::control_app_name (int device_id) const
70 {
71 #ifdef WITH_ASIO
72         if (get_current_host_api_type() == paASIO) {
73                 // is this used for anything, or just acts as a boolean?
74                 return "PortaudioASIO";
75         }
76 #endif
77
78         return std::string();
79 }
80
81 void
82 PortAudioIO::launch_control_app (int device_id)
83 {
84 #ifdef WITH_ASIO
85         PaError err = PaAsio_ShowControlPanel (device_id, NULL);
86
87         if (err != paNoError) {
88                 // error << ?
89                 DEBUG_AUDIO (string_compose (
90                     "Unable to show control panel for device with index %1\n", device_id));
91         }
92 #endif
93 }
94
95 void
96 PortAudioIO::get_default_sample_rates (std::vector<float>& rates)
97 {
98         rates.push_back(8000.0);
99         rates.push_back(22050.0);
100         rates.push_back(24000.0);
101         rates.push_back(44100.0);
102         rates.push_back(48000.0);
103         rates.push_back(88200.0);
104         rates.push_back(96000.0);
105         rates.push_back(176400.0);
106         rates.push_back(192000.0);
107 }
108
109 int
110 PortAudioIO::available_sample_rates(int device_id, std::vector<float>& sampleRates)
111 {
112         if (!pa_initialize()) return -1;
113
114 #ifdef WITH_ASIO
115         if (get_current_host_api_type() == paASIO) {
116                 get_default_sample_rates(sampleRates);
117                 return 0;
118         }
119 #endif
120
121         // TODO use  separate int device_input, int device_output ?!
122         if (device_id == DeviceDefault) {
123                 device_id = get_default_input_device ();
124         }
125
126         DEBUG_AUDIO (
127             string_compose ("Querying Samplerates for device %1\n", device_id));
128
129         sampleRates.clear();
130         const PaDeviceInfo* nfo = Pa_GetDeviceInfo(device_id);
131
132         if (nfo) {
133                 PaStreamParameters inputParam;
134                 PaStreamParameters outputParam;
135
136                 inputParam.device = device_id;
137                 inputParam.channelCount = nfo->maxInputChannels;
138                 inputParam.sampleFormat = paFloat32;
139                 inputParam.suggestedLatency = 0;
140                 inputParam.hostApiSpecificStreamInfo = 0;
141
142                 outputParam.device = device_id;
143                 outputParam.channelCount = nfo->maxOutputChannels;
144                 outputParam.sampleFormat = paFloat32;
145                 outputParam.suggestedLatency = 0;
146                 outputParam.hostApiSpecificStreamInfo = 0;
147
148                 std::vector<float> rates;
149                 get_default_sample_rates(rates);
150
151                 for (std::vector<float>::const_iterator i = rates.begin(); i != rates.end();
152                      ++i) {
153                         if (paFormatIsSupported ==
154                             Pa_IsFormatSupported(nfo->maxInputChannels > 0 ? &inputParam : NULL,
155                                                  nfo->maxOutputChannels > 0 ? &outputParam : NULL,
156                                                  *i)) {
157                                 sampleRates.push_back(*i);
158                         }
159                 }
160         }
161
162         if (sampleRates.empty()) {
163                 // fill in something..
164                 get_default_sample_rates(sampleRates);
165         }
166
167         return 0;
168 }
169
170 #ifdef WITH_ASIO
171 bool
172 PortAudioIO::get_asio_buffer_properties (int device_id,
173                                          long& min_size_samples,
174                                          long& max_size_samples,
175                                          long& preferred_size_samples,
176                                          long& granularity)
177 {
178         // we shouldn't really need all these checks but it shouldn't hurt
179         const PaDeviceInfo* device_info = Pa_GetDeviceInfo(device_id);
180
181         if (!device_info) {
182                 DEBUG_AUDIO (string_compose (
183                     "Unable to get device info from device index %1\n", device_id));
184                 return false;
185         }
186
187         if (get_current_host_api_type() != paASIO) {
188                 DEBUG_AUDIO (string_compose (
189                     "ERROR device_id %1 is not an ASIO device\n", device_id));
190                 return false;
191         }
192
193         PaError err = PaAsio_GetAvailableBufferSizes (device_id,
194                                                       &min_size_samples,
195                                                       &max_size_samples,
196                                                       &preferred_size_samples,
197                                                       &granularity);
198
199         if (err != paNoError) {
200                 DEBUG_AUDIO (string_compose (
201                     "Unable to determine available buffer sizes for device %1\n", device_id));
202                 return false;
203         }
204         return true;
205 }
206
207 static
208 bool
209 is_power_of_two (uint32_t v)
210 {
211         return ((v != 0) && !(v & (v - 1)));
212 }
213
214 bool
215 PortAudioIO::get_asio_buffer_sizes(int device_id,
216                                    std::vector<uint32_t>& buffer_sizes,
217                                    bool preferred_only)
218 {
219         long min_size_samples = 0;
220         long max_size_samples = 0;
221         long preferred_size_samples = 0;
222         long granularity = 0;
223
224         if (!get_asio_buffer_properties (device_id,
225                                          min_size_samples,
226                                          max_size_samples,
227                                          preferred_size_samples,
228                                          granularity)) {
229                 DEBUG_AUDIO (string_compose (
230                     "Unable to get device buffer properties from device index %1\n", device_id));
231                 return false;
232         }
233
234         DEBUG_AUDIO (string_compose ("ASIO buffer properties for device %1, "
235                                      "min_size_samples: %2, max_size_samples: %3, "
236                                      "preferred_size_samples: %4, granularity: %5\n",
237                                      device_id,
238                                      min_size_samples,
239                                      max_size_samples,
240                                      preferred_size_samples,
241                                      granularity));
242
243         bool driver_returns_one_size = (min_size_samples == max_size_samples) &&
244                                        (min_size_samples == preferred_size_samples);
245
246         if (preferred_only || driver_returns_one_size) {
247                 buffer_sizes.push_back(preferred_size_samples);
248                 return true;
249         }
250
251         long buffer_size = min_size_samples;
252
253         // If min size and granularity are power of two then just use values that
254         // are power of 2 even if the granularity allows for more values
255         bool use_power_of_two =
256             is_power_of_two(min_size_samples) && is_power_of_two(granularity);
257
258         if (granularity <= 0 || use_power_of_two) {
259                 // driver uses buffer sizes that are power of 2
260                 while (buffer_size <= max_size_samples) {
261                         buffer_sizes.push_back(buffer_size);
262                         buffer_size *= 2;
263                 }
264         } else {
265                 if (min_size_samples == max_size_samples) {
266                         // The devices I have tested either return the same values for
267                         // min/max/preferred and changing buffer size is intended to only be
268                         // done via the control dialog or they return a range where min != max
269                         // but I guess min == max could happen if a driver only supports a single
270                         // buffer size
271                         buffer_sizes.push_back(min_size_samples);
272                         return true;
273                 }
274
275                 // If min_size_samples is not power of 2 use at most 8 of the possible
276                 // buffer sizes spread evenly between min and max
277                 long max_values = 8;
278                 while (((max_size_samples - min_size_samples) / granularity) > max_values) {
279                         granularity *= 2;
280                 }
281
282                 while (buffer_size < max_size_samples) {
283                         buffer_sizes.push_back(buffer_size);
284                         buffer_size += granularity;
285                 }
286                 buffer_sizes.push_back(max_size_samples);
287         }
288         return true;
289 }
290 #endif
291
292 void
293 PortAudioIO::get_default_buffer_sizes(std::vector<uint32_t>& buffer_sizes)
294 {
295         buffer_sizes.push_back(64);
296         buffer_sizes.push_back(128);
297         buffer_sizes.push_back(256);
298         buffer_sizes.push_back(512);
299         buffer_sizes.push_back(1024);
300         buffer_sizes.push_back(2048);
301         buffer_sizes.push_back(4096);
302 }
303
304 int
305 PortAudioIO::available_buffer_sizes(int device_id, std::vector<uint32_t>& buffer_sizes)
306 {
307 #ifdef WITH_ASIO
308         if (get_current_host_api_type() == paASIO) {
309                 if (get_asio_buffer_sizes (device_id, buffer_sizes, false)) {
310                         return 0;
311                 }
312         }
313 #endif
314
315         get_default_buffer_sizes (buffer_sizes);
316
317         return 0;
318 }
319
320 void
321 PortAudioIO::input_device_list(std::map<int, std::string> &devices) const
322 {
323         for (std::map<int, paDevice*>::const_iterator i = _input_devices.begin ();
324              i != _input_devices.end ();
325              ++i) {
326                 devices.insert (std::pair<int, std::string>(i->first, Glib::locale_to_utf8(i->second->name)));
327         }
328 }
329
330 void
331 PortAudioIO::output_device_list(std::map<int, std::string> &devices) const
332 {
333         for (std::map<int, paDevice*>::const_iterator i = _output_devices.begin ();
334              i != _output_devices.end ();
335              ++i) {
336                 devices.insert (std::pair<int, std::string>(i->first, Glib::locale_to_utf8(i->second->name)));
337         }
338 }
339
340 bool&
341 PortAudioIO::pa_initialized()
342 {
343         static bool s_initialized = false;
344         return s_initialized;
345 }
346
347 bool
348 PortAudioIO::pa_initialize()
349 {
350         if (pa_initialized()) return true;
351
352         PaError err = Pa_Initialize();
353         if (err != paNoError) {
354                 return false;
355         }
356         pa_initialized() = true;
357
358         return true;
359 }
360
361 bool
362 PortAudioIO::pa_deinitialize()
363 {
364         if (!pa_initialized()) return true;
365
366         PaError err = Pa_Terminate();
367         if (err != paNoError) {
368                 return false;
369         }
370         pa_initialized() = false;
371         return true;
372 }
373
374 void
375 PortAudioIO::host_api_list (std::vector<std::string>& api_list)
376 {
377         if (!pa_initialize()) return;
378
379         PaHostApiIndex count = Pa_GetHostApiCount();
380
381         if (count < 0) return;
382
383         for (int i = 0; i < count; ++i) {
384                 const PaHostApiInfo* info = Pa_GetHostApiInfo (i);
385                 if (info->name != NULL) { // possible?
386                         api_list.push_back (info->name);
387                 }
388         }
389 }
390
391
392 PaHostApiTypeId
393 PortAudioIO::get_current_host_api_type () const
394 {
395         const PaHostApiInfo* info = Pa_GetHostApiInfo (_host_api_index);
396
397         if (info == NULL) {
398                 DEBUG_AUDIO(string_compose(
399                     "Unable to determine Host API type from index %1\n", _host_api_index));
400                 return (PaHostApiTypeId)0;
401         }
402
403         return info->type;
404 }
405
406 std::string
407 PortAudioIO::get_host_api_name_from_index (PaHostApiIndex index)
408 {
409         std::vector<std::string> api_list;
410         host_api_list(api_list);
411         return api_list[index];
412 }
413
414 bool
415 PortAudioIO::set_host_api (const std::string& host_api_name)
416 {
417         PaHostApiIndex new_index = get_host_api_index_from_name (host_api_name);
418
419         if (new_index < 0) {
420                 DEBUG_AUDIO ("Portaudio: Error setting host API\n");
421                 return false;
422         }
423         _host_api_index = new_index;
424         _host_api_name = host_api_name;
425         return true;
426 }
427
428 PaHostApiIndex
429 PortAudioIO::get_host_api_index_from_name (const std::string& name)
430 {
431         if (!pa_initialize()) return -1;
432
433         PaHostApiIndex count = Pa_GetHostApiCount();
434
435         if (count < 0) {
436                 DEBUG_AUDIO ("Host API count < 0\n");
437                 return -1;
438         }
439
440         for (int i = 0; i < count; ++i) {
441                 const PaHostApiInfo* info = Pa_GetHostApiInfo (i);
442                 if (info != NULL && info->name != NULL) { // possible?
443                         if (name == info->name) {
444                                 return i;
445                         }
446                 }
447         }
448         DEBUG_AUDIO (string_compose ("Unable to get host API from name: %1\n", name));
449
450         return -1;
451 }
452
453 PaDeviceIndex
454 PortAudioIO::get_default_input_device () const
455 {
456         const PaHostApiInfo* info = Pa_GetHostApiInfo (_host_api_index);
457         if (info == NULL) return -1;
458         return info->defaultInputDevice;
459 }
460
461 PaDeviceIndex
462 PortAudioIO::get_default_output_device () const
463 {
464         const PaHostApiInfo* info = Pa_GetHostApiInfo (_host_api_index);
465         if (info == NULL) return -1;
466         return info->defaultOutputDevice;
467 }
468
469 void
470 PortAudioIO::clear_device_lists ()
471 {
472         for (std::map<int, paDevice*>::const_iterator i = _input_devices.begin (); i != _input_devices.end(); ++i) {
473                 delete i->second;
474         }
475         _input_devices.clear();
476
477         for (std::map<int, paDevice*>::const_iterator i = _output_devices.begin (); i != _output_devices.end(); ++i) {
478                 delete i->second;
479         }
480         _output_devices.clear();
481 }
482
483 void
484 PortAudioIO::add_none_devices ()
485 {
486         _input_devices.insert(std::pair<int, paDevice*>(
487             DeviceNone, new paDevice(AudioBackend::get_standard_device_name(AudioBackend::DeviceNone), 0, 0)));
488         _output_devices.insert(std::pair<int, paDevice*>(
489             DeviceNone, new paDevice(AudioBackend::get_standard_device_name(AudioBackend::DeviceNone), 0, 0)));
490 }
491
492 void
493 PortAudioIO::add_default_devices ()
494 {
495         const PaHostApiInfo* info = Pa_GetHostApiInfo (_host_api_index);
496         if (info == NULL) return;
497
498         const PaDeviceInfo* nfo_i = Pa_GetDeviceInfo(get_default_input_device());
499         const PaDeviceInfo* nfo_o = Pa_GetDeviceInfo(get_default_output_device());
500         if (nfo_i && nfo_o) {
501                 _input_devices.insert (std::pair<int, paDevice*> (DeviceDefault,
502                                         new paDevice(AudioBackend::get_standard_device_name(AudioBackend::DeviceDefault),
503                                                 nfo_i->maxInputChannels,
504                                                 nfo_o->maxOutputChannels
505                                                 )));
506                 _output_devices.insert (std::pair<int, paDevice*> (DeviceDefault,
507                                         new paDevice(AudioBackend::get_standard_device_name(AudioBackend::DeviceDefault),
508                                                 nfo_i->maxInputChannels,
509                                                 nfo_o->maxOutputChannels
510                                                 )));
511         }
512 }
513
514 void
515 PortAudioIO::add_devices ()
516 {
517         const PaHostApiInfo* info = Pa_GetHostApiInfo (_host_api_index);
518         if (info == NULL) return;
519
520         int n_devices = Pa_GetDeviceCount();
521
522         DEBUG_AUDIO (string_compose ("PortAudio found %1 devices\n", n_devices));
523
524         for (int i = 0 ; i < n_devices; ++i) {
525                 const PaDeviceInfo* nfo = Pa_GetDeviceInfo(i);
526
527                 if (!nfo) continue;
528                 if (nfo->hostApi != _host_api_index) continue;
529
530                 DEBUG_AUDIO (string_compose (" (%1) '%2' '%3' in: %4 (lat: %5 .. %6) out: %7 "
531                                              "(lat: %8 .. %9) sr:%10\n",
532                                              i,
533                                              info->name,
534                                              nfo->name,
535                                              nfo->maxInputChannels,
536                                              nfo->defaultLowInputLatency * 1e3,
537                                              nfo->defaultHighInputLatency * 1e3,
538                                              nfo->maxOutputChannels,
539                                              nfo->defaultLowOutputLatency * 1e3,
540                                              nfo->defaultHighOutputLatency * 1e3,
541                                              nfo->defaultSampleRate));
542
543                 if ( nfo->maxInputChannels == 0 && nfo->maxOutputChannels == 0) {
544                         continue;
545                 }
546
547                 if (nfo->maxInputChannels > 0) {
548                         _input_devices.insert (std::pair<int, paDevice*> (i, new paDevice(
549                                                         nfo->name,
550                                                         nfo->maxInputChannels,
551                                                         nfo->maxOutputChannels
552                                                         )));
553                 }
554                 if (nfo->maxOutputChannels > 0) {
555                         _output_devices.insert (std::pair<int, paDevice*> (i, new paDevice(
556                                                         nfo->name,
557                                                         nfo->maxInputChannels,
558                                                         nfo->maxOutputChannels
559                                                         )));
560                 }
561         }
562 }
563
564 bool
565 PortAudioIO::update_devices()
566 {
567         DEBUG_AUDIO ("Update devices\n");
568         if (_stream != NULL) return false;
569         pa_deinitialize();
570         if (!pa_initialize()) return false;
571
572         clear_device_lists ();
573
574         // ASIO doesn't support separate input/output devices so adding None
575         // doesn't make sense
576         if (get_current_host_api_type() != paASIO) {
577                 add_none_devices ();
578         }
579         add_devices ();
580         return true;
581 }
582
583 void
584 PortAudioIO::reset_stream_dependents ()
585 {
586         _capture_channels = 0;
587         _playback_channels = 0;
588         _cur_sample_rate = 0;
589         _cur_input_latency = 0;
590         _cur_output_latency = 0;
591 }
592
593 PaErrorCode
594 PortAudioIO::close_stream()
595 {
596         if (!_stream) return paNoError;
597
598         PaError err = Pa_CloseStream (_stream);
599
600         if (err != paNoError) {
601                 return (PaErrorCode)err;
602         }
603         _stream = NULL;
604
605         reset_stream_dependents();
606
607         free (_input_buffer); _input_buffer = NULL;
608         free (_output_buffer); _output_buffer = NULL;
609         return paNoError;
610 }
611
612 PaErrorCode
613 PortAudioIO::start_stream()
614 {
615         PaError err = Pa_StartStream (_stream);
616
617         if (err != paNoError) {
618                 DEBUG_AUDIO(string_compose("PortAudio failed to start stream %1\n",
619                                            Pa_GetErrorText(err)));
620                 return (PaErrorCode)err;
621         }
622         return paNoError;
623 }
624
625 bool
626 PortAudioIO::set_sample_rate_and_latency_from_stream ()
627 {
628         const PaStreamInfo* nfo_s = Pa_GetStreamInfo(_stream);
629
630         if (nfo_s == NULL) {
631                 return false;
632         }
633
634         _cur_sample_rate = nfo_s->sampleRate;
635         _cur_input_latency = nfo_s->inputLatency * _cur_sample_rate;
636         _cur_output_latency = nfo_s->outputLatency * _cur_sample_rate;
637
638         DEBUG_AUDIO (string_compose ("PA Sample Rate %1 SPS\n", _cur_sample_rate));
639
640         DEBUG_AUDIO (string_compose ("PA Input Latency %1ms, %2 spl\n",
641                                      1e3 * nfo_s->inputLatency,
642                                      _cur_input_latency));
643
644         DEBUG_AUDIO (string_compose ("PA Output Latency %1ms, %2 spl\n",
645                                      1e3 * nfo_s->outputLatency,
646                                      _cur_output_latency));
647         return true;
648 }
649
650 bool
651 PortAudioIO::allocate_buffers_for_blocking_api (uint32_t samples_per_period)
652 {
653         if (_capture_channels > 0) {
654                 _input_buffer =
655                     (float*)malloc(samples_per_period * _capture_channels * sizeof(float));
656                 if (!_input_buffer) {
657                         DEBUG_AUDIO("PortAudio failed to allocate input buffer.\n");
658                         return false;
659                 }
660         }
661
662         if (_playback_channels > 0) {
663                 _output_buffer =
664                     (float*)calloc(samples_per_period * _playback_channels, sizeof(float));
665                 if (!_output_buffer) {
666                         DEBUG_AUDIO("PortAudio failed to allocate output buffer.\n");
667                         return false;
668                 }
669         }
670         return true;
671 }
672
673 bool
674 PortAudioIO::get_input_stream_params(int device_input,
675                                      PaStreamParameters& inputParam) const
676 {
677         const PaDeviceInfo *nfo_in = NULL;
678
679         if (device_input == DeviceDefault) {
680                 device_input = get_default_input_device ();
681         }
682
683         if (device_input == DeviceNone) {
684                 return false;
685         }
686
687         nfo_in = Pa_GetDeviceInfo(device_input);
688
689         if (nfo_in == NULL) {
690                 DEBUG_AUDIO ("PortAudio Cannot Query Input Device Info\n");
691                 return false;
692         }
693
694         inputParam.device = device_input;
695         inputParam.channelCount = nfo_in->maxInputChannels;
696 #ifdef INTERLEAVED_INPUT
697         inputParam.sampleFormat = paFloat32;
698 #else
699         inputParam.sampleFormat = paFloat32 | paNonInterleaved;
700 #endif
701         inputParam.suggestedLatency = nfo_in->defaultLowInputLatency;
702         inputParam.hostApiSpecificStreamInfo = NULL;
703
704         return true;
705 }
706
707 bool
708 PortAudioIO::get_output_stream_params(int device_output,
709                                       PaStreamParameters& outputParam) const
710 {
711         const PaDeviceInfo *nfo_out = NULL;
712
713         if (device_output == DeviceDefault) {
714                 device_output = get_default_output_device ();
715         }
716
717         if (device_output == DeviceNone) {
718                 return false;
719         }
720
721         nfo_out = Pa_GetDeviceInfo(device_output);
722
723         if (nfo_out == NULL) {
724                 DEBUG_AUDIO ("PortAudio Cannot Query Output Device Info\n");
725                 return false;
726         }
727
728         outputParam.device = device_output;
729         outputParam.channelCount = nfo_out->maxOutputChannels;
730 #ifdef INTERLEAVED_OUTPUT
731         outputParam.sampleFormat = paFloat32;
732 #else
733         outputParam.sampleFormat = paFloat32 | paNonInterleaved;
734 #endif
735         outputParam.suggestedLatency = nfo_out->defaultLowOutputLatency;
736         outputParam.hostApiSpecificStreamInfo = NULL;
737
738         return true;
739 }
740
741 PaErrorCode
742 PortAudioIO::pre_stream_open(int device_input,
743                              PaStreamParameters& inputParam,
744                              int device_output,
745                              PaStreamParameters& outputParam)
746 {
747         if (!pa_initialize()) {
748                 DEBUG_AUDIO ("PortAudio Initialization Failed\n");
749                 return paNotInitialized;
750         }
751
752         reset_stream_dependents ();
753
754         DEBUG_AUDIO (string_compose (
755             "PortAudio Device IDs: i:%1 o:%2\n", device_input, device_output));
756
757         if (device_input == DeviceNone && device_output == DeviceNone) {
758                 return paBadIODeviceCombination;
759         }
760
761         if (get_input_stream_params(device_input, inputParam)) {
762                 _capture_channels = inputParam.channelCount;
763         }
764
765         if (get_output_stream_params(device_output, outputParam)) {
766                 _playback_channels = outputParam.channelCount;
767         }
768
769         if (_capture_channels == 0 && _playback_channels == 0) {
770                 DEBUG_AUDIO("PortAudio no input or output channels.\n");
771                 return paBadIODeviceCombination;
772         }
773
774         DEBUG_AUDIO (string_compose ("PortAudio Channels: in:%1 out:%2\n",
775                                      _capture_channels,
776                                      _playback_channels));
777
778         return paNoError;
779 }
780
781 PaErrorCode
782 PortAudioIO::open_callback_stream(int device_input,
783                                   int device_output,
784                                   double sample_rate,
785                                   uint32_t samples_per_period,
786                                   PaStreamCallback* callback,
787                                   void* data)
788 {
789         PaStreamParameters inputParam;
790         PaStreamParameters outputParam;
791
792         PaErrorCode error_code =
793             pre_stream_open(device_input, inputParam, device_output, outputParam);
794
795         if (error_code != paNoError) return error_code;
796
797         PaError err = paNoError;
798
799         DEBUG_AUDIO ("Open Callback Stream\n");
800
801         err = Pa_OpenStream(&_stream,
802                             _capture_channels > 0 ? &inputParam : NULL,
803                             _playback_channels > 0 ? &outputParam : NULL,
804                             sample_rate,
805                             samples_per_period,
806                             paDitherOff,
807                             callback,
808                             data);
809
810         if (err != paNoError) {
811                 DEBUG_AUDIO(string_compose("PortAudio failed to open stream %1\n",
812                                            Pa_GetErrorText(err)));
813                 return paInternalError;
814         }
815
816         if (!set_sample_rate_and_latency_from_stream()) {
817                 DEBUG_AUDIO ("PortAudio failed to query stream information.\n");
818                 close_stream();
819                 return paInternalError;
820         }
821
822         return paNoError;
823 }
824
825 PaErrorCode
826 PortAudioIO::open_blocking_stream(int device_input,
827                                   int device_output,
828                                   double sample_rate,
829                                   uint32_t samples_per_period)
830 {
831         PaStreamParameters inputParam;
832         PaStreamParameters outputParam;
833
834         PaErrorCode error_code =
835             pre_stream_open(device_input, inputParam, device_output, outputParam);
836
837         if (error_code != paNoError) return error_code;
838
839         PaError err = paNoError;
840
841         err = Pa_OpenStream (
842                         &_stream,
843                         _capture_channels > 0 ? &inputParam: NULL,
844                         _playback_channels > 0 ? &outputParam: NULL,
845                         sample_rate,
846                         samples_per_period,
847                         paDitherOff,
848                         NULL, NULL);
849
850         if (err != paNoError) {
851                 DEBUG_AUDIO(string_compose("PortAudio failed to open stream %1\n",
852                                            Pa_GetErrorText(err)));
853                 return (PaErrorCode)err;
854         }
855
856         if (!set_sample_rate_and_latency_from_stream()) {
857                 DEBUG_AUDIO ("PortAudio failed to query stream information.\n");
858                 close_stream();
859                 return paInternalError;
860         }
861
862         if (!allocate_buffers_for_blocking_api(samples_per_period)) {
863                 close_stream();
864                 return paInternalError;
865         }
866         return paNoError;
867 }
868
869 int
870 PortAudioIO::next_cycle (uint32_t n_samples)
871 {
872         bool xrun = false;
873         PaError err;
874         err = Pa_IsStreamActive (_stream);
875         if (err != 1) {
876                 //   0: inactive / aborted
877                 // < 0: error
878                 return -1;
879         }
880
881         // TODO, check drift..  process part with larger capacity first.
882         // Pa_GetStreamReadAvailable(_stream) < Pa_GetStreamWriteAvailable(_stream)
883
884         if (_playback_channels > 0) {
885                 err = Pa_WriteStream (_stream, _output_buffer, n_samples);
886                 if (err) xrun = true;
887         }
888
889         if (_capture_channels > 0) {
890                 err = Pa_ReadStream (_stream, _input_buffer, n_samples);
891                 if (err) {
892                         memset (_input_buffer, 0, sizeof(float) * n_samples * _capture_channels);
893                         xrun = true;
894                 }
895         }
896
897
898         return xrun ? 1 : 0;
899 }
900
901 std::string
902 PortAudioIO::get_input_channel_name (int device_id, uint32_t channel) const
903 {
904 #ifdef WITH_ASIO
905         const char* channel_name;
906
907         // This will return an error for non-ASIO devices so no need to check if
908         // the device_id corresponds to an ASIO device.
909         PaError err = PaAsio_GetInputChannelName (device_id, channel, &channel_name);
910
911         if (err == paNoError) {
912                 DEBUG_AUDIO (
913                     string_compose ("Input channel name for device %1, channel %2 is %3\n",
914                                     device_id,
915                                     channel,
916                                     channel_name));
917                 return channel_name;
918         }
919 #endif
920         return std::string();
921 }
922
923 std::string
924 PortAudioIO::get_output_channel_name (int device_id, uint32_t channel) const
925 {
926 #ifdef WITH_ASIO
927         const char* channel_name;
928
929         PaError err = PaAsio_GetOutputChannelName (device_id, channel, &channel_name);
930
931         if (err == paNoError) {
932                 DEBUG_AUDIO (
933                     string_compose ("Output channel name for device %1, channel %2 is %3\n",
934                                     device_id,
935                                     channel,
936                                     channel_name));
937                 return channel_name;
938         }
939 #endif
940         return std::string();
941 }
942
943 #ifdef INTERLEAVED_INPUT
944
945 int
946 PortAudioIO::get_capture_channel (uint32_t chn, float *input, uint32_t n_samples)
947 {
948         assert(chn < _capture_channels);
949         const uint32_t stride = _capture_channels;
950         float *ptr = _input_buffer + chn;
951         while (n_samples-- > 0) {
952                 *input++ = *ptr;
953                 ptr += stride;
954         }
955         return 0;
956 }
957
958 #else
959
960 int
961 PortAudioIO::get_capture_channel (uint32_t chn, float *input, uint32_t n_samples)
962 {
963         assert(chn < _capture_channels);
964         memcpy((void*)input, &(_input_buffer[chn * n_samples]), n_samples * sizeof(float));
965         return 0;
966 }
967
968 #endif
969
970
971 #ifdef INTERLEAVED_OUTPUT
972
973 int
974 PortAudioIO::set_playback_channel (uint32_t chn, const float *output, uint32_t n_samples)
975 {
976         assert(chn < _playback_channels);
977         const uint32_t stride = _playback_channels;
978         float *ptr = _output_buffer + chn;
979         while (n_samples-- > 0) {
980                 *ptr = *output++;
981                 ptr += stride;
982         }
983         return 0;
984 }
985
986 #else
987
988 int
989 PortAudioIO::set_playback_channel (uint32_t chn, const float *output, uint32_t n_samples)
990 {
991         assert(chn < _playback_channels);
992         memcpy((void*)&(_output_buffer[chn * n_samples]), (void*)output, n_samples * sizeof(float));
993         return 0;
994 }
995
996 #endif