出于某种奇怪的原因QAudioRecorder::audioInputs()
返回的实际设备数量是我实际拥有的设备的两倍
它们似乎是重复但不是真的 - 看起来它们提供不同的样本,因为当我尝试播放前两个设备录制的音频时,它听起来快两倍,而后两个设备听起来正常。
继承我的代码:
#include "MicrophoneWidget.h"
#include <QLayout>
#include <sndfile.h>
MicrophoneWidget::MicrophoneWidget(QWidget *parent) : QWidget(parent)
{
QAudioEncoderSettings settings;
settings.setCodec("audio/PCM");
settings.setQuality(QMultimedia::HighQuality);
settings.setChannelCount(1);
recorder = new QAudioRecorder(this);
recorder->setEncodingSettings(settings);
button = new QPushButton();
button->setCheckable(true);
devicesBox = new QComboBox();
connect(devicesBox, SIGNAL(currentIndexChanged(int)), this, SLOT(onDeviceChanged(int)));
for(const QString& device : recorder->audioInputs()) devicesBox->addItem(device, QVariant(device));
label = new QLabel();
connect(button, SIGNAL(toggled(bool)), this, SLOT(onButtonToggled(bool)));
QVBoxLayout* layout = new QVBoxLayout();
layout->addWidget(devicesBox);
layout->addWidget(button);
layout->addWidget(label);
setLayout(layout);
probe = new QAudioProbe();
probe->setSource(recorder);
connect(probe, SIGNAL(audioBufferProbed(QAudioBuffer)), this, SLOT(onAudioBufferProbed(QAudioBuffer)));
}
void MicrophoneWidget::resizeEvent(QResizeEvent*)
{
pixmap = QPixmap(label->size());
}
void MicrophoneWidget::onAudioBufferProbed(QAudioBuffer buffer)
{
qDebug() << buffer.byteCount() / buffer.sampleCount();
const qint32 *data = buffer.constData<qint32>();
pixmap.fill(Qt::transparent);
painter.begin(&pixmap);
int count = buffer.sampleCount() / 2;
float xScale = (float)label->width() / count;
float center = (float)label->height() / 2;
for(int i = 0; i < count; i++) samples.push_back(data[i]);
for(int i = 1; i < count; i++)
{
painter.drawLine(
(i - 1) * xScale,
center + ((float)(data[i-1]) / INT_MAX * center),
i * xScale,
center + ((float)(data[i]) / INT_MAX * center)
);
}
painter.end();
label->setPixmap(pixmap);
}
void MicrophoneWidget::onButtonToggled(bool toggled)
{
if(toggled)
{
samples.clear();
recorder->record();
}
else
{
recorder->stop();
SF_INFO sndFileInfo;
sndFileInfo.channels = 1;
sndFileInfo.samplerate = 44100;
sndFileInfo.format = SF_FORMAT_WAV | SF_FORMAT_PCM_32;
QString filePath = "customWAV-" + QString::number(QDateTime::currentMSecsSinceEpoch()) + ".wav";
SNDFILE* sndFile = sf_open(filePath.toStdString().c_str(), SFM_WRITE, &sndFileInfo);
if(sndFile != nullptr)
{
sf_count_t count = sf_write_int(sndFile, samples.data(), samples.size());
qDebug() << "Written " << count << " items; " << (samples.size() / sndFileInfo.samplerate) << " seconds";
}
sf_close(sndFile);
}
}
void MicrophoneWidget::onDeviceChanged(int index)
{
recorder->stop();
recorder->setAudioInput(devicesBox->itemData(index).toString());
if(button->isChecked())recorder->record();
}
那么,我应该如何解析原始数据以绘制正确的波形?
答案 0 :(得分:0)
首先检查缓冲区是否具有您期望的样本类型,然后检查QAudioFormat sampleType函数。有3种选择:
QAudioFormat::SignedInt,
QAudioFormat::UnSignedInt,
QAudioFormat::Float
这可以帮助您确定给定样本的正确演员表。就我而言,作为不同的Qt示例,我使用:
const qint16 *data = buffer.data<qint16>();
他们可以使用此功能轻松地将其标准化:
qreal getPeakValue(const QAudioFormat& format)
{
// Note: Only the most common sample formats are supported
if (!format.isValid())
return qreal(0);
if (format.codec() != "audio/pcm")
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)
#ifdef Q_OS_WIN
return qreal(INT_MAX);
#endif
#ifdef Q_OS_UNIX
return qreal(SHRT_MAX);
#endif
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);
}
现在你应该迭代向量并除以函数返回的峰值,这将给出[-1,1]中的一系列样本,所以将它保存在QVector数组中以绘制它。
为了绘制它,你有不同的选择,Qt介绍他自己的QtCharts模块,但你仍然可以使用QCustomPlot或Qwt。 QCustomPlot的一个例子:
QCPGraph myPlot = ui->chart->addGraph();
myPlot->setData(xAxys.data(), recorded.data()); // init an X vector from 0 to the size of Y or whatever you want
ui->chart->yAxis->setRange(QCPRange(-1,1)); // set the range
ui->chart->replot();
您可以在Qt示例中找到完整的示例或查看我的小GitHub项目LogoSpeech Studio,您将找到如何绘制波形,频谱图,音高和信号的不同属性的完整示例。 / p>