2 // Copyright (C) 2006, 2007, 2008, 2012 Tim Blechmann
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.
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.
14 // You should have received a copy of the GNU General Public License
15 // along with this program; see the file COPYING. If not, write to
16 // the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 // Boston, MA 02111-1307, USA.
19 #ifndef _PORTAUDIO_HPP
20 #define _PORTAUDIO_HPP
24 #include "portaudio.h"
25 #ifdef HAVE_PORTAUDIO_CONFIG_H
26 #include "portaudio/portaudio_config.h"
27 #endif /* HAVE_PORTAUDIO_CONFIG_H */
29 #include "audio_backend_common.hpp"
30 #include "utilities/branch_hints.hpp"
35 /** \brief portaudio backend for supernova
38 template <typename engine_functor
,
39 typename sample_type
= float,
40 bool blocking
= false>
41 class portaudio_backend
:
42 public detail::audio_delivery_helper
<sample_type
, float, blocking
, false>,
43 public detail::audio_settings_basic
,
44 protected engine_functor
46 typedef detail::audio_delivery_helper
<sample_type
, float, blocking
, false> super
;
49 portaudio_backend(void):
50 stream(NULL
), blocksize_(0)
52 int err
= Pa_Initialize();
53 report_error(err
, true);
59 PaJack_SetClientName("SuperNova");
63 ~portaudio_backend(void)
65 if (audio_is_active())
70 int err
= Pa_Terminate();
74 uint32_t get_audio_blocksize(void) const
80 static void report_error(int err
, bool throw_exception
= false)
83 engine_functor::log_printf_("PortAudio error: %s\n", Pa_GetErrorText( err
));
85 throw std::runtime_error("PortAudio error");
90 static void list_devices(void)
92 int device_number
= Pa_GetDeviceCount();
93 if (device_number
< 0)
94 report_error(device_number
);
96 printf("Available Audio Devices:\n");
97 for (int i
= 0; i
!= device_number
; ++i
) {
98 const PaDeviceInfo
* device_info
= Pa_GetDeviceInfo(i
);
100 printf("%d: %s (%d inputs, %d outputs)\n", i
, device_info
->name
,
101 device_info
->maxInputChannels
, device_info
->maxOutputChannels
);
107 static bool match_device (std::string
const & device_name
, int & r_device_index
)
109 int device_number
= Pa_GetDeviceCount();
110 if (device_number
< 0)
111 report_error(device_number
);
113 for (int i
= 0; i
!= device_number
; ++i
) {
114 const PaDeviceInfo
* device_info
= Pa_GetDeviceInfo(i
);
115 if (std::string(device_info
->name
) == device_name
) {
123 bool open_stream(std::string
const & input_device
, unsigned int inchans
,
124 std::string
const & output_device
, unsigned int outchans
,
125 unsigned int samplerate
, unsigned int pa_blocksize
, unsigned int blocksize
)
127 int input_device_index
, output_device_index
;
128 if (!match_device(input_device
, input_device_index
) || !match_device(output_device
, output_device_index
))
131 PaStreamParameters in_parameters
, out_parameters
;
134 in_parameters
.channelCount
= inchans
;
135 in_parameters
.device
= input_device_index
;
136 in_parameters
.sampleFormat
= paFloat32
| paNonInterleaved
;
137 in_parameters
.suggestedLatency
= Pa_GetDeviceInfo(in_parameters
.device
)->defaultLowInputLatency
;
138 in_parameters
.hostApiSpecificStreamInfo
= NULL
;
142 out_parameters
.channelCount
= outchans
;
143 out_parameters
.device
= output_device_index
;
144 out_parameters
.sampleFormat
= paFloat32
| paNonInterleaved
;
145 out_parameters
.suggestedLatency
= Pa_GetDeviceInfo(out_parameters
.device
)->defaultLowOutputLatency
;
146 out_parameters
.hostApiSpecificStreamInfo
= NULL
;
149 PaStreamParameters
* in_stream_parameters
= inchans
? &in_parameters
: NULL
;
150 PaStreamParameters
* out_stream_parameters
= outchans
? &out_parameters
: NULL
;
152 PaError supported
= Pa_IsFormatSupported(in_stream_parameters
, out_stream_parameters
, samplerate
);
153 report_error(supported
);
157 callback_initialized
= false;
158 blocksize_
= blocksize
;
160 PaError opened
= Pa_OpenStream(&stream
, in_stream_parameters
, out_stream_parameters
,
161 samplerate
, pa_blocksize
, paNoFlag
,
162 &portaudio_backend::pa_process
, this);
164 report_error(opened
);
166 if (opened
!= paNoError
)
169 input_channels
= inchans
;
170 super::input_samples
.resize(inchans
);
171 output_channels
= outchans
;
172 super::output_samples
.resize(outchans
);
173 samplerate_
= samplerate
;
177 void close_stream(void)
184 int err
= Pa_CloseStream(stream
);
189 void activate_audio()
192 int err
= Pa_StartStream(stream
);
196 bool audio_is_active(void)
198 int is_active
= Pa_IsStreamActive(stream
);
204 report_error(is_active
);
208 void deactivate_audio()
210 if (audio_is_active()) {
211 PaError err
= Pa_StopStream(stream
);
216 bool audiostream_ready(void)
222 int perform(const void *inputBuffer
, void *outputBuffer
, unsigned long frames
,
223 const PaStreamCallbackTimeInfo
*timeInfo
, PaStreamCallbackFlags statusFlags
)
225 if (unlikely(!callback_initialized
)) {
226 engine_functor::init_thread();
227 engine_functor::sync_clock();
228 callback_initialized
= true;
231 if (statusFlags
& (paInputOverflow
| paInputUnderflow
| paOutputOverflow
| paOutputUnderflow
))
232 engine_functor::sync_clock();
234 const float * inputs
[input_channels
];
235 float * const *in
= static_cast<float * const *>(inputBuffer
);
236 for (uint16_t i
= 0; i
!= input_channels
; ++i
)
239 float * outputs
[output_channels
];
240 float **out
= static_cast<float **>(outputBuffer
);
241 for (uint16_t i
= 0; i
!= output_channels
; ++i
)
244 unsigned long processed
= 0;
245 while (processed
!= frames
) {
246 super::fetch_inputs(inputs
, blocksize_
, input_channels
);
247 engine_functor::run_tick();
248 super::deliver_outputs(outputs
, blocksize_
, output_channels
);
249 processed
+= blocksize_
;
255 static int pa_process(const void *input
, void *output
, unsigned long frame_count
,
256 const PaStreamCallbackTimeInfo
*time_info
, PaStreamCallbackFlags status_flags
, void * user_data
)
258 portaudio_backend
* self
= static_cast<portaudio_backend
*>(user_data
);
259 return self
->perform(input
, output
, frame_count
, time_info
, status_flags
);
264 bool callback_initialized
;
267 } /* namespace nova */
269 #endif /* _PORTAUDIO_HPP */