diff options
author | Lars Knoll <lars.knoll@qt.io> | 2021-01-27 19:31:13 +0100 |
---|---|---|
committer | Lars Knoll <lars.knoll@qt.io> | 2021-02-09 14:33:28 +0000 |
commit | 89f4db5857ea0c30c52510785f505a9217750db5 (patch) | |
tree | 9f8ed97cddf1ae0c21a8a5d829e61ee8401a8fcd /examples | |
parent | c401a0dc71dc49cd34f8a5dd2fd7320f451e98bf (diff) |
Cleanup QAudioFormat and friends
Reduce the amount of available formats, and always
use host endianness.
Return both sample rate and channel count as a range,
not a list of values.
Change-Id: I88389b49ace077764fb647f50834236448e55c0e
Reviewed-by: Doris Verria <doris.verria@qt.io>
Reviewed-by: Lars Knoll <lars.knoll@qt.io>
Diffstat (limited to 'examples')
17 files changed, 259 insertions, 688 deletions
diff --git a/examples/multimedia/audiodecoder/audiodecoder.cpp b/examples/multimedia/audiodecoder/audiodecoder.cpp index fb64dc93a..686256544 100644 --- a/examples/multimedia/audiodecoder/audiodecoder.cpp +++ b/examples/multimedia/audiodecoder/audiodecoder.cpp @@ -61,9 +61,8 @@ AudioDecoder::AudioDecoder(bool isPlayback, bool isDelete) // Our wav file writer only supports SignedInt sample type. QAudioFormat format; format.setChannelCount(2); - format.setSampleSize(16); + format.setSampleFormat(QAudioFormat::Int16); format.setSampleRate(48000); - format.setSampleType(QAudioFormat::SignedInt); m_decoder.setAudioFormat(format); connect(&m_decoder, &QAudioDecoder::bufferReady, diff --git a/examples/multimedia/audiodecoder/wavefilewriter.cpp b/examples/multimedia/audiodecoder/wavefilewriter.cpp index 52c78c08f..a7bac62b4 100644 --- a/examples/multimedia/audiodecoder/wavefilewriter.cpp +++ b/examples/multimedia/audiodecoder/wavefilewriter.cpp @@ -105,7 +105,7 @@ bool WaveFileWriter::open(const QString& fileName, const QAudioFormat& format) if (file.isOpen()) return false; // file already open - if (format.sampleType() != QAudioFormat::SignedInt) + if (format.sampleFormat() != QAudioFormat::Int16) return false; // data format is not supported file.setFileName(fileName); @@ -145,7 +145,7 @@ bool WaveFileWriter::close() bool WaveFileWriter::writeHeader(const QAudioFormat &format) { // check if format is supported - if (format.byteOrder() == QAudioFormat::BigEndian || format.sampleType() != QAudioFormat::SignedInt) + if (format.sampleFormat() != QAudioFormat::Int16) return false; CombinedHeader header; @@ -166,9 +166,9 @@ bool WaveFileWriter::writeHeader(const QAudioFormat &format) header.wave.audioFormat = quint16(1); header.wave.numChannels = quint16(format.channelCount()); header.wave.sampleRate = quint32(format.sampleRate()); - header.wave.byteRate = quint32(format.sampleRate() * format.channelCount() * format.sampleSize() / 8); - header.wave.blockAlign = quint16(format.channelCount() * format.sampleSize() / 8); - header.wave.bitsPerSample = quint16(format.sampleSize()); + header.wave.byteRate = quint32(format.sampleRate() * format.channelCount() * format.bytesPerSample()); + header.wave.blockAlign = quint16(format.channelCount() * format.bytesPerSample()); + header.wave.bitsPerSample = quint16(format.bytesPerSample() * 8); // DATA header memcpy(header.data.descriptor.id,"data", 4); diff --git a/examples/multimedia/audiodevices/audiodevices.cpp b/examples/multimedia/audiodevices/audiodevices.cpp index 3a6dd4c2d..c624fcb3a 100644 --- a/examples/multimedia/audiodevices/audiodevices.cpp +++ b/examples/multimedia/audiodevices/audiodevices.cpp @@ -53,40 +53,23 @@ // Utility functions for converting QAudioFormat fields into text -static QString toString(QAudioFormat::SampleType sampleType) +static QString toString(QAudioFormat::SampleFormat sampleFormat) { - QString result("Unknown"); - switch (sampleType) { - case QAudioFormat::SignedInt: - result = "SignedInt"; - break; - case QAudioFormat::UnSignedInt: - result = "UnSignedInt"; - break; - case QAudioFormat::Float: - result = "Float"; - break; + switch (sampleFormat) { case QAudioFormat::Unknown: - result = "Unknown"; - } - return result; -} - -static QString toString(QAudioFormat::Endian endian) -{ - QString result("Unknown"); - switch (endian) { - case QAudioFormat::LittleEndian: - result = "LittleEndian"; - break; - case QAudioFormat::BigEndian: - result = "BigEndian"; - break; + case QAudioFormat::NSampleFormats: + return "Unknown"; + case QAudioFormat::UInt8: + return "Unsigned 8 bit"; + case QAudioFormat::Int16: + return "Signed 16 bit"; + case QAudioFormat::Int32: + return "Signed 32 bit"; + case QAudioFormat::Float: + return "Float"; } - return result; } - AudioDevicesBase::AudioDevicesBase(QWidget *parent) : QMainWindow(parent) { @@ -102,11 +85,9 @@ AudioTest::AudioTest(QWidget *parent) connect(testButton, &QPushButton::clicked, this, &AudioTest::test); connect(modeBox, QOverload<int>::of(&QComboBox::activated), this, &AudioTest::modeChanged); connect(deviceBox, QOverload<int>::of(&QComboBox::activated), this, &AudioTest::deviceChanged); - connect(sampleRateBox, QOverload<int>::of(&QComboBox::activated), this, &AudioTest::sampleRateChanged); - connect(channelsBox, QOverload<int>::of(&QComboBox::activated), this, &AudioTest::channelChanged); - connect(sampleSizesBox, QOverload<int>::of(&QComboBox::activated), this, &AudioTest::sampleSizeChanged); - connect(sampleTypesBox, QOverload<int>::of(&QComboBox::activated), this, &AudioTest::sampleTypeChanged); - connect(endianBox, QOverload<int>::of(&QComboBox::activated), this, &AudioTest::endianChanged); + connect(sampleRateSpinBox, &QSpinBox::valueChanged, this, &AudioTest::sampleRateChanged); + connect(channelsSpinBox, &QSpinBox::valueChanged, this, &AudioTest::channelChanged); + connect(sampleFormatBox, QOverload<int>::of(&QComboBox::activated), this, &AudioTest::sampleFormatChanged); connect(populateTableButton, &QPushButton::clicked, this, &AudioTest::populateTable); connect(QMediaDeviceManager::instance(), &QMediaDeviceManager::audioInputsChanged, this, &AudioTest::updateAudioDevices); connect(QMediaDeviceManager::instance(), &QMediaDeviceManager::audioOutputsChanged, this, &AudioTest::updateAudioDevices); @@ -127,17 +108,13 @@ void AudioTest::test() testResult->setText(tr("Success")); nearestSampleRate->setText(""); nearestChannel->setText(""); - nearestSampleSize->setText(""); - nearestSampleType->setText(""); - nearestEndian->setText(""); + nearestSampleFormat->setText(""); } else { - QAudioFormat nearest = m_deviceInfo.nearestFormat(m_settings); + QAudioFormat nearest = m_deviceInfo.preferredFormat(); testResult->setText(tr("Failed")); nearestSampleRate->setText(QString("%1").arg(nearest.sampleRate())); nearestChannel->setText(QString("%1").arg(nearest.channelCount())); - nearestSampleSize->setText(QString("%1").arg(nearest.sampleSize())); - nearestSampleType->setText(toString(nearest.sampleType())); - nearestEndian->setText(toString(nearest.byteOrder())); + nearestSampleFormat->setText(toString(nearest.sampleFormat())); } } else @@ -173,40 +150,27 @@ void AudioTest::deviceChanged(int idx) // device has changed m_deviceInfo = deviceBox->itemData(idx).value<QAudioDeviceInfo>(); - sampleRateBox->clear(); - const QList<int> sampleRatez = m_deviceInfo.supportedSampleRates(); - for (int i = 0; i < sampleRatez.size(); ++i) - sampleRateBox->addItem(QString("%1").arg(sampleRatez.at(i))); - if (sampleRatez.size()) - m_settings.setSampleRate(sampleRatez.at(0)); - - channelsBox->clear(); - const QList<int> chz = m_deviceInfo.supportedChannelCounts(); - for (int i = 0; i < chz.size(); ++i) - channelsBox->addItem(QString("%1").arg(chz.at(i))); - if (chz.size()) - m_settings.setChannelCount(chz.at(0)); - - sampleSizesBox->clear(); - const QList<int> sampleSizez = m_deviceInfo.supportedSampleSizes(); - for (int i = 0; i < sampleSizez.size(); ++i) - sampleSizesBox->addItem(QString("%1").arg(sampleSizez.at(i))); - if (sampleSizez.size()) - m_settings.setSampleSize(sampleSizez.at(0)); - - sampleTypesBox->clear(); - const QList<QAudioFormat::SampleType> sampleTypez = m_deviceInfo.supportedSampleTypes(); - for (int i = 0; i < sampleTypez.size(); ++i) - sampleTypesBox->addItem(toString(sampleTypez.at(i))); - if (sampleTypez.size()) - m_settings.setSampleType(sampleTypez.at(0)); - - endianBox->clear(); - const QList<QAudioFormat::Endian> endianz = m_deviceInfo.supportedByteOrders(); - for (int i = 0; i < endianz.size(); ++i) - endianBox->addItem(toString(endianz.at(i))); - if (endianz.size()) - m_settings.setByteOrder(endianz.at(0)); + sampleRateSpinBox->clear(); + auto sampleRates = m_deviceInfo.supportedSampleRates(); + sampleRateSpinBox->setMinimum(sampleRates.minimum); + sampleRateSpinBox->setMaximum(sampleRates.maximum); + int sampleValue = qBound(sampleRates.minimum, 48000, sampleRates.maximum); + sampleRateSpinBox->setValue(sampleValue); + m_settings.setSampleRate(sampleValue); + + channelsSpinBox->clear(); + auto channelRates = m_deviceInfo.supportedChannelCounts(); + channelsSpinBox->setMinimum(channelRates.minimum); + channelsSpinBox->setMaximum(channelRates.maximum); + int channelValue = qBound(channelRates.minimum, 2, channelRates.maximum); + channelsSpinBox->setValue(channelValue); + + sampleFormatBox->clear(); + const QList<QAudioFormat::SampleFormat> sampleFormats = m_deviceInfo.supportedSampleFormats(); + for (int i = 0; i < sampleFormats.size(); ++i) + sampleFormatBox->addItem(toString(sampleFormats.at(i))); + if (sampleFormats.size()) + m_settings.setSampleFormat(sampleFormats.at(0)); allFormatsTable->clearContents(); } @@ -215,81 +179,37 @@ void AudioTest::populateTable() { int row = 0; - QAudioFormat format; - for (auto sampleRate: m_deviceInfo.supportedSampleRates()) { - format.setSampleRate(sampleRate); - for (auto channels: m_deviceInfo.supportedChannelCounts()) { - format.setChannelCount(channels); - for (auto sampleType: m_deviceInfo.supportedSampleTypes()) { - format.setSampleType(sampleType); - for (auto sampleSize: m_deviceInfo.supportedSampleSizes()) { - format.setSampleSize(sampleSize); - for (auto endian: m_deviceInfo.supportedByteOrders()) { - format.setByteOrder(endian); - if (m_deviceInfo.isFormatSupported(format)) { - allFormatsTable->setRowCount(row + 1); + for (auto sampleFormat : m_deviceInfo.supportedSampleFormats()) { + allFormatsTable->setRowCount(row + 1); - QTableWidgetItem *sampleRateItem = new QTableWidgetItem(QString("%1").arg(format.sampleRate())); - allFormatsTable->setItem(row, 0, sampleRateItem); + QTableWidgetItem *sampleTypeItem = new QTableWidgetItem(toString(sampleFormat)); + allFormatsTable->setItem(row, 2, sampleTypeItem); - QTableWidgetItem *channelsItem = new QTableWidgetItem(QString("%1").arg(format.channelCount())); - allFormatsTable->setItem(row, 1, channelsItem); + auto sampleRates = m_deviceInfo.supportedSampleRates(); + QTableWidgetItem *sampleRateItem = new QTableWidgetItem(QString("%1 - %2").arg(sampleRates.minimum).arg(sampleRates.maximum)); + allFormatsTable->setItem(row, 0, sampleRateItem); - QTableWidgetItem *sampleTypeItem = new QTableWidgetItem(toString(format.sampleType())); - allFormatsTable->setItem(row, 2, sampleTypeItem); + auto channels = m_deviceInfo.supportedChannelCounts(); + QTableWidgetItem *channelsItem = new QTableWidgetItem(QString("%1 - %2").arg(channels.minimum).arg(channels.maximum)); + allFormatsTable->setItem(row, 1, channelsItem); - QTableWidgetItem *sampleSizeItem = new QTableWidgetItem(QString("%1").arg(format.sampleSize())); - allFormatsTable->setItem(row, 3, sampleSizeItem); - - QTableWidgetItem *byteOrderItem = new QTableWidgetItem(toString(format.byteOrder())); - allFormatsTable->setItem(row, 4, byteOrderItem); - - ++row; - } - } - } - } - } + ++row; } } -void AudioTest::sampleRateChanged(int idx) +void AudioTest::sampleRateChanged(int value) { // sample rate has changed - m_settings.setSampleRate(sampleRateBox->itemText(idx).toInt()); -} - -void AudioTest::channelChanged(int idx) -{ - m_settings.setChannelCount(channelsBox->itemText(idx).toInt()); + m_settings.setSampleRate(value); } -void AudioTest::sampleSizeChanged(int idx) +void AudioTest::channelChanged(int channels) { - m_settings.setSampleSize(sampleSizesBox->itemText(idx).toInt()); + m_settings.setChannelCount(channels); } -void AudioTest::sampleTypeChanged(int idx) +void AudioTest::sampleFormatChanged(int idx) { - switch (sampleTypesBox->itemText(idx).toInt()) { - case QAudioFormat::SignedInt: - m_settings.setSampleType(QAudioFormat::SignedInt); - break; - case QAudioFormat::UnSignedInt: - m_settings.setSampleType(QAudioFormat::UnSignedInt); - break; - case QAudioFormat::Float: - m_settings.setSampleType(QAudioFormat::Float); - } -} - -void AudioTest::endianChanged(int idx) -{ - switch (endianBox->itemText(idx).toInt()) { - case QAudioFormat::LittleEndian: - m_settings.setByteOrder(QAudioFormat::LittleEndian); - break; - case QAudioFormat::BigEndian: - m_settings.setByteOrder(QAudioFormat::BigEndian); - } + auto formats = m_deviceInfo.supportedSampleFormats(); + m_settings.setSampleFormat(formats.at(idx)); } diff --git a/examples/multimedia/audiodevices/audiodevices.h b/examples/multimedia/audiodevices/audiodevices.h index be9b36ff7..31ec479df 100644 --- a/examples/multimedia/audiodevices/audiodevices.h +++ b/examples/multimedia/audiodevices/audiodevices.h @@ -82,9 +82,7 @@ private slots: void deviceChanged(int idx); void sampleRateChanged(int idx); void channelChanged(int idx); - void sampleSizeChanged(int idx); - void sampleTypeChanged(int idx); - void endianChanged(int idx); + void sampleFormatChanged(int idx); void test(); void populateTable(); diff --git a/examples/multimedia/audiodevices/audiodevicesbase.ui b/examples/multimedia/audiodevices/audiodevicesbase.ui index 5d5ef4835..9618a3d22 100644 --- a/examples/multimedia/audiodevices/audiodevicesbase.ui +++ b/examples/multimedia/audiodevices/audiodevicesbase.ui @@ -6,8 +6,8 @@ <rect> <x>0</x> <y>0</y> - <width>679</width> - <height>598</height> + <width>646</width> + <height>528</height> </rect> </property> <property name="windowTitle"> @@ -31,8 +31,8 @@ <rect> <x>0</x> <y>0</y> - <width>653</width> - <height>545</height> + <width>626</width> + <height>480</height> </rect> </property> <layout class="QGridLayout" name="gridLayout_4"> @@ -72,134 +72,72 @@ <item row="2" column="0" colspan="2"> <widget class="QTabWidget" name="tabWidget"> <property name="currentIndex"> - <number>1</number> + <number>0</number> </property> <widget class="QWidget" name="testFormatTab"> <attribute name="title"> <string>Test format</string> </attribute> <layout class="QGridLayout" name="gridLayout"> - <item row="14" column="1"> + <item row="12" column="1"> <widget class="QPushButton" name="testButton"> <property name="text"> <string>Test</string> </property> </widget> </item> - <item row="0" column="2"> - <widget class="QLabel" name="nearestLabel"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Preferred" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="frameShape"> - <enum>QFrame::NoFrame</enum> - </property> - <property name="frameShadow"> - <enum>QFrame::Plain</enum> - </property> - <property name="text"> - <string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> -<html><head><meta name="qrichtext" content="1" /><style type="text/css"> -p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-style:italic;">Nearest Settings</span></p></body></html></string> - </property> - <property name="textFormat"> - <enum>Qt::RichText</enum> - </property> - <property name="alignment"> - <set>Qt::AlignCenter</set> - </property> - </widget> - </item> - <item row="8" column="2"> - <widget class="QLineEdit" name="nearestSampleSize"> - <property name="enabled"> - <bool>false</bool> - </property> - </widget> - </item> - <item row="14" column="2"> + <item row="12" column="2"> <widget class="QLabel" name="testResult"> <property name="text"> <string/> </property> </widget> </item> - <item row="5" column="0"> - <widget class="QLabel" name="actualSampleTypeLabel"> - <property name="text"> - <string>SampleType</string> - </property> - </widget> - </item> - <item row="8" column="0"> - <widget class="QLabel" name="actualSampleSizeLabel"> - <property name="text"> - <string>Sample size (bits)</string> - </property> - </widget> - </item> - <item row="13" column="0"> - <widget class="QLabel" name="actualEndianLabel"> + <item row="4" column="0"> + <widget class="QLabel" name="actualChannelLabel"> <property name="text"> - <string>Endianness</string> + <string>Channels</string> </property> </widget> </item> - <item row="5" column="2"> - <widget class="QLineEdit" name="nearestSampleType"> + <item row="2" column="2"> + <widget class="QLineEdit" name="nearestSampleRate"> <property name="enabled"> <bool>false</bool> </property> </widget> </item> - <item row="5" column="1"> - <widget class="QComboBox" name="sampleTypesBox"/> - </item> - <item row="4" column="2"> - <widget class="QLineEdit" name="nearestChannel"> + <item row="5" column="2"> + <widget class="QLineEdit" name="nearestSampleFormat"> <property name="enabled"> <bool>false</bool> </property> </widget> </item> - <item row="4" column="0"> - <widget class="QLabel" name="actualChannelLabel"> + <item row="5" column="0"> + <widget class="QLabel" name="actualSampleTypeLabel"> <property name="text"> - <string>Channels</string> + <string>Sample Format</string> </property> </widget> </item> - <item row="13" column="1"> - <widget class="QComboBox" name="endianBox"/> - </item> - <item row="8" column="1"> - <widget class="QComboBox" name="sampleSizesBox"/> - </item> - <item row="2" column="2"> - <widget class="QLineEdit" name="nearestSampleRate"> + <item row="4" column="2"> + <widget class="QLineEdit" name="nearestChannel"> <property name="enabled"> <bool>false</bool> </property> </widget> </item> - <item row="2" column="1"> - <widget class="QComboBox" name="sampleRateBox"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Expanding" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> + <item row="5" column="1"> + <widget class="QComboBox" name="sampleFormatBox"/> + </item> + <item row="2" column="0"> + <widget class="QLabel" name="actualFreqLabel"> + <property name="text"> + <string>Frequency (Hz)</string> </property> </widget> </item> - <item row="4" column="1"> - <widget class="QComboBox" name="channelsBox"/> - </item> <item row="0" column="1"> <widget class="QLabel" name="actualLabel"> <property name="sizePolicy"> @@ -225,19 +163,53 @@ p, li { white-space: pre-wrap; } </property> </widget> </item> - <item row="2" column="0"> - <widget class="QLabel" name="actualFreqLabel"> + <item row="0" column="2"> + <widget class="QLabel" name="nearestLabel"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="frameShape"> + <enum>QFrame::NoFrame</enum> + </property> + <property name="frameShadow"> + <enum>QFrame::Plain</enum> + </property> <property name="text"> - <string>Frequency (Hz)</string> + <string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-style:italic;">Nearest Settings</span></p></body></html></string> + </property> + <property name="textFormat"> + <enum>Qt::RichText</enum> + </property> + <property name="alignment"> + <set>Qt::AlignCenter</set> </property> </widget> </item> - <item row="13" column="2"> - <widget class="QLineEdit" name="nearestEndian"> - <property name="enabled"> - <bool>false</bool> + <item row="13" column="1"> + <spacer name="verticalSpacer"> + <property name="orientation"> + <enum>Qt::Vertical</enum> </property> - </widget> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </spacer> + </item> + <item row="2" column="1"> + <widget class="QSpinBox" name="sampleRateSpinBox"/> + </item> + <item row="4" column="1"> + <widget class="QSpinBox" name="channelsSpinBox"/> </item> </layout> </widget> @@ -280,7 +252,7 @@ p, li { white-space: pre-wrap; } <bool>false</bool> </property> <property name="columnCount"> - <number>5</number> + <number>3</number> </property> <attribute name="horizontalHeaderHighlightSections"> <bool>false</bool> @@ -296,15 +268,7 @@ p, li { white-space: pre-wrap; } </attribute> <column> <property name="text"> - <string>Frequency (Hz)</string> - </property> - <property name="textAlignment"> - <set>AlignCenter</set> - </property> - </column> - <column> - <property name="text"> - <string>Channels</string> + <string>Sample Format</string> </property> <property name="textAlignment"> <set>AlignCenter</set> @@ -312,7 +276,7 @@ p, li { white-space: pre-wrap; } </column> <column> <property name="text"> - <string>Sample type</string> + <string>Frequency (Hz)</string> </property> <property name="textAlignment"> <set>AlignCenter</set> @@ -320,17 +284,12 @@ p, li { white-space: pre-wrap; } </column> <column> <property name="text"> - <string>Sample size (bits)</string> + <string>Channels</string> </property> <property name="textAlignment"> <set>AlignCenter</set> </property> </column> - <column> - <property name="text"> - <string>Endianness</string> - </property> - </column> </widget> </item> </layout> diff --git a/examples/multimedia/audioinput/audioinput.cpp b/examples/multimedia/audioinput/audioinput.cpp index d86f2d33c..40303340f 100644 --- a/examples/multimedia/audioinput/audioinput.cpp +++ b/examples/multimedia/audioinput/audioinput.cpp @@ -64,50 +64,6 @@ AudioInfo::AudioInfo(const QAudioFormat &format) : m_format(format) { - switch (m_format.sampleSize()) { - case 8: - switch (m_format.sampleType()) { - case QAudioFormat::UnSignedInt: - m_maxAmplitude = 255; - break; - case QAudioFormat::SignedInt: - m_maxAmplitude = 127; - break; - default: - break; - } - break; - case 16: - switch (m_format.sampleType()) { - case QAudioFormat::UnSignedInt: - m_maxAmplitude = 65535; - break; - case QAudioFormat::SignedInt: - m_maxAmplitude = 32767; - break; - default: - break; - } - break; - - case 32: - switch (m_format.sampleType()) { - case QAudioFormat::UnSignedInt: - m_maxAmplitude = 0xffffffff; - break; - case QAudioFormat::SignedInt: - m_maxAmplitude = 0x7fffffff; - break; - case QAudioFormat::Float: - m_maxAmplitude = 0x7fffffff; // Kind of - default: - break; - } - break; - - default: - break; - } } void AudioInfo::start() @@ -130,57 +86,25 @@ qint64 AudioInfo::readData(char *data, qint64 maxlen) qint64 AudioInfo::writeData(const char *data, qint64 len) { - if (m_maxAmplitude) { - Q_ASSERT(m_format.sampleSize() % 8 == 0); - const int channelBytes = m_format.sampleSize() / 8; - const int sampleBytes = m_format.channelCount() * channelBytes; - Q_ASSERT(len % sampleBytes == 0); - const int numSamples = len / sampleBytes; - - quint32 maxValue = 0; - const unsigned char *ptr = reinterpret_cast<const unsigned char *>(data); - - for (int i = 0; i < numSamples; ++i) { - for (int j = 0; j < m_format.channelCount(); ++j) { - quint32 value = 0; - - if (m_format.sampleSize() == 8 && m_format.sampleType() == QAudioFormat::UnSignedInt) { - value = *reinterpret_cast<const quint8*>(ptr); - } else if (m_format.sampleSize() == 8 && m_format.sampleType() == QAudioFormat::SignedInt) { - value = qAbs(*reinterpret_cast<const qint8*>(ptr)); - } else if (m_format.sampleSize() == 16 && m_format.sampleType() == QAudioFormat::UnSignedInt) { - if (m_format.byteOrder() == QAudioFormat::LittleEndian) - value = qFromLittleEndian<quint16>(ptr); - else - value = qFromBigEndian<quint16>(ptr); - } else if (m_format.sampleSize() == 16 && m_format.sampleType() == QAudioFormat::SignedInt) { - if (m_format.byteOrder() == QAudioFormat::LittleEndian) - value = qAbs(qFromLittleEndian<qint16>(ptr)); - else - value = qAbs(qFromBigEndian<qint16>(ptr)); - } else if (m_format.sampleSize() == 32 && m_format.sampleType() == QAudioFormat::UnSignedInt) { - if (m_format.byteOrder() == QAudioFormat::LittleEndian) - value = qFromLittleEndian<quint32>(ptr); - else - value = qFromBigEndian<quint32>(ptr); - } else if (m_format.sampleSize() == 32 && m_format.sampleType() == QAudioFormat::SignedInt) { - if (m_format.byteOrder() == QAudioFormat::LittleEndian) - value = qAbs(qFromLittleEndian<qint32>(ptr)); - else - value = qAbs(qFromBigEndian<qint32>(ptr)); - } else if (m_format.sampleSize() == 32 && m_format.sampleType() == QAudioFormat::Float) { - value = qAbs(*reinterpret_cast<const float*>(ptr) * 0x7fffffff); // assumes 0-1.0 - } - - maxValue = qMax(value, maxValue); - ptr += channelBytes; - } - } + const int channelBytes = m_format.bytesPerSample(); + const int sampleBytes = m_format.bytesPerFrame(); + Q_ASSERT(len % sampleBytes == 0); + const int numSamples = len / sampleBytes; - maxValue = qMin(maxValue, m_maxAmplitude); - m_level = qreal(maxValue) / m_maxAmplitude; + float maxValue = 0; + const unsigned char *ptr = reinterpret_cast<const unsigned char *>(data); + + for (int i = 0; i < numSamples; ++i) { + for (int j = 0; j < m_format.channelCount(); ++j) { + float value = m_format.normalizedSampleValue(ptr); + + maxValue = qMax(value, maxValue); + ptr += channelBytes; + } } + m_level = maxValue; + emit update(); return len; } @@ -274,14 +198,7 @@ void InputTest::initializeAudio(const QAudioDeviceInfo &deviceInfo) QAudioFormat format; format.setSampleRate(8000); format.setChannelCount(1); - format.setSampleSize(16); - format.setSampleType(QAudioFormat::SignedInt); - format.setByteOrder(QAudioFormat::LittleEndian); - - if (!deviceInfo.isFormatSupported(format)) { - qWarning() << "Default format not supported - trying to use nearest"; - format = deviceInfo.nearestFormat(format); - } + format.setSampleFormat(QAudioFormat::Int16); m_audioInfo.reset(new AudioInfo(format)); connect(m_audioInfo.data(), &AudioInfo::update, [this]() { diff --git a/examples/multimedia/audioinput/audioinput.h b/examples/multimedia/audioinput/audioinput.h index 7bfe3ea24..ea24069a0 100644 --- a/examples/multimedia/audioinput/audioinput.h +++ b/examples/multimedia/audioinput/audioinput.h @@ -80,7 +80,6 @@ public: private: const QAudioFormat m_format; - quint32 m_maxAmplitude = 0; qreal m_level = 0.0; // 0.0 <= m_level <= 1.0 signals: diff --git a/examples/multimedia/audiooutput/audiooutput.cpp b/examples/multimedia/audiooutput/audiooutput.cpp index e2133d941..971972cab 100644 --- a/examples/multimedia/audiooutput/audiooutput.cpp +++ b/examples/multimedia/audiooutput/audiooutput.cpp @@ -76,10 +76,9 @@ void Generator::stop() void Generator::generateData(const QAudioFormat &format, qint64 durationUs, int sampleRate) { - const int channelBytes = format.sampleSize() / 8; + const int channelBytes = format.bytesPerSample(); const int sampleBytes = format.channelCount() * channelBytes; - qint64 length = (format.sampleRate() * format.channelCount() * (format.sampleSize() / 8)) - * durationUs / 1000000; + qint64 length = format.bytesForDuration(durationUs); Q_ASSERT(length % sampleBytes == 0); Q_UNUSED(sampleBytes); // suppress warning in release builds @@ -91,28 +90,21 @@ void Generator::generateData(const QAudioFormat &format, qint64 durationUs, int // Produces value (-1..1) const qreal x = qSin(2 * M_PI * sampleRate * qreal(sampleIndex++ % format.sampleRate()) / format.sampleRate()); for (int i=0; i<format.channelCount(); ++i) { - if (format.sampleSize() == 8) { - if (format.sampleType() == QAudioFormat::UnSignedInt) { - const quint8 value = static_cast<quint8>((1.0 + x) / 2 * 255); - *reinterpret_cast<quint8 *>(ptr) = value; - } else if (format.sampleType() == QAudioFormat::SignedInt) { - const qint8 value = static_cast<qint8>(x * 127); - *reinterpret_cast<qint8 *>(ptr) = value; - } - } else if (format.sampleSize() == 16) { - if (format.sampleType() == QAudioFormat::UnSignedInt) { - quint16 value = static_cast<quint16>((1.0 + x) / 2 * 65535); - if (format.byteOrder() == QAudioFormat::LittleEndian) - qToLittleEndian<quint16>(value, ptr); - else - qToBigEndian<quint16>(value, ptr); - } else if (format.sampleType() == QAudioFormat::SignedInt) { - qint16 value = static_cast<qint16>(x * 32767); - if (format.byteOrder() == QAudioFormat::LittleEndian) - qToLittleEndian<qint16>(value, ptr); - else - qToBigEndian<qint16>(value, ptr); - } + switch(format.sampleFormat()) { + case QAudioFormat::UInt8: + *reinterpret_cast<quint8 *>(ptr) = static_cast<quint8>((1.0 + x) / 2 * 255); + break; + case QAudioFormat::Int16: + *reinterpret_cast<qint16 *>(ptr) = static_cast<qint16>(x * 32767); + break; + case QAudioFormat::Int32: + *reinterpret_cast<qint32 *>(ptr) = static_cast<qint32>(x * std::numeric_limits<qint32>::max()); + break; + case QAudioFormat::Float: + *reinterpret_cast<float *>(ptr) = x; + break; + default: + break; } ptr += channelBytes; @@ -204,17 +196,7 @@ void AudioTest::initializeWindow() void AudioTest::initializeAudio(const QAudioDeviceInfo &deviceInfo) { - QAudioFormat format; - format.setSampleRate(44100); - format.setChannelCount(1); - format.setSampleSize(16); - format.setByteOrder(QAudioFormat::LittleEndian); - format.setSampleType(QAudioFormat::SignedInt); - - if (!deviceInfo.isFormatSupported(format)) { - qWarning() << "Default format not supported - trying to use nearest"; - format = deviceInfo.nearestFormat(format); - } + QAudioFormat format = deviceInfo.preferredFormat(); const int durationSeconds = 1; const int toneSampleRateHz = 600; diff --git a/examples/multimedia/audiorecorder/audiorecorder.cpp b/examples/multimedia/audiorecorder/audiorecorder.cpp index dd3a22fa3..ddd28bcdf 100644 --- a/examples/multimedia/audiorecorder/audiorecorder.cpp +++ b/examples/multimedia/audiorecorder/audiorecorder.cpp @@ -62,12 +62,8 @@ #include <qaudiodeviceinfo.h> #include <qaudiobuffer.h> -static qreal getPeakValue(const QAudioFormat &format); static QList<qreal> getBufferLevels(const QAudioBuffer &buffer); -template<class T> -static QList<qreal> getBufferLevels(const T *buffer, int frames, int channels); - AudioRecorder::AudioRecorder() : ui(new Ui::AudioRecorder) { @@ -254,100 +250,29 @@ void AudioRecorder::clearAudioLevels() m_audioLevel->setLevel(0); } -// This function returns the maximum possible sample value for a given audio format -qreal getPeakValue(const QAudioFormat& format) -{ - // Note: Only the most common sample formats are supported - if (!format.isValid()) - return qreal(0); - - switch (format.sampleType()) { - case QAudioFormat::Unknown: - break; - case QAudioFormat::Float: - if (format.sampleSize() != 32) // other sample formats are not supported - return qreal(0); - return qreal(1.00003); - case QAudioFormat::SignedInt: - if (format.sampleSize() == 32) - return qreal(INT_MAX); - if (format.sampleSize() == 16) - return qreal(SHRT_MAX); - if (format.sampleSize() == 8) - return qreal(CHAR_MAX); - break; - case QAudioFormat::UnSignedInt: - if (format.sampleSize() == 32) - return qreal(UINT_MAX); - if (format.sampleSize() == 16) - return qreal(USHRT_MAX); - if (format.sampleSize() == 8) - return qreal(UCHAR_MAX); - break; - } - - return qreal(0); -} - // returns the audio level for each channel QList<qreal> getBufferLevels(const QAudioBuffer &buffer) { QList<qreal> values; - if (!buffer.format().isValid() || buffer.format().byteOrder() != QAudioFormat::LittleEndian) + auto format = buffer.format(); + if (!format.isValid()) return values; - int channelCount = buffer.format().channelCount(); - values.fill(0, channelCount); - qreal peak_value = getPeakValue(buffer.format()); - if (qFuzzyCompare(peak_value, qreal(0))) - return values; + int channels = buffer.format().channelCount(); + values.fill(0, channels); - switch (buffer.format().sampleType()) { - case QAudioFormat::Unknown: - case QAudioFormat::UnSignedInt: - if (buffer.format().sampleSize() == 32) - values = getBufferLevels(buffer.constData<quint32>(), buffer.frameCount(), channelCount); - if (buffer.format().sampleSize() == 16) - values = getBufferLevels(buffer.constData<quint16>(), buffer.frameCount(), channelCount); - if (buffer.format().sampleSize() == 8) - values = getBufferLevels(buffer.constData<quint8>(), buffer.frameCount(), channelCount); - for (double &value : values) - value = qAbs(value - peak_value / 2) / (peak_value / 2); - break; - case QAudioFormat::Float: - if (buffer.format().sampleSize() == 32) { - values = getBufferLevels(buffer.constData<float>(), buffer.frameCount(), channelCount); - for (double &value : values) - value /= peak_value; - } - break; - case QAudioFormat::SignedInt: - if (buffer.format().sampleSize() == 32) - values = getBufferLevels(buffer.constData<qint32>(), buffer.frameCount(), channelCount); - if (buffer.format().sampleSize() == 16) - values = getBufferLevels(buffer.constData<qint16>(), buffer.frameCount(), channelCount); - if (buffer.format().sampleSize() == 8) - values = getBufferLevels(buffer.constData<qint8>(), buffer.frameCount(), channelCount); - for (double &value : values) - value /= peak_value; - break; - } - - return values; -} - -template<class T> -QList<qreal> getBufferLevels(const T *buffer, int frames, int channels) -{ + int bytesPerSample = format.bytesPerSample(); QList<qreal> max_values; max_values.fill(0, channels); - for (int i = 0; i < frames; ++i) { + const char *data = buffer.constData<char>(); + for (int i = 0; i < buffer.frameCount(); ++i) { for (int j = 0; j < channels; ++j) { - qreal value = qAbs(qreal(buffer[i * channels + j])); + qreal value = qAbs(format.normalizedSampleValue(data)); if (value > max_values.at(j)) - max_values.replace(j, value); + max_values[j] = value; + data += bytesPerSample; } } diff --git a/examples/multimedia/spectrum/app/engine.cpp b/examples/multimedia/spectrum/app/engine.cpp index 8977f85cd..7c678333d 100644 --- a/examples/multimedia/spectrum/app/engine.cpp +++ b/examples/multimedia/spectrum/app/engine.cpp @@ -155,7 +155,7 @@ bool Engine::loadFile(const QString &fileName) Q_ASSERT(!fileName.isEmpty()); m_file = new WavFile(this); if (m_file->open(fileName)) { - if (isPCMS16LE(m_file->fileFormat())) { + if (m_file->fileFormat().sampleFormat() == QAudioFormat::Int16) { result = initialize(); } else { emit errorMessage(tr("Audio format not supported"), @@ -333,7 +333,7 @@ void Engine::audioNotify() { switch (m_mode) { case QAudio::AudioInput: { - const qint64 recordPosition = qMin(m_bufferLength, audioLength(m_format, m_audioInput->processedUSecs())); + const qint64 recordPosition = qMin(m_bufferLength, m_format.bytesForDuration(m_audioInput->processedUSecs())); setRecordPosition(recordPosition); const qint64 levelPosition = m_dataLength - m_levelBufferLength; if (levelPosition >= 0) @@ -346,7 +346,7 @@ void Engine::audioNotify() } break; case QAudio::AudioOutput: { - const qint64 playPosition = audioLength(m_format, m_audioOutput->processedUSecs()); + const qint64 playPosition = m_format.bytesForDuration(m_audioOutput->processedUSecs()); setPlayPosition(qMin(bufferLength(), playPosition)); const qint64 levelPosition = playPosition - m_levelBufferLength; const qint64 spectrumPosition = playPosition - m_spectrumBufferLength; @@ -359,7 +359,7 @@ void Engine::audioNotify() // Data needs to be read into m_buffer in order to be analysed const qint64 readPos = qMax(qint64(0), qMin(levelPosition, spectrumPosition)); const qint64 readEnd = qMin(m_analysisFile->size(), qMax(levelPosition + m_levelBufferLength, spectrumPosition + m_spectrumBufferLength)); - const qint64 readLen = readEnd - readPos + audioLength(m_format, WaveformWindowDuration); + const qint64 readLen = readEnd - readPos + m_format.bytesForDuration(WaveformWindowDuration); qDebug() << "Engine::audioNotify [1]" << "analysisFileSize" << m_analysisFile->size() << "readPos" << readPos @@ -494,7 +494,7 @@ bool Engine::initialize() setRecordPosition(bufferLength()); result = true; } else { - m_bufferLength = audioLength(m_format, BufferDurationUs); + m_bufferLength = m_format.bytesForDuration(BufferDurationUs); m_buffer.resize(m_bufferLength); m_buffer.fill(0); emit bufferLengthChanged(bufferLength()); @@ -555,56 +555,24 @@ bool Engine::selectFormat() } } else { - QList<int> sampleRatesList; - #ifdef Q_OS_WIN - // The Windows audio backend does not correctly report format support - // (see QTBUG-9100). Furthermore, although the audio subsystem captures - // at 11025Hz, the resulting audio is corrupted. - sampleRatesList += 8000; - #endif - - if (!m_generateTone) - sampleRatesList += m_audioInputDevice.supportedSampleRates(); - - sampleRatesList += m_audioOutputDevice.supportedSampleRates(); - std::sort(sampleRatesList.begin(), sampleRatesList.end()); - const auto uniqueRatesEnd = std::unique(sampleRatesList.begin(), sampleRatesList.end()); - sampleRatesList.erase(uniqueRatesEnd, sampleRatesList.end()); - ENGINE_DEBUG << "Engine::initialize frequenciesList" << sampleRatesList; - - QList<int> channelsList; - channelsList += m_audioInputDevice.supportedChannelCounts(); - channelsList += m_audioOutputDevice.supportedChannelCounts(); - std::sort(channelsList.begin(), channelsList.end()); - const auto uniqueChannelsEnd = std::unique(channelsList.begin(), channelsList.end()); - channelsList.erase(uniqueChannelsEnd, channelsList.end()); - ENGINE_DEBUG << "Engine::initialize channelsList" << channelsList; + QAudioDeviceInfo::Range sampleRange = m_audioInputDevice.supportedSampleRates(); + QAudioDeviceInfo::Range outputSampleRange = m_audioOutputDevice.supportedSampleRates(); + if (sampleRange.minimum < outputSampleRange.minimum) + sampleRange.minimum = outputSampleRange.minimum; + if (sampleRange.maximum > outputSampleRange.maximum) + sampleRange.maximum = outputSampleRange.maximum; - QAudioFormat format; - format.setByteOrder(QAudioFormat::LittleEndian); - format.setSampleSize(16); - format.setSampleType(QAudioFormat::SignedInt); - for (int sampleRate : qAsConst(sampleRatesList)) { - if (foundSupportedFormat) - break; - format.setSampleRate(sampleRate); - for (int channels : qAsConst(channelsList)) { - format.setChannelCount(channels); - const bool inputSupport = m_generateTone || - m_audioInputDevice.isFormatSupported(format); - const bool outputSupport = m_audioOutputDevice.isFormatSupported(format); - ENGINE_DEBUG << "Engine::initialize checking " << format - << "input" << inputSupport - << "output" << outputSupport; - if (inputSupport && outputSupport) { - foundSupportedFormat = true; - break; - } - } - } + QAudioDeviceInfo::Range channelRange = m_audioInputDevice.supportedChannelCounts(); + QAudioDeviceInfo::Range outputChannelRange = m_audioOutputDevice.supportedChannelCounts(); + if (channelRange.minimum < outputChannelRange.minimum) + channelRange.minimum = outputChannelRange.minimum; + if (channelRange.maximum > outputChannelRange.maximum) + channelRange.maximum = outputChannelRange.maximum; - if (!foundSupportedFormat) - format = QAudioFormat(); + QAudioFormat format; + format.setSampleFormat(QAudioFormat::Int16); + format.setSampleRate(qBound(sampleRange.minimum, 48000, sampleRange.maximum)); + format.setChannelCount(qBound(channelRange.minimum, 2, channelRange.maximum)); setFormat(format); } @@ -728,9 +696,8 @@ void Engine::setFormat(const QAudioFormat &format) { const bool changed = (format != m_format); m_format = format; - m_levelBufferLength = audioLength(m_format, LevelWindowUs); - m_spectrumBufferLength = SpectrumLengthSamples * - (m_format.sampleSize() / 8) * m_format.channelCount(); + m_levelBufferLength = m_format.bytesForDuration(LevelWindowUs); + m_spectrumBufferLength = SpectrumLengthSamples * format.bytesPerFrame(); if (changed) emit formatChanged(m_format); } diff --git a/examples/multimedia/spectrum/app/spectrumanalyser.cpp b/examples/multimedia/spectrum/app/spectrumanalyser.cpp index d0d1d6cf5..848aac9d6 100644 --- a/examples/multimedia/spectrum/app/spectrumanalyser.cpp +++ b/examples/multimedia/spectrum/app/spectrumanalyser.cpp @@ -116,10 +116,10 @@ void SpectrumAnalyserThread::calculateWindow() void SpectrumAnalyserThread::calculateSpectrum(const QByteArray &buffer, int inputFrequency, - int bytesPerSample) + int bytesPerFrame) { #ifndef DISABLE_FFT - Q_ASSERT(buffer.size() == m_numSamples * bytesPerSample); + Q_ASSERT(buffer.size() == m_numSamples * bytesPerFrame); // Initialize data array const char *ptr = buffer.constData(); @@ -129,7 +129,7 @@ void SpectrumAnalyserThread::calculateSpectrum(const QByteArray &buffer, const DataType realSample = pcmToReal(pcmSample); const DataType windowedSample = realSample * m_window[i]; m_input[i] = windowedSample; - ptr += bytesPerSample; + ptr += bytesPerFrame; } // Calculate the FFT @@ -214,16 +214,16 @@ void SpectrumAnalyser::calculate(const QByteArray &buffer, << "state" << m_state; if (isReady()) { - Q_ASSERT(isPCMS16LE(format)); + Q_ASSERT(format.sampleFormat() == QAudioFormat::Int16); - const int bytesPerSample = format.sampleSize() * format.channelCount() / 8; + const int bytesPerFrame = format.bytesPerFrame(); #ifdef DUMP_SPECTRUMANALYSER m_count++; const QString pcmFileName = m_outputDir.filePath(QString("spectrum_%1.pcm").arg(m_count, 4, 10, QChar('0'))); QFile pcmFile(pcmFileName); pcmFile.open(QIODevice::WriteOnly); - const int bufferLength = m_numSamples * bytesPerSample; + const int bufferLength = m_numSamples * bytesPerFrame; pcmFile.write(buffer, bufferLength); m_textStream << "TimeDomain " << m_count << "\n"; @@ -245,7 +245,7 @@ void SpectrumAnalyser::calculate(const QByteArray &buffer, Qt::AutoConnection, Q_ARG(QByteArray, buffer), Q_ARG(int, format.sampleRate()), - Q_ARG(int, bytesPerSample)); + Q_ARG(int, bytesPerFrame)); Q_ASSERT(b); Q_UNUSED(b); // suppress warnings in release builds diff --git a/examples/multimedia/spectrum/app/tonegenerator.cpp b/examples/multimedia/spectrum/app/tonegenerator.cpp index 2e549ab4f..3e70180fd 100644 --- a/examples/multimedia/spectrum/app/tonegenerator.cpp +++ b/examples/multimedia/spectrum/app/tonegenerator.cpp @@ -57,9 +57,9 @@ void generateTone(const SweptTone &tone, const QAudioFormat &format, QByteArray &buffer) { - Q_ASSERT(isPCMS16LE(format)); + Q_ASSERT(format.sampleFormat() == QAudioFormat::Int16); - const int channelBytes = format.sampleSize() / 8; + const int channelBytes = format.bytesPerSample(); const int sampleBytes = format.channelCount() * channelBytes; int length = buffer.size(); const int numSamples = buffer.size() / sampleBytes; diff --git a/examples/multimedia/spectrum/app/utils.cpp b/examples/multimedia/spectrum/app/utils.cpp index 7e635b509..2a6b2a33e 100644 --- a/examples/multimedia/spectrum/app/utils.cpp +++ b/examples/multimedia/spectrum/app/utils.cpp @@ -51,20 +51,6 @@ #include <QAudioFormat> #include "utils.h" -qint64 audioDuration(const QAudioFormat &format, qint64 bytes) -{ - return (bytes * 1000000) / - (format.sampleRate() * format.channelCount() * (format.sampleSize() / 8)); -} - -qint64 audioLength(const QAudioFormat &format, qint64 microSeconds) -{ - qint64 result = (format.sampleRate() * format.channelCount() * (format.sampleSize() / 8)) - * microSeconds / 1000000; - result -= result % (format.channelCount() * format.sampleSize()); - return result; -} - qreal nyquistFrequency(const QAudioFormat &format) { return format.sampleRate() / 2; @@ -75,24 +61,23 @@ QString formatToString(const QAudioFormat &format) QString result; if (QAudioFormat() != format) { - Q_ASSERT(format.sampleType() == QAudioFormat::SignedInt); - - const QString formatEndian = (format.byteOrder() == QAudioFormat::LittleEndian) - ? QString("LE") : QString("BE"); QString formatType; - switch (format.sampleType()) { - case QAudioFormat::SignedInt: - formatType = "signed"; + switch (format.sampleFormat()) { + case QAudioFormat::UInt8: + formatType = "Unsigned8"; + break; + case QAudioFormat::Int16: + formatType = "Signed16"; break; - case QAudioFormat::UnSignedInt: - formatType = "unsigned"; + case QAudioFormat::Int32: + formatType = "Signed32"; break; case QAudioFormat::Float: - formatType = "float"; + formatType = "Float"; break; - case QAudioFormat::Unknown: - formatType = "unknown"; + default: + formatType = "Unknown"; break; } @@ -106,24 +91,16 @@ QString formatToString(const QAudioFormat &format) break; } - result = QString("%1 Hz %2 bit %3 %4 %5") + result = QString("%1 Hz %2 bit %3 %4") .arg(format.sampleRate()) - .arg(format.sampleSize()) + .arg(format.bytesPerSample() * 8) .arg(formatType) - .arg(formatEndian) .arg(formatChannels); } return result; } -bool isPCMS16LE(const QAudioFormat &format) -{ - return format.sampleType() == QAudioFormat::SignedInt && - format.sampleSize() == 16 && - format.byteOrder() == QAudioFormat::LittleEndian; -} - const qint16 PCMS16MaxValue = 32767; const quint16 PCMS16MaxAmplitude = 32768; // because minimum is -32768 diff --git a/examples/multimedia/spectrum/app/utils.h b/examples/multimedia/spectrum/app/utils.h index cd6357182..d143a83f7 100644 --- a/examples/multimedia/spectrum/app/utils.h +++ b/examples/multimedia/spectrum/app/utils.h @@ -60,9 +60,6 @@ QT_FORWARD_DECLARE_CLASS(QAudioFormat) // Miscellaneous utility functions //----------------------------------------------------------------------------- -qint64 audioDuration(const QAudioFormat &format, qint64 bytes); -qint64 audioLength(const QAudioFormat &format, qint64 microSeconds); - QString formatToString(const QAudioFormat &format); qreal nyquistFrequency(const QAudioFormat &format); @@ -73,12 +70,6 @@ qreal pcmToReal(qint16 pcm); // Scale real value in [-1.0, 1.0] to PCM qint16 realToPcm(qreal real); -// Check whether the audio format is PCM -bool isPCM(const QAudioFormat &format); - -// Check whether the audio format is signed, little-endian, 16-bit PCM -bool isPCMS16LE(const QAudioFormat &format); - // Compile-time calculation of powers of two template<int N> class PowerOfTwo diff --git a/examples/multimedia/spectrum/app/waveform.cpp b/examples/multimedia/spectrum/app/waveform.cpp index 7dbd6057f..5f9563a8d 100644 --- a/examples/multimedia/spectrum/app/waveform.cpp +++ b/examples/multimedia/spectrum/app/waveform.cpp @@ -172,7 +172,7 @@ void Waveform::initialize(const QAudioFormat &format, qint64 audioBufferSize, qi m_tileLength = audioBufferSize; // Calculate window size - m_windowLength = audioLength(m_format, windowDurationUs); + m_windowLength = m_format.bytesForDuration(windowDurationUs); // Calculate number of tiles required int nTiles; diff --git a/examples/multimedia/spectrum/app/wavfile.cpp b/examples/multimedia/spectrum/app/wavfile.cpp index bd545d701..609ec94f0 100644 --- a/examples/multimedia/spectrum/app/wavfile.cpp +++ b/examples/multimedia/spectrum/app/wavfile.cpp @@ -138,16 +138,28 @@ bool WavFile::readHeader() return false; // Establish format - if (memcmp(&header.riff.descriptor.id, "RIFF", 4) == 0) - m_fileFormat.setByteOrder(QAudioFormat::LittleEndian); - else - m_fileFormat.setByteOrder(QAudioFormat::BigEndian); + // ### do byte swapping for RIFX +// if (memcmp(&header.riff.descriptor.id, "RIFF", 4) == 0) +// m_fileFormat.setByteOrder(QAudioFormat::LittleEndian); +// else +// m_fileFormat.setByteOrder(QAudioFormat::BigEndian); - int bps = qFromLittleEndian<quint16>(header.wave.bitsPerSample); m_fileFormat.setChannelCount(qFromLittleEndian<quint16>(header.wave.numChannels)); m_fileFormat.setSampleRate(qFromLittleEndian<quint32>(header.wave.sampleRate)); - m_fileFormat.setSampleSize(qFromLittleEndian<quint16>(header.wave.bitsPerSample)); - m_fileFormat.setSampleType(bps == 8 ? QAudioFormat::UnSignedInt : QAudioFormat::SignedInt); + switch(header.wave.bitsPerSample) { + case 8: + m_fileFormat.setSampleFormat(QAudioFormat::UInt8); + break; + case 16: + m_fileFormat.setSampleFormat(QAudioFormat::Int16); + break; + case 24: + m_fileFormat.setSampleFormat(QAudioFormat::Unknown); + break; + case 32: + m_fileFormat.setSampleFormat(QAudioFormat::Int32); + break; + } } else { result = false; } diff --git a/examples/multimediawidgets/player/histogramwidget.cpp b/examples/multimediawidgets/player/histogramwidget.cpp index 928d6816e..cdf4b62b2 100644 --- a/examples/multimediawidgets/player/histogramwidget.cpp +++ b/examples/multimediawidgets/player/histogramwidget.cpp @@ -52,9 +52,6 @@ #include <QPainter> #include <QHBoxLayout> -template<class T> -static QList<qreal> getBufferLevels(const T *buffer, int frames, int channels); - class QAudioLevel : public QWidget { Q_OBJECT @@ -124,41 +121,6 @@ void HistogramWidget::processFrame(const QVideoFrame &frame) Qt::QueuedConnection, Q_ARG(QVideoFrame, frame), Q_ARG(int, m_levels)); } -// This function returns the maximum possible sample value for a given audio format -qreal getPeakValue(const QAudioFormat& format) -{ - // Note: Only the most common sample formats are supported - if (!format.isValid()) - return qreal(0); - - switch (format.sampleType()) { - case QAudioFormat::Unknown: - break; - case QAudioFormat::Float: - if (format.sampleSize() != 32) // other sample formats are not supported - return qreal(0); - return qreal(1.00003); - case QAudioFormat::SignedInt: - if (format.sampleSize() == 32) - return qreal(INT_MAX); - if (format.sampleSize() == 16) - return qreal(SHRT_MAX); - if (format.sampleSize() == 8) - return qreal(CHAR_MAX); - break; - case QAudioFormat::UnSignedInt: - if (format.sampleSize() == 32) - return qreal(UINT_MAX); - if (format.sampleSize() == 16) - return qreal(USHRT_MAX); - if (format.sampleSize() == 8) - return qreal(UCHAR_MAX); - break; - } - - return qreal(0); -} - // returns the audio level for each channel QList<qreal> getBufferLevels(const QAudioBuffer &buffer) { @@ -167,64 +129,27 @@ QList<qreal> getBufferLevels(const QAudioBuffer &buffer) if (!buffer.isValid()) return values; - if (!buffer.format().isValid() || buffer.format().byteOrder() != QAudioFormat::LittleEndian) + if (!buffer.format().isValid()) return values; - int channelCount = buffer.format().channelCount(); - values.fill(0, channelCount); - qreal peak_value = getPeakValue(buffer.format()); - if (qFuzzyCompare(peak_value, qreal(0))) - return values; + auto format = buffer.format(); + int channelCount = format.channelCount(); + int bytesPerSample = format.bytesPerFrame(); + int frames = buffer.frameCount(); - switch (buffer.format().sampleType()) { - case QAudioFormat::Unknown: - case QAudioFormat::UnSignedInt: - if (buffer.format().sampleSize() == 32) - values = getBufferLevels(buffer.constData<quint32>(), buffer.frameCount(), channelCount); - if (buffer.format().sampleSize() == 16) - values = getBufferLevels(buffer.constData<quint16>(), buffer.frameCount(), channelCount); - if (buffer.format().sampleSize() == 8) - values = getBufferLevels(buffer.constData<quint8>(), buffer.frameCount(), channelCount); - for (double &value : values) - value = qAbs(value - peak_value / 2) / (peak_value / 2); - break; - case QAudioFormat::Float: - if (buffer.format().sampleSize() == 32) { - values = getBufferLevels(buffer.constData<float>(), buffer.frameCount(), channelCount); - for (double &value : values) - value /= peak_value; - } - break; - case QAudioFormat::SignedInt: - if (buffer.format().sampleSize() == 32) - values = getBufferLevels(buffer.constData<qint32>(), buffer.frameCount(), channelCount); - if (buffer.format().sampleSize() == 16) - values = getBufferLevels(buffer.constData<qint16>(), buffer.frameCount(), channelCount); - if (buffer.format().sampleSize() == 8) - values = getBufferLevels(buffer.constData<qint8>(), buffer.frameCount(), channelCount); - for (double &value : values) - value /= peak_value; - break; - } - - return values; -} - -template<class T> -QList<qreal> getBufferLevels(const T *buffer, int frames, int channels) -{ - QList<qreal> max_values; - max_values.fill(0, channels); + values.fill(0, channelCount); + const char *data = buffer.constData<char>(); for (int i = 0; i < frames; ++i) { - for (int j = 0; j < channels; ++j) { - qreal value = qAbs(qreal(buffer[i * channels + j])); - if (value > max_values.at(j)) - max_values.replace(j, value); + for (int j = 0; j < channelCount; ++j) { + qreal value = format.normalizedSampleValue(data); + if (value > values.at(j)) + values[j] = value; + data += bytesPerSample; } } - return max_values; + return values; } void HistogramWidget::processBuffer(const QAudioBuffer &buffer) |