2016-10-25 19 views
0

QFileをバックボーンとして使用して、WAVレコーダを作成しています。しかし、私は私のWav構造体を埋めると、それを私のQFileに書き込もうとすると、 "RIFF"しか書き込まれない、私はUNIXのod -cb 1.wavでそれを見た。ここsamleコードは次のとおりです。次のようにQFile WAVヘッダを書き込むと、4バイトのデータしか書き込まれない

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; 
}; 

答えて

-1

それはそうですこのコードのようにすべての44バイトを書き込みます:

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

ただし、すべてが正しく入力されているかどうかを確認する必要があります。

+0

。それがうまくいくと、それはあなたのコードが正しいからではなく、あなたがラッキーだからです。それは反パターンです。これをしないでください。また、 'flush()'は不要です。 –

1
  1. WavHdrをディスクに直接ダンプすることはできません。

    writeメソッドを使用する方法は、ゼロ終端文字列にのみ意味があります。最初のゼロ値バイトで書き込みを停止します。 WavHdrではありません。はNULLで終了する文字列です。

    構造体にメモリ内の特定の表現があるとは想定できません。コンパイラは、その構造が適合するように自由に配置することができます。メンバーを任意にパッドして整列させることができるだけでなく、メンバーを並べ替えることもできます。したがって、これは移植性のないパターンです。コンパイラによっては動作する可能性がありますが、他のコンパイラでは完全に壊れてしまうことがあります。

  2. WavHdrが間違っています。

    参照のためhereを参照してください。私は以下の正しいヘッダ構造を含んでいます。

  3. おそらくQSaveFileを使用します。

    ファイルを保存するときは、通常、ファイルが完全で有効なWAVファイルを取得するか、失敗し、ディスク上に何も変更されません(既存のファイルが上書きされずに破損するなど) 。それはQSaveFileのためのものです。

  4. ウェーブクラスにI/Oデバイスを使用してもらいたいと思うかもしれません。

    のインスタンスだけでI/Oを実行できるため、メモリ内のバッファ、ファイル、ネットワークソケットなどに簡単にデータを書き込むことができます。クラスのユーザーは無料でなければなりません特定のデバイスを使用するかどうかを選択できます。

代わりに、移植可能な方法でヘッダーを書くこと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; 
} 
+0

第1位が間違っています。ファイルはバイナリとしてオープンされているので、 'write(reinterpret_cast (hdr)、sizeof(* hdr));'を実行できます。しかし、その構造は正しく機能するように詰め込まれなければならず、リトルエンディアンが提供されなければならない。 – ilotXXI

+0

@ilotXXI構造を正しくパッキングし、リトルエンディアンにすることは移植性がありません。 C/C++ 'struct'は、あなたが信頼できるバイナリレイアウトを提供するようには設計されていません。あなたはハックをたくさんすることができますが、それは彼らが正しいか合理的であるということを意味しません。 –

関連する問題