2016-10-25 17 views
0

Я пишу WAV-рекордер, используя QFile в качестве основы. Однако, когда я заполняю свою структуру Wav и пытаюсь записать ее в свой QFile, она записывает только «RIFF», я просмотрел ее с помощью unix od -cb 1.wav. Вот код выборочными: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 имеет смысл только для строк с нулевым концом. Он прекратит запись в первом нулевом байте. A WavHdr является не строка с нулевым символом.

    Вы не можете предположить, что структура имеет какое-либо конкретное представление в памяти. Компилятор может упорядочить эту структуру так, как она считает нужным. Он не только может накладывать и выравнивать элементы произвольно, он также может их переупорядочить. Так что это не переносимый анти-шаблон: может быть, он работает на некоторых компиляторах, а на других он будет полностью нарушен.

  2. Ваш WavHdr неправ.

    См. here для справки. Я включил правильную структуру заголовка ниже.

  3. Возможно, вы захотите использовать QSaveFile.

    При сохранении файлов вы обычно предполагаете, что запись файла является атомарной: либо она преуспевает, и вы получаете полный, действительный файл WAV, либо он терпит неудачу, и на диске ничего не меняется (например, существующий файл не перезаписывается и не повреждается) , Вот что такое QSaveFile.

  4. Возможно, вы хотите, чтобы ваш волновой класс использовал устройство ввода-вывода, но не одно.

    Ввод-вывод может выполняться только с экземпляром QIODevice*: вы сможете легко записывать данные в буферы, файлы, сетевые сокеты в памяти и т. Д. Пользователь вашего класса должен быть бесплатным выбрать конкретное устройство для использования.

Вместо этого используйте 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 «Упаковка» структуры правильно и делает ее маленькой endian не переносимой. C/C++ 'struct' не предназначен для предоставления какого-либо бинарного макета, на который вы можете рассчитывать. Вы можете делать много хаков, но это не значит, что они правильные или разумные. –

 Смежные вопросы

  • Нет связанных вопросов^_^