📄 pwavfile.cxx
字号:
// Performs necessary byte-order swapping on for big-endian platforms.BOOL PWAVFile::Read(void * buf, PINDEX len){ if (autoConverter != NULL) return autoConverter->Read(*this, buf, len); return RawRead(buf, len);}BOOL PWAVFile::RawRead(void * buf, PINDEX len){ // Some wav files have extra data after the sound samples in a LIST chunk. // e.g. WAV files made in GoldWave have a copyright and a URL in this chunk. // We do not want to return this data by mistake. PINDEX readlen = len; off_t pos = PFile::GetPosition(); if (pos >= (lenHeader+lenData)) return FALSE; if ((pos + len) > (lenHeader+lenData)) readlen = (lenHeader+lenData) - pos; if (formatHandler != NULL) return formatHandler->Read(*this, buf, readlen); return FileRead(buf, readlen);}BOOL PWAVFile::FileRead(void * buf, PINDEX len){ return PFile::Read(buf, len);}// Performs necessary byte-order swapping on for big-endian platforms.BOOL PWAVFile::Write(const void * buf, PINDEX len){ // Needs to update header on close. header_needs_updating = TRUE; if (autoConverter != NULL) return autoConverter->Write(*this, buf, len); return RawWrite(buf, len);}BOOL PWAVFile::RawWrite(const void * buf, PINDEX len){ // Needs to update header on close. header_needs_updating = TRUE; if (formatHandler != NULL) return formatHandler->Write(*this, buf, len); return FileWrite(buf, len);}BOOL PWAVFile::FileWrite(const void * buf, PINDEX len){ return PFile::Write(buf, len);}// Both SetPosition() and GetPosition() are offset by lenHeader.BOOL PWAVFile::SetPosition(off_t pos, FilePositionOrigin origin){ if (autoConverter != NULL) return autoConverter->SetPosition(*this, pos, origin); return RawSetPosition(pos, origin);}BOOL PWAVFile::RawSetPosition(off_t pos, FilePositionOrigin origin){ if (isValidWAV) { pos += lenHeader; } return PFile::SetPosition(pos, origin);}off_t PWAVFile::GetPosition() const{ if (autoConverter != NULL) return autoConverter->GetPosition(*this); return RawGetPosition();}off_t PWAVFile::RawGetPosition() const{ off_t pos = PFile::GetPosition(); if (isValidWAV) { if (pos >= lenHeader) { pos -= lenHeader; } else { pos = 0; } } return (pos);}unsigned PWAVFile::GetFormat() const{ if (isValidWAV) return wavFmtChunk.format; else return 0;}PString PWAVFile::GetFormatAsString() const{ if (isValidWAV && formatHandler != NULL) return formatHandler->GetFormat(); else return PString::Empty();}unsigned PWAVFile::GetChannels() const{ if (isValidWAV) return wavFmtChunk.numChannels; else return 0;}void PWAVFile::SetChannels(unsigned v) { wavFmtChunk.numChannels = (WORD)v; header_needs_updating = TRUE;}unsigned PWAVFile::GetSampleRate() const{ if (isValidWAV) return wavFmtChunk.sampleRate; else return 0;}void PWAVFile::SetSampleRate(unsigned v) { wavFmtChunk.sampleRate = (WORD)v; header_needs_updating = TRUE;}unsigned PWAVFile::GetSampleSize() const{ if (isValidWAV) return wavFmtChunk.bitsPerSample; else return 0;}void PWAVFile::SetSampleSize(unsigned v) { wavFmtChunk.bitsPerSample = (WORD)v; header_needs_updating = TRUE;}off_t PWAVFile::GetHeaderLength() const{ if (isValidWAV) return lenHeader; else return 0;}off_t PWAVFile::GetDataLength(){ if (autoConverter != NULL) return autoConverter->GetDataLength(*this); return RawGetDataLength();}off_t PWAVFile::RawGetDataLength(){ if (isValidWAV) { // Updates data length before returns. lenData = PFile::GetLength() - lenHeader; return lenData; } else return 0;}BOOL PWAVFile::SetFormat(unsigned fmt){ if (IsOpen() || isValidWAV) return FALSE; SelectFormat(fmt); return TRUE;}BOOL PWAVFile::SetFormat(const PString & format){ if (IsOpen() || isValidWAV) return FALSE; SelectFormat(format); return TRUE;}static inline BOOL NeedsConverter(const PWAV::FMTChunk & fmtChunk){ return (fmtChunk.format != PWAVFile::fmt_PCM) || (fmtChunk.bitsPerSample != 16);}BOOL PWAVFile::ProcessHeader() { if (autoConverter != NULL) { delete autoConverter; autoConverter = NULL; } // Process the header information // This comes in 3 or 4 chunks, either RIFF, FORMAT and DATA // or RIFF, FORMAT, FACT and DATA. if (!IsOpen()) { PTRACE(1,"WAV\tProcessHeader: Not Open"); return (FALSE); } // go to the beginning of the file if (!PFile::SetPosition(0)) { PTRACE(1,"WAV\tProcessHeader: Cannot Set Pos"); return (FALSE); } // Read the RIFF chunk. struct PWAV::RIFFChunkHeader riffChunk; if (!ReadAndCheck(*this, &riffChunk, sizeof(riffChunk))) return FALSE; // check if tags are correct if (strncmp(riffChunk.hdr.tag, WAVLabelRIFF, sizeof(WAVLabelRIFF)) != 0) { PTRACE(1,"WAV\tProcessHeader: Not RIFF"); return (FALSE); } if (strncmp(riffChunk.tag, WAVLabelWAVE, sizeof(WAVLabelWAVE)) != 0) { PTRACE(1,"WAV\tProcessHeader: Not WAVE"); return (FALSE); } // Read the known part of the FORMAT chunk. if (!ReadAndCheck(*this, &wavFmtChunk, sizeof(wavFmtChunk))) return FALSE; // check if labels are correct if (strncmp(wavFmtChunk.hdr.tag, WAVLabelFMT_, sizeof(WAVLabelFMT_)) != 0) { PTRACE(1,"WAV\tProcessHeader: Not FMT"); return (FALSE); } // if we opened the file without knowing the format, then try and set the format now if (formatHandler == NULL) { SelectFormat(wavFmtChunk.format); if (formatHandler == NULL) { Close(); return FALSE; } } // read the extended format chunk (if any) extendedHeader.SetSize(0); if ((unsigned)wavFmtChunk.hdr.len > (sizeof(wavFmtChunk) - sizeof(wavFmtChunk.hdr))) { extendedHeader.SetSize(wavFmtChunk.hdr.len - (sizeof(wavFmtChunk) - sizeof(wavFmtChunk.hdr))); if (!ReadAndCheck(*this, extendedHeader.GetPointer(), extendedHeader.GetSize())) return FALSE; } // give format handler a chance to read extra chunks if (!formatHandler->ReadExtraChunks(*this)) return FALSE; PWAV::ChunkHeader chunkHeader; // ignore chunks until we see a DATA chunk for (;;) { if (!ReadAndCheck(*this, &chunkHeader, sizeof(chunkHeader))) return FALSE; if (strncmp(chunkHeader.tag, WAVLabelDATA, sizeof(WAVLabelDATA)) == 0) break; if (!PFile::SetPosition(PFile::GetPosition() + + chunkHeader.len)) { PTRACE(1,"WAV\tProcessHeader: Cannot set new position"); return FALSE; } } // calculate the size of header and data for accessing the WAV data. lenHeader = PFile::GetPosition(); lenData = chunkHeader.len; // get ptr to data handler if in autoconvert mode if (autoConvert && NeedsConverter(wavFmtChunk)) { autoConverter = PWAVFileConverterFactory::CreateInstance(wavFmtChunk.format); if (autoConverter == NULL) { PTRACE(1, "PWAVFile\tNo format converter for type " << (int)wavFmtChunk.format); } } formatHandler->OnStart(); return TRUE;}// Generates the wave file header.// Two types of header are supported.// a) PCM data, set to 8000Hz, mono, 16-bit samples// b) G.723.1 data// When this function is called with lenData < 0, it will write the header// as if the lenData is LONG_MAX minus header length.// Note: If it returns FALSE, the file may be left in inconsistent state.BOOL PWAVFile::GenerateHeader(){ if (autoConverter != NULL) { delete autoConverter; autoConverter = NULL; } if (!IsOpen()) { PTRACE(1, "WAV\tGenerateHeader: Not Open"); return (FALSE); } // length of audio data is set to a large value if lenData does not // contain a valid (non negative) number. We must then write out real values // when we close the wav file. int audioDataLen; if (lenData < 0) { audioDataLen = LONG_MAX - wavFmtChunk.hdr.len; header_needs_updating = TRUE; } else { audioDataLen = lenData; } // go to the beginning of the file if (!PFile::SetPosition(0)) { PTRACE(1,"WAV\tGenerateHeader: Cannot Set Pos"); return (FALSE); } // write the WAV file header PWAV::RIFFChunkHeader riffChunk; memcpy(riffChunk.hdr.tag, WAVLabelRIFF, sizeof(WAVLabelRIFF)); memcpy(riffChunk.tag, WAVLabelWAVE, sizeof(WAVLabelWAVE)); riffChunk.hdr.len = lenHeader + audioDataLen - sizeof(riffChunk.hdr); if (!WriteAndCheck(*this, &riffChunk, sizeof(riffChunk))) return FALSE; // populate and write the WAV header with the default data memcpy(wavFmtChunk.hdr.tag, WAVLabelFMT_, sizeof(WAVLabelFMT_)); wavFmtChunk.hdr.len = sizeof(wavFmtChunk) - sizeof(wavFmtChunk.hdr); // set default length assuming no extra bytes // allow the format handler to modify the header and extra bytes formatHandler->CreateHeader(wavFmtChunk, extendedHeader); // write the basic WAV header if ( !WriteAndCheck(*this, &wavFmtChunk, sizeof(wavFmtChunk)) || ((extendedHeader.GetSize() > 0) && !WriteAndCheck(*this, extendedHeader.GetPointer(), extendedHeader.GetSize())) ) return FALSE; // allow the format handler to write additional chunks if (!formatHandler->WriteExtraChunks(*this)) return FALSE; // Write the DATA chunk. PWAV::ChunkHeader dataChunk; memcpy(dataChunk.tag, WAVLabelDATA, sizeof(WAVLabelDATA)); dataChunk.len = audioDataLen; if (!WriteAndCheck(*this, &dataChunk, sizeof(dataChunk))) return FALSE; isValidWAV = TRUE; // get the length of the header lenHeader = PFile::GetPosition(); // get pointer to auto converter if (autoConvert && NeedsConverter(wavFmtChunk)) { autoConverter = PWAVFileConverterFactory::CreateInstance(wavFmtChunk.format); if (autoConverter == NULL) { PTRACE(1, "PWAVFile\tNo format converter for type " << (int)wavFmtChunk.format); return FALSE; } } return (TRUE);}// Update the WAV header according to the file length
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -