📄 pwavfile.cxx
字号:
}
if (!PFile::IsOpen())
return TRUE;
if (header_needs_updating)
UpdateHeader();
if (formatHandler != NULL)
formatHandler->OnStop();
delete formatHandler;
formatHandler = NULL;
if (origFmt != 0xffffffff)
SelectFormat(origFmt);
return PFile::Close();
}
void PWAVFile::SetAutoconvert()
{
autoConvert = TRUE;
}
// 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) {
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
if(formatHandler == NULL){
PTRACE(1,"WAV\tGenerateHeader: format handler is null!");
return FALSE;
}
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);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -