580 lines
17 KiB
C++
580 lines
17 KiB
C++
//
|
|
// tools/audwaveencoder/waveencoder_psn.cpp
|
|
//
|
|
// Copyright (C) 1999-2006 Rockstar Games. All Rights Reserved.
|
|
//
|
|
|
|
#include "stdafx.h"
|
|
#include "forceinclude/win32_release.h"
|
|
|
|
#ifdef __PPU
|
|
#undef __PPU
|
|
#endif // __PPU
|
|
#define __PPU 1
|
|
|
|
#include "waveencoder_psn.h"
|
|
|
|
typedef float FLOAT;
|
|
|
|
#include "lame.h"
|
|
#include "lame_global_flags.h"
|
|
#include "math.h"
|
|
|
|
using namespace audBuildCommon;
|
|
using namespace Microsoft::Win32;
|
|
using namespace System;
|
|
using namespace System::IO;
|
|
using namespace System::Runtime::InteropServices;
|
|
|
|
namespace audWaveEncoding
|
|
{
|
|
|
|
const int g_NumValidSampleRates = 9;
|
|
const int g_ValidSampleRates[g_NumValidSampleRates] =
|
|
{
|
|
8000,
|
|
11025,
|
|
12000,
|
|
16000,
|
|
22050,
|
|
24000,
|
|
32000,
|
|
44100,
|
|
48000
|
|
};
|
|
|
|
enum audMpegVersions
|
|
{
|
|
MPEG1,
|
|
MPEG2,
|
|
MPEG2_5
|
|
};
|
|
|
|
const int g_MpegVersionTable[] =
|
|
{
|
|
MPEG2_5,
|
|
-1,
|
|
MPEG2,
|
|
MPEG1
|
|
};
|
|
|
|
enum audMpegLayers
|
|
{
|
|
LAYER1,
|
|
LAYER2,
|
|
LAYER3
|
|
};
|
|
|
|
const int g_MpegLayerTable[] =
|
|
{
|
|
-1,
|
|
LAYER3,
|
|
LAYER2,
|
|
LAYER1
|
|
};
|
|
|
|
const int g_MpegSlotBytes[] =
|
|
{
|
|
4, //LAYER1
|
|
1, //LAYER2
|
|
1 //LAYER3
|
|
};
|
|
|
|
const int g_Mpeg1BitrateTable[16][3] =
|
|
{
|
|
-1, -1, -1,
|
|
32, 32, 32,
|
|
64, 48, 40,
|
|
96, 56, 48,
|
|
128, 64, 56,
|
|
160, 80, 64,
|
|
192, 96, 80,
|
|
224, 112, 96,
|
|
256, 128, 112,
|
|
288, 160, 128,
|
|
320, 192, 160,
|
|
352, 224, 192,
|
|
384, 256, 224,
|
|
416, 320, 256,
|
|
448, 384, 320,
|
|
-1, -1, -1
|
|
};
|
|
|
|
const int g_Mpeg2BitrateTable[16][3] =
|
|
{
|
|
-1, -1, -1,
|
|
32, 8, 8,
|
|
48, 16, 16,
|
|
56, 24, 24,
|
|
64, 32, 32,
|
|
80, 40, 40,
|
|
96, 48, 48,
|
|
112, 56, 56,
|
|
128, 64, 64,
|
|
144, 80, 80,
|
|
160, 96, 96,
|
|
176, 112, 112,
|
|
192, 128, 128,
|
|
224, 144, 144,
|
|
256, 160, 160,
|
|
-1, -1, -1
|
|
};
|
|
|
|
const int g_MpegSampleRateTable[4][3] =
|
|
{
|
|
44100, 22050, 11025,
|
|
48000, 24000, 12000,
|
|
32000, 16000, 8000,
|
|
-1, -1, -1
|
|
};
|
|
|
|
static const unsigned int g_Mp3BlockSamples = 1152; //Align to the largest possible frame size for now.
|
|
|
|
const int g_Mp3FileBufferBytes = 5*1024*1024;
|
|
|
|
audWaveEncoderPSN::audWaveEncoderPSN(String * /*fileFullLocalPath*/)
|
|
{
|
|
}
|
|
|
|
bool audWaveEncoderPSN::Encode
|
|
(
|
|
audWaveMetadataBaseWrapper *waveMetadataIn,
|
|
unsigned int waveSampleDataOffsetBytes,
|
|
|
|
void **waveMetadataOut,
|
|
unsigned int &waveMetadataOutLengthBytes,
|
|
void **waveSampleDataOut,
|
|
unsigned int &waveSampleDataOutLengthBytes,
|
|
|
|
int compression,
|
|
int &preloopPadding,
|
|
unsigned int &
|
|
)
|
|
{
|
|
preloopPadding = 0;
|
|
|
|
audWaveMetadataBase *waveBaseMetadataIn = waveMetadataIn->GetMetadata();
|
|
|
|
//Round input sample rate up to next valid MPEG setting and resample.
|
|
int inputSampleRate = (int)waveBaseMetadataIn->sampleRate;
|
|
int targetSampleRate = g_ValidSampleRates[0];
|
|
for(int i=0; i<g_NumValidSampleRates; i++)
|
|
{
|
|
if(inputSampleRate <= g_ValidSampleRates[i])
|
|
{
|
|
targetSampleRate = g_ValidSampleRates[i];
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(!Resample(waveMetadataIn, targetSampleRate))
|
|
{
|
|
fprintf(stderr, "Failed to resample wave data to a valid MPEG sample rate\n");
|
|
return false;
|
|
}
|
|
|
|
if((waveBaseMetadataIn->loopStartOffsetSamples >= 0) && !PreProcessLoop(waveBaseMetadataIn, preloopPadding))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
unsigned int samplesPerFrame;
|
|
if(!EncodeMp3(waveBaseMetadataIn, waveSampleDataOut, waveSampleDataOutLengthBytes, compression, targetSampleRate,
|
|
samplesPerFrame))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
//Generate a seek table by parsing the generated data.
|
|
unsigned short *seekTable;
|
|
unsigned int numFrames;
|
|
if(!GenerateSeekTable((unsigned char *)(*waveSampleDataOut), waveSampleDataOutLengthBytes, samplesPerFrame,
|
|
&seekTable, numFrames))
|
|
{
|
|
delete[] *waveSampleDataOut;
|
|
return false;
|
|
}
|
|
|
|
//Trim sample and seek table frames.
|
|
unsigned short *trimmedSeekTable;
|
|
PostProcessMp3Frames(waveBaseMetadataIn, waveSampleDataOut, waveSampleDataOutLengthBytes, samplesPerFrame,
|
|
seekTable, numFrames, &trimmedSeekTable);
|
|
|
|
//Write out to a test MP3 file.
|
|
//WriteMp3File(waveBaseMetadataIn, *waveSampleDataOut, waveSampleDataOutLengthBytes);
|
|
|
|
waveBaseMetadataIn->lengthSamples = numFrames * samplesPerFrame;
|
|
|
|
audWaveMetadata encodedWaveMetadata;
|
|
|
|
//Convert metadata to platform endianness.
|
|
const unsigned int waveFlags = WAVEFLAGS_PSN_MP3;
|
|
unsigned __int64 waveDataOffsetBytes = (unsigned __int64)waveSampleDataOffsetBytes;
|
|
encodedWaveMetadata.base.waveDataOffsetBytes = audPlatformSpecific::FixEndian(waveDataOffsetBytes);
|
|
encodedWaveMetadata.base.lengthBytes = audPlatformSpecific::FixEndian((unsigned int)waveSampleDataOutLengthBytes);
|
|
encodedWaveMetadata.base.lengthSamples = audPlatformSpecific::FixEndian(waveBaseMetadataIn->lengthSamples);
|
|
encodedWaveMetadata.base.loopStartOffsetSamples = (int)audPlatformSpecific::FixEndian((unsigned int)waveBaseMetadataIn->
|
|
loopStartOffsetSamples);
|
|
encodedWaveMetadata.base.sampleRate = audPlatformSpecific::FixEndian(waveBaseMetadataIn->sampleRate);
|
|
encodedWaveMetadata.base.headroom = (short)audPlatformSpecific::FixEndian((unsigned short)waveBaseMetadataIn->headroom);
|
|
encodedWaveMetadata.base.flags = audPlatformSpecific::FixEndian(waveFlags);
|
|
|
|
encodedWaveMetadata.platform.samplesPerFrame = audPlatformSpecific::FixEndian(samplesPerFrame);
|
|
encodedWaveMetadata.platform.numFrames = audPlatformSpecific::FixEndian(numFrames);
|
|
unsigned __int64 seekTableOffsetBytes = (unsigned __int64)sizeof(audWaveMetadata);
|
|
encodedWaveMetadata.platform.seekTableOffsetBytes = FlipEndian(seekTableOffsetBytes);
|
|
|
|
waveMetadataOutLengthBytes = sizeof(audWaveMetadata) + (numFrames * sizeof(unsigned short));
|
|
*waveMetadataOut = new unsigned char[waveMetadataOutLengthBytes];
|
|
memcpy(*waveMetadataOut, &encodedWaveMetadata, sizeof(audWaveMetadata));
|
|
memcpy(((char *)(*waveMetadataOut)) + sizeof(audWaveMetadata), trimmedSeekTable, numFrames * sizeof(unsigned short));
|
|
delete[] seekTable;
|
|
|
|
return true;
|
|
}
|
|
|
|
bool audWaveEncoderPSN::PreProcessLoop(audWaveMetadataBase *waveMetadata, int &preloopPadding)
|
|
{
|
|
//Align pre-loop and loop lengths via resampling and zero-padding.
|
|
if(!AlignLoop(waveMetadata, g_Mp3BlockSamples, preloopPadding))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if(waveMetadata->loopStartOffsetSamples == 0)
|
|
{
|
|
//Concatenate 3 full loops to present to the MP3 encoder.
|
|
short *concatenatedLoops = new short[waveMetadata->lengthSamples * 3];
|
|
for(int i=0; i<3; i++)
|
|
{
|
|
memcpy(concatenatedLoops + (i * waveMetadata->lengthSamples), waveMetadata->waveData,
|
|
waveMetadata->lengthSamples * sizeof(short));
|
|
}
|
|
|
|
delete[] waveMetadata->waveData;
|
|
waveMetadata->waveData = concatenatedLoops;
|
|
waveMetadata->lengthSamples *= 3;
|
|
}
|
|
else
|
|
{
|
|
//Concatenate 3 full loops onto the preloop to present to the MP3 encoder.
|
|
// - moving the loop point to the end of the first loop.
|
|
unsigned int loopLengthSamples = waveMetadata->lengthSamples -
|
|
(unsigned int)waveMetadata->loopStartOffsetSamples;
|
|
unsigned int numConcatenatedSamples = (unsigned int)waveMetadata->loopStartOffsetSamples +
|
|
(loopLengthSamples * 3);
|
|
short *concatenatedLoops = new short[numConcatenatedSamples];
|
|
|
|
//Copy preloop.
|
|
memcpy(concatenatedLoops, waveMetadata->waveData, waveMetadata->loopStartOffsetSamples * sizeof(short));
|
|
//Copy loop 3 times.
|
|
for(unsigned int i=0; i<3; i++)
|
|
{
|
|
memcpy(concatenatedLoops + waveMetadata->loopStartOffsetSamples +
|
|
(i * loopLengthSamples), ((short *)waveMetadata->waveData) +
|
|
waveMetadata->loopStartOffsetSamples, loopLengthSamples * sizeof(short));
|
|
}
|
|
|
|
delete[] waveMetadata->waveData;
|
|
waveMetadata->waveData = concatenatedLoops;
|
|
waveMetadata->lengthSamples = numConcatenatedSamples;
|
|
//Move the loop point to the end of the first loop.
|
|
waveMetadata->loopStartOffsetSamples += loopLengthSamples;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool audWaveEncoderPSN::EncodeMp3(audWaveMetadataBase *waveMetadata, void **waveSampleDataOut,
|
|
unsigned int &waveSampleDataOutLengthBytes, int compression, int sampleRate, unsigned int &samplesPerFrame)
|
|
{
|
|
//Map compression setting to MP3 VBR quality - 0(best) to 9(worst).
|
|
int vbrQuality = 10 - (int)ceil((float)compression / 10.0f);
|
|
if(vbrQuality == 10)
|
|
{
|
|
vbrQuality = 9; //Compression setting 0 will give the same compression as 1 to 10.
|
|
}
|
|
|
|
lame_global_flags *globalFlags = lame_init();
|
|
lame_set_bWriteVbrTag(globalFlags, 0); //No header.
|
|
lame_set_num_samples(globalFlags, waveMetadata->lengthSamples);
|
|
lame_set_in_samplerate(globalFlags, sampleRate);
|
|
lame_set_num_channels(globalFlags, 1); //We only support mono input.
|
|
lame_set_out_samplerate(globalFlags, sampleRate);
|
|
lame_set_quality(globalFlags, 2); //Use a better (but slower) quality compression algorithm.
|
|
lame_set_VBR(globalFlags, vbr_default);
|
|
lame_set_VBR_q(globalFlags, vbrQuality);
|
|
lame_set_lowpassfreq(globalFlags, -1); //Disable low-pass filtering.
|
|
lame_set_highpassfreq(globalFlags, -1); //Disable high-pass filtering.
|
|
lame_set_disable_reservoir(globalFlags, 1); //Disable the bit reservoir to allow seeking/looping to an arbitrary frame.
|
|
lame_init_params(globalFlags);
|
|
|
|
if(0 == lame_get_version(globalFlags))
|
|
{
|
|
// For MPEG-II, only 576 samples per frame per channel
|
|
samplesPerFrame = 576;
|
|
}
|
|
else
|
|
{
|
|
// For MPEG-I, 1152 samples per frame per channel
|
|
samplesPerFrame = 1152;
|
|
}
|
|
|
|
//Zero-pad the raw wave data (into a new buffer) to ensure it aligns to the frame size.
|
|
unsigned int paddingSamples = samplesPerFrame - (waveMetadata->lengthSamples % samplesPerFrame);
|
|
if(paddingSamples == samplesPerFrame)
|
|
{
|
|
paddingSamples = 0;
|
|
}
|
|
|
|
waveMetadata->lengthBytes = waveMetadata->lengthSamples * 2;
|
|
unsigned int unpaddedLengthBytes = waveMetadata->lengthBytes;
|
|
waveMetadata->lengthSamples += paddingSamples;
|
|
waveMetadata->lengthBytes += paddingSamples * 2;
|
|
|
|
unsigned char *paddedBuffer = new unsigned char[waveMetadata->lengthBytes];
|
|
memcpy(paddedBuffer, waveMetadata->waveData, unpaddedLengthBytes);
|
|
if(paddingSamples > 0)
|
|
{
|
|
memset(paddedBuffer + unpaddedLengthBytes, 0, paddingSamples * 2);
|
|
}
|
|
|
|
int encodedBufferBytes = (5 * waveMetadata->lengthSamples / 4) + 7200;
|
|
unsigned char *encodeBuffer = new unsigned char [encodedBufferBytes];
|
|
|
|
int bytesEncoded;
|
|
int totalBytesEncoded = 0;
|
|
for(unsigned int inputSampleOffset=0; inputSampleOffset<waveMetadata->lengthSamples; inputSampleOffset+=samplesPerFrame)
|
|
{
|
|
bytesEncoded = lame_encode_buffer(globalFlags, ((const short *)paddedBuffer) + inputSampleOffset,
|
|
NULL, samplesPerFrame, encodeBuffer + totalBytesEncoded, encodedBufferBytes - totalBytesEncoded);
|
|
|
|
if(bytesEncoded < 0)
|
|
{
|
|
fprintf(stderr, "LAME error encoding MP3\n");
|
|
lame_close(globalFlags);
|
|
delete[] paddedBuffer;
|
|
delete[] encodeBuffer;
|
|
return false;
|
|
}
|
|
|
|
totalBytesEncoded += bytesEncoded;
|
|
}
|
|
|
|
bytesEncoded = lame_encode_flush(globalFlags, encodeBuffer + totalBytesEncoded, encodedBufferBytes - totalBytesEncoded);
|
|
|
|
delete[] paddedBuffer;
|
|
|
|
if(bytesEncoded < 0)
|
|
{
|
|
fprintf(stderr, "LAME error encoding MP3\n");
|
|
lame_close(globalFlags);
|
|
delete[] encodeBuffer;
|
|
return false;
|
|
}
|
|
|
|
totalBytesEncoded += bytesEncoded;
|
|
lame_close(globalFlags);
|
|
|
|
*waveSampleDataOut = encodeBuffer;
|
|
waveSampleDataOutLengthBytes = totalBytesEncoded;
|
|
|
|
return true;
|
|
}
|
|
|
|
bool audWaveEncoderPSN::GenerateSeekTable(unsigned char *waveSampleDataOut,
|
|
unsigned int waveSampleDataOutLengthBytes, unsigned int samplesPerFrame, unsigned short **seekTable,
|
|
unsigned int &numFrames)
|
|
{
|
|
//Let's go crazy and allocate enough memory for 1-byte frames - just to be on the safe side...
|
|
*seekTable = new unsigned short [waveSampleDataOutLengthBytes];
|
|
numFrames = 0;
|
|
|
|
unsigned char *frame;
|
|
for(unsigned int byteOffset=0; byteOffset<waveSampleDataOutLengthBytes; byteOffset++)
|
|
{
|
|
frame = waveSampleDataOut + byteOffset;
|
|
|
|
//Find the frame sync.
|
|
if((frame[0] == 0xFF) && ((frame[1] & 0xE0) == 0xE0))
|
|
{
|
|
/*unsigned int privateBit = frame[2] & 0x1;
|
|
unsigned int channelMode = (frame[3] >> 6) & 0x3;
|
|
unsigned int modeExtension = (frame[3] >> 4) & 0x3;
|
|
unsigned int copyright = (frame[3] >> 3) & 0x1;
|
|
unsigned int original = (frame[3] >> 2) & 0x1;
|
|
unsigned int emphasis = frame[3] & 0x3;*/
|
|
|
|
unsigned int versionIndex = (frame[1] >> 3) & 0x3;
|
|
int version = g_MpegVersionTable[versionIndex];
|
|
if(version < 0)
|
|
{
|
|
fprintf(stderr, "Invalid MPEG version\n");
|
|
delete[] seekTable;
|
|
return false;
|
|
}
|
|
|
|
unsigned int layerIndex = (frame[1] >> 1) & 0x3;
|
|
int layer = g_MpegLayerTable[layerIndex];
|
|
if(layer < 0)
|
|
{
|
|
fprintf(stderr, "Invalid MPEG layer\n");
|
|
delete[] seekTable;
|
|
return false;
|
|
}
|
|
|
|
unsigned int bitrateIndex = (frame[2] >> 4) & 0xF;
|
|
int bitrate;
|
|
if(version == MPEG1)
|
|
{
|
|
bitrate = g_Mpeg1BitrateTable[bitrateIndex][layer] * 1000;
|
|
}
|
|
else
|
|
{
|
|
bitrate = g_Mpeg2BitrateTable[bitrateIndex][layer] * 1000;
|
|
}
|
|
|
|
if(bitrate < 0)
|
|
{
|
|
fprintf(stderr, "Invalid MPEG bitrate\n");
|
|
delete[] seekTable;
|
|
return false;
|
|
}
|
|
|
|
unsigned int sampleRateIndex = (frame[2] >> 2) & 0x3;
|
|
int sampleRate = g_MpegSampleRateTable[sampleRateIndex][version];
|
|
if(sampleRate < 0)
|
|
{
|
|
fprintf(stderr, "Invalid MPEG sample rate\n");
|
|
delete[] seekTable;
|
|
return false;
|
|
}
|
|
|
|
unsigned int padding = (frame[2] >> 1) & 0x1;
|
|
int paddingBytes = padding * g_MpegSlotBytes[layer];
|
|
|
|
int frameBytes = ((samplesPerFrame / 8 * bitrate) / sampleRate) + paddingBytes;
|
|
|
|
unsigned int protection = frame[1] & 0x01;
|
|
if(protection == 0)
|
|
{
|
|
//There should be a 16-bit CRC at the end of the header.
|
|
frameBytes += 2;
|
|
}
|
|
|
|
(*seekTable)[numFrames] = audPlatformSpecific::FixEndian((unsigned short)frameBytes);
|
|
numFrames++;
|
|
|
|
//Jump to the end of this frame.
|
|
byteOffset += frameBytes - 1;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void audWaveEncoderPSN::PostProcessMp3Frames(audWaveMetadataBase *waveMetadata, void **waveSampleDataOut,
|
|
unsigned int &waveSampleDataOutLengthBytes, unsigned int samplesPerFrame, unsigned short *seekTable,
|
|
unsigned int &numFrames, unsigned short **trimmedSeekTable)
|
|
{
|
|
if(waveMetadata->loopStartOffsetSamples == 0)
|
|
{
|
|
//Extract the central loop from the 3 concatenated loops we encoded.
|
|
unsigned int startFrame = ((numFrames - 2) / 3) + 1; //Trim the frame of silence at the start and end.
|
|
unsigned int endFrame = ((numFrames - 2) * 2 / 3) + 1; //Trim the frame of silence at the start and end.
|
|
|
|
unsigned int startOffsetBytes = 0;
|
|
unsigned int sizeBytes = 0;
|
|
for(unsigned int i=0; i<startFrame; i++)
|
|
{
|
|
startOffsetBytes += (unsigned int)audPlatformSpecific::FixEndian(seekTable[i]);
|
|
}
|
|
|
|
for(unsigned int i=startFrame; i<endFrame; i++)
|
|
{
|
|
sizeBytes += (unsigned int)audPlatformSpecific::FixEndian(seekTable[i]);
|
|
}
|
|
|
|
unsigned char *extractedLoop = new unsigned char[sizeBytes];
|
|
memcpy(extractedLoop, (unsigned char *)(*waveSampleDataOut) + startOffsetBytes, sizeBytes);
|
|
delete[] *waveSampleDataOut;
|
|
*waveSampleDataOut = extractedLoop;
|
|
|
|
*trimmedSeekTable = seekTable + startFrame;
|
|
numFrames = endFrame - startFrame;
|
|
|
|
waveSampleDataOutLengthBytes = sizeBytes;
|
|
}
|
|
else if(waveMetadata->loopStartOffsetSamples > 0)
|
|
{
|
|
//Cut the 3rd loop off the end of the preloop and 3 loops we encoded.
|
|
unsigned int loopLengthSamples = (waveMetadata->lengthSamples - waveMetadata->loopStartOffsetSamples) / 2;
|
|
unsigned int endSample = waveMetadata->loopStartOffsetSamples + loopLengthSamples;
|
|
numFrames = (endSample / samplesPerFrame) + 1; //Take the frame of silence at the start into account.
|
|
|
|
waveSampleDataOutLengthBytes = 0;
|
|
//Strip the first frame of silent MP3 data.
|
|
for(unsigned int i=1; i<numFrames; i++)
|
|
{
|
|
waveSampleDataOutLengthBytes += (unsigned int)audPlatformSpecific::FixEndian(seekTable[i]);
|
|
}
|
|
|
|
unsigned char *trimmedEncodedBuffer = new unsigned char[waveSampleDataOutLengthBytes];
|
|
memcpy(trimmedEncodedBuffer, (unsigned char *)(*waveSampleDataOut) + audPlatformSpecific::FixEndian(seekTable[0]),
|
|
waveSampleDataOutLengthBytes);
|
|
delete[] *waveSampleDataOut;
|
|
*waveSampleDataOut = trimmedEncodedBuffer;
|
|
|
|
*trimmedSeekTable = seekTable + 1;
|
|
numFrames--;
|
|
}
|
|
else if(numFrames > 2)
|
|
{
|
|
//Strip the first and last frames of silent MP3 data.
|
|
waveSampleDataOutLengthBytes -= audPlatformSpecific::FixEndian(seekTable[0]) +
|
|
audPlatformSpecific::FixEndian(seekTable[numFrames - 1]);
|
|
unsigned char *trimmedEncodedBuffer = new unsigned char[waveSampleDataOutLengthBytes];
|
|
memcpy(trimmedEncodedBuffer, (unsigned char *)(*waveSampleDataOut) + audPlatformSpecific::FixEndian(seekTable[0]),
|
|
waveSampleDataOutLengthBytes);
|
|
delete[] *waveSampleDataOut;
|
|
*waveSampleDataOut = trimmedEncodedBuffer;
|
|
|
|
*trimmedSeekTable = seekTable + 1;
|
|
numFrames -= 2;
|
|
}
|
|
else
|
|
{
|
|
*trimmedSeekTable = seekTable;
|
|
}
|
|
}
|
|
|
|
void audWaveEncoderPSN::WriteMp3File(audWaveMetadataBase *waveMetadata, void *waveSampleDataOut, unsigned int waveSampleDataOutLengthBytes)
|
|
{
|
|
BinaryWriter *mp3FileOut = NULL;
|
|
|
|
try
|
|
{
|
|
FileStream *mp3FileStream = File::Open(String::Concat(S"C:/Windows/Temp/", __box(waveMetadata->nameHash), S".mp3"), FileMode::Create);
|
|
BufferedStream *mp3FileBufStream = new BufferedStream(mp3FileStream, g_Mp3FileBufferBytes);
|
|
mp3FileOut = new BinaryWriter(mp3FileBufStream);
|
|
|
|
//Convert MP3 data to a managed array and write out.
|
|
Byte managedData __gc[] = new Byte[waveSampleDataOutLengthBytes];
|
|
System::Runtime::InteropServices::Marshal::Copy(waveSampleDataOut, managedData, 0, waveSampleDataOutLengthBytes);
|
|
mp3FileOut->Write(managedData);
|
|
managedData = NULL;
|
|
|
|
//Flush data to disk.
|
|
mp3FileOut->Flush();
|
|
}
|
|
__finally
|
|
{
|
|
if(mp3FileOut)
|
|
{
|
|
mp3FileOut->Close();
|
|
}
|
|
}
|
|
}
|
|
|
|
} //namespace
|