【发布时间】:2018-10-20 23:23:01
【问题描述】:
我必须管理电影和音频文件,并且我需要像 audacity 那样渲染声音的波形。但我只是找到了实时渲染的例子。
我想在不播放的情况下渲染所有文件。
预期结果:
我的实际结果:
使用 Qt,我尝试使用QAudioDecoder 打开我的文件并获得QAudioBuffer,但我没有找到将所有数据转换为波形的算法。我也尝试使用Qt Spectrum Example 进行查看,但这并不容易理解,而且它仍然是实时的。
我的track.h:
#ifndef TRACK_H
#define TRACK_H
#include <QWidget>
#include <QAudioBuffer>
class QAudioDecoder;
class Track : public QWidget
{
Q_OBJECT
public:
Track(QWidget *parent = Q_NULLPTR);
~Track();
void setSource(const QString &fileName);
public slots:
void setBuffer();
protected:
void paintEvent(QPaintEvent *e) override;
private:
int pointDistance(const QPoint& a, const QPoint& b);
QAudioDecoder *decoder;
QAudioBuffer buffer;
QByteArray byteArr;
};
#endif // TRACK_H
我的track.cpp:
#include "track.h"
#include <QPaintEvent>
#include <QPainter>
#include <QAudioDecoder>
Track::Track(QWidget *parent)
: QWidget(parent)
, decoder(new QAudioDecoder(this))
{
setMinimumHeight(50);
connect(decoder, SIGNAL(bufferReady()), this, SLOT(setBuffer()));
connect(decoder, SIGNAL(finished()), this, SLOT(update()));
}
Track::~Track()
{
delete decoder;
}
void Track::setSource(const QString &fileName)
{
byteArr.clear();
decoder->setSourceFilename(fileName);
decoder->start();
}
void Track::setBuffer()
{
buffer = decoder->read();
byteArr.append(buffer.constData<char>(), buffer.byteCount());
}
void Track::paintEvent(QPaintEvent *e)
{
QWidget::paintEvent(e);
int w = width(), h = height();
QBrush backgroundBrush(Qt::white);
QPainter painter(this);
painter.fillRect(0, 0, w, h, backgroundBrush);
painter.drawLine(0, h/2, w, h/2);
if (!byteArr.isEmpty()){
QPen pen(QColor(Qt::blue));
painter.setPen(pen);
int length = byteArr.size();
int samplesPerPixel = length/w;
int idx=0;
for (int i=0; i<w; i++){
QLine line;
int higher = 0;
for (int j=0; j<samplesPerPixel && idx+1<length; j++){
const QPoint a(i, byteArr.at(idx)+(h/2));
const QPoint b(i, byteArr.at(idx+1)+(h/2));
if (higher < pointDistance(a, b))
line = QLine(a, b);
idx++;
}
painter.drawLine(line);
}
}
}
int Track::pointDistance(const QPoint &a, const QPoint &b)
{
int ret = 0;
ret = sqrt(pow(b.x()-a.x(), 2) + pow(b.y()-a.y(), 2));
return ret;
}
【问题讨论】:
-
您不是在看波/光谱。您正在查看(平均)幅度。与
audiobuffer.data()成员中的数据相同。 -
@CaptainGiraffe,谢谢,这是我第一次处理声音处理,我的词汇量不好。目的是获取第一个数据并绘制一条线到下一个直到结束?
-
想象数据成员中的每个值对应于 X 轴上一条垂直线的高度。然后你只需要压缩/平均它以使它在窗口中看起来不错。所以是的,前几个数据值构成了第一条垂直线。
-
@CaptainGiraffe,所以如果我很好理解,如果我有 500 个数据要放置在 100px 的小部件中,我必须在 100px 的每个数据下画一条线?
-
是的,差不多。每个像素 5 个数据值。尝试平均和着色,你应该没问题。
标签: c++ qt waveform audio-processing