Набросал небольшой пример, который читает и пишет WAV-файл.
Боевой код можно сделать проще, сейчас пытался расписать все в деталях.
Посмотри, попробуй. Когда разберешься, переделать код для mmio труда не составит.
C++ (Qt)
// Код демонстрационный!
// Код подразумевает, что архитектура использует byte order == little endian.
// При записи ошибки не проверяются, лениво стало. :)
#include <QByteArray>
#include <QFile>
#include <QtEndian>
#include <QDebug>
#define SIG_RIFF quint32(('R' << 24) | ('I' << 16) | ('F' << 8) | ('F'))
#define SIG_WAVE quint32(('W' << 24) | ('A' << 16) | ('V' << 8) | ('E'))
#define SIG_FMT quint32(('f' << 24) | ('m' << 16) | ('t' << 8) | (' '))
#define SIG_DATA quint32(('d' << 24) | ('a' << 16) | ('t' << 8) | ('a'))
#pragma pack(push, 1)
struct WAVFormat
{
quint16 formatTag; // тип формата
quint16 channels; // количество каналов (1 - моно или 2 - стeрео)
quint32 samplesPerSec; // частота дискретизации (11025, 22050, 44100, ...)
quint32 avgBytesPerSec; // скорость потока данных
quint16 blockAlign; // выравнивание блока данных
quint16 bitsPerSample; // количество бит в сеймпле
};
#pragma pack(pop)
static bool findSig( QIODevice *dev, quint32 sig )
{
Q_ASSERT( dev );
qDebug() << "Search signature :" << hex << sig;
while( !dev->atEnd() )
{
quint32 data;
if( dev->read( (char*)&data, sizeof( data ) ) != sizeof( data ) )
break;
if( qToBigEndian( data ) == sig )
return true;
}
return false;
}
QByteArray readWav( QIODevice *dev, WAVFormat &fmt )
{
if( !dev )
{
qDebug() << "Device for reading is not specified";
return QByteArray();
}
// Последовательно перемещаемся по сигнатурам RIFF, WAVE, fmt
if( findSig( dev, SIG_RIFF ) && findSig( dev, SIG_WAVE ) && findSig( dev, SIG_FMT ) )
{
// Читаем и проверяем размер блока fmt
quint32 fmtSize;
if( dev->read( (char*)&fmtSize, sizeof( fmtSize ) ) == sizeof( fmtSize ) && fmtSize == sizeof( fmt ) )
{
// Читаем блок fmt
if( dev->read( (char*)&fmt, sizeof( fmt ) ) == sizeof( fmt ) )
{
// Перемещаемся к сигнатуре data
if( findSig( dev, SIG_DATA ) )
{
// Читаем размер данных
quint32 dataSize;
if( dev->read( (char*)&dataSize, sizeof( dataSize ) ) == sizeof( dataSize ) )
{
// Читаем блок данных
return dev->read( dataSize );
}
}
}
}
}
qDebug() << "Format file error";
return QByteArray();
}
bool writeWav( QIODevice *dev, const WAVFormat &fmt, const QByteArray &data )
{
quint32 sig;
quint32 size;
if( !dev )
{
qDebug() << "Device for writing is not specified";
return false;
}
// Пишем сигнатуру RIFF
sig = qToBigEndian( SIG_RIFF );
dev->write( (char*)&sig, sizeof( sig ) );
// Вычисляем и записываем размер блока RIFF
size = sizeof(quint32) + // Сигнатура WAVE
sizeof(quint32) + // Сигнатура fmt
sizeof(quint32) + // Размер блока fmt (0x10)
sizeof(fmt) + // Блок fmt
sizeof(quint32) + // Сигнатура data
sizeof(quint32) + // Размер данных
data.size(); // Длина данных
dev->write( (char*)&size, sizeof( size ) );
// Пишем сигнатуру WAVE
sig = qToBigEndian( SIG_WAVE );
dev->write( (char*)&sig, sizeof( sig ) );
// Пишем сигнатуру fmt
sig = qToBigEndian( SIG_FMT );
dev->write( (char*)&sig, sizeof( sig ) );
// Пишем размер блока fmt
size = sizeof( fmt );
dev->write( (char*)&size, sizeof( size ) );
// Пишем блок fmt
dev->write( (char*)&fmt, sizeof( fmt ) );
// Пишем сигнатуру data
sig = qToBigEndian( SIG_DATA );
dev->write( (char*)&sig, sizeof( sig ) );
// Пишем размер data
size = data.size();
dev->write( (char*)&size, sizeof( size ) );
// Пишем блок data
dev->write( data );
return true;
}
int main( int, char ** )
{
// Читаем файл
QFile infile( "test.wav" );
if( !infile.open( QIODevice::ReadOnly ) )
{
qDebug() << "File open error";
return 1;
}
WAVFormat fmt;
QByteArray data = readWav( &infile, fmt );
qDebug() << fmt.formatTag << fmt.channels << fmt.samplesPerSec << fmt.avgBytesPerSec << fmt.blockAlign << fmt.bitsPerSample;
// Пишем файл
QFile outfile( "out.wav" );
if( !outfile.open( QIODevice::WriteOnly ) )
{
qDebug() << "File create error";
return 1;
}
// Используем формат и данные прочитанного файла.
// Если менять формат, то нужно настраивать параметры fmt и data.
writeWav( &outfile, fmt, data );
return 0;
}