initial
This commit is contained in:
264
engine/voice_codecs/miles/milesbase.cpp
Normal file
264
engine/voice_codecs/miles/milesbase.cpp
Normal file
@@ -0,0 +1,264 @@
|
||||
//========= Copyright (c) 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#include "milesbase.h"
|
||||
#include "tier0/dbg.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
static int s_MilesRefCount = 0;
|
||||
|
||||
|
||||
void IncrementRefMiles()
|
||||
{
|
||||
if(s_MilesRefCount == 0)
|
||||
{
|
||||
#ifdef WIN32
|
||||
AIL_set_redist_directory( "." );
|
||||
#elif defined( OSX )
|
||||
AIL_set_redist_directory( "osx32" );
|
||||
#elif defined( LINUX )
|
||||
#ifdef PLATFORM_64BITS
|
||||
AIL_set_redist_directory( "bin/linux64" );
|
||||
#else
|
||||
AIL_set_redist_directory( "bin/linux32" );
|
||||
#endif
|
||||
#else
|
||||
Assert( !"Using default MSS_REDIST_DIR_NAME - this will most likely fail." );
|
||||
AIL_set_redist_directory( MSS_REDIST_DIR_NAME );
|
||||
#endif
|
||||
|
||||
AIL_startup();
|
||||
}
|
||||
|
||||
++s_MilesRefCount;
|
||||
}
|
||||
|
||||
void DecrementRefMiles()
|
||||
{
|
||||
Assert(s_MilesRefCount > 0);
|
||||
--s_MilesRefCount;
|
||||
if(s_MilesRefCount == 0)
|
||||
{
|
||||
CProvider::FreeAllProviders();
|
||||
AIL_shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------ //
|
||||
// CProvider functions.
|
||||
// ------------------------------------------------------------------------ //
|
||||
|
||||
CProvider *CProvider::s_pHead = NULL;
|
||||
|
||||
|
||||
CProvider::CProvider( HPROVIDER hProvider )
|
||||
{
|
||||
m_hProvider = hProvider;
|
||||
|
||||
// Add to the global list of CProviders.
|
||||
m_pNext = s_pHead;
|
||||
s_pHead = this;
|
||||
}
|
||||
|
||||
|
||||
CProvider::~CProvider()
|
||||
{
|
||||
RIB_free_provider_library( m_hProvider );
|
||||
|
||||
// Remove from the global list.
|
||||
CProvider **ppPrev = &s_pHead;
|
||||
for ( CProvider *pCur=s_pHead; pCur; pCur=pCur->m_pNext )
|
||||
{
|
||||
if ( pCur == this )
|
||||
{
|
||||
*ppPrev = m_pNext;
|
||||
return;
|
||||
}
|
||||
|
||||
ppPrev = &pCur->m_pNext;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
CProvider* CProvider::FindProvider( HPROVIDER hProvider )
|
||||
{
|
||||
for ( CProvider *pCur=s_pHead; pCur; pCur=pCur->m_pNext )
|
||||
{
|
||||
if ( pCur->GetProviderHandle() == hProvider )
|
||||
{
|
||||
return pCur;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
void CProvider::FreeAllProviders()
|
||||
{
|
||||
CProvider *pNext;
|
||||
for ( CProvider *pCur=s_pHead; pCur; pCur=pNext )
|
||||
{
|
||||
pNext = pCur->m_pNext;
|
||||
delete pCur;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
HPROVIDER CProvider::GetProviderHandle()
|
||||
{
|
||||
return m_hProvider;
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------ //
|
||||
// ASISTRUCT functions.
|
||||
// ------------------------------------------------------------------------ //
|
||||
ASISTRUCT::ASISTRUCT()
|
||||
{
|
||||
Clear();
|
||||
IncrementRefMiles();
|
||||
}
|
||||
|
||||
ASISTRUCT::~ASISTRUCT()
|
||||
{
|
||||
Shutdown();
|
||||
DecrementRefMiles();
|
||||
}
|
||||
|
||||
|
||||
void ASISTRUCT::Clear()
|
||||
{
|
||||
m_pProvider = NULL;
|
||||
ASI_stream_open = NULL;
|
||||
ASI_stream_process = NULL;
|
||||
ASI_stream_close = NULL;
|
||||
ASI_stream_property = NULL;
|
||||
ASI_stream_seek = NULL;
|
||||
OUTPUT_BITS = NULL;
|
||||
OUTPUT_CHANNELS = NULL;
|
||||
INPUT_BITS = NULL;
|
||||
INPUT_CHANNELS = NULL;
|
||||
POSITION = NULL;
|
||||
m_stream = NULL;
|
||||
}
|
||||
|
||||
|
||||
bool ASISTRUCT::Init( void *pCallbackObject, const char *pInputFileType, const char *pOutputFileType, AILASIFETCHCB cb )
|
||||
{
|
||||
// Get the provider.
|
||||
HPROVIDER hProvider = RIB_find_files_provider( "ASI codec",
|
||||
"Output file types", pOutputFileType, "Input file types", pInputFileType );
|
||||
|
||||
if ( !hProvider )
|
||||
return false;
|
||||
|
||||
m_pProvider = CProvider::FindProvider( hProvider );
|
||||
if ( !m_pProvider )
|
||||
{
|
||||
m_pProvider = new CProvider( hProvider );
|
||||
}
|
||||
|
||||
if ( !m_pProvider )
|
||||
return false;
|
||||
|
||||
RIB_INTERFACE_ENTRY ASISTR[] =
|
||||
{
|
||||
FN( ASI_stream_property ),
|
||||
FN( ASI_stream_open ),
|
||||
FN( ASI_stream_close ),
|
||||
FN( ASI_stream_process ),
|
||||
|
||||
PR( "Output sample rate", OUTPUT_RATE ),
|
||||
PR( "Output sample width", OUTPUT_BITS ),
|
||||
PR( "Output channels", OUTPUT_CHANNELS ),
|
||||
|
||||
PR( "Input sample rate", INPUT_RATE ),
|
||||
PR( "Input sample width", INPUT_BITS ),
|
||||
PR( "Input channels", INPUT_CHANNELS ),
|
||||
|
||||
PR( "Minimum input block size", INPUT_BLOCK_SIZE ),
|
||||
PR( "Position", POSITION ),
|
||||
};
|
||||
|
||||
RIBRESULT result = RIB_request( m_pProvider->GetProviderHandle(), "ASI stream", ASISTR );
|
||||
if(result != RIB_NOERR)
|
||||
return false;
|
||||
|
||||
|
||||
// This function doesn't exist for the voice DLLs, but it's not fatal in that case.
|
||||
RIB_INTERFACE_ENTRY seekFn[] =
|
||||
{
|
||||
FN( ASI_stream_seek ),
|
||||
};
|
||||
result = RIB_request( m_pProvider->GetProviderHandle(), "ASI stream", seekFn );
|
||||
if(result != RIB_NOERR)
|
||||
ASI_stream_seek = NULL;
|
||||
|
||||
|
||||
|
||||
|
||||
m_stream = ASI_stream_open( (MSS_ALLOC_TYPE *)MSS_CALLBACK_ALIGNED_NAME( MSS_alloc_info ),
|
||||
(MSS_FREE_TYPE *)MSS_CALLBACK_ALIGNED_NAME( MSS_free_info ),
|
||||
(UINTa)pCallbackObject, cb, 0);
|
||||
if(!m_stream)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ASISTRUCT::Shutdown()
|
||||
{
|
||||
if ( m_pProvider )
|
||||
{
|
||||
if (m_stream && ASI_stream_close)
|
||||
{
|
||||
ASI_stream_close(m_stream);
|
||||
m_stream = NULL;
|
||||
}
|
||||
|
||||
//m_pProvider->Release();
|
||||
m_pProvider = NULL;
|
||||
}
|
||||
|
||||
Clear();
|
||||
}
|
||||
|
||||
|
||||
int ASISTRUCT::Process( void *pBuffer, unsigned int bufferSize )
|
||||
{
|
||||
return ASI_stream_process( m_stream, pBuffer, bufferSize );
|
||||
}
|
||||
|
||||
|
||||
bool ASISTRUCT::IsActive() const
|
||||
{
|
||||
return m_stream != NULL ? true : false;
|
||||
}
|
||||
|
||||
|
||||
unsigned int ASISTRUCT::GetProperty( HPROPERTY hProperty )
|
||||
{
|
||||
uint32 nValue = 0;
|
||||
if ( ASI_stream_property( m_stream, hProperty, &nValue, NULL, NULL ) )
|
||||
{
|
||||
return nValue;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ASISTRUCT::Seek( int position )
|
||||
{
|
||||
if ( !ASI_stream_seek )
|
||||
Error( "ASI_stream_seek called, but it doesn't exist." );
|
||||
|
||||
ASI_stream_seek( m_stream, (S32)position );
|
||||
}
|
||||
|
||||
|
||||
87
engine/voice_codecs/miles/milesbase.h
Normal file
87
engine/voice_codecs/miles/milesbase.h
Normal file
@@ -0,0 +1,87 @@
|
||||
//========= Copyright (c) 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef MILESBASE_H
|
||||
#define MILESBASE_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
// windows.h / platform.h conflicts
|
||||
#pragma warning(disable:4005)
|
||||
#pragma warning(disable:4201) // nameless struct/union (mmssystem.h has this)
|
||||
|
||||
#include "miles/mss.h"
|
||||
|
||||
class CProvider
|
||||
{
|
||||
public:
|
||||
CProvider( HPROVIDER hProvider );
|
||||
|
||||
static CProvider* FindProvider( HPROVIDER hProvider );
|
||||
static void FreeAllProviders();
|
||||
|
||||
HPROVIDER GetProviderHandle();
|
||||
|
||||
private:
|
||||
|
||||
~CProvider();
|
||||
|
||||
private:
|
||||
|
||||
HPROVIDER m_hProvider;
|
||||
|
||||
static CProvider *s_pHead;
|
||||
CProvider *m_pNext;
|
||||
};
|
||||
|
||||
|
||||
// This holds the handles and function pointers we want from a compressor/decompressor.
|
||||
class ASISTRUCT
|
||||
{
|
||||
public:
|
||||
ASISTRUCT();
|
||||
~ASISTRUCT();
|
||||
|
||||
bool Init( void *pCallbackObject, const char *pInputFileType,
|
||||
const char *pOutputFileType, AILASIFETCHCB cb );
|
||||
void Shutdown();
|
||||
int Process( void *pBuffer, unsigned int bufferSize );
|
||||
bool IsActive() const;
|
||||
unsigned int GetProperty( HPROPERTY attribute );
|
||||
void Seek( int position );
|
||||
|
||||
public:
|
||||
HPROPERTY OUTPUT_BITS;
|
||||
HPROPERTY OUTPUT_CHANNELS;
|
||||
HPROPERTY OUTPUT_RATE;
|
||||
|
||||
HPROPERTY INPUT_BITS;
|
||||
HPROPERTY INPUT_CHANNELS;
|
||||
HPROPERTY INPUT_RATE;
|
||||
HPROPERTY INPUT_BLOCK_SIZE;
|
||||
HPROPERTY POSITION;
|
||||
|
||||
private:
|
||||
void Clear();
|
||||
|
||||
private:
|
||||
ASI_STREAM_OPEN ASI_stream_open;
|
||||
ASI_STREAM_PROCESS ASI_stream_process;
|
||||
ASI_STREAM_CLOSE ASI_stream_close;
|
||||
ASI_STREAM_SEEK ASI_stream_seek;
|
||||
ASI_STREAM_PROPERTY ASI_stream_property;
|
||||
|
||||
HASISTREAM m_stream;
|
||||
CProvider *m_pProvider;
|
||||
};
|
||||
|
||||
|
||||
extern void IncrementRefMiles();
|
||||
extern void DecrementRefMiles();
|
||||
|
||||
#endif // MILESBASE_H
|
||||
167
engine/voice_codecs/miles/mp3_miles.cpp
Normal file
167
engine/voice_codecs/miles/mp3_miles.cpp
Normal file
@@ -0,0 +1,167 @@
|
||||
//========= Copyright (c) 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#include "interface.h"
|
||||
#include "milesbase.h"
|
||||
#include "vaudio/ivaudio.h"
|
||||
#include "dbg.h"
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
|
||||
static S32 AILCALLBACK AudioStreamEventCB( UINTa user, void *dest, S32 bytes_requested, S32 offset )
|
||||
{
|
||||
IAudioStreamEvent *pThis = static_cast<IAudioStreamEvent*>( (void *)user);
|
||||
|
||||
#if defined( OSX ) && !defined( PLATFORM_64BITS )
|
||||
// save of the args to local stack vars before we screw with ESP
|
||||
volatile void *newDest = dest;
|
||||
volatile S32 newBytes = bytes_requested;
|
||||
volatile S32 newOffset = offset;
|
||||
volatile void *oldESP;
|
||||
|
||||
// now move ESP to be aligned to 16-bytes
|
||||
asm volatile(
|
||||
"movl %%esp,%0\n"
|
||||
"subl $16,%%esp\n"
|
||||
"andl $-0x10,%%esp\n"
|
||||
: "=m" (oldESP) : : "%esp");
|
||||
int val = pThis->StreamRequestData( (void *)newDest, newBytes, newOffset );
|
||||
|
||||
// undo the alignment
|
||||
asm( "movl %0,%%esp\n" ::"m" (oldESP) );
|
||||
|
||||
return val;
|
||||
#else
|
||||
return pThis->StreamRequestData( dest, bytes_requested, offset );
|
||||
#endif
|
||||
}
|
||||
|
||||
class CMilesMP3 : public IAudioStream
|
||||
{
|
||||
public:
|
||||
CMilesMP3();
|
||||
bool Init( IAudioStreamEvent *pHandler );
|
||||
virtual ~CMilesMP3();
|
||||
|
||||
// IAudioStream functions
|
||||
virtual int Decode( void *pBuffer, unsigned int bufferSize );
|
||||
virtual int GetOutputBits();
|
||||
virtual int GetOutputRate();
|
||||
virtual int GetOutputChannels();
|
||||
virtual unsigned int GetPosition();
|
||||
virtual void SetPosition( unsigned int position );
|
||||
private:
|
||||
ASISTRUCT m_decoder;
|
||||
};
|
||||
|
||||
CMilesMP3::CMilesMP3()
|
||||
{
|
||||
}
|
||||
|
||||
bool CMilesMP3::Init( IAudioStreamEvent *pHandler )
|
||||
{
|
||||
return m_decoder.Init( pHandler, ".MP3", ".RAW", &AudioStreamEventCB );
|
||||
}
|
||||
|
||||
|
||||
CMilesMP3::~CMilesMP3()
|
||||
{
|
||||
m_decoder.Shutdown();
|
||||
}
|
||||
|
||||
|
||||
// IAudioStream functions
|
||||
int CMilesMP3::Decode( void *pBuffer, unsigned int bufferSize )
|
||||
{
|
||||
return m_decoder.Process( pBuffer, bufferSize );
|
||||
}
|
||||
|
||||
|
||||
int CMilesMP3::GetOutputBits()
|
||||
{
|
||||
return m_decoder.GetProperty( m_decoder.OUTPUT_BITS );
|
||||
}
|
||||
|
||||
|
||||
int CMilesMP3::GetOutputRate()
|
||||
{
|
||||
return m_decoder.GetProperty( m_decoder.OUTPUT_RATE );
|
||||
}
|
||||
|
||||
|
||||
int CMilesMP3::GetOutputChannels()
|
||||
{
|
||||
return m_decoder.GetProperty( m_decoder.OUTPUT_CHANNELS );
|
||||
}
|
||||
|
||||
|
||||
unsigned int CMilesMP3::GetPosition()
|
||||
{
|
||||
return m_decoder.GetProperty( m_decoder.POSITION );
|
||||
}
|
||||
|
||||
// NOTE: Only supports seeking forward right now
|
||||
void CMilesMP3::SetPosition( unsigned int position )
|
||||
{
|
||||
m_decoder.Seek( position );
|
||||
}
|
||||
|
||||
|
||||
class CVAudio : public IVAudio
|
||||
{
|
||||
public:
|
||||
CVAudio()
|
||||
{
|
||||
// Assume the user will be creating multiple miles objects, so
|
||||
// keep miles running while this exists
|
||||
IncrementRefMiles();
|
||||
}
|
||||
|
||||
virtual ~CVAudio()
|
||||
{
|
||||
DecrementRefMiles();
|
||||
}
|
||||
|
||||
IAudioStream *CreateMP3StreamDecoder( IAudioStreamEvent *pEventHandler )
|
||||
{
|
||||
CMilesMP3 *pMP3 = new CMilesMP3;
|
||||
if ( !pMP3->Init( pEventHandler ) )
|
||||
{
|
||||
delete pMP3;
|
||||
return NULL;
|
||||
}
|
||||
return pMP3;
|
||||
}
|
||||
|
||||
void DestroyMP3StreamDecoder( IAudioStream *pDecoder )
|
||||
{
|
||||
delete pDecoder;
|
||||
}
|
||||
|
||||
void *CreateMilesAudioEngine()
|
||||
{
|
||||
IncrementRefMiles();
|
||||
HDIGDRIVER hDriver = AIL_open_digital_driver( 44100, 16, MSS_MC_51_DISCRETE, 0 );
|
||||
return (void *)hDriver;
|
||||
}
|
||||
|
||||
void DestroyMilesAudioEngine( void *pEngine )
|
||||
{
|
||||
HDIGDRIVER hDriver = HDIGDRIVER(pEngine);
|
||||
AIL_close_digital_driver( hDriver );
|
||||
DecrementRefMiles();
|
||||
}
|
||||
};
|
||||
|
||||
void* CreateVoiceCodec_CVAudio()
|
||||
{
|
||||
return new CVAudio;
|
||||
}
|
||||
|
||||
EXPOSE_INTERFACE_FN(CreateVoiceCodec_CVAudio, IVAudio, VAUDIO_INTERFACE_VERSION );
|
||||
|
||||
52
engine/voice_codecs/miles/vaudio_miles.vpc
Normal file
52
engine/voice_codecs/miles/vaudio_miles.vpc
Normal file
@@ -0,0 +1,52 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// VAUDIO_MILES.VPC
|
||||
//
|
||||
// Project Script
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
$Macro SRCDIR "..\..\.."
|
||||
$Macro OUTBINDIR "$SRCDIR\..\game\bin"
|
||||
|
||||
$Include "$SRCDIR\vpc_scripts\source_dll_base.vpc"
|
||||
|
||||
$Configuration
|
||||
{
|
||||
$Compiler
|
||||
{
|
||||
$AdditionalIncludeDirectories "$BASE,..\frame_encoder,..\.."
|
||||
}
|
||||
$Linker
|
||||
{
|
||||
$SystemLibraries "iconv" [$OSXALL]
|
||||
$SystemLibraries "openal" [$LINUXALL]
|
||||
}
|
||||
}
|
||||
|
||||
$Project "VAudio_Miles"
|
||||
{
|
||||
$Folder "Source Files"
|
||||
{
|
||||
$File "milesbase.cpp"
|
||||
$File "mp3_miles.cpp"
|
||||
$File "..\frame_encoder\voice_codec_frame.cpp"
|
||||
$File "voice_codec_miles.cpp"
|
||||
}
|
||||
|
||||
$Folder "Header Files"
|
||||
{
|
||||
$File "$SRCDIR\public\tier1\interface.h"
|
||||
$File "$SRCDIR\public\vaudio\ivaudio.h"
|
||||
$File "milesbase.h"
|
||||
$File "$SRCDIR\common\miles\mss.h"
|
||||
}
|
||||
|
||||
$Folder "Link Libraries"
|
||||
{
|
||||
$File "$SRCDIR\lib\common\mss32.lib" [$WIN32]
|
||||
$File "$SRCDIR\lib\common\mss64.lib" [$WIN64]
|
||||
$File "$SRCDIR\lib\osx32\release\libMilesX86.dylib" [$OSX32]
|
||||
$File "$SRCDIR\lib\osx64\release\libMilesX64.dylib" [$OSX64]
|
||||
$File "$SRCDIR\lib\linux32\release\libMiles.so" [$LINUX32]
|
||||
$ImpLibExternal "Miles" [$LINUX64]
|
||||
}
|
||||
}
|
||||
318
engine/voice_codecs/miles/voice_codec_miles.cpp
Normal file
318
engine/voice_codecs/miles/voice_codec_miles.cpp
Normal file
@@ -0,0 +1,318 @@
|
||||
//========= Copyright <20> 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//
|
||||
//=============================================================================//
|
||||
#ifdef _WIN32
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#include "quakedef.h"
|
||||
#include "iframeencoder.h"
|
||||
#include "interface.h"
|
||||
#include "milesbase.h"
|
||||
#include "tier0/dbg.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
void Con_Printf( const char *pMsg, ... )
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
class FrameEncoder_Miles : public IFrameEncoder
|
||||
{
|
||||
protected:
|
||||
virtual ~FrameEncoder_Miles();
|
||||
|
||||
public:
|
||||
FrameEncoder_Miles();
|
||||
|
||||
virtual bool Init(int quality, int &rawFrameSize, int &encodedFrameSize);
|
||||
virtual void Release();
|
||||
virtual void EncodeFrame(const char *pUncompressed, char *pCompressed);
|
||||
virtual void DecodeFrame(const char *pCompressed, char *pDecompressed);
|
||||
virtual bool ResetState();
|
||||
|
||||
|
||||
public:
|
||||
|
||||
void Shutdown();
|
||||
|
||||
static S32 AILCALLBACK EncodeStreamCB(
|
||||
UINTa user, // User value passed to ASI_open_stream()
|
||||
void *dest, // Location to which stream data should be copied by app
|
||||
S32 bytes_requested, // # of bytes requested by ASI codec
|
||||
S32 offset // If not -1, application should seek to this point in stream
|
||||
);
|
||||
|
||||
static S32 AILCALLBACK DecodeStreamCB(
|
||||
UINTa user, // User value passed to ASI_open_stream()
|
||||
void *dest, // Location to which stream data should be copied by app
|
||||
S32 bytes_requested, // # of bytes requested by ASI codec
|
||||
S32 offset // If not -1, application should seek to this point in stream
|
||||
);
|
||||
|
||||
void FigureOutFrameSizes();
|
||||
|
||||
|
||||
private:
|
||||
|
||||
// Encoder stuff.
|
||||
ASISTRUCT m_Encoder;
|
||||
|
||||
// Decoder stuff.
|
||||
ASISTRUCT m_Decoder;
|
||||
|
||||
// Destination for encoding and decoding.
|
||||
const char *m_pSrc;
|
||||
int m_SrcLen;
|
||||
int m_CurSrcPos;
|
||||
|
||||
// Frame sizes..
|
||||
int m_nRawBytes;
|
||||
int m_nEncodedBytes;
|
||||
};
|
||||
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------ //
|
||||
// Helper functions.
|
||||
// ------------------------------------------------------------------------ //
|
||||
void Convert16UnsignedToSigned(short *pDest, int nSamples)
|
||||
{
|
||||
for(int i=0; i < nSamples; i++)
|
||||
{
|
||||
int val = *((unsigned short*)&pDest[i]) - (1 << 15);
|
||||
pDest[i] = (short)val;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Convert16SignedToUnsigned(short *pDest, int nSamples)
|
||||
{
|
||||
for(int i=0; i < nSamples; i++)
|
||||
{
|
||||
int val = *((short*)&pDest[i]) + (1 << 15);
|
||||
*((unsigned short*)&pDest[i]) = (unsigned short)val;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------ //
|
||||
// FrameEncoder_Miles functions.
|
||||
// ------------------------------------------------------------------------ //
|
||||
FrameEncoder_Miles::FrameEncoder_Miles()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
FrameEncoder_Miles::~FrameEncoder_Miles()
|
||||
{
|
||||
Shutdown();
|
||||
}
|
||||
|
||||
bool FrameEncoder_Miles::Init(int quality, int &rawFrameSize, int &encodedFrameSize)
|
||||
{
|
||||
Shutdown();
|
||||
|
||||
|
||||
// This tells what protocol we're using.
|
||||
C8 suffix[128] = ".v12"; // (.v12, .v24, .v29, or .raw)
|
||||
|
||||
// encoder converts from RAW to v12
|
||||
if ( !m_Encoder.Init( (void *)this, ".RAW", suffix, &FrameEncoder_Miles::EncodeStreamCB ) )
|
||||
{
|
||||
Con_Printf("(FrameEncoder_Miles): Can't initialize ASI encoder.\n");
|
||||
Shutdown();
|
||||
return false;
|
||||
}
|
||||
|
||||
// decoder converts from v12 to RAW
|
||||
if ( !m_Decoder.Init( (void *)this, suffix, ".RAW", &FrameEncoder_Miles::DecodeStreamCB ) )
|
||||
{
|
||||
Con_Printf("(FrameEncoder_Miles): Can't initialize ASI decoder.\n");
|
||||
Shutdown();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
FigureOutFrameSizes();
|
||||
|
||||
|
||||
// Output..
|
||||
rawFrameSize = m_nRawBytes * 2; // They'll be using 16-bit samples and we're quantizing to 8-bit.
|
||||
encodedFrameSize = m_nEncodedBytes;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void FrameEncoder_Miles::Release()
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
|
||||
|
||||
void FrameEncoder_Miles::EncodeFrame(const char *pUncompressedBytes, char *pCompressed)
|
||||
{
|
||||
char samples[1024];
|
||||
|
||||
if(!m_Encoder.IsActive() || m_nRawBytes > sizeof(samples))
|
||||
return;
|
||||
|
||||
const short *pUncompressed = (const short*)pUncompressedBytes;
|
||||
for(int i=0; i < m_nRawBytes; i++)
|
||||
samples[i] = (char)(pUncompressed[i] >> 8);
|
||||
|
||||
m_pSrc = samples;
|
||||
m_SrcLen = m_nRawBytes;
|
||||
m_CurSrcPos = 0;
|
||||
|
||||
U32 len = m_Encoder.Process( pCompressed, m_nEncodedBytes );
|
||||
if ( len != (U32)m_nEncodedBytes )
|
||||
{
|
||||
Assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void FrameEncoder_Miles::DecodeFrame(const char *pCompressed, char *pDecompressed)
|
||||
{
|
||||
if(!m_Decoder.IsActive())
|
||||
return;
|
||||
|
||||
m_pSrc = pCompressed;
|
||||
m_SrcLen = m_nEncodedBytes;
|
||||
m_CurSrcPos = 0;
|
||||
|
||||
U32 outputSize = m_nRawBytes*2;
|
||||
U32 len = m_Decoder.Process( pDecompressed, outputSize );
|
||||
|
||||
if (len != outputSize)
|
||||
{
|
||||
Assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void FrameEncoder_Miles::Shutdown()
|
||||
{
|
||||
m_Decoder.Shutdown();
|
||||
m_Encoder.Shutdown();
|
||||
}
|
||||
|
||||
|
||||
bool FrameEncoder_Miles::ResetState()
|
||||
{
|
||||
if(!m_Decoder.IsActive() || !m_Encoder.IsActive())
|
||||
return true;
|
||||
|
||||
for(int i=0; i < 2; i++)
|
||||
{
|
||||
char data[2048], compressed[2048];
|
||||
memset(data, 0, sizeof(data));
|
||||
m_pSrc = data;
|
||||
m_SrcLen = m_nRawBytes;
|
||||
m_CurSrcPos = 0;
|
||||
|
||||
U32 len = m_Encoder.Process( compressed, m_nEncodedBytes );
|
||||
if ( len != (U32)m_nEncodedBytes )
|
||||
{
|
||||
Assert(0);
|
||||
}
|
||||
|
||||
m_pSrc = compressed;
|
||||
m_SrcLen = m_nEncodedBytes;
|
||||
m_CurSrcPos = 0;
|
||||
|
||||
m_Decoder.Process( data, m_nRawBytes * 2 );
|
||||
}
|
||||
|
||||
// Encode and decode a couple frames of zeros.
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
S32 AILCALLBACK FrameEncoder_Miles::EncodeStreamCB(
|
||||
UINTa user, // User value passed to ASI_open_stream()
|
||||
void *dest, // Location to which stream data should be copied by app
|
||||
S32 bytes_requested, // # of bytes requested by ASI codec
|
||||
S32 offset // If not -1, application should seek to this point in stream
|
||||
)
|
||||
{
|
||||
FrameEncoder_Miles *pThis = (FrameEncoder_Miles*)user;
|
||||
Assert(pThis && offset == -1);
|
||||
|
||||
// Figure out how many samples we can safely give it.
|
||||
int maxSamples = pThis->m_SrcLen - pThis->m_CurSrcPos;
|
||||
int samplesToGive = MIN(maxSamples, bytes_requested/2);
|
||||
|
||||
// Convert to 16-bit signed mono.
|
||||
short *pOut = (short*)dest;
|
||||
for(int i=0; i < samplesToGive; i++)
|
||||
{
|
||||
pOut[i] = pThis->m_pSrc[pThis->m_CurSrcPos+i] << 8;
|
||||
}
|
||||
|
||||
pThis->m_CurSrcPos += samplesToGive;
|
||||
return samplesToGive * 2;
|
||||
}
|
||||
|
||||
S32 AILCALLBACK FrameEncoder_Miles::DecodeStreamCB(
|
||||
UINTa user, // User value passed to ASI_open_stream()
|
||||
void *dest, // Location to which stream data should be copied by app
|
||||
S32 bytes_requested, // # of bytes requested by ASI codec
|
||||
S32 offset // If not -1, application should seek to this point in stream
|
||||
)
|
||||
{
|
||||
FrameEncoder_Miles *pThis = (FrameEncoder_Miles*)user;
|
||||
Assert(pThis && offset == -1);
|
||||
|
||||
int maxBytes = pThis->m_SrcLen - pThis->m_CurSrcPos;
|
||||
int bytesToGive = MIN(maxBytes, bytes_requested);
|
||||
memcpy(dest, &pThis->m_pSrc[pThis->m_CurSrcPos], bytesToGive);
|
||||
|
||||
pThis->m_CurSrcPos += bytesToGive;
|
||||
return bytesToGive;
|
||||
}
|
||||
|
||||
|
||||
void FrameEncoder_Miles::FigureOutFrameSizes()
|
||||
{
|
||||
// Figure out the frame sizes. It is probably not prudent in general to assume fixed frame sizes with Miles codecs
|
||||
// but it works with the voxware codec right now and simplifies things a lot.
|
||||
m_nRawBytes = (int)m_Encoder.GetProperty( m_Encoder.INPUT_BLOCK_SIZE );
|
||||
|
||||
char uncompressed[1024];
|
||||
char compressed[1024];
|
||||
|
||||
Assert(m_nRawBytes <= sizeof(uncompressed));
|
||||
|
||||
m_pSrc = uncompressed;
|
||||
m_SrcLen = m_nRawBytes;
|
||||
m_CurSrcPos = 0;
|
||||
|
||||
m_nEncodedBytes = (int)m_Encoder.Process( compressed, sizeof(compressed) );
|
||||
}
|
||||
|
||||
|
||||
|
||||
class IVoiceCodec;
|
||||
extern IVoiceCodec* CreateVoiceCodec_Frame(IFrameEncoder *pEncoder);
|
||||
void* CreateVoiceCodec_Miles()
|
||||
{
|
||||
IFrameEncoder *pEncoder = new FrameEncoder_Miles;
|
||||
if(!pEncoder)
|
||||
return NULL;
|
||||
|
||||
return CreateVoiceCodec_Frame(pEncoder);
|
||||
}
|
||||
|
||||
EXPOSE_INTERFACE_FN(CreateVoiceCodec_Miles, IVoiceCodec, "vaudio_miles")
|
||||
|
||||
|
||||
Reference in New Issue
Block a user