JD2022-TU1/main/extern/Raki/Source/RakiTests/TestBinWii/TestBinWii.cpp

469 lines
15 KiB
C++

#include "Precompiled.h"
#include "RakiEngine/Initializer/TestInitializer.h"
#include "RakiEngine/Data/MemoryBlock/MemoryBlock.h"
#include "RakiEngine/Data/Serialization/Serializer.h"
#include "RakiEngine/Data/Stream/SeekableStreamPart.h"
#include "RakiEngine/Data/WaveFile/RiffChunkManager.h"
#include "RakiEngine/Data/WaveFile/WaveFile.h"
#include "RakiEngine/Data/WaveFile/WaveDataPitchConverter.h"
#include "RakiEngine/Sounds/Format.h"
#include "RakiTests/Stream/BinFileReader.h"
#include "RakiTests/Stream/ReadFileStream.h"
#include "RakiTests/Stream/WriteFileStream.h"
#ifndef RAKI_PLATFORM_WIN32
#error // this is a bin test app - only for Win32
#endif // RAKI_PLATFORM_WIN32
typedef struct
{
// for header generation during decode
u32 num_samples; // total number of RAW samples
u32 num_adpcm_nibbles; // number of ADPCM nibbles (including frame headers)
u32 sample_rate; // Sample rate, in Hz
// DSP addressing and decode context
u16 loop_flag; // 1=LOOPED, 0=NOT LOOPED
u16 format; // Always 0x0000, for ADPCM
u32 sa; // Start offset address for looped samples (zero for non-looped)
u32 ea; // End offset address for looped samples
u32 ca; // always zero
u16 coef[16]; // decode coefficients (eight pairs of 16-bit words)
// DSP decoder initial state
u16 gain; // always zero for ADPCM
u16 ps; // predictor/scale
u16 yn1; // sample history
u16 yn2; // sample history
// DSP decoder loop context
u16 lps; // predictor/scale for loop context
u16 lyn1; // sample history (n-1) for loop context
u16 lyn2; // sample history (n-2) for loop context
u16 pad[11]; // reserved
} DSPADPCM;
namespace raki
{
bool DspadcpmCompress( const char * _inputPath, const char * _outputPath, u32 _sampleSize )
{
STARTUPINFOA si = { 0 };
si.cb = sizeof(si);
si.dwFlags = STARTF_USESHOWWINDOW;
si.cbReserved2 = 0;
si.lpReserved2 = NULL;
si.wShowWindow = SW_HIDE;//SW_SHOWNORMAL;
PROCESS_INFORMATION pi = { 0 };
char cmdLine[1024];
char exePath[] = "C:\\RVL_SDK\\X86\\bin\\dspadpcm.exe";
sprintf( cmdLine, "%s -encode %s %s -l0-%d", exePath, _inputPath, _outputPath, _sampleSize -1 );
// Start the child process.
if( !CreateProcessA( NULL, // No module name (use command line).
cmdLine, // Command line.
NULL, // Process handle not inheritable.
NULL, // Thread handle not inheritable.
FALSE, // Set handle inheritance to FALSE.
0, // No creation flags.
NULL, // Use parent's environment block.
NULL, // Use parent's starting directory.
&si, // Pointer to STARTUPINFO structure.
&pi ) // Pointer to PROCESS_INFORMATION structure.
)
{
return false;
}
// Wait until child process exits.
WaitForSingleObject( pi.hProcess, INFINITE );
// Close process and thread handles.
CloseHandle( pi.hProcess );
CloseHandle( pi.hThread );
return true;
}
void WriteWaves( const WaveDataPitchConverter * _waveData, const WAVEFORMATEX * _originalFormat, const char * _originalPath, bool _interleaveStereo = true )
{
RiffChunkManager::singleton().setIsWritingToBigEndians( false );
switch( _originalFormat->nChannels )
{
case 1:
{
char inputPath[512];
sprintf( inputPath, "%s_%d.wav", _originalPath, _waveData->getSamplingRate() );
char outputPath[512];
sprintf( outputPath, "%s_%d.wii", _originalPath, _waveData->getSamplingRate() );
WaveFile output;
WAVEFORMATEX waveformatPcm = *_originalFormat;
waveformatPcm.nSamplesPerSec = _waveData->getSamplingRate();
waveformatPcm.nAvgBytesPerSec = 2 * waveformatPcm.nSamplesPerSec;
output.createEmptyRiffChunk();
output.addChunk( "fmt ", sizeof( WAVEFORMATEX ), &waveformatPcm );
output.addChunk( "data", waveformatPcm.nBlockAlign * _waveData->getSampleSize(), _waveData->getData() );
output.recalculateRiffAndListSizes();
WriteFileStream wave;
if ( wave.open( inputPath ) )
{
Serializer writeSerializer( &wave );
output.write( writeSerializer );
}
wave.close();
DspadcpmCompress( inputPath, outputPath, _waveData->getSampleSize() );
// now make bin
BinFileReader binFileReader;
binFileReader.readFrom( outputPath );
WAVEFORMATEX waveformatAdpcm = waveformatPcm;
waveformatAdpcm.wFormatTag = WAVE_FORMAT_ADPCM;
WaveFile outputBin;
outputBin.createEmptyRiffChunk();
outputBin.addChunk( "fmt ", sizeof( WAVEFORMATEX ), &waveformatAdpcm );
outputBin.addChunk( "dspL", sizeof( DSPADPCM ), binFileReader.getData() );
outputBin.addChunk( "datL", (u32)( binFileReader.getSize() - sizeof( DSPADPCM ) ), (void*)( sizeof( DSPADPCM ) + (u64)binFileReader.getData() ) );
outputBin.recalculateRiffAndListSizes();
outputBin.changeToBigEndian();
char binPath[512];
sprintf( binPath, "%s_%d.bin", _originalPath, _waveData->getSamplingRate() );
RiffChunkManager::singleton().setIsWritingToBigEndians( true );
WriteFileStream bin;
if ( bin.open( binPath ) )
{
Serializer writeSerializer( &bin );
outputBin.write( writeSerializer );
}
bin.close();
DeleteFileA( inputPath );
DeleteFileA( outputPath );
}
break;
case 2:
{
WAVEFORMATEX waveformatPcm = *_originalFormat;
waveformatPcm.wFormatTag = WAVE_FORMAT_PCM;
waveformatPcm.nChannels = 1;
waveformatPcm.nBlockAlign = 2;
waveformatPcm.nSamplesPerSec = _waveData->getSamplingRate();
waveformatPcm.nAvgBytesPerSec = 2 * waveformatPcm.nSamplesPerSec;
// left data
char inputPathL[512];
sprintf( inputPathL, "%s_L_%d.wav", _originalPath, _waveData->getSamplingRate() );
char outputPathL[512];
sprintf( outputPathL, "%s_L_%d.wii", _originalPath, _waveData->getSamplingRate() );
WaveFile outputL;
outputL.createEmptyRiffChunk();
outputL.addChunk( "fmt ", sizeof( WAVEFORMATEX ), &waveformatPcm );
outputL.addChunk( "data", waveformatPcm.nBlockAlign * _waveData->getSampleSize(), _waveData->getData() );
outputL.recalculateRiffAndListSizes();
WriteFileStream waveL;
if ( waveL.open( inputPathL ) )
{
Serializer writeSerializer( &waveL );
outputL.write( writeSerializer );
}
waveL.close();
DspadcpmCompress( inputPathL, outputPathL, _waveData->getSampleSize() );
// right data
char inputPathR[512];
sprintf( inputPathR, "%s_R_%d.wav", _originalPath, _waveData->getSamplingRate() );
char outputPathR[512];
sprintf( outputPathR, "%s_R_%d.wii", _originalPath, _waveData->getSamplingRate() );
WaveFile outputR;
outputR.createEmptyRiffChunk();
outputR.addChunk( "fmt ", sizeof( WAVEFORMATEX ), &waveformatPcm );
outputR.addChunk( "data", waveformatPcm.nBlockAlign * _waveData->getSampleSize(), _waveData->getRightData() );
outputR.recalculateRiffAndListSizes();
WriteFileStream waveR;
if ( waveR.open( inputPathR ) )
{
Serializer writeSerializer( &waveR );
outputR.write( writeSerializer );
}
waveR.close();
DspadcpmCompress( inputPathR, outputPathR, _waveData->getSampleSize() );
// now make bin
BinFileReader binFileReaderL;
binFileReaderL.readFrom( outputPathL );
BinFileReader binFileReaderR;
binFileReaderR.readFrom( outputPathR );
WAVEFORMATEX waveformatAdpcm = waveformatPcm;
waveformatAdpcm.wFormatTag = WAVE_FORMAT_ADPCM;
waveformatAdpcm.nChannels = 2;
WaveFile outputBin;
outputBin.createEmptyRiffChunk();
outputBin.addChunk( "fmt ", sizeof( WAVEFORMATEX ), &waveformatAdpcm );
outputBin.addChunk( "dspL", sizeof( DSPADPCM ), binFileReaderL.getData() );
outputBin.addChunk( "dspR", sizeof( DSPADPCM ), binFileReaderR.getData() );
if ( _interleaveStereo )
{
// interleave on aligned size...
u32 channelSize = (u32)binFileReaderL.getSize() - sizeof( DSPADPCM );
RAKI_ASSERT( channelSize == ( binFileReaderR.getSize() - sizeof( DSPADPCM ) ) );
if ( channelSize % 8 )
channelSize = ( channelSize + 8 ) & 0xfffffff8;
MemoryBlock blockL( channelSize );
Memory::memcpy( blockL.getBuffer(), (void*)( sizeof( DSPADPCM ) + (u64)binFileReaderL.getData() ), (u32)binFileReaderL.getSize() - sizeof( DSPADPCM ) );
MemoryBlock blockR( channelSize );
Memory::memcpy( blockR.getBuffer(), (void*)( sizeof( DSPADPCM ) + (u64)binFileReaderR.getData() ), (u32)binFileReaderR.getSize() - sizeof( DSPADPCM ) );
MemoryBlock block( 2 * channelSize );
u32 * srcL = (u32*) blockL.getBuffer();
u32 * srcR = (u32*) blockR.getBuffer();
u32 * dst = (u32*) block.getBuffer();
for ( u32 u = 0 ; u < ( channelSize / 8 ) ; ++u )
{
*dst++ = *srcL++;
*dst++ = *srcL++;
*dst++ = *srcR++;
*dst++ = *srcR++;
}
outputBin.addChunk( "datS", (u32)block.getSize(), block.getBuffer() );
}
else
{
outputBin.addChunk( "datL", (u32)( binFileReaderL.getSize() - sizeof( DSPADPCM ) ), (void*)( sizeof( DSPADPCM ) + (u64)binFileReaderL.getData() ) );
outputBin.addChunk( "datR", (u32)( binFileReaderR.getSize() - sizeof( DSPADPCM ) ), (void*)( sizeof( DSPADPCM ) + (u64)binFileReaderR.getData() ) );
}
outputBin.recalculateRiffAndListSizes();
outputBin.changeToBigEndian();
char binPath[512];
sprintf( binPath, "%s_%d.bin", _originalPath, _waveData->getSamplingRate() );
RiffChunkManager::singleton().setIsWritingToBigEndians( true );
WriteFileStream bin;
if ( bin.open( binPath ) )
{
Serializer writeSerializer( &bin );
outputBin.write( writeSerializer );
}
bin.close();
DeleteFileA( inputPathL );
DeleteFileA( outputPathL );
DeleteFileA( inputPathR );
DeleteFileA( outputPathR );
}
break;
}
}
bool convertTo32AndByteSwap( const char * _inputPath, const char * _outputPath )
{
RiffChunkManager::singleton().setIsWritingToBigEndians( false );
RiffChunkManager::singleton().setShouldReadDataBlockForWaveData( true );
ReadFileStream inputStream;
if ( !inputStream.open( _inputPath ) )
return false;
const char fmtType[] = "fmt ";
WaveFile inputWaveFile;
Serializer readSerializer( &inputStream );
inputWaveFile.serialize( readSerializer );
if ( !inputWaveFile.getChunkData( fmtType ) )
return false;
WAVEFORMATEX * format = (WAVEFORMATEX*)inputWaveFile.getChunkData( fmtType );
if ( format->nSamplesPerSec != 48000 )
return false;
void * data = inputWaveFile.getChunkData( "data" );
u32 sampleSize = inputWaveFile.getChunkSize( "data" ) / (u32) format->nBlockAlign;
WAVEFORMATEX * _originalFormat = ( WAVEFORMATEX * ) inputWaveFile.getChunkData( fmtType );
WaveDataPitchConverter convert( data, sampleSize, 48000, 32000, _originalFormat->nChannels, false );
WAVEFORMATEX waveformat = *_originalFormat;
waveformat.nSamplesPerSec = 32000;
waveformat.nAvgBytesPerSec = waveformat.nBlockAlign * waveformat.nSamplesPerSec;
RiffChunkManager::singleton().setIsWritingToBigEndians( true );
WaveFile outputBin;
outputBin.createEmptyRiffChunk();
outputBin.addChunk( "fmt ", sizeof( WAVEFORMATEX ), &waveformat );
outputBin.addChunk( "data", convert.getSampleSize() * 4 , convert.getData() );
outputBin.recalculateRiffAndListSizes();
outputBin.changeToBigEndian();
WriteFileStream bin;
if ( bin.open( _outputPath ) )
{
Serializer writeSerializer( &bin );
outputBin.write( writeSerializer );
}
else
return false;
bin.close();
return true;
}
bool TestBinWii( const char * _path )
{
TestInitializer initializer;
char swapWavePath[512];
sprintf( swapWavePath, "%s_swapped.wav", _path );
if ( !convertTo32AndByteSwap( _path, swapWavePath ) )
return false;
char path_32[512];
sprintf( path_32, "%s_32.wav", _path );
RiffChunkManager::singleton().setIsWritingToBigEndians( false );
RiffChunkManager::singleton().setShouldReadDataBlockForWaveData( true );
ReadFileStream inputStream;
if ( !inputStream.open( _path ) )
return false;
const char fmtType[] = "fmt ";
WaveFile inputWaveFile;
Serializer readSerializer( &inputStream );
inputWaveFile.serialize( readSerializer );
if ( !inputWaveFile.getChunkData( fmtType ) )
return false;
WAVEFORMATEX * format = (WAVEFORMATEX*)inputWaveFile.getChunkData( fmtType );
if ( format->nSamplesPerSec != 48000 )
return false;
void * data = inputWaveFile.getChunkData( "data" );
u32 sampleSize = inputWaveFile.getChunkSize( "data" ) / (u32) format->nBlockAlign;
WaveDataPitchConverter w32( data, sampleSize, 48000, 32000, format->nChannels );
WriteWaves( &w32, format, _path );
WaveDataPitchConverter w24( data, sampleSize, 48000, 24000, format->nChannels );
WriteWaves( &w24, format, _path );
WaveDataPitchConverter w16( data, sampleSize, 48000, 16000, format->nChannels );
WriteWaves( &w16, format, _path );
/*
BinFileReader msEncFile;
if ( !msEncFile.readFrom( msEncOutputPath ) )
return false;
if ( !msEncFile.getData() )
return false;
WaveFile outputWaveFile;
outputWaveFile.createEmptyRiffChunk();
// add fmt chunk
outputWaveFile.addChunk( fmtType, inputWaveFile.getChunkSize( fmtType ), inputWaveFile.getChunkData( fmtType ) );
// add MSEnc data
outputWaveFile.addChunk( "msf ", (u32)msEncFile.getSize(), msEncFile.getData() );
outputWaveFile.recalculateRiffAndListSizes();
WriteFileStream outputFileStream;
if ( !outputFileStream.open( finalBinPath ) )
return false;
outputWaveFile.changeToBigEndian();
RiffChunkManager::singleton().setIsWritingToBigEndians( true );
Serializer writeSerializer( &outputFileStream );
outputWaveFile.serialize( writeSerializer );
if ( writeSerializer.encounteredError() )
return false;
DeleteFileA( msEncOutputPath );
*/
return true;
}
} // namespace raki
int _tmain(int argc, _TCHAR* argv[] )
{
if ( argc < 2 )
return -1;
char path[512];
wcstombs( path, argv[1], 510 );
if ( !raki::TestBinWii( path ) )
return -1;
return 0;
}