1 // Copyright 2004 "Gilles Degottex"
3 // This file is part of "Music"
5 // "Music" is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU Lesser General Public License as published by
7 // the Free Software Foundation; either version 2.1 of the License, or
8 // (at your option) any later version.
10 // "Music" is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU Lesser General Public License for more details.
15 // You should have received a copy of the GNU Lesser General Public License
16 // along with this program; if not, write to the Free Software
17 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 #include "CaptureThread.h"
31 // ------------------------------ PortAudio implementation ----------------------------
32 #ifdef CAPTURE_PORTAUDIO
33 CaptureThreadImplPortAudio::CaptureThreadImplPortAudio(CaptureThread* capture_thread)
34 : CaptureThreadImpl(capture_thread, "PortAudio", QString("Portable cross-platform Audio API (lib:")+Pa_GetVersionText()+"["+QString::number(Pa_GetVersion())+"])")
41 bool CaptureThreadImplPortAudio::is_available()
47 m_err = Pa_Initialize();
48 if(m_err != paNoError) throw QString("PortAudio: is_available:Pa_Initialize ")+Pa_GetErrorText(m_err);
52 numDevices = Pa_GetDeviceCount();
54 throw QString("PortAudio: is_available:Pa_GetDeviceCount ")+Pa_GetErrorText(numDevices);
55 else if(numDevices == 0)
56 throw QString("PortAudio: is_available:Pa_GetDeviceCount no devices available")+Pa_GetErrorText(numDevices);
58 /* const PaDeviceInfo *deviceInfo;
60 for(int i=0; i<numDevices; i++ )
62 deviceInfo = Pa_GetDeviceInfo( i );
63 cerr << deviceInfo->name << endl;
64 cerr << deviceInfo->defaultSampleRate << endl;
82 void CaptureThreadImplPortAudio::setSamplingRate(int value)
84 // cerr << "CaptureThreadImplPortAudio::setSamplingRate " << value << endl;
86 assert(value>0 || value==CaptureThread::SAMPLING_RATE_MAX);
88 if(m_sampling_rate!=value || value==CaptureThread::SAMPLING_RATE_MAX)
90 bool was_running = m_capture_thread->isCapturing();
91 if(was_running) m_capture_thread->stopCapture();
93 m_sampling_rate = value;
95 if(m_sampling_rate==CaptureThread::SAMPLING_RATE_MAX)
103 cerr << "CaptureThread: ERROR: " << error.toStdString() << endl;
104 m_capture_thread->emitError(error);
108 // it was just for testing
113 cerr << "CaptureThread: ERROR: " << error.toStdString() << endl;
114 m_capture_thread->emitError(error);
118 m_capture_thread->emitSamplingRateChanged();
120 if(was_running) m_capture_thread->startCapture();
123 // cerr << "~CaptureThreadImplPortAudio::setSamplingRate" << endl;
126 int CaptureThreadImplPortAudio::PortAudioCallback( const void *inputBuffer, void *outputBuffer,
127 unsigned long framesPerBuffer,
128 const PaStreamCallbackTimeInfo* timeInfo,
129 PaStreamCallbackFlags statusFlags,
131 {return ((CaptureThreadImplPortAudio*)userData)->portAudioCallback(inputBuffer, framesPerBuffer, timeInfo, statusFlags);}
132 int CaptureThreadImplPortAudio::portAudioCallback(const void *inputBuffer,
133 unsigned long framesPerBuffer,
134 const PaStreamCallbackTimeInfo* timeInfo,
135 PaStreamCallbackFlags statusFlags)
137 if(m_capture_thread->m_pause)
140 m_capture_thread->m_lock.lock();
142 float *in = (float*)inputBuffer;
144 for(unsigned long i=0; i<framesPerBuffer; i++)
145 m_capture_thread->m_values.push_front(*in++);
146 // addValue(*in++, i, m_channel_count); // TODO
148 m_capture_thread->m_packet_size = framesPerBuffer;
149 if(m_capture_thread->m_ext_lock)
151 m_capture_thread->m_packet_size_sll = 0;
152 m_capture_thread->m_ext_lock = false;
154 m_capture_thread->m_packet_size_sll += framesPerBuffer;
156 m_capture_thread->m_lock.unlock();
161 void CaptureThreadImplPortAudio::set_params(bool test)
163 m_err = Pa_Initialize();
164 if(m_err != paNoError) throw QString("PortAudio: set_params:Pa_Initialize ")+Pa_GetErrorText(m_err);
166 PaStreamParameters params;
167 params.device = paNoDevice;
168 params.channelCount = 1;
169 params.sampleFormat = paFloat32;
170 params.suggestedLatency = 0;
171 params.hostApiSpecificStreamInfo = NULL;
173 if(m_source!="default") // TODO hum hum
175 int numDevices = Pa_GetDeviceCount();
176 const PaDeviceInfo* deviceInfo;
177 for(int i=0; params.device==paNoDevice && i<numDevices; i++)
179 deviceInfo = Pa_GetDeviceInfo(i);
180 if(QString(deviceInfo->name)==m_source)
184 if(params.device==paNoDevice)
185 cerr << "CaptureThread: INFO: PortAudio: cannot determine selected source \"" << m_source.toStdString() << "\"" << endl;
190 if(params.device==paNoDevice)
191 cerr << "CaptureThread: INFO: PortAudio: using default device" << endl;
193 cerr << "CaptureThread: INFO: PortAudio: using \"" << m_source.toStdString() << "\"" << endl;
195 setFormatDescrsAndFns(4, true, true, 1); // TODO do something if nbchannel=1 not supported
198 if(m_sampling_rate==CaptureThread::SAMPLING_RATE_MAX || m_sampling_rate==CaptureThread::SAMPLING_RATE_UNKNOWN)
200 int old_sampling_rate = m_sampling_rate;
202 cerr << "CaptureThread: INFO: PortAudio: sampling rate set to max or undefined, try to determinate it." << endl;
204 list<int> sampling_rates;
205 sampling_rates.push_front(8000); sampling_rates.push_front(11025); sampling_rates.push_front(16000);
206 sampling_rates.push_front(22050); sampling_rates.push_front(24000); sampling_rates.push_front(32000);
207 sampling_rates.push_front(44100);
210 while(m_err!=paNoError)
212 if(sampling_rates.empty())
213 throw QString("PortAudio: cannot set any sample rate (")+Pa_GetErrorText(m_err)+")";
215 m_err = Pa_Initialize();
216 if(m_err != paNoError) throw QString("PortAudio: set_params:Pa_Initialize ")+Pa_GetErrorText(m_err);
218 m_sampling_rate = sampling_rates.front();
219 cerr << "CaptureThread: INFO: PortAudio: try sampling rate " << m_sampling_rate << " ..." << flush;
221 // cerr << "nbc1 " << params.channelCount << endl;
223 if(params.device==paNoDevice)
224 m_err = Pa_OpenDefaultStream(&m_stream, 1, 0, paFloat32, m_sampling_rate, 0, PortAudioCallback, this);
226 m_err = Pa_OpenStream(&m_stream, ¶ms, NULL, m_sampling_rate, 0, paNoFlag, PortAudioCallback, this);
228 if(m_err != paNoError) cerr << " failed" << endl;
229 else cerr << " success" << endl;
231 sampling_rates.pop_front();
234 if(old_sampling_rate!=m_sampling_rate)
235 m_capture_thread->emitSamplingRateChanged();
239 // cerr << "nbc2 " << params.channelCount << endl;
240 // cerr << "dev2 " << params.device << "/" << paNoDevice << endl;
242 if(params.device==paNoDevice)
244 m_err = Pa_OpenDefaultStream(&m_stream, 1, 0, paFloat32, m_sampling_rate, 0, PortAudioCallback, this);
245 if(m_err != paNoError)
246 throw QString("PortAudio: set_params:Pa_OpenDefaultStream ")+Pa_GetErrorText(m_err);
250 m_err = Pa_OpenStream(&m_stream, ¶ms, NULL, m_sampling_rate, 0, paNoFlag, PortAudioCallback, this);
251 if(m_err != paNoError)
252 throw QString("PortAudio: set_params:Pa_OpenStream ")+Pa_GetErrorText(m_err);
257 void CaptureThreadImplPortAudio::capture_init()
261 m_err = Pa_StartStream(m_stream);
262 if(m_err != paNoError)
263 throw QString("PortAudio: capture_init:Pa_StartStream ")+Pa_GetErrorText(m_err);
265 m_capture_thread->m_capturing = true;
266 m_capture_thread->emitCaptureStarted();
267 m_capture_thread->emitCaptureToggled(true);
269 void CaptureThreadImplPortAudio::capture_finished()
273 if(!Pa_IsStreamStopped(m_stream))
275 m_err = Pa_StopStream(m_stream);
276 if(m_err != paNoError) throw QString("PortAudio: capture_finished: ")+Pa_GetErrorText(m_err);
281 m_err = Pa_CloseStream(m_stream);
282 if(m_err != paNoError) throw QString("PortAudio: capture_finished: ")+Pa_GetErrorText(m_err);
287 m_capture_thread->m_capturing = false;
288 m_capture_thread->emitCaptureStoped();
289 m_capture_thread->emitCaptureToggled(false);
292 m_err = Pa_Terminate();
293 // if(m_err != paNoError) throw QString("PortAudio: capture_finished: ")+Pa_GetErrorText(m_err);
295 void CaptureThreadImplPortAudio::startCapture()
304 cerr << "CaptureThread: ERROR: " << error.toStdString() << endl;
305 m_capture_thread->emitError(error);
308 void CaptureThreadImplPortAudio::stopCapture()
316 cerr << "CaptureThread: ERROR: " << error.toStdString() << endl;
317 m_capture_thread->emitError(error);
320 CaptureThreadImplPortAudio::~CaptureThreadImplPortAudio()