QFile wavFile;
QAudioFormat m_fileFormat;
QAudioOutput * m_audioOutput;
QIODevice * m_output;
#include "wavefile.h"
#include <QByteArray>
#include <QtEndian>
#include <QEventLoop>
#include <QObject>
typedef struct WAV_HEADER
{
char RIFF[4]; // RIFF Header Magic header
quint32 ChunkSize; // RIFF Chunk Size
char WAVE[4]; // WAVE Header
char fmt[4]; // FMT header
quint32 Subchunk1Size; // Size of the fmt chunk
quint16 AudioFormat; // Audio format 1=PCM,6=mulaw,7=alaw, 257=IBM Mu-Law, 258=IBM A-Law, 259=ADPCM
quint16 NumOfChan; // Number of channels 1=Mono 2=Sterio
quint32 SamplesPerSec; // Frequency in Hz
quint32 bytesPerSec; // bytes per second
quint16 blockAlign; // 2=16-bit mono, 4=16-bit stereo Количество байт для одной выборки, включая все каналы.
quint16 bitsPerSample; // Number of bits per sample Так называемая "глубина" или точность звучания. 8 бит, 16 бит и т.д.
char Subchunk2ID[4]; // "data" string
quint32 Subchunk2Size; // Sampled data length
} wav_hdr;
bool WaveFile::open(const QString &FileName)
{
wavFile.setFileName(FileName);
return wavFile.open(QIODevice::ReadOnly) && readHeader();
}
bool WaveFile::readHeader()
{
wavFile.seek(0);
wav_hdr wavHeader;
int headerSize = sizeof(wav_hdr);
wavFile.read((char *)&wavHeader, headerSize);
if ((memcmp(&wavHeader.RIFF, "RIFF", 4) == 0
|| memcmp(&wavHeader.RIFF, "RIFX", 4) == 0)
&& memcmp(&wavHeader.WAVE, "WAVE", 4) == 0
&& memcmp(&wavHeader.fmt, "fmt ", 4) == 0
&& (wavHeader.AudioFormat == 1 || wavHeader.AudioFormat == 0))
{
wavHeader.Subchunk2Size=qFromBigEndian<quint32>(wavHeader.Subchunk2Size);
int bps = wavHeader.bitsPerSample;
m_fileFormat.setChannelCount(wavHeader.NumOfChan);
m_fileFormat.setCodec("audio/pcm");
m_fileFormat.setSampleRate(wavHeader.SamplesPerSec);
m_fileFormat.setSampleSize(wavHeader.bitsPerSample);
m_fileFormat.setSampleType(bps == 8 ? QAudioFormat::UnSignedInt : QAudioFormat::SignedInt);
if (memcmp(&wavHeader.RIFF, "RIFF", 4) == 0)
m_fileFormat.setByteOrder(QAudioFormat::LittleEndian);
else
m_fileFormat.setByteOrder(QAudioFormat::BigEndian);
//получаю указатель на системное аудио устройство, на которое потом буду write
m_audioOutput = new QAudioOutput(m_fileFormat);
m_output=m_audioOutput->start();
QByteArray buffer;
QEventLoop loop;
QObject::connect(m_output, SIGNAL(bytesWritten(qint64)), &loop, SLOT(quit()));
//кол-во секунд в файле
int seconds = wavHeader.Subchunk2Size/wavHeader.SamplesPerSec;
for (int i = 0; i < seconds; i++)
{
//читаю в буфер 1 секунду
buffer = wavFile.read(wavHeader.bytesPerSec);
m_output->write(buffer.data(), buffer.size());
loop.exec();
}
return true;
}
return false;
}
Для чего я хочу использовать луп - если его не вызвать, то цикл с write() выполнится без задержек и не будет звука. Он просто почти за секунду запишет все данные в аудиобуфер и ни чего не произойдет. С помощью лупа я хочу сделать задержку. чтоб аудио устройство успело проиграть все что я в него записал.
Я заменял сигнал QIODevice::bytesWritten() на сигнал QAudioOutput::stateChanged(). Он вызывается когда аудио устройство меняет свое состояние. И все тогда работает, но присутствует крохотная задержка между шагами цикла (видимо возникает из-за смены состояния), которая порождает задержки в звуке.
По поводу 1 пункта. Сигнал bytesWritten() не вызывается вообще.