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
;
133 in_parameters
.channelCount
= inchans
;
134 in_parameters
.device
= input_device_index
;
135 in_parameters
.sampleFormat
= paFloat32
| paNonInterleaved
;
136 in_parameters
.suggestedLatency
= Pa_GetDeviceInfo(in_parameters
.device
)->defaultLowInputLatency
;
137 in_parameters
.hostApiSpecificStreamInfo
= NULL
;
139 out_parameters
.channelCount
= outchans
;
140 out_parameters
.device
= output_device_index
;
141 out_parameters
.sampleFormat
= paFloat32
| paNonInterleaved
;
142 out_parameters
.suggestedLatency
= Pa_GetDeviceInfo(out_parameters
.device
)->defaultLowOutputLatency
;
143 out_parameters
.hostApiSpecificStreamInfo
= NULL
;
145 PaError supported
= Pa_IsFormatSupported(&in_parameters
, &out_parameters
, samplerate
);
146 report_error(supported
);
150 callback_initialized
= false;
151 blocksize_
= blocksize
;
152 PaError opened
= Pa_OpenStream(&stream
, &in_parameters
, &out_parameters
,
153 samplerate
, pa_blocksize
, paNoFlag
,
154 &portaudio_backend::pa_process
, this);
156 report_error(opened
);
158 if (opened
!= paNoError
)
161 input_channels
= inchans
;
162 super::input_samples
.resize(inchans
);
163 output_channels
= outchans
;
164 super::output_samples
.resize(outchans
);
165 samplerate_
= samplerate
;
169 void close_stream(void)
176 int err
= Pa_CloseStream(stream
);
181 void activate_audio()
184 int err
= Pa_StartStream(stream
);
188 bool audio_is_active(void)
190 int is_active
= Pa_IsStreamActive(stream
);
196 report_error(is_active
);
200 void deactivate_audio()
202 if (audio_is_active()) {
203 PaError err
= Pa_StopStream(stream
);
208 bool audiostream_ready(void)
214 int perform(const void *inputBuffer
, void *outputBuffer
, unsigned long frames
,
215 const PaStreamCallbackTimeInfo
*timeInfo
, PaStreamCallbackFlags statusFlags
)
217 if (unlikely(!callback_initialized
)) {
218 engine_functor::init_thread();
219 engine_functor::sync_clock();
220 callback_initialized
= true;
223 if (statusFlags
& (paInputOverflow
| paInputUnderflow
| paOutputOverflow
| paOutputUnderflow
))
224 engine_functor::sync_clock();
226 const float * inputs
[input_channels
];
227 float * const *in
= static_cast<float * const *>(inputBuffer
);
228 for (uint16_t i
= 0; i
!= input_channels
; ++i
)
231 float * outputs
[output_channels
];
232 float **out
= static_cast<float **>(outputBuffer
);
233 for (uint16_t i
= 0; i
!= output_channels
; ++i
)
236 unsigned long processed
= 0;
237 while (processed
!= frames
) {
238 super::fetch_inputs(inputs
, blocksize_
, input_channels
);
239 engine_functor::run_tick();
240 super::deliver_outputs(outputs
, blocksize_
, output_channels
);
241 processed
+= blocksize_
;
247 static int pa_process(const void *input
, void *output
, unsigned long frame_count
,
248 const PaStreamCallbackTimeInfo
*time_info
, PaStreamCallbackFlags status_flags
, void * user_data
)
250 portaudio_backend
* self
= static_cast<portaudio_backend
*>(user_data
);
251 return self
->perform(input
, output
, frame_count
, time_info
, status_flags
);
256 bool callback_initialized
;
259 } /* namespace nova */
261 #endif /* _PORTAUDIO_HPP */