// // tools/audwaveencoder/waveencoder.cpp // // Copyright (C) 1999-2005 Rockstar Games. All Rights Reserved. // #include "stdafx.h" #include "forceinclude/win32_release.h" #ifdef __WIN32PC #undef __WIN32PC #endif // __WIN32PC #define __WIN32PC 1 #include "libresample.h" #include "math.h" #include "memory.h" #include "waveencoder.h" #include using namespace audBuildCommon; namespace audWaveEncoding { bool audWaveEncoder::Encode(audWaveMetadataBaseWrapper *waveMetadataInWrapped, unsigned int waveSampleDataOffsetBytes, void **waveMetadataOut, unsigned int &waveMetadataOutLengthBytes, void **waveSampleDataOut, unsigned int &waveSampleDataOutLengthBytes, int /*compression*/, int & /*preloopPadding*/, unsigned int &) { audWaveMetadataBase *waveMetadataIn = waveMetadataInWrapped->GetMetadata(); // // NOTE: If this base implementation is called, no Wave compression is required, so simply convert Wave metadata and // sample data to native platform endianness. // *waveSampleDataOut = new char[waveMetadataIn->lengthBytes]; waveSampleDataOutLengthBytes = waveMetadataIn->lengthBytes; if(audPlatformSpecific::IsPlatformBigEndian()) { for(int i=0; i<(int)(waveMetadataIn->lengthSamples); i++) { (*((unsigned short **)waveSampleDataOut))[i] = audPlatformSpecific::FlipEndian(((unsigned short *)(waveMetadataIn->waveData))[i]); } } else { memcpy(*waveSampleDataOut, waveMetadataIn->waveData, waveMetadataIn->lengthBytes); } *waveMetadataOut = new audWaveMetadataBase(); waveMetadataOutLengthBytes = sizeof(audWaveMetadataBase); const unsigned __int64 waveDataOffsetBytes = (unsigned __int64)waveSampleDataOffsetBytes; const unsigned int waveFlags = WAVEFLAGS_PCM; (*((audWaveMetadataBase **)waveMetadataOut))->waveDataOffsetBytes = audPlatformSpecific::FixEndian(waveDataOffsetBytes); (*((audWaveMetadataBase **)waveMetadataOut))->lengthBytes = audPlatformSpecific::FixEndian(waveMetadataIn->lengthBytes); (*((audWaveMetadataBase **)waveMetadataOut))->lengthSamples = audPlatformSpecific::FixEndian(waveMetadataIn->lengthSamples); (*((audWaveMetadataBase **)waveMetadataOut))->loopStartOffsetSamples = (int)audPlatformSpecific::FixEndian((unsigned int)waveMetadataIn->loopStartOffsetSamples); (*((audWaveMetadataBase **)waveMetadataOut))->sampleRate = audPlatformSpecific::FixEndian(waveMetadataIn->sampleRate); (*((audWaveMetadataBase **)waveMetadataOut))->headroom = (short)audPlatformSpecific::FixEndian((unsigned short)waveMetadataIn->headroom); (*((audWaveMetadataBase **)waveMetadataOut))->flags = audPlatformSpecific::FixEndian(waveFlags); return true; } bool audWaveEncoder::Resample(audWaveMetadataBaseWrapper *waveMetadataInWrapped, int targetSampleRate) { audWaveMetadataBase *waveMetadataIn = waveMetadataInWrapped->GetMetadata(); if(targetSampleRate == (int)(waveMetadataIn->sampleRate)) { return true; } const float resamplingRatio = (float)targetSampleRate / (float)(waveMetadataIn->sampleRate); //Initialize resampler. void *resampler = resample_open(1, resamplingRatio, resamplingRatio); if(resampler == NULL) { return false; } int resamplerTargetSamplesIn = waveMetadataIn->lengthSamples; int resamplerTargetSamplesOut = (int)ceil((float)(waveMetadataIn->lengthSamples) * resamplingRatio); //Allocating floating-point buffers for resampler. float *rawData = new float[resamplerTargetSamplesIn]; float *resampledData = new float[resamplerTargetSamplesOut]; //Convert raw samples to floating-point. for(int i=0; iwaveData))[i]) / 32767.0f; } fprintf(stderr, "Starting resample (%d -> %d)\n", waveMetadataIn->sampleRate, targetSampleRate); //Resample loop. int resamplerSamplesUsed; int resamplerSamplesOut = resample_process(resampler, resamplingRatio, rawData, resamplerTargetSamplesIn, 1, &resamplerSamplesUsed, resampledData, resamplerTargetSamplesOut); fprintf(stderr, "Completed resample\n"); //Convert resampled data back to fixed-point samples. short *resampleBuffer = new short[resamplerTargetSamplesOut]; for(int i=0; iwaveData; waveMetadataIn->waveData = (void *)resampleBuffer; waveMetadataIn->lengthSamples = resamplerTargetSamplesOut; waveMetadataIn->lengthBytes = resamplerTargetSamplesOut * 2; //16-bit PCM. waveMetadataIn->sampleRate = (unsigned short)targetSampleRate; if(waveMetadataIn->loopStartOffsetSamples > 0) { waveMetadataIn->loopStartOffsetSamples = (int)floor((float)waveMetadataIn->loopStartOffsetSamples * resamplingRatio); } //Free memory and shutdown resampler. delete[] rawData; delete[] resampledData; resample_close(resampler); return ((resamplerSamplesOut == resamplerTargetSamplesOut) && (resamplerSamplesUsed == resamplerTargetSamplesIn)); } bool audWaveEncoder::AlignLoop(audWaveMetadataBase *waveMetadata, unsigned int alignmentSamples, int &preloopPadding) { unsigned int i; unsigned int preloopLengthSamples = (unsigned int )(waveMetadata->loopStartOffsetSamples); unsigned int resampledPreloopLengthSamples = 0; unsigned int loopLengthSamples = waveMetadata->lengthSamples - preloopLengthSamples; unsigned int resampledLoopLengthSamples = 0; float *resampledPreloopData = NULL; float *resampledLoopData = NULL; preloopPadding = 0; //Check loop length is integrally divisible by block size. unsigned int loopPadSamples = alignmentSamples - (loopLengthSamples % alignmentSamples); if((loopPadSamples > 0) && (loopPadSamples < alignmentSamples)) //We need to resample the Wave. { // //Resample loop. // if(loopPadSamples > alignmentSamples / 2) { //Resample down. resampledLoopLengthSamples = loopLengthSamples - (alignmentSamples - loopPadSamples); } else { //Resample up. resampledLoopLengthSamples = loopLengthSamples + loopPadSamples; } float resamplingRatio = (float)resampledLoopLengthSamples / (float)loopLengthSamples; //Ensure that resampling does not result in a sample rate above 48kHz. if((int)ceilf(resamplingRatio * (float)(waveMetadata->sampleRate)) > 48000) { //Resample down instead. resampledLoopLengthSamples = loopLengthSamples - (alignmentSamples - loopPadSamples); resamplingRatio = (float)resampledLoopLengthSamples / (float)loopLengthSamples; } //Initialize resampler. void *resampler = resample_open(1, resamplingRatio, resamplingRatio); if(resampler == NULL) { return false; } //Allocating floating-point buffers for resampler. float *loopData = new float[loopLengthSamples]; resampledLoopData = new float[resampledLoopLengthSamples]; //Convert loop samples to floating-point. for(i=0; iwaveData))[preloopLengthSamples + i]) / 32767.0f; } //Resample loop. int resamplerSamplesIn = (int)loopLengthSamples; int resamplerSamplesOut = resample_process(resampler, resamplingRatio, loopData, resamplerSamplesIn, 1, &resamplerSamplesIn, resampledLoopData, resampledLoopLengthSamples); delete[] loopData; if((resamplerSamplesOut != (int)resampledLoopLengthSamples) || (resamplerSamplesIn != (int)loopLengthSamples)) { delete[] resampledLoopData; resample_close(resampler); return false; } if(preloopLengthSamples > 0) { // //Resample preloop. // resampledPreloopLengthSamples = (unsigned int)ceilf((float)preloopLengthSamples * resamplingRatio); //Check resampled preloop length is integrally divisible by XMA block size. unsigned int resampledPreloopPadSamples = alignmentSamples - (resampledPreloopLengthSamples % alignmentSamples); if(resampledPreloopPadSamples == alignmentSamples) { resampledPreloopPadSamples = 0; } preloopPadding = resampledPreloopPadSamples; //Allocating floating-point buffers for resampler. float *preloopData = new float[preloopLengthSamples]; resampledPreloopData = new float[resampledPreloopLengthSamples + resampledPreloopPadSamples]; if(resampledPreloopPadSamples > 0) { //Zero pad the start of the preloop. memset(resampledPreloopData, 0, resampledPreloopPadSamples * sizeof(float)); } //Convert preloop samples to floating-point. for(i=0; iwaveData))[i]) / 32767.0f; } //Resample loop. resamplerSamplesIn = (int)preloopLengthSamples; resamplerSamplesOut = resample_process(resampler, resamplingRatio, preloopData, resamplerSamplesIn, 1, &resamplerSamplesIn, resampledPreloopData + resampledPreloopPadSamples, resampledPreloopLengthSamples); delete[] preloopData; if((resamplerSamplesOut != (int)resampledPreloopLengthSamples) || (resamplerSamplesIn != (int)preloopLengthSamples)) { delete[] resampledPreloopData; delete[] resampledLoopData; resample_close(resampler); return false; } resampledPreloopLengthSamples += resampledPreloopPadSamples; } //preloopLengthSamples > 0 resample_close(resampler); waveMetadata->lengthSamples = resampledPreloopLengthSamples + resampledLoopLengthSamples; waveMetadata->lengthBytes = waveMetadata->lengthSamples * 2; waveMetadata->loopStartOffsetSamples = resampledPreloopLengthSamples; waveMetadata->sampleRate = (unsigned short)ceilf((float)(waveMetadata->sampleRate) * resamplingRatio); //Convert resampled Wave data back to 16-bit PCM. short *aligmentBuffer = new short[waveMetadata->lengthSamples]; for(i=0; iwaveData; waveMetadata->waveData = (void *)aligmentBuffer; if(resampledPreloopData) { delete[] resampledPreloopData; } if(resampledLoopData) { delete[] resampledLoopData; } } //(loopPadSamples > 0) && (loopPadSamples < alignmentSamples) else if(preloopLengthSamples > 0) { //Check preloop length is integrally divisible by block size. unsigned int preloopPadSamples = alignmentSamples - (preloopLengthSamples % alignmentSamples); if((preloopPadSamples > 0) && (preloopPadSamples < alignmentSamples)) //We need to zero pad the preloop. { //Zero pad preloop to align. short *aligmentBuffer = new short[waveMetadata->lengthSamples + preloopPadSamples]; memset(aligmentBuffer, 0, preloopPadSamples * sizeof(short)); memcpy(aligmentBuffer + preloopPadSamples, waveMetadata->waveData, waveMetadata->lengthSamples * sizeof(short)); delete[] waveMetadata->waveData; waveMetadata->waveData = (void *)aligmentBuffer; waveMetadata->lengthSamples += preloopPadSamples; waveMetadata->lengthBytes = waveMetadata->lengthSamples * 2; waveMetadata->loopStartOffsetSamples += preloopPadSamples; preloopPadding = preloopPadSamples; } } return true; } unsigned short audWaveEncoder::FlipEndian(unsigned short value) { unsigned char b1, b2; b1 = (unsigned char)(value & 255); b2 = (unsigned char)((value >> 8) & 255); value = (b1 << 8) + b2; return value; } unsigned int audWaveEncoder::FlipEndian(unsigned int value) { unsigned char b1, b2, b3, b4; b1 = (unsigned char)(value & 255); b2 = (unsigned char)((value >> 8 ) & 255); b3 = (unsigned char)((value >> 16 ) & 255); b4 = (unsigned char)((value >> 24 ) & 255); value = ((unsigned int)b1 << 24) + ((unsigned int)b2 << 16) + ((unsigned int)b3 << 8) + b4; return value; } unsigned __int64 audWaveEncoder::FlipEndian(unsigned __int64 value) { union { unsigned __int64 i; unsigned char b[8]; } dat1, dat2; dat1.i = value; dat2.b[0] = dat1.b[7]; dat2.b[1] = dat1.b[6]; dat2.b[2] = dat1.b[5]; dat2.b[3] = dat1.b[4]; dat2.b[4] = dat1.b[3]; dat2.b[5] = dat1.b[2]; dat2.b[6] = dat1.b[1]; dat2.b[7] = dat1.b[0]; return dat2.i; } } // namespace audWaveEncoding