QFile写一个WAV头只写4字节数据

时间:2016-10-25 11:07:49

标签: qt wav qfile

我正在编写WAV录音机,使用QFile作为主干。但是,当我填充我的Wav结构,并尝试将其写入我的QFile时,它只会写入" RIFF",我用unix' s od -cb 1.wav查看它。这是一个代码:

wavwriter.cpp

   Wav::Wav(const char *fname, QFile* parent)
    : QFile(fname, parent),
      m_fname(fname)
{
    setFileName(fname);
    bool res = this->open(QIODevice::ReadWrite);
    if (res) {
        std::cout << "File opened for RW\n";
    }
}

Wav::~Wav()
{
}

void Wav::writeHeader(const WavHdr* hdr)
{
    write((char*)hdr);
    flush();
}

void Wav::appendData(const QByteArray &data)
{
    m_data.append(data);
}

QByteArray Wav::getWavData()
{
    return m_data;
}

用法如下:

    WavHdr hdr;
    hdr.bits_per_sample = 8;
    hdr.riff[0] = 'R';
    hdr.riff[1] = 'I';
    hdr.riff[2] = 'F';
    hdr.riff[3] = 'F';
    hdr.sample_rate = 8;
    hdr.fmt[0] = 'f';
    hdr.fmt[1] = 'm';
    hdr.fmt[2] = 't';
    m_wavs[i]->writeHeader(&hdr);

WavHdr具有以下设置:

    struct WavHdr
{
    char riff[4];
    qint32 file_size;
    char wave[4];
    char fmt[4];
    char len[3];
    qint16 type;
    quint16 format;
    qint32 sample_rate;
    qint32 sr_bs_channs;
    quint8 bits_per_sample;
    char data[4];
    qint32 fsize;
};

2 个答案:

答案 0 :(得分:1)

  1. 您无法直接将WavHdr转储到磁盘。

    使用write方法的方式仅适用于以零结尾的字符串。它将停止写入第一个零值字节。 WavHdr 不是以空字符结尾的字符串。

    您不能假设结构在内存中有任何特定的表示。编译器可以按照它认为合适的方式自由安排该结构。它不仅可以任意填充和对齐成员,还可以重新排列它们。因此,这是一种非便携式反模式:它可能恰好在某些编译器上运行,而在其他编译器上则会彻底破坏。

  2. 您的WavHdr错了。

    请参阅here以供参考。我在下面提供了正确的标题结构。

  3. 您可能希望使用QSaveFile

    保存文件时,通常打算将文件写入为原子:要么成功又要得到完整有效的WAV文件,否则它会失败并且磁盘上没有任何更改(例如,现有文件不会被覆盖和腐败的)。这是QSaveFile的目的。

  4. 您可能希望wave类使用I / O设备,但不能使用。

    只需QIODevice*的实例即可完成I / O:您可以轻松地将数据写入内存缓冲区,文件,网络套接字等。您的班级应该可以自由选择要使用的特定设备。

  5. 相反,使用QDataStream以便携方式编写标题:

    struct WavHdr
    {
       constexpr static quint32 k_riff_id = 0x46464952;
       constexpr static quint32 k_wave_format = 0x45564157;
       constexpr static quint32 k_fmt_id = 0x20746d66;
       constexpr static quint32 k_data_id = 0x61746164;
       // RIFF
       quint32 chunk_id = k_riff_id;
       quint32 chunk_size;
       quint32 chunk_format = k_wave_format;
       // fmt
       quint32 fmt_id = k_fmt_id;
       quint32 fmt_size;
       quint16 audio_format;
       quint16 num_channels;
       quint32 sample_rate;
       quint32 byte_rate;
       quint16 block_align;
       quint16 bits_per_sample;
       // data
       quint32 data_id = k_data_id;
       quint32 data_size;
    };
    
    bool write(QIODevice * dev, const WavHdr & h) {
      QDataStream s{dev};
      s.setByteOrder(QDataStream::LittleEndian); // for RIFF
      s << h.chunk_id << h.chunk_size
        << h.chunk_format;
      s << h.fmt_id << h.fmt_size
        << h.audio_format
        << h.num_channels
        << h.sample_rate
        << h.byte_rate
        << h.block_align
        << h.bits_per_sample;
      s << h.data_id << h.data_size;
      return s.status() == QDataStream::Ok;
    }
    

答案 1 :(得分:-1)

看起来这段代码写了所有44个字节:

char wav[44]={0};
memcpy(wav, hdr, 44);
write(QByteArray(wav), 44);
flush();

但是我必须检查一切是否正确填充。