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 #include <qdatetime.h>
33 double DecodeUnsigned8Bits(void* buffer, int i) {return 2*(((unsigned char*)buffer)[i])/256.0 - 1;}
34 double DecodeSigned8Bits(void* buffer, int i) {return (((signed char*)buffer)[i])/128.0;}
35 double DecodeUnsigned16Bits(void* buffer, int i){return 2*((unsigned short*)buffer)[i]/65536.0 - 1;}
36 double DecodeSigned16Bits(void* buffer, int i) {return ((signed short*)buffer)[i]/32768.0;}
37 void AddValue2ChannelFirst(CaptureThreadImpl* impl, double value, int i)
40 impl->m_capture_thread->m_values.push_front(value);
42 void AddValue2ChannelMix(CaptureThreadImpl* impl, double value, int i)
45 impl->m_tmp_value = value;
46 // impl->m_capture_thread->m_values.push_front(value);
48 impl->m_capture_thread->m_values.push_front((impl->m_tmp_value+value)/2.0);
49 // impl->m_capture_thread->m_values[0] = (impl->m_capture_thread->m_values[0]+value)/2.0;
51 void AddValue1Channel(CaptureThreadImpl* impl, double value, int i)
53 impl->m_capture_thread->m_values.push_front(value);
56 CaptureThread::CaptureThread(const QString& name)
58 m_current_impl = NULL;
63 m_packet_size_sll = 0;
66 m_mix_multiple_channel = false;
71 m_impls.push_back(new CaptureThreadImplJACK(this));
74 m_impls.push_back(new CaptureThreadImplALSA(this));
77 m_impls.push_back(new CaptureThreadImplOSS(this));
79 #ifdef CAPTURE_PORTAUDIO
80 m_impls.push_back(new CaptureThreadImplPortAudio(this));
86 void CaptureThread::autoDetectTransport()
88 bool was_capturing = isCapturing();
93 if(m_current_impl!=NULL)
94 old_name = m_current_impl->m_name;
96 cerr << "CaptureThread: INFO: Auto detecting a working transport ... " << flush;
98 CaptureThreadImpl* impl = NULL;
99 for(vector<CaptureThreadImpl*>::iterator it=m_impls.begin(); impl==NULL && it!=m_impls.end(); it++)
100 if((*it)->is_available())
105 m_current_impl = impl;
107 cerr << "using " << m_current_impl->m_name.toStdString() << endl;
109 if(m_current_impl->m_name!=old_name)
110 emit(transportChanged(m_current_impl->m_name));
117 cerr << "no working transport !" << endl;
120 emit(transportChanged(""));
123 void CaptureThread::selectTransport(const QString& name)
125 cerr << "CaptureThread: INFO: using " << name.toStdString() << " transport" << endl;
126 if(getCurrentTransport() && name==getCurrentTransport()->getName()) return;
128 bool was_capturing = isCapturing();
133 if(m_current_impl!=NULL)
134 old_name = m_current_impl->m_name;
136 CaptureThreadImpl* impl = NULL;
137 for(vector<CaptureThreadImpl*>::iterator it=m_impls.begin(); impl==NULL && it!=m_impls.end(); it++)
138 if((*it)->m_name==name)
143 cerr << "CaptureThread: ERROR: unknown transport '" << name.toStdString() << "'" << endl;
144 throw QString("CaptureThread: ERROR: unknown transport '")+name+"'";
147 m_current_impl = impl;
149 if(m_current_impl->m_name!=old_name)
150 emit(transportChanged(m_current_impl->m_name));
155 void CaptureThread::selectTransport(int index)
157 assert(index>=0 && index<m_impls.size());
159 if(m_impls[index]==getCurrentTransport()) return;
160 cerr << "CaptureThread: INFO: change transport to " << m_impls[index]->getName().toStdString() << " transport" << endl;
162 bool was_capturing = isCapturing();
166 m_current_impl = m_impls[index];
168 emit(transportChanged(m_current_impl->m_name));
173 const vector<CaptureThreadImpl*>& CaptureThread::getTransports() const
177 void CaptureThread::listTransports()
179 cerr << "CaptureThread: INFO: Built in transports" << endl;
180 for(vector<CaptureThreadImpl*>::iterator it=m_impls.begin(); it!=m_impls.end(); it++)
181 cerr << "CaptureThread: INFO: " << (*it)->getStatus().toStdString() << " " << (*it)->m_name.toStdString() << " " << (*it)->m_descr.toStdString() << endl;
183 const CaptureThreadImpl* CaptureThread::getCurrentTransport() const
185 return m_current_impl;
187 int CaptureThread::getCurrentTransportIndex() const
189 for(int i=0; i<m_impls.size(); i++)
190 if(m_impls[i]==getCurrentTransport())
195 QString CaptureThread::getCurrentTransportDescr() const
197 if(m_current_impl==NULL)
200 return m_current_impl->m_descr;
202 const CaptureThreadImpl* CaptureThread::getTransport(const QString& name) const
204 for(vector<CaptureThreadImpl*>::const_iterator it=m_impls.begin(); it!=m_impls.end(); it++)
205 if((*it)->m_name==name)
210 QString CaptureThread::getFormatDescr() const
212 if(m_current_impl==NULL)
218 void CaptureThread::emitError(const QString& error)
220 emit(errorRaised(error));
222 void CaptureThread::emitSamplingRateChanged()
224 if(m_current_impl->m_sampling_rate>0)
225 emit(samplingRateChanged(m_current_impl->m_sampling_rate));
227 void CaptureThread::emitCaptureStarted()
229 emit(captureStarted());
231 void CaptureThread::emitCaptureStoped()
233 emit(captureStoped());
235 void CaptureThread::emitCaptureToggled(bool value)
237 emit(captureToggled(value));
240 void CaptureThread::startCapture()
242 if(m_current_impl==NULL) return;
244 m_current_impl->startCapture();
246 void CaptureThread::stopCapture()
248 // cerr << "CaptureThread::stopCapture" << endl;
250 if(m_current_impl==NULL) return;
252 m_current_impl->stopCapture();
254 // cerr << "/CaptureThread::stopCapture" << endl;
257 void CaptureThread::toggleCapture(bool run)
259 if(run && !m_capturing) startCapture();
260 if(!run && m_capturing) stopCapture();
263 void CaptureThread::reset()
269 void CaptureThread::togglePause(bool pause)
274 int CaptureThread::getSamplingRate() const
276 if(m_current_impl==NULL) return SAMPLING_RATE_UNKNOWN;
278 return m_current_impl->m_sampling_rate;
280 void CaptureThread::setSamplingRate(int rate)
282 if(m_current_impl!=NULL)
283 m_current_impl->setSamplingRate(rate);
285 void CaptureThread::setSource(const QString& name)
287 if(m_current_impl==NULL)
289 cerr << "CaptureThread: setSource: ERROR: select a transport first" << endl;
293 if(name!=m_current_impl->m_source)
295 m_current_impl->m_source = name;
302 emit(sourceChanged(m_current_impl->m_source));
306 void CaptureThread::setMixMultipleChannels(bool mix)
308 m_mix_multiple_channel = mix;
311 CaptureThread::~CaptureThread()
315 for(vector<CaptureThreadImpl*>::iterator it=m_impls.begin(); it!=m_impls.end(); it++)
319 // -------------------------------- implementation ------------------------------
321 CaptureThreadImpl::CaptureThreadImpl(CaptureThread* capture_thread, const QString& name, const QString& descr)
322 : m_capture_thread(capture_thread)
328 m_sampling_rate = CaptureThread::SAMPLING_RATE_UNKNOWN;
330 m_format_signed = true;
335 const QString& CaptureThreadImpl::getStatus()
343 void CaptureThreadImpl::setFormatDescrsAndFns(int format_size, bool format_signed, bool format_float, int channel_count)
345 m_format_size = format_size;
346 m_format_signed = format_signed;
347 m_format_float = format_float;
348 m_channel_count = channel_count;
350 if(m_format_size==2) // 16bits
352 if(m_format_signed) decodeValue = DecodeSigned16Bits;
353 else decodeValue = DecodeUnsigned16Bits;
357 if(m_format_signed) decodeValue = DecodeSigned8Bits;
358 else decodeValue = DecodeUnsigned8Bits;
361 if(m_channel_count==1)
362 addValue = AddValue1Channel;
363 else if(m_channel_count==2)
365 if(m_capture_thread->m_mix_multiple_channel)
366 addValue = AddValue2ChannelMix;
368 addValue = AddValue2ChannelFirst;
371 cerr << "CaptureThread: INFO: format is " << (m_format_signed?"signed":"unsigned") << " " << (m_format_float?"float":"integer") << " " << m_format_size*8 << "bits with " << m_channel_count << " channel(s)" << endl;