clean up indentation and spacing
[supercollider.git] / server / supernova / audio_backend / portaudio_backend.hpp
blobc515923f1b2042387dbfde4668bc423135383a30
1 // portaudio backend
2 // Copyright (C) 2006, 2007, 2008, 2012 Tim Blechmann
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.
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
22 #include <cstdio>
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"
33 namespace nova {
35 /** \brief portaudio backend for supernova
37 * */
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;
48 public:
49 portaudio_backend(void):
50 stream(NULL), blocksize_(0)
52 int err = Pa_Initialize();
53 report_error(err, true);
56 list_devices();
58 #ifdef PA_HAVE_JACK
59 PaJack_SetClientName("SuperNova");
60 #endif
63 ~portaudio_backend(void)
65 if (audio_is_active())
66 deactivate_audio();
68 close_stream();
70 int err = Pa_Terminate();
71 report_error(err);
74 uint32_t get_audio_blocksize(void) const
76 return blocksize_;
79 private:
80 static void report_error(int err, bool throw_exception = false)
82 if (err < 0) {
83 engine_functor::log_printf_("PortAudio error: %s\n", Pa_GetErrorText( err ));
84 if (throw_exception)
85 throw std::runtime_error("PortAudio error");
89 public:
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);
99 if (device_info) {
100 printf("%d: %s (%d inputs, %d outputs)\n", i, device_info->name,
101 device_info->maxInputChannels, device_info->maxOutputChannels);
104 printf("\n");
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) {
116 r_device_index = i;
117 return true;
120 return false;
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))
129 return false;
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);
147 if (supported != 0)
148 return false;
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)
159 return false;
161 input_channels = inchans;
162 super::input_samples.resize(inchans);
163 output_channels = outchans;
164 super::output_samples.resize(outchans);
165 samplerate_ = samplerate;
166 return true;
169 void close_stream(void)
171 if (stream == NULL)
172 return;
174 deactivate_audio();
176 int err = Pa_CloseStream(stream);
177 report_error(err);
178 stream = NULL;
181 void activate_audio()
183 assert(stream);
184 int err = Pa_StartStream(stream);
185 report_error(err);
188 bool audio_is_active(void)
190 int is_active = Pa_IsStreamActive(stream);
191 if (is_active == 1)
192 return true;
193 if (is_active == 0)
194 return false;
196 report_error(is_active);
197 return false;
200 void deactivate_audio()
202 if (audio_is_active()) {
203 PaError err = Pa_StopStream(stream);
204 report_error(err);
208 bool audiostream_ready(void)
210 return stream;
213 private:
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)
229 inputs[i] = in[i];
231 float * outputs[output_channels];
232 float **out = static_cast<float **>(outputBuffer);
233 for (uint16_t i = 0; i != output_channels; ++i)
234 outputs[i] = out[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_;
244 return paContinue;
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);
254 PaStream *stream;
255 uint32_t blocksize_;
256 bool callback_initialized;
259 } /* namespace nova */
261 #endif /* _PORTAUDIO_HPP */