gpt4 book ai didi

c++ - 使用QtAudioOutput处理大型QByteArray会导致std::bad_alloc

转载 作者:行者123 更新时间:2023-12-03 01:37:01 27 4
gpt4 key购买 nike

使用QAudioOut我试图按顺序播放存储在QByteArray中的数据...这在追加少量数据时起作用,但是当数据过多时,可以说是2到3个小时的RAW PCM从不同组合追加由于堆的大小不足以同时保存所有数据,因此一次将所有数据都转换为QByteArray会导致生成std::bad_alloc

我知道问题出在哪里,我想我有一个可能的解决方案,只是我不知道如何实现它。

下面是一个转换后的函数,它采用列表中的值
第一个440Hz,持续1800000毫秒,并创建了RAW PCM方波。然后工作,将其附加到QByteArray上,然后播放它。

如果没有来自多个已添加序列的大量附加数据,这将起作用。

我正在寻找一种方法,可以一次从列表中进行一次操作,然后创建wave,将其播放x毫秒,然后转到MySeq列表中的下一个条目。该列表可以包含连续3小时的3分钟频率的大型序列。

QStringList MySeq;

MySeq << "1:440:180000";
MySeq << "1:20:180000";
MySeq << "1:2120:180000";
MySeq << "1:240:180000";
MySeq << "1:570:180000";

foreach(QString seq, MySeq)
{
QStringList Assits = seq.split(":");

qDebug() << "Now At: " << seq;

QString A = Assits.at(0);
QString B = Assits.at(1);
QString C = Assits.at(2);

qreal amplitude = A.toInt();
float frequency = B.toFloat();
int msecs = C.toInt();

qreal singleWaveTime = amplitude / frequency;

qreal samplesPerWave = qCeil(format->sampleRate() * singleWaveTime);

quint32 waveCount = qCeil(msecs / (singleWaveTime * 1000.0));

quint32 sampleSize = static_cast<quint32>(format->sampleSize() / 8.0);

QByteArray data(waveCount * samplesPerWave * sampleSize * format->channelCount(), '\0');

unsigned char* dataPointer = reinterpret_cast<unsigned char*>(data.data());

for (quint32 currentWave = 0; currentWave < waveCount; currentWave++)
{
for (int currentSample = 0; currentSample < samplesPerWave; currentSample++)
{
double nextRadStep = (currentSample / static_cast<double>(samplesPerWave)) * (2 * M_PI);

quint16 sampleValue = static_cast<quint16>((qSin(nextRadStep) > 0 ? 1 : -1) * 32767);

for (int channel = 0; channel < format->channelCount(); channel++)
{
qToLittleEndian(sampleValue, dataPointer);
dataPointer += sampleSize;
}
}
}

soundBuffer->append(data); // HERE IS THE Std::Bad_Alloc
output->start(outputBuffer);
qDebug() << data.size()
}

我希望一次只用一个序列填充 QByteArray,然后用 QAudioOutput播放它,然后清除 ByteArray,然后加载下一个序列重复,直到在 QStringList中完成所有序列。

现在这种方法的问题是 QAudioOutput是异步的,并且不等待第一个序列完成
如果我如上所述循环遍历列表,则它们会依次加载,并且只播放最后一个实际播放的频率。就像循环一样,继续覆盖之前的序列。

我不确定这里是否需要 QEventLoop(我还没有使用过的东西)或线程。我尝试了几种不同的方法,但均未成功。任何建议将不胜感激。这是我对以下有关波形文件,数据和频率生成的以下问题的延续
Qt C++ Creating a square audio tone wave. Play and saving it

mainWindows.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QtCore>
#include <QtMultimedia/QAudioOutput>

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
Q_OBJECT

public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();

public slots:

void playbackFinished();

private slots:
void appendSound();

void on_pushButton_Run_clicked();

void on_pushButton_Stop_clicked();

private:
Ui::MainWindow *ui;

QByteArray *soundBuffer;
QBuffer *outputBuffer;
QAudioFormat *format;
QAudioOutput *output;
};

#endif // MAINWINDOW_H

mainWindows.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"

#include <QDebug>

int sampleRate = 44100;
int channelCount = 2;
int sampleSize = 16;
const QString codec = "audio/pcm";

MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);

soundBuffer = new QByteArray();

format = new QAudioFormat();
format->setSampleRate(sampleRate);
format->setChannelCount(channelCount);
format->setSampleSize(sampleSize);
format->setCodec(codec);
format->setByteOrder(QAudioFormat::LittleEndian);
format->setSampleType(QAudioFormat::UnSignedInt);

output = new QAudioOutput(*format, this);

connect(output, SIGNAL(stateChanged(QAudio::State)), this, SLOT(playbackFinished()));

outputBuffer = new QBuffer(soundBuffer);
if (outputBuffer->open(QIODevice::ReadOnly) == false) {
qCritical() << "Invalid operation while opening QBuffer. audio/pcm";
return;
}
}

MainWindow::~MainWindow()
{
delete ui;
delete soundBuffer;
delete format;
delete output;
delete outputBuffer;
}

void MainWindow::playbackFinished()
{
if (output->state() == QAudio::IdleState)
{
qDebug() << "Playback finished";
}
}

void MainWindow::appendSound()
{

QStringList MySq;

MySq << "1:440:180000";
MySq << "1:20:180000";
MySq << "1:2120:180000";
MySq << "1:240:180000";
MySq << "1:570:180000";
MySq << "1:570:180000";
MySq << "1:570:180000";
MySq << "1:850:180000";
MySq << "1:1570:180000";
MySq << "1:200:180000";
MySq << "1:50:180000";
MySq << "1:85:180000";
MySq << "1:59:180000";
MySq << "1:20:180000";

foreach(QString seq, MySq)
{
QStringList Assits = seq.split(":");

qDebug() << "Now At: " << seq;

QString A = Assits.at(0);
QString B = Assits.at(1);
QString C = Assits.at(2);

qreal amplitude = A.toInt();
float frequency = B.toFloat();
int msecs = C.toInt();

msecs = (msecs < 50) ? 50 : msecs;

qreal singleWaveTime = amplitude / frequency;

qreal samplesPerWave = qCeil(format->sampleRate() * singleWaveTime);

quint32 waveCount = qCeil(msecs / (singleWaveTime * 1000.0));

quint32 sampleSize = static_cast<quint32>(format->sampleSize() / 8.0);

QByteArray data(waveCount * samplesPerWave * sampleSize * format->channelCount(), '\0');

unsigned char* dataPointer = reinterpret_cast<unsigned char*>(data.data());

for (quint32 currentWave = 0; currentWave < waveCount; currentWave++)
{
for (int currentSample = 0; currentSample < samplesPerWave; currentSample++)
{
double nextRadStep = (currentSample / static_cast<double>(samplesPerWave)) * (2 * M_PI);

quint16 sampleValue = static_cast<quint16>((qSin(nextRadStep) > 0 ? 1 : -1) * 32767);

for (int channel = 0; channel < format->channelCount(); channel++)
{
qToLittleEndian(sampleValue, dataPointer);
dataPointer += sampleSize;
}
}
}

soundBuffer->append(data); // <-- STD::Bad_alloc Not enough memory on heap for appending all the frequencies at once in buffer
output->start(outputBuffer);
qDebug() << data.size();
}
}

void MainWindow::on_pushButton_Run_clicked()
{
appendSound();
}

void MainWindow::on_pushButton_Stop_clicked()
{
output->stop();
soundBuffer->clear();
output->reset();
qDebug() << "Playback Stopped";
}

最佳答案

我想出了一个使用QThread和一个解释器的解决方案,让该线程等待更多事件,然后再继续该系列中的下一个序列。

通过这样做,我不需要将全部3到4个小时的PCM数据全部同时加载到QBufferArray中,而是将其分解。运行一个较小的序列,然后等待线程完成,然后在行中加载下一个序列,依此类推,直到所有的序列都播放完毕。

不再需要std::bad_alloc了,因为在任何给定时间,线程仅在堆上使用大约80mb。

关于c++ - 使用QtAudioOutput处理大型QByteArray会导致std::bad_alloc,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51839634/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com