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