static boolByte _readWaveFileInfo(const char *filename, SampleSourcePcmData extraData) { int chunkOffset = 0; RiffChunk chunk = newRiffChunk(); boolByte dataChunkFound = false; char format[4]; size_t itemsRead; unsigned int audioFormat; unsigned int byteRate; unsigned int expectedByteRate; unsigned int blockAlign; unsigned int expectedBlockAlign; if (riffChunkReadNext(chunk, extraData->fileHandle, false)) { if (!riffChunkIsIdEqualTo(chunk, "RIFF")) { logFileError(filename, "Invalid RIFF chunk descriptor"); freeRiffChunk(chunk); return false; } // The WAVE file format has two sub-chunks, with the size of both calculated in the size field. Before // either of the subchunks, there are an extra 4 bytes which indicate the format type. We need to read // that before either of the subchunks can be parsed. itemsRead = fread(format, sizeof(byte), 4, extraData->fileHandle); if (itemsRead != 4 || strncmp(format, "WAVE", 4)) { logFileError(filename, "Invalid format description"); freeRiffChunk(chunk); return false; } } else { logFileError(filename, "No chunks following descriptor"); freeRiffChunk(chunk); return false; } if (riffChunkReadNext(chunk, extraData->fileHandle, true)) { if (!riffChunkIsIdEqualTo(chunk, "fmt ")) { logError(filename, "Invalid format chunk header"); freeRiffChunk(chunk); return false; } audioFormat = convertByteArrayToUnsignedShort(chunk->data + chunkOffset); chunkOffset += 2; if (audioFormat != 1) { logError("WAVE file with audio format %d is not supported", audioFormat); freeRiffChunk(chunk); return false; } extraData->numChannels = convertByteArrayToUnsignedShort(chunk->data + chunkOffset); chunkOffset += 2; setNumChannels(extraData->numChannels); extraData->sampleRate = convertByteArrayToUnsignedInt(chunk->data + chunkOffset); chunkOffset += 4; setSampleRate(extraData->sampleRate); byteRate = convertByteArrayToUnsignedInt(chunk->data + chunkOffset); chunkOffset += 4; blockAlign = convertByteArrayToUnsignedShort(chunk->data + chunkOffset); chunkOffset += 2; extraData->bitDepth = (BitDepth) convertByteArrayToUnsignedShort(chunk->data + chunkOffset); if (extraData->bitDepth != kBitDepth16Bit) { logUnsupportedFeature("Non-16-bit files with internal WAVE file support (build with audiofile instead!)"); freeRiffChunk(chunk); return false; } expectedByteRate = (unsigned int)(extraData->sampleRate) * extraData->numChannels * extraData->bitDepth / 8; if (expectedByteRate != byteRate) { logWarn("Possibly invalid bitrate %d, expected %d", byteRate, expectedByteRate); } expectedBlockAlign = (unsigned int)(extraData->numChannels * extraData->bitDepth / 8); if (expectedBlockAlign != blockAlign) { logWarn("Possibly invalid block align %d, expected %d", blockAlign, expectedBlockAlign); } } else { logFileError(filename, "WAVE file has no chunks following format"); freeRiffChunk(chunk); return false; } // We don't need the format data anymore, so free and re-alloc the chunk to avoid a small memory leak freeRiffChunk(chunk); chunk = newRiffChunk(); // FFMpeg (and possibly other programs) have extra sections between the fmt and data chunks. They // can be safely ignored. We just need to find the data chunk. See also: // http://forum.videohelp.com/threads/359689-ffmpeg-Override-Set-ISFT-Metadata while (!dataChunkFound) { if (riffChunkReadNext(chunk, extraData->fileHandle, false)) { if (riffChunkIsIdEqualTo(chunk, "data")) { logDebug("WAVE file has %d bytes", chunk->size); dataChunkFound = true; } else { fseek(extraData->fileHandle, (long) chunk->size, SEEK_CUR); } } else { break; } } if (!dataChunkFound) { logFileError(filename, "Could not find a data chunk. Possibly malformed WAVE file."); freeRiffChunk(chunk); return false; } freeRiffChunk(chunk); return true; }
static boolByte _readWaveFileInfo(const char* filename, SampleSourcePcmData extraData) { int chunkOffset = 0; RiffChunk chunk = newRiffChunk(); char format[4]; size_t itemsRead; unsigned int audioFormat; unsigned int byteRate; unsigned int expectedByteRate; unsigned int blockAlign; unsigned int expectedBlockAlign; if(riffChunkReadNext(chunk, extraData->fileHandle, false)) { if(!riffChunkIsIdEqualTo(chunk, "RIFF")) { logFileError(filename, "Invalid RIFF chunk descriptor"); freeRiffChunk(chunk); return false; } // The WAVE file format has two sub-chunks, with the size of both calculated in the size field. Before // either of the subchunks, there are an extra 4 bytes which indicate the format type. We need to read // that before either of the subchunks can be parsed. itemsRead = fread(format, sizeof(byte), 4, extraData->fileHandle); if(itemsRead != 4 || strncmp(format, "WAVE", 4)) { logFileError(filename, "Invalid format description"); freeRiffChunk(chunk); return false; } } else { logFileError(filename, "No chunks following descriptor"); freeRiffChunk(chunk); return false; } if(riffChunkReadNext(chunk, extraData->fileHandle, true)) { if(!riffChunkIsIdEqualTo(chunk, "fmt ")) { logError(filename, "Invalid format chunk header"); freeRiffChunk(chunk); return false; } audioFormat = convertByteArrayToUnsignedShort(chunk->data + chunkOffset); chunkOffset += 2; if(audioFormat != 1) { logUnsupportedFeature("Compressed WAVE files"); freeRiffChunk(chunk); return false; } extraData->numChannels = convertByteArrayToUnsignedShort(chunk->data + chunkOffset); chunkOffset += 2; setNumChannels(extraData->numChannels); extraData->sampleRate = convertByteArrayToUnsignedInt(chunk->data + chunkOffset); chunkOffset += 4; setSampleRate(extraData->sampleRate); byteRate = convertByteArrayToUnsignedInt(chunk->data + chunkOffset); chunkOffset += 4; blockAlign = convertByteArrayToUnsignedShort(chunk->data + chunkOffset); chunkOffset += 2; extraData->bitsPerSample = convertByteArrayToUnsignedShort(chunk->data + chunkOffset); if(extraData->bitsPerSample > 16) { logUnsupportedFeature("Bitrates greater than 16"); freeRiffChunk(chunk); return false; } else if(extraData->bitsPerSample < 16) { logUnsupportedFeature("Bitrates lower than 16"); freeRiffChunk(chunk); return false; } expectedByteRate = extraData->sampleRate * extraData->numChannels * extraData->bitsPerSample / 8; if(expectedByteRate != byteRate) { logWarn("Possibly invalid bitrate %d, expected %d", byteRate, expectedByteRate); } expectedBlockAlign = extraData->numChannels * extraData->bitsPerSample / 8; if(expectedBlockAlign != blockAlign) { logWarn("Possibly invalid block align %d, expected %d", blockAlign, expectedBlockAlign); } } else { logFileError(filename, "WAVE file has no chunks following format"); freeRiffChunk(chunk); return false; } // We don't need the format data anymore, so free and re-alloc the chunk to avoid a small memory leak freeRiffChunk(chunk); chunk = newRiffChunk(); if(riffChunkReadNext(chunk, extraData->fileHandle, false)) { if(!riffChunkIsIdEqualTo(chunk, "data")) { logFileError(filename, "WAVE file has invalid data chunk header"); freeRiffChunk(chunk); return false; } logDebug("WAVE file has %d bytes", chunk->size); } freeRiffChunk(chunk); return true; }