1
0
mirror of https://foundry.openuru.org/gitblit/r/CWE-ou-minkata.git synced 2025-07-18 11:19:10 +00:00

Initial Commit of CyanWorlds.com Engine Open Source Client/Plugin

This commit is contained in:
jwplatt
2011-03-12 12:34:52 -05:00
commit b970ae4bad
3976 changed files with 1301355 additions and 0 deletions

View File

@ -0,0 +1,68 @@
/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
//////////////////////////////////////////////////////////////////////////////
// //
// plAudioCore - Core, common stuff that all of the audio system needs //
// //
//////////////////////////////////////////////////////////////////////////////
#ifndef _plAudioCore_h
#define _plAudioCore_h
//// plWAVHeader Class ///////////////////////////////////////////////////////
// Just a small info class about WAV sound
class plWAVHeader
{
public:
UInt16 fFormatTag;
UInt16 fNumChannels;
UInt32 fNumSamplesPerSec;
UInt32 fAvgBytesPerSec;
UInt16 fBlockAlign;
UInt16 fBitsPerSample;
enum
{
kPCMFormatTag = 1
};
};
//// plAudioCore Konstants ///////////////////////////////////////////////////
namespace plAudioCore
{
enum ChannelSelect
{
kAll = 0,
kLeft,
kRight
};
};
#endif //_plAudioCore_h

View File

@ -0,0 +1,36 @@
/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
#ifndef plAudioCoreCreatable_inc
#define plAudioCoreCreatable_inc
#include "../pnFactory/plCreator.h"
#include "plSoundBuffer.h"
REGISTER_CREATABLE( plSoundBuffer );
#endif // plAudioCoreCreatable_inc

View File

@ -0,0 +1,169 @@
/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
//////////////////////////////////////////////////////////////////////////////
// //
// plAudioFileReader //
// //
//// Notes ///////////////////////////////////////////////////////////////////
// //
// 3.5.2001 - Created by mcn. //
// //
//////////////////////////////////////////////////////////////////////////////
#include <string.h>
#include "hsTypes.h"
#include "plAudioFileReader.h"
#include "plAudioCore.h"
//#include "hsTimer.h"
#include "hsUtils.h"
#include "../plFile/hsFiles.h"
#include "../plFile/plFileUtils.h"
#include "../plUnifiedTime/plUnifiedTime.h"
#include "plBufferedFileReader.h"
#include "plFastWavReader.h"
#include "../plAudio/plOGGCodec.h"
#include "../plAudio/plWavFile.h"
#define kCacheDirName "streamingCache"
static void hsStrUpper(char *s)
{
if (s)
{
int len = hsStrlen(s);
for (int i = 0; i < len; i++)
s[i] = toupper(s[i]);
}
}
plAudioFileReader* plAudioFileReader::CreateReader(const char* path, plAudioCore::ChannelSelect whichChan, StreamType type)
{
const char* ext = plFileUtils::GetFileExt(path);
if (type == kStreamWAV)
{
bool isWav = (stricmp(ext, "wav") == 0);
// We want to stream a wav off disk, but this is a compressed file.
// Get the uncompressed path. Ignore the requested channel, since it
// will have already been split into two files if that is necessary.
if (!isWav)
{
char cachedPath[256];
IGetCachedPath(path, cachedPath, whichChan);
plAudioFileReader *r = TRACKED_NEW plFastWAV(cachedPath, plAudioCore::kAll);
return r;
}
plAudioFileReader *r = TRACKED_NEW plFastWAV(path, whichChan);
return r;
}
else if (type == kStreamRAM)
return TRACKED_NEW plBufferedFileReader(path, whichChan);
else if (type == kStreamNative)
return TRACKED_NEW plOGGCodec(path, whichChan);
return nil;
}
plAudioFileReader* plAudioFileReader::CreateWriter(const char* path, plWAVHeader& header)
{
const char* ext = plFileUtils::GetFileExt(path);
plAudioFileReader* writer = TRACKED_NEW CWaveFile(path, plAudioCore::kAll);
writer->OpenForWriting(path, header);
return writer;
}
void plAudioFileReader::IGetCachedPath(const char* path, char* cachedPath, plAudioCore::ChannelSelect whichChan)
{
// Get the file's path and add our streaming cache folder to it
strcpy(cachedPath, path);
plFileUtils::StripFile(cachedPath);
strcat(cachedPath, kCacheDirName"\\");
// Create the directory first
plFileUtils::CreateDir(cachedPath);
// Get the path to the cached version of the file, without the extension
const char* fileName = plFileUtils::GetFileName(path);
const char* fileExt = plFileUtils::GetFileExt(fileName);
strncat(cachedPath, fileName, fileExt-fileName-1);
if (whichChan == plAudioCore::kLeft)
strcat(cachedPath, "-Left.wav");
else if (whichChan == plAudioCore::kRight)
strcat(cachedPath, "-Right.wav");
else if (whichChan == plAudioCore::kAll)
strcat(cachedPath, ".wav");
}
void plAudioFileReader::ICacheFile(const char* path, bool noOverwrite, plAudioCore::ChannelSelect whichChan)
{
char cachedPath[256];
IGetCachedPath(path, cachedPath, whichChan);
if (!noOverwrite || !plFileUtils::FileExists(cachedPath))
{
plAudioFileReader* reader = plAudioFileReader::CreateReader(path, whichChan, kStreamNative);
if (!reader || !reader->IsValid())
{
delete reader;
return;
}
plAudioFileReader* writer = CreateWriter(cachedPath, reader->GetHeader());
if (!writer || !writer->IsValid())
{
delete reader;
delete writer;
return;
}
UInt8 buffer[4096];
UInt32 numLeft;
while ((numLeft = reader->NumBytesLeft()) > 0)
{
UInt32 toRead = (numLeft < sizeof(buffer)) ? numLeft : sizeof(buffer);
reader->Read(toRead, buffer);
writer->Write(toRead, buffer);
}
writer->Close();
delete writer;
delete reader;
}
}
void plAudioFileReader::CacheFile(const char* path, bool splitChannels, bool noOverwrite)
{
if (splitChannels)
{
ICacheFile(path, noOverwrite, plAudioCore::kLeft);
ICacheFile(path, noOverwrite, plAudioCore::kRight);
}
else
{
ICacheFile(path, noOverwrite, plAudioCore::kAll);
}
}

View File

@ -0,0 +1,83 @@
/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
//////////////////////////////////////////////////////////////////////////////
// //
// plAudioFileReader - Microsoft's way of making our lives difficult when //
// reading in .WMA files. Hacking Winamp's plugins is //
// probably easier... //
// //
//////////////////////////////////////////////////////////////////////////////
#ifndef _plAudioFileReader_h
#define _plAudioFileReader_h
#include "plAudioCore.h"
#include "hsTemplates.h"
//// Class Definition ////////////////////////////////////////////////////////
class plUnifiedTime;
class plWAVHeader;
class plAudioFileReader
{
public:
virtual ~plAudioFileReader() {}
virtual plWAVHeader &GetHeader( void ) = 0;
enum StreamType
{
kStreamRAM, // Stream from a WAV loaded into RAM
kStreamWAV, // Stream from a WAV on disk
kStreamNative, // Stream from the native type (ie, an Ogg on disk)
};
virtual void Open(){}
virtual void Close( void ) = 0;
virtual UInt32 GetDataSize( void ) = 0;
virtual float GetLengthInSecs( void ) = 0;
virtual hsBool SetPosition( UInt32 numBytes ) = 0;
virtual hsBool Read( UInt32 numBytes, void *buffer ) = 0;
virtual UInt32 NumBytesLeft( void ) = 0;
virtual hsBool OpenForWriting( const char *path, plWAVHeader &header ) { return false; }
virtual UInt32 Write( UInt32 bytes, void *buffer ) { return 0; }
virtual hsBool IsValid( void ) = 0;
static plAudioFileReader* CreateReader(const char* path, plAudioCore::ChannelSelect whichChan = plAudioCore::kAll, StreamType type = kStreamWAV);
static plAudioFileReader* CreateWriter(const char* path, plWAVHeader& header);
// Decompresses a compressed file to the cache directory
static void CacheFile(const char* path, bool splitChannels=false, bool noOverwrite=false);
protected:
static void IGetCachedPath(const char* path, char* cachedPath, plAudioCore::ChannelSelect whichChan);
static void ICacheFile(const char* path, bool noOverwrite, plAudioCore::ChannelSelect whichChan);
};
#endif //_plAudioFileReader_h

View File

@ -0,0 +1,166 @@
/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
//////////////////////////////////////////////////////////////////////////////
// //
// plBufferedFileReader - Reads in a given file into a RAM buffer, then //
// "reads" from that buffer as requested. Useless //
// for normal sounds, but perfect for streaming //
// from RAM. //
// //
//// Notes ///////////////////////////////////////////////////////////////////
// //
// 11.1.2002 - Created by mcn. //
// //
//////////////////////////////////////////////////////////////////////////////
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "hsTypes.h"
#include "plBufferedFileReader.h"
//#include "plProfile.h"
//plProfile_CreateMemCounter( "BufferedRAM", "Sound", SndBufferedMem );
//// Constructor/Destructor //////////////////////////////////////////////////
plBufferedFileReader::plBufferedFileReader( const char *path, plAudioCore::ChannelSelect whichChan )
{
// Init some stuff
fBufferSize = 0;
fBuffer = nil;
fCursor = 0;
hsAssert( path != nil, "Invalid path specified in plBufferedFileReader" );
// Ask plAudioFileReader for another reader to get this file
// Note: have this reader do the chanSelect for us
plAudioFileReader *reader = plAudioFileReader::CreateReader( path, whichChan );
if( reader == nil || !reader->IsValid() )
{
delete reader;
IError( "Unable to open file to read in to RAM buffer" );
return;
}
fHeader = reader->GetHeader();
fBufferSize = reader->GetDataSize();
fBuffer = TRACKED_NEW UInt8[ fBufferSize ];
//plProfile_NewMem( SndBufferedMem, fBufferSize );
if( fBuffer == nil )
{
delete reader;
IError( "Unable to allocate RAM buffer" );
return;
}
if( !reader->Read( fBufferSize, fBuffer ) )
{
delete reader;
IError( "Unable to read file into RAM buffer" );
return;
}
// All done!
delete reader;
}
plBufferedFileReader::~plBufferedFileReader()
{
Close();
}
void plBufferedFileReader::Close( void )
{
//plProfile_DelMem( SndBufferedMem, fBufferSize );
DEL(fBuffer);;
fBuffer = nil;
fBufferSize = 0;
fCursor = 0;
}
void plBufferedFileReader::IError( const char *msg )
{
hsAssert( false, msg );
Close();
}
plWAVHeader &plBufferedFileReader::GetHeader( void )
{
hsAssert( IsValid(), "GetHeader() called on an invalid RAM buffer" );
return fHeader;
}
float plBufferedFileReader::GetLengthInSecs( void )
{
hsAssert( IsValid(), "GetLengthInSecs() called on an invalid RAM buffer" );
return (float)fBufferSize / (float)fHeader.fAvgBytesPerSec;
}
hsBool plBufferedFileReader::SetPosition( UInt32 numBytes )
{
hsAssert( IsValid(), "SetPosition() called on an invalid RAM buffer" );
if( numBytes > fBufferSize )
{
hsAssert( false, "Invalid position in SetPosition()" );
return false;
}
fCursor = numBytes;
return true;
}
hsBool plBufferedFileReader::Read( UInt32 numBytes, void *buffer )
{
hsAssert( IsValid(), "Read() called on an invalid RAM buffer" );
hsBool valid = true;
if( fCursor + numBytes > fBufferSize )
{
numBytes = fBufferSize - fCursor;
valid = false;
}
memcpy( buffer, fBuffer + fCursor, numBytes );
fCursor += numBytes;
return valid;
}
UInt32 plBufferedFileReader::NumBytesLeft( void )
{
hsAssert( IsValid(), "NumBytesLeft() called on an invalid RAM buffer" );
return fBufferSize - fCursor;
}

View File

@ -0,0 +1,66 @@
/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
//////////////////////////////////////////////////////////////////////////////
// //
// plBufferedFileReader - Reads in a given file into a RAM buffer, then //
// "reads" from that buffer as requested. Useless //
// for normal sounds, but perfect for streaming //
// from RAM. //
// //
//////////////////////////////////////////////////////////////////////////////
#ifndef _plBufferedFileReader_h
#define _plBufferedFileReader_h
#include "../plAudioCore/plAudioFileReader.h"
//// Class Definition ////////////////////////////////////////////////////////
class plBufferedFileReader : public plAudioFileReader
{
public:
plBufferedFileReader( const char *path, plAudioCore::ChannelSelect whichChan = plAudioCore::kAll );
virtual ~plBufferedFileReader();
virtual plWAVHeader &GetHeader( void );
virtual void Close( void );
virtual UInt32 GetDataSize( void ) { return fBufferSize; }
virtual float GetLengthInSecs( void );
virtual hsBool SetPosition( UInt32 numBytes );
virtual hsBool Read( UInt32 numBytes, void *buffer );
virtual UInt32 NumBytesLeft( void );
virtual hsBool IsValid( void ) { return ( fBuffer != nil ) ? true : false; }
protected:
UInt32 fBufferSize;
UInt8 *fBuffer;
plWAVHeader fHeader;
UInt32 fCursor;
void IError( const char *msg );
};
#endif //_plBufferedFileReader_h

View File

@ -0,0 +1,334 @@
/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
//////////////////////////////////////////////////////////////////////////////
// //
// plFastWavReader - Quick, dirty, and highly optimized class for reading //
// in the samples of a WAV file when you're in a hurry. //
// ONLY WORKS WITH PCM (i.e. uncompressed) DATA //
// //
//// Notes ///////////////////////////////////////////////////////////////////
// //
// 11.5.2001 - Created by mcn. //
// //
//////////////////////////////////////////////////////////////////////////////
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "hsTypes.h"
#include "plFastWavReader.h"
//// Local Helpers ///////////////////////////////////////////////////////////
class plRIFFChunk
{
public:
char fID[ 4 ];
UInt32 fSize;
void Read( FILE *fp )
{
fread( fID, 1, 4, fp );
fread( &fSize, sizeof( UInt32 ), 1, fp );
}
bool IsA( const char *type )
{
return ( memcmp( fID, type, 4 ) == 0 ) ? true : false;
}
};
class plRIFFHeader
{
protected:
plRIFFChunk fChunk;
bool fValid;
char fFormat[ 4 ];
public:
plRIFFHeader( FILE *fp )
{
fValid = false;
fChunk.Read( fp );
if( fChunk.IsA( "RIFF" ) )
{
if( fread( &fFormat, 1, 4, fp ) == 4 )
{
fValid = true;
}
}
}
bool IsValid( void )
{
return fValid;
}
bool IsA( const char *type )
{
return ( memcmp( fFormat, type, 4 ) == 0 ) ? true : false;
}
};
//// Constructor/Destructor //////////////////////////////////////////////////
plFastWAV::plFastWAV( const char *path, plAudioCore::ChannelSelect whichChan ) : fFileHandle( nil )
{
hsAssert( path != nil, "Invalid path specified in plFastWAV reader" );
strncpy( fFilename, path, sizeof( fFilename ) );
fWhichChannel = whichChan;
fFileHandle = fopen( path, "rb" );
if( fFileHandle != nil )
{
/// Read in our header and calc our start position
plRIFFHeader riffHdr( fFileHandle );
if( !riffHdr.IsValid() )
{
IError( "Invalid RIFF file header in plFastWAV" );
return;
}
if( !riffHdr.IsA( "WAVE" ) )
{
IError( "Invalid RIFF file type in plFastWAV" );
return;
}
fChunkStart = ftell( fFileHandle );
// Seek and read the "fmt " header
plRIFFChunk chunk;
if( !ISeekToChunk( "fmt ", &chunk ) )
{
IError( "Unable to find fmt chunk in WAV file" );
return;
}
if( fread( &fHeader, 1, sizeof( plWAVHeader ), fFileHandle ) != sizeof( plWAVHeader ) )
{
IError( "Invalid WAV file header in plFastWAV" );
return;
}
// Check format
if( fHeader.fFormatTag != kPCMFormatTag )
{
IError( "Invalid format in plFastWAV" );
return;
}
// Seek to and get the position of the data chunk
if( !ISeekToChunk( "data", &chunk ) )
{
IError( "Unable to find data chunk in WAV file" );
return;
}
fDataStartPos = ftell( fFileHandle );
fDataSize = chunk.fSize;
// HACKY FIX FOR BAD WAV FILES
fDataSize -= ( fDataSize & ( fHeader.fBlockAlign - 1 ) );
if( fWhichChannel != plAudioCore::kAll )
{
fChannelAdjust = 2;
fChannelOffset = ( fWhichChannel == plAudioCore::kLeft ) ? 0 : 1;
}
else
{
fChannelAdjust = 1;
fChannelOffset = 0;
}
fFakeHeader = fHeader;
fFakeHeader.fAvgBytesPerSec /= fChannelAdjust;
fFakeHeader.fNumChannels /= (UInt16)fChannelAdjust;
fFakeHeader.fBlockAlign /= (UInt16)fChannelAdjust;
SetPosition( 0 );
// fCurrDataPos = 0;
}
}
plFastWAV::~plFastWAV()
{
if( fFileHandle != nil )
fclose( fFileHandle );
}
bool plFastWAV::ISeekToChunk( const char *type, plRIFFChunk *c )
{
plRIFFChunk chunk;
// Start from chunk start and search through all the, well, chunks :)
fseek( fFileHandle, fChunkStart, SEEK_SET );
while( !feof( fFileHandle ) )
{
chunk.Read( fFileHandle );
if( chunk.IsA( type ) )
{
*c = chunk;
return true;
}
// Seek past this one
fseek( fFileHandle, chunk.fSize, SEEK_CUR );
}
return false;
}
void plFastWAV::Open()
{
if(fFileHandle)
return;
fFileHandle = fopen( fFilename, "rb" );
if(!fFileHandle)
return;
fCurrDataPos = 0;
fseek( fFileHandle, fDataStartPos, SEEK_SET );
}
void plFastWAV::Close( void )
{
if( fFileHandle != nil )
{
fclose( fFileHandle );
fFileHandle = nil;
}
}
void plFastWAV::IError( const char *msg )
{
hsAssert( false, msg );
Close();
}
plWAVHeader &plFastWAV::GetHeader( void )
{
hsAssert( IsValid(), "GetHeader() called on an invalid WAV file" );
return fFakeHeader;
}
float plFastWAV::GetLengthInSecs( void )
{
hsAssert( IsValid(), "GetLengthInSecs() called on an invalid WAV file" );
return (float)( fDataSize / fChannelAdjust ) / (float)fHeader.fAvgBytesPerSec;
}
hsBool plFastWAV::SetPosition( UInt32 numBytes )
{
hsAssert( IsValid(), "GetHeader() called on an invalid WAV file" );
fCurrDataPos = numBytes * fChannelAdjust + ( fChannelOffset * fHeader.fBlockAlign / fChannelAdjust );
hsAssert( fCurrDataPos <= fDataSize, "Invalid new position while seeking WAV file" );
return ( fseek( fFileHandle, fDataStartPos + fCurrDataPos, SEEK_SET ) == 0 ) ? true : false;
}
hsBool plFastWAV::Read( UInt32 numBytes, void *buffer )
{
hsAssert( IsValid(), "GetHeader() called on an invalid WAV file" );
if( fWhichChannel != plAudioCore::kAll )
{
size_t numRead, sampleSize = fHeader.fBlockAlign / fChannelAdjust;
static UInt8 trashBuffer[ 32 ];
UInt32 numBytesFull = numBytes;
if( fCurrDataPos + ( numBytes * fChannelAdjust ) > fDataSize )
numBytesFull -= sampleSize;
for( numRead = 0; numRead < numBytesFull; numRead += sampleSize )
{
size_t thisRead = fread( buffer, 1, sampleSize, fFileHandle );
if( thisRead != sampleSize )
return false;
// fseek( fFileHandle, sampleSize * ( fChannelAdjust - 1 ), SEEK_CUR );
thisRead = fread( trashBuffer, 1, sampleSize, fFileHandle );
if( thisRead != sampleSize )
return false;
buffer = (void *)( (UInt8 *)buffer + sampleSize );
fCurrDataPos += sampleSize * fChannelAdjust;
}
if( numRead < numBytes )
{
if( numBytes - numRead > sampleSize )
{
hsAssert( false, "Invalid logic in plFastWAV::Read()" );
return false;
}
// Must not have enough room left, so no more skipping
size_t thisRead = fread( buffer, 1, sampleSize, fFileHandle );
if( thisRead != sampleSize )
return false;
buffer = (void *)( (UInt8 *)buffer + sampleSize );
fCurrDataPos += sampleSize;
}
hsAssert( fCurrDataPos <= fDataSize, "Invalid new position while reading WAV file" );
}
else
{
size_t numRead = fread( buffer, 1, numBytes, fFileHandle );
fCurrDataPos += numRead;
hsAssert( fCurrDataPos <= fDataSize, "Invalid new position while reading WAV file" );
if( numRead < numBytes )
return false;
}
return true;
}
UInt32 plFastWAV::NumBytesLeft( void )
{
hsAssert( IsValid(), "GetHeader() called on an invalid WAV file" );
hsAssert( fCurrDataPos <= fDataSize, "Invalid current position while reading WAV file" );
return ( fDataSize - fCurrDataPos ) / fChannelAdjust;
}

View File

@ -0,0 +1,82 @@
/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
//////////////////////////////////////////////////////////////////////////////
// //
// plFastWavReader - Quick, dirty, and highly optimized class for reading //
// in the samples of a WAV file when you're in a hurry. //
// ONLY WORKS WITH PCM (i.e. uncompressed) DATA //
// //
//////////////////////////////////////////////////////////////////////////////
#ifndef _plFastWavReader_h
#define _plFastWavReader_h
#include "plAudioFileReader.h"
//// Class Definition ////////////////////////////////////////////////////////
class plRIFFChunk;
class plFastWAV : public plAudioFileReader
{
public:
plFastWAV( const char *path, plAudioCore::ChannelSelect whichChan = plAudioCore::kAll );
virtual ~plFastWAV();
virtual plWAVHeader &GetHeader( void );
virtual void Open();
virtual void Close( void );
virtual UInt32 GetDataSize( void ) { return fDataSize / fChannelAdjust; }
virtual float GetLengthInSecs( void );
virtual hsBool SetPosition( UInt32 numBytes );
virtual hsBool Read( UInt32 numBytes, void *buffer );
virtual UInt32 NumBytesLeft( void );
virtual hsBool IsValid( void ) { return ( fFileHandle != nil ) ? true : false; }
protected:
enum
{
kPCMFormatTag = 1
};
char fFilename[ 512 ];
FILE * fFileHandle;
plWAVHeader fHeader, fFakeHeader;
UInt32 fDataStartPos, fCurrDataPos, fDataSize;
UInt32 fChunkStart;
plAudioCore::ChannelSelect fWhichChannel;
UInt32 fChannelAdjust, fChannelOffset;
void IError( const char *msg );
bool ISeekToChunk( const char *type, plRIFFChunk *c );
};
#endif //_plFastWavReader_h

View File

@ -0,0 +1,565 @@
/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
#include <process.h>
#include "hsTypes.h"
#include "plSoundBuffer.h"
#include "hsStream.h"
#include "hsUtils.h"
#include "plgDispatch.h"
#include "hsResMgr.h"
#include "../pnMessage/plRefMsg.h"
#include "../plFile/plFileUtils.h"
#include "../plFile/hsFiles.h"
#include "../plUnifiedTime/plUnifiedTime.h"
#include "../pnUtils/pnUtils.h"
#include "../plStatusLog/plStatusLog.h"
#include "hsTimer.h"
static bool s_running;
static LISTDECL(plSoundBuffer, link) s_loading;
static CCritSect s_critsect;
static CEvent s_event(kEventAutoReset);
static void GetFullPath( const char filename[], char *destStr )
{
char path[ kFolderIterator_MaxPath ];
if( strchr( filename, '\\' ) != nil )
strcpy( path, filename );
else
sprintf( path, "sfx\\%s", filename );
strcpy( destStr, path );
}
//// IGetReader //////////////////////////////////////////////////////////////
// Makes sure the sound is ready to load without any extra processing (like
// decompression or the like), then opens a reader for it.
// fullpath tells the function whether to append 'sfx' to the path or not (we don't want to do this if were providing the full path)
static plAudioFileReader *CreateReader( hsBool fullpath, const char filename[], plAudioFileReader::StreamType type, plAudioCore::ChannelSelect channel )
{
char path[512];
if(fullpath) GetFullPath(filename, path);
else
strcpy(path, filename);
plAudioFileReader* reader = plAudioFileReader::CreateReader(path, channel, type);
if( reader == nil || !reader->IsValid() )
{
delete reader;
return nil;
}
return reader;
}
// our loading thread
static void LoadCallback(void *)
{
LISTDECL(plSoundBuffer, link) templist;
while(s_running)
{
s_critsect.Enter();
{
while(plSoundBuffer *buffer = s_loading.Head())
{
templist.Link(buffer);
}
}
s_critsect.Leave();
if(!templist.Head())
{
s_event.Wait(kEventWaitForever);
}
else
{
plAudioFileReader *reader = nil;
while(plSoundBuffer *buffer = templist.Head())
{
if(buffer->GetData())
{
reader = CreateReader(true, buffer->GetFileName(), buffer->GetAudioReaderType(), buffer->GetReaderSelect());
if( reader )
{
unsigned readLen = buffer->GetAsyncLoadLength() ? buffer->GetAsyncLoadLength() : buffer->GetDataLength();
reader->Read( readLen, buffer->GetData() );
buffer->SetAudioReader(reader); // give sound buffer reader, since we may need it later
}
else
buffer->SetError();
}
templist.Unlink(buffer);
buffer->SetLoaded(true);
}
}
}
// we need to be sure that all buffers are removed from our load list when shutting this thread down or we will hang,
// since the sound buffer will wait to be destroyed until it is marked as loaded
s_critsect.Enter();
{
while(plSoundBuffer *buffer = s_loading.Head())
{
buffer->SetLoaded(true);
s_loading.Unlink(buffer);
}
}
s_critsect.Leave();
}
void plSoundBuffer::Init()
{
s_running = true;
_beginthread(LoadCallback, 0, 0);
}
void plSoundBuffer::Shutdown()
{
s_running = false;
s_event.Signal();
}
//// Constructor/Destructor //////////////////////////////////////////////////
plSoundBuffer::plSoundBuffer()
{
IInitBuffer();
}
plSoundBuffer::plSoundBuffer( const char *fileName, UInt32 flags )
{
IInitBuffer();
SetFileName( fileName );
fFlags = flags;
fValid = IGrabHeaderInfo();
}
plSoundBuffer::~plSoundBuffer()
{
// if we are loading a sound we need to wait for the loading thread to be completely done processing this buffer.
// otherwise it may try to access this buffer after it's been deleted
if(fLoading)
{
while(!fLoaded)
{
Sleep(10);
}
}
ASSERT(!link.IsLinked());
delete [] fFileName;
UnLoad();
}
void plSoundBuffer::IInitBuffer()
{
fError = false;
fValid = false;
fFileName = nil;
fData = nil;
fDataLength = 0;
fFlags = 0;
fDataRead = 0;
fReader = nil;
fLoaded = 0;
fLoading = false;
fHeader.fFormatTag = 0;
fHeader.fNumChannels = 0;
fHeader.fNumSamplesPerSec = 0;
fHeader.fAvgBytesPerSec = 0;
fHeader.fBlockAlign = 0;
fHeader.fBitsPerSample = 0;
}
//// GetDataLengthInSecs /////////////////////////////////////////////////////
hsScalar plSoundBuffer::GetDataLengthInSecs( void ) const
{
return (hsScalar)fDataLength / (hsScalar)fHeader.fAvgBytesPerSec;
}
//// Read/Write //////////////////////////////////////////////////////////////
void plSoundBuffer::Read( hsStream *s, hsResMgr *mgr )
{
hsKeyedObject::Read( s, mgr );
s->ReadSwap( &fFlags );
s->ReadSwap( &fDataLength );
fFileName = s->ReadSafeString();
s->ReadSwap( &fHeader.fFormatTag );
s->ReadSwap( &fHeader.fNumChannels );
s->ReadSwap( &fHeader.fNumSamplesPerSec );
s->ReadSwap( &fHeader.fAvgBytesPerSec );
s->ReadSwap( &fHeader.fBlockAlign );
s->ReadSwap( &fHeader.fBitsPerSample );
fValid = false;
if( !( fFlags & kIsExternal ) )
{
fData = TRACKED_NEW UInt8[ fDataLength ];
if( fData == nil )
fFlags |= kIsExternal;
else
{
s->Read( fDataLength, fData );
fValid = true;
SetLoaded(true);
}
}
else
{
fData = nil;
// fValid = EnsureInternal();
fValid = true;
}
}
void plSoundBuffer::Write( hsStream *s, hsResMgr *mgr )
{
hsKeyedObject::Write( s, mgr );
if( fData == nil )
fFlags |= kIsExternal;
s->WriteSwap( fFlags );
s->WriteSwap( fDataLength );
// Truncate the path to just a file name on write
if( fFileName != nil )
{
char *nameOnly = strrchr( fFileName, '\\' );
if( nameOnly != nil )
s->WriteSafeString( nameOnly + 1 );
else
s->WriteSafeString( fFileName );
}
else
s->WriteSafeString( nil );
s->WriteSwap( fHeader.fFormatTag );
s->WriteSwap( fHeader.fNumChannels );
s->WriteSwap( fHeader.fNumSamplesPerSec );
s->WriteSwap( fHeader.fAvgBytesPerSec );
s->WriteSwap( fHeader.fBlockAlign );
s->WriteSwap( fHeader.fBitsPerSample );
if( !( fFlags & kIsExternal ) )
s->Write( fDataLength, fData );
}
//// SetFileName /////////////////////////////////////////////////////////////
void plSoundBuffer::SetFileName( const char *name )
{
if(fLoading)
{
hsAssert(false, "Unable to set SoundBuffer filename");
return;
}
delete [] fFileName;
if( name != nil )
fFileName = hsStrcpy( name );
else
fFileName = nil;
// Data is no longer valid
UnLoad();
}
//// GetReaderSelect /////////////////////////////////////////////////////////
// Translates our flags into the ChannelSelect enum for plAudioFileReader
plAudioCore::ChannelSelect plSoundBuffer::GetReaderSelect( void ) const
{
if( fFlags & kOnlyLeftChannel )
return plAudioCore::kLeft;
else if( fFlags & kOnlyRightChannel )
return plAudioCore::kRight;
else
return plAudioCore::kAll;
}
//// IGetFullPath ////////////////////////////////////////////////////////////
// Construct our current full path to our sound.
void plSoundBuffer::IGetFullPath( char *destStr )
{
if(!fFileName)
{
*destStr = 0;
return;
}
char path[ kFolderIterator_MaxPath ];
if( strchr( fFileName, '\\' ) != nil )
strcpy( path, fFileName );
else
sprintf( path, "sfx\\%s", fFileName );
strcpy( destStr, path );
}
//============================================================================
// Asyncload will queue up a buffer for loading in our loading list the first time it is called.
// It will load in "length" number of bytes, if length is non zero. If length is zero the entire file will be loaded
// When called subsequent times it will check to see if the data has been loaded.
// Returns kPending while still loading the file. Returns kSuccess when the data has been loaded.
// While a file is loading(fLoading == true, and fLoaded == false) a buffer, no paremeters of the buffer should be modified.
plSoundBuffer::ELoadReturnVal plSoundBuffer::AsyncLoad(plAudioFileReader::StreamType type, unsigned length /* = 0 */ )
{
if(!s_running)
return kError; // we cannot load the data since the load thread is no longer running
if(!fLoading && !fLoaded)
{
fAsyncLoadLength = length;
fStreamType = type;
if(fData == nil )
{
fData = TRACKED_NEW UInt8[ fAsyncLoadLength ? fAsyncLoadLength : fDataLength ];
if( fData == nil )
return kError;
}
s_critsect.Enter();
{
fLoading = true;
s_loading.Link(this);
}
s_critsect.Leave();
s_event.Signal();
}
if(fLoaded)
{
if(fLoading) // ensures we only do this stuff one time
{
ELoadReturnVal retVal = kSuccess;
if(fError)
{
retVal = kError;
fError = false;
}
if(fReader)
{
fHeader = fReader->GetHeader();
SetDataLength(fReader->GetDataSize());
}
fFlags &= ~kIsExternal;
fLoading = false;
return retVal;
}
return kSuccess;
}
return kPending;
}
//// ForceNonInternal ////////////////////////////////////////////////////////
// destroys loaded, and frees data
void plSoundBuffer::UnLoad( void )
{
if(fLoaded)
int i = 0;
if(fLoading)
return;
if(fReader)
fReader->Close();
delete fReader;
fReader = nil;
delete [] fData;
fData = nil;
SetLoaded(false);
fFlags |= kIsExternal;
}
//// IRoundDataPos ///////////////////////////////////////////////////////////
void plSoundBuffer::RoundDataPos( UInt32 &pos )
{
UInt32 extra = pos & ( fHeader.fBlockAlign - 1 );
pos -= extra;
}
// transfers ownership to caller
plAudioFileReader *plSoundBuffer::GetAudioReader()
{
plAudioFileReader * reader = fReader;
fReader = nil;
return reader;
}
// WARNING: called by the loader thread(only)
// the reader will be handed off for later use. This is useful for streaming sound if we want to load the first chunk of data
// and the continue streaming the file from disk.
void plSoundBuffer::SetAudioReader(plAudioFileReader *reader)
{
if(fReader)
fReader->Close();
delete fReader;
fReader = reader;
}
void plSoundBuffer::SetLoaded(bool loaded)
{
fLoaded = loaded;
}
/*****************************************************************************
*
* for plugins only
*
***/
//// SetInternalData /////////////////////////////////////////////////////////
void plSoundBuffer::SetInternalData( plWAVHeader &header, UInt32 length, UInt8 *data )
{
if(fLoading) return;
fFileName = nil;
fHeader = header;
fFlags = 0;
fDataLength = length;
fData = TRACKED_NEW UInt8[ length ];
memcpy( fData, data, length );
fValid = true;
}
//// EnsureInternal //////////////////////////////////////////////////////////
// for plugins only
plSoundBuffer::ELoadReturnVal plSoundBuffer::EnsureInternal()
{
if( fData == nil )
{
fData = TRACKED_NEW UInt8[fDataLength ];
if( fData == nil )
return kError;
}
if(!fReader)
fReader = IGetReader(true);
//else
// fReader->Open();
if( fReader == nil )
return kError;
unsigned readLen = fDataLength;
if( !fReader->Read( readLen, fData ) )
{
delete [] fData;
fData = nil;
return kError;
}
if(fReader)
{
fReader->Close();
delete fReader;
fReader = nil;
}
return kSuccess;
}
//// IGrabHeaderInfo /////////////////////////////////////////////////////////
hsBool plSoundBuffer::IGrabHeaderInfo( void )
{
static char path[ 512 ];
if( fFileName != nil )
{
IGetFullPath( path );
// Go grab from the WAV file
if(!fReader)
{
fReader = plAudioFileReader::CreateReader(path, GetReaderSelect(), plAudioFileReader::kStreamNative);
if( fReader == nil || !fReader->IsValid() )
{
delete fReader;
fReader = nil;
return false;
}
}
fHeader = fReader->GetHeader();
fDataLength = fReader->GetDataSize();
RoundDataPos( fDataLength );
fReader->Close();
delete fReader;
fReader = nil;
}
return true;
}
//// IGetReader //////////////////////////////////////////////////////////////
// Makes sure the sound is ready to load without any extra processing (like
// decompression or the like), then opens a reader for it.
// fullpath tells the function whether to append 'sfx' to the path or not (we don't want to do this if were providing the full path)
plAudioFileReader *plSoundBuffer::IGetReader( hsBool fullpath )
{
char path[512];
if(fullpath) IGetFullPath(path);
else
strcpy(path, fFileName);
// Go grab from the WAV file
plAudioFileReader::StreamType type = plAudioFileReader::kStreamWAV;
if (HasFlag(kStreamCompressed))
type = plAudioFileReader::kStreamNative;
plAudioFileReader* reader = plAudioFileReader::CreateReader(path, GetReaderSelect(), type);
if( reader == nil || !reader->IsValid() )
{
delete reader;
return nil;
}
fHeader = reader->GetHeader();
fDataLength = reader->GetDataSize();
RoundDataPos( fDataLength );
return reader;
}

View File

@ -0,0 +1,146 @@
/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
//////////////////////////////////////////////////////////////////////////////
// //
// plSoundBuffer - Quick, dirty, and highly optimized class for reading //
// in the samples of a WAV file when you're in a hurry. //
// ONLY WORKS WITH PCM (i.e. uncompressed) DATA //
// //
// Now loads data asynchronously. When fLoading is true //
// do not touch any data in the soundbuffer //
//////////////////////////////////////////////////////////////////////////////
#ifndef _plSoundBuffer_h
#define _plSoundBuffer_h
#include "../pnKeyedObject/hsKeyedObject.h"
#include "plAudioCore.h"
#include "plAudioFileReader.h"
#include "../pnUtils/pnUtils.h"
//// Class Definition ////////////////////////////////////////////////////////
class plUnifiedTime;
class plAudioFileReader;
class plSoundBuffer : public hsKeyedObject
{
public:
plSoundBuffer();
plSoundBuffer( const char *fileName, UInt32 flags = 0 );
~plSoundBuffer();
CLASSNAME_REGISTER( plSoundBuffer );
GETINTERFACE_ANY( plSoundBuffer, hsKeyedObject );
LINK(plSoundBuffer) link;
enum Flags
{
kIsExternal = 0x0001,
kAlwaysExternal = 0x0002,
kOnlyLeftChannel = 0x0004,
kOnlyRightChannel = 0x0008,
kStreamCompressed = 0x0010,
};
enum ELoadReturnVal
{
kSuccess,
kError,
kPending,
};
void RoundDataPos( UInt32 &pos );
virtual void Read( hsStream *s, hsResMgr *mgr );
virtual void Write( hsStream *s, hsResMgr *mgr );
plWAVHeader &GetHeader( void ) { return fHeader; }
UInt32 GetDataLength( void ) const { return fDataLength; }
void SetDataLength(unsigned length) { fDataLength = length; }
void *GetData( void ) const { return fData; }
const char *GetFileName( void ) const { return fFileName; }
hsBool IsValid( void ) const { return fValid; }
hsScalar GetDataLengthInSecs( void ) const;
void SetFileName( const char *name );
hsBool HasFlag( UInt32 flag ) { return ( fFlags & flag ) ? true : false; }
void SetFlag( UInt32 flag, hsBool yes = true ) { if( yes ) fFlags |= flag; else fFlags &= ~flag; }
// Must be called until return value is kSuccess. starts an asynchronous load first time called. returns kSuccess when finished.
ELoadReturnVal AsyncLoad( plAudioFileReader::StreamType type, unsigned length = 0 );
void UnLoad( );
plAudioCore::ChannelSelect GetReaderSelect( void ) const;
static void Init();
static void Shutdown();
plAudioFileReader * GetAudioReader(); // transfers ownership to caller
void SetAudioReader(plAudioFileReader *reader);
void SetLoaded(bool loaded);
plAudioFileReader::StreamType GetAudioReaderType() { return fStreamType; }
unsigned GetAsyncLoadLength() { return fAsyncLoadLength ? fAsyncLoadLength : fDataLength; }
// for plugins only
void SetInternalData( plWAVHeader &header, UInt32 length, UInt8 *data );
ELoadReturnVal EnsureInternal( );
void SetError() { fError = true; }
protected:
// plSoundBuffers can be two ways--they can either have a filename and no
// data, in which case they reference a file in the sfx folder, or they
// can store the data directly
void IInitBuffer();
hsBool IGrabHeaderInfo( void );
void IAddBuffers( void *base, void *toAdd, UInt32 lengthInBytes, UInt8 bitsPerSample );
void IGetFullPath( char *destStr );
UInt32 fFlags;
hsBool fValid;
UInt32 fDataRead;
char *fFileName;
bool fLoaded;
bool fLoading;
bool fError;
plAudioFileReader * fReader;
UInt8 * fData;
plWAVHeader fHeader;
UInt32 fDataLength;
UInt32 fAsyncLoadLength;
plAudioFileReader::StreamType fStreamType;
// for plugins only
plAudioFileReader *IGetReader( hsBool fullpath );
};
#endif //_plSoundBuffer_h

View File

@ -0,0 +1,81 @@
/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
//////////////////////////////////////////////////////////////////////////////
// //
// plSoundDeswizzler - Quick helper class to extract a single channel of //
// data from stereo (or more)-channel data. //
// //
//////////////////////////////////////////////////////////////////////////////
#include "hsTypes.h"
#include "plSoundDeswizzler.h"
#include <string.h>
plSoundDeswizzler::plSoundDeswizzler( void *srcPtr, UInt32 srcLength, UInt8 numChannels, UInt32 sampleSize )
{
fNumSamples = srcLength / sampleSize;
fSampleSize = sampleSize;
fStride = fSampleSize * numChannels;
fData = (UInt8 *)srcPtr;
fOwnsData = false;
}
plSoundDeswizzler::plSoundDeswizzler( UInt32 srcLength, UInt8 numChannels, UInt32 sampleSize )
{
fNumSamples = srcLength / sampleSize;
fSampleSize = sampleSize;
fStride = fSampleSize * numChannels;
fData = TRACKED_NEW UInt8[ srcLength ];
fOwnsData = true;
}
plSoundDeswizzler::~plSoundDeswizzler()
{
if( fOwnsData )
delete [] fData;
}
void plSoundDeswizzler::Extract( UInt8 channelSelect, void *dest, UInt32 numBytesToProcess )
{
UInt8 *srcPtr = fData + channelSelect * fSampleSize;
UInt8 *destPtr = (UInt8 *)dest;
UInt32 i;
if( numBytesToProcess == 0 )
numBytesToProcess = fNumSamples;
else
numBytesToProcess /= fStride;
// Extract!
for( i = 0; i < numBytesToProcess; i++ )
{
memcpy( destPtr, srcPtr, fSampleSize );
destPtr += fSampleSize;
srcPtr += fStride;
}
}

View File

@ -0,0 +1,57 @@
/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
//////////////////////////////////////////////////////////////////////////////
// //
// plSoundDeswizzler - Quick helper class to extract a single channel of //
// data from stereo (or more)-channel data. //
// //
//////////////////////////////////////////////////////////////////////////////
#ifndef _plSoundDeswizzler_h
#define _plSoundDeswizzler_h
#include "hsTypes.h"
//// Class Definition ////////////////////////////////////////////////////////
class plSoundDeswizzler
{
public:
plSoundDeswizzler( void *srcPtr, UInt32 srcLength, UInt8 numChannels, UInt32 sampleSize );
plSoundDeswizzler( UInt32 srcLength, UInt8 numChannels, UInt32 sampleSize );
~plSoundDeswizzler();
void *GetSourceBuffer( void ) const { return fData; }
void Extract( UInt8 channelSelect, void *destPtr, UInt32 numBytesToProcess = 0 );
protected:
UInt8 *fData;
UInt32 fNumSamples, fSampleSize, fStride;
hsBool fOwnsData;
};
#endif //_plSoundDeswizzler_h