示例#1
0
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;
}
示例#2
0
static boolByte _writeWaveFileInfo(SampleSourcePcmData extraData)
{
    RiffChunk chunk = newRiffChunk();
    unsigned short audioFormat = 1;
    unsigned int byteRate = (unsigned int)(extraData->sampleRate) * extraData->numChannels * extraData->bitDepth / 8;
    unsigned short blockAlign = (unsigned short)(extraData->numChannels * extraData->bitDepth / 8);
    unsigned int extraParams = 0;

    memcpy(chunk->id, "RIFF", 4);

    if (fwrite(chunk->id, sizeof(byte), 4, extraData->fileHandle) != 4) {
        logError("Could not write RIFF header");
        freeRiffChunk(chunk);
        return false;
    }

    // Write the size, but this will need to be set again when the file is finished writing
    if (fwrite(&(chunk->size), sizeof(unsigned int), 1, extraData->fileHandle) != 1) {
        logError("Could not write RIFF chunk size");
        freeRiffChunk(chunk);
        return false;
    }

    memcpy(chunk->id, "WAVE", 4);

    if (fwrite(chunk->id, sizeof(byte), 4, extraData->fileHandle) != 4) {
        logError("Could not WAVE format");
        freeRiffChunk(chunk);
        return false;
    }

    // Write the format header
    memcpy(chunk->id, "fmt ", 4);
    chunk->size = 20;

    if (fwrite(chunk->id, sizeof(byte), 4, extraData->fileHandle) != 4) {
        logError("Could not write format header");
        freeRiffChunk(chunk);
        return false;
    }

    if (fwrite(&(chunk->size), sizeof(unsigned int), 1, extraData->fileHandle) != 1) {
        logError("Could not write format chunk size");
        freeRiffChunk(chunk);
        return false;
    }

    if (!platformInfoIsLittleEndian()) {
        logUnsupportedFeature("WAVE files on big-endian platforms");
        freeRiffChunk(chunk);
        return false;
    }

    if (fwrite(&audioFormat, sizeof(unsigned short), 1, extraData->fileHandle) != 1) {
        logError("Could not write audio format");
        freeRiffChunk(chunk);
        return false;
    }

    if (fwrite(&(extraData->numChannels), sizeof(unsigned short), 1, extraData->fileHandle) != 1) {
        logError("Could not write channel count");
        freeRiffChunk(chunk);
        return false;
    }

    unsigned int sampleRateAsUInt = (unsigned int)extraData->sampleRate;
    if (fwrite(&(sampleRateAsUInt), sizeof(unsigned int), 1, extraData->fileHandle) != 1) {
        logError("Could not write sample rate");
        freeRiffChunk(chunk);
        return false;
    }

    if (fwrite(&(byteRate), sizeof(unsigned int), 1, extraData->fileHandle) != 1) {
        logError("Could not write byte rate");
        freeRiffChunk(chunk);
        return false;
    }

    if (fwrite(&(blockAlign), sizeof(unsigned short), 1, extraData->fileHandle) != 1) {
        logError("Could not write block align");
        freeRiffChunk(chunk);
        return false;
    }

    if (fwrite(&(extraData->bitDepth), sizeof(unsigned short), 1, extraData->fileHandle) != 1) {
        logError("Could not write bits per sample");
        freeRiffChunk(chunk);
        return false;
    }

    if (fwrite(&(extraParams), sizeof(byte), 4, extraData->fileHandle) != 4) {
        logError("Could not write extra PCM parameters");
        freeRiffChunk(chunk);
        return false;
    }

    memcpy(chunk->id, "data", 4);

    if (fwrite(chunk->id, sizeof(byte), 4, extraData->fileHandle) != 4) {
        logError("Could not write format header");
        freeRiffChunk(chunk);
        return false;
    }

    if (fwrite(&(chunk->size), sizeof(unsigned int), 1, extraData->fileHandle) != 1) {
        logError("Could not write data chunk size");
        freeRiffChunk(chunk);
        return false;
    }

    freeRiffChunk(chunk);
    return true;
}
示例#3
0
void _closeSampleSourceWave(void *sampleSourceDataPtr)
{
    SampleSource sampleSource = (SampleSource)sampleSourceDataPtr;
    SampleSourcePcmData extraData = (SampleSourcePcmData)sampleSource->extraData;
    size_t numBytesWritten;
    RiffChunk chunk;

    if (sampleSource->openedAs == SAMPLE_SOURCE_OPEN_WRITE) {
        // Re-open the file for editing
        fflush(extraData->fileHandle);

        if (fclose(extraData->fileHandle) != 0) {
            logError("Could not close WAVE file for finalization");
            return;
        }

        extraData->fileHandle = fopen(sampleSource->sourceName->data, "rb+");

        if (extraData->fileHandle == NULL) {
            logError("Could not reopen WAVE file for finalization");
            return;
        }

        // First go to the second chunk in the file and re-read the chunk length
        if (fseek(extraData->fileHandle, 12, SEEK_SET) != 0) {
            logError("Could not seek to second chunk during WAVE file finalization");
            fclose(extraData->fileHandle);
            return;
        }

        chunk = newRiffChunk();

        if (!riffChunkReadNext(chunk, extraData->fileHandle, false)) {
            logError("Could not read RIFF chunk during WAVE file finalization");
            fclose(extraData->fileHandle);
            freeRiffChunk(chunk);
            return;
        }

        // Go to the next chunk, and then skip the type and write the new length
        if (fseek(extraData->fileHandle, (long)(chunk->size + 4), SEEK_CUR) != 0) {
            logError("Could not seek to next chunk during WAVE file finalization");
            fclose(extraData->fileHandle);
            freeRiffChunk(chunk);
            return;
        }

        numBytesWritten = sampleSource->numSamplesProcessed * extraData->bitDepth / 8;

        if (fwrite(&numBytesWritten, sizeof(unsigned int), 1, extraData->fileHandle) != 1) {
            logError("Could not write WAVE file size during finalization");
            fclose(extraData->fileHandle);
            freeRiffChunk(chunk);
            return;
        }

        // Add 40 bytes for fmt chunk size and write the RIFF chunk size
        numBytesWritten += ftell(extraData->fileHandle) - 8;

        if (fseek(extraData->fileHandle, 4, SEEK_SET) != 0) {
            logError("Could not seek to fmt chunk during WAVE file finalization");
            fclose(extraData->fileHandle);
            freeRiffChunk(chunk);
            return;
        }

        if (fwrite(&numBytesWritten, sizeof(unsigned int), 1, extraData->fileHandle) != 1) {
            logError("Could not write WAVE file size in fmt chunk during finalization");
            fclose(extraData->fileHandle);
            freeRiffChunk(chunk);
            return;
        }

        fflush(extraData->fileHandle);
        fclose(extraData->fileHandle);
        freeRiffChunk(chunk);
    } else if (sampleSource->openedAs == SAMPLE_SOURCE_OPEN_READ && extraData->fileHandle != NULL) {
        fclose(extraData->fileHandle);
    }
}
示例#4
0
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;
}