Qt文档阅读笔记-Audio Example解析

Posted IT1995

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Qt文档阅读笔记-Audio Example解析相关的知识,希望对你有一定的参考价值。

这个例子很有意思,今天分析了下,在此记录下笔记,方便下次查阅。

这个例子展示了画动态数据(麦克风输入的数据)

界面如下:

关键文件如下:

这里官方给出的解释就没了,后面我自己补充下。

首先要学习两个类,分别是:QAudioInput和QAudioFormat

具体可以查本人的这篇博文-Qt文档阅读笔记-QAudioInput&QAudioFormat解析与实例。

首先在main.cpp中的关键代码:

const QAudioDeviceInfo inputDevice = QAudioDeviceInfo::defaultInputDevice();
if (inputDevice.isNull()) 
    QMessageBox::warning(nullptr, "audio",
                         "There is no audio input device available.");
    return -1;

这里查询了当前系统中是否设置了麦克风,如果没有,就直接退出了。

在Widget.cpp中配置了QAudioFormat相关属性,如下:

QAudioFormat formatAudio;
formatAudio.setSampleRate(8000);
formatAudio.setChannelCount(1);
formatAudio.setSampleSize(8);
formatAudio.setCodec("audio/pcm");
formatAudio.setByteOrder(QAudioFormat::LittleEndian);
formatAudio.setSampleType(QAudioFormat::UnSignedInt);

 

参数描述
Sample Rate每秒音频的Hertz
Number of channels单声道还是双声道
Sample size数据按8位存还是16位存
Sample type存储的类型是int还是unsigned int还是float
Byte order存成大端还是小端

最后说下最有意思的类XYSeriesIODevice。对应的

xyseriesiodevice.h:

#ifndef XYSERIESIODEVICE_H
#define XYSERIESIODEVICE_H

#include <QtCore/QIODevice>
#include <QtCore/QPointF>
#include <QtCore/QVector>
#include <QtCharts/QChartGlobal>

QT_CHARTS_BEGIN_NAMESPACE
class QXYSeries;
QT_CHARTS_END_NAMESPACE

QT_CHARTS_USE_NAMESPACE

class XYSeriesIODevice : public QIODevice

    Q_OBJECT
public:
    explicit XYSeriesIODevice(QXYSeries *series, QObject *parent = nullptr);

    static const int sampleCount = 2000;

protected:
    qint64 readData(char *data, qint64 maxSize) override;
    qint64 writeData(const char *data, qint64 maxSize) override;

private:
    QXYSeries *m_series;
    QVector<QPointF> m_buffer;
;

#endif // XYSERIESIODEVICE_H

xyseriesiodevice.cpp:

#include "xyseriesiodevice.h"

#include <QtCharts/QXYSeries>
#include <QDebug>

XYSeriesIODevice::XYSeriesIODevice(QXYSeries *series, QObject *parent) :
    QIODevice(parent),
    m_series(series)



qint64 XYSeriesIODevice::readData(char *data, qint64 maxSize)

    Q_UNUSED(data)
    Q_UNUSED(maxSize)
    return -1;


qint64 XYSeriesIODevice::writeData(const char *data, qint64 maxSize)

    static const int resolution = 4;
    if (m_buffer.isEmpty()) 
        m_buffer.reserve(sampleCount);
        for (int i = 0; i < sampleCount; ++i)
            m_buffer.append(QPointF(i, 0));
    

    int start = 0;
    const int availableSamples = int(maxSize) / resolution;

    if (availableSamples < sampleCount) 
        start = sampleCount - availableSamples;
        for (int s = 0; s < start; ++s)
            m_buffer[s].setY(m_buffer.at(s + availableSamples).y());
    

    for (int s = start; s < sampleCount; ++s, data += resolution)
        m_buffer[s].setY(qreal(uchar(*data) - 128) / qreal(128));

    m_series->replace(m_buffer);
    return (sampleCount - start) * resolution;

 这里最关键的代码是这个:

qint64 XYSeriesIODevice::writeData(const char *data, qint64 maxSize)

    static const int resolution = 4;
    if (m_buffer.isEmpty()) 
        m_buffer.reserve(sampleCount);
        for (int i = 0; i < sampleCount; ++i)
            m_buffer.append(QPointF(i, 0));
    

    int start = 0;
    const int availableSamples = int(maxSize) / resolution;

    if (availableSamples < sampleCount) 
        start = sampleCount - availableSamples;
        for (int s = 0; s < start; ++s)
            m_buffer[s].setY(m_buffer.at(s + availableSamples).y());
    

    for (int s = start; s < sampleCount; ++s, data += resolution)
        m_buffer[s].setY(qreal(uchar(*data) - 128) / qreal(128));

    m_series->replace(m_buffer);
    return (sampleCount - start) * resolution;

整个曲线x轴长度是:

static const int sampleCount = 2000;

y轴长度:

axisY->setRange(-1, 1);

音频大小是:

formatAudio.setSampleType(QAudioFormat::UnSignedInt);

这个函数data每次会传320个字节过来,换成UnsignedInt就是80个UnsignedInt。

下面这一段是对x轴数据都初始化:

if (m_buffer.isEmpty()) 
    m_buffer.reserve(sampleCount);
    for (int i = 0; i < sampleCount; ++i)
        m_buffer.append(QPointF(i, 0));

下面是将数据网x轴左方向移动1920个坐标:

if (availableSamples < sampleCount) 
    start = sampleCount - availableSamples;
    for (int s = 0; s < start; ++s)
        m_buffer[s].setY(m_buffer.at(s + availableSamples).y());

将刚刚采集的音频放到最后80坐标里面(1920~2000)

for (int s = start; s < sampleCount; ++s, data += resolution)
    m_buffer[s].setY(qreal(uchar(*data) - 128) / qreal(128));

这里-128是为了使得y轴有负数,除以128是因为。

axisY->setRange(-1, 1);

Y轴坐标是-1,到1之间。

以上是关于Qt文档阅读笔记-Audio Example解析的主要内容,如果未能解决你的问题,请参考以下文章

Qt文档阅读笔记-Simple Chat Example解析

Qt文档阅读笔记-Broadcast Sender Example解析

Qt文档阅读笔记-QtConcurrent Progress Dialog Example解析

Qt文档阅读笔记-Broadcast Receiver Example解析

Qt文档阅读笔记-Threaded Fortune Server Example解析

Qt文档阅读笔记-Simple Anchor Layout Example解析