qt quick(qml)实现8bit和16bit的pcm的音频波形
网上看了一些别人实现音频波形绘制的例子,关于qt qml的较少,16bit pcm的也少,所以写此文章记录一下,代码是基于他人的代码进行修改的,并非完全原创,特此声明。
效果图:
//DataSource.h
#ifndef DATASOURCE_H
#define DATASOURCE_H
#include <QtCore/QObject>
#include <QtCharts/QAbstractSeries>
#include <QtCharts/QXYSeries>
#include <QtCore/QIODevice>
QT_BEGIN_NAMESPACE
class QQuickView;
QT_END_NAMESPACE
QT_CHARTS_USE_NAMESPACE
class DataSource : public QObject
{
Q_OBJECT
public:
explicit DataSource(QObject *parent = 0);
Q_INVOKABLE void setSeries(QAbstractSeries *series);
public slots:
void append(const QByteArray &audioData);
protected:
qint64 readData(char *data, qint64 maxSize);
qint64 writeData_8bit(const char *data, qint64 maxSize);
qint64 writeData_16bit(const char *data, qint64 maxSize);
private:
QXYSeries *m_series;
};
#endif // DATASOURCE_H
//DataSource.cpp
#include "DataSource.h"
#include <QtCharts/QXYSeries>
#include <QtCharts/QAreaSeries>
#include <QtQuick/QQuickItem>
#include <QtCore/QDebug>
#include <QtCore/QtMath>
#include <QTime>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
QT_CHARTS_USE_NAMESPACE
Q_DECLARE_METATYPE(QAbstractSeries *)
Q_DECLARE_METATYPE(QAbstractAxis *)
DataSource::DataSource( QObject *parent)
{
qRegisterMetaType<QAbstractSeries *>();
qRegisterMetaType<QAbstractAxis *>();
}
qint64 DataSource::readData(char *data, qint64 maxSize)
{
Q_UNUSED(data)
Q_UNUSED(maxSize)
return -1;
}
qint64 DataSource::writeData_8bit(const char *data, qint64 maxSize)
{
if (m_series)
{
qint64 range = 2000;
QVector<QPointF> oldPoints = m_series->pointsVector();
QVector<QPointF> points;
int resolution = 4;//每4个取1个数
if (oldPoints.count() < range)
{
points = m_series->pointsVector();
}
else
{
for (int i = maxSize / resolution; i < oldPoints.count(); i++)
points.append(QPointF(i - maxSize / resolution, oldPoints.at(i).y()));
}
qint64 size = points.count();
for (int k = 0; k < maxSize / resolution; k++)
points.append(QPointF(k + size, ((quint8)data[resolution * k] - 128) / 128.0));
m_series->replace(points);
}
return maxSize;
}
qint64 DataSource::writeData_16bit(const char *srcdata, qint64 len)
{
int maxSize = len / 2;
short *data = (short *)srcdata;
if (m_series)
{
qint64 range = 2000;//和界面保持 一致
QVector<QPointF> oldPoints = m_series->pointsVector();
QVector<QPointF> points;
int resolution = 4;//每4个取1个数
if (oldPoints.count() < range)
{
//m_series序列的数据未满2000点,
points = m_series->pointsVector();
}
else
{
//将原来maxSize至4000的数据点前移,
for (int i = maxSize / resolution; i < oldPoints.count(); i++)
points.append(QPointF(i - maxSize / resolution, oldPoints.at(i).y()));
}
qint64 size = points.count();
for (int k = 0; k < maxSize / resolution; k++) //数据块内的数据填充序列的尾部
{
// qDebug("%d\n", (quint8)data[resolution * k]);
points.append(QPointF(k + size, (data[resolution * k]) / 32768.0));
}
m_series->replace(points);//最快的方式
}
return maxSize;
}
void DataSource::setSeries(QAbstractSeries *series)
{
m_series = static_cast<QXYSeries *>(series);
}
void DataSource::append(const QByteArray &audioData)
{
// writeData_8bit(audioData.data(), audioData.size());
writeData_16bit(audioData.data(), audioData.size());
}
//main.qml
import QtQuick 2.12
import QtQuick.Window 2.12
import QtCharts 2.3
Item {
visible: true
width: 640
height: 480
ChartView{
id:chartView
animationOptions: chartView.NoAnimation
theme: chartView.ChartThemeBlueIcy
property bool openGL: true
property bool openGLSupported: true
anchors.fill: parent
Component.onCompleted: {
dataSource.setSeries(chartView.series(0));
}
Component.onDestruction: {
dataSource.setSeries(0);
}
ValueAxis{
id:axisY1
min: -1
max: 1
}
ValueAxis{
id:axisX
min: 0
max: 2000
}
LineSeries{
id: lineSeries
name: "Audio Sample"
axisX: axisX
axisY: axisY1
useOpenGL: chartView.openGL
}
}
}