82 return 0; |
113 return 0; |
83 } |
114 } |
84 |
115 |
85 qint64 AudioInfo::writeData(const char *data, qint64 len) |
116 qint64 AudioInfo::writeData(const char *data, qint64 len) |
86 { |
117 { |
87 int samples = len/2; // 2 bytes per sample |
118 if (m_maxAmplitude) { |
88 int maxAmp = 32768; // max for S16 samples |
119 Q_ASSERT(m_format.sampleSize() % 8 == 0); |
89 bool clipping = false; |
120 const int channelBytes = m_format.sampleSize() / 8; |
90 |
121 const int sampleBytes = m_format.channels() * channelBytes; |
91 m_maxValue = 0; |
122 Q_ASSERT(len % sampleBytes == 0); |
92 |
123 const int numSamples = len / sampleBytes; |
93 qint16* s = (qint16*)data; |
124 |
94 |
125 quint16 maxValue = 0; |
95 // sample format is S16LE, only! |
126 const unsigned char *ptr = reinterpret_cast<const unsigned char *>(data); |
96 |
127 |
97 for(int i=0;i<samples;i++) { |
128 for (int i = 0; i < numSamples; ++i) { |
98 qint16 sample = *s; |
129 for(int j = 0; j < m_format.channels(); ++j) { |
99 s++; |
130 quint16 value = 0; |
100 if(abs(sample) > m_maxValue) m_maxValue = abs(sample); |
131 |
101 } |
132 if (m_format.sampleSize() == 8 && m_format.sampleType() == QAudioFormat::UnSignedInt) { |
102 // check for clipping |
133 value = *reinterpret_cast<const quint8*>(ptr); |
103 if(m_maxValue>=(maxAmp-1)) clipping = true; |
134 } else if (m_format.sampleSize() == 8 && m_format.sampleType() == QAudioFormat::SignedInt) { |
104 |
135 value = qAbs(*reinterpret_cast<const qint8*>(ptr)); |
105 float value = ((float)m_maxValue/(float)maxAmp); |
136 } else if (m_format.sampleSize() == 16 && m_format.sampleType() == QAudioFormat::UnSignedInt) { |
106 if(clipping) m_maxValue = 100; |
137 if (m_format.byteOrder() == QAudioFormat::LittleEndian) |
107 else m_maxValue = (int)(value*100); |
138 value = qFromLittleEndian<quint16>(ptr); |
|
139 else |
|
140 value = qFromBigEndian<quint16>(ptr); |
|
141 } else if (m_format.sampleSize() == 16 && m_format.sampleType() == QAudioFormat::SignedInt) { |
|
142 if (m_format.byteOrder() == QAudioFormat::LittleEndian) |
|
143 value = qAbs(qFromLittleEndian<qint16>(ptr)); |
|
144 else |
|
145 value = qAbs(qFromBigEndian<qint16>(ptr)); |
|
146 } |
|
147 |
|
148 maxValue = qMax(value, maxValue); |
|
149 ptr += channelBytes; |
|
150 } |
|
151 } |
|
152 |
|
153 maxValue = qMin(maxValue, m_maxAmplitude); |
|
154 m_level = qreal(maxValue) / m_maxAmplitude; |
|
155 } |
108 |
156 |
109 emit update(); |
157 emit update(); |
110 |
|
111 return len; |
158 return len; |
112 } |
|
113 |
|
114 int AudioInfo::LinearMax() |
|
115 { |
|
116 return m_maxValue; |
|
117 } |
159 } |
118 |
160 |
119 RenderArea::RenderArea(QWidget *parent) |
161 RenderArea::RenderArea(QWidget *parent) |
120 : QWidget(parent) |
162 : QWidget(parent) |
121 { |
163 { |
122 setBackgroundRole(QPalette::Base); |
164 setBackgroundRole(QPalette::Base); |
123 setAutoFillBackground(true); |
165 setAutoFillBackground(true); |
124 |
166 |
125 level = 0; |
167 m_level = 0; |
126 setMinimumHeight(30); |
168 setMinimumHeight(30); |
127 setMinimumWidth(200); |
169 setMinimumWidth(200); |
128 } |
170 } |
129 |
171 |
130 void RenderArea::paintEvent(QPaintEvent * /* event */) |
172 void RenderArea::paintEvent(QPaintEvent * /* event */) |
131 { |
173 { |
132 QPainter painter(this); |
174 QPainter painter(this); |
133 |
175 |
134 painter.setPen(Qt::black); |
176 painter.setPen(Qt::black); |
135 painter.drawRect(QRect(painter.viewport().left()+10, painter.viewport().top()+10, |
177 painter.drawRect(QRect(painter.viewport().left()+10, |
136 painter.viewport().right()-20, painter.viewport().bottom()-20)); |
178 painter.viewport().top()+10, |
137 |
179 painter.viewport().right()-20, |
138 if(level == 0) |
180 painter.viewport().bottom()-20)); |
|
181 if (m_level == 0.0) |
139 return; |
182 return; |
140 |
183 |
141 painter.setPen(Qt::red); |
184 painter.setPen(Qt::red); |
142 |
185 |
143 int pos = ((painter.viewport().right()-20)-(painter.viewport().left()+11))*level/100; |
186 int pos = ((painter.viewport().right()-20)-(painter.viewport().left()+11))*m_level; |
144 int x1,y1,x2,y2; |
187 for (int i = 0; i < 10; ++i) { |
145 for(int i=0;i<10;i++) { |
188 int x1 = painter.viewport().left()+11; |
146 x1 = painter.viewport().left()+11; |
189 int y1 = painter.viewport().top()+10+i; |
147 y1 = painter.viewport().top()+10+i; |
190 int x2 = painter.viewport().left()+20+pos; |
148 x2 = painter.viewport().left()+20+pos; |
191 int y2 = painter.viewport().top()+10+i; |
149 y2 = painter.viewport().top()+10+i; |
192 if (x2 < painter.viewport().left()+10) |
150 if(x2 < painter.viewport().left()+10) |
|
151 x2 = painter.viewport().left()+10; |
193 x2 = painter.viewport().left()+10; |
152 |
194 |
153 painter.drawLine(QPoint(x1,y1),QPoint(x2,y2)); |
195 painter.drawLine(QPoint(x1, y1),QPoint(x2, y2)); |
154 } |
196 } |
155 } |
197 } |
156 |
198 |
157 void RenderArea::setLevel(int value) |
199 void RenderArea::setLevel(qreal value) |
158 { |
200 { |
159 level = value; |
201 m_level = value; |
160 repaint(); |
202 repaint(); |
161 } |
203 } |
162 |
204 |
163 |
205 |
164 InputTest::InputTest() |
206 InputTest::InputTest() |
165 { |
207 : m_canvas(0) |
166 QWidget *window = new QWidget; |
208 , m_modeButton(0) |
167 QVBoxLayout* layout = new QVBoxLayout; |
209 , m_suspendResumeButton(0) |
168 |
210 , m_deviceBox(0) |
169 canvas = new RenderArea; |
211 , m_device(QAudioDeviceInfo::defaultInputDevice()) |
170 layout->addWidget(canvas); |
212 , m_audioInfo(0) |
171 |
213 , m_audioInput(0) |
172 deviceBox = new QComboBox(this); |
214 , m_input(0) |
|
215 , m_pullMode(false) |
|
216 , m_buffer(BufferSize, 0) |
|
217 { |
|
218 initializeWindow(); |
|
219 initializeAudio(); |
|
220 } |
|
221 |
|
222 InputTest::~InputTest() {} |
|
223 |
|
224 void InputTest::initializeWindow() |
|
225 { |
|
226 QScopedPointer<QWidget> window(new QWidget); |
|
227 QScopedPointer<QVBoxLayout> layout(new QVBoxLayout); |
|
228 |
|
229 m_canvas = new RenderArea(this); |
|
230 layout->addWidget(m_canvas); |
|
231 |
|
232 m_deviceBox = new QComboBox(this); |
173 QList<QAudioDeviceInfo> devices = QAudioDeviceInfo::availableDevices(QAudio::AudioInput); |
233 QList<QAudioDeviceInfo> devices = QAudioDeviceInfo::availableDevices(QAudio::AudioInput); |
174 for(int i = 0; i < devices.size(); ++i) { |
234 for(int i = 0; i < devices.size(); ++i) |
175 deviceBox->addItem(devices.at(i).deviceName(), qVariantFromValue(devices.at(i))); |
235 m_deviceBox->addItem(devices.at(i).deviceName(), qVariantFromValue(devices.at(i))); |
176 } |
236 |
177 connect(deviceBox,SIGNAL(activated(int)),SLOT(deviceChanged(int))); |
237 connect(m_deviceBox, SIGNAL(activated(int)), SLOT(deviceChanged(int))); |
178 layout->addWidget(deviceBox); |
238 layout->addWidget(m_deviceBox); |
179 |
239 |
180 button = new QPushButton(this); |
240 m_modeButton = new QPushButton(this); |
181 button->setText(tr("Click for Push Mode")); |
241 m_modeButton->setText(PushModeLabel); |
182 connect(button,SIGNAL(clicked()),SLOT(toggleMode())); |
242 connect(m_modeButton, SIGNAL(clicked()), SLOT(toggleMode())); |
183 layout->addWidget(button); |
243 layout->addWidget(m_modeButton); |
184 |
244 |
185 button2 = new QPushButton(this); |
245 m_suspendResumeButton = new QPushButton(this); |
186 button2->setText(tr("Click To Suspend")); |
246 m_suspendResumeButton->setText(SuspendLabel); |
187 connect(button2,SIGNAL(clicked()),SLOT(toggleSuspend())); |
247 connect(m_suspendResumeButton, SIGNAL(clicked()), SLOT(toggleSuspend())); |
188 layout->addWidget(button2); |
248 layout->addWidget(m_suspendResumeButton); |
189 |
249 |
190 window->setLayout(layout); |
250 window->setLayout(layout.data()); |
191 setCentralWidget(window); |
251 layout.take(); // ownership transferred |
192 window->show(); |
252 |
193 |
253 setCentralWidget(window.data()); |
194 buffer = new char[BUFFER_SIZE]; |
254 QWidget *const windowPtr = window.take(); // ownership transferred |
195 |
255 windowPtr->show(); |
196 pullMode = true; |
256 } |
197 |
257 |
198 format.setFrequency(8000); |
258 void InputTest::initializeAudio() |
199 format.setChannels(1); |
259 { |
200 format.setSampleSize(16); |
260 m_pullMode = true; |
201 format.setSampleType(QAudioFormat::SignedInt); |
261 |
202 format.setByteOrder(QAudioFormat::LittleEndian); |
262 m_format.setFrequency(8000); |
203 format.setCodec("audio/pcm"); |
263 m_format.setChannels(1); |
|
264 m_format.setSampleSize(16); |
|
265 m_format.setSampleType(QAudioFormat::SignedInt); |
|
266 m_format.setByteOrder(QAudioFormat::LittleEndian); |
|
267 m_format.setCodec("audio/pcm"); |
204 |
268 |
205 QAudioDeviceInfo info(QAudioDeviceInfo::defaultInputDevice()); |
269 QAudioDeviceInfo info(QAudioDeviceInfo::defaultInputDevice()); |
206 if (!info.isFormatSupported(format)) { |
270 if (!info.isFormatSupported(m_format)) { |
207 qWarning()<<"default format not supported try to use nearest"; |
271 qWarning() << "Default format not supported - trying to use nearest"; |
208 format = info.nearestFormat(format); |
272 m_format = info.nearestFormat(m_format); |
209 } |
273 } |
210 |
274 |
211 if(format.sampleSize() != 16) { |
275 m_audioInfo = new AudioInfo(m_format, this); |
212 qWarning()<<"audio device doesn't support 16 bit samples, example cannot run"; |
276 connect(m_audioInfo, SIGNAL(update()), SLOT(refreshDisplay())); |
|
277 |
|
278 createAudioInput(); |
|
279 } |
|
280 |
|
281 void InputTest::createAudioInput() |
|
282 { |
|
283 m_audioInput = new QAudioInput(m_device, m_format, this); |
|
284 connect(m_audioInput, SIGNAL(notify()), SLOT(notified())); |
|
285 connect(m_audioInput, SIGNAL(stateChanged(QAudio::State)), SLOT(stateChanged(QAudio::State))); |
|
286 m_audioInfo->start(); |
|
287 m_audioInput->start(m_audioInfo); |
|
288 } |
|
289 |
|
290 void InputTest::notified() |
|
291 { |
|
292 qWarning() << "bytesReady = " << m_audioInput->bytesReady() |
|
293 << ", " << "elapsedUSecs = " <<m_audioInput->elapsedUSecs() |
|
294 << ", " << "processedUSecs = "<<m_audioInput->processedUSecs(); |
|
295 } |
|
296 |
|
297 void InputTest::readMore() |
|
298 { |
|
299 if(!m_audioInput) |
213 return; |
300 return; |
214 } |
301 qint64 len = m_audioInput->bytesReady(); |
215 |
|
216 audioInput = new QAudioInput(format,this); |
|
217 connect(audioInput,SIGNAL(notify()),SLOT(status())); |
|
218 connect(audioInput,SIGNAL(stateChanged(QAudio::State)),SLOT(state(QAudio::State))); |
|
219 audioinfo = new AudioInfo(this,audioInput); |
|
220 connect(audioinfo,SIGNAL(update()),SLOT(refreshDisplay())); |
|
221 audioinfo->start(); |
|
222 audioInput->start(audioinfo); |
|
223 } |
|
224 |
|
225 InputTest::~InputTest() {} |
|
226 |
|
227 void InputTest::status() |
|
228 { |
|
229 qWarning()<<"bytesReady = "<<audioInput->bytesReady()<<" bytes, elapsedUSecs = "<<audioInput->elapsedUSecs()<<", processedUSecs = "<<audioInput->processedUSecs(); |
|
230 } |
|
231 |
|
232 void InputTest::readMore() |
|
233 { |
|
234 if(!audioInput) |
|
235 return; |
|
236 qint64 len = audioInput->bytesReady(); |
|
237 if(len > 4096) |
302 if(len > 4096) |
238 len = 4096; |
303 len = 4096; |
239 qint64 l = input->read(buffer,len); |
304 qint64 l = m_input->read(m_buffer.data(), len); |
240 if(l > 0) { |
305 if(l > 0) { |
241 audioinfo->write(buffer,l); |
306 m_audioInfo->write(m_buffer.constData(), l); |
242 } |
307 } |
243 } |
308 } |
244 |
309 |
245 void InputTest::toggleMode() |
310 void InputTest::toggleMode() |
246 { |
311 { |
247 // Change bewteen pull and push modes |
312 // Change bewteen pull and push modes |
248 audioInput->stop(); |
313 m_audioInput->stop(); |
249 |
314 |
250 if (pullMode) { |
315 if (m_pullMode) { |
251 button->setText(tr("Click for Pull Mode")); |
316 m_modeButton->setText(PullModeLabel); |
252 input = audioInput->start(); |
317 m_input = m_audioInput->start(); |
253 connect(input,SIGNAL(readyRead()),SLOT(readMore())); |
318 connect(m_input, SIGNAL(readyRead()), SLOT(readMore())); |
254 pullMode = false; |
319 m_pullMode = false; |
255 } else { |
320 } else { |
256 button->setText(tr("Click for Push Mode")); |
321 m_modeButton->setText(PushModeLabel); |
257 pullMode = true; |
322 m_pullMode = true; |
258 audioInput->start(audioinfo); |
323 m_audioInput->start(m_audioInfo); |
259 } |
324 } |
|
325 |
|
326 m_suspendResumeButton->setText(SuspendLabel); |
260 } |
327 } |
261 |
328 |
262 void InputTest::toggleSuspend() |
329 void InputTest::toggleSuspend() |
263 { |
330 { |
264 // toggle suspend/resume |
331 // toggle suspend/resume |
265 if(audioInput->state() == QAudio::SuspendedState) { |
332 if(m_audioInput->state() == QAudio::SuspendedState) { |
266 qWarning()<<"status: Suspended, resume()"; |
333 qWarning() << "status: Suspended, resume()"; |
267 audioInput->resume(); |
334 m_audioInput->resume(); |
268 button2->setText("Click To Suspend"); |
335 m_suspendResumeButton->setText(SuspendLabel); |
269 } else if (audioInput->state() == QAudio::ActiveState) { |
336 } else if (m_audioInput->state() == QAudio::ActiveState) { |
270 qWarning()<<"status: Active, suspend()"; |
337 qWarning() << "status: Active, suspend()"; |
271 audioInput->suspend(); |
338 m_audioInput->suspend(); |
272 button2->setText("Click To Resume"); |
339 m_suspendResumeButton->setText(ResumeLabel); |
273 } else if (audioInput->state() == QAudio::StoppedState) { |
340 } else if (m_audioInput->state() == QAudio::StoppedState) { |
274 qWarning()<<"status: Stopped, resume()"; |
341 qWarning() << "status: Stopped, resume()"; |
275 audioInput->resume(); |
342 m_audioInput->resume(); |
276 button2->setText("Click To Suspend"); |
343 m_suspendResumeButton->setText(SuspendLabel); |
277 } else if (audioInput->state() == QAudio::IdleState) { |
344 } else if (m_audioInput->state() == QAudio::IdleState) { |
278 qWarning()<<"status: IdleState"; |
345 qWarning() << "status: IdleState"; |
279 } |
346 } |
280 } |
347 } |
281 |
348 |
282 void InputTest::state(QAudio::State state) |
349 void InputTest::stateChanged(QAudio::State state) |
283 { |
350 { |
284 qWarning()<<" state="<<state; |
351 qWarning() << "state = " << state; |
285 } |
352 } |
286 |
353 |
287 void InputTest::refreshDisplay() |
354 void InputTest::refreshDisplay() |
288 { |
355 { |
289 canvas->setLevel(audioinfo->LinearMax()); |
356 m_canvas->setLevel(m_audioInfo->level()); |
290 canvas->repaint(); |
357 m_canvas->repaint(); |
291 } |
358 } |
292 |
359 |
293 void InputTest::deviceChanged(int idx) |
360 void InputTest::deviceChanged(int index) |
294 { |
361 { |
295 audioinfo->stop(); |
362 m_audioInfo->stop(); |
296 audioInput->stop(); |
363 m_audioInput->stop(); |
297 audioInput->disconnect(this); |
364 m_audioInput->disconnect(this); |
298 delete audioInput; |
365 delete m_audioInput; |
299 |
366 |
300 device = deviceBox->itemData(idx).value<QAudioDeviceInfo>(); |
367 m_device = m_deviceBox->itemData(index).value<QAudioDeviceInfo>(); |
301 audioInput = new QAudioInput(device, format, this); |
368 createAudioInput(); |
302 connect(audioInput,SIGNAL(notify()),SLOT(status())); |
369 } |
303 connect(audioInput,SIGNAL(stateChanged(QAudio::State)),SLOT(state(QAudio::State))); |
|
304 audioinfo->start(); |
|
305 audioInput->start(audioinfo); |
|
306 } |
|