Support selecting separate input and output devices in portaudio backend
[ardour.git] / libs / backends / portaudio / portaudio_io.cc
1 /*
2  * Copyright (C) 2015 Robin Gareus <robin@gareus.org>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17  */
18
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <assert.h>
23 #include <glibmm.h>
24 #include "portaudio_io.h"
25
26 #define INTERLEAVED_INPUT
27 #define INTERLEAVED_OUTPUT
28
29 using namespace ARDOUR;
30
31 PortAudioIO::PortAudioIO ()
32         : _state (-1)
33         , _initialized (false)
34         , _capture_channels (0)
35         , _playback_channels (0)
36         , _stream (0)
37         , _input_buffer (0)
38         , _output_buffer (0)
39         , _cur_sample_rate (0)
40         , _cur_input_latency (0)
41         , _cur_output_latency (0)
42 {
43 }
44
45 PortAudioIO::~PortAudioIO ()
46 {
47         if (_state == 0) {
48                 pcm_stop();
49         }
50         if (_initialized) {
51                 Pa_Terminate();
52         }
53
54         clear_device_lists ();
55
56         free (_input_buffer); _input_buffer = NULL;
57         free (_output_buffer); _output_buffer = NULL;
58 }
59
60
61 int
62 PortAudioIO::available_sample_rates(int device_id, std::vector<float>& sampleRates)
63 {
64         static const float ardourRates[] = { 8000.0, 22050.0, 24000.0, 44100.0, 48000.0, 88200.0, 96000.0, 176400.0, 192000.0};
65
66         assert(_initialized);
67
68         // TODO use  separate int device_input, int device_output ?!
69         if (device_id == -1) {
70                 device_id = get_default_input_device ();
71         }
72 #ifndef NDEBUG
73         printf("PortAudio: Querying Samplerates for device %d\n", device_id);
74 #endif
75
76         sampleRates.clear();
77         const PaDeviceInfo* nfo = Pa_GetDeviceInfo(device_id);
78
79         if (nfo) {
80                 PaStreamParameters inputParam;
81                 PaStreamParameters outputParam;
82
83                 inputParam.device = device_id;
84                 inputParam.channelCount = nfo->maxInputChannels;
85                 inputParam.sampleFormat = paFloat32;
86                 inputParam.suggestedLatency = 0;
87                 inputParam.hostApiSpecificStreamInfo = 0;
88
89                 outputParam.device = device_id;
90                 outputParam.channelCount = nfo->maxOutputChannels;
91                 outputParam.sampleFormat = paFloat32;
92                 outputParam.suggestedLatency = 0;
93                 outputParam.hostApiSpecificStreamInfo = 0;
94
95                 for (uint32_t i = 0; i < sizeof(ardourRates)/sizeof(float); ++i) {
96                         if (paFormatIsSupported == Pa_IsFormatSupported(
97                                                 nfo->maxInputChannels > 0 ? &inputParam : NULL,
98                                                 nfo->maxOutputChannels > 0 ? &outputParam : NULL,
99                                                 ardourRates[i])) {
100                                 sampleRates.push_back (ardourRates[i]);
101                         }
102                 }
103         }
104
105         if (sampleRates.empty()) {
106                 // fill in something..
107                 sampleRates.push_back (44100.0);
108                 sampleRates.push_back (48000.0);
109         }
110
111         return 0;
112 }
113
114 int
115 PortAudioIO::available_buffer_sizes(int device_id, std::vector<uint32_t>& bufferSizes)
116 {
117         // TODO
118         static const uint32_t ardourSizes[] = { 64, 128, 256, 512, 1024, 2048, 4096 };
119         for(uint32_t i = 0; i < sizeof(ardourSizes)/sizeof(uint32_t); ++i) {
120                 bufferSizes.push_back (ardourSizes[i]);
121         }
122         return 0;
123 }
124
125 void
126 PortAudioIO::input_device_list(std::map<int, std::string> &devices) const
127 {
128         for (std::map<int, paDevice*>::const_iterator i = _input_devices.begin ();
129              i != _input_devices.end ();
130              ++i) {
131                 devices.insert (std::pair<int, std::string>(i->first, Glib::locale_to_utf8(i->second->name)));
132         }
133 }
134
135 void
136 PortAudioIO::output_device_list(std::map<int, std::string> &devices) const
137 {
138         for (std::map<int, paDevice*>::const_iterator i = _output_devices.begin ();
139              i != _output_devices.end ();
140              ++i) {
141                 devices.insert (std::pair<int, std::string>(i->first, Glib::locale_to_utf8(i->second->name)));
142         }
143 }
144
145 bool
146 PortAudioIO::initialize_pa ()
147 {
148         PaError err = paNoError;
149
150         if (!_initialized) {
151                 err = Pa_Initialize();
152                 if (err != paNoError) {
153                         return false;
154                 }
155                 _initialized = true;
156         }
157
158         return true;
159 }
160
161 void
162 PortAudioIO::host_api_list (std::vector<std::string>& api_list)
163 {
164         if (!initialize_pa()) return;
165
166         PaHostApiIndex count = Pa_GetHostApiCount();
167
168         if (count < 0) return;
169
170         for (int i = 0; i < count; ++i) {
171                 const PaHostApiInfo* info = Pa_GetHostApiInfo (i);
172                 if (info->name != NULL) { // possible?
173                         api_list.push_back (info->name);
174                 }
175         }
176 }
177
178 void
179 PortAudioIO::set_host_api (const std::string& host_api_name)
180 {
181         _host_api_index = get_host_api_index_from_name (host_api_name);
182
183         if (_host_api_index < 0) {
184                 fprintf(stderr, "Error setting host API\n");
185         }
186 }
187
188 PaHostApiIndex
189 PortAudioIO::get_host_api_index_from_name (const std::string& name)
190 {
191         if (!initialize_pa()) return -1;
192
193         PaHostApiIndex count = Pa_GetHostApiCount();
194
195         if (count < 0) return -1;
196
197         for (int i = 0; i < count; ++i) {
198                 const PaHostApiInfo* info = Pa_GetHostApiInfo (i);
199                 if (info->name != NULL) { // possible?
200                         if (name == info->name) return i;
201                 }
202         }
203         return -1;
204 }
205
206 PaDeviceIndex
207 PortAudioIO::get_default_input_device ()
208 {
209         const PaHostApiInfo* info = Pa_GetHostApiInfo (_host_api_index);
210         if (info == NULL) return -1;
211         return info->defaultInputDevice;
212 }
213
214 PaDeviceIndex
215 PortAudioIO::get_default_output_device ()
216 {
217         const PaHostApiInfo* info = Pa_GetHostApiInfo (_host_api_index);
218         if (info == NULL) return -1;
219         return info->defaultOutputDevice;
220 }
221
222 void
223 PortAudioIO::clear_device_lists ()
224 {
225         for (std::map<int, paDevice*>::const_iterator i = _input_devices.begin (); i != _input_devices.end(); ++i) {
226                 delete i->second;
227         }
228         _input_devices.clear();
229
230         for (std::map<int, paDevice*>::const_iterator i = _output_devices.begin (); i != _output_devices.end(); ++i) {
231                 delete i->second;
232         }
233         _output_devices.clear();
234 }
235
236 void
237 PortAudioIO::add_default_devices ()
238 {
239         const PaHostApiInfo* info = Pa_GetHostApiInfo (_host_api_index);
240         if (info == NULL) return;
241
242         const PaDeviceInfo* nfo_i = Pa_GetDeviceInfo(get_default_input_device());
243         const PaDeviceInfo* nfo_o = Pa_GetDeviceInfo(get_default_output_device());
244         if (nfo_i && nfo_o) {
245                 _input_devices.insert (std::pair<int, paDevice*> (-1,
246                                         new paDevice("Default",
247                                                 nfo_i->maxInputChannels,
248                                                 nfo_o->maxOutputChannels
249                                                 )));
250                 _output_devices.insert (std::pair<int, paDevice*> (-1,
251                                         new paDevice("Default",
252                                                 nfo_i->maxInputChannels,
253                                                 nfo_o->maxOutputChannels
254                                                 )));
255         }
256 }
257
258 void
259 PortAudioIO::add_devices ()
260 {
261         const PaHostApiInfo* info = Pa_GetHostApiInfo (_host_api_index);
262         if (info == NULL) return;
263
264         int n_devices = Pa_GetDeviceCount();
265 #ifndef NDEBUG
266         printf("PortAudio %d devices found:\n", n_devices);
267 #endif
268
269         for (int i = 0 ; i < n_devices; ++i) {
270                 const PaDeviceInfo* nfo = Pa_GetDeviceInfo(i);
271
272                 if (!nfo) continue;
273                 if (nfo->hostApi != _host_api_index) continue;
274 #ifndef NDEBUG
275                 printf(" (%d) '%s' '%s' in: %d (lat: %.1f .. %.1f) out: %d (lat: %.1f .. %.1f) sr:%.2f\n",
276                                 i, info->name, nfo->name,
277                                 nfo->maxInputChannels,
278                                 nfo->defaultLowInputLatency * 1e3,
279                                 nfo->defaultHighInputLatency * 1e3,
280                                 nfo->maxOutputChannels,
281                                 nfo->defaultLowOutputLatency * 1e3,
282                                 nfo->defaultHighOutputLatency * 1e3,
283                                 nfo->defaultSampleRate);
284 #endif
285                 if ( nfo->maxInputChannels == 0 && nfo->maxOutputChannels == 0) {
286                         continue;
287                 }
288
289                 if (nfo->maxInputChannels > 0) {
290                         _input_devices.insert (std::pair<int, paDevice*> (i, new paDevice(
291                                                         nfo->name,
292                                                         nfo->maxInputChannels,
293                                                         nfo->maxOutputChannels
294                                                         )));
295                 }
296                 if (nfo->maxOutputChannels > 0) {
297                         _output_devices.insert (std::pair<int, paDevice*> (i, new paDevice(
298                                                         nfo->name,
299                                                         nfo->maxInputChannels,
300                                                         nfo->maxOutputChannels
301                                                         )));
302                 }
303         }
304 }
305
306 void
307 PortAudioIO::discover()
308 {
309         if (!initialize_pa()) return;
310
311         clear_device_lists ();
312         add_default_devices ();
313         add_devices ();
314 }
315
316 void
317 PortAudioIO::pcm_stop ()
318 {
319         if (_stream) {
320                 Pa_CloseStream (_stream);
321         }
322         _stream = NULL;
323
324         _capture_channels = 0;
325         _playback_channels = 0;
326         _cur_sample_rate = 0;
327         _cur_input_latency = 0;
328         _cur_output_latency = 0;
329
330         free (_input_buffer); _input_buffer = NULL;
331         free (_output_buffer); _output_buffer = NULL;
332         _state = -1;
333 }
334
335 int
336 PortAudioIO::pcm_start()
337 {
338         PaError err = Pa_StartStream (_stream);
339
340         if (err != paNoError) {
341                 _state = -1;
342                 return -1;
343         }
344         return 0;
345 }
346
347 #ifdef __APPLE__
348 static uint32_t lower_power_of_two (uint32_t v) {
349         v--;
350         v |= v >> 1;
351         v |= v >> 2;
352         v |= v >> 4;
353         v |= v >> 8;
354         v |= v >> 16;
355         v++;
356         return v >> 1;
357 }
358 #endif
359
360 int
361 PortAudioIO::pcm_setup (
362                 int device_input, int device_output,
363                 double sample_rate, uint32_t samples_per_period)
364 {
365         _state = -2;
366
367         // TODO error reporting sans fprintf()
368
369         PaError err = paNoError;
370         const PaDeviceInfo *nfo_in;
371         const PaDeviceInfo *nfo_out;
372         const PaStreamInfo *nfo_s;
373                 
374         if (!initialize_pa()) {
375                 fprintf(stderr, "PortAudio Initialization Failed\n");
376                 goto error;
377         }
378
379         if (device_input == -1) {
380                 device_input = get_default_input_device ();
381         }
382         if (device_output == -1) {
383                 device_output = get_default_output_device ();
384         }
385
386         _capture_channels = 0;
387         _playback_channels = 0;
388         _cur_sample_rate = 0;
389         _cur_input_latency = 0;
390         _cur_output_latency = 0;
391
392 #ifndef NDEBUG
393         printf("PortAudio Device IDs: i:%d o:%d\n", device_input, device_output);
394 #endif
395
396         nfo_in = Pa_GetDeviceInfo(device_input);
397         nfo_out = Pa_GetDeviceInfo(device_output);
398
399         if (!nfo_in && ! nfo_out) {
400                 fprintf(stderr, "PortAudio Cannot Query Device Info\n");
401                 goto error;
402         }
403
404         if (nfo_in) {
405                 _capture_channels = nfo_in->maxInputChannels;
406         }
407         if (nfo_out) {
408                 _playback_channels = nfo_out->maxOutputChannels;
409         }
410
411         if(_capture_channels == 0 && _playback_channels == 0) {
412                 fprintf(stderr, "PortAudio no Input and no output channels.\n");
413                 goto error;
414         }
415
416
417 #ifdef __APPLE__
418         // pa_mac_core_blocking.c pa_stable_v19_20140130
419         // BUG: ringbuffer alloc requires power-of-two chn count.
420         if ((_capture_channels & (_capture_channels - 1)) != 0) {
421                 printf("Adjusted capture channes to power of two (portaudio rb bug)\n");
422                 _capture_channels = lower_power_of_two (_capture_channels);
423         }
424
425         if ((_playback_channels & (_playback_channels - 1)) != 0) {
426                 printf("Adjusted capture channes to power of two (portaudio rb bug)\n");
427                 _playback_channels = lower_power_of_two (_playback_channels);
428         }
429 #endif
430         
431 #ifndef NDEBUG
432         printf("PortAudio Channels: in:%d out:%d\n",
433                         _capture_channels, _playback_channels);
434 #endif
435
436         PaStreamParameters inputParam;
437         PaStreamParameters outputParam;
438
439         if (nfo_in) {
440                 inputParam.device = device_input;
441                 inputParam.channelCount = _capture_channels;
442 #ifdef INTERLEAVED_INPUT
443                 inputParam.sampleFormat = paFloat32;
444 #else
445                 inputParam.sampleFormat = paFloat32 | paNonInterleaved;
446 #endif
447                 inputParam.suggestedLatency = nfo_in->defaultLowInputLatency;
448                 inputParam.hostApiSpecificStreamInfo = NULL;
449         }
450
451         if (nfo_out) {
452                 outputParam.device = device_output;
453                 outputParam.channelCount = _playback_channels;
454 #ifdef INTERLEAVED_OUTPUT
455                 outputParam.sampleFormat = paFloat32;
456 #else
457                 outputParam.sampleFormat = paFloat32 | paNonInterleaved;
458 #endif
459                 outputParam.suggestedLatency = nfo_out->defaultLowOutputLatency;
460                 outputParam.hostApiSpecificStreamInfo = NULL;
461         }
462
463         // XXX re-consider using callback API, testing needed.
464         err = Pa_OpenStream (
465                         &_stream,
466                         _capture_channels > 0 ? &inputParam: NULL,
467                         _playback_channels > 0 ? &outputParam: NULL,
468                         sample_rate,
469                         samples_per_period,
470                         paClipOff | paDitherOff,
471                         NULL, NULL);
472
473         if (err != paNoError) {
474                 fprintf(stderr, "PortAudio failed to start stream.\n");
475                 goto error;
476         }
477
478         nfo_s = Pa_GetStreamInfo (_stream);
479         if (!nfo_s) {
480                 fprintf(stderr, "PortAudio failed to query stream information.\n");
481                 pcm_stop();
482                 goto error;
483         }
484
485         _cur_sample_rate = nfo_s->sampleRate;
486         _cur_input_latency = nfo_s->inputLatency * _cur_sample_rate;
487         _cur_output_latency = nfo_s->outputLatency * _cur_sample_rate;
488
489 #ifndef NDEBUG
490         printf("PA Sample Rate  %.1f SPS\n", _cur_sample_rate);
491         printf("PA Input Latency  %.1fms  %d spl\n", 1e3 * nfo_s->inputLatency, _cur_input_latency);
492         printf("PA Output Latency %.1fms  %d spl\n", 1e3 * nfo_s->outputLatency, _cur_output_latency);
493 #endif
494
495         _state = 0;
496
497         if (_capture_channels > 0) {
498                 _input_buffer = (float*) malloc (samples_per_period * _capture_channels * sizeof(float));
499                 if (!_input_buffer) {
500                         fprintf(stderr, "PortAudio failed to allocate input buffer.\n");
501                         pcm_stop();
502                         goto error;
503                 }
504         }
505
506         if (_playback_channels > 0) {
507                 _output_buffer = (float*) calloc (samples_per_period * _playback_channels, sizeof(float));
508                 if (!_output_buffer) {
509                         fprintf(stderr, "PortAudio failed to allocate output buffer.\n");
510                         pcm_stop();
511                         goto error;
512                 }
513         }
514
515         return 0;
516
517 error:
518         _capture_channels = 0;
519         _playback_channels = 0;
520         free (_input_buffer); _input_buffer = NULL;
521         free (_output_buffer); _output_buffer = NULL;
522         return -1;
523 }
524
525 int
526 PortAudioIO::next_cycle (uint32_t n_samples)
527 {
528         bool xrun = false;
529         PaError err;
530         err = Pa_IsStreamActive (_stream);
531         if (err != 1) {
532                 //   0: inactive / aborted
533                 // < 0: error
534                 return -1;
535         }
536
537         // TODO, check drift..  process part with larger capacity first.
538         // Pa_GetStreamReadAvailable(_stream) < Pa_GetStreamWriteAvailable(_stream)
539
540         if (_playback_channels > 0) {
541                 err = Pa_WriteStream (_stream, _output_buffer, n_samples);
542                 if (err) xrun = true;
543         }
544
545         if (_capture_channels > 0) {
546                 err = Pa_ReadStream (_stream, _input_buffer, n_samples);
547                 if (err) {
548                         memset (_input_buffer, 0, sizeof(float) * n_samples * _capture_channels);
549                         xrun = true;
550                 }
551         }
552
553
554         return xrun ? 1 : 0;
555 }
556
557
558 #ifdef INTERLEAVED_INPUT
559
560 int
561 PortAudioIO::get_capture_channel (uint32_t chn, float *input, uint32_t n_samples)
562 {
563         assert(chn < _capture_channels);
564         const uint32_t stride = _capture_channels;
565         float *ptr = _input_buffer + chn;
566         while (n_samples-- > 0) {
567                 *input++ = *ptr;
568                 ptr += stride;
569         }
570         return 0;
571 }
572
573 #else
574
575 int
576 PortAudioIO::get_capture_channel (uint32_t chn, float *input, uint32_t n_samples)
577 {
578         assert(chn < _capture_channels);
579         memcpy((void*)input, &(_input_buffer[chn * n_samples]), n_samples * sizeof(float));
580         return 0;
581 }
582
583 #endif
584
585
586 #ifdef INTERLEAVED_OUTPUT
587
588 int
589 PortAudioIO::set_playback_channel (uint32_t chn, const float *output, uint32_t n_samples)
590 {
591         assert(chn < _playback_channels);
592         const uint32_t stride = _playback_channels;
593         float *ptr = _output_buffer + chn;
594         while (n_samples-- > 0) {
595                 *ptr = *output++;
596                 ptr += stride;
597         }
598         return 0;
599 }
600
601 #else
602
603 int
604 PortAudioIO::set_playback_channel (uint32_t chn, const float *output, uint32_t n_samples)
605 {
606         assert(chn < _playback_channels);
607         memcpy((void*)&(_output_buffer[chn * n_samples]), (void*)output, n_samples * sizeof(float));
608         return 0;
609 }
610
611 #endif