Вы можете использовать QAudioDecoder . Вы должны создать декодер и вызвать setSourceFileName . Затем позвоните start . Подключите bufferReady () к вашему слоту, затем read () буфер и делайте все до конца. Вы также можете объединить полученные фрагменты в QByteArray и воссоздать один QAudioBuffer для всего аудио. Затем вы можете нарезать буфер и получить значение выбора для желаемой длительности на основе вычисленных байтов в секунду.
Вот краткая реализация, которая по умолчанию задает продолжительность кадрами, полученными QAudioDecoder . Таким образом, в этом коде отсутствует механизм рефрейминга. Эти три метода (getBufferLevels
как две перегрузки и getPeakValue
) скопированы из Пример аудиозаписи из Qt и Я не включаю их здесь
//waveformgenerator.h
#ifndef WAVEFORMGENERATOR_H
#define WAVEFORMGENERATOR_H
#include <QObject>
#include <QAudioDecoder>
#include <QFile>
#include <QBuffer>
class WaveformGenerator : public QObject
{
Q_OBJECT
public:
explicit WaveformGenerator(QObject *parent = nullptr);
template<class T>
static QVector<qreal> getBufferLevels(const T *buffer, int frames, int channels);
static QVector<qreal> getBufferLevels(const QAudioBuffer &buffer);
static qreal getPeakValue(const QAudioFormat &format);
private:
QAudioDecoder m_decoder;
QFile file;
QVector<QVector<qreal>> bufferLevels;
signals:
void bufferLevelsReady(QVector<QVector<qreal>> bufferLevels);
public slots:
void start(const QString& filepath);
private slots:
void bufferReady();
void sendBufferLevels();
void handleError(QAudioDecoder::Error error);
};
#endif // WAVEFORMGENERATOR_H
//waveformgenerator.cpp
#include "waveformgenerator.h"
WaveformGenerator::WaveformGenerator(QObject *parent) : QObject(parent){
connect(&m_decoder,&QAudioDecoder::bufferReady,this,&WaveformGenerator::bufferReady);
connect(&m_decoder,&QAudioDecoder::finished,this,&WaveformGenerator::sendBufferLevels);
connect(&m_decoder, QOverload<QAudioDecoder::Error>::of(&QAudioDecoder::error),this,&WaveformGenerator::handleError);
}
void WaveformGenerator::start(const QString &filepath){
if (m_decoder.state()==QAudioDecoder::DecodingState)
m_decoder.stop();
bufferLevels.clear();
file.setFileName(filepath);
if (file.open(QFile::ReadOnly)){
m_decoder.setSourceDevice(&file);
m_decoder.start();
}
else
{
//TODO: handle this error where file could not be opened
}
}
void WaveformGenerator::bufferReady(){
auto current_buff = m_decoder.read();
auto current_buff_level = getBufferLevels(current_buff);
bufferLevels.append(current_buff_level);
}
void WaveformGenerator::sendBufferLevels(){
file.close();
emit bufferLevelsReady(bufferLevels);
//Will emit a QVector of QVectors which every inner QVector
//has two values for each channel from 0~1.0 as level
//these pairs of values are generate for each frame
//you can do your stuff like drawing by connecting an appropriate
//slots to bufferLevelsReady signal
}
void WaveformGenerator::handleError(QAudioDecoder::Error error)
{
if(error!=QAudioDecoder::NoError){
file.close();
bufferLevels.clear();
}
}
//using
auto waveformView = new WaveformView (); // your fancy waveform view
auto wfg = new WaveFormGenerate();
//TODO: connect bufferLevelsReady signal to the object to draw those data
wfg.start(":/sample.mp3");