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