chore(fmod): add files from Chensne/DragonNest
This commit is contained in:
commit
50fb3c6b1c
544 changed files with 315778 additions and 0 deletions
13755
src/fmod.cpp
Executable file
13755
src/fmod.cpp
Executable file
File diff suppressed because it is too large
Load diff
285
src/fmod_3d.h
Executable file
285
src/fmod_3d.h
Executable file
|
|
@ -0,0 +1,285 @@
|
|||
#ifndef _FMOD_3D_H
|
||||
#define _FMOD_3D_H
|
||||
|
||||
#include "fmod_settings.h"
|
||||
|
||||
#include "fmod.h"
|
||||
#include "fmod_types.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
/*
|
||||
CONSTANTS
|
||||
*/
|
||||
|
||||
#define FMOD_3D_MAXLISTENERS 4
|
||||
|
||||
/*
|
||||
MACROS
|
||||
*/
|
||||
|
||||
#define FMOD_Vector_CrossProduct(_a, _b, _r) \
|
||||
(_r)->x = ((_a)->y * (_b)->z) - ((_a)->z * (_b)->y); \
|
||||
(_r)->y = ((_a)->z * (_b)->x) - ((_a)->x * (_b)->z); \
|
||||
(_r)->z = ((_a)->x * (_b)->y) - ((_a)->y * (_b)->x);
|
||||
|
||||
#define FMOD_Vector_Subtract(_a, _b, _r) \
|
||||
(_r)->x = (_a)->x - (_b)->x; \
|
||||
(_r)->y = (_a)->y - (_b)->y; \
|
||||
(_r)->z = (_a)->z - (_b)->z;
|
||||
|
||||
#define FMOD_Vector_Add(_a, _b, _r) \
|
||||
(_r)->x = (_a)->x + (_b)->x; \
|
||||
(_r)->y = (_a)->y + (_b)->y; \
|
||||
(_r)->z = (_a)->z + (_b)->z;
|
||||
|
||||
#define FMOD_Vector_Set(_r, _x, _y, _z) \
|
||||
(_r)->x = (_x); \
|
||||
(_r)->y = (_y); \
|
||||
(_r)->z = (_z);
|
||||
|
||||
#define FMOD_Vector_Copy(_a, _r) \
|
||||
(_r)->x = (_a)->x; \
|
||||
(_r)->y = (_a)->y; \
|
||||
(_r)->z = (_a)->z;
|
||||
|
||||
#define FMOD_Vector_DotProduct(_a, _b) \
|
||||
(((_a)->x * (_b)->x) + ((_a)->y * (_b)->y) + ((_a)->z * (_b)->z))
|
||||
|
||||
#define FMOD_Vector_DotProduct64(_a, _b) \
|
||||
FMOD_SCALEDOWN64( ((FMOD_SINT64)((_a)->x) * (FMOD_SINT64)((_b)->x)) + ((FMOD_SINT64)((_a)->y) * (FMOD_SINT64)((_b)->y)) + ((FMOD_SINT64)((_a)->z) * (FMOD_SINT64)((_b)->z)) )
|
||||
|
||||
#define FMOD_Vector_Scale(_a, _s, _r) \
|
||||
(_r)->x = ((_a)->x * (_s)); \
|
||||
(_r)->y = ((_a)->y * (_s)); \
|
||||
(_r)->z = ((_a)->z * (_s));
|
||||
|
||||
static FMOD_INLINE void FMOD_Vector_AxisRotate(FMOD_VECTOR *in,FMOD_VECTOR *at,FMOD_VECTOR *up,float theta)
|
||||
{
|
||||
float a,b,c,u,v,w,x,y,z;
|
||||
float cost,sint;
|
||||
|
||||
a = at->x;
|
||||
b = at->y;
|
||||
c = at->z;
|
||||
|
||||
u = up->x;
|
||||
v = up->y;
|
||||
w = up->z;
|
||||
|
||||
x = in->x;
|
||||
y = in->y;
|
||||
z = in->z;
|
||||
|
||||
cost = FMOD_COS(theta);
|
||||
sint = FMOD_SIN(theta);
|
||||
|
||||
in->x=(a*(v*v+w*w)+u*(-b*v-c*w+u*x+v*y+w*z)+((x-a)*(v*v+w*w)+u*(b*v+c*w-v*y-w*z))*cost+FMOD_SQRT(u*u+v*v+w*w)*(b*w-c*v-w*y+v*z)*sint)/(u*u+v*v+w*w);
|
||||
in->y=(b*(u*u+w*w)+v*(-a*u-c*w+u*x+v*y+w*z)+((y-b)*(u*u+w*w)+v*(a*u+c*w-u*x-w*z))*cost+FMOD_SQRT(u*u+v*v+w*w)*(-a*w+c*u+w*x-u*z)*sint)/(u*u+v*v+w*w);
|
||||
in->z=(c*(u*u+v*v)+w*(-a*u-b*v+u*x+v*y+w*z)+((z-c)*(u*u+v*v)+w*(a*u+b*v-u*x-v*y))*cost+FMOD_SQRT(u*u+v*v+w*w)*(a*v-b*u-v*x+u*y)*sint)/(u*u+v*v+w*w);
|
||||
}
|
||||
|
||||
static FMOD_INLINE int FMOD_Cart2Angle(int y, int x)
|
||||
{
|
||||
int coeff_1, coeff_2, abs_y;
|
||||
int r, angle;
|
||||
|
||||
#define SHIFT 10
|
||||
#define M_PII (int)(3.1415926535897932384626433832795f * (float)(1<<SHIFT))
|
||||
|
||||
if (!x && !y)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
x <<= SHIFT;
|
||||
y <<= SHIFT;
|
||||
|
||||
coeff_1 = M_PII/4;
|
||||
coeff_2 = 3*coeff_1;
|
||||
|
||||
abs_y = abs(y) + 1 ; /* kludge to prevent 0/0 condition */
|
||||
|
||||
if (x >= 0)
|
||||
{
|
||||
r = (x - abs_y) / ((x + abs_y) >> SHIFT);
|
||||
angle = coeff_1 - ((coeff_1 * r) >> SHIFT);
|
||||
}
|
||||
else
|
||||
{
|
||||
r = (x + abs_y) / ((abs_y - x) >> SHIFT);
|
||||
angle = coeff_2 - ((coeff_1 * r) >> SHIFT);
|
||||
}
|
||||
|
||||
if (y < 0)
|
||||
{
|
||||
angle = -angle; /* negate if in quad III or IV */
|
||||
}
|
||||
|
||||
angle *= 180;
|
||||
angle /= M_PII;
|
||||
angle = (angle < 0) ? angle + 360 : (angle >= 360) ? angle - 360 : angle;
|
||||
|
||||
return angle;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Angle Sort Functions
|
||||
====================
|
||||
Functions for quick sorting and comparison of 2D vector angles.
|
||||
Values are in the range [0,8) and correspond to the angles shown below:
|
||||
|
||||
y
|
||||
0.0 | 2.0
|
||||
.-+-.
|
||||
---+ + +--- x
|
||||
.-+-.
|
||||
6.0 | 4.0
|
||||
*/
|
||||
|
||||
#define FMOD_ANGLESORT_REVOLUTION 8.0f
|
||||
#define FMOD_ANGLESORT_STRAIGHT_TOLERANCE 0.002f /* ~0.1 degrees */
|
||||
|
||||
/*
|
||||
Return an angle in the range [0,8) from cartesian coordinates. (vector doesn't need to be normalised)
|
||||
*/
|
||||
static FMOD_INLINE float FMOD_AngleSort_GetValue(float x, float y)
|
||||
{
|
||||
if(x == 0.0f && y == 0.0f)
|
||||
{
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
float abs_y = FMOD_ABS(y);
|
||||
float abs_x = FMOD_ABS(x);
|
||||
float value;
|
||||
|
||||
if(abs_x <= abs_y)
|
||||
{
|
||||
/*
|
||||
Top and bottom sides of square.
|
||||
The angle is calculated for positive 'y' and then mirrored if y is negative.
|
||||
(-1, 1) => 0; (1, 1) => 2
|
||||
*/
|
||||
value = x / abs_y + 1.0f;
|
||||
|
||||
if(y < 0.0f)
|
||||
{
|
||||
/* values 0 -> 2 (front) map to values 6 -> 4 (back) */
|
||||
return 6.0f - value;
|
||||
}
|
||||
else
|
||||
{
|
||||
return value;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
Left and right sides of square.
|
||||
The angle is calculated for positive 'x' and then mirrored if x is negative.
|
||||
(1, -1) => 4; (1, 1) => 2
|
||||
*/
|
||||
value = 3.0f - y / abs_x;
|
||||
|
||||
if(x < 0.0f)
|
||||
{
|
||||
/* values 2 -> 4 (front) map to values 8 -> 6 (back) */
|
||||
return 10.0f - value;
|
||||
}
|
||||
else
|
||||
{
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Check that values in the range [0,8) represent angles sorted in a clockwise order.
|
||||
(or anti-clockwise for left-handed coordinate systems)
|
||||
*/
|
||||
static FMOD_INLINE bool FMOD_AngleSort_IsClockwise(float a, float b, float c)
|
||||
{
|
||||
float c_unwrapped = (c >= a) ? c : c + FMOD_ANGLESORT_REVOLUTION;
|
||||
|
||||
return (a <= b && b < c_unwrapped) || (a <= b + FMOD_ANGLESORT_REVOLUTION && b + FMOD_ANGLESORT_REVOLUTION < c_unwrapped);
|
||||
}
|
||||
|
||||
/*
|
||||
Checks if the clockwise (or anti-clockwise for left-handed coordinate systems) difference
|
||||
between two angles is 180 degrees (FMOD_AngleSort_IsStraight) or more (FMOD_AngleSort_IsReflex).
|
||||
*/
|
||||
#define FMOD_AngleSort_IsStraight(_a, _b) (FMOD_ABS(FMOD_ABS((_b) - (_a)) - FMOD_ANGLESORT_REVOLUTION * 0.5f) <= FMOD_ANGLESORT_STRAIGHT_TOLERANCE)
|
||||
#define FMOD_AngleSort_IsReflex(_a, _b) (((_b) - (_a) > FMOD_ANGLESORT_REVOLUTION * 0.5f) || (((_a) > (_b)) && ((_a) - (_b) < FMOD_ANGLESORT_REVOLUTION * 0.5f)))
|
||||
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#define FMOD_Vector_GetLengthFast(_x) FMOD_SQRT(FMOD_Vector_DotProduct((_x), (_x)))
|
||||
#define FMOD_Vector_GetLength(_x) FMOD_SQRT(FMOD_Vector_DotProduct((_x), (_x)))
|
||||
|
||||
|
||||
static FMOD_INLINE void FMOD_Vector_Normalize(FMOD_VECTOR *v)
|
||||
{
|
||||
float distance = FMOD_Vector_GetLength(v);
|
||||
|
||||
if (distance <= 0)
|
||||
{
|
||||
v->x = 0;
|
||||
v->y = 0;
|
||||
v->z = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
Normalize
|
||||
*/
|
||||
v->x = v->x / distance;
|
||||
v->y = v->y / distance;
|
||||
v->z = v->z / distance;
|
||||
}
|
||||
}
|
||||
|
||||
static FMOD_INLINE FMOD_RESULT FMOD_CHECKFLOAT(float value)
|
||||
{
|
||||
int s, e;
|
||||
unsigned long src;
|
||||
long f;
|
||||
union {
|
||||
float fval;
|
||||
unsigned int ival;
|
||||
} u;
|
||||
u.fval = value;
|
||||
|
||||
src = u.ival;
|
||||
|
||||
s = (src & 0x80000000UL) >> 31;
|
||||
e = (src & 0x7F800000UL) >> 23;
|
||||
f = (src & 0x007FFFFFUL);
|
||||
|
||||
if (e == 255 && f != 0)
|
||||
{
|
||||
return FMOD_ERR_INVALID_FLOAT;
|
||||
}
|
||||
else if (e == 255 && f == 0 && s == 1)
|
||||
{
|
||||
return FMOD_ERR_INVALID_FLOAT;
|
||||
}
|
||||
else if (e == 255 && f == 0 && s == 0)
|
||||
{
|
||||
return FMOD_ERR_INVALID_FLOAT;
|
||||
}
|
||||
else if (e == 0 && f != 0)
|
||||
{
|
||||
return FMOD_ERR_INVALID_FLOAT;
|
||||
}
|
||||
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
674
src/fmod_async.cpp
Executable file
674
src/fmod_async.cpp
Executable file
|
|
@ -0,0 +1,674 @@
|
|||
#include "fmod_settings.h"
|
||||
|
||||
#ifdef FMOD_SUPPORT_NONBLOCKING
|
||||
|
||||
#include "fmod_async.h"
|
||||
#include "fmod_dspi.h"
|
||||
#include "fmod_soundi.h"
|
||||
#include "fmod_systemi.h"
|
||||
|
||||
namespace FMOD
|
||||
{
|
||||
|
||||
LinkedListNode AsyncThread::gAsyncHead;
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
void asyncThreadFunc(void *data)
|
||||
{
|
||||
AsyncThread *asyncThread = (AsyncThread *)data;
|
||||
asyncThread->threadFunc();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
AsyncThread::AsyncThread()
|
||||
{
|
||||
mCrit = 0;
|
||||
mThreadActive = false;
|
||||
mBusy = false;
|
||||
mDone = false;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT AsyncThread::shutDown()
|
||||
{
|
||||
if (FMOD::gGlobal->gAsyncCrit)
|
||||
{
|
||||
AsyncThread *asyncthread;
|
||||
LinkedListNode *current, *next;
|
||||
|
||||
FMOD_OS_CriticalSection_Enter(FMOD::gGlobal->gAsyncCrit);
|
||||
{
|
||||
current = gAsyncHead.getNext();
|
||||
while (current != &gAsyncHead)
|
||||
{
|
||||
next = current->getNext();
|
||||
|
||||
asyncthread = SAFE_CAST(AsyncThread, current);
|
||||
asyncthread->reallyRelease();
|
||||
|
||||
current = next;
|
||||
}
|
||||
}
|
||||
FMOD_OS_CriticalSection_Leave(FMOD::gGlobal->gAsyncCrit);
|
||||
}
|
||||
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT AsyncThread::addCallback(FMOD_ASYNC_CALLBACK callback, AsyncThread **asyncthread)
|
||||
{
|
||||
FMOD_RESULT result;
|
||||
|
||||
if (asyncthread)
|
||||
{
|
||||
*asyncthread = 0;
|
||||
}
|
||||
|
||||
LinkedListNode *node = (LinkedListNode *)FMOD_Object_Alloc(LinkedListNode);
|
||||
if (!node)
|
||||
{
|
||||
return FMOD_ERR_MEMORY;
|
||||
}
|
||||
|
||||
node->setData((void *)callback);
|
||||
|
||||
/*
|
||||
Make sure there's a thread for us
|
||||
*/
|
||||
result = getAsyncThread(0);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
LinkedListNode *threadnode = gAsyncHead.getNext();
|
||||
if (threadnode != &gAsyncHead)
|
||||
{
|
||||
AsyncThread *thread = SAFE_CAST(AsyncThread, threadnode);
|
||||
FMOD_OS_CriticalSection_Enter(FMOD::gGlobal->gAsyncCrit);
|
||||
{
|
||||
node->addBefore(&thread->mCallbackHead);
|
||||
}
|
||||
FMOD_OS_CriticalSection_Leave(FMOD::gGlobal->gAsyncCrit);
|
||||
|
||||
if (asyncthread)
|
||||
{
|
||||
*asyncthread = thread;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return FMOD_ERR_INTERNAL;
|
||||
}
|
||||
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT AsyncThread::removeCallback(FMOD_ASYNC_CALLBACK callback)
|
||||
{
|
||||
LinkedListNode *threadnode = gAsyncHead.getNext();
|
||||
|
||||
if (threadnode != &gAsyncHead)
|
||||
{
|
||||
AsyncThread *asyncthread = SAFE_CAST(AsyncThread, threadnode);
|
||||
|
||||
FMOD_OS_CriticalSection_Enter(FMOD::gGlobal->gAsyncCrit);
|
||||
|
||||
LinkedListNode *callbacknode = asyncthread->mCallbackHead.getNext();
|
||||
for (; callbacknode != &asyncthread->mCallbackHead; callbacknode = callbacknode->getNext())
|
||||
{
|
||||
if (callbacknode->getData() == (void *)callback)
|
||||
{
|
||||
callbacknode->removeNode();
|
||||
FMOD_Memory_Free(callbacknode);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
FMOD_OS_CriticalSection_Leave(FMOD::gGlobal->gAsyncCrit);
|
||||
}
|
||||
else
|
||||
{
|
||||
return FMOD_ERR_INTERNAL;
|
||||
}
|
||||
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT AsyncThread::init(bool owned, SystemI *system)
|
||||
{
|
||||
FMOD_RESULT result;
|
||||
|
||||
mOwned = owned;
|
||||
|
||||
result = FMOD_OS_CriticalSection_Create(&mCrit);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
result = mThread.initThread("FMOD thread for FMOD_NONBLOCKING", asyncThreadFunc, this, ASYNC_THREADPRIORITY, 0, ASYNC_STACKSIZE, true, 0, system);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
mThreadActive = true;
|
||||
|
||||
FMOD_OS_CriticalSection_Enter(FMOD::gGlobal->gAsyncCrit);
|
||||
addBefore(&gAsyncHead);
|
||||
FMOD_OS_CriticalSection_Leave(FMOD::gGlobal->gAsyncCrit);
|
||||
|
||||
FLOG((FMOD_DEBUG_USER_ANDREW, __FILE__, __LINE__, "AsyncThread::init", "created thread for %p %s\n", this, mOwned ? "(owned)" : ""));
|
||||
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT AsyncThread::release()
|
||||
{
|
||||
if (mOwned)
|
||||
{
|
||||
if (mHead.getNext() != &mHead)
|
||||
{
|
||||
FLOG((FMOD_DEBUG_USER_ANDREW, __FILE__, __LINE__, "AsyncThread::release", "%p queue not empty\n", this));
|
||||
}
|
||||
|
||||
mDone = true;
|
||||
}
|
||||
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT AsyncThread::reallyRelease()
|
||||
{
|
||||
FMOD_OS_CriticalSection_Enter(mCrit);
|
||||
{
|
||||
if (mHead.getNext() != &mHead)
|
||||
{
|
||||
FLOG((FMOD_DEBUG_USER_ANDREW, __FILE__, __LINE__, "AsyncThread::reallyRelease", "%p queue not empty\n", this));
|
||||
}
|
||||
if (mBusy)
|
||||
{
|
||||
FLOG((FMOD_DEBUG_USER_ANDREW, __FILE__, __LINE__, "AsyncThread::reallyRelease", "%p still busy\n", this));
|
||||
}
|
||||
|
||||
LinkedListNode *next, *current = mCallbackHead.getNext();
|
||||
while (current != &mCallbackHead)
|
||||
{
|
||||
next = current->getNext();
|
||||
current->removeNode();
|
||||
FMOD_Memory_Free(current);
|
||||
current = next;
|
||||
}
|
||||
}
|
||||
FMOD_OS_CriticalSection_Leave(mCrit);
|
||||
|
||||
// FMOD_OS_CriticalSection_Enter(FMOD::gGlobal->gAsyncCrit);
|
||||
removeNode();
|
||||
// FMOD_OS_CriticalSection_Leave(FMOD::gGlobal->gAsyncCrit);
|
||||
|
||||
mThreadActive = false;
|
||||
mThread.closeThread();
|
||||
|
||||
if (mCrit)
|
||||
{
|
||||
FMOD_OS_CriticalSection_Free(mCrit);
|
||||
}
|
||||
|
||||
FLOG((FMOD_DEBUG_USER_ANDREW, __FILE__, __LINE__, "AsyncThread::reallyRelease", "released thread for %p %s\n", this, mOwned ? "(owned)" : ""));
|
||||
|
||||
FMOD_Memory_Free(this);
|
||||
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT AsyncThread::wakeupThread()
|
||||
{
|
||||
return mThread.wakeupThread();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT AsyncThread::update()
|
||||
{
|
||||
if (FMOD::gGlobal->gAsyncCrit)
|
||||
{
|
||||
AsyncThread *asyncthread;
|
||||
LinkedListNode *current, *next;
|
||||
|
||||
FMOD_OS_CriticalSection_Enter(FMOD::gGlobal->gAsyncCrit);
|
||||
{
|
||||
current = gAsyncHead.getNext();
|
||||
while (current != &gAsyncHead)
|
||||
{
|
||||
next = current->getNext();
|
||||
|
||||
asyncthread = SAFE_CAST(AsyncThread, current);
|
||||
if (asyncthread->mDone)
|
||||
{
|
||||
asyncthread->reallyRelease();
|
||||
}
|
||||
|
||||
current = next;
|
||||
}
|
||||
}
|
||||
FMOD_OS_CriticalSection_Leave(FMOD::gGlobal->gAsyncCrit);
|
||||
}
|
||||
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT AsyncThread::threadFunc()
|
||||
{
|
||||
FMOD_RESULT result = FMOD_OK;
|
||||
SoundI *sound = 0;
|
||||
SystemI *system;
|
||||
LinkedListNode *current;
|
||||
|
||||
if (mThreadActive)
|
||||
{
|
||||
FMOD_OS_CriticalSection_Enter(mCrit);
|
||||
{
|
||||
current = mHead.getNext();
|
||||
if (current != &mHead)
|
||||
{
|
||||
sound = (SoundI *)current->getData();
|
||||
current->removeNode();
|
||||
mBusy = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
current = 0;
|
||||
}
|
||||
}
|
||||
FMOD_OS_CriticalSection_Leave(mCrit);
|
||||
|
||||
if (sound)
|
||||
{
|
||||
FLOG((FMOD_DEBUG_LEVEL_LOG, __FILE__, __LINE__, "AsyncThread::threadFunc", "Starting Asynchronous operation on sound %p\n", sound));
|
||||
FLOG_INDENT(4);
|
||||
|
||||
system = sound->mSystem;
|
||||
|
||||
if (sound->mOpenState == FMOD_OPENSTATE_LOADING)
|
||||
{
|
||||
if (sound->mMode & (FMOD_OPENMEMORY | FMOD_OPENMEMORY_POINT))
|
||||
{
|
||||
result = system->createSoundInternal((const char *)sound->mAsyncData->mNameData, sound->mMode, sound->mAsyncData->mBufferSize, sound->mAsyncData->mBufferSizeType, sound->mAsyncData->mExInfoExists ? &sound->mAsyncData->mExInfo : 0, true, &sound);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = system->createSoundInternal(sound->mAsyncData->mName, sound->mMode, sound->mAsyncData->mBufferSize, sound->mAsyncData->mBufferSizeType, sound->mAsyncData->mExInfoExists ? &sound->mAsyncData->mExInfo : 0, true, &sound);
|
||||
}
|
||||
}
|
||||
#ifdef FMOD_SUPPORT_STREAMING
|
||||
#ifdef FMOD_SUPPORT_NONBLOCKSETPOS
|
||||
else if (sound->mOpenState == FMOD_OPENSTATE_SETPOSITION)
|
||||
{
|
||||
Stream *stream = SAFE_CAST(Stream, sound);
|
||||
|
||||
/*
|
||||
Block here and wait for stream thread to stop doing stuff.
|
||||
*/
|
||||
while (!(stream->mFlags & (FMOD_SOUND_FLAG_SETPOS_SAFE | FMOD_SOUND_FLAG_THREADFINISHED)))
|
||||
{
|
||||
FMOD_OS_Time_Sleep(10);
|
||||
}
|
||||
|
||||
if (!(stream->mFlags & FMOD_SOUND_FLAG_THREADFINISHED))
|
||||
{
|
||||
result = stream->mChannel->setPositionEx(sound->mAsyncData->mPosition, sound->mAsyncData->mPositionType, true);
|
||||
if (result == FMOD_OK)
|
||||
{
|
||||
stream->mChannel->mFlags &= ~CHANNELREAL_FLAG_PAUSEDFORSETPOS;
|
||||
|
||||
FMOD_OS_CriticalSection_Enter(sound->mSystem->mStreamRealchanCrit);
|
||||
if (stream->mChannel->mRealChannel[0])
|
||||
{
|
||||
stream->mChannel->setPaused(stream->mChannel->mFlags & CHANNELREAL_FLAG_PAUSED ? true : false);
|
||||
}
|
||||
FMOD_OS_CriticalSection_Leave(sound->mSystem->mStreamRealchanCrit);
|
||||
}
|
||||
else if (result == FMOD_ERR_INVALID_HANDLE)
|
||||
{
|
||||
result = FMOD_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
else if (sound->mOpenState == FMOD_OPENSTATE_SEEKING)
|
||||
{
|
||||
Stream *stream = SAFE_CAST(Stream, sound);
|
||||
|
||||
if (stream->mSubSoundList)
|
||||
{
|
||||
result = FMOD_OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = stream->updateSubSound(stream->mSubSoundIndex, false);
|
||||
}
|
||||
|
||||
if (result == FMOD_OK)
|
||||
{
|
||||
result = stream->setPosition(0, FMOD_TIMEUNIT_PCM);
|
||||
FLOG((FMOD_DEBUG_LEVEL_LOG, __FILE__, __LINE__, "AsyncThread::threadFunc", "done setposition\n"));
|
||||
if (result == FMOD_OK)
|
||||
{
|
||||
result = stream->flush();
|
||||
if (result == FMOD_OK)
|
||||
{
|
||||
FLOG((FMOD_DEBUG_LEVEL_LOG, __FILE__, __LINE__, "AsyncThread::threadFunc", "done flush\n"));
|
||||
}
|
||||
else
|
||||
{
|
||||
FLOG((FMOD_DEBUG_LEVEL_LOG, __FILE__, __LINE__, "AsyncThread::threadFunc", "stream->flush returned %d\n", result));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
FLOG((FMOD_DEBUG_LEVEL_LOG, __FILE__, __LINE__, "AsyncThread::threadFunc", "stream->setPosition returned %d\n", result));
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
else
|
||||
{
|
||||
FLOG((FMOD_DEBUG_LEVEL_LOG, __FILE__, __LINE__, "AsyncThread::threadFunc", "AsyncThread::threadFunc: unexpected mOpenState (%d). Result = %d\n", sound->mOpenState, result));
|
||||
}
|
||||
|
||||
sound->mAsyncData->mResult = result;
|
||||
sound->mFlags |= FMOD_SOUND_FLAG_DONOTRELEASE; /* Dissalow release... */
|
||||
sound->mOpenState = (result == FMOD_OK) ? FMOD_OPENSTATE_READY : FMOD_OPENSTATE_ERROR; /* .. but allow everything else. */
|
||||
if (sound->mSubSoundParent)
|
||||
{
|
||||
sound->mSubSoundParent->mOpenState = sound->mOpenState;
|
||||
}
|
||||
if (sound->mSubSoundShared)
|
||||
{
|
||||
sound->mSubSoundShared->mOpenState = sound->mOpenState;
|
||||
}
|
||||
mBusy = false;
|
||||
|
||||
if (sound->mAsyncData->mExInfoExists)
|
||||
{
|
||||
if (sound->mAsyncData->mExInfo.nonblockcallback)
|
||||
{
|
||||
sound->mUserData = sound->mAsyncData->mExInfo.userdata;
|
||||
|
||||
sound->mAsyncData->mExInfo.nonblockcallback((FMOD_SOUND *)sound, result);
|
||||
}
|
||||
}
|
||||
|
||||
sound->mFlags &= ~FMOD_SOUND_FLAG_DONOTRELEASE;
|
||||
|
||||
/*
|
||||
Release this thread if it's owned
|
||||
*/
|
||||
release();
|
||||
|
||||
FLOG_INDENT(-4);
|
||||
FLOG((FMOD_DEBUG_LEVEL_LOG, __FILE__, __LINE__, "AsyncThread::threadFunc", "Finished Asynchronous operation on sound %p\n", sound));
|
||||
}
|
||||
|
||||
/*
|
||||
Call any callbacks that have been added
|
||||
*/
|
||||
LinkedListNode *node;
|
||||
|
||||
FMOD_OS_CriticalSection_Enter(mCrit);
|
||||
{
|
||||
node = mCallbackHead.getNext();
|
||||
}
|
||||
FMOD_OS_CriticalSection_Leave(mCrit);
|
||||
|
||||
while (node != &mCallbackHead)
|
||||
{
|
||||
FMOD_ASYNC_CALLBACK callback = (FMOD_ASYNC_CALLBACK)node->getData();
|
||||
|
||||
result = callback();
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
FMOD_OS_CriticalSection_Enter(mCrit);
|
||||
{
|
||||
node = node->getNext();
|
||||
}
|
||||
FMOD_OS_CriticalSection_Leave(mCrit);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT AsyncThread::getAsyncThread(SoundI *sound)
|
||||
{
|
||||
FMOD_RESULT result;
|
||||
LinkedListNode *current;
|
||||
bool found, owned;
|
||||
AsyncThread *asyncthread = 0;
|
||||
|
||||
owned = false;
|
||||
found = false;
|
||||
|
||||
FMOD_OS_CriticalSection_Enter(FMOD::gGlobal->gAsyncCrit);
|
||||
{
|
||||
current = gAsyncHead.getNext();
|
||||
if (current != &gAsyncHead)
|
||||
{
|
||||
asyncthread = SAFE_CAST(AsyncThread, current);
|
||||
|
||||
FMOD_OS_CriticalSection_Enter(asyncthread->mCrit);
|
||||
{
|
||||
if (0) //(asyncthread->mHead.getNext() != &asyncthread->mHead) || asyncthread->mBusy || asyncthread->mDone)
|
||||
{
|
||||
owned = true; /* The first asyncthread is or will be busy so make a new one */
|
||||
}
|
||||
else
|
||||
{
|
||||
found = true; /* The first asyncthread isn't doing anything so use it */
|
||||
}
|
||||
}
|
||||
FMOD_OS_CriticalSection_Leave(asyncthread->mCrit);
|
||||
}
|
||||
}
|
||||
FMOD_OS_CriticalSection_Leave(FMOD::gGlobal->gAsyncCrit);
|
||||
|
||||
if (!found)
|
||||
{
|
||||
asyncthread = FMOD_Object_Alloc(AsyncThread);
|
||||
if (!asyncthread)
|
||||
{
|
||||
return FMOD_ERR_MEMORY;
|
||||
}
|
||||
|
||||
result = asyncthread->init(owned, sound ? sound->mSystem : 0);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
if (sound)
|
||||
{
|
||||
if (sound->mAsyncData->mThread)
|
||||
{
|
||||
FLOG((FMOD_DEBUG_USER_ANDREW, __FILE__, __LINE__, "AsyncThread::getAsyncThread", "sound->mAsyncData->Thread not null == %p\n", sound->mAsyncData->mThread));
|
||||
}
|
||||
|
||||
sound->mAsyncData->mThread = asyncthread;
|
||||
}
|
||||
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
83
src/fmod_async.h
Executable file
83
src/fmod_async.h
Executable file
|
|
@ -0,0 +1,83 @@
|
|||
#ifndef _FMOD_ASYNC_H
|
||||
#define _FMOD_ASYNC_H
|
||||
|
||||
#ifndef _FMOD_SETTINGS_H
|
||||
#include "fmod_settings.h"
|
||||
#endif
|
||||
|
||||
#ifndef _FMOD_LINKEDLIST_H
|
||||
#include "fmod_linkedlist.h"
|
||||
#endif
|
||||
#ifndef _FMOD_THREAD_H
|
||||
#include "fmod_thread.h"
|
||||
#endif
|
||||
#ifndef _FMOD_SOUND_STREAM_H
|
||||
#include "fmod_sound_stream.h"
|
||||
#endif
|
||||
|
||||
typedef FMOD_RESULT (F_CALLBACK *FMOD_ASYNC_CALLBACK)();
|
||||
|
||||
namespace FMOD
|
||||
{
|
||||
class SoundI;
|
||||
|
||||
class AsyncThread : public LinkedListNode /* This linked list node entry is for AsyncThread::gAsyncHead */
|
||||
{
|
||||
friend class SystemI;
|
||||
friend class Stream;
|
||||
friend class SoundI;
|
||||
friend class ChannelStream;
|
||||
friend void asyncThreadFunc(void *data);
|
||||
|
||||
private:
|
||||
|
||||
Thread mThread;
|
||||
bool mThreadActive;
|
||||
LinkedListNode mHead;
|
||||
FMOD_OS_CRITICALSECTION *mCrit;
|
||||
bool mOwned;
|
||||
bool mBusy;
|
||||
bool mDone;
|
||||
LinkedListNode mCallbackHead;
|
||||
|
||||
FMOD_RESULT threadFunc();
|
||||
FMOD_RESULT init(bool owned, SystemI *system);
|
||||
FMOD_RESULT reallyRelease();
|
||||
|
||||
|
||||
public :
|
||||
|
||||
static LinkedListNode gAsyncHead;
|
||||
|
||||
AsyncThread();
|
||||
|
||||
FMOD_RESULT release();
|
||||
FMOD_RESULT F_API wakeupThread();
|
||||
|
||||
static FMOD_RESULT getAsyncThread(SoundI *sound);
|
||||
static FMOD_RESULT update();
|
||||
static FMOD_RESULT shutDown();
|
||||
static FMOD_RESULT F_API addCallback(FMOD_ASYNC_CALLBACK callback, AsyncThread **asyncthread);
|
||||
static FMOD_RESULT F_API removeCallback(FMOD_ASYNC_CALLBACK callback);
|
||||
};
|
||||
|
||||
struct AsyncData
|
||||
{
|
||||
char mName[FMOD_STRING_MAXNAMELEN * 2]; // doubled to allow for Unicode strings
|
||||
unsigned int mBufferSize;
|
||||
FMOD_TIMEUNIT mBufferSizeType;
|
||||
AsyncThread *mThread;
|
||||
LinkedListNode mNode;
|
||||
void *mNameData;
|
||||
FMOD_CREATESOUNDEXINFO mExInfo;
|
||||
bool mExInfoExists;
|
||||
#ifdef FMOD_SUPPORT_NONBLOCKSETPOS
|
||||
unsigned int mPosition;
|
||||
FMOD_TIMEUNIT mPositionType;
|
||||
#endif
|
||||
|
||||
FMOD_RESULT mResult;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
307
src/fmod_autocleanup.h
Executable file
307
src/fmod_autocleanup.h
Executable file
|
|
@ -0,0 +1,307 @@
|
|||
#ifndef _FMOD_AUTOCLEANUP_H
|
||||
#define _FMOD_AUTOCLEANUP_H
|
||||
|
||||
#include "fmod_os_misc.h"
|
||||
#include "fmod_memory.h"
|
||||
#include "fmod_linkedlist.h"
|
||||
|
||||
#ifdef PLATFORM_WINDOWS
|
||||
// disable "identifier was truncated in the debug info" warnings
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable: 4786)
|
||||
#endif
|
||||
|
||||
namespace FMOD
|
||||
{
|
||||
|
||||
/*! \brief Parameterised resource cleanup.
|
||||
An object of this class stores a value of type \a T. \a T must provide a convesion
|
||||
to bool. If the value is valid (converts to true), the destructor calls the
|
||||
\a CleanupPolicy::cleanup function on it.
|
||||
Copying is disabled for this class, as it doesn't make sense and could easily
|
||||
lead to bugs.
|
||||
*/
|
||||
template <class T, class CleanupPolicy>
|
||||
class AutoCleanup : public CleanupPolicy
|
||||
{
|
||||
public:
|
||||
AutoCleanup(const T &val = T()) : m_val(val) { }
|
||||
~AutoCleanup() { if(m_val) CleanupPolicy::cleanup(m_val); }
|
||||
|
||||
/*! Sets the internal pointer.
|
||||
*/
|
||||
AutoCleanup<T, CleanupPolicy> &operator=(T val) { m_val = val; return *this; }
|
||||
bool operator!() { return !m_val; }
|
||||
|
||||
/*! Releases the internal pointer, so the cleanup policy will not be invoked.
|
||||
*/
|
||||
T releasePtr() { T tmp = m_val; m_val = T(); return tmp; }
|
||||
private:
|
||||
AutoCleanup(const AutoCleanup<T, CleanupPolicy> &other); // disabled
|
||||
void operator=(const AutoCleanup<T, CleanupPolicy> &other); // disabled
|
||||
T m_val;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
Convenience cleanup types
|
||||
These types wrap the AutoCleanup class for common cleanup policies so we
|
||||
have nicer template instantiation code everywhere.
|
||||
*/
|
||||
|
||||
/*! Stores a value of type T*.
|
||||
Cleanup: Calls T::close() on the stored pointer.
|
||||
*/
|
||||
template <class T>
|
||||
class AutoClose;
|
||||
|
||||
/*! Stores a value of type T*.
|
||||
Cleanup: Calls T::release() on the stored pointer.
|
||||
*/
|
||||
template <class T>
|
||||
class AutoRelease;
|
||||
|
||||
/*! Stores a value of type T*, and an FMOD_OS_CRITICALSECTION*.
|
||||
Cleanup: Enters the stored critical section, calls T::release() on the
|
||||
stored pointer and then exits the critical section.
|
||||
*/
|
||||
template <class T>
|
||||
class AutoCritRelease;
|
||||
|
||||
/*! Stores a value of type T*, and a cleanup function pointer.
|
||||
Cleanup: Calls the stored function pointer with the stored pointer as its argument.
|
||||
*/
|
||||
template <class T>
|
||||
class AutoCleanupFunc;
|
||||
|
||||
/*! Stores a value of type T**.
|
||||
Cleanup: Calls T::release() on *value, then sets *value to 0, where value
|
||||
is the stored T**.
|
||||
*/
|
||||
template <class T>
|
||||
class AutoReleaseClear;
|
||||
|
||||
/*! Stores a pointer of type T*, and a value of type T.
|
||||
Cleanup: Sets *pointer to the stored value.
|
||||
*/
|
||||
template <class T>
|
||||
class AutoSet;
|
||||
|
||||
/*! Stores a value of type T**.
|
||||
Cleanup: Calls FMOD_Memory_Free on *value, then sets *value to 0.
|
||||
*/
|
||||
template <class T>
|
||||
class AutoFreeClear;
|
||||
|
||||
/*! \class AutoFree
|
||||
Stores a value of type void*.
|
||||
Cleanup: Calls FMOD_Memory_Free on the stored value.
|
||||
*/
|
||||
|
||||
/*! \class AutoFreeCrit
|
||||
Stores a value of type FMOD_OS_CRITICALSECTION*.
|
||||
Cleanup: Calls FMOD_OS_CriticalSection_Free on the stored value.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
Cleanup policy and convenience class implementations
|
||||
*/
|
||||
|
||||
/*
|
||||
Cleanup policy classes
|
||||
*/
|
||||
|
||||
template <class T>
|
||||
class CleanupRelease
|
||||
{
|
||||
public:
|
||||
static void cleanup(T ptr) { ptr->release(); }
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class CleanupClose
|
||||
{
|
||||
public:
|
||||
static void cleanup(T ptr) { ptr->close(); }
|
||||
};
|
||||
|
||||
template <class T, class CleanupPolicy>
|
||||
class CleanupClear : public CleanupPolicy
|
||||
{
|
||||
public:
|
||||
static void cleanup(T ptr)
|
||||
{
|
||||
if(*ptr)
|
||||
{
|
||||
CleanupPolicy::cleanup(*ptr);
|
||||
*ptr = 0;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class CleanupSet
|
||||
{
|
||||
public:
|
||||
CleanupSet() : mSetValue() { }
|
||||
|
||||
void setValue(const T &value) { mSetValue = value; }
|
||||
void cleanup(T *ptr) { *ptr = mSetValue; }
|
||||
|
||||
private:
|
||||
T mSetValue;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class CleanupFree
|
||||
{
|
||||
public:
|
||||
static void cleanup(T ptr) { FMOD_Memory_Free(ptr); }
|
||||
};
|
||||
|
||||
template <>
|
||||
class CleanupFree<FMOD_OS_CRITICALSECTION*>
|
||||
{
|
||||
public:
|
||||
static void cleanup(FMOD_OS_CRITICALSECTION *ptr)
|
||||
{ FMOD_OS_CriticalSection_Free(ptr); }
|
||||
};
|
||||
|
||||
template <>
|
||||
class CleanupFree<FMOD_OS_SEMAPHORE*>
|
||||
{
|
||||
public:
|
||||
static void cleanup(FMOD_OS_SEMAPHORE *ptr)
|
||||
{ FMOD_OS_Semaphore_Free(ptr); }
|
||||
};
|
||||
|
||||
template <class T, class CleanupPolicy>
|
||||
class CleanupCrit : public CleanupPolicy
|
||||
{
|
||||
public:
|
||||
CleanupCrit() : mCrit(0) { }
|
||||
|
||||
void setCrit(FMOD_OS_CRITICALSECTION *crit) { mCrit = crit; }
|
||||
|
||||
void cleanup(T ptr)
|
||||
{
|
||||
if(mCrit) FMOD_OS_CriticalSection_Enter(mCrit);
|
||||
CleanupPolicy::cleanup(ptr);
|
||||
if(mCrit) FMOD_OS_CriticalSection_Leave(mCrit);
|
||||
}
|
||||
|
||||
private:
|
||||
FMOD_OS_CRITICALSECTION *mCrit;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class CleanupFuncPtr
|
||||
{
|
||||
public:
|
||||
typedef void (F_STDCALL *CleanupFunction)(T);
|
||||
|
||||
CleanupFuncPtr() : mFunc(0) { }
|
||||
|
||||
void setFunc(CleanupFunction func) { mFunc = func; }
|
||||
|
||||
void cleanup(T val)
|
||||
{
|
||||
if(mFunc) mFunc(val);
|
||||
}
|
||||
|
||||
private:
|
||||
CleanupFunction mFunc;
|
||||
};
|
||||
|
||||
/*
|
||||
Convenience cleanup type implementations
|
||||
*/
|
||||
|
||||
template <class T>
|
||||
class AutoClose : public AutoCleanup<T*, CleanupClose<T*> >
|
||||
{
|
||||
public:
|
||||
typedef AutoCleanup<T*, CleanupClose<T*> > Base;
|
||||
|
||||
AutoClose(T *ptr = 0) : Base(ptr) { }
|
||||
AutoClose<T> &operator=(T *ptr) { Base::operator=(ptr); return *this; }
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class AutoRelease : public AutoCleanup<T*, CleanupRelease<T*> >
|
||||
{
|
||||
public:
|
||||
typedef AutoCleanup<T*, CleanupRelease<T*> > Base;
|
||||
|
||||
AutoRelease(T *ptr = 0) : Base(ptr) { }
|
||||
AutoRelease<T> &operator=(T *ptr) { Base::operator=(ptr); return *this; }
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class AutoCritRelease : public AutoCleanup<T*, CleanupCrit<T*, CleanupRelease<T*> > >
|
||||
{
|
||||
public:
|
||||
typedef AutoCleanup<T*, CleanupCrit<T*, CleanupRelease<T*> > > Base;
|
||||
|
||||
AutoCritRelease(FMOD_OS_CRITICALSECTION *crit, T *ptr = 0) : Base(ptr)
|
||||
{ Base::setCrit(crit); }
|
||||
AutoCritRelease<T> &operator=(T *ptr) { Base::operator=(ptr); return *this; }
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class AutoCleanupFunc : public AutoCleanup<T*, CleanupFuncPtr<T*> >
|
||||
{
|
||||
public:
|
||||
typedef void (F_STDCALL *CleanupFunction)(T *ptr);
|
||||
typedef AutoCleanup<T*, CleanupFuncPtr<T*> > Base;
|
||||
|
||||
AutoCleanupFunc(CleanupFunction func, T *ptr = 0) : Base(ptr)
|
||||
{ setFunc(func); }
|
||||
AutoCleanupFunc<T> &operator=(T *ptr) { Base::operator=(ptr); return *this; }
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class AutoReleaseClear : public AutoCleanup<T*, CleanupClear<T*, CleanupRelease<T> > >
|
||||
{
|
||||
public:
|
||||
typedef AutoCleanup<T*, CleanupClear<T*, CleanupRelease<T> > > Base;
|
||||
|
||||
AutoReleaseClear(T *ptr = 0) : Base(ptr) { }
|
||||
AutoReleaseClear<T> &operator=(T *ptr) { Base::operator=(ptr); return *this; }
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class AutoSet : public AutoCleanup<T*, CleanupSet<T> >
|
||||
{
|
||||
public:
|
||||
typedef AutoCleanup<T*, CleanupSet<T> > Base;
|
||||
|
||||
AutoSet(const T &value, T *ptr = 0) : Base(ptr)
|
||||
{ setValue(value); }
|
||||
AutoSet<T> &operator=(T *ptr) { Base::operator=(ptr); return *this; }
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class AutoFreeClear : public AutoCleanup<T*, CleanupClear<T*, CleanupFree<T> > >
|
||||
{
|
||||
public:
|
||||
typedef AutoCleanup<T*, CleanupClear<T*, CleanupFree<T> > > Base;
|
||||
|
||||
AutoFreeClear(T *ptr = 0) : Base(ptr) { }
|
||||
AutoFreeClear<T> &operator=(T *ptr) { Base::operator=(ptr); return *this; }
|
||||
};
|
||||
|
||||
typedef AutoCleanup<void*, CleanupFree<void*> > AutoFree;
|
||||
typedef AutoCleanup<FMOD_OS_CRITICALSECTION*,
|
||||
CleanupFree<FMOD_OS_CRITICALSECTION*> > AutoFreeCrit;
|
||||
typedef AutoCleanup<FMOD_OS_SEMAPHORE*,
|
||||
CleanupFree<FMOD_OS_SEMAPHORE*> > AutoFreeSema;
|
||||
|
||||
} // namespace FMOD
|
||||
|
||||
#ifdef PLATFORM_WINDOWS
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
#endif // _FMOD_AUTOCLEANUP_H
|
||||
1363
src/fmod_channel.cpp
Executable file
1363
src/fmod_channel.cpp
Executable file
File diff suppressed because it is too large
Load diff
539
src/fmod_channel_emulated.cpp
Executable file
539
src/fmod_channel_emulated.cpp
Executable file
|
|
@ -0,0 +1,539 @@
|
|||
#include "fmod_settings.h"
|
||||
|
||||
#include "fmod_channeli.h"
|
||||
#include "fmod_channel_emulated.h"
|
||||
#include "fmod_debug.h"
|
||||
#include "fmod_dspi.h"
|
||||
#include "fmod_sound_stream.h"
|
||||
#include "fmod_soundi.h"
|
||||
#include "fmod_systemi.h"
|
||||
#include "fmod_os_misc.h"
|
||||
|
||||
namespace FMOD
|
||||
{
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
ChannelEmulated::ChannelEmulated()
|
||||
{
|
||||
#ifdef FMOD_SUPPORT_SOFTWARE
|
||||
mDSPHead = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
FMOD_OK
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT ChannelEmulated::init(int index, SystemI *system, Output *output, DSPI *dspmixtarget)
|
||||
{
|
||||
ChannelReal::init(index, system, output, dspmixtarget);
|
||||
|
||||
#ifdef FMOD_SUPPORT_SOFTWARE
|
||||
if (!(mSystem->mFlags & FMOD_INIT_SOFTWARE_DISABLE))
|
||||
{
|
||||
FMOD_RESULT result;
|
||||
FMOD_DSP_DESCRIPTION_EX descriptionex;
|
||||
|
||||
/*
|
||||
Create a head unit that things can connect to.
|
||||
*/
|
||||
FMOD_memset(&descriptionex, 0, sizeof(FMOD_DSP_DESCRIPTION_EX));
|
||||
FMOD_strcpy(descriptionex.name, "EmulatedChannel DSPHead Unit");
|
||||
descriptionex.version = 0x00010100;
|
||||
descriptionex.mCategory = FMOD_DSP_CATEGORY_FILTER;
|
||||
descriptionex.mFormat = FMOD_SOUND_FORMAT_PCMFLOAT;
|
||||
|
||||
#ifdef PLATFORM_PS3
|
||||
mDSPHead = (DSPI *)FMOD_ALIGNPOINTER(&mDSPHeadMemory, 16);
|
||||
mDSPHead = new (mDSPHead) (DSPFilter);
|
||||
#else
|
||||
mDSPHead = &mDSPHeadMemory;
|
||||
#endif
|
||||
|
||||
result = mSystem->createDSP(&descriptionex, &mDSPHead, false);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifdef PLATFORM_PS3
|
||||
mDSPHead->mMramAddress = (unsigned int)mDSPHead;
|
||||
mDSPHead->mDescription.mSize = (sizeof(DSPFilter) + 15) & ~15;
|
||||
#endif
|
||||
|
||||
mMinFrequency = -mMaxFrequency;
|
||||
}
|
||||
#endif
|
||||
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT ChannelEmulated::alloc()
|
||||
{
|
||||
FMOD_RESULT result;
|
||||
|
||||
result = ChannelReal::alloc();
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifdef FMOD_SUPPORT_SOFTWARE
|
||||
if (mDSPHead)
|
||||
{
|
||||
result = mDSPHead->disconnectFrom(0);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
result = mParent->mChannelGroup->mDSPMixTarget->addInputQueued(mDSPHead, false, 0, 0);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT ChannelEmulated::stop()
|
||||
{
|
||||
#ifdef FMOD_SUPPORT_STREAMING
|
||||
if (mSound)
|
||||
{
|
||||
if (mSound->isStream())
|
||||
{
|
||||
Stream *stream = SAFE_CAST(Stream, mSound);
|
||||
if (stream->mChannel)
|
||||
{
|
||||
stream->mChannel->mFinished = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef FMOD_SUPPORT_SOFTWARE
|
||||
if (mDSPHead)
|
||||
{
|
||||
mDSPHead->setActive(false);
|
||||
mDSPHead->disconnectAll(false, true);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef FMOD_SUPPORT_REVERB
|
||||
if (mParent)
|
||||
{
|
||||
int instance;
|
||||
|
||||
for (instance = 0; instance < FMOD_REVERB_MAXINSTANCES; instance++)
|
||||
{
|
||||
mSystem->mReverbGlobal.resetConnectionPointer(instance, mParent->mIndex);
|
||||
}
|
||||
|
||||
#ifdef FMOD_SUPPORT_MULTIREVERB
|
||||
{
|
||||
ReverbI *reverb_c;
|
||||
|
||||
mSystem->mReverb3D.resetConnectionPointer(0, mParent->mIndex);
|
||||
|
||||
reverb_c = SAFE_CAST(ReverbI, mSystem->mReverb3DHead.getNext());
|
||||
while (reverb_c != &(mSystem->mReverb3DHead))
|
||||
{
|
||||
reverb_c->resetConnectionPointer(0, mParent->mIndex);
|
||||
reverb_c = SAFE_CAST(ReverbI, reverb_c->getNext());
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
return ChannelReal::stop();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT ChannelEmulated::close()
|
||||
{
|
||||
FMOD_RESULT result;
|
||||
|
||||
result = ChannelReal::close();
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifdef FMOD_SUPPORT_SOFTWARE
|
||||
if (mDSPHead)
|
||||
{
|
||||
mDSPHead->release(false); /* false = dont free this, as it is not alloced. */
|
||||
mDSPHead= 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT ChannelEmulated::update(int delta)
|
||||
{
|
||||
FMOD_RESULT result;
|
||||
|
||||
result = ChannelReal::update(delta);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
if (mFlags & CHANNELREAL_FLAG_PAUSED || !(mFlags & CHANNELREAL_FLAG_PLAYING))
|
||||
{
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
||||
if ((mParent->mFlags & CHANNELI_FLAG_JUSTWENTVIRTUAL && !(mParent->mFlags & CHANNELI_FLAG_FORCEVIRTUAL)) || mMode & FMOD_VIRTUAL_PLAYFROMSTART)
|
||||
{
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
||||
if (mSystem->mDSPClock.mValue < mParent->mDSPClockDelay.mValue)
|
||||
{
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Convert from ms to samples
|
||||
*/
|
||||
delta = delta * (int)(mParent->mFrequency * mParent->mPitch3D) / 1000;
|
||||
|
||||
if (mDirection == CHANNELREAL_PLAYDIR_BACKWARDS)
|
||||
{
|
||||
delta = -delta;
|
||||
}
|
||||
|
||||
if ((int)mPosition + delta > 0)
|
||||
{
|
||||
mPosition += delta;
|
||||
}
|
||||
else
|
||||
{
|
||||
mPosition = 0;
|
||||
}
|
||||
|
||||
if (mSound)
|
||||
{
|
||||
SoundI *soundi = SAFE_CAST(SoundI, mSound);
|
||||
|
||||
if (mMode & FMOD_LOOP_NORMAL || mMode & FMOD_LOOP_BIDI && mLoopCount)
|
||||
{
|
||||
while ((mParent->mFrequency > 0 && mPosition >= mLoopStart + mLoopLength) ||
|
||||
(mParent->mFrequency < 0 && mPosition <= mLoopStart))
|
||||
{
|
||||
if (!mLoopCount)
|
||||
{
|
||||
if (mDirection == CHANNELREAL_PLAYDIR_FORWARDS && mParent->mFrequency > 0)
|
||||
{
|
||||
mPosition = mLoopStart + mLoopLength;
|
||||
}
|
||||
else
|
||||
{
|
||||
mPosition = mLoopStart;
|
||||
}
|
||||
|
||||
mFlags = (CHANNELREAL_FLAG)(mFlags & ~CHANNELREAL_FLAG_PLAYING);
|
||||
break;
|
||||
}
|
||||
else if (mMode & FMOD_LOOP_NORMAL)
|
||||
{
|
||||
if (mParent->mFrequency > 0)
|
||||
{
|
||||
mPosition -= mLoopLength;
|
||||
}
|
||||
else
|
||||
{
|
||||
mPosition += mLoopLength;
|
||||
}
|
||||
}
|
||||
else if (mMode & FMOD_LOOP_BIDI)
|
||||
{
|
||||
if (mDirection == CHANNELREAL_PLAYDIR_FORWARDS)
|
||||
{
|
||||
mDirection = CHANNELREAL_PLAYDIR_BACKWARDS;
|
||||
}
|
||||
else
|
||||
{
|
||||
mDirection = CHANNELREAL_PLAYDIR_FORWARDS;
|
||||
}
|
||||
mPosition += -delta;
|
||||
}
|
||||
|
||||
if (mLoopCount >= 0)
|
||||
{
|
||||
mLoopCount--;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (mPosition >= soundi->mLength)
|
||||
{
|
||||
mPosition = soundi->mLength;
|
||||
|
||||
mFlags = (CHANNELREAL_FLAG)(mFlags & ~CHANNELREAL_FLAG_PLAYING);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT ChannelEmulated::isVirtual(bool *isvirtual)
|
||||
{
|
||||
if (!isvirtual)
|
||||
{
|
||||
return FMOD_ERR_INVALID_PARAM;
|
||||
}
|
||||
|
||||
*isvirtual = true;
|
||||
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT ChannelEmulated::getDSPHead(DSPI **dsp)
|
||||
{
|
||||
if (!dsp)
|
||||
{
|
||||
return FMOD_ERR_INVALID_PARAM;
|
||||
}
|
||||
|
||||
#ifdef FMOD_SUPPORT_SOFTWARE
|
||||
*dsp = mDSPHead;
|
||||
#endif
|
||||
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT ChannelEmulated::setSpeakerLevels(int speaker, float *levels, int numlevels)
|
||||
{
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT ChannelEmulated::setSpeakerMix(float frontleft, float frontright, float center, float lfe, float backleft, float backright, float sideleft, float sideright)
|
||||
{
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT ChannelEmulated::moveChannelGroup(ChannelGroupI *oldchannelgroup, ChannelGroupI *newchannelgroup)
|
||||
{
|
||||
#ifdef FMOD_SUPPORT_SOFTWARE
|
||||
FMOD_RESULT result;
|
||||
|
||||
if (oldchannelgroup == newchannelgroup || !mDSPHead)
|
||||
{
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
1. disconnect from previous channel group's head.
|
||||
*/
|
||||
if (oldchannelgroup && oldchannelgroup->mDSPMixTarget)
|
||||
{
|
||||
result = oldchannelgroup->mDSPMixTarget->disconnectFrom(mDSPHead);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
2. reconnect to DSP group's head.
|
||||
*/
|
||||
result = newchannelgroup->mDSPMixTarget->addInputQueued(mDSPHead, false, 0, 0);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
38
src/fmod_channel_emulated.h
Executable file
38
src/fmod_channel_emulated.h
Executable file
|
|
@ -0,0 +1,38 @@
|
|||
#ifndef _FMOD_CHANNEL_EMULATED_H
|
||||
#define _FMOD_CHANNEL_EMULATED_H
|
||||
|
||||
#include "fmod_settings.h"
|
||||
|
||||
#include "fmod_channel_real.h"
|
||||
#include "fmod_dsp_filter.h"
|
||||
|
||||
namespace FMOD
|
||||
{
|
||||
class ChannelEmulated : public ChannelReal
|
||||
{
|
||||
private:
|
||||
|
||||
#ifdef FMOD_SUPPORT_SOFTWARE
|
||||
DSPFilter mDSPHeadMemory;
|
||||
DSPI *mDSPHead;
|
||||
#endif
|
||||
|
||||
public:
|
||||
|
||||
ChannelEmulated();
|
||||
|
||||
FMOD_RESULT init(int index, SystemI *system, Output *output, DSPI *dspmixtarget);
|
||||
FMOD_RESULT alloc();
|
||||
FMOD_RESULT stop();
|
||||
FMOD_RESULT close();
|
||||
FMOD_RESULT update(int delta);
|
||||
FMOD_RESULT isVirtual(bool *isvirtual);
|
||||
FMOD_RESULT getDSPHead(DSPI **dsp);
|
||||
FMOD_RESULT setSpeakerLevels(int speaker, float *levels, int numlevels);
|
||||
FMOD_RESULT setSpeakerMix(float frontleft, float frontright, float center, float lfe, float backleft, float backright, float sideleft, float sideright);
|
||||
FMOD_RESULT moveChannelGroup(ChannelGroupI *oldchannelgroup, ChannelGroupI *newchannelgroup);
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
1600
src/fmod_channel_real.cpp
Executable file
1600
src/fmod_channel_real.cpp
Executable file
File diff suppressed because it is too large
Load diff
173
src/fmod_channel_real.h
Executable file
173
src/fmod_channel_real.h
Executable file
|
|
@ -0,0 +1,173 @@
|
|||
#ifndef _FMOD_CHANNEL_REAL_H
|
||||
#define _FMOD_CHANNEL_REAL_H
|
||||
|
||||
#include "fmod_settings.h"
|
||||
|
||||
#include "fmod.h"
|
||||
#include "fmod_channeli.h"
|
||||
#include "fmod_types.h"
|
||||
|
||||
namespace FMOD
|
||||
{
|
||||
class ChannelPool;
|
||||
class DSPI;
|
||||
class Output;
|
||||
class SoundI;
|
||||
class SystemI;
|
||||
struct ChannelRealData;
|
||||
class ReverbI;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
CHANNELREAL_TYPE_HW3D,
|
||||
CHANNELREAL_TYPE_HW2D,
|
||||
CHANNELREAL_TYPE_SW,
|
||||
CHANNELREAL_TYPE_MAX
|
||||
} CHANNELREAL_TYPE;
|
||||
|
||||
#define CHANNELREAL_TYPE_HW CHANNELREAL_TYPE_HW3D
|
||||
|
||||
typedef unsigned int CHANNELREAL_FLAG;
|
||||
|
||||
#define CHANNELREAL_FLAG_ALLOCATED 0x00000010
|
||||
#define CHANNELREAL_FLAG_PAUSED 0x00000020
|
||||
#define CHANNELREAL_FLAG_PLAYING 0x00000040
|
||||
#define CHANNELREAL_FLAG_STOPPED 0x00000080
|
||||
#define CHANNELREAL_FLAG_IN_USE 0x00000100
|
||||
#define CHANNELREAL_FLAG_NOREVERB 0x00000800
|
||||
#define CHANNELREAL_FLAG_RESERVED 0x00001000
|
||||
#define CHANNELREAL_FLAG_HASPLAYED 0x00002000
|
||||
#define CHANNELREAL_FLAG_PAUSEDFORSETPOS 0x00004000
|
||||
#define CHANNELREAL_FLAG_MAX 0xFFFFFFFF
|
||||
|
||||
typedef enum
|
||||
{
|
||||
CHANNELREAL_PLAYDIR_FORWARDS,
|
||||
CHANNELREAL_PLAYDIR_BACKWARDS,
|
||||
CHANNELREAL_PLAYDIR_MAX = 0xFFFFFFFF
|
||||
} CHANNELREAL_PLAYDIR;
|
||||
|
||||
/*
|
||||
*************************************************************************************
|
||||
DON'T IFDEF STUFF OUT THAT MIGHT BE INCLUDED IN FMOD.DLL BUT NOT IN A PLUGIN DLL!
|
||||
(staticforplugins vs fmod.dll code sharing conflict)
|
||||
*************************************************************************************
|
||||
*/
|
||||
class ChannelReal
|
||||
{
|
||||
friend class ChannelPool;
|
||||
friend class SystemI;
|
||||
friend class ChannelI;
|
||||
friend class ChannelStream;
|
||||
friend class MusicSong;
|
||||
friend class Stream;
|
||||
friend class SoundI;
|
||||
friend class DSPWaveTable;
|
||||
friend class DSPResampler;
|
||||
friend class DSPCodec;
|
||||
friend class OutputOpenAL;
|
||||
friend class AsyncThread;
|
||||
|
||||
protected:
|
||||
|
||||
SystemI *mSystem;
|
||||
int mSubChannelIndex;
|
||||
ChannelPool *mPool;
|
||||
ChannelI *mParent;
|
||||
|
||||
Output *mOutput;
|
||||
SoundI *mSound;
|
||||
DSPI *mDSP;
|
||||
FMOD_MODE mMode;
|
||||
CHANNELREAL_FLAG mFlags;
|
||||
|
||||
int mIndex;
|
||||
unsigned int mPosition;
|
||||
int mDirection;
|
||||
int mLoopCount;
|
||||
unsigned int mLoopStart;
|
||||
unsigned int mLoopLength;
|
||||
unsigned int mLength;
|
||||
float mMaxFrequency;
|
||||
float mMinFrequency;
|
||||
int mSubSoundListCurrent;
|
||||
|
||||
#ifdef PLATFORM_WII
|
||||
int mLPFCutoff;
|
||||
bool mBiquadActive;
|
||||
unsigned short mBiquadB0;
|
||||
unsigned short mBiquadB1;
|
||||
unsigned short mBiquadB2;
|
||||
unsigned short mBiquadA1;
|
||||
unsigned short mBiquadA2;
|
||||
unsigned int mControllerSpeaker;
|
||||
#endif
|
||||
|
||||
FMOD_RESULT init();
|
||||
FMOD_RESULT calcVolumeAndPitchFor3D();
|
||||
virtual FMOD_RESULT set2DFreqVolumePanFor3D();
|
||||
virtual bool isStream() { return false; }
|
||||
virtual FMOD_RESULT moveChannelGroup(ChannelGroupI *oldchannelgroup, ChannelGroupI *newchannelgroup, bool forcedspreconnect) { return FMOD_OK; }
|
||||
|
||||
public:
|
||||
|
||||
ChannelReal();
|
||||
virtual ~ChannelReal() { }
|
||||
|
||||
virtual FMOD_RESULT init (int index, SystemI *system, Output *output, DSPI *dspmixtarget);
|
||||
virtual FMOD_RESULT close ();
|
||||
virtual FMOD_RESULT alloc ();
|
||||
virtual FMOD_RESULT alloc (DSPI *dsp);
|
||||
virtual FMOD_RESULT start ();
|
||||
virtual FMOD_RESULT update (int delta);
|
||||
virtual FMOD_RESULT updateStream ();
|
||||
virtual FMOD_RESULT stop ();
|
||||
virtual FMOD_RESULT setPaused (bool paused);
|
||||
virtual FMOD_RESULT getPaused (bool *paused);
|
||||
virtual FMOD_RESULT setVolume (float volume);
|
||||
virtual FMOD_RESULT setFrequency (float frequency);
|
||||
virtual FMOD_RESULT setPan (float pan, float fbpan = 1);
|
||||
virtual FMOD_RESULT setDSPClockDelay ();
|
||||
virtual FMOD_RESULT setSpeakerMix (float frontleft, float frontright, float center, float lfe, float backleft, float backright, float sideleft, float sideright);
|
||||
virtual FMOD_RESULT setSpeakerLevels (int speaker, float *levels, int numlevels);
|
||||
virtual FMOD_RESULT updateSpeakerLevels (float volume);
|
||||
virtual FMOD_RESULT setPosition (unsigned int position, FMOD_TIMEUNIT postype);
|
||||
virtual FMOD_RESULT setPositionEx (unsigned int position, FMOD_TIMEUNIT postype, bool fromasync) { return setPosition(position, postype); }
|
||||
virtual FMOD_RESULT getPosition (unsigned int *position, FMOD_TIMEUNIT postype);
|
||||
virtual FMOD_RESULT setLoopPoints (unsigned int loopstart, unsigned int looplength);
|
||||
virtual FMOD_RESULT setLoopCount (int loopcount);
|
||||
virtual FMOD_RESULT setLowPassGain (float gain);
|
||||
virtual FMOD_RESULT set3DAttributes ();
|
||||
virtual FMOD_RESULT set3DMinMaxDistance ();
|
||||
virtual FMOD_RESULT set3DOcclusion (float directOcclusion, float reverbOcclusion);
|
||||
virtual FMOD_RESULT setReverbProperties (const FMOD_REVERB_CHANNELPROPERTIES *prop);
|
||||
virtual FMOD_RESULT getReverbProperties (FMOD_REVERB_CHANNELPROPERTIES *prop);
|
||||
virtual FMOD_RESULT isPlaying (bool *isplaying, bool includethreadlatency = false);
|
||||
virtual FMOD_RESULT isVirtual (bool *isvirtual);
|
||||
virtual FMOD_RESULT getSpectrum (float *spectrumarray, int numvalues, int channeloffset, FMOD_DSP_FFT_WINDOW windowtype);
|
||||
virtual FMOD_RESULT getWaveData (float *wavearray, int numvalues, int channeloffset);
|
||||
virtual FMOD_RESULT getDSPHead (DSPI **dsp);
|
||||
virtual FMOD_RESULT setMode (FMOD_MODE mode);
|
||||
|
||||
#ifdef PLATFORM_WII
|
||||
virtual FMOD_RESULT setLowPassFilter (int cutoff);
|
||||
virtual FMOD_RESULT getLowPassFilter (int *cutoff);
|
||||
virtual FMOD_RESULT setBiquadFilter (bool active, unsigned short b0, unsigned short b1, unsigned short b2, unsigned short a1, unsigned short a2);
|
||||
virtual FMOD_RESULT getBiquadFilter (bool *active, unsigned short *b0, unsigned short *b1, unsigned short *b2, unsigned short *a1, unsigned short *a2);
|
||||
virtual FMOD_RESULT setControllerSpeaker (unsigned int controllerspeaker, int subchannel = -1);
|
||||
virtual FMOD_RESULT getControllerSpeaker (unsigned int *controllerspeaker);
|
||||
#endif
|
||||
FMOD_RESULT setReserved(bool reserved)
|
||||
{
|
||||
if (mFlags & (CHANNELREAL_FLAG_ALLOCATED | CHANNELREAL_FLAG_IN_USE)) return FMOD_ERR_CHANNEL_ALLOC;
|
||||
if (reserved) mFlags |= CHANNELREAL_FLAG_RESERVED; else mFlags &= ~CHANNELREAL_FLAG_RESERVED;
|
||||
return FMOD_OK;
|
||||
}
|
||||
FMOD_RESULT allowReverb(bool allow) { if (allow) mFlags &= ~CHANNELREAL_FLAG_NOREVERB; else mFlags |= CHANNELREAL_FLAG_NOREVERB; return FMOD_OK; }
|
||||
FMOD_RESULT hasPlayed(bool *hasplayed) { if (hasplayed) *hasplayed = ((mFlags & CHANNELREAL_FLAG_HASPLAYED) ? true : false); return FMOD_OK; }
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
671
src/fmod_channel_realmanual3d.cpp
Executable file
671
src/fmod_channel_realmanual3d.cpp
Executable file
|
|
@ -0,0 +1,671 @@
|
|||
#include "fmod_settings.h"
|
||||
|
||||
#include "fmod_3d.h"
|
||||
#include "fmod_channeli.h"
|
||||
#include "fmod_channel_realmanual3d.h"
|
||||
#include "fmod_soundi.h"
|
||||
#include "fmod_speakermap.h"
|
||||
#include "fmod_systemi.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
namespace FMOD
|
||||
{
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
ChannelRealManual3D::ChannelRealManual3D()
|
||||
{
|
||||
#ifdef FMOD_SUPPORT_SOFTWARE
|
||||
mAngleToListener = 0.0f;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT ChannelRealManual3D::alloc()
|
||||
{
|
||||
#ifdef FMOD_SUPPORT_SOFTWARE
|
||||
mAngleToListener = 0.0f;
|
||||
#endif
|
||||
|
||||
return ChannelReal::alloc();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT ChannelRealManual3D::set2DFreqVolumePanFor3D()
|
||||
{
|
||||
#ifdef FMOD_SUPPORT_3DSOUND
|
||||
float lrpan[FMOD_CHANNEL_MAXINPUTCHANNELS] = { 0 }, fbpan[FMOD_CHANNEL_MAXINPUTCHANNELS] = { 0 };
|
||||
int subchannel, numsubchannels;
|
||||
float lrpan_base = 0.0f, fbpan_base = 0.0f, angle = 0.0f;
|
||||
bool monospread = false;
|
||||
|
||||
if (!(mMode & FMOD_3D))
|
||||
{
|
||||
return FMOD_OK;
|
||||
}
|
||||
if (mSound)
|
||||
{
|
||||
if (mSound->mSubSampleParent)
|
||||
{
|
||||
numsubchannels = mSound->mSubSampleParent->mChannels;
|
||||
}
|
||||
else
|
||||
{
|
||||
numsubchannels = mSound->mChannels;
|
||||
}
|
||||
}
|
||||
else if (mDSP)
|
||||
{
|
||||
numsubchannels = mDSP->mDescription.channels;
|
||||
}
|
||||
else
|
||||
{
|
||||
return FMOD_ERR_INVALID_HANDLE;
|
||||
}
|
||||
|
||||
/*
|
||||
CALCULATE 3D PAN
|
||||
*/
|
||||
if (mSystem->mNumListeners == 1)
|
||||
{
|
||||
FMOD_VECTOR currdiff;
|
||||
FMOD_VECTOR front, right;
|
||||
FMOD_VECTOR position;
|
||||
float distance;
|
||||
|
||||
position = mParent->mPosition3D;
|
||||
|
||||
/*
|
||||
Distance between emitter and listener this frame
|
||||
*/
|
||||
if (mMode & FMOD_3D_HEADRELATIVE)
|
||||
{
|
||||
front.x = 0.0f;
|
||||
front.y = 0.0f;
|
||||
front.z = 1.0f;
|
||||
right.x = 1.0f;
|
||||
right.y = 0.0f;
|
||||
right.z = 0.0f;
|
||||
|
||||
currdiff = position;
|
||||
}
|
||||
else
|
||||
{
|
||||
front = mSystem->mListener[0].mFront;
|
||||
right = mSystem->mListener[0].mRight;
|
||||
FMOD_Vector_Subtract(&position, &mSystem->mListener[0].mPosition, &currdiff);
|
||||
}
|
||||
|
||||
if (mSystem->mFlags & FMOD_INIT_3D_RIGHTHANDED)
|
||||
{
|
||||
front.z = -front.z;
|
||||
currdiff.z = -currdiff.z;
|
||||
}
|
||||
|
||||
/*
|
||||
Normalize difference vector
|
||||
*/
|
||||
distance = FMOD_Vector_GetLength(&currdiff);
|
||||
|
||||
if (distance <= 0)
|
||||
{
|
||||
currdiff.x = 0;
|
||||
currdiff.y = 0;
|
||||
currdiff.z = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
Normalize
|
||||
*/
|
||||
currdiff.x /= (float)distance;
|
||||
currdiff.y /= (float)distance;
|
||||
currdiff.z /= (float)distance;
|
||||
}
|
||||
|
||||
/*
|
||||
Base L/R and F/B pan, and the base direction of the sound
|
||||
*/
|
||||
lrpan_base = FMOD_Vector_DotProduct(&currdiff, &right);
|
||||
fbpan_base = FMOD_Vector_DotProduct(&currdiff, &front);
|
||||
|
||||
if (lrpan_base > 1.01f || lrpan_base < -1.01f)
|
||||
{
|
||||
return FMOD_ERR_INVALID_VECTOR;
|
||||
}
|
||||
if (fbpan_base > 1.01f || fbpan_base < -1.01f)
|
||||
{
|
||||
return FMOD_ERR_INVALID_VECTOR;
|
||||
}
|
||||
|
||||
/*
|
||||
Clamp (floating point accuracy issues on some platforms)
|
||||
*/
|
||||
lrpan_base = lrpan_base > 1.0f ? 1.0f : lrpan_base;
|
||||
lrpan_base = lrpan_base < -1.0f ? -1.0f : lrpan_base;
|
||||
fbpan_base = fbpan_base > 1.0f ? 1.0f : fbpan_base;
|
||||
fbpan_base = fbpan_base < -1.0f ? -1.0f : fbpan_base;
|
||||
|
||||
angle = FMOD_AngleSort_GetValue(lrpan_base, fbpan_base);
|
||||
|
||||
#ifdef FMOD_SUPPORT_SOFTWARE
|
||||
mAngleToListener = FMOD_ACOS(fbpan_base) * (180.0f / FMOD_PI);
|
||||
#endif
|
||||
|
||||
/*
|
||||
Spread the pan field for each part of a sound using the spread angle.
|
||||
If a stereo sound has a spread of 90 degrees, the pan will be rotated 45 degrees left for left channel, 45 degrees right for right channel.
|
||||
*/
|
||||
float radian_spread = mParent->mSpread * FMOD_PI / 180.0f;
|
||||
|
||||
if (mParent->mSpread != 0.0f && numsubchannels == 1)
|
||||
{
|
||||
monospread = true;
|
||||
numsubchannels = 2;
|
||||
}
|
||||
|
||||
for (subchannel = 0; subchannel < numsubchannels; subchannel++)
|
||||
{
|
||||
if (mParent->mSpread == 0.0f || numsubchannels == 1)
|
||||
{
|
||||
lrpan[subchannel] = lrpan_base;
|
||||
fbpan[subchannel] = fbpan_base;
|
||||
}
|
||||
else
|
||||
{
|
||||
//
|
||||
// Map input channel to speaker position index in spread
|
||||
// We don't have access to the sound's channel format so make a guess
|
||||
// For spread pos -1.0 for leftmost, 1.0 for rightmost
|
||||
//
|
||||
float spread_pos = 0.0f;
|
||||
switch(numsubchannels)
|
||||
{
|
||||
case 4: // Could be either L/R/LR/RR or L/R/C/B so last 2 subs get centre
|
||||
switch(subchannel)
|
||||
{
|
||||
case 0: spread_pos = -1.0f; break; // L
|
||||
case 1: spread_pos = 1.0f; break; // R
|
||||
case 2: spread_pos = 0.0f; break; // unknown
|
||||
case 3: spread_pos = 0.0f; break; // unknown
|
||||
}
|
||||
break;
|
||||
|
||||
case 6:
|
||||
switch(subchannel)
|
||||
{
|
||||
case 0: spread_pos = -0.5f; break; // L
|
||||
case 1: spread_pos = 0.5f; break; // R
|
||||
case 2: spread_pos = 0.0f; break; // C
|
||||
case 3: spread_pos = 0.0f; break; // LFE
|
||||
case 4: spread_pos = -1.0f; break; // LR
|
||||
case 5: spread_pos = 1.0f; break; // RR
|
||||
}
|
||||
break;
|
||||
case 8:
|
||||
switch(subchannel)
|
||||
{
|
||||
case 0: spread_pos = -0.333f; break; // L
|
||||
case 1: spread_pos = 0.333f; break; // R
|
||||
case 2: spread_pos = 0.0f; break; // C
|
||||
case 3: spread_pos = 0.0f; break; // LFE
|
||||
case 4: spread_pos = -1.0f; break; // LR
|
||||
case 5: spread_pos = 1.0f; break; // RR
|
||||
case 6: spread_pos = -0.667f; break; // LS
|
||||
case 7: spread_pos = 0.667f; break; // RS
|
||||
}
|
||||
break;
|
||||
default:
|
||||
spread_pos = -1.0f + 2.0f * (float)subchannel / (float)(numsubchannels - 1);
|
||||
break;
|
||||
}
|
||||
float theta = -0.5f * spread_pos * radian_spread;
|
||||
float cost = FMOD_COS(theta);
|
||||
float sint = FMOD_SIN(theta);
|
||||
|
||||
lrpan[subchannel] = (cost * lrpan_base) - (sint * fbpan_base);
|
||||
fbpan[subchannel] = (cost * fbpan_base) + (sint * lrpan_base);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
CALL THE DRIVER TO SET THE VOLUME, FREQUENCY AND PAN
|
||||
*/
|
||||
|
||||
setFrequency(mParent->mFrequency);
|
||||
|
||||
if (mParent->mSpeakerMode != FMOD_SPEAKERMODE_MONO &&
|
||||
mParent->mSpeakerMode != FMOD_SPEAKERMODE_RAW)
|
||||
{
|
||||
float speakerlevel[FMOD_SPEAKER_MAX][FMOD_CHANNEL_MAXINPUTCHANNELS]; /* 8 * 16 * sizeof(float) = 512 bytes */
|
||||
int numspeakers = 0, numrealspeakers = 0;
|
||||
int subchannel;
|
||||
|
||||
FMOD_memset(speakerlevel, 0, sizeof(float) * FMOD_SPEAKER_MAX * FMOD_CHANNEL_MAXINPUTCHANNELS);
|
||||
|
||||
for (subchannel = 0; subchannel < numsubchannels; subchannel++)
|
||||
{
|
||||
speakerlevel[FMOD_SPEAKER_LOW_FREQUENCY][subchannel] = mSystem->mSpeaker[FMOD_SPEAKER_LOW_FREQUENCY].mActive ? mParent->mSpeakerLFE : 0;
|
||||
}
|
||||
|
||||
if (mParent->mSpeakerMode == FMOD_SPEAKERMODE_STEREO)
|
||||
{
|
||||
numspeakers = 2;
|
||||
numrealspeakers = 2;
|
||||
}
|
||||
else if (mParent->mSpeakerMode == FMOD_SPEAKERMODE_PROLOGIC)
|
||||
{
|
||||
numspeakers = 5;
|
||||
numrealspeakers = 6;
|
||||
}
|
||||
else if (mParent->mSpeakerMode == FMOD_SPEAKERMODE_QUAD)
|
||||
{
|
||||
numspeakers = 4;
|
||||
numrealspeakers = 4;
|
||||
}
|
||||
else if (mParent->mSpeakerMode == FMOD_SPEAKERMODE_SURROUND)
|
||||
{
|
||||
numspeakers = 5;
|
||||
numrealspeakers = 5;
|
||||
}
|
||||
else if (mParent->mSpeakerMode == FMOD_SPEAKERMODE_5POINT1)
|
||||
{
|
||||
numspeakers = 5;
|
||||
numrealspeakers = 6;
|
||||
}
|
||||
else if (mParent->mSpeakerMode == FMOD_SPEAKERMODE_7POINT1)
|
||||
{
|
||||
numspeakers = 7;
|
||||
numrealspeakers = 8;
|
||||
}
|
||||
|
||||
if (mParent->m3DPanLevel > 0.0f) /* 0.0 = pure 2d. Less than this has some 3d component. 1 = pure 3d. */
|
||||
{
|
||||
for (subchannel = 0; subchannel < numsubchannels; subchannel++)
|
||||
{
|
||||
if (fbpan[subchannel] == 0 && lrpan[subchannel] == 0)
|
||||
{
|
||||
float level = 1.4142135623730950488016887242097f / numspeakers;
|
||||
|
||||
speakerlevel[FMOD_SPEAKER_FRONT_LEFT][subchannel] = mSystem->mSpeaker[FMOD_SPEAKER_FRONT_LEFT].mActive ? level : 0;
|
||||
speakerlevel[FMOD_SPEAKER_FRONT_RIGHT][subchannel] = mSystem->mSpeaker[FMOD_SPEAKER_FRONT_RIGHT].mActive ? level : 0;
|
||||
speakerlevel[FMOD_SPEAKER_FRONT_CENTER][subchannel] = mSystem->mSpeaker[FMOD_SPEAKER_FRONT_CENTER].mActive ? level : 0;
|
||||
speakerlevel[FMOD_SPEAKER_BACK_LEFT][subchannel] = mSystem->mSpeaker[FMOD_SPEAKER_BACK_LEFT].mActive ? level : 0;
|
||||
speakerlevel[FMOD_SPEAKER_BACK_RIGHT][subchannel] = mSystem->mSpeaker[FMOD_SPEAKER_BACK_RIGHT].mActive ? level : 0;
|
||||
speakerlevel[FMOD_SPEAKER_SIDE_LEFT][subchannel] = mSystem->mSpeaker[FMOD_SPEAKER_SIDE_LEFT].mActive ? level : 0;
|
||||
speakerlevel[FMOD_SPEAKER_SIDE_RIGHT][subchannel] = mSystem->mSpeaker[FMOD_SPEAKER_SIDE_RIGHT].mActive ? level : 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
int speaker;
|
||||
float subchannelangle;
|
||||
|
||||
if (lrpan[subchannel] == lrpan_base && fbpan[subchannel] == fbpan_base)
|
||||
{
|
||||
subchannelangle = angle;
|
||||
}
|
||||
else
|
||||
{
|
||||
subchannelangle = FMOD_AngleSort_GetValue(lrpan[subchannel], fbpan[subchannel]);
|
||||
}
|
||||
|
||||
if (!mSystem->mSpeakerList[0]) /* No speakers are active. */
|
||||
{
|
||||
|
||||
}
|
||||
else if (!mSystem->mSpeakerList[1]) /* Only 1 speaker is active. */
|
||||
{
|
||||
speakerlevel[mSystem->mSpeakerList[0]->mSpeaker][subchannel] = 1.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (speaker = 1; speaker < numspeakers + 1; speaker++)
|
||||
{
|
||||
FMOD_SPEAKERCONFIG *spkA, *spkB;
|
||||
|
||||
spkA = mSystem->mSpeakerList[speaker-1];
|
||||
if (mSystem->mSpeakerList[speaker])
|
||||
{
|
||||
spkB = mSystem->mSpeakerList[speaker];
|
||||
}
|
||||
else
|
||||
{
|
||||
spkB = mSystem->mSpeakerList[0];
|
||||
}
|
||||
|
||||
if (spkA->mXZAngle == spkB->mXZAngle) /* 2 speakers are at the same location so skip to the next pair */
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (FMOD_AngleSort_IsClockwise(spkA->mXZAngle, subchannelangle, spkB->mXZAngle))
|
||||
{
|
||||
/*
|
||||
VBAP only makes sense if source direction is in the vector space spanned by positive gains.
|
||||
So if the speaker angles are 180 deg apart then the best we can do is resolve the lateral
|
||||
(side-to-side) component of the source's direction.
|
||||
*/
|
||||
if (spkA->mPairUseVBAP)
|
||||
{
|
||||
/*
|
||||
Use Vector-Based Amplitude Panning by soving the equations:
|
||||
1. [x_src] = [x_spkA x_spkB] * [gainA']
|
||||
[y_src] [y_spkA y_spkB] [gainB']
|
||||
2. gainA = k * gainA'
|
||||
3. gainB = k * gainB'
|
||||
4. gainA ^ 2 + gainB ^ 2 = 1
|
||||
Note: there is no need to evaluate the determinant when inverting the speaker matrix
|
||||
in Eq.1 since gains will we normalised for constant power.
|
||||
*/
|
||||
float gainA = lrpan[subchannel] * spkB->mXZNormal.z - fbpan[subchannel] * spkB->mXZNormal.x;
|
||||
float gainB = fbpan[subchannel] * spkA->mXZNormal.x - lrpan[subchannel] * spkA->mXZNormal.z;
|
||||
float norm = spkA->mPairVBAPSign / FMOD_SQRT(gainA * gainA + gainB * gainB);
|
||||
speakerlevel[spkA->mSpeaker][subchannel] = gainA * norm;
|
||||
speakerlevel[spkB->mSpeaker][subchannel] = gainB * norm;
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
Resolve lateral component using the dot product, solving the following equations:
|
||||
1. u_src = u_spkA * gainA + u_spkB * gainB
|
||||
2. gainA ^ 2 + gainB ^ 2 = 1
|
||||
where 'u_' denotes the lateral component of the source and speaker unit direction vectors
|
||||
*/
|
||||
float lateral = (lrpan[subchannel] * spkA->mXZNormal.x + fbpan[subchannel] * spkA->mXZNormal.z);
|
||||
float d = FMOD_SQRT(2.0f - lateral * lateral);
|
||||
speakerlevel[spkA->mSpeaker][subchannel] = (d + lateral) * 0.5f;
|
||||
speakerlevel[spkB->mSpeaker][subchannel] = (d - lateral) * 0.5f;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (numsubchannels > 1)
|
||||
{
|
||||
int speaker;
|
||||
float levels[DSP_MAXLEVELS_OUT * DSP_MAXLEVELS_IN] = { 0 };
|
||||
int numinputlevels;
|
||||
|
||||
if (mParent->m3DPanLevel < 1.0f)
|
||||
{
|
||||
float _3dmix = mParent->m3DPanLevel, _2dmix = 1.0f - mParent->m3DPanLevel;
|
||||
|
||||
if (mParent->mLastPanMode == FMOD_CHANNEL_PANMODE_PAN || mParent->mLastPanMode == FMOD_CHANNEL_PANMODE_SPEAKERMIX)
|
||||
{
|
||||
float fl = 0.0f, fr = 0.0f, c = 0.0f, lfe = 0.0f, bl = 0.0f, br = 0.0f, sl = 0.0f, sr = 0.0f;
|
||||
|
||||
if (mParent->mLastPanMode == FMOD_CHANNEL_PANMODE_PAN)
|
||||
{
|
||||
float pan = (mParent->mPan + 1.0f) / 2.0f;
|
||||
float l, r;
|
||||
|
||||
if (pan <= 0.5f)
|
||||
{
|
||||
l = 1.0f;
|
||||
r = pan * 2.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
l = (1.0f - pan) * 2.0f;
|
||||
r = 1.0f;
|
||||
}
|
||||
|
||||
if (numsubchannels == 2 && !(mSound->mDefaultChannelMask & SPEAKER_ALLMONO))
|
||||
{
|
||||
fl = l; fr = r; c = 0; lfe = 0; bl = 0; br = 0; sl = 0; sr = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
fl = l; fr = r; c = 1.0f; lfe = 1.0f; bl = l; br = r; sl = l; sr = r;
|
||||
}
|
||||
}
|
||||
else if (mParent->mLastPanMode == FMOD_CHANNEL_PANMODE_SPEAKERMIX)
|
||||
{
|
||||
fl = mParent->mSpeakerFL;
|
||||
fr = mParent->mSpeakerFR;
|
||||
c = mParent->mSpeakerC;
|
||||
lfe = mParent->mSpeakerLFE;
|
||||
bl = mParent->mSpeakerBL;
|
||||
br = mParent->mSpeakerBR;
|
||||
sl = mParent->mSpeakerSL;
|
||||
sr = mParent->mSpeakerSR;
|
||||
}
|
||||
|
||||
FMOD_SPEAKERMAPTYPE speakermap = FMOD_SPEAKERMAPTYPE_DEFAULT;
|
||||
|
||||
if (mSound)
|
||||
{
|
||||
if (mSound->mDefaultChannelMask & SPEAKER_ALLMONO)
|
||||
{
|
||||
speakermap = FMOD_SPEAKERMAPTYPE_ALLMONO;
|
||||
}
|
||||
else if (mSound->mDefaultChannelMask & SPEAKER_ALLSTEREO)
|
||||
{
|
||||
speakermap = FMOD_SPEAKERMAPTYPE_ALLSTEREO;
|
||||
}
|
||||
else if (mSound->mDefaultChannelMask & SPEAKER_PROTOOLS)
|
||||
{
|
||||
speakermap = FMOD_SPEAKERMAPTYPE_51_PROTOOLS;
|
||||
}
|
||||
}
|
||||
|
||||
DSPI::calculateSpeakerLevels(fl,
|
||||
fr,
|
||||
c,
|
||||
lfe,
|
||||
bl,
|
||||
br,
|
||||
sl,
|
||||
sr,
|
||||
mParent->mSpeakerMode,
|
||||
numsubchannels,
|
||||
speakermap,
|
||||
levels,
|
||||
&numinputlevels);
|
||||
|
||||
for (subchannel = 0; subchannel < numsubchannels; subchannel++)
|
||||
{
|
||||
speakerlevel[FMOD_SPEAKER_FRONT_LEFT][subchannel] = (speakerlevel[FMOD_SPEAKER_FRONT_LEFT][subchannel] * _3dmix) + (levels[(FMOD_SPEAKER_FRONT_LEFT * numinputlevels) + subchannel] * _2dmix);
|
||||
speakerlevel[FMOD_SPEAKER_FRONT_RIGHT][subchannel] = (speakerlevel[FMOD_SPEAKER_FRONT_RIGHT][subchannel] * _3dmix) + (levels[(FMOD_SPEAKER_FRONT_RIGHT * numinputlevels) + subchannel] * _2dmix);
|
||||
speakerlevel[FMOD_SPEAKER_FRONT_CENTER][subchannel] = (speakerlevel[FMOD_SPEAKER_FRONT_CENTER][subchannel] * _3dmix) + (levels[(FMOD_SPEAKER_FRONT_CENTER * numinputlevels) + subchannel] * _2dmix);
|
||||
speakerlevel[FMOD_SPEAKER_BACK_LEFT][subchannel] = (speakerlevel[FMOD_SPEAKER_BACK_LEFT][subchannel] * _3dmix) + (levels[(FMOD_SPEAKER_BACK_LEFT * numinputlevels) + subchannel] * _2dmix);
|
||||
speakerlevel[FMOD_SPEAKER_BACK_RIGHT][subchannel] = (speakerlevel[FMOD_SPEAKER_BACK_RIGHT][subchannel] * _3dmix) + (levels[(FMOD_SPEAKER_BACK_RIGHT * numinputlevels) + subchannel] * _2dmix);
|
||||
speakerlevel[FMOD_SPEAKER_SIDE_LEFT][subchannel] = (speakerlevel[FMOD_SPEAKER_SIDE_LEFT][subchannel] * _3dmix) + (levels[(FMOD_SPEAKER_SIDE_LEFT * numinputlevels) + subchannel] * _2dmix);
|
||||
speakerlevel[FMOD_SPEAKER_SIDE_RIGHT][subchannel] = (speakerlevel[FMOD_SPEAKER_SIDE_RIGHT][subchannel] * _3dmix) + (levels[(FMOD_SPEAKER_SIDE_RIGHT * numinputlevels) + subchannel] * _2dmix);
|
||||
}
|
||||
}
|
||||
else if (mParent->mLastPanMode == FMOD_CHANNEL_PANMODE_SPEAKERLEVELS && mParent->mLevels)
|
||||
{
|
||||
numinputlevels = mSystem->mMaxInputChannels;
|
||||
|
||||
for (subchannel = 0; subchannel < numsubchannels; subchannel++)
|
||||
{
|
||||
speakerlevel[FMOD_SPEAKER_FRONT_LEFT][subchannel] = (speakerlevel[FMOD_SPEAKER_FRONT_LEFT][subchannel] * _3dmix) + (mParent->mLevels[(FMOD_SPEAKER_FRONT_LEFT * numinputlevels) + subchannel] * _2dmix);
|
||||
speakerlevel[FMOD_SPEAKER_FRONT_RIGHT][subchannel] = (speakerlevel[FMOD_SPEAKER_FRONT_RIGHT][subchannel] * _3dmix) + (mParent->mLevels[(FMOD_SPEAKER_FRONT_RIGHT * numinputlevels) + subchannel] * _2dmix);
|
||||
|
||||
if (numspeakers > 2)
|
||||
{
|
||||
speakerlevel[FMOD_SPEAKER_FRONT_CENTER][subchannel] = (speakerlevel[FMOD_SPEAKER_FRONT_CENTER][subchannel] * _3dmix) + (mParent->mLevels[(FMOD_SPEAKER_FRONT_CENTER * numinputlevels) + subchannel] * _2dmix);
|
||||
|
||||
if (numspeakers > 3)
|
||||
{
|
||||
speakerlevel[FMOD_SPEAKER_BACK_LEFT][subchannel] = (speakerlevel[FMOD_SPEAKER_BACK_LEFT][subchannel] * _3dmix) + (mParent->mLevels[(FMOD_SPEAKER_BACK_LEFT * numinputlevels) + subchannel] * _2dmix);
|
||||
speakerlevel[FMOD_SPEAKER_BACK_RIGHT][subchannel] = (speakerlevel[FMOD_SPEAKER_BACK_RIGHT][subchannel] * _3dmix) + (mParent->mLevels[(FMOD_SPEAKER_BACK_RIGHT * numinputlevels) + subchannel] * _2dmix);
|
||||
|
||||
if (numspeakers > 5)
|
||||
{
|
||||
speakerlevel[FMOD_SPEAKER_SIDE_LEFT][subchannel] = (speakerlevel[FMOD_SPEAKER_SIDE_LEFT][subchannel] * _3dmix) + (mParent->mLevels[(FMOD_SPEAKER_SIDE_LEFT * numinputlevels) + subchannel] * _2dmix);
|
||||
speakerlevel[FMOD_SPEAKER_SIDE_RIGHT][subchannel] = (speakerlevel[FMOD_SPEAKER_SIDE_RIGHT][subchannel] * _3dmix) + (mParent->mLevels[(FMOD_SPEAKER_SIDE_RIGHT * numinputlevels) + subchannel] * _2dmix);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (mParent->mSpeakerMode == FMOD_SPEAKERMODE_PROLOGIC && (mSound->mMode & FMOD_SOFTWARE)) /* Downmix logic. */
|
||||
{
|
||||
for (subchannel = 0; subchannel < numsubchannels; subchannel++)
|
||||
{
|
||||
DSPI::calculateSpeakerLevels(speakerlevel[FMOD_SPEAKER_FRONT_LEFT][subchannel],
|
||||
speakerlevel[FMOD_SPEAKER_FRONT_RIGHT][subchannel],
|
||||
speakerlevel[FMOD_SPEAKER_FRONT_CENTER][subchannel],
|
||||
speakerlevel[FMOD_SPEAKER_LOW_FREQUENCY][subchannel],
|
||||
speakerlevel[FMOD_SPEAKER_BACK_LEFT][subchannel],
|
||||
speakerlevel[FMOD_SPEAKER_BACK_RIGHT][subchannel],
|
||||
speakerlevel[FMOD_SPEAKER_SIDE_LEFT][subchannel],
|
||||
speakerlevel[FMOD_SPEAKER_SIDE_RIGHT][subchannel],
|
||||
mParent->mSpeakerMode,
|
||||
1,
|
||||
FMOD_SPEAKERMAPTYPE_DEFAULT,
|
||||
levels,
|
||||
&numinputlevels);
|
||||
|
||||
speakerlevel[FMOD_SPEAKER_FRONT_LEFT][subchannel] = levels[0];
|
||||
speakerlevel[FMOD_SPEAKER_FRONT_RIGHT][subchannel] = levels[1];
|
||||
speakerlevel[FMOD_SPEAKER_FRONT_CENTER][subchannel] = 0;
|
||||
speakerlevel[FMOD_SPEAKER_BACK_LEFT][subchannel] = 0;
|
||||
speakerlevel[FMOD_SPEAKER_BACK_RIGHT][subchannel] = 0;
|
||||
speakerlevel[FMOD_SPEAKER_SIDE_LEFT][subchannel] = 0;
|
||||
speakerlevel[FMOD_SPEAKER_SIDE_RIGHT][subchannel] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (monospread)
|
||||
{
|
||||
numsubchannels = 1; /* Put it back to normal */
|
||||
}
|
||||
|
||||
for (speaker = 0; speaker < numrealspeakers; speaker++)
|
||||
{
|
||||
if (monospread)
|
||||
{
|
||||
speakerlevel[speaker][0] = (speakerlevel[speaker][0] + speakerlevel[speaker][1]) / 2.0f;
|
||||
}
|
||||
setSpeakerLevels(speaker, speakerlevel[speaker], numsubchannels);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (mParent->m3DPanLevel < 1.0f)
|
||||
{
|
||||
float _3dmix = mParent->m3DPanLevel, _2dmix = 1.0f - mParent->m3DPanLevel;
|
||||
|
||||
if (mParent->mLastPanMode == FMOD_CHANNEL_PANMODE_PAN)
|
||||
{
|
||||
float pan = (mParent->mPan + 1.0f) / 2.0f;
|
||||
float l = FMOD_SQRT(1.0f - pan);
|
||||
float r = FMOD_SQRT(pan);
|
||||
|
||||
speakerlevel[FMOD_SPEAKER_FRONT_LEFT][0] = (speakerlevel[FMOD_SPEAKER_FRONT_LEFT][0] * _3dmix) + (l * _2dmix);
|
||||
speakerlevel[FMOD_SPEAKER_FRONT_RIGHT][0] = (speakerlevel[FMOD_SPEAKER_FRONT_RIGHT][0] * _3dmix) + (r * _2dmix);
|
||||
speakerlevel[FMOD_SPEAKER_FRONT_CENTER][0] = (speakerlevel[FMOD_SPEAKER_FRONT_CENTER][0] * _3dmix);
|
||||
speakerlevel[FMOD_SPEAKER_BACK_LEFT][0] = (speakerlevel[FMOD_SPEAKER_BACK_LEFT][0] * _3dmix);
|
||||
speakerlevel[FMOD_SPEAKER_BACK_RIGHT][0] = (speakerlevel[FMOD_SPEAKER_BACK_RIGHT][0] * _3dmix);
|
||||
speakerlevel[FMOD_SPEAKER_SIDE_LEFT][0] = (speakerlevel[FMOD_SPEAKER_SIDE_LEFT][0] * _3dmix);
|
||||
speakerlevel[FMOD_SPEAKER_SIDE_RIGHT][0] = (speakerlevel[FMOD_SPEAKER_SIDE_RIGHT][0] * _3dmix);
|
||||
}
|
||||
else if (mParent->mLastPanMode == FMOD_CHANNEL_PANMODE_SPEAKERMIX)
|
||||
{
|
||||
speakerlevel[FMOD_SPEAKER_FRONT_LEFT][0] = (speakerlevel[FMOD_SPEAKER_FRONT_LEFT][0] * _3dmix) + (mParent->mSpeakerFL * _2dmix);
|
||||
speakerlevel[FMOD_SPEAKER_FRONT_RIGHT][0] = (speakerlevel[FMOD_SPEAKER_FRONT_RIGHT][0] * _3dmix) + (mParent->mSpeakerFR * _2dmix);
|
||||
speakerlevel[FMOD_SPEAKER_FRONT_CENTER][0] = (speakerlevel[FMOD_SPEAKER_FRONT_CENTER][0] * _3dmix) + (mParent->mSpeakerC * _2dmix);
|
||||
speakerlevel[FMOD_SPEAKER_BACK_LEFT][0] = (speakerlevel[FMOD_SPEAKER_BACK_LEFT][0] * _3dmix) + (mParent->mSpeakerBL * _2dmix);
|
||||
speakerlevel[FMOD_SPEAKER_BACK_RIGHT][0] = (speakerlevel[FMOD_SPEAKER_BACK_RIGHT][0] * _3dmix) + (mParent->mSpeakerBR * _2dmix);
|
||||
speakerlevel[FMOD_SPEAKER_SIDE_LEFT][0] = (speakerlevel[FMOD_SPEAKER_SIDE_LEFT][0] * _3dmix) + (mParent->mSpeakerSL * _2dmix);
|
||||
speakerlevel[FMOD_SPEAKER_SIDE_RIGHT][0] = (speakerlevel[FMOD_SPEAKER_SIDE_RIGHT][0] * _3dmix) + (mParent->mSpeakerSR * _2dmix);
|
||||
}
|
||||
else if (mParent->mLastPanMode == FMOD_CHANNEL_PANMODE_SPEAKERLEVELS && mParent->mLevels)
|
||||
{
|
||||
speakerlevel[FMOD_SPEAKER_FRONT_LEFT][0] = (speakerlevel[FMOD_SPEAKER_FRONT_LEFT][0] * _3dmix) + (mParent->mLevels[mSystem->mMaxInputChannels * FMOD_SPEAKER_FRONT_LEFT] * _2dmix);
|
||||
speakerlevel[FMOD_SPEAKER_FRONT_RIGHT][0] = (speakerlevel[FMOD_SPEAKER_FRONT_RIGHT][0] * _3dmix) + (mParent->mLevels[mSystem->mMaxInputChannels * FMOD_SPEAKER_FRONT_RIGHT] * _2dmix);
|
||||
|
||||
if (numspeakers > 2)
|
||||
{
|
||||
speakerlevel[FMOD_SPEAKER_FRONT_CENTER][0] = (speakerlevel[FMOD_SPEAKER_FRONT_CENTER][0] * _3dmix) + (mParent->mLevels[mSystem->mMaxInputChannels * FMOD_SPEAKER_FRONT_CENTER] * _2dmix);
|
||||
|
||||
if (numspeakers > 3)
|
||||
{
|
||||
speakerlevel[FMOD_SPEAKER_BACK_LEFT][0] = (speakerlevel[FMOD_SPEAKER_BACK_LEFT][0] * _3dmix) + (mParent->mLevels[mSystem->mMaxInputChannels * FMOD_SPEAKER_BACK_LEFT] * _2dmix);
|
||||
speakerlevel[FMOD_SPEAKER_BACK_RIGHT][0] = (speakerlevel[FMOD_SPEAKER_BACK_RIGHT][0] * _3dmix) + (mParent->mLevels[mSystem->mMaxInputChannels * FMOD_SPEAKER_BACK_RIGHT] * _2dmix);
|
||||
|
||||
if (numspeakers > 5)
|
||||
{
|
||||
speakerlevel[FMOD_SPEAKER_SIDE_LEFT][0] = (speakerlevel[FMOD_SPEAKER_SIDE_LEFT][0] * _3dmix) + (mParent->mLevels[mSystem->mMaxInputChannels * FMOD_SPEAKER_SIDE_LEFT] * _2dmix);
|
||||
speakerlevel[FMOD_SPEAKER_SIDE_RIGHT][0] = (speakerlevel[FMOD_SPEAKER_SIDE_RIGHT][0] * _3dmix) + (mParent->mLevels[mSystem->mMaxInputChannels * FMOD_SPEAKER_SIDE_RIGHT] * _2dmix);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setSpeakerMix(speakerlevel[FMOD_SPEAKER_FRONT_LEFT][0],
|
||||
speakerlevel[FMOD_SPEAKER_FRONT_RIGHT][0],
|
||||
speakerlevel[FMOD_SPEAKER_FRONT_CENTER][0],
|
||||
mParent->mSpeakerLFE,
|
||||
speakerlevel[FMOD_SPEAKER_BACK_LEFT][0],
|
||||
speakerlevel[FMOD_SPEAKER_BACK_RIGHT][0],
|
||||
speakerlevel[FMOD_SPEAKER_SIDE_LEFT][0],
|
||||
speakerlevel[FMOD_SPEAKER_SIDE_RIGHT][0]);
|
||||
}
|
||||
}
|
||||
|
||||
setVolume(mParent->mVolume);
|
||||
#endif
|
||||
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
27
src/fmod_channel_realmanual3d.h
Executable file
27
src/fmod_channel_realmanual3d.h
Executable file
|
|
@ -0,0 +1,27 @@
|
|||
#ifndef _FMOD_CHANNEL_REALMANUAL3D_H
|
||||
#define _FMOD_CHANNEL_REALMANUAL3D_H
|
||||
|
||||
#include "fmod_settings.h"
|
||||
|
||||
#include "fmod_channel_real.h"
|
||||
|
||||
namespace FMOD
|
||||
{
|
||||
class ChannelRealManual3D : public ChannelReal
|
||||
{
|
||||
friend class ChannelSoftware;
|
||||
|
||||
#ifdef FMOD_SUPPORT_SOFTWARE
|
||||
float mAngleToListener;
|
||||
#endif
|
||||
|
||||
public:
|
||||
|
||||
ChannelRealManual3D();
|
||||
|
||||
FMOD_RESULT alloc();
|
||||
FMOD_RESULT set2DFreqVolumePanFor3D();
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
3300
src/fmod_channel_software.cpp
Executable file
3300
src/fmod_channel_software.cpp
Executable file
File diff suppressed because it is too large
Load diff
89
src/fmod_channel_software.h
Executable file
89
src/fmod_channel_software.h
Executable file
|
|
@ -0,0 +1,89 @@
|
|||
#ifndef _FMOD_CHANNEL_SOFTWARE_H
|
||||
#define _FMOD_CHANNEL_SOFTWARE_H
|
||||
|
||||
#include "fmod_settings.h"
|
||||
|
||||
#ifdef FMOD_SUPPORT_SOFTWARE
|
||||
|
||||
#include "fmod_channel_realmanual3d.h"
|
||||
#include "fmod_dsp_filter.h"
|
||||
#include "fmod_dsp_wavetable.h"
|
||||
|
||||
namespace FMOD
|
||||
{
|
||||
class DSPCodec;
|
||||
class ReverbI;
|
||||
|
||||
class ChannelSoftware : public ChannelRealManual3D
|
||||
{
|
||||
friend class DSPCodecPool;
|
||||
friend class OutputSoftware;
|
||||
|
||||
protected:
|
||||
|
||||
/* __________________ __________ _______________ */
|
||||
/* | |<---.. | | | | */
|
||||
/* | channelgroup DSP |<--------| mDSPHead |<------| mDSPWaveTable | */
|
||||
/* |__________________|<---.. |__________| |_______________| */
|
||||
|
||||
DSPI *mDSPHead;
|
||||
DSPFilter mDSPHeadMemory;
|
||||
#ifdef PLATFORM_PS3
|
||||
char mDSPHeadMemoryPad[16];
|
||||
#endif
|
||||
DSPWaveTable *mDSPWaveTable;
|
||||
DSPWaveTable mDSPWaveTableMemory;
|
||||
#ifdef PLATFORM_PS3
|
||||
char mDSPWaveTableMemoryPad[16];
|
||||
#endif
|
||||
DSPResampler *mDSPResampler; /* mDSPResampler is connected between mDSPHead and mDSPWaveTable sometimes. */
|
||||
DSPI *mDSPLowPass; /* Optional if the user specifies FMOD_INIT_OCCLUSION_LOWPASS. */
|
||||
DSPI *mDSPReverb; /* Points to the unit the reverb unit is connected to. */
|
||||
DSPCodec *mDSPCodec;
|
||||
DSPConnectionI *mDSPConnection;
|
||||
|
||||
public:
|
||||
|
||||
ChannelSoftware();
|
||||
|
||||
FMOD_RESULT init (int index, SystemI *system, Output *output, DSPI *dspmixtarget);
|
||||
FMOD_RESULT close ();
|
||||
FMOD_RESULT alloc ();
|
||||
FMOD_RESULT alloc (DSPI *dsp);
|
||||
FMOD_RESULT start ();
|
||||
|
||||
FMOD_RESULT stop ();
|
||||
FMOD_RESULT setVolume (float volume);
|
||||
FMOD_RESULT setFrequency (float frequency);
|
||||
FMOD_RESULT setPan (float pan, float fbpan = 1);
|
||||
FMOD_RESULT setDSPClockDelay ();
|
||||
FMOD_RESULT setSpeakerMix (float frontleft, float frontright, float center, float lfe, float backleft, float backright, float sideleft, float sideright);
|
||||
FMOD_RESULT setSpeakerLevels (int speaker, float *levels, int numlevels);
|
||||
FMOD_RESULT setPaused (bool paused);
|
||||
FMOD_RESULT getPaused (bool *paused);
|
||||
FMOD_RESULT setPosition (unsigned int position, FMOD_TIMEUNIT postype);
|
||||
FMOD_RESULT getPosition (unsigned int *position, FMOD_TIMEUNIT postype);
|
||||
FMOD_RESULT setLoopPoints (unsigned int loopstart, unsigned int looplength);
|
||||
FMOD_RESULT setLoopCount (int loopcount);
|
||||
FMOD_RESULT setMode (FMOD_MODE mode);
|
||||
FMOD_RESULT setLowPassGain (float gain);
|
||||
FMOD_RESULT set3DOcclusion (float directOcclusion, float reverbOcclusion);
|
||||
FMOD_RESULT isPlaying (bool *isplaying, bool includethreadlatency = false);
|
||||
FMOD_RESULT getSpectrum (float *spectrumarray, int numentries, int channeloffset, FMOD_DSP_FFT_WINDOW windowtype);
|
||||
FMOD_RESULT getWaveData (float *wavearray, int numentries, int channeloffset);
|
||||
FMOD_RESULT getDSPHead (DSPI **dsp);
|
||||
FMOD_RESULT setReverbProperties (const FMOD_REVERB_CHANNELPROPERTIES *prop);
|
||||
FMOD_RESULT getReverbProperties (FMOD_REVERB_CHANNELPROPERTIES *prop);
|
||||
FMOD_RESULT setReverbMix (ReverbI* reverb, float gainlin);
|
||||
FMOD_RESULT updateDirectMix (float volume);
|
||||
FMOD_RESULT updateReverbMix (ReverbI* reverb, float volume);
|
||||
FMOD_RESULT addToReverbs (DSPI *dsp);
|
||||
FMOD_RESULT moveChannelGroup (ChannelGroupI *oldchannelgroup, ChannelGroupI *newchannelgroup, bool forcedspreconnect);
|
||||
FMOD_RESULT setupDSPCodec (DSPI *dsp);
|
||||
FMOD_RESULT getDSPCodec (DSPCodec **dsp) { *dsp = mDSPCodec; return FMOD_OK; }
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
1846
src/fmod_channel_stream.cpp
Executable file
1846
src/fmod_channel_stream.cpp
Executable file
File diff suppressed because it is too large
Load diff
81
src/fmod_channel_stream.h
Executable file
81
src/fmod_channel_stream.h
Executable file
|
|
@ -0,0 +1,81 @@
|
|||
#ifndef _FMOD_CHANNEL_STREAM_H
|
||||
#define _FMOD_CHANNEL_STREAM_H
|
||||
|
||||
#include "fmod_settings.h"
|
||||
|
||||
#ifdef FMOD_SUPPORT_STREAMING
|
||||
|
||||
#include "fmod_channel_real.h"
|
||||
|
||||
namespace FMOD
|
||||
{
|
||||
class ChannelStream : public ChannelReal, public LinkedListNode
|
||||
{
|
||||
public:
|
||||
|
||||
volatile bool mFinished;
|
||||
unsigned int mLastPCM;
|
||||
unsigned int mDecodeOffset;
|
||||
unsigned int mSamplesPlayed;
|
||||
unsigned int mSamplesWritten;
|
||||
LinkedListNode mStreamNode;
|
||||
int mNumRealChannels;
|
||||
ChannelReal *mRealChannel[FMOD_CHANNEL_MAXREALSUBCHANNELS]; /* Even a real channel may contain a pointer to another real channel! (ie stream channel points to dsound channel) */
|
||||
|
||||
public:
|
||||
|
||||
ChannelStream();
|
||||
|
||||
FMOD_RESULT setRealChannel(ChannelReal *realchan);
|
||||
bool isStream() { return true; }
|
||||
|
||||
FMOD_RESULT set2DFreqVolumePanFor3D();
|
||||
FMOD_RESULT moveChannelGroup(ChannelGroupI *oldchannelgroup, ChannelGroupI *newchannelgroup, bool forcedspreconnect);
|
||||
|
||||
FMOD_RESULT alloc ();
|
||||
FMOD_RESULT start ();
|
||||
FMOD_RESULT update (int delta);
|
||||
FMOD_RESULT updateStream ();
|
||||
FMOD_RESULT setMode (FMOD_MODE mode);
|
||||
|
||||
FMOD_RESULT stop ();
|
||||
FMOD_RESULT setPaused (bool paused);
|
||||
FMOD_RESULT setVolume (float volume);
|
||||
FMOD_RESULT setFrequency (float frequency);
|
||||
FMOD_RESULT setPan (float pan, float fbpan = 1);
|
||||
FMOD_RESULT setDSPClockDelay ();
|
||||
FMOD_RESULT setSpeakerMix (float frontleft, float frontright, float center, float lfe, float backleft, float backright, float sideleft, float sideright);
|
||||
FMOD_RESULT setSpeakerLevels (int speaker, float *levels, int numlevels);
|
||||
FMOD_RESULT setPosition (unsigned int position, FMOD_TIMEUNIT postype) { return setPositionEx(position, postype); }
|
||||
FMOD_RESULT setPositionEx (unsigned int position, FMOD_TIMEUNIT postype, bool fromasync = false);
|
||||
FMOD_RESULT getPosition (unsigned int *position, FMOD_TIMEUNIT postype);
|
||||
FMOD_RESULT setLoopPoints (unsigned int loopstart, unsigned int looplength);
|
||||
FMOD_RESULT setLoopCount (int loopcount);
|
||||
FMOD_RESULT setLowPassGain (float gain);
|
||||
FMOD_RESULT set3DAttributes ();
|
||||
FMOD_RESULT set3DMinMaxDistance ();
|
||||
FMOD_RESULT set3DConeSettings (float iconeangle, float oconeangle, float ovolume);
|
||||
FMOD_RESULT set3DConeOrientation(FMOD_VECTOR *orientation);
|
||||
FMOD_RESULT set3DOcclusion (float directocclusion, float reverbocclusion);
|
||||
FMOD_RESULT setReverbProperties (const FMOD_REVERB_CHANNELPROPERTIES *prop);
|
||||
FMOD_RESULT getReverbProperties (FMOD_REVERB_CHANNELPROPERTIES *prop);
|
||||
FMOD_RESULT isPlaying (bool *isplaying, bool includethreadlatency = false);
|
||||
FMOD_RESULT getSpectrum (float *spectrumarray, int numvalues, int channeloffset, FMOD_DSP_FFT_WINDOW windowtype);
|
||||
FMOD_RESULT getWaveData (float *wavearray, int numvalues, int channeloffset);
|
||||
FMOD_RESULT getDSPHead (DSPI **dsp);
|
||||
|
||||
#ifdef PLATFORM_WII
|
||||
FMOD_RESULT setLowPassFilter (int cutoff);
|
||||
FMOD_RESULT getLowPassFilter (int *cutoff);
|
||||
FMOD_RESULT setBiquadFilter (bool active, unsigned short b0, unsigned short b1, unsigned short b2, unsigned short a1, unsigned short a2);
|
||||
FMOD_RESULT getBiquadFilter (bool *active, unsigned short *b0, unsigned short *b1, unsigned short *b2, unsigned short *a1, unsigned short *a2);
|
||||
FMOD_RESULT setControllerSpeaker(unsigned int controllerspeaker, int subchannel = -1);
|
||||
FMOD_RESULT getControllerSpeaker(unsigned int *controllerspeaker);
|
||||
#endif
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
577
src/fmod_channelgroup.cpp
Executable file
577
src/fmod_channelgroup.cpp
Executable file
|
|
@ -0,0 +1,577 @@
|
|||
/*$ preserve start $*/
|
||||
|
||||
#include "fmod_settings.h"
|
||||
|
||||
#include "fmod.hpp"
|
||||
#include "fmod_channelgroupi.h"
|
||||
#include "fmod_systemi.h"
|
||||
|
||||
namespace FMOD
|
||||
{
|
||||
/*$ preserve end $*/
|
||||
|
||||
|
||||
FMOD_RESULT ChannelGroup::release()
|
||||
{
|
||||
FMOD_RESULT result;
|
||||
ChannelGroupI *channelgroupi;
|
||||
|
||||
result = ChannelGroupI::validate(this, &channelgroupi);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
return channelgroupi->release();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
FMOD_RESULT ChannelGroup::getSystemObject(System **system)
|
||||
{
|
||||
FMOD_RESULT result;
|
||||
ChannelGroupI *channelgroupi;
|
||||
|
||||
result = ChannelGroupI::validate(this, &channelgroupi);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
return channelgroupi->getSystemObject(system);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
FMOD_RESULT ChannelGroup::setVolume(float volume)
|
||||
{
|
||||
FMOD_RESULT result;
|
||||
ChannelGroupI *channelgroupi;
|
||||
|
||||
result = ChannelGroupI::validate(this, &channelgroupi);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
return channelgroupi->setVolume(volume);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
FMOD_RESULT ChannelGroup::getVolume(float *volume)
|
||||
{
|
||||
FMOD_RESULT result;
|
||||
ChannelGroupI *channelgroupi;
|
||||
|
||||
result = ChannelGroupI::validate(this, &channelgroupi);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
return channelgroupi->getVolume(volume);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
FMOD_RESULT ChannelGroup::setPitch(float pitch)
|
||||
{
|
||||
FMOD_RESULT result;
|
||||
ChannelGroupI *channelgroupi;
|
||||
|
||||
result = ChannelGroupI::validate(this, &channelgroupi);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
return channelgroupi->setPitch(pitch);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
FMOD_RESULT ChannelGroup::getPitch(float *pitch)
|
||||
{
|
||||
FMOD_RESULT result;
|
||||
ChannelGroupI *channelgroupi;
|
||||
|
||||
result = ChannelGroupI::validate(this, &channelgroupi);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
return channelgroupi->getPitch(pitch);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
FMOD_RESULT ChannelGroup::set3DOcclusion(float directocclusion, float reverbocclusion)
|
||||
{
|
||||
FMOD_RESULT result;
|
||||
ChannelGroupI *channelgroupi;
|
||||
|
||||
result = ChannelGroupI::validate(this, &channelgroupi);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
return channelgroupi->set3DOcclusion(directocclusion, reverbocclusion);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
FMOD_RESULT ChannelGroup::get3DOcclusion(float *directocclusion, float *reverbocclusion)
|
||||
{
|
||||
FMOD_RESULT result;
|
||||
ChannelGroupI *channelgroupi;
|
||||
|
||||
result = ChannelGroupI::validate(this, &channelgroupi);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
return channelgroupi->get3DOcclusion(directocclusion, reverbocclusion);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
FMOD_RESULT ChannelGroup::setPaused(bool paused)
|
||||
{
|
||||
FMOD_RESULT result;
|
||||
ChannelGroupI *channelgroupi;
|
||||
|
||||
result = ChannelGroupI::validate(this, &channelgroupi);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
return channelgroupi->setPaused(paused);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
FMOD_RESULT ChannelGroup::getPaused(bool *paused)
|
||||
{
|
||||
FMOD_RESULT result;
|
||||
ChannelGroupI *channelgroupi;
|
||||
|
||||
result = ChannelGroupI::validate(this, &channelgroupi);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
return channelgroupi->getPaused(paused);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
FMOD_RESULT ChannelGroup::setMute(bool mute)
|
||||
{
|
||||
FMOD_RESULT result;
|
||||
ChannelGroupI *channelgroupi;
|
||||
|
||||
result = ChannelGroupI::validate(this, &channelgroupi);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
return channelgroupi->setMute(mute);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
FMOD_RESULT ChannelGroup::getMute(bool *mute)
|
||||
{
|
||||
FMOD_RESULT result;
|
||||
ChannelGroupI *channelgroupi;
|
||||
|
||||
result = ChannelGroupI::validate(this, &channelgroupi);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
return channelgroupi->getMute(mute);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
FMOD_RESULT ChannelGroup::stop()
|
||||
{
|
||||
FMOD_RESULT result;
|
||||
ChannelGroupI *channelgroupi;
|
||||
|
||||
result = ChannelGroupI::validate(this, &channelgroupi);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
return channelgroupi->stop();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
FMOD_RESULT ChannelGroup::overrideVolume(float volume)
|
||||
{
|
||||
FMOD_RESULT result;
|
||||
ChannelGroupI *channelgroupi;
|
||||
|
||||
result = ChannelGroupI::validate(this, &channelgroupi);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
return channelgroupi->overrideVolume(volume);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
FMOD_RESULT ChannelGroup::overrideFrequency(float frequency)
|
||||
{
|
||||
FMOD_RESULT result;
|
||||
ChannelGroupI *channelgroupi;
|
||||
|
||||
result = ChannelGroupI::validate(this, &channelgroupi);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
return channelgroupi->overrideFrequency(frequency);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
FMOD_RESULT ChannelGroup::overridePan(float pan)
|
||||
{
|
||||
FMOD_RESULT result;
|
||||
ChannelGroupI *channelgroupi;
|
||||
|
||||
result = ChannelGroupI::validate(this, &channelgroupi);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
return channelgroupi->overridePan(pan);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
FMOD_RESULT ChannelGroup::overrideReverbProperties(const FMOD_REVERB_CHANNELPROPERTIES *prop)
|
||||
{
|
||||
FMOD_RESULT result;
|
||||
ChannelGroupI *channelgroupi;
|
||||
|
||||
result = ChannelGroupI::validate(this, &channelgroupi);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
return channelgroupi->overrideReverbProperties(prop);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
FMOD_RESULT ChannelGroup::override3DAttributes(const FMOD_VECTOR *pos, const FMOD_VECTOR *vel)
|
||||
{
|
||||
FMOD_RESULT result;
|
||||
ChannelGroupI *channelgroupi;
|
||||
|
||||
result = ChannelGroupI::validate(this, &channelgroupi);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
return channelgroupi->override3DAttributes(pos, vel);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
FMOD_RESULT ChannelGroup::overrideSpeakerMix(float frontleft, float frontright, float center, float lfe, float backleft, float backright, float sideleft, float sideright)
|
||||
{
|
||||
FMOD_RESULT result;
|
||||
ChannelGroupI *channelgroupi;
|
||||
|
||||
result = ChannelGroupI::validate(this, &channelgroupi);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
return channelgroupi->overrideSpeakerMix(frontleft, frontright, center, lfe, backleft, backright, sideleft, sideright);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
FMOD_RESULT ChannelGroup::addGroup(ChannelGroup *group)
|
||||
{
|
||||
FMOD_RESULT result;
|
||||
ChannelGroupI *channelgroupi;
|
||||
|
||||
result = ChannelGroupI::validate(this, &channelgroupi);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
return channelgroupi->addGroup((ChannelGroupI *)group);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
FMOD_RESULT ChannelGroup::getNumGroups(int *numgroups)
|
||||
{
|
||||
FMOD_RESULT result;
|
||||
ChannelGroupI *channelgroupi;
|
||||
|
||||
result = ChannelGroupI::validate(this, &channelgroupi);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
return channelgroupi->getNumGroups(numgroups);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
FMOD_RESULT ChannelGroup::getGroup(int index, ChannelGroup **group)
|
||||
{
|
||||
FMOD_RESULT result;
|
||||
ChannelGroupI *channelgroupi;
|
||||
|
||||
result = ChannelGroupI::validate(this, &channelgroupi);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
return channelgroupi->getGroup(index, (ChannelGroupI **)group);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
FMOD_RESULT ChannelGroup::getParentGroup(ChannelGroup **group)
|
||||
{
|
||||
FMOD_RESULT result;
|
||||
ChannelGroupI *channelgroupi;
|
||||
|
||||
result = ChannelGroupI::validate(this, &channelgroupi);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
return channelgroupi->getParentGroup((ChannelGroupI **)group);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
FMOD_RESULT ChannelGroup::getDSPHead(DSP **dsp)
|
||||
{
|
||||
FMOD_RESULT result;
|
||||
ChannelGroupI *channelgroupi;
|
||||
|
||||
result = ChannelGroupI::validate(this, &channelgroupi);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
return channelgroupi->getDSPHead((DSPI **)dsp);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
FMOD_RESULT ChannelGroup::addDSP(DSP *dsp, DSPConnection **connection)
|
||||
{
|
||||
FMOD_RESULT result;
|
||||
ChannelGroupI *channelgroupi;
|
||||
|
||||
result = ChannelGroupI::validate(this, &channelgroupi);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
return channelgroupi->addDSP((DSPI *)dsp, (DSPConnectionI **)connection);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
FMOD_RESULT ChannelGroup::getName(char *name, int namelen)
|
||||
{
|
||||
FMOD_RESULT result;
|
||||
ChannelGroupI *channelgroupi;
|
||||
|
||||
result = ChannelGroupI::validate(this, &channelgroupi);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
return channelgroupi->getName(name, namelen);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
FMOD_RESULT ChannelGroup::getNumChannels(int *numchannels)
|
||||
{
|
||||
FMOD_RESULT result;
|
||||
ChannelGroupI *channelgroupi;
|
||||
|
||||
result = ChannelGroupI::validate(this, &channelgroupi);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
return channelgroupi->getNumChannels(numchannels);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
FMOD_RESULT ChannelGroup::getChannel(int index, Channel **channel)
|
||||
{
|
||||
FMOD_RESULT result;
|
||||
ChannelGroupI *channelgroupi;
|
||||
|
||||
result = ChannelGroupI::validate(this, &channelgroupi);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
return channelgroupi->getChannel(index, (Channel **)channel);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
FMOD_RESULT ChannelGroup::getSpectrum(float *spectrumarray, int numvalues, int channeloffset, FMOD_DSP_FFT_WINDOW windowtype)
|
||||
{
|
||||
FMOD_RESULT result;
|
||||
ChannelGroupI *channelgroupi;
|
||||
|
||||
result = ChannelGroupI::validate(this, &channelgroupi);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
return channelgroupi->getSpectrum(spectrumarray, numvalues, channeloffset, windowtype);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
FMOD_RESULT ChannelGroup::getWaveData(float *wavearray, int numvalues, int channeloffset)
|
||||
{
|
||||
FMOD_RESULT result;
|
||||
ChannelGroupI *channelgroupi;
|
||||
|
||||
result = ChannelGroupI::validate(this, &channelgroupi);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
return channelgroupi->getWaveData(wavearray, numvalues, channeloffset);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
FMOD_RESULT ChannelGroup::setUserData(void *_userdata)
|
||||
{
|
||||
FMOD_RESULT result;
|
||||
ChannelGroupI *channelgroupi;
|
||||
|
||||
result = ChannelGroupI::validate(this, &channelgroupi);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
return channelgroupi->setUserData(_userdata);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
FMOD_RESULT ChannelGroup::getUserData(void **_userdata)
|
||||
{
|
||||
FMOD_RESULT result;
|
||||
ChannelGroupI *channelgroupi;
|
||||
|
||||
result = ChannelGroupI::validate(this, &channelgroupi);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
return channelgroupi->getUserData(_userdata);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
FMOD_RESULT ChannelGroup::getMemoryInfo(unsigned int memorybits, unsigned int event_memorybits, unsigned int *memoryused, FMOD_MEMORY_USAGE_DETAILS *memoryused_details)
|
||||
{
|
||||
FMOD_RESULT result;
|
||||
ChannelGroupI *channelgroupi;
|
||||
|
||||
result = ChannelGroupI::validate(this, &channelgroupi);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
return channelgroupi->getMemoryInfo(memorybits, event_memorybits, memoryused, memoryused_details);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*$ preserve start $*/
|
||||
}
|
||||
/*$ preserve end $*/
|
||||
1959
src/fmod_channelgroupi.cpp
Executable file
1959
src/fmod_channelgroupi.cpp
Executable file
File diff suppressed because it is too large
Load diff
128
src/fmod_channelgroupi.h
Executable file
128
src/fmod_channelgroupi.h
Executable file
|
|
@ -0,0 +1,128 @@
|
|||
#ifndef _FMOD_CHANNELGROUPI_H
|
||||
#define _FMOD_CHANNELGROUPI_H
|
||||
|
||||
#include "fmod_settings.h"
|
||||
|
||||
#include "fmod.hpp"
|
||||
#include "fmod_dsp_filter.h"
|
||||
#include "fmod_linkedlist.h"
|
||||
#include "fmod_string.h"
|
||||
#ifndef _FMOD_MEMORYTRACKER_H
|
||||
#include "fmod_memorytracker.h"
|
||||
#endif
|
||||
|
||||
namespace FMOD
|
||||
{
|
||||
class ChannelI;
|
||||
class DSPI;
|
||||
class DSPConnectionI;
|
||||
class SystemI;
|
||||
|
||||
class ChannelGroupI : public LinkedListNode /* This linked list node entry is for System::mChannelGroupHead */
|
||||
{
|
||||
DECLARE_MEMORYTRACKER
|
||||
|
||||
public:
|
||||
|
||||
static FMOD_RESULT validate(ChannelGroup *channelgroup, ChannelGroupI **channelgroupi);
|
||||
|
||||
SystemI *mSystem;
|
||||
void *mUserData;
|
||||
DSPI *mDSPHead;
|
||||
DSPI *mDSPMixTarget; /* By default this just points to mDSPHead unless dsp effects are added. */
|
||||
ChannelGroupI *mParent;
|
||||
ChannelGroupI *mGroupHead;
|
||||
LinkedListNode mChannelHead;
|
||||
int mNumChannels;
|
||||
char *mName;
|
||||
float mVolume, mRealVolume;
|
||||
float mDirectOcclusion, mReverbOcclusion;
|
||||
float mRealDirectOcclusionVolume, mRealReverbOcclusionVolume;
|
||||
float mPitch;
|
||||
float mRealPitch;
|
||||
|
||||
bool mMute;
|
||||
bool mPaused;
|
||||
|
||||
FMOD_RESULT updateChildMixTarget(DSPI *dsp);
|
||||
|
||||
public:
|
||||
|
||||
ChannelGroupI()
|
||||
{
|
||||
mVolume = mRealVolume = 1;
|
||||
mPitch = mRealPitch = 1;
|
||||
mDirectOcclusion = mReverbOcclusion = 0;
|
||||
mRealDirectOcclusionVolume = mRealReverbOcclusionVolume = 1;
|
||||
}
|
||||
|
||||
FMOD_RESULT release ();
|
||||
FMOD_RESULT releaseInternal (bool releasechildren = false);
|
||||
FMOD_RESULT getSystemObject (System **system);
|
||||
|
||||
// Channelgroup scale values. (changes attributes relative to the channels, doesn't overwrite them)
|
||||
FMOD_RESULT setVolume (float volume);
|
||||
FMOD_RESULT setVolumeInternal ();
|
||||
FMOD_RESULT getVolume (float *volume);
|
||||
FMOD_RESULT setPitch (float pitch);
|
||||
FMOD_RESULT setPitchInternal ();
|
||||
FMOD_RESULT getPitch (float *pitch);
|
||||
FMOD_RESULT set3DOcclusion (float directocclusion, float reverbocclusion);
|
||||
FMOD_RESULT set3DOcclusionInternal ();
|
||||
FMOD_RESULT get3DOcclusion (float *directocclusion, float *reverbocclusion);
|
||||
FMOD_RESULT setPaused (bool paused, bool setpausedflag = true);
|
||||
FMOD_RESULT getPaused (bool *paused);
|
||||
FMOD_RESULT setMute (bool mute, bool setmuteflag = true);
|
||||
FMOD_RESULT getMute (bool *mute);
|
||||
|
||||
// Channelgroup override values. (recursively overwrites whatever settings the channels had)
|
||||
FMOD_RESULT stop ();
|
||||
FMOD_RESULT overrideVolume (float volume);
|
||||
FMOD_RESULT overrideFrequency (float frequency);
|
||||
FMOD_RESULT overridePan (float pan);
|
||||
FMOD_RESULT overrideReverbProperties(const FMOD_REVERB_CHANNELPROPERTIES *prop);
|
||||
FMOD_RESULT override3DAttributes (const FMOD_VECTOR *pos, const FMOD_VECTOR *vel);
|
||||
FMOD_RESULT overrideSpeakerMix (float frontleft, float frontright, float center, float lfe, float backleft, float backright, float sideleft, float sideright);
|
||||
|
||||
// Nested channel groups.
|
||||
FMOD_RESULT addGroup (ChannelGroupI *group);
|
||||
FMOD_RESULT getNumGroups (int *numgroups);
|
||||
FMOD_RESULT getGroup (int index, ChannelGroupI **group);
|
||||
FMOD_RESULT getParentGroup (ChannelGroupI **group);
|
||||
|
||||
// DSP functionality only for channel groups playing sounds created with FMOD_SOFTWARE.
|
||||
FMOD_RESULT getDSPHead (DSPI **dsp);
|
||||
FMOD_RESULT addDSP (DSPI *dsp, DSPConnectionI **connection);
|
||||
|
||||
// Information only functions.
|
||||
FMOD_RESULT getName (char *name, int namelen);
|
||||
FMOD_RESULT getNumChannels (int *numchannels);
|
||||
FMOD_RESULT getChannel (int index, Channel **channel);
|
||||
FMOD_RESULT getSpectrum (float *spectrumarray, int numvalues, int channeloffset, FMOD_DSP_FFT_WINDOW windowtype);
|
||||
FMOD_RESULT getWaveData (float *wavearray, int numvalues, int channeloffset);
|
||||
|
||||
// Userdata set/get.
|
||||
FMOD_RESULT setUserData (void *userdata);
|
||||
FMOD_RESULT getUserData (void **userdata);
|
||||
|
||||
FMOD_RESULT getMemoryInfo (unsigned int memorybits, unsigned int event_memorybits, unsigned int *memoryused, FMOD_MEMORY_USAGE_DETAILS *memoryused_details);
|
||||
};
|
||||
|
||||
#ifdef FMOD_SUPPORT_SOFTWARE
|
||||
class ChannelGroupSoftware : public ChannelGroupI
|
||||
{
|
||||
DECLARE_MEMORYTRACKER
|
||||
|
||||
public:
|
||||
DSPFilter mDSPHeadMemory;
|
||||
#if defined(PLATFORM_PS3) || defined(PLATFORM_WINDOWS_PS3MODE)
|
||||
char mAlign[128];
|
||||
#endif
|
||||
};
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
6756
src/fmod_channeli.cpp
Executable file
6756
src/fmod_channeli.cpp
Executable file
File diff suppressed because it is too large
Load diff
322
src/fmod_channeli.h
Executable file
322
src/fmod_channeli.h
Executable file
|
|
@ -0,0 +1,322 @@
|
|||
#ifndef _FMOD_CHANNELI_H
|
||||
#define _FMOD_CHANNELI_H
|
||||
|
||||
#include "fmod_settings.h"
|
||||
|
||||
#include "fmod.hpp"
|
||||
#include "fmod_linkedlist.h"
|
||||
#ifndef _FMOD_MEMORYTRACKER_H
|
||||
#include "fmod_memorytracker.h"
|
||||
#endif
|
||||
|
||||
namespace FMOD
|
||||
{
|
||||
|
||||
const unsigned int SYSTEMID_BITS = 4;
|
||||
const unsigned int CHANINDEX_BITS = 12;
|
||||
const unsigned int REFCOUNT_BITS = 16;
|
||||
const unsigned int SYSTEMID_SHIFT = REFCOUNT_BITS + CHANINDEX_BITS;
|
||||
const unsigned int CHANINDEX_SHIFT = REFCOUNT_BITS;
|
||||
const unsigned int REFCOUNT_SHIFT = 0;
|
||||
const unsigned int SYSTEMID_MASK = (unsigned int)0xffffffff >> (32 - SYSTEMID_BITS);
|
||||
const unsigned int CHANINDEX_MASK = (unsigned int)0xffffffff >> (32 - CHANINDEX_BITS);
|
||||
const unsigned int REFCOUNT_MASK = (unsigned int)0xffffffff >> (32 - REFCOUNT_BITS);
|
||||
|
||||
const unsigned int FMOD_CHANNEL_DEFAULTPRIORITY = 128;
|
||||
|
||||
const int FMOD_CHANNEL_MAXINPUTCHANNELS = 16;
|
||||
|
||||
#if defined(PLATFORM_PS3) || defined(PLATFORM_XENON) || defined(PLATFORM_MAC) || defined(PLATFORM_LINUX)
|
||||
const int FMOD_CHANNEL_MAXREALSUBCHANNELS = 1; /* We know these 2 are definitely software only and the mixer supports 16ch. */
|
||||
#else
|
||||
const int FMOD_CHANNEL_MAXREALSUBCHANNELS = FMOD_CHANNEL_MAXINPUTCHANNELS;
|
||||
#endif
|
||||
|
||||
typedef enum
|
||||
{
|
||||
FMOD_CHANNEL_PANMODE_PAN,
|
||||
FMOD_CHANNEL_PANMODE_SPEAKERMIX,
|
||||
FMOD_CHANNEL_PANMODE_SPEAKERLEVELS,
|
||||
} FMOD_CHANNEL_PANMODE;
|
||||
|
||||
class ChannelGroupI;
|
||||
class ChannelReal;
|
||||
class DSPI;
|
||||
class DSPConnectionI;
|
||||
class ReverbI;
|
||||
class SoundI;
|
||||
class Stream;
|
||||
class SyncPoint;
|
||||
class SystemI;
|
||||
class OcclusionProcessor;
|
||||
|
||||
typedef unsigned int FMOD_CHANNEL_FLAG;
|
||||
typedef unsigned int FMOD_CHANNEL_STOPFLAG;
|
||||
|
||||
#define CHANNELI_FLAG_PAUSED 0x00000001
|
||||
#define CHANNELI_FLAG_MUTED 0x00000002
|
||||
#define CHANNELI_FLAG_JUSTWENTVIRTUAL 0x00000004
|
||||
#define CHANNELI_FLAG_REALMUTE 0x00000008
|
||||
#define CHANNELI_FLAG_MOVED 0x00000010
|
||||
#define CHANNELI_FLAG_FORCEVIRTUAL 0x00000040
|
||||
#define CHANNELI_FLAG_USEDINPUTMIX 0x00000080
|
||||
#define CHANNELI_FLAG_PLAYINGPAUSED 0x00000100
|
||||
#define CHANNELI_FLAG_USEDPAUSEDELAY 0x00000200
|
||||
#define CHANNELI_FLAG_ENDDELAY 0x00000400
|
||||
#define CHANNELI_FLAG_MUSICOWNED 0x00000800
|
||||
|
||||
#define CHANNELI_STOPFLAG_REFSTAMP 0x00000001
|
||||
#define CHANNELI_STOPFLAG_UPDATELIST 0x00000002
|
||||
#define CHANNELI_STOPFLAG_RESETCALLBACKS 0x00000004
|
||||
#define CHANNELI_STOPFLAG_CALLENDCALLBACK 0x00000008
|
||||
#define CHANNELI_STOPFLAG_RESETCHANNELGROUP 0x00000010
|
||||
#define CHANNELI_STOPFLAG_PROCESSENDDELAY 0x00000020
|
||||
#define CHANNELI_STOPFLAG_UPDATESYNCPOINTS 0x00000040
|
||||
#define CHANNELI_STOPFLAG_DONTFREELEVELS 0x00000080
|
||||
|
||||
typedef struct
|
||||
{
|
||||
float *mLevels;
|
||||
unsigned int mPCM, mLoopStart, mLoopEnd;
|
||||
ChannelReal *mRealChannel;
|
||||
SoundI *mSound;
|
||||
DSPI *mDSP;
|
||||
int mLoopCount;
|
||||
bool mMute, mPaused;
|
||||
unsigned int mDSPClockHi, mDSPClockLo;
|
||||
FMOD_MODE mMode;
|
||||
|
||||
#ifdef PLATFORM_WII
|
||||
int mLowPassCutoff;
|
||||
bool mBiquadActive;
|
||||
unsigned short mBiquadB0;
|
||||
unsigned short mBiquadB1;
|
||||
unsigned short mBiquadB2;
|
||||
unsigned short mBiquadA1;
|
||||
unsigned short mBiquadA2;
|
||||
unsigned int mControllerSpeaker;
|
||||
#endif
|
||||
} FMOD_CHANNEL_INFO;
|
||||
|
||||
class ChannelI : public LinkedListNode /* This linked list node entry is for System::mChannelFreeListHead / mChannelUsedListHead */
|
||||
{ /* 16 bytes */
|
||||
DECLARE_MEMORYTRACKER
|
||||
|
||||
friend class Channel;
|
||||
friend class OcclusionProcessor;
|
||||
|
||||
public:
|
||||
|
||||
SortedLinkedListNode mSortedListNode; /* 12 bytes */
|
||||
SortedLinkedListNode mSoundGroupSortedListNode; /* 12 bytes */
|
||||
|
||||
int mIndex; /* 4 bytes */
|
||||
void *mUserData; /* 4 bytes */
|
||||
unsigned int mHandleOriginal; /* Handle as it was when this channel was first played */ /* 4 bytes */
|
||||
SystemI *mSystem; /* 4 bytes */
|
||||
int mNumRealChannels; /* 4 bytes */
|
||||
ChannelReal *mRealChannel[FMOD_CHANNEL_MAXREALSUBCHANNELS]; /* 64 bytes <-------- */
|
||||
unsigned int mHandleCurrent; /* Handle as it is now */ /* 4 bytes */
|
||||
|
||||
/*
|
||||
Misc
|
||||
*/
|
||||
FMOD_CHANNEL_FLAG mFlags; /* 4 bytes */
|
||||
FMOD_CHANNEL_PANMODE mLastPanMode; /* 4 bytes */
|
||||
int mPriority; /* 4 bytes */
|
||||
unsigned int mListPosition; /* 4 bytes */
|
||||
unsigned int mSoundGroupListPosition; /* 4 bytes */
|
||||
SyncPoint *mSyncPointCurrent; /* 4 bytes */
|
||||
unsigned int mSyncPointLastPos; /* 4 bytes */
|
||||
ChannelGroupI *mChannelGroup; /* 4 bytes */
|
||||
LinkedListNode mChannelGroupNode; /* 16 bytes */
|
||||
float mFadeVolume; /* 4 bytes */
|
||||
float mFadeTarget; /* 4 bytes */
|
||||
unsigned int mEndDelay; /* 4 bytes */
|
||||
FMOD_UINT64P mDSPClockDelay; /* 8 bytes */
|
||||
FMOD_UINT64P mDSPClockEnd; /* 8 bytes */
|
||||
FMOD_UINT64P mDSPClockPause; /* 8 bytes */
|
||||
float mLowPassGain; /* 4 bytes */
|
||||
DSPI *mAddDSPHead; /* 4 bytes */
|
||||
FMOD_SPEAKERMODE mSpeakerMode; /* 4 bytes */
|
||||
|
||||
/*
|
||||
2D
|
||||
*/
|
||||
float mVolume; /* 4 bytes */
|
||||
float mFrequency; /* 4 bytes */
|
||||
float mPan; /* 4 bytes */
|
||||
float mSpeakerFL, mSpeakerFR, mSpeakerC, mSpeakerLFE; /* 16 bytes */
|
||||
float mSpeakerBL, mSpeakerBR, mSpeakerSL, mSpeakerSR; /* 16 bytes */
|
||||
float mInputMix[FMOD_CHANNEL_MAXINPUTCHANNELS]; /* 64 bytes */
|
||||
float *mLevels; /* 4 bytes */
|
||||
|
||||
/*
|
||||
3D
|
||||
*/
|
||||
float mReverbDryVolume; /* 4 bytes */
|
||||
float mVolume3D; /* current relative 3d volume. */ /* 4 bytes */
|
||||
float mPitch3D; /* current relative 3d frequency. */ /* 4 bytes */
|
||||
FMOD_VECTOR mPosition3D; /* 12 bytes */
|
||||
FMOD_VECTOR mVelocity3D; /* 12 bytes */
|
||||
float mDistance; /* 4 bytes */
|
||||
float mMinDistance; /* 4 bytes */
|
||||
float mMaxDistance; /* 4 bytes */
|
||||
float mConeVolume3D; /* 4 bytes */
|
||||
float mConeInsideAngle; /* 4 bytes */
|
||||
float mConeOutsideAngle; /* 4 bytes */
|
||||
float mConeOutsideVolume; /* 4 bytes */
|
||||
FMOD_VECTOR mConeOrientation; /* 12 bytes */
|
||||
float mDirectOcclusion; /* 4 bytes */
|
||||
float mReverbOcclusion; /* 4 bytes */
|
||||
float mDirectOcclusionTarget; /* 4 bytes */
|
||||
float mReverbOcclusionTarget; /* 4 bytes */
|
||||
float mUserDirectOcclusion; /* 4 bytes */
|
||||
float mUserReverbOcclusion; /* 4 bytes */
|
||||
float mDirectOcclusionRateOfChange; /* 4 bytes */
|
||||
float mReverbOcclusionRateOfChange; /* 4 bytes */
|
||||
FMOD_VECTOR *mRolloffPoint; /* 4 bytes */
|
||||
int mNumRolloffPoints; /* 4 bytes */
|
||||
float mSpread; /* 4 bytes */
|
||||
float m3DPanLevel; /* 4 bytes */
|
||||
float m3DDopplerLevel; /* 4 bytes */
|
||||
|
||||
FMOD_CHANNEL_CALLBACK mCallback; /* 4 bytes */
|
||||
/* --------- */
|
||||
// F_API so EventSound::getEndTime can link to it
|
||||
static FMOD_RESULT F_API validate(Channel *channel, ChannelI **channeli); /* ??? bytes */
|
||||
|
||||
FMOD_RESULT returnToFreeList();
|
||||
FMOD_RESULT setDefaults();
|
||||
FMOD_RESULT referenceStamp(bool newstamp = false);
|
||||
FMOD_RESULT updatePosition();
|
||||
FMOD_RESULT forceVirtual(bool force);
|
||||
FMOD_RESULT getChannelInfo(FMOD_CHANNEL_INFO *info);
|
||||
FMOD_RESULT setChannelInfo(FMOD_CHANNEL_INFO *info);
|
||||
FMOD_RESULT getRealChannel(ChannelReal **realchan, int *subchannels);
|
||||
FMOD_RESULT calcVolumeAndPitchFor3D(int delta);
|
||||
FMOD_RESULT setChannelGroupInternal(ChannelGroupI *channelgroup, bool resetattributes, bool forcedspreconnect = false);
|
||||
FMOD_RESULT set3DOcclusionInternal(float directOcclusion, float reverbOcclusion, bool resettarget=true);
|
||||
FMOD_RESULT get3DOcclusionInternal(float *directOcclusion, float *reverbOcclusion);
|
||||
FMOD_RESULT getAudibilityInternal(float *audibility, bool usefadevolume);
|
||||
// F_API so EventSound::getEndTime can link to it
|
||||
FMOD_RESULT F_API getFinalFrequency(float *frequency);
|
||||
|
||||
public:
|
||||
|
||||
ChannelI();
|
||||
ChannelI(int index, SystemI *system);
|
||||
FMOD_RESULT init();
|
||||
|
||||
|
||||
FMOD_RESULT getSystemObject (System **system);
|
||||
|
||||
FMOD_RESULT play (SoundI *sound, bool paused, bool reset, bool startmuted);
|
||||
FMOD_RESULT play (DSPI *dsp, bool paused, bool reset, bool startmuted);
|
||||
FMOD_RESULT alloc (SoundI *sound, bool reset);
|
||||
FMOD_RESULT alloc (DSPI *dsp, bool reset);
|
||||
FMOD_RESULT start ();
|
||||
FMOD_RESULT updateSyncPoints (bool seeking);
|
||||
FMOD_RESULT update (int delta, bool updategeometrynow = false);
|
||||
FMOD_RESULT updateStream ();
|
||||
|
||||
FMOD_RESULT stop ();
|
||||
FMOD_RESULT stopEx (FMOD_CHANNEL_STOPFLAG stopflag);
|
||||
FMOD_RESULT setPaused (bool paused);
|
||||
FMOD_RESULT getPaused (bool *paused);
|
||||
FMOD_RESULT setVolume (float volume, bool forceupdatepos = false);
|
||||
FMOD_RESULT getVolume (float *volume);
|
||||
FMOD_RESULT setFrequency (float frequency);
|
||||
FMOD_RESULT getFrequency (float *frequency);
|
||||
FMOD_RESULT setPan (float pan, bool calldriver = true);
|
||||
FMOD_RESULT getPan (float *pan);
|
||||
FMOD_RESULT setDelay (FMOD_DELAYTYPE delaytype, unsigned int delayhi, unsigned int delaylo);
|
||||
FMOD_RESULT getDelay (FMOD_DELAYTYPE delaytype, unsigned int *delayhi, unsigned int *delaylo);
|
||||
FMOD_RESULT setSpeakerMix (float frontleft, float frontright, float center, float lfe, float backleft, float backright, float sideleft, float sideright, bool calldriver = true);
|
||||
FMOD_RESULT getSpeakerMix (float *frontleft, float *frontright, float *center, float *lfe, float *backleft, float *backright, float *sideleft, float *sideright);
|
||||
FMOD_RESULT setSpeakerLevels (FMOD_SPEAKER speaker, float *levels, int numlevels, bool calldriver = true);
|
||||
FMOD_RESULT getSpeakerLevels (FMOD_SPEAKER speaker, float *levels, int numlevels);
|
||||
FMOD_RESULT setInputChannelMix (float *levels, int numlevels);
|
||||
FMOD_RESULT getInputChannelMix (float *levels, int numlevels);
|
||||
FMOD_RESULT setMute (bool mute);
|
||||
FMOD_RESULT getMute (bool *mute);
|
||||
FMOD_RESULT setPriority (int priority);
|
||||
FMOD_RESULT getPriority (int *priority);
|
||||
FMOD_RESULT setPosition (unsigned int position, FMOD_TIMEUNIT postype);
|
||||
FMOD_RESULT getPosition (unsigned int *position, FMOD_TIMEUNIT postype);
|
||||
FMOD_RESULT setReverbProperties (const FMOD_REVERB_CHANNELPROPERTIES *prop);
|
||||
FMOD_RESULT getReverbProperties (FMOD_REVERB_CHANNELPROPERTIES *prop);
|
||||
FMOD_RESULT setChannelGroup (ChannelGroupI *channelgroup);
|
||||
FMOD_RESULT getChannelGroup (ChannelGroupI **channelgroup);
|
||||
FMOD_RESULT setCallback (FMOD_CHANNEL_CALLBACK callback);
|
||||
FMOD_RESULT calculate3DReverbGain(ReverbI *reverb, FMOD_VECTOR *channelpos, float *gain);
|
||||
FMOD_RESULT setLowPassGain (float gain);
|
||||
FMOD_RESULT getLowPassGain (float *gain);
|
||||
|
||||
// 3D functionality.
|
||||
FMOD_RESULT set3DAttributes (const FMOD_VECTOR *pos, const FMOD_VECTOR *vel);
|
||||
FMOD_RESULT get3DAttributes (FMOD_VECTOR *pos, FMOD_VECTOR *vel);
|
||||
FMOD_RESULT set3DMinMaxDistance (float mindistance, float maxdistance);
|
||||
FMOD_RESULT get3DMinMaxDistance (float *mindistance, float *maxdistance);
|
||||
FMOD_RESULT set3DConeSettings (float insideconeangle, float outsideconeangle, float outsidevolume);
|
||||
FMOD_RESULT get3DConeSettings (float *insideconeangle, float *outsideconeangle, float *outsidevolume);
|
||||
FMOD_RESULT set3DConeOrientation (FMOD_VECTOR *orientation);
|
||||
FMOD_RESULT get3DConeOrientation (FMOD_VECTOR *orientation);
|
||||
FMOD_RESULT set3DCustomRolloff (FMOD_VECTOR *points, int numpoints);
|
||||
FMOD_RESULT get3DCustomRolloff (FMOD_VECTOR **points, int *numpoints);
|
||||
FMOD_RESULT set3DOcclusion (float directOcclusion, float reverbOcclusion);
|
||||
FMOD_RESULT get3DOcclusion (float *directOcclusion, float *reverbOcclusion);
|
||||
FMOD_RESULT set3DSpread (float angle);
|
||||
FMOD_RESULT get3DSpread (float *angle);
|
||||
FMOD_RESULT set3DPanLevel (float level);
|
||||
FMOD_RESULT get3DPanLevel (float *level);
|
||||
FMOD_RESULT set3DDopplerLevel (float level);
|
||||
FMOD_RESULT get3DDopplerLevel (float *level);
|
||||
|
||||
// DSP functionality only for channels playing sounds created with FMOD_SOFTWARE.
|
||||
FMOD_RESULT getDSPHead (DSPI **dsp);
|
||||
FMOD_RESULT addDSP (DSPI *dsp, DSPConnectionI **connection);
|
||||
|
||||
// Information only functions.
|
||||
FMOD_RESULT isPlaying (bool *isplaying);
|
||||
FMOD_RESULT isVirtual (bool *isvirtual);
|
||||
FMOD_RESULT getAudibility (float *audibility);
|
||||
FMOD_RESULT getCurrentSound (SoundI **sound);
|
||||
FMOD_RESULT getCurrentDSP (DSPI **dsp);
|
||||
FMOD_RESULT getSpectrum (float *spectrumarray, int numvalues, int channeloffset, FMOD_DSP_FFT_WINDOW windowtype);
|
||||
FMOD_RESULT getWaveData (float *wavearray, int numvalues, int channeloffset);
|
||||
FMOD_RESULT getIndex (int *index);
|
||||
|
||||
// Functions also found in Sound class but here they can be set per channel.
|
||||
FMOD_RESULT setMode (FMOD_MODE mode);
|
||||
FMOD_RESULT getMode (FMOD_MODE *mode);
|
||||
FMOD_RESULT setLoopCount (int loopcount);
|
||||
FMOD_RESULT getLoopCount (int *loopcount);
|
||||
FMOD_RESULT setLoopPoints (unsigned int loopstart, FMOD_TIMEUNIT loopstarttype, unsigned int loopend, FMOD_TIMEUNIT loopendtype);
|
||||
FMOD_RESULT getLoopPoints (unsigned int *loopstart, FMOD_TIMEUNIT loopstarttype, unsigned int *loopend, FMOD_TIMEUNIT loopendtype);
|
||||
|
||||
// Userdata set/get.
|
||||
FMOD_RESULT setUserData (void *userdata);
|
||||
FMOD_RESULT getUserData (void **userdata);
|
||||
|
||||
FMOD_RESULT getMemoryInfo (unsigned int memorybits, unsigned int event_memorybits, unsigned int *memoryused, FMOD_MEMORY_USAGE_DETAILS *memoryused_details);
|
||||
|
||||
#ifdef PLATFORM_WII
|
||||
// Lowpass set/get, this is for GameCube and Wii only
|
||||
FMOD_RESULT setLowPassFilter (int cutoff);
|
||||
FMOD_RESULT getLowPassFilter (int *cutoff);
|
||||
|
||||
// Biquad set/get, this is for Wii only
|
||||
FMOD_RESULT setBiquadFilter (bool active, unsigned short b0, unsigned short b1, unsigned short b2, unsigned short a1, unsigned short a2);
|
||||
FMOD_RESULT getBiquadFilter (bool *active, unsigned short *b0, unsigned short *b1, unsigned short *b2, unsigned short *a1, unsigned short *a2);
|
||||
|
||||
// Controller speaker set/get, this is for Wii only
|
||||
FMOD_RESULT setControllerSpeaker (unsigned int controller, int subchannel = -1);
|
||||
FMOD_RESULT getControllerSpeaker (unsigned int *controller);
|
||||
#endif
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
364
src/fmod_channelpool.cpp
Executable file
364
src/fmod_channelpool.cpp
Executable file
|
|
@ -0,0 +1,364 @@
|
|||
#include "fmod_settings.h"
|
||||
|
||||
#include "fmod_channeli.h"
|
||||
#include "fmod_channel_real.h"
|
||||
#include "fmod_channelpool.h"
|
||||
#include "fmod_memory.h"
|
||||
#include "fmod_soundi.h"
|
||||
#include "fmod_channel_software.h"
|
||||
|
||||
#include "fmod_systemi.h"
|
||||
|
||||
namespace FMOD
|
||||
{
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
ChannelPool::ChannelPool()
|
||||
{
|
||||
mChannel = 0;
|
||||
mNumChannels = 0;
|
||||
mChannelsUsed = 0;
|
||||
mSystem = 0;
|
||||
mOutput = 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT ChannelPool::init(SystemI *system, Output *output, int numchannels)
|
||||
{
|
||||
if (numchannels < 0)
|
||||
{
|
||||
return FMOD_ERR_INVALID_PARAM;
|
||||
}
|
||||
|
||||
if (numchannels)
|
||||
{
|
||||
mChannel = (ChannelReal **)FMOD_Memory_Calloc(numchannels * sizeof(ChannelReal *));
|
||||
if (!mChannel)
|
||||
{
|
||||
return FMOD_ERR_MEMORY;
|
||||
}
|
||||
}
|
||||
|
||||
mNumChannels = numchannels;
|
||||
mSystem = system;
|
||||
mOutput = output;
|
||||
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT ChannelPool::release()
|
||||
{
|
||||
int count;
|
||||
|
||||
if (mChannel)
|
||||
{
|
||||
for (count = 0; count < mNumChannels; count++)
|
||||
{
|
||||
if (mChannel[count])
|
||||
{
|
||||
mChannel[count]->close();
|
||||
}
|
||||
}
|
||||
|
||||
FMOD_Memory_Free(mChannel);
|
||||
}
|
||||
|
||||
FMOD_Memory_Free(this);
|
||||
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT ChannelPool::allocateChannel(ChannelReal **realchannel, int index, int numchannels, int *found_out, bool ignorereserved)
|
||||
{
|
||||
int count;
|
||||
int found = 0;
|
||||
|
||||
if (!realchannel)
|
||||
{
|
||||
if (found_out)
|
||||
{
|
||||
*found_out = found;
|
||||
}
|
||||
return FMOD_ERR_INVALID_PARAM;
|
||||
}
|
||||
|
||||
if (index == FMOD_CHANNEL_FREE)
|
||||
{
|
||||
for (count = 0; count < mNumChannels; count++)
|
||||
{
|
||||
FMOD_RESULT result;
|
||||
bool playing;
|
||||
|
||||
if (mChannel[count]->mFlags & CHANNELREAL_FLAG_ALLOCATED ||
|
||||
mChannel[count]->mFlags & CHANNELREAL_FLAG_IN_USE ||
|
||||
(mChannel[count]->mFlags & CHANNELREAL_FLAG_RESERVED && !ignorereserved))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
result = mChannel[count]->isPlaying(&playing, true);
|
||||
if (result == FMOD_OK && !playing)
|
||||
{
|
||||
mChannel[count]->mFlags |= CHANNELREAL_FLAG_ALLOCATED;
|
||||
mChannel[count]->mFlags |= CHANNELREAL_FLAG_IN_USE;
|
||||
mChannel[count]->mFlags &= ~CHANNELREAL_FLAG_STOPPED;
|
||||
mChannel[count]->mFlags &= ~CHANNELREAL_FLAG_RESERVED;
|
||||
|
||||
realchannel[found] = mChannel[count];
|
||||
found++;
|
||||
if (found == numchannels)
|
||||
{
|
||||
if (found_out)
|
||||
{
|
||||
*found_out = found;
|
||||
}
|
||||
return FMOD_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (index >= 0 && index < mNumChannels)
|
||||
{
|
||||
if (numchannels > 1)
|
||||
{
|
||||
return FMOD_ERR_CHANNEL_ALLOC;
|
||||
}
|
||||
|
||||
mChannel[index]->mFlags |= CHANNELREAL_FLAG_ALLOCATED;
|
||||
mChannel[index]->mFlags |= CHANNELREAL_FLAG_IN_USE;
|
||||
mChannel[index]->mFlags &= ~CHANNELREAL_FLAG_STOPPED;
|
||||
|
||||
realchannel[0] = mChannel[index];
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
Undo the allocations that occured before just in case they are not used.
|
||||
*/
|
||||
for (count = 0; count < found; count++)
|
||||
{
|
||||
if (realchannel[count])
|
||||
{
|
||||
realchannel[count]->mFlags &= ~CHANNELREAL_FLAG_ALLOCATED;
|
||||
realchannel[count]->mFlags &= ~CHANNELREAL_FLAG_IN_USE;
|
||||
realchannel[count]->mFlags |= CHANNELREAL_FLAG_STOPPED;
|
||||
}
|
||||
}
|
||||
|
||||
if (found_out)
|
||||
{
|
||||
*found_out = found;
|
||||
}
|
||||
|
||||
return FMOD_ERR_CHANNEL_ALLOC;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT ChannelPool::getNumChannels(int *numchannels)
|
||||
{
|
||||
if (!numchannels)
|
||||
{
|
||||
return FMOD_ERR_INVALID_PARAM;
|
||||
}
|
||||
|
||||
*numchannels = mNumChannels;
|
||||
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT ChannelPool::getChannelsUsed(int *numchannels)
|
||||
{
|
||||
if (!numchannels)
|
||||
{
|
||||
return FMOD_ERR_INVALID_PARAM;
|
||||
}
|
||||
|
||||
*numchannels = mChannelsUsed;
|
||||
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT ChannelPool::setChannel(int index, ChannelReal *channel, DSPI *dspmixtarget)
|
||||
{
|
||||
if (!channel || index < 0 || index >= mNumChannels)
|
||||
{
|
||||
return FMOD_ERR_INVALID_PARAM;
|
||||
}
|
||||
|
||||
mChannel[index] = channel;
|
||||
mChannel[index]->mPool = this;
|
||||
|
||||
return mChannel[index]->init(index, mSystem, mOutput, dspmixtarget);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT ChannelPool::getChannel(int index, ChannelReal **channel)
|
||||
{
|
||||
if (!channel || index < 0 || index >= mNumChannels)
|
||||
{
|
||||
return FMOD_ERR_INVALID_PARAM;
|
||||
}
|
||||
|
||||
*channel = mChannel[index];
|
||||
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
FMOD_OK
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
|
||||
#ifdef FMOD_SUPPORT_MEMORYTRACKER
|
||||
|
||||
FMOD_RESULT ChannelPool::getMemoryUsedImpl(MemoryTracker *tracker)
|
||||
{
|
||||
tracker->add(false, FMOD_MEMBITS_CHANNEL, sizeof(*this));
|
||||
|
||||
if (mChannel)
|
||||
{
|
||||
tracker->add(false, FMOD_MEMBITS_CHANNEL, mNumChannels * sizeof(ChannelReal *));
|
||||
}
|
||||
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
49
src/fmod_channelpool.h
Executable file
49
src/fmod_channelpool.h
Executable file
|
|
@ -0,0 +1,49 @@
|
|||
#ifndef _FMOD_CHANNELPOOL_H
|
||||
#define _FMOD_CHANNELPOOL_H
|
||||
|
||||
#include "fmod_settings.h"
|
||||
#include "fmod.h"
|
||||
|
||||
#ifndef _FMOD_MEMORYTRACKER_H
|
||||
#include "fmod_memorytracker.h"
|
||||
#endif
|
||||
|
||||
namespace FMOD
|
||||
{
|
||||
class ChannelReal;
|
||||
class DSPI;
|
||||
class Output;
|
||||
class Sound;
|
||||
class SystemI;
|
||||
|
||||
class ChannelPool
|
||||
{
|
||||
DECLARE_MEMORYTRACKER_NONVIRTUAL
|
||||
|
||||
friend class ChannelReal;
|
||||
|
||||
protected:
|
||||
|
||||
int mNumChannels;
|
||||
int mChannelsUsed;
|
||||
SystemI *mSystem;
|
||||
Output *mOutput;
|
||||
|
||||
public:
|
||||
|
||||
ChannelReal **mChannel;
|
||||
|
||||
ChannelPool();
|
||||
|
||||
FMOD_RESULT init(SystemI *system, Output *output, int numchannels);
|
||||
FMOD_RESULT release();
|
||||
FMOD_RESULT find(int id, Sound *sound, ChannelReal **channel, int excludeid, bool stopstreamable);
|
||||
FMOD_RESULT allocateChannel(ChannelReal **realchannel, int index, int numchannels, int *found, bool ignorereserved = false);
|
||||
FMOD_RESULT getNumChannels(int *numchannels);
|
||||
FMOD_RESULT getChannelsUsed(int *numchannels);
|
||||
FMOD_RESULT setChannel(int index, ChannelReal *channel, DSPI *dspmixtarget = 0);
|
||||
FMOD_RESULT getChannel(int index, ChannelReal **channel);
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
249
src/fmod_cmdlog.cpp
Executable file
249
src/fmod_cmdlog.cpp
Executable file
|
|
@ -0,0 +1,249 @@
|
|||
#include "fmod_settings.h"
|
||||
|
||||
#ifdef FMOD_SUPPORT_CMDLOG
|
||||
|
||||
#define FMOD_CMDLOG_PLAYBACK
|
||||
|
||||
|
||||
#include "fmod_cmdlog.h"
|
||||
#include "fmod.hpp"
|
||||
#include "fmod_memory.h"
|
||||
#include "fmod_time.h"
|
||||
#include "fmod_systemi.h"
|
||||
#include "stdio.h"
|
||||
|
||||
|
||||
FMOD_RESULT FMOD_CmdLog_Flush();
|
||||
|
||||
const char *FMOD_CMDLOG_FILENAME = "cmdlog.bin";
|
||||
const int FMOD_CMDLOGSIZE = 1024 * 1024;
|
||||
|
||||
static char *gCmdLogBuf = 0;
|
||||
static char *gCmdLogPtr = 0;
|
||||
static FILE *readfp = 0;
|
||||
|
||||
|
||||
FMOD_RESULT FMOD_CmdLog_Init()
|
||||
{
|
||||
#ifndef FMOD_CMDLOG_PLAYBACK
|
||||
|
||||
gCmdLogBuf = (char *)FMOD_Memory_Calloc(FMOD_CMDLOGSIZE);
|
||||
if (!gCmdLogBuf)
|
||||
{
|
||||
return FMOD_ERR_MEMORY;
|
||||
}
|
||||
|
||||
FILE *fp = fopen(FMOD_CMDLOG_FILENAME, "wb");
|
||||
if (!fp)
|
||||
{
|
||||
return FMOD_ERR_FILE_BAD;
|
||||
}
|
||||
unsigned int version = FMOD_VERSION;
|
||||
fwrite(&version, 1, sizeof(version), fp);
|
||||
fclose(fp);
|
||||
|
||||
gCmdLogPtr = gCmdLogBuf;
|
||||
|
||||
#endif
|
||||
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
||||
|
||||
FMOD_RESULT FMOD_CmdLog_Release()
|
||||
{
|
||||
#ifndef FMOD_CMDLOG_PLAYBACK
|
||||
|
||||
FMOD_RESULT result = FMOD_CmdLog_Flush();
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
if (gCmdLogBuf)
|
||||
{
|
||||
FMOD_Memory_Free(gCmdLogBuf);
|
||||
gCmdLogBuf = 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
||||
|
||||
void FMOD_CmdLog_Push(void *data, int datalen)
|
||||
{
|
||||
#ifndef FMOD_CMDLOG_PLAYBACK
|
||||
|
||||
int i;
|
||||
char *d;
|
||||
/*AJS
|
||||
unsigned int t;
|
||||
|
||||
FMOD_OS_Time_GetMs(&t);
|
||||
d = (char *)(&t);
|
||||
for (i=0; i < sizeof(t); i++)
|
||||
{
|
||||
*gCmdLogPtr++ = *d++;
|
||||
|
||||
if ((gCmdLogPtr - gCmdLogBuf) >= FMOD_CMDLOGSIZE)
|
||||
{
|
||||
FMOD_CmdLog_Flush();
|
||||
}
|
||||
}
|
||||
AJS*/
|
||||
|
||||
d = (char *)data;
|
||||
for (i=0; i < datalen; i++)
|
||||
{
|
||||
*gCmdLogPtr++ = *d++;
|
||||
|
||||
if ((gCmdLogPtr - gCmdLogBuf) >= FMOD_CMDLOGSIZE)
|
||||
{
|
||||
FMOD_CmdLog_Flush();
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
FMOD_RESULT FMOD_CmdLog_Flush()
|
||||
{
|
||||
#ifndef FMOD_CMDLOG_PLAYBACK
|
||||
|
||||
FILE *fp = fopen(FMOD_CMDLOG_FILENAME, "ab");
|
||||
if (!fp)
|
||||
{
|
||||
FLOGC((FMOD::LOG_ERROR, __FILE__, __LINE__, "FMOD_CmdLog_Flush", "Error opening %s for writing\n", FMOD_CMDLOG_FILENAME));
|
||||
return FMOD_ERR_FILE_BAD;
|
||||
}
|
||||
|
||||
int b = gCmdLogPtr - gCmdLogBuf;
|
||||
|
||||
if (fwrite(gCmdLogBuf, 1, b, fp) != (unsigned int)b)
|
||||
{
|
||||
FLOGC((FMOD::LOG_ERROR, __FILE__, __LINE__, "FMOD_CmdLog_Flush", "Error writing %d bytes to %s\n", b, FMOD_CMDLOG_FILENAME));
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
|
||||
gCmdLogPtr = gCmdLogBuf;
|
||||
|
||||
#endif
|
||||
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
FMOD_RESULT FMOD_CmdLog_Begin()
|
||||
{
|
||||
if (readfp)
|
||||
{
|
||||
return FMOD_ERR_INITIALIZED;
|
||||
}
|
||||
|
||||
readfp = fopen(FMOD_CMDLOG_FILENAME, "rb");
|
||||
if (!readfp)
|
||||
{
|
||||
return FMOD_ERR_FILE_BAD;
|
||||
}
|
||||
|
||||
unsigned int version;
|
||||
if (fread(&version, 1, sizeof(version), readfp) != sizeof(version))
|
||||
{
|
||||
fclose(readfp);
|
||||
return FMOD_ERR_FILE_BAD;
|
||||
}
|
||||
|
||||
if (version != FMOD_VERSION)
|
||||
{
|
||||
//AJS complain?
|
||||
}
|
||||
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
||||
|
||||
FMOD_RESULT FMOD_CmdLog_Read(void *buf, int bytes)
|
||||
{
|
||||
if (!readfp)
|
||||
{
|
||||
return FMOD_ERR_UNINITIALIZED;
|
||||
}
|
||||
|
||||
if (buf)
|
||||
{
|
||||
int bytesread = fread(buf, 1, bytes, readfp);
|
||||
if (bytesread != bytes)
|
||||
{
|
||||
return FMOD_ERR_FILE_EOF;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (fseek(readfp, bytes, SEEK_CUR))
|
||||
{
|
||||
return FMOD_ERR_FILE_EOF;
|
||||
}
|
||||
}
|
||||
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
||||
|
||||
FMOD_RESULT FMOD_CmdLog_Execute()
|
||||
{
|
||||
int cmd;
|
||||
|
||||
FMOD_CmdLog_Read(&cmd, sizeof(int));
|
||||
|
||||
switch (cmd)
|
||||
{
|
||||
case FMOD_CMDLOG_SYSTEM_PLAYSOUND :
|
||||
{
|
||||
FMOD::SystemI *_cl_system;
|
||||
FMOD_CHANNELINDEX _cl_channelid;
|
||||
FMOD::SoundI *_cl_sound;
|
||||
bool _cl_paused;
|
||||
FMOD::Channel **_cl_channel;
|
||||
|
||||
FMOD_CmdLog_Read(&_cl_system, sizeof(FMOD::System *));
|
||||
FMOD_CmdLog_Read(&_cl_channelid, sizeof(FMOD_CHANNELINDEX));
|
||||
FMOD_CmdLog_Read(&_cl_sound, sizeof(FMOD::SoundI *));
|
||||
FMOD_CmdLog_Read(&_cl_paused, sizeof(bool));
|
||||
FMOD_CmdLog_Read(0, sizeof(FMOD::Channel **));
|
||||
|
||||
_cl_system = (FMOD::SystemI *)FMOD::gSystemHead->getNodeByIndex(0);
|
||||
|
||||
//AJS need to resolve sound and system somehow
|
||||
//AJS they're ptrs not handles - make them handles? just use indices?
|
||||
|
||||
FMOD_RESULT result = _cl_system->playSound(_cl_channelid, _cl_sound, _cl_paused, 0);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default :
|
||||
break;
|
||||
}
|
||||
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
||||
|
||||
FMOD_RESULT FMOD_CmdLog_End()
|
||||
{
|
||||
if (readfp)
|
||||
{
|
||||
fclose(readfp);
|
||||
readfp = 0;
|
||||
}
|
||||
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
29
src/fmod_cmdlog.h
Executable file
29
src/fmod_cmdlog.h
Executable file
|
|
@ -0,0 +1,29 @@
|
|||
#ifndef _FMOD_CMDLOG_H
|
||||
#define _FMOD_CMDLOG_H
|
||||
|
||||
#ifdef FMOD_SUPPORT_CMDLOG
|
||||
|
||||
|
||||
#ifndef _FMOD_H
|
||||
#include "fmod.h"
|
||||
#endif
|
||||
|
||||
|
||||
// don't change the order!
|
||||
enum
|
||||
{
|
||||
FMOD_CMDLOG_SYSTEM_PLAYSOUND = 0,
|
||||
};
|
||||
|
||||
|
||||
extern FMOD_RESULT FMOD_CmdLog_Init();
|
||||
extern FMOD_RESULT FMOD_CmdLog_Release();
|
||||
extern void FMOD_CmdLog_Push(void *data, int datalen);
|
||||
|
||||
extern FMOD_RESULT FMOD_CmdLog_Begin();
|
||||
extern FMOD_RESULT FMOD_CmdLog_Execute();
|
||||
extern FMOD_RESULT FMOD_CmdLog_End();
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
865
src/fmod_codec.cpp
Executable file
865
src/fmod_codec.cpp
Executable file
|
|
@ -0,0 +1,865 @@
|
|||
#include "fmod_settings.h"
|
||||
|
||||
#include "fmod_codeci.h"
|
||||
#include "fmod_file.h"
|
||||
#include "fmod_metadata.h"
|
||||
#include "fmod_soundi.h"
|
||||
#include "fmod_file_disk.h"
|
||||
namespace FMOD
|
||||
{
|
||||
|
||||
#ifndef PLATFORM_PS3_SPU
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT Codec::release()
|
||||
{
|
||||
FMOD_RESULT result;
|
||||
|
||||
FLOG((FMOD_DEBUG_LEVEL_LOG, __FILE__, __LINE__, "Codec::release", "\n"));
|
||||
|
||||
if (mDescription.close)
|
||||
{
|
||||
mDescription.close(this);
|
||||
}
|
||||
|
||||
if (mFile)
|
||||
{
|
||||
FLOG((FMOD_DEBUG_LEVEL_LOG, __FILE__, __LINE__, "Codec::release", "Close file (mFile = %p)\n", mFile));
|
||||
|
||||
mFile->close();
|
||||
|
||||
FMOD_Memory_Free(mFile);
|
||||
mFile = 0;
|
||||
}
|
||||
|
||||
if (mWaveFormatMemory && mType == FMOD_SOUND_TYPE_FSB)
|
||||
{
|
||||
FMOD_Memory_Free(mWaveFormatMemory);
|
||||
mWaveFormatMemory = 0;
|
||||
}
|
||||
|
||||
if (mMetadata)
|
||||
{
|
||||
mMetadata->release();
|
||||
mMetadata = 0;
|
||||
}
|
||||
|
||||
result = Plugin::release();
|
||||
|
||||
FLOG((FMOD_DEBUG_LEVEL_LOG, __FILE__, __LINE__, "Codec::release", "done\n"));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif // !PLATFORM_PS3_SPU
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
This is just a helper function for codecs if mPCMBuffer and mPCMBufferLengthBytes have been allocated inside the codec code.
|
||||
It simply calls the decode in a loop, feeding the output buffer from a smaller pcm decode buffer (mPCMBuffer).
|
||||
Codecs that want to skip offline buffering and write directly to the output pointer (ie raw 1:1 pcm that just does an fread for example)
|
||||
should not allocate those variables.
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT Codec::read(void *buffer, unsigned int sizebytes, unsigned int *bytesread)
|
||||
{
|
||||
FMOD_RESULT result = FMOD_OK;
|
||||
bool checkmetadata = false;
|
||||
unsigned int read = 0;
|
||||
|
||||
if (mPCMBuffer && mPCMBufferLengthBytes)
|
||||
{
|
||||
while (sizebytes)
|
||||
{
|
||||
unsigned int lenbytes = sizebytes;
|
||||
unsigned int bytesdecoded = 0;
|
||||
|
||||
if (!mPCMBufferOffsetBytes)
|
||||
{
|
||||
result = mDescription.read(this, mPCMBuffer, mPCMBufferLengthBytes, &bytesdecoded);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
mPCMBufferFilledBytes = bytesdecoded;
|
||||
|
||||
lenbytes = bytesdecoded;
|
||||
if (lenbytes > sizebytes)
|
||||
{
|
||||
lenbytes = sizebytes;
|
||||
}
|
||||
|
||||
checkmetadata = true;
|
||||
}
|
||||
|
||||
if (mPCMBufferOffsetBytes + lenbytes > mPCMBufferFilledBytes)
|
||||
{
|
||||
lenbytes = mPCMBufferFilledBytes - mPCMBufferOffsetBytes;
|
||||
}
|
||||
|
||||
FMOD_memcpy((char *)buffer + read, mPCMBuffer + mPCMBufferOffsetBytes, lenbytes);
|
||||
|
||||
|
||||
mPCMBufferOffsetBytes += lenbytes;
|
||||
if (mPCMBufferOffsetBytes >= mPCMBufferFilledBytes)
|
||||
{
|
||||
mPCMBufferOffsetBytes = 0;
|
||||
}
|
||||
|
||||
if (!lenbytes)
|
||||
{
|
||||
lenbytes = sizebytes;
|
||||
break;
|
||||
}
|
||||
|
||||
sizebytes -= lenbytes;
|
||||
read += lenbytes;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
result = mDescription.read(this, buffer, sizebytes, &read);
|
||||
if (result == FMOD_OK)
|
||||
{
|
||||
checkmetadata = true;
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef PLATFORM_PS3_SPU
|
||||
if (checkmetadata)
|
||||
{
|
||||
getMetadataFromFile();
|
||||
}
|
||||
#endif
|
||||
|
||||
if (bytesread)
|
||||
{
|
||||
*bytesread = read;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
#ifndef PLATFORM_PS3_SPU
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT Codec::getMetadataFromFile()
|
||||
{
|
||||
FMOD_RESULT result = FMOD_OK;
|
||||
Metadata *filemetadata;
|
||||
|
||||
if (mFile)
|
||||
{
|
||||
result = mFile->getMetadata(&filemetadata);
|
||||
if (result == FMOD_OK)
|
||||
{
|
||||
if (!mMetadata)
|
||||
{
|
||||
mMetadata = FMOD_Object_Alloc(Metadata);
|
||||
if (!mMetadata)
|
||||
{
|
||||
return FMOD_ERR_MEMORY;
|
||||
}
|
||||
}
|
||||
|
||||
result = mMetadata->add(filemetadata);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT Codec::getLength(unsigned int *length, FMOD_TIMEUNIT lengthtype)
|
||||
{
|
||||
FMOD_RESULT result;
|
||||
|
||||
if (lengthtype == FMOD_TIMEUNIT_RAWBYTES)
|
||||
{
|
||||
FMOD_CODEC_WAVEFORMAT waveformat;
|
||||
|
||||
result = mDescription.getwaveformat(this, mSubSoundIndex, &waveformat);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
*length = waveformat.lengthbytes;
|
||||
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
||||
if (!mDescription.getlength)
|
||||
{
|
||||
*length = 0;
|
||||
return FMOD_ERR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
result = mDescription.getlength(this, length, lengthtype);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
||||
#endif // !PLATFORM_PS3_SPU
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT Codec::setPosition(int subsound, unsigned int position, FMOD_TIMEUNIT postype)
|
||||
{
|
||||
FMOD_RESULT result;
|
||||
FMOD_CODEC_WAVEFORMAT waveformat;
|
||||
|
||||
if (numsubsounds && subsound >= numsubsounds)
|
||||
{
|
||||
return FMOD_ERR_INVALID_POSITION;
|
||||
}
|
||||
|
||||
if (!mDescription.setposition)
|
||||
{
|
||||
return FMOD_ERR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
if (subsound < 0)
|
||||
{
|
||||
subsound = mSubSoundIndex;
|
||||
}
|
||||
|
||||
if (!numsubsounds)
|
||||
{
|
||||
subsound = 0;
|
||||
}
|
||||
|
||||
|
||||
result = mDescription.getwaveformat(this, subsound, &waveformat);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
If the incoming timeformat is not a codec friendly format, convert it to the
|
||||
codec's favourite time format. (for convertable formats like ms/pcm/bytes)
|
||||
*/
|
||||
if (mDescription.timeunits & FMOD_TIMEUNIT_PCM)
|
||||
{
|
||||
if (postype & FMOD_TIMEUNIT_PCMBYTES)
|
||||
{
|
||||
SoundI::getSamplesFromBytes(position, &position, waveformat.channels, waveformat.format);
|
||||
postype = FMOD_TIMEUNIT_PCM;
|
||||
}
|
||||
else if (postype & FMOD_TIMEUNIT_MS)
|
||||
{
|
||||
position = (unsigned int)((float)position / 1000.0f * waveformat.frequency);
|
||||
postype = FMOD_TIMEUNIT_PCM;
|
||||
}
|
||||
}
|
||||
else if (mDescription.timeunits & FMOD_TIMEUNIT_PCMBYTES)
|
||||
{
|
||||
if (postype & FMOD_TIMEUNIT_PCM)
|
||||
{
|
||||
SoundI::getBytesFromSamples(position, &position, waveformat.channels, waveformat.format);
|
||||
postype = FMOD_TIMEUNIT_PCMBYTES;
|
||||
}
|
||||
else if (postype & FMOD_TIMEUNIT_MS)
|
||||
{
|
||||
position = (unsigned int)((float)position / 1000.0f * waveformat.frequency);
|
||||
SoundI::getBytesFromSamples(position, &position, waveformat.channels, waveformat.format);
|
||||
postype = FMOD_TIMEUNIT_PCMBYTES;
|
||||
}
|
||||
}
|
||||
else if (mDescription.timeunits & FMOD_TIMEUNIT_MS)
|
||||
{
|
||||
if (postype & FMOD_TIMEUNIT_PCM)
|
||||
{
|
||||
position = (unsigned int)((float)position / waveformat.frequency * 1000.0f);
|
||||
postype = FMOD_TIMEUNIT_MS;
|
||||
}
|
||||
else if (postype & FMOD_TIMEUNIT_PCMBYTES)
|
||||
{
|
||||
SoundI::getSamplesFromBytes(position, &position, waveformat.channels, waveformat.format);
|
||||
position = (unsigned int)((float)position / waveformat.frequency * 1000.0f);
|
||||
postype = FMOD_TIMEUNIT_MS;
|
||||
}
|
||||
}
|
||||
|
||||
if (!(postype & mDescription.timeunits))
|
||||
{
|
||||
return FMOD_ERR_FORMAT;
|
||||
}
|
||||
|
||||
mPCMBufferOffsetBytes = 0;
|
||||
|
||||
result = mDescription.setposition(this, subsound, position, postype);
|
||||
if (result != FMOD_OK && result != FMOD_ERR_FILE_EOF)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
mSubSoundIndex = subsound;
|
||||
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
||||
|
||||
#ifndef PLATFORM_PS3_SPU
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT Codec::getPosition(unsigned int *position, FMOD_TIMEUNIT postype)
|
||||
{
|
||||
FMOD_RESULT result;
|
||||
|
||||
if (postype == FMOD_TIMEUNIT_RAWBYTES)
|
||||
{
|
||||
if (!mFile)
|
||||
{
|
||||
*position = 0;
|
||||
}
|
||||
|
||||
result = mFile->tell(position);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
*position = 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
*position -= mSrcDataOffset;
|
||||
}
|
||||
|
||||
if (!mDescription.getposition)
|
||||
{
|
||||
return FMOD_ERR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
if (!(postype & mDescription.timeunits))
|
||||
{
|
||||
return FMOD_ERR_FORMAT;
|
||||
}
|
||||
|
||||
result = mDescription.getposition(this, position, postype);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
|
||||
[SEE_ALSO]
|
||||
FMOD_TAGDATATYPE
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT Codec::metaData(FMOD_TAGTYPE type, const char *name, void *data, unsigned int datalen, FMOD_TAGDATATYPE datatype, bool unique)
|
||||
{
|
||||
if (!mMetadata)
|
||||
{
|
||||
mMetadata = FMOD_Object_Alloc(Metadata);
|
||||
if (!mMetadata)
|
||||
{
|
||||
return FMOD_ERR_MEMORY;
|
||||
}
|
||||
}
|
||||
|
||||
return mMetadata->addTag(type, name, data, datalen, datatype, unique);
|
||||
}
|
||||
|
||||
#endif // !PLATFORM_PS3_SPU
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
|
||||
#if defined(FMOD_SUPPORT_MEMORYTRACKER) && !defined(PLATFORM_PS3_SPU)
|
||||
|
||||
FMOD_RESULT Codec::getMemoryUsedImpl(MemoryTracker *tracker)
|
||||
{
|
||||
tracker->add(false, FMOD_MEMBITS_CODEC, mDescription.mSize);
|
||||
|
||||
if (mFile)
|
||||
{
|
||||
CHECK_RESULT(((FMOD::DiskFile *)mFile)->getMemoryUsed(tracker));
|
||||
}
|
||||
|
||||
if (mDescription.getmemoryused)
|
||||
{
|
||||
CHECK_RESULT(mDescription.getmemoryused(this, tracker));
|
||||
}
|
||||
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
[API]
|
||||
[
|
||||
[DESCRIPTION]
|
||||
Open callback for the codec for when FMOD tries to open a sound using this codec.
|
||||
This is the callback the file format check is done in, codec related memory is allocated, and things are generally initialized / set up for the codec.
|
||||
|
||||
[PARAMETERS]
|
||||
'codec_state' Pointer to the codec state. The user can use this variable to access runtime plugin specific variables and plugin writer user data.
|
||||
'usermode' Mode that the user supplied via System::createSound. This is informational and can be ignored, or used if it has relevance to your codec.
|
||||
'userexinfo' Extra info structure that the user supplied via System::createSound. This is informational and can be ignored, or used if it has relevance to your codec.
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
The usermode and userexinfo parameters tell the codec what was passed in by the user.<br>
|
||||
Generally these can be ignored, as the file format usually determines the format and frequency of the sound.<br>
|
||||
<br>
|
||||
If you have a flexible format codec (ie you don't mind what output format your codec writes to), you might want to use the parameter that was passed in by the user to specify the output sound format / frequency.<br>
|
||||
For example if you normally create a codec that is always 32bit floating point, the user might supply 16bit integer to save memory, so you could use this information to decode your data to this format instead of the original default format.
|
||||
<br>
|
||||
Read and seek within the file using the 'fileread' and 'fileseek' members of the FMOD_CODEC codec that is passed in.<br>
|
||||
Note: <b>DO NOT USE YOUR OWN FILESYSTEM.</b><br>
|
||||
The reasons for this are:<br>
|
||||
<li>The user may have set their own file system via user filesystem callbacks.<br>
|
||||
<li>FMOD allows file reading via disk, memory and TCP/IP. If you use your own file routines you will lose this ability.<br>
|
||||
<br>
|
||||
<b>Important!</b> FMOD will ping all codecs trying to find the right one for the file the user has passed in. Make sure the first line of your codec open is a FAST format check. Ie it reads an identifying string, checks it and returns an error FMOD_ERR_FORMAT if it is not found.<br>
|
||||
There may be a lot of codecs loaded into FMOD, so you don't want yours slowing down the System::createSound call because it is inneficient in determining if it is the right format or not.<br>
|
||||
<br>
|
||||
Remember to return FMOD_OK at the bottom of the function, or an appropriate error code from FMOD_RESULT.<br>
|
||||
|
||||
[PLATFORMS]
|
||||
Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation 2, PlayStation Portable, PlayStation 3, Wii, Solaris, iPhone
|
||||
|
||||
[SEE_ALSO]
|
||||
System::createSound
|
||||
FMOD_CREATESOUNDEXINFO
|
||||
FMOD_CODEC_STATE
|
||||
FMOD_CODEC_DESCRIPTION
|
||||
FMOD_CODEC_CLOSECALLBACK
|
||||
FMOD_CODEC_READCALLBACK
|
||||
FMOD_CODEC_GETLENGTHCALLBACK
|
||||
FMOD_CODEC_SETPOSITIONCALLBACK
|
||||
FMOD_CODEC_GETPOSITIONCALLBACK
|
||||
FMOD_CODEC_SOUNDCREATECALLBACK
|
||||
]
|
||||
*/
|
||||
/*
|
||||
FMOD_RESULT F_CALLBACK FMOD_CODEC_OPENCALLBACK(FMOD_CODEC_STATE *codec_state, FMOD_MODE usermode, FMOD_CREATESOUNDEXINFO *userexinfo)
|
||||
{
|
||||
#if 0
|
||||
// here purely for documentation purposes.
|
||||
#endif
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
[API]
|
||||
[
|
||||
[DESCRIPTION]
|
||||
Close callback for the codec for when FMOD tries to close a sound using this codec.<br>
|
||||
This is the callback any codec related memory is freed, and things are generally de-initialized / shut down for the codec.
|
||||
|
||||
[PARAMETERS]
|
||||
'codec_state' Pointer to the codec state. The user can use this variable to access runtime plugin specific variables and plugin writer user data.
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
Remember to return FMOD_OK at the bottom of the function, or an appropriate error code from FMOD_RESULT.<br>
|
||||
|
||||
[PLATFORMS]
|
||||
Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation 2, PlayStation Portable, PlayStation 3, Wii, Solaris, iPhone
|
||||
|
||||
[SEE_ALSO]
|
||||
FMOD_CODEC_STATE
|
||||
FMOD_CODEC_DESCRIPTION
|
||||
FMOD_CODEC_OPENCALLBACK
|
||||
FMOD_CODEC_READCALLBACK
|
||||
FMOD_CODEC_GETLENGTHCALLBACK
|
||||
FMOD_CODEC_SETPOSITIONCALLBACK
|
||||
FMOD_CODEC_GETPOSITIONCALLBACK
|
||||
FMOD_CODEC_SOUNDCREATECALLBACK
|
||||
]
|
||||
*/
|
||||
/*
|
||||
FMOD_RESULT F_CALLBACK FMOD_CODEC_CLOSECALLBACK(FMOD_CODEC_STATE *codec_state)
|
||||
{
|
||||
#if 0
|
||||
// here purely for documentation purposes.
|
||||
#endif
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
[API]
|
||||
[
|
||||
[DESCRIPTION]
|
||||
Read callback for the codec for when FMOD tries to read some data from the file to the destination format (format specified in the open callback).
|
||||
|
||||
[PARAMETERS]
|
||||
'codec_state' Pointer to the codec state. The user can use this variable to access runtime plugin specific variables and plugin writer user data.
|
||||
'buffer' Buffer to read PCM data to. Note that the format of this data is the format described in FMOD_CODEC_WAVEFORMAT.
|
||||
'sizebytes' Number of bytes to read
|
||||
'bytesread' Number of bytes actually read
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
If you cannot read number of bytes requested, simply return FMOD_OK and give bytesread the number of bytes you read.
|
||||
<br>
|
||||
Read and seek within the file using the 'fileread' and 'fileseek' members of the FMOD_CODEC codec that is passed in.<br>
|
||||
Note: <b>DO NOT USE YOUR OWN FILESYSTEM.</b><br>
|
||||
The reasons for this are:<br>
|
||||
<li>The user may have set their own file system via user filesystem callbacks.<br>
|
||||
<li>FMOD allows file reading via disk, memory and TCP/IP. If you use your own file routines you will lose this ability.<br>
|
||||
<br>
|
||||
Remember to return FMOD_OK at the bottom of the function, or an appropriate error code from FMOD_RESULT.<br>
|
||||
|
||||
[PLATFORMS]
|
||||
Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation 2, PlayStation Portable, PlayStation 3, Wii, Solaris, iPhone
|
||||
|
||||
[SEE_ALSO]
|
||||
FMOD_CODEC_STATE
|
||||
FMOD_CODEC_DESCRIPTION
|
||||
FMOD_CODEC_OPENCALLBACK
|
||||
FMOD_CODEC_CLOSECALLBACK
|
||||
FMOD_CODEC_GETLENGTHCALLBACK
|
||||
FMOD_CODEC_SETPOSITIONCALLBACK
|
||||
FMOD_CODEC_GETPOSITIONCALLBACK
|
||||
FMOD_CODEC_SOUNDCREATECALLBACK
|
||||
]
|
||||
*/
|
||||
/*
|
||||
FMOD_RESULT F_CALLBACK FMOD_CODEC_READCALLBACK(FMOD_CODEC_STATE *codec_state, void *buffer, unsigned int sizebytes, unsigned int *bytesread)
|
||||
{
|
||||
#if 0
|
||||
// here purely for documentation purposes.
|
||||
#endif
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
[API]
|
||||
[
|
||||
[DESCRIPTION]
|
||||
Callback to return the length of the song in whatever format required when Sound::getLength is called.
|
||||
|
||||
[PARAMETERS]
|
||||
'codec_state' Pointer to the codec state. The user can use this variable to access runtime plugin specific variables and plugin writer user data.
|
||||
'length' Address of a variable that is to receive the length of the sound determined by the format specified in the lengttype parameter.
|
||||
'lengthtype' Timeunit type of length to return. This will be one of the timeunits supplied by the codec author in the FMOD_CODEC_DESCRIPTION structure.
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
Remember to return FMOD_OK at the bottom of the function, or an appropriate error code from FMOD_RESULT.<br>
|
||||
|
||||
[PLATFORMS]
|
||||
Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation 2, PlayStation Portable, PlayStation 3, Wii, Solaris, iPhone
|
||||
|
||||
[SEE_ALSO]
|
||||
FMOD_TIMEUNIT
|
||||
FMOD_CODEC_STATE
|
||||
FMOD_CODEC_DESCRIPTION
|
||||
FMOD_CODEC_OPENCALLBACK
|
||||
FMOD_CODEC_CLOSECALLBACK
|
||||
FMOD_CODEC_READCALLBACK
|
||||
FMOD_CODEC_SETPOSITIONCALLBACK
|
||||
FMOD_CODEC_GETPOSITIONCALLBACK
|
||||
FMOD_CODEC_SOUNDCREATECALLBACK
|
||||
]
|
||||
*/
|
||||
/*
|
||||
FMOD_RESULT F_CALLBACK FMOD_CODEC_GETLENGTHCALLBACK(FMOD_CODEC_STATE *codec_state, unsigned int *length, FMOD_TIMEUNIT lengthtype)
|
||||
{
|
||||
#if 0
|
||||
// here purely for documentation purposes.
|
||||
#endif
|
||||
}
|
||||
*/
|
||||
/*
|
||||
[API]
|
||||
[
|
||||
[DESCRIPTION]
|
||||
Seek callback for the codec for when FMOD tries to seek within the file with Channel::setPosition.
|
||||
|
||||
[PARAMETERS]
|
||||
'codec_state' Pointer to the codec state. The user can use this variable to access runtime plugin specific variables and plugin writer user data.
|
||||
'subsound' Subsound within which to seek.
|
||||
'position' Position to seek to in the sound based on the timeunit specified in the postype parameter.
|
||||
'postype' Timeunit type of the position parameter. This will be one of the timeunits supplied by the codec author in the FMOD_CODEC_DESCRIPTION structure.
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
Read and seek within the file using the 'fileread' and 'fileseek' members of the FMOD_CODEC codec that is passed in.<br>
|
||||
Note: <b>DO NOT USE YOUR OWN FILESYSTEM.</b><br>
|
||||
The reasons for this are:<br>
|
||||
<li>The user may have set their own file system via user filesystem callbacks.<br>
|
||||
<li>FMOD allows file reading via disk, memory and TCP/IP. If you use your own file routines you will lose this ability.<br>
|
||||
<br>
|
||||
Remember to return FMOD_OK at the bottom of the function, or an appropriate error code from FMOD_RESULT.<br>
|
||||
|
||||
[PLATFORMS]
|
||||
Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation 2, PlayStation Portable, PlayStation 3, Wii, Solaris, iPhone
|
||||
|
||||
[SEE_ALSO]
|
||||
Channel::setPosition
|
||||
FMOD_CODEC_STATE
|
||||
FMOD_CODEC_DESCRIPTION
|
||||
FMOD_CODEC_OPENCALLBACK
|
||||
FMOD_CODEC_CLOSECALLBACK
|
||||
FMOD_CODEC_READCALLBACK
|
||||
FMOD_CODEC_GETLENGTHCALLBACK
|
||||
FMOD_CODEC_GETPOSITIONCALLBACK
|
||||
FMOD_CODEC_SOUNDCREATECALLBACK
|
||||
]
|
||||
*/
|
||||
/*
|
||||
FMOD_RESULT F_CALLBACK FMOD_CODEC_SETPOSITIONCALLBACK(FMOD_CODEC_STATE *codec_state, int subsound, unsigned int position, FMOD_TIMEUNIT postype)
|
||||
{
|
||||
#if 0
|
||||
// here purely for documentation purposes.
|
||||
#endif
|
||||
}
|
||||
*/
|
||||
/*
|
||||
[API]
|
||||
[
|
||||
[DESCRIPTION]
|
||||
Tell callback for the codec for when FMOD tries to get the current position within the with Channel::getPosition.
|
||||
|
||||
[PARAMETERS]
|
||||
'codec_state' Pointer to the codec state. The user can use this variable to access runtime plugin specific variables and plugin writer user data.
|
||||
'position' Address of a variable to receive the current position in the codec based on the timeunit specified in the postype parameter.
|
||||
'postype' Timeunit type of the position parameter that is requested. This will be one of the timeunits supplied by the codec author in the FMOD_CODEC_DESCRIPTION structure.
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
Remember to return FMOD_OK at the bottom of the function, or an appropriate error code from FMOD_RESULT.<br>
|
||||
|
||||
[PLATFORMS]
|
||||
Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation 2, PlayStation Portable, PlayStation 3, Wii, Solaris, iPhone
|
||||
|
||||
[SEE_ALSO]
|
||||
Channel::getPosition
|
||||
FMOD_CODEC_STATE
|
||||
FMOD_CODEC_DESCRIPTION
|
||||
FMOD_CODEC_OPENCALLBACK
|
||||
FMOD_CODEC_CLOSECALLBACK
|
||||
FMOD_CODEC_READCALLBACK
|
||||
FMOD_CODEC_GETLENGTHCALLBACK
|
||||
FMOD_CODEC_SETPOSITIONCALLBACK
|
||||
FMOD_CODEC_SOUNDCREATECALLBACK
|
||||
]
|
||||
*/
|
||||
/*
|
||||
FMOD_RESULT F_CALLBACK FMOD_CODEC_GETPOSITIONCALLBACK(FMOD_CODEC_STATE *codec_state, unsigned int *position, FMOD_TIMEUNIT postype)
|
||||
{
|
||||
#if 0
|
||||
// here purely for documentation purposes.
|
||||
#endif
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
[API]
|
||||
[
|
||||
[DESCRIPTION]
|
||||
Sound creation callback for the codec when FMOD finishes creating the sound. Ie so the codec can set more parameters for the related created sound, ie loop points/mode or 3D attributes etc.
|
||||
|
||||
[PARAMETERS]
|
||||
'codec_state' Pointer to the codec state. The user can use this variable to access runtime plugin specific variables and plugin writer user data.
|
||||
'subsound' Subsound index being created.
|
||||
'sound' Pointer to the sound being created.
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
Remember to return FMOD_OK at the bottom of the function, or an appropriate error code from FMOD_RESULT.<br>
|
||||
|
||||
[PLATFORMS]
|
||||
Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation 2, PlayStation Portable, PlayStation 3, Wii, Solaris, iPhone
|
||||
|
||||
[SEE_ALSO]
|
||||
System::createSound
|
||||
System::createStream
|
||||
FMOD_CODEC_STATE
|
||||
FMOD_CODEC_DESCRIPTION
|
||||
FMOD_CODEC_OPENCALLBACK
|
||||
FMOD_CODEC_CLOSECALLBACK
|
||||
FMOD_CODEC_READCALLBACK
|
||||
FMOD_CODEC_GETLENGTHCALLBACK
|
||||
FMOD_CODEC_SETPOSITIONCALLBACK
|
||||
FMOD_CODEC_GETPOSITIONCALLBACK
|
||||
]
|
||||
*/
|
||||
/*
|
||||
FMOD_RESULT F_CALLBACK FMOD_CODEC_SOUNDCREATECALLBACK(FMOD_CODEC_STATE *codec_state, int subsound, FMOD_SOUND *sound)
|
||||
{
|
||||
#if 0
|
||||
// here purely for documentation purposes.
|
||||
#endif
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
[API]
|
||||
[
|
||||
[DESCRIPTION]
|
||||
Callback for sounds that have their
|
||||
|
||||
[PARAMETERS]
|
||||
'codec_state' Pointer to the codec state. The user can use this variable to access runtime plugin specific variables and plugin writer user data.
|
||||
'type' Source of tag being updated, ie id3v2 or oggvorbis tag for example. See FMOD_TAGDATATYPE.
|
||||
'name' Name of the tag being updated.
|
||||
'data' Contents of tag.
|
||||
'datalen' Length of the tag data in bytes.
|
||||
'datatype' Data type of tag. Binary / string / unicode etc. See FMOD_TAGDATATYPE.
|
||||
'unique' If this is true, then the tag (determined by the name) being updated is the only one of its type. If it is false then there are multiple versions of this tag with the same name.
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
This callback is usually called from sounds that can udate their metadata / tag info at runtime. Such a sound could be an internet SHOUTcast / Icecast stream for example.<br>
|
||||
<br>
|
||||
Remember to return FMOD_OK at the bottom of the function, or an appropriate error code from FMOD_RESULT.<br>
|
||||
|
||||
[PLATFORMS]
|
||||
Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation 2, PlayStation Portable, PlayStation 3, Wii, Solaris, iPhone
|
||||
|
||||
[SEE_ALSO]
|
||||
FMOD_CODEC_STATE
|
||||
FMOD_CODEC_DESCRIPTION
|
||||
FMOD_CODEC_OPENCALLBACK
|
||||
FMOD_CODEC_CLOSECALLBACK
|
||||
FMOD_CODEC_READCALLBACK
|
||||
FMOD_CODEC_GETLENGTHCALLBACK
|
||||
FMOD_CODEC_SETPOSITIONCALLBACK
|
||||
FMOD_CODEC_GETPOSITIONCALLBACK
|
||||
FMOD_CODEC_SOUNDCREATECALLBACK
|
||||
FMOD_TAGDATATYPE
|
||||
]
|
||||
*/
|
||||
/*
|
||||
FMOD_RESULT F_CALLBACK FMOD_CODEC_METADATACALLBACK(FMOD_CODEC_STATE *codec_state, FMOD_TAGTYPE type, char *name, void *data, unsigned int datalen, FMOD_TAGDATATYPE datatype, int unique)
|
||||
{
|
||||
#if 0
|
||||
// here purely for documentation purposes.
|
||||
#endif
|
||||
}
|
||||
*/
|
||||
|
||||
}
|
||||
|
||||
|
||||
815
src/fmod_codec_aiff.cpp
Executable file
815
src/fmod_codec_aiff.cpp
Executable file
|
|
@ -0,0 +1,815 @@
|
|||
#include "fmod_settings.h"
|
||||
|
||||
#ifdef FMOD_SUPPORT_AIFF
|
||||
|
||||
#include "fmod.h"
|
||||
#include "fmod_codec_aiff.h"
|
||||
#include "fmod_debug.h"
|
||||
#include "fmod_file.h"
|
||||
#include "fmod_soundi.h"
|
||||
#include "fmod_string.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
namespace FMOD
|
||||
{
|
||||
|
||||
|
||||
FMOD_CODEC_DESCRIPTION_EX aiffcodec;
|
||||
|
||||
#ifdef PLUGIN_EXPORTS
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
FMODGetCodecDescriptionEx is mandantory for every fmod plugin. This is the symbol the registerplugin function searches for.
|
||||
Must be declared with F_API to make it export as stdcall.
|
||||
*/
|
||||
F_DECLSPEC F_DLLEXPORT FMOD_CODEC_DESCRIPTION_EX * F_API FMODGetCodecDescriptionEx()
|
||||
{
|
||||
return CodecAIFF::getDescriptionEx();
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* PLUGIN_EXPORTS */
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_CODEC_DESCRIPTION_EX *CodecAIFF::getDescriptionEx()
|
||||
{
|
||||
FMOD_memset(&aiffcodec, 0, sizeof(FMOD_CODEC_DESCRIPTION_EX));
|
||||
|
||||
aiffcodec.name = "FMOD AIFF Codec";
|
||||
aiffcodec.version = 0x00010100;
|
||||
aiffcodec.timeunits = FMOD_TIMEUNIT_PCM;
|
||||
aiffcodec.open = &CodecAIFF::openCallback;
|
||||
aiffcodec.close = &CodecAIFF::closeCallback;
|
||||
aiffcodec.read = &CodecAIFF::readCallback;
|
||||
aiffcodec.setposition = &CodecAIFF::setPositionCallback;
|
||||
|
||||
aiffcodec.mType = FMOD_SOUND_TYPE_AIFF;
|
||||
aiffcodec.mSize = sizeof(CodecAIFF);
|
||||
|
||||
return &aiffcodec;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#define UnsignedToFloat(u) (((float)((int)(u - 2147483647L - 1))) + 2147483648.0f)
|
||||
|
||||
/****************************************************************
|
||||
* Extended precision IEEE floating-point conversion routine.
|
||||
****************************************************************/
|
||||
float ConvertFromIeeeExtended(unsigned char *bytes)
|
||||
{
|
||||
float f;
|
||||
int expon;
|
||||
unsigned int hiMant, loMant;
|
||||
|
||||
expon = ((bytes[0] & 0x7F) << 8) | (bytes[1] & 0xFF);
|
||||
hiMant = ((unsigned int)(bytes[2] & 0xFF) << 24)
|
||||
| ((unsigned int)(bytes[3] & 0xFF) << 16)
|
||||
| ((unsigned int)(bytes[4] & 0xFF) << 8)
|
||||
| ((unsigned int)(bytes[5] & 0xFF));
|
||||
loMant = ((unsigned int)(bytes[6] & 0xFF) << 24)
|
||||
| ((unsigned int)(bytes[7] & 0xFF) << 16)
|
||||
| ((unsigned int)(bytes[8] & 0xFF) << 8)
|
||||
| ((unsigned int)(bytes[9] & 0xFF));
|
||||
|
||||
if (expon == 0 && hiMant == 0 && loMant == 0)
|
||||
{
|
||||
f = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (expon == 0x7FFF)
|
||||
{ /* Infinity or NaN */
|
||||
f = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
expon -= 16383;
|
||||
f = (float)FMOD_LDEXP(UnsignedToFloat(hiMant), expon-=31);
|
||||
f += (float)FMOD_LDEXP(UnsignedToFloat(loMant), expon-=32);
|
||||
}
|
||||
}
|
||||
|
||||
if (bytes[0] & 0x80)
|
||||
{
|
||||
return -f;
|
||||
}
|
||||
else
|
||||
{
|
||||
return f;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT CodecAIFF::openInternal(FMOD_MODE usermode, FMOD_CREATESOUNDEXINFO *userexinfo)
|
||||
{
|
||||
FMOD_RESULT result = FMOD_OK;
|
||||
unsigned int fileoffset, filesize;
|
||||
int beginloop = -1, endloop = -1;
|
||||
unsigned int lensamples = 0;
|
||||
char id[4];
|
||||
AIFF_CHUNK chunk;
|
||||
bool done = false;
|
||||
int bits = 0;
|
||||
|
||||
mIsAIFC = false;
|
||||
mLittleEndian = false;
|
||||
|
||||
init(FMOD_SOUND_TYPE_AIFF);
|
||||
|
||||
FLOG((FMOD_DEBUG_LEVEL_LOG, __FILE__, __LINE__, "CodecAIFF::openInternal", "attempting to open as AIFF..\n"));
|
||||
|
||||
result = mFile->seek(0, SEEK_SET);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
Read header
|
||||
*/
|
||||
result = mFile->read(&chunk, 1, sizeof(AIFF_CHUNK), 0);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
if (FMOD_strncmp((const char *)chunk.id, "FORM", 4))
|
||||
{
|
||||
return FMOD_ERR_FORMAT;
|
||||
}
|
||||
|
||||
result = mFile->read(&id, 1, 4, 0);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
filesize = chunk.size;
|
||||
#ifdef PLATFORM_ENDIAN_LITTLE
|
||||
filesize = FMOD_SWAPENDIAN_DWORD(filesize);
|
||||
#endif
|
||||
|
||||
if (!FMOD_strncmp(id, "AIFC", 4))
|
||||
{
|
||||
mIsAIFC = true;
|
||||
FLOG((FMOD_DEBUG_LEVEL_LOG, __FILE__, __LINE__, "CodecAIFF::openInternal", "This AIFF is an AIF-C variation.\n"));
|
||||
}
|
||||
else if (FMOD_strncmp(id, "AIFF", 4))
|
||||
{
|
||||
FLOG((FMOD_DEBUG_LEVEL_ERROR, __FILE__, __LINE__, "CodecAIFF::openInternal", "'FORM' or 'AIFF' ID check failed [%c%c%c%c] : [%c%c%c%c]\n", chunk.id[0], chunk.id[1], chunk.id[2], chunk.id[3], id[0], id[1], id[2], id[3]));
|
||||
return FMOD_ERR_FORMAT;
|
||||
}
|
||||
|
||||
mWaveFormatMemory = (FMOD_CODEC_WAVEFORMAT *)FMOD_Memory_Calloc(sizeof(FMOD_CODEC_WAVEFORMAT));
|
||||
if (!mWaveFormatMemory)
|
||||
{
|
||||
return FMOD_ERR_MEMORY;
|
||||
}
|
||||
waveformat = mWaveFormatMemory;
|
||||
|
||||
|
||||
/*
|
||||
Get size of file in bytes
|
||||
*/
|
||||
result = mFile->getSize(&waveformat[0].lengthbytes);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
mSrcDataOffset = (unsigned int)-1;
|
||||
|
||||
fileoffset = 0;
|
||||
fileoffset += sizeof(AIFF_CHUNK);
|
||||
fileoffset += 4;
|
||||
|
||||
/*
|
||||
Decode chunks
|
||||
*/
|
||||
do
|
||||
{
|
||||
result = mFile->seek(fileoffset, SEEK_SET);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
result = mFile->read(&chunk, 1, sizeof(AIFF_CHUNK), 0);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifdef PLATFORM_ENDIAN_LITTLE
|
||||
chunk.size = FMOD_SWAPENDIAN_DWORD(chunk.size);
|
||||
#endif
|
||||
|
||||
FLOG((FMOD_DEBUG_LEVEL_LOG, __FILE__, __LINE__, "CodecAIFF::openInternal", "chunk : id %c%c%c%c size %d\n", chunk.id[0],chunk.id[1],chunk.id[2],chunk.id[3], chunk.size));
|
||||
|
||||
/*
|
||||
COMMON CHUNK
|
||||
*/
|
||||
if (!FMOD_strncmp((const char *)chunk.id, "COMM", 4))
|
||||
{
|
||||
AIFF_COMMONCHUNK commonchunk;
|
||||
AIFC_COMMONCHUNK commonchunkaifc;
|
||||
|
||||
if (mIsAIFC)
|
||||
{
|
||||
result = mFile->read(&commonchunkaifc, 1, sizeof(AIFC_COMMONCHUNK), 0);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
// If format is "sowt", this means it is little endian
|
||||
if (!FMOD_strncmp(commonchunkaifc.compressionid, "NONE", 4))
|
||||
{
|
||||
mLittleEndian = false;
|
||||
}
|
||||
else if (!FMOD_strncmp(commonchunkaifc.compressionid, "sowt", 4))
|
||||
{
|
||||
mLittleEndian = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return FMOD_ERR_FORMAT;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
result = mFile->read(&commonchunk, 1, sizeof(AIFF_COMMONCHUNK), 0);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef PLATFORM_ENDIAN_LITTLE
|
||||
if (mIsAIFC)
|
||||
{
|
||||
commonchunkaifc.numChannels = FMOD_SWAPENDIAN_WORD(commonchunkaifc.numChannels);
|
||||
commonchunkaifc.numSampleFrames = FMOD_SWAPENDIAN_DWORD(commonchunkaifc.numSampleFrames);
|
||||
commonchunkaifc.sampleSize = FMOD_SWAPENDIAN_WORD(commonchunkaifc.sampleSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
commonchunk.numChannels = FMOD_SWAPENDIAN_WORD(commonchunk.numChannels);
|
||||
commonchunk.numSampleFrames = FMOD_SWAPENDIAN_DWORD(commonchunk.numSampleFrames);
|
||||
commonchunk.sampleSize = FMOD_SWAPENDIAN_WORD(commonchunk.sampleSize);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (mIsAIFC)
|
||||
{
|
||||
lensamples = commonchunkaifc.numSampleFrames;
|
||||
|
||||
waveformat[0].frequency = (int)ConvertFromIeeeExtended(&commonchunkaifc.eSampleRate[0]);
|
||||
|
||||
FLOG((FMOD_DEBUG_LEVEL_LOG, __FILE__, __LINE__, "CodecAIFF::openInternal", "channels %d samplesize %d\n", commonchunkaifc.numChannels, commonchunkaifc.sampleSize));
|
||||
|
||||
bits = commonchunkaifc.sampleSize;
|
||||
result = SoundI::getFormatFromBits(bits, &waveformat[0].format);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
waveformat[0].channels = commonchunkaifc.numChannels;
|
||||
}
|
||||
else
|
||||
{
|
||||
lensamples = commonchunk.numSampleFrames;
|
||||
|
||||
waveformat[0].frequency = (int)ConvertFromIeeeExtended(&commonchunk.eSampleRate[0]);
|
||||
|
||||
FLOG((FMOD_DEBUG_LEVEL_LOG, __FILE__, __LINE__, "CodecAIFF::openInternal", "channels %d samplesize %d\n", commonchunk.numChannels, commonchunk.sampleSize));
|
||||
|
||||
bits = commonchunk.sampleSize;
|
||||
result = SoundI::getFormatFromBits(bits, &waveformat[0].format);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
waveformat[0].channels = commonchunk.numChannels;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
SOUND DATA CHUNK
|
||||
*/
|
||||
else if (!FMOD_strncmp((const char *)chunk.id, "SSND", 4))
|
||||
{
|
||||
AIFF_SOUNDDATACHUNK sounddatachunk;
|
||||
|
||||
result = mFile->read(&sounddatachunk, 1, sizeof(AIFF_SOUNDDATACHUNK), 0);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
if (mSrcDataOffset == (unsigned int)-1)
|
||||
{
|
||||
waveformat[0].lengthbytes = chunk.size - sizeof(AIFF_SOUNDDATACHUNK);
|
||||
result = mFile->tell(&mSrcDataOffset);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
if (!(mFile->mFlags & FMOD_FILE_SEEKABLE))
|
||||
{
|
||||
done = true;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
SOUND DATA CHUNK
|
||||
*/
|
||||
else if (!FMOD_strncmp((const char *)chunk.id, "INST", 4))
|
||||
{
|
||||
AIFF_INSTRUMENTCHUNK instchunk;
|
||||
|
||||
result = mFile->read(&instchunk, 1, sizeof(AIFF_INSTRUMENTCHUNK), 0);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
/* want sustainLoop */
|
||||
#ifdef PLATFORM_ENDIAN_LITTLE
|
||||
instchunk.sustainLoop.beginLoop = FMOD_SWAPENDIAN_WORD(instchunk.sustainLoop.beginLoop);
|
||||
instchunk.sustainLoop.endLoop = FMOD_SWAPENDIAN_WORD(instchunk.sustainLoop.endLoop);
|
||||
#endif
|
||||
|
||||
beginloop = instchunk.sustainLoop.beginLoop;
|
||||
endloop = instchunk.sustainLoop.endLoop;
|
||||
|
||||
if (!beginloop)
|
||||
{
|
||||
beginloop++;
|
||||
endloop++;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
SOUND DATA CHUNK
|
||||
*/
|
||||
else if (!FMOD_strncmp((const char *)chunk.id, "MARK", 4))
|
||||
{
|
||||
#if 0
|
||||
AIFF_MARKER markerchunk;
|
||||
unsigned short nummarkers;
|
||||
int count;
|
||||
|
||||
result = mFile->read(&nummarkers, 1, 2, 0);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifdef PLATFORM_ENDIAN_LITTLE
|
||||
nummarkers = FMOD_SWAPENDIAN_WORD(nummarkers);
|
||||
#endif
|
||||
|
||||
if (nummarkers && points)
|
||||
{
|
||||
FMOD_SyncPoints_Init(points);
|
||||
}
|
||||
|
||||
for (count=0; count < nummarkers; count++)
|
||||
{
|
||||
char name[FMOD_STRING_MAXNAMELEN];
|
||||
|
||||
if (FMOD_File_Read(&markerchunk, 1, sizeof(AIFF_MARKER), fp) != sizeof(AIFF_MARKER))
|
||||
{
|
||||
FMOD_ErrorNo = FMOD_ERR_FILE_BAD;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
#ifdef PLATFORM_ENDIAN_LITTLE
|
||||
markerchunk.position = FMOD_SWAPENDIAN_DWORD(markerchunk.position);
|
||||
#endif
|
||||
|
||||
FMOD_memset(name, 0, FMOD_STRING_MAXNAMELEN);
|
||||
if (FMOD_File_Read(name, 1, markerchunk.markerlength + 1, fp) != markerchunk.markerlength + 1)
|
||||
{
|
||||
FMOD_ErrorNo = FMOD_ERR_FILE_BAD;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (markerchunk.position >= lensamples)
|
||||
{
|
||||
markerchunk.position = lensamples - 1;
|
||||
}
|
||||
|
||||
if (looppoints)
|
||||
{
|
||||
if (beginloop == count + 1)
|
||||
{
|
||||
looppoints[0] = markerchunk.position;
|
||||
}
|
||||
else if (endloop == count + 1)
|
||||
{
|
||||
looppoints[1] = markerchunk.position;
|
||||
}
|
||||
}
|
||||
|
||||
if (points)
|
||||
{
|
||||
FMOD_SyncPoint_Add(points, markerchunk.position, name);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
fileoffset += sizeof(AIFF_CHUNK);
|
||||
fileoffset += chunk.size;
|
||||
|
||||
if (chunk.size & 1)
|
||||
{
|
||||
fileoffset++;
|
||||
}
|
||||
|
||||
if (chunk.size < 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
FLOG((FMOD_DEBUG_LEVEL_LOG, __FILE__, __LINE__, "CodecAIFF::openInternal", "offset = %d / %d\n", fileoffset, filesize));
|
||||
|
||||
} while (fileoffset < filesize && fileoffset > 0 && !done);
|
||||
|
||||
/*
|
||||
Didnt find the data chunk!
|
||||
*/
|
||||
if (mSrcDataOffset == (unsigned int)-1)
|
||||
{
|
||||
mSrcDataOffset = 0;
|
||||
FLOG((FMOD_DEBUG_LEVEL_ERROR, __FILE__, __LINE__, "CodecAIFF::openInternal", "couldn't find a data chunk\n"));
|
||||
|
||||
return FMOD_ERR_FILE_BAD;
|
||||
}
|
||||
|
||||
result = SoundI::getSamplesFromBytes(waveformat[0].lengthbytes, &waveformat[0].lengthpcm, waveformat[0].channels, waveformat[0].format);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
waveformat[0].blockalign = waveformat[0].channels * bits / 8;
|
||||
|
||||
/*
|
||||
Fill out base class members, also pointing to or allocating storage for them.
|
||||
*/
|
||||
numsubsounds = 0;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT CodecAIFF::closeInternal()
|
||||
{
|
||||
if (mWaveFormatMemory)
|
||||
{
|
||||
FMOD_Memory_Free(mWaveFormatMemory);
|
||||
mWaveFormatMemory = 0;
|
||||
}
|
||||
|
||||
waveformat = 0;
|
||||
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT CodecAIFF::readInternal(void *buffer, unsigned int sizebytes, unsigned int *bytesread)
|
||||
{
|
||||
FMOD_RESULT result;
|
||||
|
||||
// Bring the number of bytes to a multiple of 3 bytes
|
||||
if(waveformat[0].format == FMOD_SOUND_FORMAT_PCM24)
|
||||
{
|
||||
if(sizebytes >= 3)
|
||||
{
|
||||
sizebytes = (sizebytes / 3) * 3;
|
||||
}
|
||||
}
|
||||
|
||||
result = mFile->read(buffer, 1, sizebytes, bytesread);
|
||||
if (result != FMOD_OK && result != FMOD_ERR_FILE_EOF)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
if (waveformat[0].format == FMOD_SOUND_FORMAT_PCM16)
|
||||
{
|
||||
unsigned int count;
|
||||
signed short *wptr = (signed short *)buffer;
|
||||
|
||||
#ifdef PLATFORM_ENDIAN_LITTLE
|
||||
|
||||
if (!mLittleEndian)
|
||||
{
|
||||
count = *bytesread >> 1;
|
||||
count >>= 2;
|
||||
while (count)
|
||||
{
|
||||
wptr[0] = FMOD_SWAPENDIAN_WORD(wptr[0]);
|
||||
wptr[1] = FMOD_SWAPENDIAN_WORD(wptr[1]);
|
||||
wptr[2] = FMOD_SWAPENDIAN_WORD(wptr[2]);
|
||||
wptr[3] = FMOD_SWAPENDIAN_WORD(wptr[3]);
|
||||
wptr+=4;
|
||||
count--;
|
||||
}
|
||||
|
||||
count = *bytesread >> 1;
|
||||
count &= 3;
|
||||
while (count)
|
||||
{
|
||||
wptr[0] = FMOD_SWAPENDIAN_WORD(wptr[0]);
|
||||
wptr++;
|
||||
count--;
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
if (mLittleEndian)
|
||||
{
|
||||
count = *bytesread >> 1;
|
||||
count >>= 2;
|
||||
while (count)
|
||||
{
|
||||
wptr[0] = FMOD_SWAPENDIAN_WORD(wptr[0]);
|
||||
wptr[1] = FMOD_SWAPENDIAN_WORD(wptr[1]);
|
||||
wptr[2] = FMOD_SWAPENDIAN_WORD(wptr[2]);
|
||||
wptr[3] = FMOD_SWAPENDIAN_WORD(wptr[3]);
|
||||
wptr+=4;
|
||||
count--;
|
||||
}
|
||||
|
||||
count = *bytesread >> 1;
|
||||
count &= 3;
|
||||
while (count)
|
||||
{
|
||||
wptr[0] = FMOD_SWAPENDIAN_WORD(wptr[0]);
|
||||
wptr++;
|
||||
count--;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
else if (waveformat[0].format == FMOD_SOUND_FORMAT_PCM24)
|
||||
{
|
||||
unsigned int count;
|
||||
unsigned char tmp0, tmp1, tmp2, tmp3;
|
||||
FMOD_INT24 *wptr = (FMOD_INT24 *)buffer;
|
||||
|
||||
count = *bytesread / 3;
|
||||
count >>= 2;
|
||||
while (count)
|
||||
{
|
||||
tmp0 = wptr[0].val[0];
|
||||
tmp1 = wptr[1].val[0];
|
||||
tmp2 = wptr[2].val[0];
|
||||
tmp3 = wptr[3].val[0];
|
||||
|
||||
wptr[0].val[0] = wptr[0].val[2];
|
||||
wptr[1].val[0] = wptr[1].val[2];
|
||||
wptr[2].val[0] = wptr[2].val[2];
|
||||
wptr[3].val[0] = wptr[3].val[2];
|
||||
|
||||
wptr[0].val[2] = tmp0;
|
||||
wptr[1].val[2] = tmp1;
|
||||
wptr[2].val[2] = tmp2;
|
||||
wptr[3].val[2] = tmp3;
|
||||
|
||||
wptr+=4;
|
||||
count--;
|
||||
}
|
||||
|
||||
count = *bytesread / 3;
|
||||
count &= 3;
|
||||
while (count)
|
||||
{
|
||||
tmp0 = wptr[0].val[0];
|
||||
wptr[0].val[0] = wptr[0].val[2];
|
||||
wptr[0].val[2] = tmp0;
|
||||
wptr++;
|
||||
count--;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT CodecAIFF::setPositionInternal(int subsound, unsigned int position, FMOD_TIMEUNIT postype)
|
||||
{
|
||||
FMOD_RESULT result;
|
||||
int bits;
|
||||
unsigned int bytes;
|
||||
|
||||
result = SoundI::getBitsFromFormat(waveformat[0].format, &bits);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
SoundI::getBytesFromSamples(position, &bytes, waveformat[0].channels, waveformat[0].format);
|
||||
|
||||
result = mFile->seek(mSrcDataOffset + bytes, SEEK_SET);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT F_CALLBACK CodecAIFF::openCallback(FMOD_CODEC_STATE *codec, FMOD_MODE usermode, FMOD_CREATESOUNDEXINFO *userexinfo)
|
||||
{
|
||||
CodecAIFF *aiff = (CodecAIFF *)codec;
|
||||
|
||||
return aiff->openInternal(usermode, userexinfo);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT F_CALLBACK CodecAIFF::closeCallback(FMOD_CODEC_STATE *codec)
|
||||
{
|
||||
CodecAIFF *aiff = (CodecAIFF *)codec;
|
||||
|
||||
return aiff->closeInternal();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT F_CALLBACK CodecAIFF::readCallback(FMOD_CODEC_STATE *codec, void *buffer, unsigned int sizebytes, unsigned int *bytesread)
|
||||
{
|
||||
CodecAIFF *aiff = (CodecAIFF *)codec;
|
||||
|
||||
return aiff->readInternal(buffer, sizebytes, bytesread);
|
||||
}
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT F_CALLBACK CodecAIFF::setPositionCallback(FMOD_CODEC_STATE *codec, int subsound, unsigned int position, FMOD_TIMEUNIT postype)
|
||||
{
|
||||
CodecAIFF *aiff = (CodecAIFF *)codec;
|
||||
|
||||
return aiff->setPositionInternal(subsound, position, postype);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
111
src/fmod_codec_aiff.h
Executable file
111
src/fmod_codec_aiff.h
Executable file
|
|
@ -0,0 +1,111 @@
|
|||
#ifndef _FMOD_CODEC_AIFF_H
|
||||
#define _FMOD_CODEC_AIFF_H
|
||||
|
||||
#include "fmod_settings.h"
|
||||
|
||||
#ifdef FMOD_SUPPORT_AIFF
|
||||
|
||||
#include "fmod_codeci.h"
|
||||
#include "fmod_types.h"
|
||||
|
||||
namespace FMOD
|
||||
{
|
||||
|
||||
#ifdef FMOD_SUPPORT_PRAGMAPACK
|
||||
#pragma pack(1)
|
||||
#endif
|
||||
|
||||
typedef struct
|
||||
{
|
||||
signed char id[4] FMOD_PACKED_INTERNAL;
|
||||
int size FMOD_PACKED_INTERNAL;
|
||||
} FMOD_PACKED AIFF_CHUNK;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
short numChannels FMOD_PACKED_INTERNAL;
|
||||
unsigned int numSampleFrames FMOD_PACKED_INTERNAL;
|
||||
short sampleSize FMOD_PACKED_INTERNAL;
|
||||
unsigned char eSampleRate[10] FMOD_PACKED_INTERNAL;
|
||||
} FMOD_PACKED AIFF_COMMONCHUNK;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
short numChannels FMOD_PACKED_INTERNAL;
|
||||
unsigned int numSampleFrames FMOD_PACKED_INTERNAL;
|
||||
short sampleSize FMOD_PACKED_INTERNAL;
|
||||
unsigned char eSampleRate[10] FMOD_PACKED_INTERNAL;
|
||||
char compressionid[4]; FMOD_PACKED_INTERNAL;
|
||||
unsigned char compressionName[256]; FMOD_PACKED_INTERNAL;
|
||||
unsigned char compressionNameLength; FMOD_PACKED_INTERNAL;
|
||||
} FMOD_PACKED AIFC_COMMONCHUNK;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned int offset FMOD_PACKED_INTERNAL;
|
||||
unsigned int blockSize FMOD_PACKED_INTERNAL;
|
||||
} FMOD_PACKED AIFF_SOUNDDATACHUNK;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
short id FMOD_PACKED_INTERNAL;
|
||||
unsigned int position FMOD_PACKED_INTERNAL;
|
||||
unsigned char markerlength FMOD_PACKED_INTERNAL;
|
||||
} FMOD_PACKED AIFF_MARKER;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
short playMode FMOD_PACKED_INTERNAL;
|
||||
short beginLoop FMOD_PACKED_INTERNAL;
|
||||
short endLoop FMOD_PACKED_INTERNAL;
|
||||
} FMOD_PACKED AIFF_LOOP;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char baseNote FMOD_PACKED_INTERNAL;
|
||||
char detune FMOD_PACKED_INTERNAL;
|
||||
char lowNote FMOD_PACKED_INTERNAL;
|
||||
char highNote FMOD_PACKED_INTERNAL;
|
||||
char lowVelocity FMOD_PACKED_INTERNAL;
|
||||
char highVelocity FMOD_PACKED_INTERNAL;
|
||||
short gain FMOD_PACKED_INTERNAL;
|
||||
AIFF_LOOP sustainLoop FMOD_PACKED_INTERNAL;
|
||||
AIFF_LOOP releaseLoop FMOD_PACKED_INTERNAL;
|
||||
} FMOD_PACKED AIFF_INSTRUMENTCHUNK;
|
||||
|
||||
#ifdef FMOD_SUPPORT_PRAGMAPACK
|
||||
#ifdef CODEWARRIOR
|
||||
#pragma pack(0)
|
||||
#else
|
||||
#pragma pack()
|
||||
#endif
|
||||
#endif
|
||||
|
||||
class CodecAIFF : public Codec
|
||||
{
|
||||
private:
|
||||
|
||||
bool mIsAIFC;
|
||||
bool mLittleEndian;
|
||||
|
||||
FMOD_RESULT openInternal(FMOD_MODE usermode, FMOD_CREATESOUNDEXINFO *userexinfo);
|
||||
FMOD_RESULT closeInternal();
|
||||
FMOD_RESULT readInternal(void *buffer, unsigned int size, unsigned int *read);
|
||||
FMOD_RESULT setPositionInternal(int subsound, unsigned int position, FMOD_TIMEUNIT postype);
|
||||
|
||||
public:
|
||||
|
||||
static FMOD_RESULT F_CALLBACK openCallback(FMOD_CODEC_STATE *codec, FMOD_MODE usermode, FMOD_CREATESOUNDEXINFO *userexinfo);
|
||||
static FMOD_RESULT F_CALLBACK closeCallback(FMOD_CODEC_STATE *codec);
|
||||
static FMOD_RESULT F_CALLBACK readCallback(FMOD_CODEC_STATE *codec, void *buffer, unsigned int sizebytes, unsigned int *bytesread);
|
||||
static FMOD_RESULT F_CALLBACK setPositionCallback(FMOD_CODEC_STATE *codec, int subsound, unsigned int position, FMOD_TIMEUNIT postype);
|
||||
|
||||
static FMOD_CODEC_DESCRIPTION_EX *getDescriptionEx();
|
||||
};
|
||||
}
|
||||
|
||||
#endif /* FMOD_SUPPORT_AIFF */
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
758
src/fmod_codec_celt.cpp
Executable file
758
src/fmod_codec_celt.cpp
Executable file
|
|
@ -0,0 +1,758 @@
|
|||
#include "fmod_settings.h"
|
||||
|
||||
#ifdef FMOD_SUPPORT_CELT
|
||||
|
||||
#include "fmod.h"
|
||||
#include "fmod_codec_celt.h"
|
||||
#include "fmod_soundi.h"
|
||||
|
||||
extern "C" {
|
||||
|
||||
void * FMOD_CELT_Calloc(int size)
|
||||
{
|
||||
return FMOD_Memory_Calloc(size);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
namespace FMOD
|
||||
{
|
||||
|
||||
CELTMode *CodecCELT::mCELTModeMono = 0;
|
||||
CELTMode *CodecCELT::mCELTModeStereo = 0;
|
||||
int CodecCELT::mCELTModeMonoRef = 0;
|
||||
int CodecCELT::mCELTModeStereoRef = 0;
|
||||
|
||||
FMOD_CODEC_DESCRIPTION_EX celtcodec;
|
||||
|
||||
#if defined(PLUGIN_EXPORTS) && !defined(PLUGIN_FSB)
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
FMODGetCodecDescription is mandantory for every fmod plugin. This is the symbol the registerplugin function searches for.
|
||||
Must be declared with F_API to make it export as stdcall.
|
||||
*/
|
||||
F_DECLSPEC F_DLLEXPORT FMOD_CODEC_DESCRIPTION_EX * F_API FMODGetCodecDescriptionEx()
|
||||
{
|
||||
return CodecCELT::getDescriptionEx();
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* PLUGIN_EXPORTS */
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_CODEC_DESCRIPTION_EX *CodecCELT::getDescriptionEx()
|
||||
{
|
||||
FMOD_memset(&celtcodec, 0, sizeof(FMOD_CODEC_DESCRIPTION_EX));
|
||||
|
||||
celtcodec.name = "FMOD CELT Codec";
|
||||
celtcodec.version = 0x00010100;
|
||||
celtcodec.timeunits = FMOD_TIMEUNIT_PCM;
|
||||
celtcodec.open = &CodecCELT::openCallback;
|
||||
celtcodec.close = &CodecCELT::closeCallback;
|
||||
celtcodec.read = &CodecCELT::readCallback;
|
||||
celtcodec.setposition = &CodecCELT::setPositionCallback;
|
||||
celtcodec.init = &CodecCELT::initCallback;
|
||||
|
||||
#ifdef FMOD_SUPPORT_MEMORYTRACKER
|
||||
celtcodec.getmemoryused = &CodecCELT::getMemoryUsedCallback;
|
||||
#endif
|
||||
|
||||
celtcodec.mSize = sizeof(CodecCELT);
|
||||
|
||||
return &celtcodec;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT CodecCELT::createCELTModeMono()
|
||||
{
|
||||
int error;
|
||||
|
||||
if (!mCELTModeMono)
|
||||
{
|
||||
mCELTModeMono = celt_mode_create(FMOD_CELT_RATE, 1, FMOD_CELT_FRAMESIZESAMPLES, &error);
|
||||
if (error != CELT_OK)
|
||||
{
|
||||
FLOG((FMOD_DEBUG_LEVEL_ERROR, __FILE__, __LINE__, "CodecCELT::createCELTModeMono", "Error (%d) creating CELT mode: %d\n", error, 1));
|
||||
return FMOD_ERR_INTERNAL;
|
||||
}
|
||||
}
|
||||
|
||||
mCELTModeMonoRef++;
|
||||
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT CodecCELT::createCELTModeStereo()
|
||||
{
|
||||
int error;
|
||||
|
||||
if (!mCELTModeStereo)
|
||||
{
|
||||
mCELTModeStereo = celt_mode_create(FMOD_CELT_RATE, 2, FMOD_CELT_FRAMESIZESAMPLES, &error);
|
||||
if (error != CELT_OK)
|
||||
{
|
||||
FLOG((FMOD_DEBUG_LEVEL_ERROR, __FILE__, __LINE__, "CodecCELT::createCELTModeStereo", "Error creating CELT mode: %d\n", error));
|
||||
return FMOD_ERR_INTERNAL;
|
||||
}
|
||||
}
|
||||
|
||||
mCELTModeStereoRef++;
|
||||
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
int CodecCELT::getBitstreamVersion()
|
||||
{
|
||||
int bitstreamversion = 0;
|
||||
|
||||
if (mCELTModeMono)
|
||||
{
|
||||
celt_mode_info(mCELTModeMono, CELT_GET_BITSTREAM_VERSION, (celt_int32_t *)&bitstreamversion);
|
||||
}
|
||||
else if (mCELTModeStereo)
|
||||
{
|
||||
celt_mode_info(mCELTModeStereo, CELT_GET_BITSTREAM_VERSION, (celt_int32_t *)&bitstreamversion);
|
||||
}
|
||||
|
||||
return bitstreamversion;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT CodecCELT::CELTinit(int numstreams)
|
||||
{
|
||||
mCELTDecoderBuffer = (char *)FMOD_Memory_Calloc(numstreams * FMOD_CELT_DECODERBUFFERSIZE);
|
||||
if (!mCELTDecoderBuffer)
|
||||
{
|
||||
return FMOD_ERR_MEMORY;
|
||||
}
|
||||
|
||||
for (int i = 0; i < numstreams; i++)
|
||||
{
|
||||
mCELTDecoder[i] = fmod_celt_decoder_create_only(mCELTDecoderBuffer + i * FMOD_CELT_DECODERBUFFERSIZE);
|
||||
if (!mCELTDecoder[i])
|
||||
{
|
||||
FLOG((FMOD_DEBUG_LEVEL_ERROR, __FILE__, __LINE__, "CodecCELT::CELTinit", "celt_decoder_create failed\n"));
|
||||
return FMOD_ERR_INTERNAL;
|
||||
}
|
||||
}
|
||||
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT CodecCELT::openInternal(FMOD_MODE usermode, FMOD_CREATESOUNDEXINFO *userexinfo)
|
||||
{
|
||||
/*
|
||||
CodecCELT for fsb only
|
||||
*/
|
||||
|
||||
return FMOD_ERR_FORMAT;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT CodecCELT::closeInternal()
|
||||
{
|
||||
mCELTModeMonoRef--;
|
||||
if (mCELTModeMonoRef == 0)
|
||||
{
|
||||
celt_mode_destroy(mCELTModeMono);
|
||||
}
|
||||
|
||||
mCELTModeStereoRef--;
|
||||
if (mCELTModeStereoRef == 0)
|
||||
{
|
||||
celt_mode_destroy(mCELTModeStereo);
|
||||
}
|
||||
|
||||
if (mCELTDecoderBuffer)
|
||||
{
|
||||
FMOD_Memory_Free(mCELTDecoderBuffer);
|
||||
mCELTDecoderBuffer = 0;
|
||||
}
|
||||
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT CodecCELT::decodeHeader(void *buffer, unsigned int *framesize)
|
||||
{
|
||||
FMOD_CELT_FRAMEHEADER *frameheader = (FMOD_CELT_FRAMEHEADER *)buffer;
|
||||
|
||||
#ifdef PLATFORM_ENDIAN_BIG
|
||||
frameheader->magic = FMOD_SWAPENDIAN_DWORD(frameheader->magic);
|
||||
frameheader->framesize = FMOD_SWAPENDIAN_DWORD(frameheader->framesize);
|
||||
#endif
|
||||
|
||||
if (frameheader->magic != FMOD_CELT_MAGIC)
|
||||
{
|
||||
return FMOD_ERR_FORMAT;
|
||||
}
|
||||
|
||||
if (framesize)
|
||||
{
|
||||
*framesize = frameheader->framesize;
|
||||
}
|
||||
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT CodecCELT::readInternal(void *buffer, unsigned int sizebytes, unsigned int *bytesread)
|
||||
{
|
||||
FMOD_RESULT result;
|
||||
int error = 0;
|
||||
unsigned char readbuffer[1024];
|
||||
unsigned int framesize;
|
||||
int channel = 0;
|
||||
|
||||
*bytesread = 0;
|
||||
|
||||
/*
|
||||
Multichannel interleaved.
|
||||
*/
|
||||
do
|
||||
{
|
||||
unsigned int bytesreadinternal = 0;
|
||||
|
||||
/*
|
||||
Get next valid header
|
||||
*/
|
||||
do
|
||||
{
|
||||
result = mFile->read(readbuffer, sizeof(FMOD_CELT_FRAMEHEADER), 1);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
Decode header
|
||||
*/
|
||||
result = decodeHeader(readbuffer, &framesize);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
mFile->seek(-3, SEEK_CUR); /* increment a byte at a time! */
|
||||
}
|
||||
}
|
||||
while (result != FMOD_OK);
|
||||
|
||||
/*
|
||||
Read in a frame and decode it
|
||||
*/
|
||||
result = mFile->read(readbuffer, framesize, 1);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
if (waveformat[0].channels > 2)
|
||||
{
|
||||
short decodebuffer[FMOD_CELT_FRAMESIZESAMPLES * 2];
|
||||
|
||||
error = celt_decode(mCELTDecoder[channel], readbuffer, framesize, (celt_int16_t *)decodebuffer);
|
||||
if (error != CELT_OK)
|
||||
{
|
||||
return FMOD_ERR_INTERNAL;
|
||||
}
|
||||
|
||||
/*
|
||||
Interleave into pcm decode buffer
|
||||
*/
|
||||
short *outbuffer = (short *)buffer + channel * 2;
|
||||
|
||||
for (int i = 0; i < FMOD_CELT_FRAMESIZESAMPLES * 2; i+= 2)
|
||||
{
|
||||
outbuffer[0] = decodebuffer[i + 0];
|
||||
outbuffer[1] = decodebuffer[i + 1];
|
||||
|
||||
outbuffer += waveformat[0].channels;
|
||||
}
|
||||
|
||||
SoundI::getBytesFromSamples(FMOD_CELT_FRAMESIZESAMPLES, &bytesreadinternal, 2, FMOD_SOUND_FORMAT_PCM16);
|
||||
}
|
||||
else
|
||||
{
|
||||
error = celt_decode(mCELTDecoder[channel], readbuffer, framesize, (celt_int16_t *)buffer);
|
||||
if (error != CELT_OK)
|
||||
{
|
||||
return FMOD_ERR_INTERNAL;
|
||||
}
|
||||
|
||||
SoundI::getBytesFromSamples(FMOD_CELT_FRAMESIZESAMPLES, &bytesreadinternal, waveformat[0].channels, FMOD_SOUND_FORMAT_PCM16);
|
||||
}
|
||||
|
||||
*bytesread += bytesreadinternal;
|
||||
|
||||
channel++;
|
||||
}
|
||||
while (channel < waveformat[0].channels / 2);
|
||||
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT CodecCELT::setPositionInternal(int subsound, unsigned int position, FMOD_TIMEUNIT postype)
|
||||
{
|
||||
FMOD_RESULT result;
|
||||
unsigned int frame, pcmbytes, bytespersample;
|
||||
unsigned int excessbytes = 0;
|
||||
unsigned int raw = 0;
|
||||
|
||||
FLOG((FMOD_DEBUG_LEVEL_ERROR, __FILE__, __LINE__, "CodecCELT::setPositionInternal", "%d\n", position));
|
||||
|
||||
/*
|
||||
set the CELT mode
|
||||
*/
|
||||
if (waveformat[0].channels == 1)
|
||||
{
|
||||
/*
|
||||
Mono
|
||||
*/
|
||||
fmod_celt_decoder_setmode(mCELTDecoder[0], mCELTModeMono);
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
Stereo or Multichannel. (Interleaved stereo pairs)
|
||||
*/
|
||||
for (int i = 0; i < waveformat[0].channels / 2; i++)
|
||||
{
|
||||
fmod_celt_decoder_setmode(mCELTDecoder[i], mCELTModeStereo);
|
||||
}
|
||||
}
|
||||
|
||||
bytespersample = sizeof(signed short) * waveformat[0].channels;
|
||||
pcmbytes = position * bytespersample;
|
||||
frame = pcmbytes / mPCMFrameLengthBytes;
|
||||
|
||||
if (pcmbytes)
|
||||
{
|
||||
unsigned int framerewind = 1;
|
||||
|
||||
excessbytes = pcmbytes - (frame * mPCMFrameLengthBytes);
|
||||
|
||||
if (frame < framerewind)
|
||||
{
|
||||
framerewind = frame;
|
||||
}
|
||||
|
||||
frame -= framerewind;
|
||||
excessbytes += (mPCMFrameLengthBytes * framerewind);
|
||||
}
|
||||
else
|
||||
{
|
||||
excessbytes = 0;
|
||||
position = 0;
|
||||
}
|
||||
|
||||
if (position > (excessbytes / bytespersample))
|
||||
{
|
||||
int numframes = (int)((waveformat[0].lengthpcm * bytespersample) / mPCMFrameLengthBytes);
|
||||
int compressedframesize = waveformat[0].lengthbytes / numframes;
|
||||
raw = frame * compressedframesize;
|
||||
}
|
||||
else
|
||||
{
|
||||
raw = 0;
|
||||
}
|
||||
|
||||
raw += mSrcDataOffset;
|
||||
|
||||
if (raw > (unsigned int)mSrcDataOffset + (unsigned int)waveformat[0].lengthbytes)
|
||||
{
|
||||
raw = mSrcDataOffset;
|
||||
}
|
||||
|
||||
result = mFile->seek(raw, SEEK_SET);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
if (!(mFlags & FMOD_CODEC_FROMFSB))
|
||||
{
|
||||
mFlags |= FMOD_CODEC_SEEKING;
|
||||
}
|
||||
|
||||
while (excessbytes)
|
||||
{
|
||||
char buff[2048];
|
||||
unsigned int read = 0, toread = 2048;
|
||||
|
||||
if (toread > excessbytes)
|
||||
{
|
||||
toread = excessbytes;
|
||||
}
|
||||
|
||||
result = Codec::read(buff, toread, &read);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
During the first read after the seek, decode sometimes fails because the decoder
|
||||
hasn't built up state yet, just push on, decoded frames are dropped anyway.
|
||||
*/
|
||||
if (read == 0)
|
||||
{
|
||||
read = toread;
|
||||
}
|
||||
|
||||
if (excessbytes >= read)
|
||||
{
|
||||
excessbytes -= read;
|
||||
}
|
||||
else
|
||||
{
|
||||
excessbytes = 0;
|
||||
}
|
||||
}
|
||||
|
||||
mFlags &= ~FMOD_CODEC_SEEKING;
|
||||
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
||||
|
||||
#ifdef FMOD_SUPPORT_MEMORYTRACKER
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT CodecCELT::getMemoryUsedImpl(MemoryTracker *tracker)
|
||||
{
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT F_CALLBACK CodecCELT::openCallback(FMOD_CODEC_STATE *codec, FMOD_MODE usermode, FMOD_CREATESOUNDEXINFO *userexinfo)
|
||||
{
|
||||
CodecCELT *celt = (CodecCELT *)codec;
|
||||
|
||||
return celt->openInternal(usermode, userexinfo);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT F_CALLBACK CodecCELT::closeCallback(FMOD_CODEC_STATE *codec)
|
||||
{
|
||||
CodecCELT *celt = (CodecCELT *)codec;
|
||||
|
||||
return celt->closeInternal();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT F_CALLBACK CodecCELT::readCallback(FMOD_CODEC_STATE *codec, void *buffer, unsigned int sizebytes, unsigned int *bytesread)
|
||||
{
|
||||
CodecCELT *celt = (CodecCELT *)codec;
|
||||
|
||||
return celt->readInternal(buffer, sizebytes, bytesread);
|
||||
}
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT F_CALLBACK CodecCELT::setPositionCallback(FMOD_CODEC_STATE *codec, int subsound, unsigned int position, FMOD_TIMEUNIT postype)
|
||||
{
|
||||
CodecCELT *celt = (CodecCELT *)codec;
|
||||
|
||||
return celt->setPositionInternal(subsound, position, postype);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT F_CALLBACK CodecCELT::initCallback(FMOD_CODEC_STATE *codec, int numstreams)
|
||||
{
|
||||
CodecCELT *celt = (CodecCELT *)codec;
|
||||
|
||||
return celt->CELTinit(numstreams);
|
||||
}
|
||||
|
||||
#ifdef FMOD_SUPPORT_MEMORYTRACKER
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT F_CALLBACK CodecCELT::getMemoryUsedCallback(FMOD_CODEC_STATE *codec, MemoryTracker *tracker)
|
||||
{
|
||||
CodecCELT *celt = (CodecCELT *)codec;
|
||||
|
||||
return celt->getMemoryUsed(tracker);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif // FMOD_SUPPORT_CELT
|
||||
119
src/fmod_codec_celt.h
Executable file
119
src/fmod_codec_celt.h
Executable file
|
|
@ -0,0 +1,119 @@
|
|||
#ifndef _FMOD_CODEC_CELT_H
|
||||
#define _FMOD_CODEC_CELT_H
|
||||
|
||||
/*
|
||||
Changes made to CELT code:
|
||||
|
||||
- inline changed to FMOD_INLINE
|
||||
|
||||
- add fmod_celt_decoder_create_only() function
|
||||
- add fmod_celt_decoder_setmode() function
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#include "fmod_settings.h"
|
||||
|
||||
#ifdef FMOD_SUPPORT_CELT
|
||||
|
||||
#include "fmod_codeci.h"
|
||||
#include "../lib/libcelt/celt.h"
|
||||
#include "../lib/libcelt/modes.h"
|
||||
#include "../lib/libcelt/rate.h" /* For MAX_PULSES */
|
||||
#include "../lib/libcelt/mdct.h" /* For mdct_lookup */
|
||||
#include "../lib/libcelt/kiss_fftr.h" /* For kiss_fftr_cfg */
|
||||
|
||||
#define FMOD_CELT_MAGIC 0xf30dc317
|
||||
#define FMOD_CELT_FRAMESIZESAMPLES 512
|
||||
#define FMOD_CELT_MAXFRAMESIZEBYTES 1024
|
||||
#define FMOD_CELT_RATE 44100
|
||||
|
||||
/*
|
||||
Make sure to double check these values on each CELT update
|
||||
*/
|
||||
#define FMOD_CELT_MAX_EBANDS 24
|
||||
#define FMOD_CELT_MAX_PBANDS 8
|
||||
#define FMOD_CELT_MAX_ALLOCVECTORS 12
|
||||
#define FMOD_CELT_MAX_OVERLAP 128
|
||||
|
||||
/*
|
||||
CELTDecoder memory usage:
|
||||
|
||||
FMOD: MemPool::alloc : 76 bytes (01A7FD40) (alloc 387) - 32 bit
|
||||
or
|
||||
FMOD: MemPool::alloc : 136 bytes (01A7FD40) (alloc 387) - 64 bit
|
||||
|
||||
FMOD: MemPool::alloc : 5120 bytes (0214FA38) (alloc 388)
|
||||
FMOD: MemPool::alloc : 192 bytes (02150E88) (alloc 389)
|
||||
FMOD: MemPool::alloc : 8 bytes (0121FFB8) (alloc 386)
|
||||
|
||||
= 5456 bytes, round up to 5520 bytes
|
||||
*/
|
||||
#define FMOD_CELT_DECODERBUFFERSIZE 5520
|
||||
|
||||
namespace FMOD
|
||||
{
|
||||
typedef struct
|
||||
{
|
||||
unsigned int magic;
|
||||
unsigned int framesize;
|
||||
|
||||
} FMOD_CELT_FRAMEHEADER;
|
||||
|
||||
|
||||
class CodecCELT : public Codec
|
||||
{
|
||||
friend class CodecFSB;
|
||||
friend class ChannelSoftware;
|
||||
|
||||
DECLARE_MEMORYTRACKER_NONVIRTUAL
|
||||
|
||||
private:
|
||||
|
||||
|
||||
//char mCELTDecoderBuffer[5408]; /* For multichannel, will need multiples of this */
|
||||
|
||||
char *mCELTDecoderBuffer;
|
||||
CELTDecoder *mCELTDecoder[8]; /* Need on for each stereo stream in a multichannel sound */
|
||||
|
||||
static CELTMode *mCELTModeMono;
|
||||
static int mCELTModeMonoRef;
|
||||
static CELTMode *mCELTModeStereo;
|
||||
static int mCELTModeStereoRef;
|
||||
|
||||
FMOD_CODEC_WAVEFORMAT mWaveFormat;
|
||||
|
||||
FMOD_RESULT openInternal (FMOD_MODE usermode, FMOD_CREATESOUNDEXINFO *userexinfo);
|
||||
FMOD_RESULT closeInternal ();
|
||||
FMOD_RESULT readInternal (void *buffer, unsigned int size, unsigned int *read);
|
||||
FMOD_RESULT setPositionInternal (int subsound, unsigned int position, FMOD_TIMEUNIT postype);
|
||||
|
||||
FMOD_RESULT decodeHeader (void *buffer, unsigned int *framesize);
|
||||
|
||||
public:
|
||||
|
||||
unsigned int mPCMFrameLengthBytes;
|
||||
|
||||
FMOD_RESULT CELTinit (int numstreams);
|
||||
|
||||
static FMOD_RESULT createCELTModeMono();
|
||||
static FMOD_RESULT createCELTModeStereo();
|
||||
static int getBitstreamVersion();
|
||||
|
||||
static FMOD_RESULT F_CALLBACK openCallback(FMOD_CODEC_STATE *codec, FMOD_MODE usermode, FMOD_CREATESOUNDEXINFO *userexinfo);
|
||||
static FMOD_RESULT F_CALLBACK closeCallback(FMOD_CODEC_STATE *codec);
|
||||
static FMOD_RESULT F_CALLBACK readCallback(FMOD_CODEC_STATE *codec, void *buffer, unsigned int size, unsigned int *read);
|
||||
static FMOD_RESULT F_CALLBACK setPositionCallback(FMOD_CODEC_STATE *codec, int subsound, unsigned int position, FMOD_TIMEUNIT postype);
|
||||
|
||||
#ifdef FMOD_SUPPORT_MEMORYTRACKER
|
||||
static FMOD_RESULT F_CALLBACK getMemoryUsedCallback(FMOD_CODEC_STATE *codec, MemoryTracker *tracker);
|
||||
#endif
|
||||
|
||||
static FMOD_RESULT F_CALLBACK initCallback(FMOD_CODEC_STATE *codec, int numstreams);
|
||||
|
||||
static FMOD_CODEC_DESCRIPTION_EX *getDescriptionEx();
|
||||
};
|
||||
}
|
||||
|
||||
#endif // FMOD_SUPPORT_CELT
|
||||
#endif // _FMOD_CODEC_CELT_H
|
||||
971
src/fmod_codec_dls.cpp
Executable file
971
src/fmod_codec_dls.cpp
Executable file
|
|
@ -0,0 +1,971 @@
|
|||
#include "fmod_settings.h"
|
||||
|
||||
#ifdef FMOD_SUPPORT_DLS
|
||||
|
||||
#include "fmod.h"
|
||||
#include "fmod_codec_dls.h"
|
||||
#include "fmod_codec_wav.h"
|
||||
#include "fmod_soundi.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
namespace FMOD
|
||||
{
|
||||
|
||||
FMOD_CODEC_DESCRIPTION_EX dlscodec;
|
||||
|
||||
|
||||
#ifdef PLUGIN_EXPORTS
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
FMODGetCodecDescription is mandatory for every fmod plugin. This is the symbol the registerplugin function searches for.
|
||||
Must be declared with F_API to make it export as stdcall.
|
||||
*/
|
||||
F_DECLSPEC F_DLLEXPORT FMOD_CODEC_DESCRIPTION_EX * F_API FMODGetCodecDescriptionEx()
|
||||
{
|
||||
return CodecDLS::getDescriptionEx();
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* PLUGIN_EXPORTS */
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_CODEC_DESCRIPTION_EX *CodecDLS::getDescriptionEx()
|
||||
{
|
||||
FMOD_memset(&dlscodec, 0, sizeof(FMOD_CODEC_DESCRIPTION_EX));
|
||||
|
||||
dlscodec.name = "FMOD DLS Codec";
|
||||
dlscodec.version = 0x00010100;
|
||||
dlscodec.timeunits = FMOD_TIMEUNIT_PCM;
|
||||
dlscodec.open = &CodecDLS::openCallback;
|
||||
dlscodec.close = &CodecDLS::closeCallback;
|
||||
dlscodec.read = &CodecDLS::readCallback;
|
||||
dlscodec.setposition = &CodecDLS::setPositionCallback;
|
||||
|
||||
dlscodec.mType = FMOD_SOUND_TYPE_DLS;
|
||||
dlscodec.mSize = sizeof(CodecDLS);
|
||||
|
||||
return &dlscodec;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT CodecDLS::parseChunk(char *parentchunk, unsigned int chunksize)
|
||||
{
|
||||
unsigned int offset, fileoffset;
|
||||
FMOD_RESULT result;
|
||||
bool done = false;
|
||||
|
||||
result = mFile->tell(&fileoffset);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
offset = 4;
|
||||
fileoffset -= sizeof(WAVE_CHUNK);
|
||||
|
||||
/*
|
||||
Decode chunks
|
||||
*/
|
||||
do
|
||||
{
|
||||
WAVE_CHUNK chunk;
|
||||
|
||||
result = mFile->seek(fileoffset + sizeof(WAVE_CHUNK), SEEK_SET);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
result = mFile->read(&chunk, 1, sizeof(WAVE_CHUNK), 0);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifdef PLATFORM_ENDIAN_BIG
|
||||
chunk.size = FMOD_SWAPENDIAN_DWORD(chunk.size);
|
||||
#endif
|
||||
|
||||
//FLOG((FMOD_DEBUG_LEVEL_LOG, __FILE__, __LINE__, "CodecDLS::parseRIFF","chunk : id %c%c%c%c size %d\n", chunk.id[0],chunk.id[1],chunk.id[2],chunk.id[3], chunk.size));
|
||||
|
||||
/*
|
||||
CHUNKS WE DONT CARE ABOUT
|
||||
*/
|
||||
if (!FMOD_strncmp((const char *)chunk.id, "vers", 4) ||
|
||||
!FMOD_strncmp((const char *)chunk.id, "msyn", 4) ||
|
||||
!FMOD_strncmp((const char *)chunk.id, "dlid", 4))
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
NUMBER OF INSTRUMENTS CHUNK
|
||||
*/
|
||||
else if (!FMOD_strncmp((const char *)chunk.id, "colh", 4))
|
||||
{
|
||||
result = mFile->read(&mNumInstruments, 4, 1, 0);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
mInstrument = (CodecDLSInstrument *)FMOD_Memory_Calloc(mNumInstruments * sizeof(CodecDLSInstrument));
|
||||
if (!mInstrument)
|
||||
{
|
||||
return FMOD_ERR_MEMORY;
|
||||
}
|
||||
}
|
||||
/*
|
||||
POOL TABLE CHUNK
|
||||
*/
|
||||
else if (!FMOD_strncmp((const char *)chunk.id, "ptbl", 4))
|
||||
{
|
||||
unsigned int size;
|
||||
|
||||
result = mFile->read(&size, 4, 1, 0);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
result = mFile->read(&mNumSamples, 4, 1, 0);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
Fill out base class members, also pointing to or allocating storage for them.
|
||||
*/
|
||||
waveformat = (FMOD_CODEC_WAVEFORMAT *)FMOD_Memory_Calloc(sizeof(FMOD_CODEC_WAVEFORMAT) * mNumSamples);
|
||||
if (!waveformat)
|
||||
{
|
||||
return FMOD_ERR_MEMORY;
|
||||
}
|
||||
|
||||
mSample = (CodecDLSSample *)FMOD_Memory_Calloc(mNumSamples *sizeof(CodecDLSSample));
|
||||
if (!mSample)
|
||||
{
|
||||
return FMOD_ERR_MEMORY;
|
||||
}
|
||||
}
|
||||
/*
|
||||
LIST CHUNK
|
||||
*/
|
||||
else if (!FMOD_strncmp((const char *)chunk.id, "LIST", 4))
|
||||
{
|
||||
char listid[4];
|
||||
|
||||
result = mFile->read(listid, 1, 4, 0);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
result = parseChunk(listid, chunk.size);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
if (!FMOD_strncmp((const char *)listid, "wave", 4))
|
||||
{
|
||||
mSampleID++;
|
||||
}
|
||||
else if (!FMOD_strncmp((const char *)listid, "ins ", 4))
|
||||
{
|
||||
mInstrumentID++;
|
||||
if (mInstrumentID >= mNumInstruments)
|
||||
{
|
||||
mInstrumentID = mInstrumentID;
|
||||
}
|
||||
}
|
||||
else if (!FMOD_strncmp((const char *)listid, "rgn ", 4))
|
||||
{
|
||||
mRegionID++;
|
||||
}
|
||||
}
|
||||
else if (!FMOD_strncmp((const char *)chunk.id, "dlid", 4))
|
||||
{
|
||||
FMOD_GUID dlsid;
|
||||
|
||||
result = mFile->read(&dlsid, 1, sizeof(FMOD_GUID), 0);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
}
|
||||
else if (!FMOD_strncmp((const char *)chunk.id, "insh", 4))
|
||||
{
|
||||
result = mFile->read(&mInstrument[mInstrumentID].mHeader, 1, sizeof(DLS_INSTRUMENTHEADER), 0);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifdef PLATFORM_ENDIAN_BIG
|
||||
mInstrument[mInstrumentID].mHeader.cRegions = FMOD_SWAPENDIAN_DWORD(mInstrument[mInstrumentID].mHeader.cRegions);
|
||||
mInstrument[mInstrumentID].mHeader.Locale.ulBank = FMOD_SWAPENDIAN_DWORD(mInstrument[mInstrumentID].mHeader.Locale.ulBank);
|
||||
mInstrument[mInstrumentID].mHeader.Locale.ulInstrument = FMOD_SWAPENDIAN_DWORD(mInstrument[mInstrumentID].mHeader.Locale.ulInstrument);
|
||||
#endif
|
||||
|
||||
mInstrument[mInstrumentID].mRegion = (CodecDLSRegion *)FMOD_Memory_Calloc(sizeof(CodecDLSRegion) * mInstrument[mInstrumentID].mHeader.cRegions);
|
||||
if (!mInstrument[mInstrumentID].mRegion)
|
||||
{
|
||||
return FMOD_ERR_MEMORY;
|
||||
}
|
||||
mRegionID = 0;
|
||||
}
|
||||
else if (!FMOD_strncmp((const char *)chunk.id, "rgnh", 4))
|
||||
{
|
||||
result = mFile->read(&mInstrument[mInstrumentID].mRegion[mRegionID].mRegionHeader, 1, sizeof(DLS_REGIONHEADER), 0);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifdef PLATFORM_ENDIAN_BIG
|
||||
mInstrument[mInstrumentID].mRegion[mRegionID].mRegionHeader.RangeKey.usLow = FMOD_SWAPENDIAN_WORD(mInstrument[mInstrumentID].mRegion[mRegionID].mRegionHeader.RangeKey.usLow);
|
||||
mInstrument[mInstrumentID].mRegion[mRegionID].mRegionHeader.RangeKey.usHigh = FMOD_SWAPENDIAN_WORD(mInstrument[mInstrumentID].mRegion[mRegionID].mRegionHeader.RangeKey.usHigh);
|
||||
mInstrument[mInstrumentID].mRegion[mRegionID].mRegionHeader.RangeVelocity.usLow = FMOD_SWAPENDIAN_WORD(mInstrument[mInstrumentID].mRegion[mRegionID].mRegionHeader.RangeVelocity.usLow);
|
||||
mInstrument[mInstrumentID].mRegion[mRegionID].mRegionHeader.RangeVelocity.usHigh = FMOD_SWAPENDIAN_WORD(mInstrument[mInstrumentID].mRegion[mRegionID].mRegionHeader.RangeVelocity.usHigh);
|
||||
mInstrument[mInstrumentID].mRegion[mRegionID].mRegionHeader.fusOptions = FMOD_SWAPENDIAN_WORD(mInstrument[mInstrumentID].mRegion[mRegionID].mRegionHeader.fusOptions);
|
||||
mInstrument[mInstrumentID].mRegion[mRegionID].mRegionHeader.usKeyGroup = FMOD_SWAPENDIAN_WORD(mInstrument[mInstrumentID].mRegion[mRegionID].mRegionHeader.usKeyGroup);
|
||||
#endif
|
||||
}
|
||||
else if (!FMOD_strncmp((const char *)chunk.id, "wsmp", 4))
|
||||
{
|
||||
unsigned int size = sizeof(DLS_WAVESAMPLE);
|
||||
|
||||
if (chunk.size < size)
|
||||
{
|
||||
size = chunk.size;
|
||||
}
|
||||
|
||||
if (!FMOD_strncmp(parentchunk, "wave", 4))
|
||||
{
|
||||
result = mFile->read(&mSample[mSampleID].mWaveSample, 1, size, 0);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifdef PLATFORM_ENDIAN_BIG
|
||||
mSample[mSampleID].mWaveSample.cbSize = FMOD_SWAPENDIAN_DWORD(mSample[mSampleID].mWaveSample.cbSize);
|
||||
mSample[mSampleID].mWaveSample.usUnityNote = FMOD_SWAPENDIAN_WORD(mSample[mSampleID].mWaveSample.usUnityNote);
|
||||
mSample[mSampleID].mWaveSample.sFineTune = FMOD_SWAPENDIAN_WORD(mSample[mSampleID].mWaveSample.sFineTune);
|
||||
mSample[mSampleID].mWaveSample.lAttenuation = FMOD_SWAPENDIAN_DWORD(mSample[mSampleID].mWaveSample.lAttenuation);
|
||||
mSample[mSampleID].mWaveSample.fulOptions = FMOD_SWAPENDIAN_DWORD(mSample[mSampleID].mWaveSample.fulOptions);
|
||||
#endif
|
||||
|
||||
if (mSample[mSampleID].mWaveSample.cSampleLoops)
|
||||
{
|
||||
#ifdef PLATFORM_ENDIAN_BIG
|
||||
mSample[mSampleID].mWaveSample.loop[0].cbSize = FMOD_SWAPENDIAN_DWORD(mSample[mSampleID].mWaveSample.loop[0].cbSize);
|
||||
mSample[mSampleID].mWaveSample.loop[0].ulLoopType = FMOD_SWAPENDIAN_DWORD(mSample[mSampleID].mWaveSample.loop[0].ulLoopType);
|
||||
mSample[mSampleID].mWaveSample.loop[0].ulLoopStart = FMOD_SWAPENDIAN_DWORD(mSample[mSampleID].mWaveSample.loop[0].ulLoopStart);
|
||||
mSample[mSampleID].mWaveSample.loop[0].ulLoopLength = FMOD_SWAPENDIAN_DWORD(mSample[mSampleID].mWaveSample.loop[0].ulLoopLength);
|
||||
#endif
|
||||
|
||||
waveformat[mSampleID].mode = FMOD_LOOP_NORMAL;
|
||||
waveformat[mSampleID].loopstart = mSample[mSampleID].mWaveSample.loop[0].ulLoopStart;
|
||||
waveformat[mSampleID].loopend = mSample[mSampleID].mWaveSample.loop[0].ulLoopStart +
|
||||
mSample[mSampleID].mWaveSample.loop[0].ulLoopLength - 1;
|
||||
}
|
||||
}
|
||||
else if (!FMOD_strncmp(parentchunk, "rgn ", 4))
|
||||
{
|
||||
result = mFile->read(&mInstrument[mInstrumentID].mRegion[mRegionID].mWaveSample, 1, size, 0);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifdef PLATFORM_ENDIAN_BIG
|
||||
mInstrument[mInstrumentID].mRegion[mRegionID].mWaveSample.cbSize = FMOD_SWAPENDIAN_DWORD(mInstrument[mInstrumentID].mRegion[mRegionID].mWaveSample.cbSize);
|
||||
mInstrument[mInstrumentID].mRegion[mRegionID].mWaveSample.usUnityNote = FMOD_SWAPENDIAN_WORD(mInstrument[mInstrumentID].mRegion[mRegionID].mWaveSample.usUnityNote);
|
||||
mInstrument[mInstrumentID].mRegion[mRegionID].mWaveSample.sFineTune = FMOD_SWAPENDIAN_WORD(mInstrument[mInstrumentID].mRegion[mRegionID].mWaveSample.sFineTune);
|
||||
mInstrument[mInstrumentID].mRegion[mRegionID].mWaveSample.lAttenuation = FMOD_SWAPENDIAN_DWORD(mInstrument[mInstrumentID].mRegion[mRegionID].mWaveSample.lAttenuation);
|
||||
mInstrument[mInstrumentID].mRegion[mRegionID].mWaveSample.fulOptions = FMOD_SWAPENDIAN_DWORD(mInstrument[mInstrumentID].mRegion[mRegionID].mWaveSample.fulOptions);
|
||||
|
||||
if (mInstrument[mInstrumentID].mRegion[mRegionID].mWaveSample.cSampleLoops)
|
||||
{
|
||||
mInstrument[mInstrumentID].mRegion[mRegionID].mWaveSample.loop[0].cbSize = FMOD_SWAPENDIAN_DWORD(mInstrument[mInstrumentID].mRegion[mRegionID].mWaveSample.loop[0].cbSize);
|
||||
mInstrument[mInstrumentID].mRegion[mRegionID].mWaveSample.loop[0].ulLoopType = FMOD_SWAPENDIAN_DWORD(mInstrument[mInstrumentID].mRegion[mRegionID].mWaveSample.loop[0].ulLoopType);
|
||||
mInstrument[mInstrumentID].mRegion[mRegionID].mWaveSample.loop[0].ulLoopStart = FMOD_SWAPENDIAN_DWORD(mInstrument[mInstrumentID].mRegion[mRegionID].mWaveSample.loop[0].ulLoopStart);
|
||||
mInstrument[mInstrumentID].mRegion[mRegionID].mWaveSample.loop[0].ulLoopLength = FMOD_SWAPENDIAN_DWORD(mInstrument[mInstrumentID].mRegion[mRegionID].mWaveSample.loop[0].ulLoopLength);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
else if (!FMOD_strncmp((const char *)chunk.id, "wlnk", 4))
|
||||
{
|
||||
result = mFile->read(&mInstrument[mInstrumentID].mRegion[mRegionID].mWaveLink, 1, sizeof(DLS_WAVELINK), 0);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifdef PLATFORM_ENDIAN_BIG
|
||||
mInstrument[mInstrumentID].mRegion[mRegionID].mWaveLink.fusOptions = FMOD_SWAPENDIAN_WORD(mInstrument[mInstrumentID].mRegion[mRegionID].mWaveLink.fusOptions);
|
||||
mInstrument[mInstrumentID].mRegion[mRegionID].mWaveLink.usPhaseGroup = FMOD_SWAPENDIAN_WORD(mInstrument[mInstrumentID].mRegion[mRegionID].mWaveLink.usPhaseGroup);
|
||||
mInstrument[mInstrumentID].mRegion[mRegionID].mWaveLink.ulChannel = FMOD_SWAPENDIAN_DWORD(mInstrument[mInstrumentID].mRegion[mRegionID].mWaveLink.ulChannel);
|
||||
mInstrument[mInstrumentID].mRegion[mRegionID].mWaveLink.ulTableIndex = FMOD_SWAPENDIAN_DWORD(mInstrument[mInstrumentID].mRegion[mRegionID].mWaveLink.ulTableIndex);
|
||||
#endif
|
||||
}
|
||||
else if (!FMOD_strncmp((const char *)chunk.id, "art1", 4))
|
||||
{
|
||||
struct
|
||||
{
|
||||
unsigned int cbSize;
|
||||
unsigned int cConnectionBlocks;
|
||||
} articulator;
|
||||
|
||||
result = mFile->read(&articulator, 1, sizeof(articulator), 0);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifdef PLATFORM_ENDIAN_BIG
|
||||
articulator.cbSize = FMOD_SWAPENDIAN_DWORD(articulator.cbSize);
|
||||
articulator.cConnectionBlocks = FMOD_SWAPENDIAN_DWORD(articulator.cConnectionBlocks);
|
||||
#endif
|
||||
|
||||
if (articulator.cbSize > sizeof(articulator))
|
||||
{
|
||||
mFile->seek(articulator.cbSize - sizeof(articulator), SEEK_CUR);
|
||||
}
|
||||
|
||||
if (mRegionID < mInstrument[mInstrumentID].mHeader.cRegions)
|
||||
{
|
||||
mInstrument[mInstrumentID].mRegion[mRegionID].mConnectionBlock = (DLS_CONNECTIONBLOCK *)FMOD_Memory_Calloc(sizeof(DLS_CONNECTIONBLOCK) * articulator.cConnectionBlocks);
|
||||
if (!mInstrument[mInstrumentID].mRegion[mRegionID].mConnectionBlock)
|
||||
{
|
||||
return FMOD_ERR_MEMORY;
|
||||
}
|
||||
|
||||
mInstrument[mInstrumentID].mRegion[mRegionID].mNumConnectionBlocks = articulator.cConnectionBlocks;
|
||||
|
||||
result = mFile->read(mInstrument[mInstrumentID].mRegion[mRegionID].mConnectionBlock, 1, sizeof(DLS_CONNECTIONBLOCK) * articulator.cConnectionBlocks, 0);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifdef PLATFORM_ENDIAN_BIG
|
||||
{
|
||||
unsigned int count;
|
||||
|
||||
for (count = 0; count < articulator.cConnectionBlocks; count++)
|
||||
{
|
||||
mInstrument[mInstrumentID].mRegion[mRegionID].mConnectionBlock[count].usSource = FMOD_SWAPENDIAN_WORD(mInstrument[mInstrumentID].mRegion[mRegionID].mConnectionBlock[count].usSource);
|
||||
mInstrument[mInstrumentID].mRegion[mRegionID].mConnectionBlock[count].usControl = FMOD_SWAPENDIAN_WORD(mInstrument[mInstrumentID].mRegion[mRegionID].mConnectionBlock[count].usControl);
|
||||
mInstrument[mInstrumentID].mRegion[mRegionID].mConnectionBlock[count].usDestination = FMOD_SWAPENDIAN_WORD(mInstrument[mInstrumentID].mRegion[mRegionID].mConnectionBlock[count].usDestination);
|
||||
mInstrument[mInstrumentID].mRegion[mRegionID].mConnectionBlock[count].usTransform = FMOD_SWAPENDIAN_WORD(mInstrument[mInstrumentID].mRegion[mRegionID].mConnectionBlock[count].usTransform);
|
||||
mInstrument[mInstrumentID].mRegion[mRegionID].mConnectionBlock[count].lScale = FMOD_SWAPENDIAN_DWORD(mInstrument[mInstrumentID].mRegion[mRegionID].mConnectionBlock[count].lScale);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
mInstrument[mInstrumentID].mConnectionBlock = (DLS_CONNECTIONBLOCK *)FMOD_Memory_Calloc(sizeof(DLS_CONNECTIONBLOCK) * articulator.cConnectionBlocks);
|
||||
if (!mInstrument[mInstrumentID].mConnectionBlock)
|
||||
{
|
||||
return FMOD_ERR_MEMORY;
|
||||
}
|
||||
|
||||
mInstrument[mInstrumentID].mNumConnectionBlocks = articulator.cConnectionBlocks;
|
||||
|
||||
result = mFile->read(mInstrument[mInstrumentID].mConnectionBlock, 1, sizeof(DLS_CONNECTIONBLOCK) * articulator.cConnectionBlocks, 0);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifdef PLATFORM_ENDIAN_BIG
|
||||
unsigned int count;
|
||||
|
||||
for (count = 0; count < articulator.cConnectionBlocks; count++)
|
||||
{
|
||||
mInstrument[mInstrumentID].mConnectionBlock[count].usSource = FMOD_SWAPENDIAN_WORD(mInstrument[mInstrumentID].mConnectionBlock[count].usSource);
|
||||
mInstrument[mInstrumentID].mConnectionBlock[count].usControl = FMOD_SWAPENDIAN_WORD(mInstrument[mInstrumentID].mConnectionBlock[count].usControl);
|
||||
mInstrument[mInstrumentID].mConnectionBlock[count].usDestination = FMOD_SWAPENDIAN_WORD(mInstrument[mInstrumentID].mConnectionBlock[count].usDestination);
|
||||
mInstrument[mInstrumentID].mConnectionBlock[count].usTransform = FMOD_SWAPENDIAN_WORD(mInstrument[mInstrumentID].mConnectionBlock[count].usTransform);
|
||||
mInstrument[mInstrumentID].mConnectionBlock[count].lScale = FMOD_SWAPENDIAN_DWORD(mInstrument[mInstrumentID].mConnectionBlock[count].lScale);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
/*
|
||||
FORMAT CHUNK
|
||||
*/
|
||||
else if (!FMOD_strncmp((const char *)chunk.id, "fmt ", 4))
|
||||
{
|
||||
WAVE_FORMATEXTENSIBLE srcformat;
|
||||
unsigned int size = chunk.size;
|
||||
|
||||
/* Reduced allocs here and used a local instance of waveformatextensible instead */
|
||||
if (size > sizeof(WAVE_FORMATEXTENSIBLE))
|
||||
{
|
||||
size = sizeof(WAVE_FORMATEXTENSIBLE);
|
||||
}
|
||||
|
||||
FMOD_memset(&srcformat, 0, sizeof(WAVE_FORMATEXTENSIBLE));
|
||||
result = mFile->read(&srcformat, 1, size, 0);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
if (chunk.size > sizeof(WAVE_FORMATEXTENSIBLE))
|
||||
{
|
||||
result = mFile->seek(chunk.size - sizeof(WAVE_FORMATEXTENSIBLE), SEEK_CUR);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef PLATFORM_ENDIAN_BIG
|
||||
srcformat.Format.wFormatTag = FMOD_SWAPENDIAN_WORD (srcformat.Format.wFormatTag);
|
||||
srcformat.Format.nChannels = FMOD_SWAPENDIAN_WORD (srcformat.Format.nChannels);
|
||||
srcformat.Format.nSamplesPerSec = FMOD_SWAPENDIAN_DWORD(srcformat.Format.nSamplesPerSec);
|
||||
srcformat.Format.nAvgBytesPerSec = FMOD_SWAPENDIAN_DWORD(srcformat.Format.nAvgBytesPerSec);
|
||||
srcformat.Format.nBlockAlign = FMOD_SWAPENDIAN_WORD (srcformat.Format.nBlockAlign);
|
||||
srcformat.Format.wBitsPerSample = FMOD_SWAPENDIAN_WORD (srcformat.Format.wBitsPerSample);
|
||||
srcformat.Format.cbSize = FMOD_SWAPENDIAN_WORD (srcformat.Format.cbSize);
|
||||
srcformat.Samples.wValidBitsPerSample = FMOD_SWAPENDIAN_WORD (srcformat.Samples.wValidBitsPerSample);
|
||||
srcformat.dwChannelMask = FMOD_SWAPENDIAN_DWORD(srcformat.dwChannelMask);
|
||||
#endif
|
||||
|
||||
switch (srcformat.Format.wBitsPerSample)
|
||||
{
|
||||
case 4:
|
||||
{
|
||||
if (srcformat.Format.wFormatTag == 0x6666)
|
||||
{
|
||||
waveformat[mSampleID].format = FMOD_SOUND_FORMAT_VAG;
|
||||
}
|
||||
else if (srcformat.Format.wFormatTag == 0x7777)
|
||||
{
|
||||
waveformat[mSampleID].format = FMOD_SOUND_FORMAT_GCADPCM;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 8:
|
||||
{
|
||||
waveformat[mSampleID].format = FMOD_SOUND_FORMAT_PCM8;
|
||||
break;
|
||||
}
|
||||
case 16:
|
||||
{
|
||||
waveformat[mSampleID].format = FMOD_SOUND_FORMAT_PCM16;
|
||||
break;
|
||||
}
|
||||
case 24:
|
||||
{
|
||||
waveformat[mSampleID].format = FMOD_SOUND_FORMAT_PCM24;
|
||||
break;
|
||||
}
|
||||
case 32:
|
||||
{
|
||||
if (srcformat.Format.wFormatTag == WAVE_FORMAT_PCM)
|
||||
{
|
||||
waveformat[mSampleID].format = FMOD_SOUND_FORMAT_PCM32;
|
||||
}
|
||||
else if (srcformat.Format.wFormatTag == WAVE_FORMAT_IEEE_FLOAT)
|
||||
{
|
||||
waveformat[mSampleID].format = FMOD_SOUND_FORMAT_PCMFLOAT;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
waveformat[mSampleID].channels = srcformat.Format.nChannels;
|
||||
waveformat[mSampleID].frequency = srcformat.Format.nSamplesPerSec;
|
||||
waveformat[mSampleID].blockalign = srcformat.Format.nBlockAlign;
|
||||
}
|
||||
/*
|
||||
DATA CHUNK
|
||||
*/
|
||||
else if (!FMOD_strncmp((const char *)chunk.id, "data", 4))
|
||||
{
|
||||
SoundI::getSamplesFromBytes(chunk.size, &waveformat[mSampleID].lengthpcm, waveformat[mSampleID].channels, waveformat[mSampleID].format);
|
||||
|
||||
result = mFile->tell(&mSample[mSampleID].mDataOffset);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
}
|
||||
else if (!FMOD_strncmp((const char *)chunk.id, "INAM", 4))
|
||||
{
|
||||
if (mInstrumentID < mNumInstruments)
|
||||
{
|
||||
FMOD_memset(mInstrument[mInstrumentID].mName, 0, FMOD_STRING_MAXNAMELEN);
|
||||
|
||||
result = mFile->read(mInstrument[mInstrumentID].mName, 1, chunk.size, 0);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
}
|
||||
else if (mSampleID < mNumSamples)
|
||||
{
|
||||
FMOD_memset(mSample[mSampleID].mName, 0, FMOD_STRING_MAXNAMELEN);
|
||||
|
||||
result = mFile->read(mSample[mSampleID].mName, 1, chunk.size, 0);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
FMOD_strncpy(waveformat[mSampleID].name, mSample[mSampleID].mName, FMOD_STRING_MAXNAMELEN);
|
||||
}
|
||||
}
|
||||
else if (!FMOD_strncmp((const char *)chunk.id, "IARL", 4) ||
|
||||
!FMOD_strncmp((const char *)chunk.id, "IART", 4) ||
|
||||
!FMOD_strncmp((const char *)chunk.id, "ICMS", 4) ||
|
||||
!FMOD_strncmp((const char *)chunk.id, "ICMT", 4) ||
|
||||
!FMOD_strncmp((const char *)chunk.id, "ICOP", 4) ||
|
||||
!FMOD_strncmp((const char *)chunk.id, "ICRD", 4) ||
|
||||
!FMOD_strncmp((const char *)chunk.id, "IENG", 4) ||
|
||||
!FMOD_strncmp((const char *)chunk.id, "IGNR", 4) ||
|
||||
!FMOD_strncmp((const char *)chunk.id, "IKEY", 4) ||
|
||||
!FMOD_strncmp((const char *)chunk.id, "IMED", 4) ||
|
||||
!FMOD_strncmp((const char *)chunk.id, "IPRD", 4) ||
|
||||
!FMOD_strncmp((const char *)chunk.id, "ISBJ", 4) ||
|
||||
!FMOD_strncmp((const char *)chunk.id, "ISFT", 4) ||
|
||||
!FMOD_strncmp((const char *)chunk.id, "ISRC", 4) ||
|
||||
!FMOD_strncmp((const char *)chunk.id, "ISRF", 4) ||
|
||||
!FMOD_strncmp((const char *)chunk.id, "ITCH", 4))
|
||||
{
|
||||
result = result;
|
||||
}
|
||||
else
|
||||
{
|
||||
mFile->seek(chunk.size, SEEK_CUR);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
offset += (chunk.size+sizeof(WAVE_CHUNK));
|
||||
fileoffset += (chunk.size+sizeof(WAVE_CHUNK));
|
||||
|
||||
if (chunk.size & 1)
|
||||
{
|
||||
offset++;
|
||||
fileoffset++;
|
||||
}
|
||||
|
||||
if (chunk.size < 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
//FLOG((FMOD_DEBUG_LEVEL_LOG, __FILE__, __LINE__, "CodecDLS::parseRIFF", "offset = %d / %d\n", offset, chunksize));
|
||||
|
||||
} while (offset < chunksize && offset > 0 && !done);
|
||||
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT CodecDLS::openInternal(FMOD_MODE usermode, FMOD_CREATESOUNDEXINFO *userexinfo)
|
||||
{
|
||||
FMOD_RESULT result = FMOD_OK;
|
||||
WAVE_CHUNK chunk;
|
||||
char dls[4];
|
||||
|
||||
init(FMOD_SOUND_TYPE_DLS);
|
||||
|
||||
FLOG((FMOD_DEBUG_LEVEL_LOG, __FILE__, __LINE__, "CodecDLS::openInternal", "attempting to open as DLS..\n"));
|
||||
|
||||
result = mFile->seek(0, SEEK_SET);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
mSrcDataOffset = 0;
|
||||
mNumInstruments = 0;
|
||||
mNumSamples = 0;
|
||||
|
||||
result = mFile->read(&chunk, 1, sizeof(WAVE_CHUNK), 0);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
if (FMOD_strncmp((const char *)chunk.id, "RIFF", 4))
|
||||
{
|
||||
return FMOD_ERR_FORMAT;
|
||||
}
|
||||
|
||||
result = mFile->read(dls, 1, 4, 0);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
if (FMOD_strncmp(dls, "DLS ", 4))
|
||||
{
|
||||
return FMOD_ERR_FORMAT;
|
||||
}
|
||||
|
||||
#ifdef PLATFORM_ENDIAN_BIG
|
||||
chunk.size = FMOD_SWAPENDIAN_DWORD(chunk.size);
|
||||
#endif
|
||||
|
||||
mSrcDataOffset = 0;
|
||||
mSampleID = 0;
|
||||
|
||||
result = parseChunk(dls, chunk.size);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
if (mNumInstruments <= 0)
|
||||
{
|
||||
return FMOD_ERR_FORMAT;
|
||||
}
|
||||
|
||||
numsubsounds = mNumSamples;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT CodecDLS::closeInternal()
|
||||
{
|
||||
if (waveformat)
|
||||
{
|
||||
FMOD_Memory_Free(waveformat);
|
||||
waveformat = 0;
|
||||
}
|
||||
|
||||
if (mInstrument)
|
||||
{
|
||||
int count;
|
||||
|
||||
for (count = 0; count < mNumInstruments; count++)
|
||||
{
|
||||
if (mInstrument[count].mRegion)
|
||||
{
|
||||
unsigned int region;
|
||||
|
||||
/*
|
||||
Look for special drum articulators.
|
||||
*/
|
||||
for (region = 0; region < mInstrument[count].mHeader.cRegions; region++)
|
||||
{
|
||||
if (mInstrument[count].mRegion[region].mConnectionBlock)
|
||||
{
|
||||
FMOD_Memory_Free(mInstrument[count].mRegion[region].mConnectionBlock);
|
||||
}
|
||||
}
|
||||
|
||||
FMOD_Memory_Free(mInstrument[count].mRegion);
|
||||
}
|
||||
if (mInstrument[count].mConnectionBlock)
|
||||
{
|
||||
FMOD_Memory_Free(mInstrument[count].mConnectionBlock);
|
||||
}
|
||||
}
|
||||
|
||||
FMOD_Memory_Free(mInstrument);
|
||||
mInstrument = 0;
|
||||
}
|
||||
|
||||
if (mSample)
|
||||
{
|
||||
FMOD_Memory_Free(mSample);
|
||||
mSample = 0;
|
||||
}
|
||||
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT CodecDLS::readInternal(void *buffer, unsigned int sizebytes, unsigned int *bytesread)
|
||||
{
|
||||
FMOD_RESULT result = FMOD_OK;
|
||||
|
||||
result = mFile->read(buffer, 1, sizebytes, bytesread);
|
||||
if (result != FMOD_OK && result != FMOD_ERR_FILE_EOF)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
PCM8 is stored in unsigned 8-bit, so convert it to signed 8-bit for FMOD
|
||||
*/
|
||||
if (waveformat[mCurrentIndex].format == FMOD_SOUND_FORMAT_PCM8)
|
||||
{
|
||||
unsigned char *wptr = (unsigned char *)buffer;
|
||||
|
||||
for (unsigned int count = 0; count < *bytesread; count++)
|
||||
{
|
||||
*wptr++ ^= 128;
|
||||
}
|
||||
}
|
||||
else /* Must be PCM16 */
|
||||
{
|
||||
#ifdef PLATFORM_ENDIAN_BIG
|
||||
{
|
||||
signed short *wptr = (signed short *)buffer;
|
||||
|
||||
for (unsigned int count = 0; count < *bytesread >> 1; count++)
|
||||
{
|
||||
wptr[count] = FMOD_SWAPENDIAN_WORD(wptr[count]);
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT CodecDLS::setPositionInternal(int subsound, unsigned int position, FMOD_TIMEUNIT postype)
|
||||
{
|
||||
FMOD_RESULT result = FMOD_OK;
|
||||
|
||||
if (subsound < 0 || (numsubsounds && subsound >= numsubsounds))
|
||||
{
|
||||
return FMOD_ERR_INVALID_POSITION;
|
||||
}
|
||||
|
||||
if (mFile->mFlags & FMOD_FILE_SEEKABLE)
|
||||
{
|
||||
unsigned int posbytes;
|
||||
|
||||
if (subsound != mCurrentIndex)
|
||||
{
|
||||
mCurrentIndex = subsound;
|
||||
}
|
||||
|
||||
result = SoundI::getBytesFromSamples(position, &posbytes, waveformat[mCurrentIndex].channels, waveformat[mCurrentIndex].format);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
posbytes += mSample[mCurrentIndex].mDataOffset;
|
||||
|
||||
result = mFile->seek(posbytes, SEEK_SET);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT F_CALLBACK CodecDLS::openCallback(FMOD_CODEC_STATE *codec, FMOD_MODE usermode, FMOD_CREATESOUNDEXINFO *userexinfo)
|
||||
{
|
||||
CodecDLS *dls = (CodecDLS *)codec;
|
||||
|
||||
return dls->openInternal(usermode, userexinfo);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT F_CALLBACK CodecDLS::closeCallback(FMOD_CODEC_STATE *codec)
|
||||
{
|
||||
CodecDLS *dls = (CodecDLS *)codec;
|
||||
|
||||
return dls->closeInternal();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT F_CALLBACK CodecDLS::readCallback(FMOD_CODEC_STATE *codec, void *buffer, unsigned int sizebytes, unsigned int *bytesread)
|
||||
{
|
||||
CodecDLS *dls = (CodecDLS *)codec;
|
||||
|
||||
return dls->readInternal(buffer, sizebytes, bytesread);
|
||||
}
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT F_CALLBACK CodecDLS::setPositionCallback(FMOD_CODEC_STATE *codec, int subsound, unsigned int position, FMOD_TIMEUNIT postype)
|
||||
{
|
||||
CodecDLS *dls = (CodecDLS *)codec;
|
||||
|
||||
return dls->setPositionInternal(subsound, position, postype);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
252
src/fmod_codec_dls.h
Executable file
252
src/fmod_codec_dls.h
Executable file
|
|
@ -0,0 +1,252 @@
|
|||
#ifndef _FMOD_CODEC_DLS_H
|
||||
#define _FMOD_CODEC_DLS_H
|
||||
|
||||
#include "fmod_settings.h"
|
||||
|
||||
#ifdef FMOD_SUPPORT_DLS
|
||||
|
||||
#include "fmod_codeci.h"
|
||||
|
||||
namespace FMOD
|
||||
{
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Articulation connection graph definitions
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Generic Sources
|
||||
#define CONN_SRC_NONE 0x0000
|
||||
#define CONN_SRC_LFO 0x0001
|
||||
#define CONN_SRC_KEYONVELOCITY 0x0002
|
||||
#define CONN_SRC_KEYNUMBER 0x0003
|
||||
#define CONN_SRC_EG1 0x0004
|
||||
#define CONN_SRC_EG2 0x0005
|
||||
#define CONN_SRC_PITCHWHEEL 0x0006
|
||||
|
||||
// Midi Controllers 0-127
|
||||
#define CONN_SRC_CC1 0x0081 // mod wheel
|
||||
#define CONN_SRC_CC7 0x0087 // Channel volume
|
||||
#define CONN_SRC_CC10 0x008a // Pan
|
||||
#define CONN_SRC_CC11 0x008b // Expression.
|
||||
|
||||
// Generic Destinations
|
||||
#define CONN_DST_NONE 0x0000
|
||||
#define CONN_DST_ATTENUATION 0x0001
|
||||
#define CONN_DST_RESERVED 0x0002
|
||||
#define CONN_DST_PITCH 0x0003
|
||||
#define CONN_DST_PAN 0x0004
|
||||
|
||||
// LFO Destinations
|
||||
#define CONN_DST_LFO_FREQUENCY 0x0104
|
||||
#define CONN_DST_LFO_STARTDELAY 0x0105
|
||||
|
||||
// EG1 Destinations
|
||||
#define CONN_DST_EG1_ATTACKTIME 0x0206
|
||||
#define CONN_DST_EG1_DECAYTIME 0x0207
|
||||
#define CONN_DST_EG1_RESERVED 0x0208
|
||||
#define CONN_DST_EG1_RELEASETIME 0x0209
|
||||
#define CONN_DST_EG1_SUSTAINLEVEL 0x020a
|
||||
|
||||
// EG2 Destinations
|
||||
#define CONN_DST_EG2_ATTACKTIME 0x030a
|
||||
#define CONN_DST_EG2_DECAYTIME 0x030b
|
||||
#define CONN_DST_EG2_RESERVED 0x030c
|
||||
#define CONN_DST_EG2_RELEASETIME 0x030d
|
||||
#define CONN_DST_EG2_SUSTAINLEVEL 0x030e
|
||||
|
||||
// Envelope transform type
|
||||
#define CONN_TRN_NONE 0x0000
|
||||
#define CONN_TRN_CONCAVE 0x0001
|
||||
|
||||
#define F_RGN_OPTION_SELFNONEXCLUSIVE 0x0001
|
||||
|
||||
typedef enum
|
||||
{
|
||||
CONN_SRC_FLAG_NONE = 0x0001,
|
||||
CONN_SRC_FLAG_LFO = 0x0002,
|
||||
CONN_SRC_FLAG_KEYONVELOCITY = 0x0004,
|
||||
CONN_SRC_FLAG_KEYNUMBER = 0x0008,
|
||||
CONN_SRC_FLAG_EG1 = 0x0010,
|
||||
CONN_SRC_FLAG_EG2 = 0x0020,
|
||||
CONN_SRC_FLAG_PITCHWHEEL = 0x0040,
|
||||
CONN_SRC_FLAG_MODWHEEL = 0x0080,
|
||||
CONN_SRC_FLAG_CHANNELVOL = 0x0100,
|
||||
CONN_SRC_FLAG_PAN = 0x0200,
|
||||
CONN_SRC_FLAG_EXPRESSION = 0x0400
|
||||
} CONN_SRC_FLAGS;
|
||||
|
||||
#define CONN_SRC_FLAG_COMMON (CONN_SRC_FLAGS)(CONN_SRC_FLAG_NONE | \
|
||||
CONN_SRC_FLAG_KEYONVELOCITY | \
|
||||
CONN_SRC_FLAG_KEYNUMBER | \
|
||||
CONN_SRC_FLAG_PITCHWHEEL | \
|
||||
CONN_SRC_FLAG_MODWHEEL | \
|
||||
CONN_SRC_FLAG_CHANNELVOL | \
|
||||
CONN_SRC_FLAG_PAN | \
|
||||
CONN_SRC_FLAG_EXPRESSION)
|
||||
|
||||
#ifdef FMOD_SUPPORT_PRAGMAPACK
|
||||
#pragma pack(1)
|
||||
#endif
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned int ulBank FMOD_PACKED_INTERNAL;
|
||||
unsigned int ulInstrument FMOD_PACKED_INTERNAL;
|
||||
} FMOD_PACKED DLS_MIDILOCALE;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned int cRegions FMOD_PACKED_INTERNAL;
|
||||
DLS_MIDILOCALE Locale FMOD_PACKED_INTERNAL;
|
||||
} FMOD_PACKED DLS_INSTRUMENTHEADER;
|
||||
|
||||
|
||||
typedef struct _RGNRANGE
|
||||
{
|
||||
unsigned short usLow FMOD_PACKED_INTERNAL; /* Low Value of Range */
|
||||
unsigned short usHigh FMOD_PACKED_INTERNAL; /* High Value of Range*/
|
||||
} FMOD_PACKED DLS_RGNRANGE;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
DLS_RGNRANGE RangeKey FMOD_PACKED_INTERNAL;
|
||||
DLS_RGNRANGE RangeVelocity FMOD_PACKED_INTERNAL;
|
||||
unsigned short fusOptions FMOD_PACKED_INTERNAL;
|
||||
unsigned short usKeyGroup FMOD_PACKED_INTERNAL;
|
||||
} FMOD_PACKED DLS_REGIONHEADER;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned short fusOptions FMOD_PACKED_INTERNAL;
|
||||
unsigned short usPhaseGroup FMOD_PACKED_INTERNAL;
|
||||
unsigned int ulChannel FMOD_PACKED_INTERNAL;
|
||||
unsigned int ulTableIndex FMOD_PACKED_INTERNAL;
|
||||
} FMOD_PACKED DLS_WAVELINK;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned int cbSize FMOD_PACKED_INTERNAL;
|
||||
unsigned int ulLoopType FMOD_PACKED_INTERNAL;
|
||||
unsigned int ulLoopStart FMOD_PACKED_INTERNAL;
|
||||
unsigned int ulLoopLength FMOD_PACKED_INTERNAL;
|
||||
} FMOD_PACKED DLS_WAVESAMPLELOOP;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned int cbSize FMOD_PACKED_INTERNAL;
|
||||
unsigned short usUnityNote FMOD_PACKED_INTERNAL;
|
||||
signed short sFineTune FMOD_PACKED_INTERNAL;
|
||||
signed int lAttenuation FMOD_PACKED_INTERNAL;
|
||||
unsigned int fulOptions FMOD_PACKED_INTERNAL;
|
||||
unsigned int cSampleLoops FMOD_PACKED_INTERNAL;
|
||||
DLS_WAVESAMPLELOOP loop[1] FMOD_PACKED_INTERNAL;
|
||||
} FMOD_PACKED DLS_WAVESAMPLE;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned short usSource FMOD_PACKED_INTERNAL;
|
||||
unsigned short usControl FMOD_PACKED_INTERNAL;
|
||||
unsigned short usDestination FMOD_PACKED_INTERNAL;
|
||||
unsigned short usTransform FMOD_PACKED_INTERNAL;
|
||||
int lScale FMOD_PACKED_INTERNAL;
|
||||
} FMOD_PACKED DLS_CONNECTIONBLOCK;
|
||||
|
||||
#ifdef FMOD_SUPPORT_PRAGMAPACK
|
||||
#ifdef CODEWARRIOR
|
||||
#pragma pack(0)
|
||||
#else
|
||||
#pragma pack()
|
||||
#endif
|
||||
#endif
|
||||
|
||||
typedef struct
|
||||
{
|
||||
float mTime;
|
||||
float mSrcValue, mDestValue;
|
||||
} CodecDLSEnvelopePoint;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
CODEC_DLS_ENVPOINT_ATTACK,
|
||||
CODEC_DLS_ENVPOINT_DECAY,
|
||||
CODEC_DLS_ENVPOINT_RELEASE,
|
||||
CODEC_DLS_ENVPOINT_MAX
|
||||
} CODEC_DLS_ENVPOINT;
|
||||
|
||||
class CodecDLSEnvelope
|
||||
{
|
||||
public:
|
||||
|
||||
CodecDLSEnvelopePoint mPoint[CODEC_DLS_ENVPOINT_MAX]; /* Attack, decay, release. Sustain is the point decay ends. */
|
||||
|
||||
CODEC_DLS_ENVPOINT mPosition;
|
||||
float mTime;
|
||||
float mSustain;
|
||||
float mRange;
|
||||
bool mActive;
|
||||
};
|
||||
|
||||
|
||||
class CodecDLSRegion
|
||||
{
|
||||
public:
|
||||
DLS_REGIONHEADER mRegionHeader;
|
||||
DLS_WAVESAMPLE mWaveSample;
|
||||
DLS_WAVELINK mWaveLink;
|
||||
int mNumConnectionBlocks;
|
||||
DLS_CONNECTIONBLOCK *mConnectionBlock;
|
||||
};
|
||||
|
||||
class CodecDLSInstrument
|
||||
{
|
||||
public:
|
||||
char mName[FMOD_STRING_MAXNAMELEN];
|
||||
DLS_INSTRUMENTHEADER mHeader;
|
||||
CodecDLSRegion *mRegion;
|
||||
int mNumConnectionBlocks;
|
||||
DLS_CONNECTIONBLOCK *mConnectionBlock;
|
||||
};
|
||||
|
||||
class CodecDLSSample
|
||||
{
|
||||
public:
|
||||
char mName[FMOD_STRING_MAXNAMELEN];
|
||||
unsigned int mDataOffset;
|
||||
DLS_WAVESAMPLE mWaveSample;
|
||||
};
|
||||
|
||||
class CodecDLS : public Codec
|
||||
{
|
||||
public:
|
||||
|
||||
int mNumInstruments;
|
||||
int mInstrumentID;
|
||||
CodecDLSInstrument *mInstrument;
|
||||
|
||||
int mNumSamples;
|
||||
int mSampleID;
|
||||
CodecDLSSample *mSample;
|
||||
|
||||
int mCurrentIndex; /* current DLS index */
|
||||
unsigned int mRegionID; /* This should always be 0-15 with melodic instruments. */
|
||||
|
||||
FMOD_RESULT parseChunk(char *parentchunk, unsigned int chunksize);
|
||||
|
||||
FMOD_RESULT openInternal(FMOD_MODE usermode, FMOD_CREATESOUNDEXINFO *userexinfo);
|
||||
FMOD_RESULT closeInternal();
|
||||
FMOD_RESULT readInternal(void *buffer, unsigned int size, unsigned int *read);
|
||||
FMOD_RESULT setPositionInternal(int subsound, unsigned int position, FMOD_TIMEUNIT postype);
|
||||
|
||||
public:
|
||||
|
||||
static FMOD_RESULT F_CALLBACK openCallback(FMOD_CODEC_STATE *codec, FMOD_MODE usermode, FMOD_CREATESOUNDEXINFO *userexinfo);
|
||||
static FMOD_RESULT F_CALLBACK closeCallback(FMOD_CODEC_STATE *codec);
|
||||
static FMOD_RESULT F_CALLBACK readCallback(FMOD_CODEC_STATE *codec, void *buffer, unsigned int sizebytes, unsigned int *bytesread);
|
||||
static FMOD_RESULT F_CALLBACK setPositionCallback(FMOD_CODEC_STATE *codec, int subsound, unsigned int position, FMOD_TIMEUNIT postype);
|
||||
|
||||
static FMOD_CODEC_DESCRIPTION_EX *getDescriptionEx();
|
||||
};
|
||||
}
|
||||
|
||||
#endif /* FMOD_SUPPORT_DLS */
|
||||
|
||||
#endif
|
||||
|
||||
787
src/fmod_codec_flac.cpp
Executable file
787
src/fmod_codec_flac.cpp
Executable file
|
|
@ -0,0 +1,787 @@
|
|||
#include "fmod_settings.h"
|
||||
|
||||
#ifdef FMOD_SUPPORT_FLAC
|
||||
|
||||
#include "fmod.h"
|
||||
#include "fmod_codec_flac.h"
|
||||
#include "fmod_debug.h"
|
||||
#include "fmod_file.h"
|
||||
#include "fmod_metadata.h"
|
||||
#include "fmod_soundi.h"
|
||||
#include "fmod_string.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
#define FMOD_FLAC_MAX_BLOCKSIZE 8192 // Theoretically, this should be 65536 but that's way too much memory and
|
||||
// hopefully we won't get blocks that big in real life
|
||||
|
||||
|
||||
#ifdef PLUGIN_EXPORTS
|
||||
extern "C"
|
||||
{
|
||||
void * FMOD_FLAC_Malloc(void *context, int size)
|
||||
{
|
||||
void *mem = FMOD_Memory_Alloc(size);
|
||||
|
||||
if (mem)
|
||||
{
|
||||
FMOD::CodecFLAC *flac = (FMOD::CodecFLAC *)context;
|
||||
|
||||
flac->mMemUsed += size;
|
||||
}
|
||||
|
||||
return mem;
|
||||
}
|
||||
void * FMOD_FLAC_Calloc(void *context, int count, int size)
|
||||
{
|
||||
void *mem = FMOD_Memory_Calloc(count * size);
|
||||
|
||||
if (mem)
|
||||
{
|
||||
FMOD::CodecFLAC *flac = (FMOD::CodecFLAC *)context;
|
||||
flac->mMemUsed += (count * size);
|
||||
}
|
||||
|
||||
return mem;
|
||||
}
|
||||
void * FMOD_FLAC_ReAlloc(void *context, void *ptr, int size)
|
||||
{
|
||||
void *mem;
|
||||
FMOD::CodecFLAC *flac = (FMOD::CodecFLAC *)context;
|
||||
|
||||
if (ptr)
|
||||
{
|
||||
FMOD::MemBlockHeader *block = (FMOD::MemBlockHeader *)ptr;
|
||||
|
||||
block--;
|
||||
|
||||
flac->mMemUsed -= block->mSize;
|
||||
}
|
||||
|
||||
mem = FMOD_Memory_ReAlloc(ptr, size);
|
||||
if (mem)
|
||||
{
|
||||
flac->mMemUsed += size;
|
||||
}
|
||||
|
||||
return mem;
|
||||
}
|
||||
void FMOD_FLAC_Free(void *context, void *ptr)
|
||||
{
|
||||
if (ptr)
|
||||
{
|
||||
FMOD::MemBlockHeader *block = (FMOD::MemBlockHeader *)ptr;
|
||||
FMOD::CodecFLAC *flac = (FMOD::CodecFLAC *)context;
|
||||
|
||||
block--;
|
||||
|
||||
flac->mMemUsed -= block->mSize;
|
||||
}
|
||||
|
||||
FMOD_Memory_Free(ptr);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace FMOD
|
||||
{
|
||||
|
||||
|
||||
FMOD_CODEC_DESCRIPTION_EX flaccodec;
|
||||
|
||||
|
||||
#ifdef PLUGIN_EXPORTS
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
FMODGetCodecDescription is mandatory for every fmod plugin. This is the symbol the registerplugin function searches for.
|
||||
Must be declared with F_API to make it export as stdcall.
|
||||
*/
|
||||
F_DECLSPEC F_DLLEXPORT FMOD_CODEC_DESCRIPTION_EX * F_API FMODGetCodecDescriptionEx()
|
||||
{
|
||||
return CodecFLAC::getDescriptionEx();
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* PLUGIN_EXPORTS */
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
static FLAC__StreamDecoderReadStatus FMOD_FLAC_ReadCallback(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data)
|
||||
{
|
||||
FMOD_RESULT result;
|
||||
unsigned int rd;
|
||||
CodecFLAC *codec;
|
||||
|
||||
codec = (CodecFLAC *)client_data;
|
||||
|
||||
result = codec->mFile->read(buffer, 1, (unsigned int)*bytes, &rd);
|
||||
*bytes = rd;
|
||||
|
||||
if (!*bytes)
|
||||
{
|
||||
return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
|
||||
}
|
||||
|
||||
return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
|
||||
}
|
||||
|
||||
|
||||
static FLAC__StreamDecoderWriteStatus FMOD_FLAC_WriteCallback(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data)
|
||||
{
|
||||
CodecFLAC *codec;
|
||||
int i, j;
|
||||
|
||||
codec = (CodecFLAC *)client_data;
|
||||
|
||||
if (codec->mPCMBuffer)
|
||||
{
|
||||
int blocksize = (frame->header.blocksize > FMOD_FLAC_MAX_BLOCKSIZE) ? FMOD_FLAC_MAX_BLOCKSIZE : frame->header.blocksize;
|
||||
|
||||
if (frame->header.bits_per_sample == 8)
|
||||
{
|
||||
signed char *dst = (signed char *)codec->mPCMBuffer;
|
||||
|
||||
for (i = 0; i < blocksize; i++)
|
||||
{
|
||||
for (j=0; j < (int)frame->header.channels; j++)
|
||||
{
|
||||
*dst++ = ((signed char)buffer[j][i]);
|
||||
}
|
||||
}
|
||||
|
||||
codec->mPCMBufferFilledBytes = blocksize * frame->header.channels;
|
||||
}
|
||||
else if (frame->header.bits_per_sample == 16)
|
||||
{
|
||||
signed short *dst = (signed short *)codec->mPCMBuffer;
|
||||
|
||||
for (i=0; i < blocksize; i++)
|
||||
{
|
||||
for (j=0; j < (int)frame->header.channels; j++)
|
||||
{
|
||||
*dst++ = (signed short)buffer[j][i];
|
||||
}
|
||||
}
|
||||
|
||||
codec->mPCMBufferFilledBytes = blocksize * frame->header.channels * 2;
|
||||
}
|
||||
else if (frame->header.bits_per_sample == 24)
|
||||
{
|
||||
signed char *dst = (signed char *)codec->mPCMBuffer;
|
||||
|
||||
for (i = 0; i < blocksize; i++)
|
||||
{
|
||||
for (j = 0; j < (int)frame->header.channels; j++)
|
||||
{
|
||||
FMOD_memcpy(dst, &buffer[j][i], 3);
|
||||
dst += 3;
|
||||
}
|
||||
}
|
||||
|
||||
codec->mPCMBufferFilledBytes = blocksize * frame->header.channels * 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
//printf("Unhandled bitdepth %d\n", frame->header.bits_per_sample);
|
||||
}
|
||||
}
|
||||
|
||||
return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
|
||||
}
|
||||
|
||||
|
||||
static FLAC__StreamDecoderSeekStatus FMOD_FLAC_SeekCallback(const FLAC__StreamDecoder *decoder, FLAC__uint64 absolute_byte_offset, void *client_data)
|
||||
{
|
||||
CodecFLAC *codec;
|
||||
|
||||
codec = (CodecFLAC *)client_data;
|
||||
|
||||
if (codec->mFile->seek((int)absolute_byte_offset, SEEK_SET) == FMOD_OK)
|
||||
{
|
||||
return FLAC__STREAM_DECODER_SEEK_STATUS_OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
return FLAC__STREAM_DECODER_SEEK_STATUS_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static FLAC__StreamDecoderTellStatus FMOD_FLAC_TellCallback(const FLAC__StreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void *client_data)
|
||||
{
|
||||
unsigned int pos;
|
||||
CodecFLAC *codec;
|
||||
|
||||
codec = (CodecFLAC *)client_data;
|
||||
|
||||
if (codec->mFile->tell(&pos) == FMOD_OK)
|
||||
{
|
||||
*absolute_byte_offset = (FLAC__uint64)pos;
|
||||
return FLAC__STREAM_DECODER_TELL_STATUS_OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
return FLAC__STREAM_DECODER_TELL_STATUS_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static FLAC__StreamDecoderLengthStatus FMOD_FLAC_LengthCallback(const FLAC__StreamDecoder *decoder, FLAC__uint64 *stream_length, void *client_data)
|
||||
{
|
||||
unsigned int len;
|
||||
CodecFLAC *codec;
|
||||
|
||||
codec = (CodecFLAC *)client_data;
|
||||
|
||||
if (codec->mFile->getSize(&len) == FMOD_OK)
|
||||
{
|
||||
*stream_length = (FLAC__uint64)len;
|
||||
return FLAC__STREAM_DECODER_LENGTH_STATUS_OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
return FLAC__STREAM_DECODER_LENGTH_STATUS_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static FLAC__bool FMOD_FLAC_EofCallback(const FLAC__StreamDecoder *decoder, void *client_data)
|
||||
{
|
||||
unsigned int pos, len;
|
||||
CodecFLAC *codec;
|
||||
|
||||
codec = (CodecFLAC *)client_data;
|
||||
|
||||
codec->mFile->tell(&pos);
|
||||
codec->mFile->getSize(&len);
|
||||
|
||||
return (pos >= len);
|
||||
}
|
||||
|
||||
|
||||
static void FMOD_FLAC_ErrorCallback(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data)
|
||||
{
|
||||
CodecFLAC *codec;
|
||||
|
||||
codec = (CodecFLAC *)client_data;
|
||||
|
||||
switch (status)
|
||||
{
|
||||
/**< An error in the stream caused the decoder to lose synchronization. */
|
||||
case FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC :
|
||||
break;
|
||||
|
||||
/**< The decoder encountered a corrupted frame header. */
|
||||
case FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER :
|
||||
break;
|
||||
|
||||
case FLAC__STREAM_DECODER_ERROR_STATUS_FRAME_CRC_MISMATCH :
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void FMOD_FLAC_MetadataCallback(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data)
|
||||
{
|
||||
CodecFLAC *codec;
|
||||
|
||||
codec = (CodecFLAC *)client_data;
|
||||
|
||||
if (metadata->type == FLAC__METADATA_TYPE_STREAMINFO)
|
||||
{
|
||||
FMOD_RESULT result;
|
||||
|
||||
result = SoundI::getFormatFromBits(metadata->data.stream_info.bits_per_sample, &codec->waveformat[0].format);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return;
|
||||
}
|
||||
codec->waveformat[0].channels = metadata->data.stream_info.channels;
|
||||
codec->waveformat[0].frequency = metadata->data.stream_info.sample_rate;
|
||||
codec->waveformat[0].lengthpcm = (unsigned int)metadata->data.stream_info.total_samples;
|
||||
}
|
||||
else if (metadata->type == FLAC__METADATA_TYPE_VORBIS_COMMENT)
|
||||
{
|
||||
int i;
|
||||
char *name, *value, buf[4096];
|
||||
|
||||
for (i=0;i < (int)metadata->data.vorbis_comment.num_comments;i++)
|
||||
{
|
||||
if (metadata->data.vorbis_comment.comments[i].length > 4095)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
FMOD_memcpy(buf, metadata->data.vorbis_comment.comments[i].entry, metadata->data.vorbis_comment.comments[i].length);
|
||||
buf[metadata->data.vorbis_comment.comments[i].length] = 0;
|
||||
|
||||
name = buf;
|
||||
value = name;
|
||||
for (;value && (*value != '=');value++) ;
|
||||
*value++ = 0;
|
||||
|
||||
codec->metadata(codec, FMOD_TAGTYPE_VORBISCOMMENT, name, value, FMOD_strlen(value) + 1, FMOD_TAGDATATYPE_STRING, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_CODEC_DESCRIPTION_EX *CodecFLAC::getDescriptionEx()
|
||||
{
|
||||
FMOD_memset(&flaccodec, 0, sizeof(FMOD_CODEC_DESCRIPTION_EX));
|
||||
|
||||
flaccodec.name = "FMOD FLAC Codec";
|
||||
flaccodec.version = 0x00010100;
|
||||
flaccodec.timeunits = FMOD_TIMEUNIT_PCM;
|
||||
flaccodec.open = &CodecFLAC::openCallback;
|
||||
flaccodec.close = &CodecFLAC::closeCallback;
|
||||
flaccodec.read = &CodecFLAC::readCallback;
|
||||
flaccodec.setposition = &CodecFLAC::setPositionCallback;
|
||||
|
||||
flaccodec.mType = FMOD_SOUND_TYPE_FLAC;
|
||||
flaccodec.mSize = sizeof(CodecFLAC);
|
||||
|
||||
return &flaccodec;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT CodecFLAC::openInternal(FMOD_MODE usermode, FMOD_CREATESOUNDEXINFO *userexinfo)
|
||||
{
|
||||
unsigned int rd;
|
||||
char header[4];
|
||||
FMOD_RESULT result = FMOD_OK;
|
||||
int bits;
|
||||
|
||||
init(FMOD_SOUND_TYPE_FLAC);
|
||||
|
||||
FLOG((FMOD_DEBUG_LEVEL_LOG, __FILE__, __LINE__, "CodecFLAC::openInternal", "attempting to open as FLAC..\n"));
|
||||
|
||||
result = mFile->seek(0, SEEK_SET);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
Quick format check
|
||||
*/
|
||||
result = mFile->read(header, 1, 4, &rd);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
if (rd != 4)
|
||||
{
|
||||
return FMOD_ERR_FILE_BAD;
|
||||
}
|
||||
|
||||
if ((header[0] == 'f') &&
|
||||
(header[1] == 'L') &&
|
||||
(header[2] == 'a') &&
|
||||
(header[3] == 'C'))
|
||||
{
|
||||
result = mFile->seek(0, SEEK_SET);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return FMOD_ERR_FORMAT;
|
||||
}
|
||||
|
||||
mDecoder = FLAC__stream_decoder_new();
|
||||
if (!mDecoder)
|
||||
{
|
||||
return FMOD_ERR_FILE_BAD;
|
||||
}
|
||||
|
||||
if (!FLAC__stream_decoder_set_md5_checking(mDecoder, false))
|
||||
{
|
||||
return FMOD_ERR_FILE_BAD;
|
||||
}
|
||||
|
||||
if (!FLAC__stream_decoder_set_metadata_respond(mDecoder, FLAC__METADATA_TYPE_VORBIS_COMMENT))
|
||||
{
|
||||
return FMOD_ERR_FILE_BAD;
|
||||
}
|
||||
|
||||
if (FLAC__stream_decoder_init_stream(this,
|
||||
mDecoder,
|
||||
FMOD_FLAC_ReadCallback,
|
||||
FMOD_FLAC_SeekCallback,
|
||||
FMOD_FLAC_TellCallback,
|
||||
FMOD_FLAC_LengthCallback,
|
||||
FMOD_FLAC_EofCallback,
|
||||
FMOD_FLAC_WriteCallback,
|
||||
FMOD_FLAC_MetadataCallback,
|
||||
FMOD_FLAC_ErrorCallback,
|
||||
this) != FLAC__STREAM_DECODER_INIT_STATUS_OK)
|
||||
{
|
||||
return FMOD_ERR_FILE_BAD;
|
||||
}
|
||||
|
||||
mWaveFormatMemory = (FMOD_CODEC_WAVEFORMAT *)FMOD_Memory_Calloc(sizeof(FMOD_CODEC_WAVEFORMAT));
|
||||
if (!mWaveFormatMemory)
|
||||
{
|
||||
return FMOD_ERR_MEMORY;
|
||||
}
|
||||
waveformat = mWaveFormatMemory;
|
||||
|
||||
/*
|
||||
Get the first block which is guaranteed to be a STREAMINFO metadata block
|
||||
*/
|
||||
FLAC__stream_decoder_process_until_end_of_metadata(this, mDecoder);
|
||||
|
||||
/*
|
||||
Get size of file in bytes
|
||||
*/
|
||||
result = mFile->getSize(&waveformat[0].lengthbytes);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
mSrcDataOffset = 0;
|
||||
|
||||
result = SoundI::getBitsFromFormat(waveformat[0].format, &bits);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
result = SoundI::getBytesFromSamples(FMOD_FLAC_MAX_BLOCKSIZE, &mPCMBufferLengthBytes, waveformat[0].channels, waveformat[0].format);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
if (mPCMBufferLengthBytes)
|
||||
{
|
||||
#ifdef PLATFORM_PS3
|
||||
|
||||
mPCMBufferMemory = (unsigned char *)FMOD_Memory_Calloc(mPCMBufferLengthBytes + 16);
|
||||
if (!mPCMBufferMemory)
|
||||
{
|
||||
return FMOD_ERR_MEMORY;
|
||||
}
|
||||
mPCMBuffer = (unsigned char *)FMOD_ALIGNPOINTER(mPCMBufferMemory, 16);
|
||||
|
||||
#else
|
||||
|
||||
mPCMBufferMemory = (unsigned char *)FMOD_Memory_Calloc(mPCMBufferLengthBytes);
|
||||
if (!mPCMBufferMemory)
|
||||
{
|
||||
return FMOD_ERR_MEMORY;
|
||||
}
|
||||
mPCMBuffer = mPCMBufferMemory;
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
Fill out base class members, also pointing to or allocating storage for them.
|
||||
*/
|
||||
numsubsounds = 0;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT CodecFLAC::closeInternal()
|
||||
{
|
||||
if (mDecoder)
|
||||
{
|
||||
FLAC__stream_decoder_finish(this, mDecoder);
|
||||
FLAC__stream_decoder_delete(this, mDecoder);
|
||||
mDecoder = 0;
|
||||
}
|
||||
|
||||
if (mPCMBufferMemory)
|
||||
{
|
||||
FLOG((FMOD_DEBUG_LEVEL_LOG, __FILE__, __LINE__, "CodecFLAC::release", "Free PCM Buffer\n"));
|
||||
|
||||
FMOD_Memory_Free(mPCMBufferMemory);
|
||||
mPCMBuffer = mPCMBufferMemory = 0;
|
||||
}
|
||||
mPCMBufferLengthBytes = 0;
|
||||
|
||||
if (mWaveFormatMemory)
|
||||
{
|
||||
FMOD_Memory_Free(mWaveFormatMemory);
|
||||
mWaveFormatMemory = 0;
|
||||
}
|
||||
|
||||
waveformat = 0;
|
||||
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT CodecFLAC::readInternal(void *buffer, unsigned int sizebytes, unsigned int *bytesread)
|
||||
{
|
||||
FMOD_RESULT result = FMOD_OK;
|
||||
FLAC__StreamDecoderState state;
|
||||
|
||||
if (!mDecoder)
|
||||
{
|
||||
return FMOD_ERR_INVALID_PARAM;
|
||||
}
|
||||
|
||||
// Only get a new frame if there isn't one ready and waiting
|
||||
if (!mFrameReady)
|
||||
{
|
||||
FLAC__stream_decoder_process_single(this, mDecoder);
|
||||
}
|
||||
|
||||
// These variables were already set directly via the FLAC Write Callback, but pass them
|
||||
// back here for consistency
|
||||
buffer = mPCMBuffer;
|
||||
*bytesread = mPCMBufferFilledBytes;
|
||||
mFrameReady = false;
|
||||
|
||||
state = FLAC__stream_decoder_get_state(mDecoder);
|
||||
if (state == FLAC__STREAM_DECODER_END_OF_STREAM)
|
||||
{
|
||||
*bytesread = 0;
|
||||
return FMOD_ERR_FILE_EOF;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT CodecFLAC::setPositionInternal(int subsound, unsigned int position, FMOD_TIMEUNIT postype)
|
||||
{
|
||||
if (!mDecoder)
|
||||
{
|
||||
return FMOD_ERR_INVALID_PARAM;
|
||||
}
|
||||
|
||||
if (mFile->mFlags & FMOD_FILE_SEEKABLE)
|
||||
{
|
||||
/*
|
||||
NOTE! I think there is a stack corruption in this function.
|
||||
previously there was an 'FMOD_RESULT result' variable that was stored in a register (esi)
|
||||
which was then pushed onto the stack before calling this function.
|
||||
When the stack was popped back into esi, the number was corrupted.
|
||||
*/
|
||||
if (!FLAC__stream_decoder_seek_absolute(this, mDecoder, position))
|
||||
{
|
||||
return FMOD_ERR_INTERNAL;
|
||||
}
|
||||
|
||||
// FLAC decoder seek will cause the sample at the given position to be written via the FLAC
|
||||
// Write Callback, so flag that data is ready so ReadInternal() will not overwrite the data
|
||||
mFrameReady = true;
|
||||
}
|
||||
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT F_CALLBACK CodecFLAC::openCallback(FMOD_CODEC_STATE *codec, FMOD_MODE usermode, FMOD_CREATESOUNDEXINFO *userexinfo)
|
||||
{
|
||||
CodecFLAC *flac = (CodecFLAC *)codec;
|
||||
|
||||
return flac->openInternal(usermode, userexinfo);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT F_CALLBACK CodecFLAC::closeCallback(FMOD_CODEC_STATE *codec)
|
||||
{
|
||||
CodecFLAC *flac = (CodecFLAC *)codec;
|
||||
|
||||
return flac->closeInternal();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT F_CALLBACK CodecFLAC::readCallback(FMOD_CODEC_STATE *codec, void *buffer, unsigned int sizebytes, unsigned int *bytesread)
|
||||
{
|
||||
CodecFLAC *flac = (CodecFLAC *)codec;
|
||||
|
||||
return flac->readInternal(buffer, sizebytes, bytesread);
|
||||
}
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT F_CALLBACK CodecFLAC::setPositionCallback(FMOD_CODEC_STATE *codec, int subsound, unsigned int position, FMOD_TIMEUNIT postype)
|
||||
{
|
||||
CodecFLAC *flac = (CodecFLAC *)codec;
|
||||
|
||||
return flac->setPositionInternal(subsound, position, postype);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
48
src/fmod_codec_flac.h
Executable file
48
src/fmod_codec_flac.h
Executable file
|
|
@ -0,0 +1,48 @@
|
|||
#ifndef _FMOD_CODEC_FLAC_H
|
||||
#define _FMOD_CODEC_FLAC_H
|
||||
|
||||
#include "fmod_settings.h"
|
||||
|
||||
#ifdef FMOD_SUPPORT_FLAC
|
||||
|
||||
#include "fmod_codeci.h"
|
||||
|
||||
#include "../lib/flac-1.2.1/include/FLAC/all.h"
|
||||
|
||||
namespace FMOD
|
||||
{
|
||||
class CodecFLAC : public Codec
|
||||
{
|
||||
DECLARE_MEMORYTRACKER_NONVIRTUAL
|
||||
|
||||
private:
|
||||
|
||||
FLAC__StreamDecoder *mDecoder;
|
||||
bool mFrameReady;
|
||||
|
||||
FMOD_RESULT openInternal(FMOD_MODE usermode, FMOD_CREATESOUNDEXINFO *userexinfo);
|
||||
FMOD_RESULT closeInternal();
|
||||
FMOD_RESULT readInternal(void *buffer, unsigned int size, unsigned int *read);
|
||||
FMOD_RESULT setPositionInternal(int subsound, unsigned int position, FMOD_TIMEUNIT postype);
|
||||
|
||||
public:
|
||||
|
||||
unsigned int mMemUsed;
|
||||
|
||||
static FMOD_RESULT F_CALLBACK openCallback(FMOD_CODEC_STATE *codec, FMOD_MODE usermode, FMOD_CREATESOUNDEXINFO *userexinfo);
|
||||
static FMOD_RESULT F_CALLBACK closeCallback(FMOD_CODEC_STATE *codec);
|
||||
static FMOD_RESULT F_CALLBACK readCallback(FMOD_CODEC_STATE *codec, void *buffer, unsigned int sizebytes, unsigned int *bytesread);
|
||||
static FMOD_RESULT F_CALLBACK setPositionCallback(FMOD_CODEC_STATE *codec, int subsound, unsigned int position, FMOD_TIMEUNIT postype);
|
||||
#ifdef FMOD_SUPPORT_MEMORYTRACKER
|
||||
static FMOD_RESULT F_CALLBACK getMemoryUsedCallback(FMOD_CODEC_STATE *codec, MemoryTracker *tracker);
|
||||
#endif
|
||||
|
||||
static FMOD_CODEC_DESCRIPTION_EX *getDescriptionEx();
|
||||
};
|
||||
}
|
||||
|
||||
#endif /* FMOD_SUPPORT_FLAC */
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
3764
src/fmod_codec_fsb.cpp
Executable file
3764
src/fmod_codec_fsb.cpp
Executable file
File diff suppressed because it is too large
Load diff
243
src/fmod_codec_fsb.h
Executable file
243
src/fmod_codec_fsb.h
Executable file
|
|
@ -0,0 +1,243 @@
|
|||
#ifndef _FMOD_CODEC_FSB_H
|
||||
#define _FMOD_CODEC_FSB_H
|
||||
|
||||
#include "fmod_settings.h"
|
||||
|
||||
#ifdef FMOD_SUPPORT_FSB
|
||||
|
||||
#include "fmod_codeci.h"
|
||||
#include "fmod_syncpoint.h"
|
||||
|
||||
#define FMOD_FSB_NAMELEN 30
|
||||
|
||||
#define FMOD_FSB_SOURCE_FORMAT 0x00000001 /* all samples stored in their original compressed format */
|
||||
#define FMOD_FSB_SOURCE_BASICHEADERS 0x00000002 /* samples should use the basic header structure */
|
||||
#define FMOD_FSB_SOURCE_ENCRYPTED 0x00000004 /* all sample data is encrypted */
|
||||
#define FMOD_FSB_SOURCE_BIGENDIANPCM 0x00000008 /* pcm samples have been written out in big-endian format */
|
||||
#define FMOD_FSB_SOURCE_NOTINTERLEAVED 0x00000010 /* Sample data is not interleaved. */
|
||||
#define FMOD_FSB_SOURCE_MPEG_PADDED 0x00000020 /* Mpeg frames are now rounded up to the nearest 2 bytes for normal sounds, or 16 bytes for multichannel. */
|
||||
#define FMOD_FSB_SOURCE_MPEG_PADDED4 0x00000040 /* Mpeg frames are now rounded up to the nearest 4 bytes for normal sounds, or 16 bytes for multichannel. */
|
||||
|
||||
//#define FMOD_FSB_FORCE_3_0
|
||||
|
||||
#define FMOD_FSB_VERSION_3_0 0x00030000 /* FSB version 3.0 */
|
||||
#define FMOD_FSB_VERSION_3_1 0x00030001 /* FSB version 3.1 */
|
||||
#define FMOD_FSB_VERSION_4_0 0x00040000 /* FSB version 4.0 */
|
||||
|
||||
/*
|
||||
FMOD 3 defines.
|
||||
*/
|
||||
#define FSOUND_LOOP_OFF 0x00000001 /* For non looping samples. */
|
||||
#define FSOUND_LOOP_NORMAL 0x00000002 /* For forward looping samples. */
|
||||
#define FSOUND_LOOP_BIDI 0x00000004 /* For bidirectional looping samples. (no effect if in hardware). */
|
||||
#define FSOUND_8BITS 0x00000008 /* For 8 bit samples. */
|
||||
#define FSOUND_16BITS 0x00000010 /* For 16 bit samples. */
|
||||
#define FSOUND_MONO 0x00000020 /* For mono samples. */
|
||||
#define FSOUND_STEREO 0x00000040 /* For stereo samples. */
|
||||
#define FSOUND_UNSIGNED 0x00000080 /* For user created source data containing unsigned samples. */
|
||||
#define FSOUND_SIGNED 0x00000100 /* For user created source data containing signed data. */
|
||||
#define FSOUND_MPEG 0x00000200 /* For MPEG layer 2/3 data. */
|
||||
#define FSOUND_CHANNELMODE_ALLMONO 0x00000400 /* Sample is a collection of mono channels. */
|
||||
#define FSOUND_CHANNELMODE_ALLSTEREO 0x00000800 /* Sample is a collection of stereo channel pairs */
|
||||
#define FSOUND_HW3D 0x00001000 /* Attempts to make samples use 3d hardware acceleration. (if the card supports it) */
|
||||
#define FSOUND_2D 0x00002000 /* Tells software (not hardware) based sample not to be included in 3d processing. */
|
||||
#define FSOUND_SYNCPOINTS_NONAMES 0x00004000 /* Specifies that syncpoints are present with no names */
|
||||
#define FSOUND_DUPLICATE 0x00008000 /* This subsound is a duplicate of the previous one i.e. it uses the same sample data but w/different mode bits */
|
||||
#define FSOUND_CHANNELMODE_PROTOOLS 0x00010000 /* Sample is 6ch and uses L C R LS RS LFE standard. */
|
||||
#define FSOUND_MPEGACCURATE 0x00020000 /* For FSOUND_Stream_Open - for accurate FSOUND_Stream_GetLengthMs/FSOUND_Stream_SetTime. WARNING, see FSOUND_Stream_Open for inital opening time performance issues. */
|
||||
#define FSOUND_HW2D 0x00080000 /* 2D hardware sounds. allows hardware specific effects */
|
||||
#define FSOUND_3D 0x00100000 /* 3D software sounds */
|
||||
#define FSOUND_32BITS 0x00200000 /* For 32 bit (float) samples. */
|
||||
#define FSOUND_IMAADPCM 0x00400000 /* Contents are stored compressed as IMA ADPCM */
|
||||
#define FSOUND_VAG 0x00800000 /* For PS2 only - Contents are compressed as Sony VAG format */
|
||||
#define FSOUND_XMA 0x01000000 /* For Xbox360 only - Contents are compressed as XMA format */
|
||||
#define FSOUND_GCADPCM 0x02000000 /* For Gamecube only - Contents are compressed as Gamecube DSP-ADPCM format */
|
||||
#define FSOUND_MULTICHANNEL 0x04000000 /* For PS2 and Gamecube only - Contents are interleaved into a multi-channel (more than stereo) format */
|
||||
#define FSOUND_OGG 0x08000000 /* For vorbis encoded ogg data */
|
||||
#define FSOUND_CELT 0x08000000 /* For vorbis encoded ogg data */
|
||||
#define FSOUND_MPEG_LAYER3 0x10000000 /* Data is in MP3 format. */
|
||||
#define FSOUND_MPEG_LAYER2 0x00040000 /* Data is in MP2 format. */
|
||||
#define FSOUND_LOADMEMORYIOP 0x20000000 /* For PS2 only - "name" will be interpreted as a pointer to data for streaming and samples. The address provided will be an IOP address */
|
||||
#define FSOUND_IMAADPCMSTEREO 0x20000000 /* Signify IMA ADPCM is actually stereo not two interleaved mono */
|
||||
#define FSOUND_IGNORETAGS 0x40000000 /* Skips id3v2 etc tag checks when opening a stream, to reduce seek/read overhead when opening files (helps with CD performance) */
|
||||
#define FSOUND_SYNCPOINTS 0x80000000 /* Specifies that syncpoints are present */
|
||||
|
||||
#define FSOUND_CHANNELMODE_MASK (FSOUND_CHANNELMODE_ALLMONO | FSOUND_CHANNELMODE_ALLSTEREO | FSOUND_CHANNELMODE_PROTOOLS)
|
||||
#define FSOUND_CHANNELMODE_DEFAULT 0x00000000 /* Determine channel assignment automatically from channel count. */
|
||||
#define FSOUND_CHANNELMODE_RESERVED 0x00000C00
|
||||
|
||||
#define FSOUND_NORMAL (FSOUND_16BITS | FSOUND_SIGNED | FSOUND_MONO)
|
||||
|
||||
#define FSB_SAMPLE_DATA_ALIGN 32
|
||||
|
||||
namespace FMOD
|
||||
{
|
||||
typedef struct
|
||||
{
|
||||
char id[4]; /* 'FSB3' */
|
||||
int numsamples; /* number of samples in the file */
|
||||
unsigned int shdrsize; /* size in bytes of all of the sample headers including extended information */
|
||||
unsigned int datasize; /* size in bytes of compressed sample data */
|
||||
|
||||
unsigned int version; /* extended fsb version */
|
||||
unsigned int mode; /* flags that apply to all samples in the fsb */
|
||||
} FMOD_FSB3_HEADER; /* 24 bytes */
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char id[4]; /* 'FSB4' */
|
||||
int numsamples; /* number of samples in the file */
|
||||
unsigned int shdrsize; /* size in bytes of all of the sample headers including extended information */
|
||||
unsigned int datasize; /* size in bytes of compressed sample data */
|
||||
|
||||
unsigned int version; /* extended fsb version */
|
||||
unsigned int mode; /* flags that apply to all samples in the fsb */
|
||||
FMOD_UINT64 hash; /* trunacted MD5 hash generated using only information which would break FEV/FSB combatibility */
|
||||
FMOD_GUID guid; /* Unique identifier. */
|
||||
|
||||
} FMOD_FSB_HEADER; /* 48 bytes */
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned short size;
|
||||
char name[FMOD_FSB_NAMELEN];
|
||||
|
||||
unsigned int lengthsamples;
|
||||
unsigned int lengthcompressedbytes;
|
||||
unsigned int loopstart;
|
||||
unsigned int loopend;
|
||||
|
||||
unsigned int mode;
|
||||
int deffreq;
|
||||
unsigned short defvol;
|
||||
short defpan;
|
||||
unsigned short defpri;
|
||||
unsigned short numchannels;
|
||||
#ifndef FMOD_FSB_FORCE_3_0
|
||||
float mindistance;
|
||||
float maxdistance;
|
||||
unsigned int size_32bits;
|
||||
unsigned short varvol;
|
||||
short varpan;
|
||||
#endif
|
||||
} FMOD_FSB_SAMPLE_HEADER; /* 80 bytes */
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned int lengthsamples;
|
||||
unsigned int lengthcompressedbytes;
|
||||
|
||||
} FMOD_FSB_SAMPLE_HEADER_BASIC; /* 8 bytes */
|
||||
|
||||
|
||||
class CodecXMA;
|
||||
class CodecWav;
|
||||
class CodecMPEG;
|
||||
class CodecVAG;
|
||||
class CodecCELT;
|
||||
class ChannelSoftware;
|
||||
class ChannelOpenAL;
|
||||
class CodecFSB;
|
||||
|
||||
#define FMOD_FSB_USEHEADERCACHE
|
||||
|
||||
#ifdef FMOD_FSB_USEHEADERCACHE
|
||||
class CodecFSBCache : public LinkedListNode
|
||||
{
|
||||
public:
|
||||
FMOD_FSB_HEADER mHeader; /* These should be a GUID that is stored with the FSB. */
|
||||
FMOD_FSB_SAMPLE_HEADER **mShdr; /* array of sample header pointers */
|
||||
FMOD_FSB_SAMPLE_HEADER_BASIC **mShdrb; /* array of sample header pointers */
|
||||
char *mShdrData; /* Pointer to data block */
|
||||
unsigned int *mDataOffset; /* array of offsets to raw sample data */
|
||||
int mShareCount;
|
||||
bool mStillLoading;
|
||||
};
|
||||
#endif
|
||||
|
||||
class CodecFSB : public Codec
|
||||
{
|
||||
DECLARE_MEMORYTRACKER_NONVIRTUAL
|
||||
|
||||
friend class ChannelSoftware;
|
||||
friend class ChannelOpenAL;
|
||||
friend class DSPCodec;
|
||||
|
||||
private:
|
||||
|
||||
FMOD_PPCALIGN16(FMOD_FSB_HEADER mHeader);
|
||||
FMOD_PPCALIGN16(FMOD_FSB_SAMPLE_HEADER **mShdr); /* array of sample header pointers */
|
||||
FMOD_PPCALIGN16(FMOD_FSB_SAMPLE_HEADER_BASIC **mShdrb); /* array of sample header pointers */
|
||||
FMOD_PPCALIGN16(FMOD_FSB_SAMPLE_HEADER *mFirstSample); /* first sample header */
|
||||
|
||||
unsigned int *mDataOffset; /* array of offsets to raw sample data */
|
||||
int mCurrentIndex; /* current FSB index */
|
||||
#ifdef FMOD_FSB_USEHEADERCACHE
|
||||
CodecFSBCache *mCacheEntry;
|
||||
#endif
|
||||
|
||||
char **mSyncPointData;
|
||||
|
||||
#ifdef FMOD_SUPPORT_XMA
|
||||
CodecXMA *mXMA;
|
||||
bool mDecodeXMA;
|
||||
#endif
|
||||
#ifdef FMOD_SUPPORT_IMAADPCM
|
||||
CodecWav *mADPCM;
|
||||
bool mDecodeADPCM;
|
||||
#endif
|
||||
#ifdef FMOD_SUPPORT_MPEG
|
||||
CodecMPEG *mMPEG;
|
||||
#endif
|
||||
#ifdef FMOD_SUPPORT_VAG
|
||||
CodecVAG *mVAG;
|
||||
#endif
|
||||
#ifdef FMOD_SUPPORT_CELT
|
||||
CodecCELT *mCELT;
|
||||
#endif
|
||||
|
||||
int mChannels;
|
||||
FMOD_MODE mUserMode;
|
||||
|
||||
FMOD_RESULT openInternal(FMOD_MODE usermode, FMOD_CREATESOUNDEXINFO *userexinfo);
|
||||
FMOD_RESULT closeInternal();
|
||||
FMOD_RESULT readInternal(void *buffer, unsigned int size, unsigned int *read);
|
||||
FMOD_RESULT setPositionInternal(int subsound, unsigned int position, FMOD_TIMEUNIT postype);
|
||||
FMOD_RESULT getPositionInternal(unsigned int *position, FMOD_TIMEUNIT postype);
|
||||
FMOD_RESULT soundcreateInternal(int subsound, FMOD_SOUND *sound);
|
||||
FMOD_RESULT getWaveFormatInternal(int index, FMOD_CODEC_WAVEFORMAT *waveformat);
|
||||
FMOD_RESULT resetInternal();
|
||||
FMOD_RESULT canPointInternal();
|
||||
FMOD_RESULT getNumSyncPoints(int subsound, int *numsyncpoints);
|
||||
FMOD_RESULT getSyncPointData(int subsound, int index, char **name, int *offset);
|
||||
|
||||
public:
|
||||
|
||||
static FMOD_RESULT F_CALLBACK openCallback(FMOD_CODEC_STATE *codec, FMOD_MODE usermode, FMOD_CREATESOUNDEXINFO *userexinfo);
|
||||
static FMOD_RESULT F_CALLBACK closeCallback(FMOD_CODEC_STATE *codec);
|
||||
static FMOD_RESULT F_CALLBACK readCallback(FMOD_CODEC_STATE *codec, void *buffer, unsigned int sizebytes, unsigned int *bytesread);
|
||||
static FMOD_RESULT F_CALLBACK setPositionCallback(FMOD_CODEC_STATE *codec, int subsound, unsigned int position, FMOD_TIMEUNIT postype);
|
||||
static FMOD_RESULT F_CALLBACK getPositionCallback(FMOD_CODEC_STATE *codec, unsigned int *position, FMOD_TIMEUNIT postype);
|
||||
static FMOD_RESULT F_CALLBACK soundcreateCallback(FMOD_CODEC_STATE *codec, int subsound, FMOD_SOUND *sound);
|
||||
static FMOD_RESULT F_CALLBACK getWaveFormatCallback(FMOD_CODEC_STATE *codec_state, int index, FMOD_CODEC_WAVEFORMAT *waveformat);
|
||||
static FMOD_RESULT F_CALLBACK resetCallback(FMOD_CODEC_STATE *codec_state);
|
||||
static FMOD_RESULT F_CALLBACK canPointCallback(FMOD_CODEC_STATE *codec_state);
|
||||
#ifdef FMOD_SUPPORT_MEMORYTRACKER
|
||||
static FMOD_RESULT F_CALLBACK getMemoryUsedCallback(FMOD_CODEC_STATE *codec, MemoryTracker *tracker);
|
||||
#endif
|
||||
|
||||
static FMOD_CODEC_DESCRIPTION_EX *getDescriptionEx();
|
||||
|
||||
#ifdef FMOD_FSB_USEHEADERCACHE
|
||||
static CodecFSBCache gCacheHead;
|
||||
#endif
|
||||
|
||||
FMOD_FSB_SAMPLE_HEADER **getShdr() { return mShdr; }
|
||||
FMOD_UINT64 getHash() { return mHeader.hash; }
|
||||
};
|
||||
}
|
||||
|
||||
#endif /* FMOD_SUPPORT_FSB */
|
||||
|
||||
#endif
|
||||
|
||||
6614
src/fmod_codec_it.cpp
Executable file
6614
src/fmod_codec_it.cpp
Executable file
File diff suppressed because it is too large
Load diff
200
src/fmod_codec_it.h
Executable file
200
src/fmod_codec_it.h
Executable file
|
|
@ -0,0 +1,200 @@
|
|||
#ifndef _FMOD_CODEC_IT_H
|
||||
#define _FMOD_CODEC_IT_H
|
||||
|
||||
#include "fmod_settings.h"
|
||||
|
||||
#ifdef FMOD_SUPPORT_IT
|
||||
|
||||
#include "fmod_music.h"
|
||||
|
||||
namespace FMOD
|
||||
{
|
||||
class DSPI;
|
||||
class ChannelPool;
|
||||
|
||||
enum FMUSIC_ITCOMMANDS
|
||||
{
|
||||
FMUSIC_IT_SETSPEED = 1, // always
|
||||
FMUSIC_IT_PATTERNJUMP, // always
|
||||
FMUSIC_IT_PATTERNBREAK, // always
|
||||
FMUSIC_IT_VOLUMESLIDE, // always set, foreground channel only execute
|
||||
FMUSIC_IT_PORTADOWN, // always set, foreground channel only execute
|
||||
FMUSIC_IT_PORTAUP, // always set, foreground channel only execute
|
||||
FMUSIC_IT_PORTATO, // always set, foreground channel only execute
|
||||
FMUSIC_IT_VIBRATO, // always set, foreground channel only execute
|
||||
FMUSIC_IT_TREMOR, // always set, foreground channel only execute
|
||||
FMUSIC_IT_ARPEGGIO, // always set, foreground channel only execute
|
||||
FMUSIC_IT_VIBRATOVOLSLIDE, // always set, foreground channel only execute
|
||||
FMUSIC_IT_PORTATOVOLSLIDE, // always set, foreground channel only execute
|
||||
FMUSIC_IT_SETCHANNELVOLUME, // always
|
||||
FMUSIC_IT_CHANNELVOLSLIDE, // always
|
||||
FMUSIC_IT_SETSAMPLEOFFSET, // always set, foreground channel only execute
|
||||
FMUSIC_IT_PANSLIDE, // always set, foreground channel only execute
|
||||
FMUSIC_IT_RETRIGVOLSLIDE, // always set, foreground channel only execute
|
||||
FMUSIC_IT_TREMOLO, // always set, foreground channel only execute
|
||||
FMUSIC_IT_SPECIAL, //
|
||||
FMUSIC_IT_SETTEMPO, // always
|
||||
FMUSIC_IT_FINEVIBRATO, // always set, foreground channel only execute
|
||||
FMUSIC_IT_SETGLOBALVOLUME, // always
|
||||
FMUSIC_IT_GLOBALVOLUMESLIDE, // always
|
||||
FMUSIC_IT_SETPAN, // foreground channel only
|
||||
FMUSIC_IT_PANBRELLO, // foreground channel only
|
||||
FMUSIC_IT_MIDIMACROS //
|
||||
};
|
||||
|
||||
enum FMUSIC_ITCOMMANDS_SPECIAL
|
||||
{
|
||||
FMUSIC_IT_S0, //
|
||||
FMUSIC_IT_S1, //
|
||||
FMUSIC_IT_S2, //
|
||||
FMUSIC_IT_SETVIBRATOWAVE, //
|
||||
FMUSIC_IT_SETTREMOLOWAVE, //
|
||||
FMUSIC_IT_SETPANBRELLOWAVE, //
|
||||
FMUSIC_IT_PATTERNDELAYTICKS, //
|
||||
FMUSIC_IT_S7SPECIAL, //
|
||||
FMUSIC_IT_SETPANPOSITION16, //
|
||||
FMUSIC_IT_S9SPECIAL, //
|
||||
FMUSIC_IT_SETHIGHOFFSET, //
|
||||
FMUSIC_IT_PATTERNLOOP, //
|
||||
FMUSIC_IT_NOTECUT, //
|
||||
FMUSIC_IT_NOTEDELAY, //
|
||||
FMUSIC_IT_PATTERNDELAY, //
|
||||
FMUSIC_IT_SF
|
||||
};
|
||||
|
||||
enum FMUSIC_ITCOMMANDS_S7SPECIAL
|
||||
{
|
||||
FMUSIC_IT_PASTNOTECUT, //
|
||||
FMUSIC_IT_PASTNOTEOFF, //
|
||||
FMUSIC_IT_PASTNOTEFADE, //
|
||||
FMUSIC_IT_SETNNACUT, //
|
||||
FMUSIC_IT_SETNNACONTINUE, //
|
||||
FMUSIC_IT_SETNNANOTEOFF, //
|
||||
FMUSIC_IT_SETNNANOTEFADE, //
|
||||
FMUSIC_IT_VOLENVELOPEOFF, //
|
||||
FMUSIC_IT_VOLENVELOPEON, //
|
||||
FMUSIC_IT_S79,
|
||||
FMUSIC_IT_S7A,
|
||||
FMUSIC_IT_S7B,
|
||||
FMUSIC_IT_S7C,
|
||||
FMUSIC_IT_S7D,
|
||||
FMUSIC_IT_S7E,
|
||||
FMUSIC_IT_S7F
|
||||
};
|
||||
|
||||
enum FMUSIC_ITCOMMANDS_S9SPECIAL
|
||||
{
|
||||
FMUSIC_IT_DISABLESURROUND,
|
||||
FMUSIC_IT_ENABLESURROUND,
|
||||
FMUSIC_IT_S92,
|
||||
FMUSIC_IT_S93,
|
||||
FMUSIC_IT_S94,
|
||||
FMUSIC_IT_S95,
|
||||
FMUSIC_IT_S96,
|
||||
FMUSIC_IT_S97,
|
||||
FMUSIC_IT_DISABLEREVERB,
|
||||
FMUSIC_IT_FORCEREVERB,
|
||||
FMUSIC_IT_MONOSURROUND,
|
||||
FMUSIC_IT_QUADSURROUND,
|
||||
FMUSIC_IT_GLOBALFILTER,
|
||||
FMUSIC_IT_LOCALFILTER,
|
||||
FMUSIC_IT_PLAYFORWARD,
|
||||
FMUSIC_IT_PLAYBACKWARD
|
||||
};
|
||||
|
||||
#define FMUSIC_ITFLAGS_NONE 0x0
|
||||
#define FMUSIC_ITFLAGS_MONOSTEREO 0x1
|
||||
#define FMUSIC_ITFLAGS_VOL0OPTIMIZATIONS 0x2
|
||||
#define FMUSIC_ITFLAGS_INSTRUMENTS 0x4
|
||||
#define FMUSIC_ITFLAGS_LINEARFREQUENCY 0x8
|
||||
#define FMUSIC_ITFLAGS_OLD_IT_EFFECTS 0x10
|
||||
#define FMUSIC_ITFLAGS_EFFECT_G 0x20
|
||||
#define FMUSIC_ITFLAGS_EMBEDMIDICFG 0x80
|
||||
#define FMUSIC_ITFLAGS_EXTENDFILTERRANGE 0x1000
|
||||
|
||||
#define MAX_MIXPLUGINS 50
|
||||
|
||||
typedef struct MODMIDICFG
|
||||
{
|
||||
char szMidiGlb[9*32];
|
||||
char szMidiSFXExt[16*32];
|
||||
char szMidiZXXExt[128*32];
|
||||
} MODMIDICFG, *LPMODMIDICFG;
|
||||
|
||||
const int IT_MAXROWS = 256;
|
||||
const int IT_MAXSAMPLES = 256;
|
||||
|
||||
class CodecIT : public MusicSong
|
||||
{
|
||||
private:
|
||||
|
||||
MusicSample **mSample;
|
||||
MusicSample mSampleMem[IT_MAXSAMPLES];
|
||||
signed char *mPatternPtr;
|
||||
unsigned int *mSrcBuffer; /* source buffer */
|
||||
unsigned int *mSrcPos; /* actual reading position */
|
||||
unsigned char mSrcRemBits; /* bits remaining in actual read dword */
|
||||
int mNumRealChannels;
|
||||
SNDMIXPLUGIN *mMixPlugin[MAX_MIXPLUGINS];
|
||||
unsigned int mChannelPlugin[64];
|
||||
DSPI *mDSPFinalHead; /* Extra unit that comes before mDSPUnit for submixing purposes. */
|
||||
DSPI *mDSPEffectHead;
|
||||
|
||||
FMOD_RESULT calculateLength();
|
||||
|
||||
FMOD_RESULT readBits(unsigned char b, unsigned int *result); /* reads b bits from the stream */
|
||||
FMOD_RESULT readBlock(signed char **buff); /* gets block of compressed data from file */
|
||||
FMOD_RESULT freeBlock(); /* frees that block again */
|
||||
FMOD_RESULT decompress8(void **src, void *dst, int len, bool it215, int channels);
|
||||
FMOD_RESULT decompress16(void **src, void *dst, int len, bool it215, int channels);
|
||||
FMOD_RESULT cutOffToFrequency(unsigned int nCutOff, int flt_modifier, float *freq);
|
||||
FMOD_RESULT setupChannelFilter(MusicVirtualChannel *vcptr, bool bReset, int flt_modifier);
|
||||
|
||||
FMOD_RESULT updateRow(bool audible);
|
||||
FMOD_RESULT updateEffects();
|
||||
FMOD_RESULT update(bool audible);
|
||||
|
||||
FMOD_RESULT unpackRow();
|
||||
FMOD_RESULT processEnvelope(MusicEnvelopeState *env, MusicVirtualChannel *vcptr, int Inumpoints, MusicEnvelopeNode *v, int type, int loopstart, int loopend, int susloopstart, int susloopend, unsigned char control);
|
||||
FMOD_RESULT processPitchEnvelope(MusicVirtualChannel *vcptr, MusicInstrument *iptr, int note);
|
||||
FMOD_RESULT sampleVibrato(MusicVirtualChannel *vcptr);
|
||||
FMOD_RESULT play(bool fromopen = false);
|
||||
|
||||
FMOD_RESULT openInternal(FMOD_MODE usermode, FMOD_CREATESOUNDEXINFO *userexinfo);
|
||||
FMOD_RESULT closeInternal();
|
||||
FMOD_RESULT readInternal(void *buffer, unsigned int size, unsigned int *read);
|
||||
FMOD_RESULT setPositionInternal(int subsound, unsigned int position, FMOD_TIMEUNIT postype);
|
||||
|
||||
public:
|
||||
|
||||
static FMOD_RESULT F_CALLBACK openCallback(FMOD_CODEC_STATE *codec, FMOD_MODE usermode, FMOD_CREATESOUNDEXINFO *userexinfo);
|
||||
static FMOD_RESULT F_CALLBACK closeCallback(FMOD_CODEC_STATE *codec);
|
||||
static FMOD_RESULT F_CALLBACK readCallback(FMOD_CODEC_STATE *codec, void *buffer, unsigned int sizebytes, unsigned int *bytesread);
|
||||
static FMOD_RESULT F_CALLBACK setPositionCallback(FMOD_CODEC_STATE *codec, int subsound, unsigned int position, FMOD_TIMEUNIT postype);
|
||||
|
||||
static FMOD_CODEC_DESCRIPTION_EX *getDescriptionEx();
|
||||
|
||||
};
|
||||
|
||||
class MusicChannelIT : public MusicChannel
|
||||
{
|
||||
public:
|
||||
CodecIT *mModule;
|
||||
|
||||
FMOD_RESULT volumeSlide();
|
||||
FMOD_RESULT panSlide();
|
||||
FMOD_RESULT portamento();
|
||||
FMOD_RESULT vibrato();
|
||||
FMOD_RESULT tremolo();
|
||||
FMOD_RESULT fineVibrato();
|
||||
FMOD_RESULT panbrello();
|
||||
FMOD_RESULT processVolumeByte(MusicNote *current, bool newrow);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif /* FMOD_SUPPORT_IT */
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
3908
src/fmod_codec_midi.cpp
Executable file
3908
src/fmod_codec_midi.cpp
Executable file
File diff suppressed because it is too large
Load diff
358
src/fmod_codec_midi.h
Executable file
358
src/fmod_codec_midi.h
Executable file
|
|
@ -0,0 +1,358 @@
|
|||
#ifndef _FMOD_CODEC_MIDI_H
|
||||
#define _FMOD_CODEC_MIDI_H
|
||||
|
||||
#include "fmod_settings.h"
|
||||
|
||||
#ifdef FMOD_SUPPORT_MIDI
|
||||
|
||||
#include "fmod_music.h"
|
||||
|
||||
namespace FMOD
|
||||
{
|
||||
class DSPI;
|
||||
class ChannelPool;
|
||||
class CodecMIDI;
|
||||
class CodecMIDITrack;
|
||||
class CodecMIDIChannel;
|
||||
|
||||
#ifdef FMOD_SUPPORT_PRAGMAPACK
|
||||
#pragma pack(1)
|
||||
#endif
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char mID[4] FMOD_PACKED_INTERNAL;
|
||||
unsigned int mSize FMOD_PACKED_INTERNAL;
|
||||
} FMOD_PACKED MIDI_CHUNK;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
MIDI_CHUNK mChunk FMOD_PACKED_INTERNAL;
|
||||
unsigned short mFormat FMOD_PACKED_INTERNAL;
|
||||
unsigned short mNumTracks FMOD_PACKED_INTERNAL;
|
||||
unsigned short mDivision FMOD_PACKED_INTERNAL;
|
||||
} FMOD_PACKED MTHD_CHUNK;
|
||||
|
||||
#ifdef FMOD_SUPPORT_PRAGMAPACK
|
||||
#ifdef CODEWARRIOR
|
||||
#pragma pack(0)
|
||||
#else
|
||||
#pragma pack()
|
||||
#endif
|
||||
#endif
|
||||
|
||||
typedef enum
|
||||
{
|
||||
MIDI_FORMAT_SINGLETRACK,
|
||||
MIDI_FORMAT_MULTITRACK,
|
||||
MIDI_FORMAT_PATTERN,
|
||||
} MIDI_FORMAT;
|
||||
|
||||
static const unsigned char MIDI_VOICE_NOTEOFF = 0x80;
|
||||
static const unsigned char MIDI_VOICE_NOTEON = 0x90;
|
||||
static const unsigned char MIDI_VOICE_AFTERTOUCH = 0xA0;
|
||||
static const unsigned char MIDI_VOICE_CONTROLLERCHANGE = 0xB0;
|
||||
static const unsigned char MIDI_VOICE_PROGRAMCHANGE = 0xC0;
|
||||
static const unsigned char MIDI_VOICE_CHANNELKEYPRESSURE= 0xD0;
|
||||
static const unsigned char MIDI_VOICE_PITCHBEND = 0xE0;
|
||||
static const unsigned char MIDI_SYSEXESCAPE = 0xF7;
|
||||
static const unsigned char MIDI_SYSEXEVENT = 0xF0;
|
||||
static const unsigned char MIDI_METAEVENT = 0xFF;
|
||||
|
||||
static const unsigned char MIDI_METAEVENT_SEQNUMBER = 0x00;
|
||||
static const unsigned char MIDI_METAEVENT_TEXT = 0x01;
|
||||
static const unsigned char MIDI_METAEVENT_COPYRIGHT = 0x02;
|
||||
static const unsigned char MIDI_METAEVENT_NAME = 0x03;
|
||||
static const unsigned char MIDI_METAEVENT_INSTRUMENT = 0x04;
|
||||
static const unsigned char MIDI_METAEVENT_LYRIC = 0x05;
|
||||
static const unsigned char MIDI_METAEVENT_MARKER = 0x06;
|
||||
static const unsigned char MIDI_METAEVENT_CUEPOINT = 0x07;
|
||||
static const unsigned char MIDI_METAEVENT_PATCHNAME = 0x08;
|
||||
static const unsigned char MIDI_METAEVENT_PORTNAME = 0x09;
|
||||
static const unsigned char MIDI_METAEVENT_CHANNEL = 0x20;
|
||||
static const unsigned char MIDI_METAEVENT_PORT = 0x21;
|
||||
static const unsigned char MIDI_METAEVENT_ENDOFTRACK = 0x2F;
|
||||
static const unsigned char MIDI_METAEVENT_TEMPO = 0x51;
|
||||
static const unsigned char MIDI_METAEVENT_SMTPOFFSET = 0x54;
|
||||
static const unsigned char MIDI_METAEVENT_TIMESIGNATURE = 0x58;
|
||||
static const unsigned char MIDI_METAEVENT_KEYSIGNATURE = 0x59;
|
||||
static const unsigned char MIDI_METAEVENT_PROPRIETARY = 0x7F;
|
||||
|
||||
static const unsigned char MIDI_CONTROLLERCHANGE_BANKSELECT_MSB = 0; // 0-127 MSB
|
||||
static const unsigned char MIDI_CONTROLLERCHANGE_MODULATIONWHEEL_MSB = 1; // 0-127 MSB
|
||||
static const unsigned char MIDI_CONTROLLERCHANGE_BREATHCONTROL_MSB = 2; // 0-127 MSB
|
||||
static const unsigned char MIDI_CONTROLLERCHANGE_FOOTCONTROLLER_MSB = 4; // 0-127 MSB
|
||||
static const unsigned char MIDI_CONTROLLERCHANGE_PORTAMENTOTIME_MSB = 5; // 0-127 MSB
|
||||
static const unsigned char MIDI_CONTROLLERCHANGE_DATAENTRY_MSB = 6; // 0-127 MSB
|
||||
static const unsigned char MIDI_CONTROLLERCHANGE_CHANNELVOLUME_MSB = 7; // 0-127 MSB
|
||||
static const unsigned char MIDI_CONTROLLERCHANGE_BALANCE_MSB = 8; // 0-127 MSB
|
||||
static const unsigned char MIDI_CONTROLLERCHANGE_PAN_MSB = 10; // 0-127 MSB
|
||||
static const unsigned char MIDI_CONTROLLERCHANGE_EXPRESSIONCONTROLLER_MSB = 11; // 0-127 MSB
|
||||
static const unsigned char MIDI_CONTROLLERCHANGE_EFFECTCONTROL1_MSB = 12; // 0-127 MSB
|
||||
static const unsigned char MIDI_CONTROLLERCHANGE_EFFECTCONTROL2_MSB = 13; // 0-127 MSB
|
||||
static const unsigned char MIDI_CONTROLLERCHANGE_GENERALPURPOSECONTROLLER1_MSB = 16; // 0-127 MSB
|
||||
static const unsigned char MIDI_CONTROLLERCHANGE_GENERALPURPOSECONTROLLER2_MSB = 17; // 0-127 MSB
|
||||
static const unsigned char MIDI_CONTROLLERCHANGE_GENERALPURPOSECONTROLLER3_MSB = 18; // 0-127 MSB
|
||||
static const unsigned char MIDI_CONTROLLERCHANGE_GENERALPURPOSECONTROLLER4_MSB = 19; // 0-127 MSB
|
||||
|
||||
static const unsigned char MIDI_CONTROLLERCHANGE_BANKSELECT_LSB = 32; // 0-127 LSB
|
||||
static const unsigned char MIDI_CONTROLLERCHANGE_MODULATIONWHEEL_LSB = 33; // 0-127 LSB
|
||||
static const unsigned char MIDI_CONTROLLERCHANGE_BREATHCONTROL_LSB = 34; // 0-127 LSB
|
||||
static const unsigned char MIDI_CONTROLLERCHANGE_FOOTCONTROLLER_LSB = 36; // 0-127 LSB
|
||||
static const unsigned char MIDI_CONTROLLERCHANGE_PORTAMENTOTIME_LSB = 37; // 0-127 LSB
|
||||
static const unsigned char MIDI_CONTROLLERCHANGE_DATAENTRY_LSB = 38; // 0-127 LSB
|
||||
static const unsigned char MIDI_CONTROLLERCHANGE_CHANNELVOLUME_LSB = 39; // 0-127 LSB
|
||||
static const unsigned char MIDI_CONTROLLERCHANGE_BALANCE_LSB = 40; // 0-127 LSB
|
||||
static const unsigned char MIDI_CONTROLLERCHANGE_PAN_LSB = 42; // 0-127 LSB
|
||||
static const unsigned char MIDI_CONTROLLERCHANGE_EXPRESSIONCONTROLLER_LSB = 43; // 0-127 LSB
|
||||
static const unsigned char MIDI_CONTROLLERCHANGE_EFFECTCONTROL1_LSB = 44; // 0-127 LSB
|
||||
static const unsigned char MIDI_CONTROLLERCHANGE_EFFECTCONTROL2_LSB = 45; // 0-127 LSB
|
||||
static const unsigned char MIDI_CONTROLLERCHANGE_GENERALPURPOSECONTROLLER1_LSB = 48; // 0-127 LSB
|
||||
static const unsigned char MIDI_CONTROLLERCHANGE_GENERALPURPOSECONTROLLER2_LSB = 49; // 0-127 LSB
|
||||
static const unsigned char MIDI_CONTROLLERCHANGE_GENERALPURPOSECONTROLLER3_LSB = 50; // 0-127 LSB
|
||||
static const unsigned char MIDI_CONTROLLERCHANGE_GENERALPURPOSECONTROLLER4_LSB = 51; // 0-127 LSB
|
||||
|
||||
static const unsigned char MIDI_CONTROLLERCHANGE_DAMPERPEDALONOFF = 64; // >64=ON
|
||||
static const unsigned char MIDI_CONTROLLERCHANGE_PORTAMENTOONOFF = 65; // >64=ON
|
||||
static const unsigned char MIDI_CONTROLLERCHANGE_SUSTENUTOONOFF = 66; // >64=ON
|
||||
static const unsigned char MIDI_CONTROLLERCHANGE_SOFTPEDALONOFF = 67; // >64=ON
|
||||
static const unsigned char MIDI_CONTROLLERCHANGE_LEGATOFOOTSWITCH = 68; // >64=ON
|
||||
static const unsigned char MIDI_CONTROLLERCHANGE_HOLD2 = 69; // >64=ON
|
||||
static const unsigned char MIDI_CONTROLLERCHANGE_SOUNDCONTROLLER1 = 70; // 0-127 LSB
|
||||
static const unsigned char MIDI_CONTROLLERCHANGE_SOUNDCONTROLLER2 = 71; // 0-127 LSB
|
||||
static const unsigned char MIDI_CONTROLLERCHANGE_SOUNDCONTROLLER3 = 72; // 0-127 LSB
|
||||
static const unsigned char MIDI_CONTROLLERCHANGE_SOUNDCONTROLLER4 = 73; // 0-127 LSB
|
||||
static const unsigned char MIDI_CONTROLLERCHANGE_SOUNDCONTROLLER5 = 74; // 0-127 LSB
|
||||
static const unsigned char MIDI_CONTROLLERCHANGE_SOUNDCONTROLLER6 = 75; // 0-127 LSB
|
||||
static const unsigned char MIDI_CONTROLLERCHANGE_SOUNDCONTROLLER7 = 76; // 0-127 LSB
|
||||
static const unsigned char MIDI_CONTROLLERCHANGE_SOUNDCONTROLLER8 = 77; // 0-127 LSB
|
||||
static const unsigned char MIDI_CONTROLLERCHANGE_SOUNDCONTROLLER9 = 78; // 0-127 LSB
|
||||
static const unsigned char MIDI_CONTROLLERCHANGE_SOUNDCONTROLLER10 = 79; // 0-127 LSB
|
||||
static const unsigned char MIDI_CONTROLLERCHANGE_GENERALPURPOSECONTROLLER5 = 80; // 0-127 LSB
|
||||
static const unsigned char MIDI_CONTROLLERCHANGE_GENERALPURPOSECONTROLLER6 = 81; // 0-127 LSB
|
||||
static const unsigned char MIDI_CONTROLLERCHANGE_GENERALPURPOSECONTROLLER7 = 82; // 0-127 LSB
|
||||
static const unsigned char MIDI_CONTROLLERCHANGE_GENERALPURPOSECONTROLLER8 = 83; // 0-127 LSB
|
||||
static const unsigned char MIDI_CONTROLLERCHANGE_PORTAMENTOCONTROL = 84; // -127 SOURCE NOTE
|
||||
static const unsigned char MIDI_CONTROLLERCHANGE_EFFECTS1DEPTH = 91; // 0-127 LSB
|
||||
static const unsigned char MIDI_CONTROLLERCHANGE_EFFECTS2DEPTH = 92; // 0-127 LSB
|
||||
static const unsigned char MIDI_CONTROLLERCHANGE_EFFECTS3DEPTH = 93; // 0-127 LSB
|
||||
static const unsigned char MIDI_CONTROLLERCHANGE_EFFECTS4DEPTH = 94; // 0-127 LSB
|
||||
static const unsigned char MIDI_CONTROLLERCHANGE_EFFECTS5DEPTH = 95; // 0-127 LSB
|
||||
static const unsigned char MIDI_CONTROLLERCHANGE_DATAENTRYINC = 96; // N/A
|
||||
static const unsigned char MIDI_CONTROLLERCHANGE_DATAENTRYDEC = 97; // N/A
|
||||
static const unsigned char MIDI_CONTROLLERCHANGE_NONREGISTEREDPARAMNUMBER_LSB = 98; // 0-127 LSB
|
||||
static const unsigned char MIDI_CONTROLLERCHANGE_NONREGISTEREDPARAMNUMBER_MSB = 99; // 0-127 MSB
|
||||
static const unsigned char MIDI_CONTROLLERCHANGE_REGISTEREDPARAMETERNUMBER_LSB = 100; // 0-127 LSB
|
||||
static const unsigned char MIDI_CONTROLLERCHANGE_REGISTEREDPARAMETERNUMBER_MSB = 101; // 0-127 MSB
|
||||
static const unsigned char MIDI_CONTROLLERCHANGE_ALLSOUNDOFF = 120;
|
||||
static const unsigned char MIDI_CONTROLLERCHANGE_RESETALLCONTROLLERS = 121;
|
||||
static const unsigned char MIDI_CONTROLLERCHANGE_LOCALCONTROLONOFF = 122;
|
||||
static const unsigned char MIDI_CONTROLLERCHANGE_ALLNOTESOFF = 123;
|
||||
static const unsigned char MIDI_CONTROLLERCHANGE_OMNIMODEOFF = 124;
|
||||
static const unsigned char MIDI_CONTROLLERCHANGE_OMNIMODEON = 125;
|
||||
static const unsigned char MIDI_CONTROLLERCHANGE_POLYMODEONOFF = 126;
|
||||
static const unsigned char MIDI_CONTROLLERCHANGE_POLYMODEON = 127;
|
||||
|
||||
static const unsigned char MIDI_CONTROLLERCHANGE_RPN_PITCHBENDSENSITIVITY = 0;
|
||||
|
||||
static const unsigned int MIDI_F_INSTRUMENT_DRUMS = 0x80000000;
|
||||
|
||||
static const int MIDI_DEFAULTSUBCHANNELS = 32;
|
||||
static const int MIDI_MINIMUMSAMPLEGRANULARITY = 512; // 10.66ms @ 48khz :S
|
||||
|
||||
class CodecMIDIDLSCache : public LinkedListNode
|
||||
{
|
||||
public:
|
||||
|
||||
char mFilePath[FMOD_STRING_MAXPATHLEN];
|
||||
SoundI *mDLSFile;
|
||||
int mRefCount;
|
||||
};
|
||||
|
||||
class CodecMIDISubChannel : public LinkedListNode
|
||||
{
|
||||
public:
|
||||
|
||||
CodecMIDI *mMIDI;
|
||||
ChannelI mChannel;
|
||||
CodecDLSInstrument *mInstrument;
|
||||
|
||||
float mLFOStartDelay;
|
||||
float mLFOTime;
|
||||
float mLFOFrequency;
|
||||
CodecDLSEnvelope mVolumeEnvelope;
|
||||
CodecDLSEnvelope mPitchEnvelope;
|
||||
|
||||
int mCurrentNote;
|
||||
SoundI *mSound;
|
||||
unsigned char mKeyOnKey;
|
||||
unsigned char mUnityNote;
|
||||
int mFineTune;
|
||||
unsigned char mKeyOnVelocity;
|
||||
int mNumArticulators;
|
||||
DLS_CONNECTIONBLOCK *mArticulator;
|
||||
|
||||
float mTremoloScale;
|
||||
float mVibratoScale;
|
||||
float mPanbrelloScale;
|
||||
|
||||
bool mKeyOff;
|
||||
int mMiddleC;
|
||||
int mKeyGroup;
|
||||
float mSampleAttenuation;
|
||||
CodecMIDIChannel *mParent;
|
||||
|
||||
FMOD_RESULT displayArticulators();
|
||||
FMOD_RESULT findArticulator(int src, int dest);
|
||||
FMOD_RESULT articulateDest(CONN_SRC_FLAGS srcflags, int dest, int *usDestination);
|
||||
FMOD_RESULT setUpArticulators();
|
||||
FMOD_RESULT stop();
|
||||
FMOD_RESULT updateVolume();
|
||||
FMOD_RESULT updatePitch();
|
||||
FMOD_RESULT updatePan();
|
||||
|
||||
float getTimeCentsFromlScale(int lScale);
|
||||
};
|
||||
|
||||
class CodecMIDIChannel : public LinkedListNode
|
||||
{
|
||||
public:
|
||||
CodecMIDITrack *mTrack;
|
||||
CodecMIDISubChannel mChannelHead;
|
||||
unsigned char mIndex;
|
||||
unsigned char mKeyOffVelocity;
|
||||
unsigned char mKeyOnVelocity;
|
||||
unsigned char mAfterTouchKey;
|
||||
unsigned char mAfterTouchPressure;
|
||||
unsigned int mBank;
|
||||
unsigned char mProgram;
|
||||
unsigned int mRPN;
|
||||
unsigned char mChannelPressure;
|
||||
float mMasterVolume;
|
||||
int mPitchBend;
|
||||
int mPitchBendSensitivity;
|
||||
bool mDamperPedal;
|
||||
|
||||
int mModWheel; // cc1
|
||||
int mVolume; // cc7
|
||||
int mPan; // cc10
|
||||
int mExpression; // cc11
|
||||
|
||||
FMOD_RESULT getSound(int key, SoundI **sound, CodecDLSInstrument **instrument, int *unitynote, int *finetune, int *attenuation, bool *duplicateallowed, int *keygroup, int *numarticulators, DLS_CONNECTIONBLOCK **articulators);
|
||||
FMOD_RESULT process(unsigned char event, bool reuse, unsigned char runningdata, bool calledfromopen);
|
||||
FMOD_RESULT update();
|
||||
};
|
||||
|
||||
class CodecMIDITrack
|
||||
{
|
||||
public:
|
||||
|
||||
CodecMIDI *mMIDI;
|
||||
|
||||
unsigned char *mData;
|
||||
unsigned int mOffset;
|
||||
unsigned int mLength;
|
||||
int mIndex;
|
||||
bool mReadDelta;
|
||||
float mTick;
|
||||
bool mFinished;
|
||||
unsigned char mPort;
|
||||
unsigned char mEvent;
|
||||
|
||||
FMOD_RESULT readVarLen(unsigned int *result);
|
||||
FMOD_RESULT readByte(unsigned char *result);
|
||||
FMOD_RESULT readWord(unsigned short *result);
|
||||
FMOD_RESULT readDWord(unsigned int *result);
|
||||
FMOD_RESULT read(void *buff, int length);
|
||||
FMOD_RESULT addTag(const char *name, int length, bool calledfromopen);
|
||||
FMOD_RESULT process(bool calledfromopen);
|
||||
};
|
||||
|
||||
|
||||
class CodecMIDI : public Codec
|
||||
{
|
||||
friend class CodecMIDIChannel;
|
||||
friend class CodecMIDITrack;
|
||||
|
||||
private:
|
||||
|
||||
DSPI *mDSPHead;
|
||||
ChannelPool *mChannelPool;
|
||||
ChannelSoftware *mChannelSoftware; /* Array of FMOD Ex low level real channels. Each one of these lives in a ChannelI channel. */
|
||||
int mNumSubChannels;
|
||||
ChannelGroupI mChannelGroup;
|
||||
CodecMIDISubChannel *mMIDISubChannel;
|
||||
CodecMIDIChannel mMIDIChannel[16];
|
||||
|
||||
bool mFinished;
|
||||
|
||||
int mSequenceNumber;
|
||||
unsigned int mMixerSamplesLeft;
|
||||
unsigned int mMixerSamplesPerTick;
|
||||
float mTimingScale;
|
||||
unsigned int mPCMOffset;
|
||||
unsigned int mDSPTick;
|
||||
|
||||
int mNumTracks;
|
||||
MIDI_FORMAT mMIDIFormat;
|
||||
int mDivision;
|
||||
unsigned char mSMTPOffsetHours;
|
||||
unsigned char mSMTPOffsetMinutes;
|
||||
unsigned char mSMTPOffsetSeconds;
|
||||
unsigned char mSMTPOffsetFrames;
|
||||
unsigned char mSMTPOffsetSubFrames;
|
||||
|
||||
unsigned char mTimeSignatureNumerator;
|
||||
unsigned char mTimeSignatureDenominator;
|
||||
unsigned char mTimeSignatureMetronome;
|
||||
unsigned char mTimeSignatureNotated32nds;
|
||||
|
||||
unsigned char mKeySignatureSF;
|
||||
unsigned char mKeySignatureMI;
|
||||
|
||||
CodecMIDITrack *mTrack;
|
||||
unsigned int mTempo;
|
||||
float mTick;
|
||||
float mMillisecondsPerTick;
|
||||
float mMillisecondsPlayed; /* Only valid while loading */
|
||||
|
||||
CodecMIDIDLSCache *mDLSCache;
|
||||
SoundI *mDLSSound;
|
||||
CodecDLS *mDLS;
|
||||
bool *mSampleInclusionList;
|
||||
|
||||
FMOD_RESULT play(bool fromopen);
|
||||
FMOD_RESULT readVarLen(unsigned int *length);
|
||||
FMOD_RESULT update(bool audible);
|
||||
|
||||
FMOD_RESULT openInternal(FMOD_MODE usermode, FMOD_CREATESOUNDEXINFO *userexinfo);
|
||||
FMOD_RESULT closeInternal();
|
||||
FMOD_RESULT readInternal(void *buffer, unsigned int size, unsigned int *read);
|
||||
FMOD_RESULT setPositionInternal(int subsound, unsigned int position, FMOD_TIMEUNIT postype);
|
||||
FMOD_RESULT getMusicNumChannelsInternal(int *numchannels);
|
||||
FMOD_RESULT setMusicChannelVolumeInternal(int channel, float volume);
|
||||
FMOD_RESULT getMusicChannelVolumeInternal(int channel, float *volume);
|
||||
|
||||
static CodecMIDIDLSCache gDLSCacheHead;
|
||||
|
||||
public:
|
||||
|
||||
CodecMIDISubChannel mChannelFreeListHead;
|
||||
|
||||
static FMOD_RESULT F_CALLBACK openCallback(FMOD_CODEC_STATE *codec, FMOD_MODE usermode, FMOD_CREATESOUNDEXINFO *userexinfo);
|
||||
static FMOD_RESULT F_CALLBACK closeCallback(FMOD_CODEC_STATE *codec);
|
||||
static FMOD_RESULT F_CALLBACK readCallback(FMOD_CODEC_STATE *codec, void *buffer, unsigned int sizebytes, unsigned int *bytesread);
|
||||
static FMOD_RESULT F_CALLBACK setPositionCallback(FMOD_CODEC_STATE *codec, int subsound, unsigned int position, FMOD_TIMEUNIT postype);
|
||||
static FMOD_RESULT F_CALLBACK getMusicNumChannelsCallback(FMOD_CODEC_STATE *codec, int *numchannels);
|
||||
static FMOD_RESULT F_CALLBACK setMusicChannelVolumeCallback(FMOD_CODEC_STATE *codec, int channel, float volume);
|
||||
static FMOD_RESULT F_CALLBACK getMusicChannelVolumeCallback(FMOD_CODEC_STATE *codec, int channel, float *volume);
|
||||
|
||||
static FMOD_CODEC_DESCRIPTION_EX *getDescriptionEx();
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
#endif /* FMOD_SUPPORT_MIDI */
|
||||
|
||||
#endif
|
||||
|
||||
2297
src/fmod_codec_mod.cpp
Executable file
2297
src/fmod_codec_mod.cpp
Executable file
File diff suppressed because it is too large
Load diff
99
src/fmod_codec_mod.h
Executable file
99
src/fmod_codec_mod.h
Executable file
|
|
@ -0,0 +1,99 @@
|
|||
#ifndef _FMOD_CODEC_MOD_H
|
||||
#define _FMOD_CODEC_MOD_H
|
||||
|
||||
#include "fmod_settings.h"
|
||||
|
||||
#ifdef FMOD_SUPPORT_MOD
|
||||
|
||||
#include "fmod_music.h"
|
||||
|
||||
namespace FMOD
|
||||
{
|
||||
class DSPI;
|
||||
class ChannelPool;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
FMUSIC_MOD_ARPEGGIO,
|
||||
FMUSIC_MOD_PORTAUP,
|
||||
FMUSIC_MOD_PORTADOWN,
|
||||
FMUSIC_MOD_PORTATO,
|
||||
FMUSIC_MOD_VIBRATO,
|
||||
FMUSIC_MOD_PORTATOVOLSLIDE,
|
||||
FMUSIC_MOD_VIBRATOVOLSLIDE,
|
||||
FMUSIC_MOD_TREMOLO,
|
||||
FMUSIC_MOD_SETPANPOSITION,
|
||||
FMUSIC_MOD_SETSAMPLEOFFSET,
|
||||
FMUSIC_MOD_VOLUMESLIDE,
|
||||
FMUSIC_MOD_PATTERNJUMP,
|
||||
FMUSIC_MOD_SETVOLUME,
|
||||
FMUSIC_MOD_PATTERNBREAK,
|
||||
FMUSIC_MOD_SPECIAL,
|
||||
FMUSIC_MOD_SETSPEED
|
||||
} MODCOMMANDS;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
FMUSIC_MOD_SETFILTER,
|
||||
FMUSIC_MOD_FINEPORTAUP,
|
||||
FMUSIC_MOD_FINEPORTADOWN,
|
||||
FMUSIC_MOD_SETGLISSANDO,
|
||||
FMUSIC_MOD_SETVIBRATOWAV,
|
||||
FMUSIC_MOD_SETFINETUNE,
|
||||
FMUSIC_MOD_PATTERNLOOP,
|
||||
FMUSIC_MOD_SETTREMOLOWAV,
|
||||
FMUSIC_MOD_SETPANPOSITION16,
|
||||
FMUSIC_MOD_RETRIG,
|
||||
FMUSIC_MOD_FINEVOLUMESLIDEUP,
|
||||
FMUSIC_MOD_FINEVOLUMESLIDEDOWN,
|
||||
FMUSIC_MOD_NOTECUT,
|
||||
FMUSIC_MOD_NOTEDELAY,
|
||||
FMUSIC_MOD_PATTERNDELAY,
|
||||
FMUSIC_MOD_FUNKREPEAT
|
||||
} MODCOMMANDSSPECIAL;
|
||||
|
||||
const int MOD_MAXROWS = 64;
|
||||
const int MOD_MAXSAMPLES = 31;
|
||||
|
||||
class MusicChannelMOD : public MusicChannel
|
||||
{
|
||||
public:
|
||||
FMOD_RESULT portamento();
|
||||
FMOD_RESULT vibrato();
|
||||
FMOD_RESULT tremolo();
|
||||
};
|
||||
|
||||
class CodecMOD : public MusicSong
|
||||
{
|
||||
private:
|
||||
|
||||
MusicSample mSample[MOD_MAXSAMPLES];
|
||||
|
||||
FMOD_RESULT calculateLength();
|
||||
inline int getAmigaPeriod(int note, int middlec);
|
||||
|
||||
FMOD_RESULT updateNote(bool audible);
|
||||
FMOD_RESULT updateEffects();
|
||||
FMOD_RESULT update(bool audible);
|
||||
|
||||
FMOD_RESULT openInternal(FMOD_MODE usermode, FMOD_CREATESOUNDEXINFO *userexinfo);
|
||||
FMOD_RESULT closeInternal();
|
||||
FMOD_RESULT readInternal(void *buffer, unsigned int size, unsigned int *read);
|
||||
FMOD_RESULT setPositionInternal(int subsound, unsigned int position, FMOD_TIMEUNIT postype);
|
||||
|
||||
public:
|
||||
|
||||
static FMOD_RESULT F_CALLBACK openCallback(FMOD_CODEC_STATE *codec, FMOD_MODE usermode, FMOD_CREATESOUNDEXINFO *userexinfo);
|
||||
static FMOD_RESULT F_CALLBACK closeCallback(FMOD_CODEC_STATE *codec);
|
||||
static FMOD_RESULT F_CALLBACK readCallback(FMOD_CODEC_STATE *codec, void *buffer, unsigned int sizebytes, unsigned int *bytesread);
|
||||
static FMOD_RESULT F_CALLBACK setPositionCallback(FMOD_CODEC_STATE *codec, int subsound, unsigned int position, FMOD_TIMEUNIT postype);
|
||||
|
||||
static FMOD_CODEC_DESCRIPTION_EX *getDescriptionEx();
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
#endif /* FMOD_SUPPORT_MOD */
|
||||
|
||||
#endif
|
||||
|
||||
1683
src/fmod_codec_mpeg.cpp
Executable file
1683
src/fmod_codec_mpeg.cpp
Executable file
File diff suppressed because it is too large
Load diff
353
src/fmod_codec_mpeg.h
Executable file
353
src/fmod_codec_mpeg.h
Executable file
|
|
@ -0,0 +1,353 @@
|
|||
#ifndef _FMOD_CODEC_MPEG_H
|
||||
#define _FMOD_CODEC_MPEG_H
|
||||
|
||||
#include "fmod_settings.h"
|
||||
|
||||
#ifdef FMOD_SUPPORT_MPEG
|
||||
|
||||
#include "fmod_codeci.h"
|
||||
|
||||
#ifdef FMOD_SUPPORT_MPEG_SONYDECODER
|
||||
#include "../ps3/lib/sony/mp3declib.h"
|
||||
#endif
|
||||
|
||||
#ifndef PLATFORM_PS3
|
||||
#define USE_ISPOW_TABLE
|
||||
#endif
|
||||
|
||||
namespace FMOD
|
||||
{
|
||||
/*
|
||||
DEFINITIONS
|
||||
*/
|
||||
|
||||
#define SBLIMIT 32
|
||||
#define SSLIMIT 18
|
||||
#define SCALE_BLOCK 12
|
||||
|
||||
#define MPG_MD_STEREO 0
|
||||
#define MPG_MD_JOINT_STEREO 1
|
||||
#define MPG_MD_DUAL_CHANNEL 2
|
||||
#define MPG_MD_MONO 3
|
||||
|
||||
#define MAXFRAMESIZE 1792
|
||||
|
||||
/*
|
||||
STRUCTURE DEFINITIONS
|
||||
*/
|
||||
|
||||
struct al_table
|
||||
{
|
||||
short bits;
|
||||
short d;
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
struct al_table *alloc;
|
||||
int stereo;
|
||||
int jsbound;
|
||||
int II_sblimit;
|
||||
int lsf;
|
||||
int mpeg25;
|
||||
int header_change;
|
||||
int lay;
|
||||
int error_protection;
|
||||
int bitrate_index;
|
||||
int sampling_frequency;
|
||||
int padding;
|
||||
int extension;
|
||||
int mode;
|
||||
int mode_ext;
|
||||
int copyright;
|
||||
int original;
|
||||
int emphasis;
|
||||
int framesize; /* computed framesize */
|
||||
} MPEG_FRAME;
|
||||
|
||||
struct gr_info_s
|
||||
{
|
||||
int scfsi;
|
||||
unsigned part2_3_length;
|
||||
unsigned big_values;
|
||||
unsigned scalefac_compress;
|
||||
unsigned block_type;
|
||||
unsigned mixed_block_flag;
|
||||
unsigned table_select[3];
|
||||
unsigned subblock_gain[3];
|
||||
unsigned maxband[3];
|
||||
unsigned maxbandl;
|
||||
unsigned maxb;
|
||||
unsigned region1start;
|
||||
unsigned region2start;
|
||||
unsigned preflag;
|
||||
unsigned scalefac_scale;
|
||||
unsigned count1table_select;
|
||||
float *full_gain[3];
|
||||
float *pow2gain;
|
||||
};
|
||||
|
||||
struct III_sideinfo
|
||||
{
|
||||
unsigned main_data_begin;
|
||||
unsigned private_bits;
|
||||
|
||||
struct
|
||||
{
|
||||
struct gr_info_s gr[2];
|
||||
} ch[2];
|
||||
};
|
||||
|
||||
struct bandInfoStruct
|
||||
{
|
||||
int longIdx[23];
|
||||
int longDiff[22];
|
||||
int shortIdx[14];
|
||||
int shortDiff[13];
|
||||
};
|
||||
|
||||
class SyncPoint;
|
||||
|
||||
struct bitstream_info
|
||||
{
|
||||
int mBitIndex;
|
||||
unsigned char *mWordPointer;
|
||||
};
|
||||
|
||||
struct CodecMPEG_MemoryBlock
|
||||
{
|
||||
#ifdef FMOD_SUPPORT_MPEG_SONYDECODER
|
||||
|
||||
CellMP3Context mContext1;
|
||||
CellMP3Context mContext2;
|
||||
int mCount;
|
||||
int mStereo;
|
||||
char mPad[4];
|
||||
|
||||
#else
|
||||
|
||||
unsigned char mBSSpace[2][MAXFRAMESIZE+512]; /* 4608 */
|
||||
float mSynthBuffsMem[(2 * 576) + 16]; /* 4608 */
|
||||
float *mSynthBuffs;
|
||||
float mBlock[2][2][SBLIMIT * SSLIMIT]; /* 9216 */
|
||||
|
||||
int mFrameSize;
|
||||
int mFrameSizeOld;
|
||||
MPEG_FRAME mFrame;
|
||||
unsigned int mFrameHeader;
|
||||
|
||||
int mPcmPoint;
|
||||
int mBSNum;
|
||||
int mSynthBo;
|
||||
bitstream_info mBSI;
|
||||
int mBlc[2];
|
||||
|
||||
#ifdef PLATFORM_PS3
|
||||
char mPad[4];
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
int mLayer;
|
||||
unsigned int mNumFrames;
|
||||
unsigned int *mFrameOffset;
|
||||
|
||||
unsigned char mXingToc[100];
|
||||
bool mHasXingNumFrames;
|
||||
bool mHasXingToc;
|
||||
};
|
||||
|
||||
class CodecMPEG : public Codec
|
||||
{
|
||||
public:
|
||||
CodecMPEG_MemoryBlock *mMemoryBlock;
|
||||
CodecMPEG_MemoryBlock *mMemoryBlockMemory;
|
||||
|
||||
SyncPoint *mSyncPoint;
|
||||
int mNumSyncPoints;
|
||||
unsigned int mPCMFrameLengthBytes;
|
||||
unsigned char *mPCMBufferMemory;
|
||||
int mChannels;
|
||||
|
||||
static int gTabSel123[2][3][16];
|
||||
static int gFreqs[9];
|
||||
|
||||
static bool gInitialized;
|
||||
|
||||
#ifndef FMOD_SUPPORT_MPEG_SONYDECODER
|
||||
/*
|
||||
Static, global members used by all codecs
|
||||
*/
|
||||
static float gDecWinMem[512+32+16]; /* +16 for alignment */
|
||||
static FMOD_ALIGN16(float gCos64[16]);
|
||||
static FMOD_ALIGN16(float gCos32[8]);
|
||||
static FMOD_ALIGN16(float gCos16[4]);
|
||||
static FMOD_ALIGN16(float gCos8[2]);
|
||||
static FMOD_ALIGN16(float gCos4[1]);
|
||||
static float *gPnts[5];
|
||||
static int gIntWinBase[];
|
||||
|
||||
|
||||
/*
|
||||
Layer 2 globals
|
||||
*/
|
||||
static unsigned char gGrp3Tab[32 * 3];
|
||||
static unsigned char gGrp5Tab[128 * 3];
|
||||
static unsigned char gGrp9Tab[1024 * 3];
|
||||
static float gMulsTab[27][64];
|
||||
static struct al_table gAlloc0[];
|
||||
static struct al_table gAlloc1[];
|
||||
static struct al_table gAlloc2[];
|
||||
static struct al_table gAlloc3[];
|
||||
static struct al_table gAlloc4[];
|
||||
|
||||
/*
|
||||
Layer 3 globals
|
||||
*/
|
||||
static float gIsPowTable[8207];
|
||||
static float gAaCa[8];
|
||||
static float gAaCs[8];
|
||||
static float gWin[4][36];
|
||||
static float gWin1[4][36];
|
||||
static float gGainPow2[256 + 118 + 4];
|
||||
static float gCos6_1;
|
||||
static float gCos6_2;
|
||||
static float gTfCos36[9];
|
||||
static float gTfCos12[3];
|
||||
static float gCos9[3];
|
||||
static float gCos18[3];
|
||||
static int gLongLimit[9][23];
|
||||
static int gShortLimit[9][14];
|
||||
static struct bandInfoStruct gBandInfo[9];
|
||||
static int gMapBuf0[9][152];
|
||||
static int gMapBuf1[9][156];
|
||||
static int gMapBuf2[9][44];
|
||||
static int *gMap[9][3];
|
||||
static int *gMapEnd[9][3];
|
||||
static unsigned int gN_SLen2[512]; /* MPEG 2.0 slen for 'normal' mode */
|
||||
static unsigned int gI_SLen2[256]; /* MPEG 2.0 slen for intensity stereo */
|
||||
static float gTan1_1[16];
|
||||
static float gTan2_1[16];
|
||||
static float gTan1_2[16];
|
||||
static float gTan2_2[16];
|
||||
static float gPow1_1[2][16];
|
||||
static float gPow2_1[2][16];
|
||||
static float gPow1_2[2][16];
|
||||
static float gPow2_2[2][16];
|
||||
|
||||
static FMOD_RESULT makeTables(int scaleval);
|
||||
static FMOD_RESULT initLayer2();
|
||||
static FMOD_RESULT initLayer3(int down_sample_sblimit);
|
||||
#endif
|
||||
|
||||
static FMOD_RESULT initAll();
|
||||
|
||||
#ifdef FMOD_SUPPORT_MPEG_SPU
|
||||
static FMOD_RESULT closeAll();
|
||||
#endif
|
||||
|
||||
/*
|
||||
Per mpeg member functions
|
||||
*/
|
||||
FMOD_RESULT decodeHeader(void *in, int *samplerate, int *channels, int *framesize);
|
||||
FMOD_RESULT decodeXingHeader(unsigned char *in, unsigned char *toc, unsigned int *numframes);
|
||||
FMOD_RESULT decodeFrame(unsigned char *in, void *out, unsigned int *outlen);
|
||||
FMOD_RESULT decodeLayer2(void *out, unsigned int *outlen);
|
||||
FMOD_RESULT decodeLayer3(void *out, unsigned int *outlen);
|
||||
FMOD_RESULT decodeLayer3(unsigned char *in, void *out, unsigned int *outlen); /* Using Sony Decoder for PS3 */
|
||||
FMOD_RESULT getPCMLength();
|
||||
FMOD_RESULT resetFrame();
|
||||
FMOD_RESULT getIIStuff();
|
||||
FMOD_RESULT II_step_one(unsigned int *bit_alloc,int *scale);
|
||||
FMOD_RESULT II_step_two(unsigned int *bit_alloc,float fraction[2][4][SBLIMIT],int *scale,int x1);
|
||||
FMOD_RESULT III_get_side_info_1(struct III_sideinfo *si, int stereo, int ms_stereo, int sfreq);
|
||||
FMOD_RESULT III_get_side_info_2(struct III_sideinfo *si, int stereo, int ms_stereo, int sfreq);
|
||||
FMOD_RESULT III_get_scale_factors_1(int *scf,struct gr_info_s *gr_info, int *numbits);
|
||||
FMOD_RESULT III_get_scale_factors_2(int *scf,struct gr_info_s *gr_info,int i_stereo, int *numbits);
|
||||
FMOD_RESULT III_dequantize_sample(float xr[SBLIMIT][SSLIMIT],int *scf, struct gr_info_s *gr_info,int sfreq,int part2bits);
|
||||
FMOD_RESULT III_dequantize_sample_ms(float xr[2][SBLIMIT][SSLIMIT], int *scf, struct gr_info_s *gr_info, int sfreq, int part2bits);
|
||||
FMOD_RESULT III_i_stereo(float xr_buf[2][SBLIMIT][SSLIMIT], int *scalefac, struct gr_info_s *gr_info, int sfreq, int ms_stereo, int lsf);
|
||||
FMOD_RESULT III_antialias(float xr[SBLIMIT][SSLIMIT], struct gr_info_s *gr_info);
|
||||
FMOD_RESULT III_hybrid(float fsIn[SBLIMIT][SSLIMIT], float tsOut[SSLIMIT][SBLIMIT], int ch, struct gr_info_s *gr_info);
|
||||
|
||||
FMOD_RESULT synth(void *samples, float *bandPtr, int channels, int channelskip);
|
||||
FMOD_RESULT synthC(float *b0, int bo1, int channels, signed short *samples);
|
||||
|
||||
unsigned int getBits(int number_of_bits);
|
||||
unsigned int getBitsFast(int number_of_bits);
|
||||
|
||||
#ifndef FMOD_SUPPORT_MPEG_SONYDECODER
|
||||
FMOD_INLINE unsigned int get1Bit()
|
||||
{
|
||||
unsigned char rval;
|
||||
|
||||
rval = *(mMemoryBlock->mBSI.mWordPointer) << mMemoryBlock->mBSI.mBitIndex;
|
||||
|
||||
mMemoryBlock->mBSI.mBitIndex++;
|
||||
mMemoryBlock->mBSI.mWordPointer += (mMemoryBlock->mBSI.mBitIndex>>3);
|
||||
mMemoryBlock->mBSI.mBitIndex &= 7;
|
||||
|
||||
return (unsigned int)(rval>>7);
|
||||
}
|
||||
FMOD_INLINE int getByte()
|
||||
{
|
||||
return *mMemoryBlock->mBSI.mWordPointer++;
|
||||
}
|
||||
FMOD_INLINE void backbits(int number_of_bits)
|
||||
{
|
||||
mMemoryBlock->mBSI.mBitIndex -= number_of_bits;
|
||||
mMemoryBlock->mBSI.mWordPointer += (mMemoryBlock->mBSI.mBitIndex>>3);
|
||||
mMemoryBlock->mBSI.mBitIndex &= 0x7;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void dct64(float *out0,float *out1,float *samples);
|
||||
static void dct36(float * inbuf, float * o1, float * o2, float * wintab, float * tsbuf);
|
||||
static void dct12(float * in, float * rawout1, float * rawout2, register float * wi, register float * ts);
|
||||
|
||||
/*
|
||||
Codec functions
|
||||
*/
|
||||
#ifndef PLATFORM_PS3_SPU
|
||||
FMOD_RESULT openInternal(FMOD_MODE usermode, FMOD_CREATESOUNDEXINFO *userexinfo);
|
||||
FMOD_RESULT closeInternal();
|
||||
FMOD_RESULT soundCreateInternal(int subsound, FMOD_SOUND *sound);
|
||||
#endif
|
||||
FMOD_RESULT readInternal(void *buffer, unsigned int size, unsigned int *read);
|
||||
FMOD_RESULT setPositionInternal(int subsound, unsigned int position, FMOD_TIMEUNIT postype);
|
||||
FMOD_RESULT resetInternal() { return resetFrame(); }
|
||||
|
||||
public:
|
||||
|
||||
#ifndef PLATFORM_PS3_SPU
|
||||
static FMOD_RESULT F_CALLBACK openCallback(FMOD_CODEC_STATE *codec, FMOD_MODE usermode, FMOD_CREATESOUNDEXINFO *userexinfo);
|
||||
static FMOD_RESULT F_CALLBACK closeCallback(FMOD_CODEC_STATE *codec);
|
||||
static FMOD_RESULT F_CALLBACK soundCreateCallback(FMOD_CODEC_STATE *codec, int subsound, FMOD_SOUND *sound);
|
||||
|
||||
static FMOD_CODEC_DESCRIPTION_EX *getDescriptionEx();
|
||||
#endif
|
||||
static FMOD_RESULT F_CALLBACK readCallback(FMOD_CODEC_STATE *codec, void *buffer, unsigned int sizebytes, unsigned int *bytesread);
|
||||
static FMOD_RESULT F_CALLBACK setPositionCallback(FMOD_CODEC_STATE *codec, int subsound, unsigned int position, FMOD_TIMEUNIT postype);
|
||||
static FMOD_RESULT F_CALLBACK resetCallback(FMOD_CODEC_STATE *codec);
|
||||
};
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern float *FMOD_Mpeg_DecWin;
|
||||
|
||||
void FMOD_Mpeg_Synth_FPU(float *b0, int bo1, int numchannels, short *samps);
|
||||
void FMOD_Mpeg_DCT64(float *out0,float *out1,float *samples);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* FMOD_SUPPORT_MPEG */
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
1241
src/fmod_codec_mpeg_decode.cpp
Executable file
1241
src/fmod_codec_mpeg_decode.cpp
Executable file
File diff suppressed because it is too large
Load diff
615
src/fmod_codec_mpeg_layer2.cpp
Executable file
615
src/fmod_codec_mpeg_layer2.cpp
Executable file
|
|
@ -0,0 +1,615 @@
|
|||
#include "fmod_settings.h"
|
||||
|
||||
#ifdef FMOD_SUPPORT_MPEG
|
||||
|
||||
#ifdef FMOD_SUPPORT_MPEG_LAYER2
|
||||
|
||||
#include "fmod_codec_mpeg.h"
|
||||
#include "fmod_types.h"
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#ifndef PLATFORM_PS3_SPU
|
||||
#define USE_MULS_TABLE
|
||||
#endif
|
||||
|
||||
namespace FMOD
|
||||
{
|
||||
|
||||
#ifndef FMOD_SUPPORT_MPEG_SONYDECODER
|
||||
|
||||
unsigned char CodecMPEG::gGrp3Tab[32 * 3] = { 0, }; // used: 27
|
||||
unsigned char CodecMPEG::gGrp5Tab[128 * 3] = { 0, }; // used: 125
|
||||
unsigned char CodecMPEG::gGrp9Tab[1024 * 3] = { 0, }; // used: 729
|
||||
|
||||
|
||||
#ifdef USE_MULS_TABLE
|
||||
float CodecMPEG::gMulsTab[27][64]; // also used by layer 1
|
||||
|
||||
#define gMuls(_x, _y) gMulsTab[_x][_y]
|
||||
#else
|
||||
|
||||
float gMulMul[27] =
|
||||
{
|
||||
0.0f , -2.0f/3.0f , 2.0f/3.0f ,
|
||||
2.0f/7.0f , 2.0f/15.0f , 2.0f/31.0f, 2.0f/63.0f , 2.0f/127.0f , 2.0f/255.0f ,
|
||||
2.0f/511.0f , 2.0f/1023.0f , 2.0f/2047.0f , 2.0f/4095.0f , 2.0f/8191.0f ,
|
||||
2.0f/16383.0f , 2.0f/32767.0f , 2.0f/65535.0f ,
|
||||
-4.0f/5.0f , -2.0f/5.0f , 2.0f/5.0f, 4.0f/5.0f ,
|
||||
-8.0f/9.0f , -4.0f/9.0f , -2.0f/9.0f , 2.0f/9.0f , 4.0f/9.0f , 8.0f/9.0f
|
||||
};
|
||||
|
||||
#ifdef PLATFORM_PS3_SPU
|
||||
|
||||
float gMuls(int _x, int _y) { return ((_y) == 63) ? 0.0f : (float)(gMulMul[(_x)] * FMOD_POW(2.0f, (3 - (int)(_y)) / 3.0f)); } /* Function call to make code smaller */
|
||||
|
||||
#else
|
||||
|
||||
#define gMuls(_x, _y) ((_y) == 63) ? 0.0f : (float)(gMulMul[(_x)] * FMOD_POW(2.0f, (3 - (int)(_y)) / 3.0f))
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Layer 2 Alloc tables ..
|
||||
* most other tables are calculated on program start (which is (of course)
|
||||
* not ISO-conform) ..
|
||||
* Layer-3 huffman table is in huffman.h
|
||||
*/
|
||||
|
||||
struct al_table CodecMPEG::gAlloc0[] =
|
||||
{
|
||||
{4,0},{5,3},{3,-3},{4,-7},{5,-15},{6,-31},{7,-63},{8,-127},{9,-255},{10,-511},
|
||||
{11,-1023},{12,-2047},{13,-4095},{14,-8191},{15,-16383},{16,-32767},
|
||||
{4,0},{5,3},{3,-3},{4,-7},{5,-15},{6,-31},{7,-63},{8,-127},{9,-255},{10,-511},
|
||||
{11,-1023},{12,-2047},{13,-4095},{14,-8191},{15,-16383},{16,-32767},
|
||||
{4,0},{5,3},{3,-3},{4,-7},{5,-15},{6,-31},{7,-63},{8,-127},{9,-255},{10,-511},
|
||||
{11,-1023},{12,-2047},{13,-4095},{14,-8191},{15,-16383},{16,-32767},
|
||||
{4,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{6,-31},{7,-63},{8,-127},
|
||||
{9,-255},{10,-511},{11,-1023},{12,-2047},{13,-4095},{16,-32767},
|
||||
{4,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{6,-31},{7,-63},{8,-127},
|
||||
{9,-255},{10,-511},{11,-1023},{12,-2047},{13,-4095},{16,-32767},
|
||||
{4,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{6,-31},{7,-63},{8,-127},
|
||||
{9,-255},{10,-511},{11,-1023},{12,-2047},{13,-4095},{16,-32767},
|
||||
{4,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{6,-31},{7,-63},{8,-127},
|
||||
{9,-255},{10,-511},{11,-1023},{12,-2047},{13,-4095},{16,-32767},
|
||||
{4,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{6,-31},{7,-63},{8,-127},
|
||||
{9,-255},{10,-511},{11,-1023},{12,-2047},{13,-4095},{16,-32767},
|
||||
{4,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{6,-31},{7,-63},{8,-127},
|
||||
{9,-255},{10,-511},{11,-1023},{12,-2047},{13,-4095},{16,-32767},
|
||||
{4,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{6,-31},{7,-63},{8,-127},
|
||||
{9,-255},{10,-511},{11,-1023},{12,-2047},{13,-4095},{16,-32767},
|
||||
{4,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{6,-31},{7,-63},{8,-127},
|
||||
{9,-255},{10,-511},{11,-1023},{12,-2047},{13,-4095},{16,-32767},
|
||||
{3,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{16,-32767},
|
||||
{3,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{16,-32767},
|
||||
{3,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{16,-32767},
|
||||
{3,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{16,-32767},
|
||||
{3,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{16,-32767},
|
||||
{3,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{16,-32767},
|
||||
{3,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{16,-32767},
|
||||
{3,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{16,-32767},
|
||||
{3,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{16,-32767},
|
||||
{3,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{16,-32767},
|
||||
{3,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{16,-32767},
|
||||
{3,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{16,-32767},
|
||||
{2,0},{5,3},{7,5},{16,-32767},
|
||||
{2,0},{5,3},{7,5},{16,-32767},
|
||||
{2,0},{5,3},{7,5},{16,-32767},
|
||||
{2,0},{5,3},{7,5},{16,-32767}
|
||||
};
|
||||
|
||||
struct al_table CodecMPEG::gAlloc1[] =
|
||||
{
|
||||
{4,0},{5,3},{3,-3},{4,-7},{5,-15},{6,-31},{7,-63},{8,-127},{9,-255},{10,-511},
|
||||
{11,-1023},{12,-2047},{13,-4095},{14,-8191},{15,-16383},{16,-32767},
|
||||
{4,0},{5,3},{3,-3},{4,-7},{5,-15},{6,-31},{7,-63},{8,-127},{9,-255},{10,-511},
|
||||
{11,-1023},{12,-2047},{13,-4095},{14,-8191},{15,-16383},{16,-32767},
|
||||
{4,0},{5,3},{3,-3},{4,-7},{5,-15},{6,-31},{7,-63},{8,-127},{9,-255},{10,-511},
|
||||
{11,-1023},{12,-2047},{13,-4095},{14,-8191},{15,-16383},{16,-32767},
|
||||
{4,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{6,-31},{7,-63},{8,-127},
|
||||
{9,-255},{10,-511},{11,-1023},{12,-2047},{13,-4095},{16,-32767},
|
||||
{4,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{6,-31},{7,-63},{8,-127},
|
||||
{9,-255},{10,-511},{11,-1023},{12,-2047},{13,-4095},{16,-32767},
|
||||
{4,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{6,-31},{7,-63},{8,-127},
|
||||
{9,-255},{10,-511},{11,-1023},{12,-2047},{13,-4095},{16,-32767},
|
||||
{4,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{6,-31},{7,-63},{8,-127},
|
||||
{9,-255},{10,-511},{11,-1023},{12,-2047},{13,-4095},{16,-32767},
|
||||
{4,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{6,-31},{7,-63},{8,-127},
|
||||
{9,-255},{10,-511},{11,-1023},{12,-2047},{13,-4095},{16,-32767},
|
||||
{4,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{6,-31},{7,-63},{8,-127},
|
||||
{9,-255},{10,-511},{11,-1023},{12,-2047},{13,-4095},{16,-32767},
|
||||
{4,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{6,-31},{7,-63},{8,-127},
|
||||
{9,-255},{10,-511},{11,-1023},{12,-2047},{13,-4095},{16,-32767},
|
||||
{4,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{6,-31},{7,-63},{8,-127},
|
||||
{9,-255},{10,-511},{11,-1023},{12,-2047},{13,-4095},{16,-32767},
|
||||
{3,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{16,-32767},
|
||||
{3,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{16,-32767},
|
||||
{3,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{16,-32767},
|
||||
{3,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{16,-32767},
|
||||
{3,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{16,-32767},
|
||||
{3,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{16,-32767},
|
||||
{3,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{16,-32767},
|
||||
{3,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{16,-32767},
|
||||
{3,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{16,-32767},
|
||||
{3,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{16,-32767},
|
||||
{3,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{16,-32767},
|
||||
{3,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{16,-32767},
|
||||
{2,0},{5,3},{7,5},{16,-32767},
|
||||
{2,0},{5,3},{7,5},{16,-32767},
|
||||
{2,0},{5,3},{7,5},{16,-32767},
|
||||
{2,0},{5,3},{7,5},{16,-32767},
|
||||
{2,0},{5,3},{7,5},{16,-32767},
|
||||
{2,0},{5,3},{7,5},{16,-32767},
|
||||
{2,0},{5,3},{7,5},{16,-32767} };
|
||||
|
||||
struct al_table CodecMPEG::gAlloc2[] =
|
||||
{
|
||||
{4,0},{5,3},{7,5},{10,9},{4,-7},{5,-15},{6,-31},{7,-63},{8,-127},{9,-255},
|
||||
{10,-511},{11,-1023},{12,-2047},{13,-4095},{14,-8191},{15,-16383},
|
||||
{4,0},{5,3},{7,5},{10,9},{4,-7},{5,-15},{6,-31},{7,-63},{8,-127},{9,-255},
|
||||
{10,-511},{11,-1023},{12,-2047},{13,-4095},{14,-8191},{15,-16383},
|
||||
{3,0},{5,3},{7,5},{10,9},{4,-7},{5,-15},{6,-31},{7,-63},
|
||||
{3,0},{5,3},{7,5},{10,9},{4,-7},{5,-15},{6,-31},{7,-63},
|
||||
{3,0},{5,3},{7,5},{10,9},{4,-7},{5,-15},{6,-31},{7,-63},
|
||||
{3,0},{5,3},{7,5},{10,9},{4,-7},{5,-15},{6,-31},{7,-63},
|
||||
{3,0},{5,3},{7,5},{10,9},{4,-7},{5,-15},{6,-31},{7,-63},
|
||||
{3,0},{5,3},{7,5},{10,9},{4,-7},{5,-15},{6,-31},{7,-63}
|
||||
};
|
||||
|
||||
struct al_table CodecMPEG::gAlloc3[] =
|
||||
{
|
||||
{4,0},{5,3},{7,5},{10,9},{4,-7},{5,-15},{6,-31},{7,-63},{8,-127},{9,-255},
|
||||
{10,-511},{11,-1023},{12,-2047},{13,-4095},{14,-8191},{15,-16383},
|
||||
{4,0},{5,3},{7,5},{10,9},{4,-7},{5,-15},{6,-31},{7,-63},{8,-127},{9,-255},
|
||||
{10,-511},{11,-1023},{12,-2047},{13,-4095},{14,-8191},{15,-16383},
|
||||
{3,0},{5,3},{7,5},{10,9},{4,-7},{5,-15},{6,-31},{7,-63},
|
||||
{3,0},{5,3},{7,5},{10,9},{4,-7},{5,-15},{6,-31},{7,-63},
|
||||
{3,0},{5,3},{7,5},{10,9},{4,-7},{5,-15},{6,-31},{7,-63},
|
||||
{3,0},{5,3},{7,5},{10,9},{4,-7},{5,-15},{6,-31},{7,-63},
|
||||
{3,0},{5,3},{7,5},{10,9},{4,-7},{5,-15},{6,-31},{7,-63},
|
||||
{3,0},{5,3},{7,5},{10,9},{4,-7},{5,-15},{6,-31},{7,-63},
|
||||
{3,0},{5,3},{7,5},{10,9},{4,-7},{5,-15},{6,-31},{7,-63},
|
||||
{3,0},{5,3},{7,5},{10,9},{4,-7},{5,-15},{6,-31},{7,-63},
|
||||
{3,0},{5,3},{7,5},{10,9},{4,-7},{5,-15},{6,-31},{7,-63},
|
||||
{3,0},{5,3},{7,5},{10,9},{4,-7},{5,-15},{6,-31},{7,-63}
|
||||
};
|
||||
|
||||
struct al_table CodecMPEG::gAlloc4[] =
|
||||
{
|
||||
{4,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{6,-31},{7,-63},{8,-127},
|
||||
{9,-255},{10,-511},{11,-1023},{12,-2047},{13,-4095},{14,-8191},
|
||||
{4,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{6,-31},{7,-63},{8,-127},
|
||||
{9,-255},{10,-511},{11,-1023},{12,-2047},{13,-4095},{14,-8191},
|
||||
{4,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{6,-31},{7,-63},{8,-127},
|
||||
{9,-255},{10,-511},{11,-1023},{12,-2047},{13,-4095},{14,-8191},
|
||||
{4,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{6,-31},{7,-63},{8,-127},
|
||||
{9,-255},{10,-511},{11,-1023},{12,-2047},{13,-4095},{14,-8191},
|
||||
{3,0},{5,3},{7,5},{10,9},{4,-7},{5,-15},{6,-31},{7,-63},
|
||||
{3,0},{5,3},{7,5},{10,9},{4,-7},{5,-15},{6,-31},{7,-63},
|
||||
{3,0},{5,3},{7,5},{10,9},{4,-7},{5,-15},{6,-31},{7,-63},
|
||||
{3,0},{5,3},{7,5},{10,9},{4,-7},{5,-15},{6,-31},{7,-63},
|
||||
{3,0},{5,3},{7,5},{10,9},{4,-7},{5,-15},{6,-31},{7,-63},
|
||||
{3,0},{5,3},{7,5},{10,9},{4,-7},{5,-15},{6,-31},{7,-63},
|
||||
{3,0},{5,3},{7,5},{10,9},{4,-7},{5,-15},{6,-31},{7,-63},
|
||||
{2,0},{5,3},{7,5},{10,9},
|
||||
{2,0},{5,3},{7,5},{10,9},
|
||||
{2,0},{5,3},{7,5},{10,9},
|
||||
{2,0},{5,3},{7,5},{10,9},
|
||||
{2,0},{5,3},{7,5},{10,9},
|
||||
{2,0},{5,3},{7,5},{10,9},
|
||||
{2,0},{5,3},{7,5},{10,9},
|
||||
{2,0},{5,3},{7,5},{10,9},
|
||||
{2,0},{5,3},{7,5},{10,9},
|
||||
{2,0},{5,3},{7,5},{10,9},
|
||||
{2,0},{5,3},{7,5},{10,9},
|
||||
{2,0},{5,3},{7,5},{10,9},
|
||||
{2,0},{5,3},{7,5},{10,9},
|
||||
{2,0},{5,3},{7,5},{10,9},
|
||||
{2,0},{5,3},{7,5},{10,9},
|
||||
{2,0},{5,3},{7,5},{10,9},
|
||||
{2,0},{5,3},{7,5},{10,9},
|
||||
{2,0},{5,3},{7,5},{10,9},
|
||||
{2,0},{5,3},{7,5},{10,9}
|
||||
};
|
||||
|
||||
|
||||
#if defined(PLATFORM_PS3_SPU_STREAMDECODE) || !defined(PLATFORM_PS3_SPU)
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT CodecMPEG::initLayer2()
|
||||
{
|
||||
float mulmul[27] =
|
||||
{
|
||||
0.0f , -2.0f/3.0f , 2.0f/3.0f ,
|
||||
2.0f/7.0f , 2.0f/15.0f , 2.0f/31.0f, 2.0f/63.0f , 2.0f/127.0f , 2.0f/255.0f ,
|
||||
2.0f/511.0f , 2.0f/1023.0f , 2.0f/2047.0f , 2.0f/4095.0f , 2.0f/8191.0f ,
|
||||
2.0f/16383.0f , 2.0f/32767.0f , 2.0f/65535.0f ,
|
||||
-4.0f/5.0f , -2.0f/5.0f , 2.0f/5.0f, 4.0f/5.0f ,
|
||||
-8.0f/9.0f , -4.0f/9.0f , -2.0f/9.0f , 2.0f/9.0f , 4.0f/9.0f , 8.0f/9.0f
|
||||
};
|
||||
char base[3][9] =
|
||||
{
|
||||
{ 1 , 0, 2 , } ,
|
||||
{ 17, 18, 0 , 19, 20 , } ,
|
||||
{ 21, 1, 22, 23, 0, 24, 25, 2, 26 }
|
||||
};
|
||||
int i,j,k,l,len;
|
||||
int tablen[3] = { 3 , 5 , 9 };
|
||||
unsigned char *itable,*tables[3] = { gGrp3Tab , gGrp5Tab , gGrp9Tab };
|
||||
|
||||
for(i=0;i<3;i++)
|
||||
{
|
||||
itable = tables[i];
|
||||
len = tablen[i];
|
||||
for(j=0;j<len;j++)
|
||||
{
|
||||
for(k=0;k<len;k++)
|
||||
{
|
||||
for(l=0;l<len;l++)
|
||||
{
|
||||
*itable++ = base[i][l];
|
||||
*itable++ = base[i][k];
|
||||
*itable++ = base[i][j];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef USE_MULS_TABLE
|
||||
{
|
||||
float * table;
|
||||
|
||||
for(k=0;k<27;k++)
|
||||
{
|
||||
float m=mulmul[k];
|
||||
table = gMulsTab[k];
|
||||
|
||||
for(j=3,i=0;i<63;i++,j--)
|
||||
*table++ = (float)(m * FMOD_POW(2.0f, (3 - i) / 3.0f));
|
||||
|
||||
*table++ = 0.0f;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
return FMOD_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT CodecMPEG::II_step_one(unsigned int *bit_alloc,int *scale)
|
||||
{
|
||||
int stereo = mMemoryBlock->mFrame.stereo-1;
|
||||
int sblimit = mMemoryBlock->mFrame.II_sblimit;
|
||||
int jsbound = mMemoryBlock->mFrame.jsbound;
|
||||
int sblimit2 = mMemoryBlock->mFrame.II_sblimit<<stereo;
|
||||
struct al_table *alloc1 = mMemoryBlock->mFrame.alloc;
|
||||
int i;
|
||||
unsigned int scfsi_buf[64];
|
||||
unsigned int *scfsi,*bita;
|
||||
int sc,step;
|
||||
|
||||
bita = bit_alloc;
|
||||
|
||||
if(stereo)
|
||||
{
|
||||
for (i=jsbound;i;i--,alloc1+=(1<<step))
|
||||
{
|
||||
*bita++ = (char)getBits(step=alloc1->bits);
|
||||
*bita++ = (char)getBits(step);
|
||||
}
|
||||
for (i=sblimit-jsbound;i;i--,alloc1+=(1<<step))
|
||||
{
|
||||
bita[0] = (char) getBits(step=alloc1->bits);
|
||||
bita[1] = bita[0];
|
||||
bita+=2;
|
||||
}
|
||||
|
||||
bita = bit_alloc;
|
||||
scfsi=scfsi_buf;
|
||||
|
||||
for (i=sblimit2;i;i--)
|
||||
if (*bita++)
|
||||
*scfsi++ = (char) getBitsFast(2);
|
||||
}
|
||||
else // mono
|
||||
{
|
||||
for (i=sblimit;i;i--,alloc1+=(1<<step))
|
||||
{
|
||||
*bita++ = (char) getBits(step=alloc1->bits);
|
||||
}
|
||||
|
||||
bita = bit_alloc;
|
||||
scfsi=scfsi_buf;
|
||||
|
||||
for (i=sblimit;i;i--)
|
||||
{
|
||||
if (*bita++)
|
||||
{
|
||||
*scfsi++ = (char) getBitsFast(2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bita = bit_alloc;
|
||||
scfsi=scfsi_buf;
|
||||
for (i=sblimit2;i;i--)
|
||||
{
|
||||
if (*bita++)
|
||||
{
|
||||
switch (*scfsi++)
|
||||
{
|
||||
case 0:
|
||||
*scale++ = getBitsFast(6);
|
||||
*scale++ = getBitsFast(6);
|
||||
*scale++ = getBitsFast(6);
|
||||
break;
|
||||
case 1 :
|
||||
*scale++ = sc = getBitsFast(6);
|
||||
*scale++ = sc;
|
||||
*scale++ = getBitsFast(6);
|
||||
break;
|
||||
case 2:
|
||||
*scale++ = sc = getBitsFast(6);
|
||||
*scale++ = sc;
|
||||
*scale++ = sc;
|
||||
break;
|
||||
default: // case 3
|
||||
*scale++ = getBitsFast(6);
|
||||
*scale++ = sc = getBitsFast(6);
|
||||
*scale++ = sc;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT CodecMPEG::II_step_two(unsigned int *bit_alloc,float fraction[2][4][SBLIMIT],int *scale,int x1)
|
||||
{
|
||||
int i,j,k,ba;
|
||||
int stereo = mMemoryBlock->mFrame.stereo;
|
||||
int sblimit = mMemoryBlock->mFrame.II_sblimit;
|
||||
int jsbound = mMemoryBlock->mFrame.jsbound;
|
||||
struct al_table *alloc2,*alloc1 = mMemoryBlock->mFrame.alloc;
|
||||
unsigned int * bita=bit_alloc;
|
||||
int d1,step;
|
||||
|
||||
for (i=0;i<jsbound;i++,alloc1+=(1<<step))
|
||||
{
|
||||
step = alloc1->bits;
|
||||
for (j=0;j<stereo;j++)
|
||||
{
|
||||
ba=*bita++;
|
||||
if ( ba )
|
||||
{
|
||||
k=(alloc2 = alloc1+ba)->bits;
|
||||
if( (d1=alloc2->d) < 0)
|
||||
{
|
||||
float cm = gMuls(k, scale[x1]);
|
||||
|
||||
fraction[j][0][i] = ((float) ((int)getBits(k) + d1)) * cm;
|
||||
fraction[j][1][i] = ((float) ((int)getBits(k) + d1)) * cm;
|
||||
fraction[j][2][i] = ((float) ((int)getBits(k) + d1)) * cm;
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned char *table[] = { 0,0,0, gGrp3Tab, 0, gGrp5Tab, 0, 0, 0, gGrp9Tab };
|
||||
unsigned int idx,m=scale[x1];
|
||||
unsigned char *tab;
|
||||
|
||||
idx = (unsigned int) getBits(k);
|
||||
tab = table[d1] + idx + idx + idx;
|
||||
|
||||
fraction[j][0][i] = gMuls(*tab++, m);
|
||||
fraction[j][1][i] = gMuls(*tab++, m);
|
||||
fraction[j][2][i] = gMuls(*tab, m);
|
||||
}
|
||||
scale+=3;
|
||||
}
|
||||
else
|
||||
{
|
||||
fraction[j][0][i] = fraction[j][1][i] = fraction[j][2][i] = 0.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
for (i=jsbound;i<sblimit;i++,alloc1+=(1<<step))
|
||||
{
|
||||
step = alloc1->bits;
|
||||
bita++; // channel 1 and channel 2 bitalloc are the same
|
||||
|
||||
ba=*bita++;
|
||||
if (ba)
|
||||
{
|
||||
k=(alloc2 = alloc1+ba)->bits;
|
||||
if( (d1=alloc2->d) < 0)
|
||||
{
|
||||
float cm;
|
||||
cm = gMuls(k, scale[x1+3]);
|
||||
fraction[1][0][i] = (fraction[0][0][i] = (float) ((int)getBits(k) + d1) ) * cm;
|
||||
fraction[1][1][i] = (fraction[0][1][i] = (float) ((int)getBits(k) + d1) ) * cm;
|
||||
fraction[1][2][i] = (fraction[0][2][i] = (float) ((int)getBits(k) + d1) ) * cm;
|
||||
cm = gMuls(k, scale[x1]);
|
||||
fraction[0][0][i] *= cm; fraction[0][1][i] *= cm; fraction[0][2][i] *= cm;
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned char *table[] = { 0,0,0, gGrp3Tab, 0, gGrp5Tab, 0, 0, 0, gGrp9Tab };
|
||||
unsigned int idx,m1,m2;
|
||||
unsigned char *tab;
|
||||
|
||||
m1 = scale[x1]; m2 = scale[x1+3];
|
||||
idx = (unsigned int) getBits(k);
|
||||
tab = table[d1] + idx + idx + idx;
|
||||
fraction[0][0][i] = gMuls(*tab, m1); fraction[1][0][i] = gMuls(*tab++, m2);
|
||||
fraction[0][1][i] = gMuls(*tab, m1); fraction[1][1][i] = gMuls(*tab++, m2);
|
||||
fraction[0][2][i] = gMuls(*tab, m1); fraction[1][2][i] = gMuls(*tab, m2);
|
||||
}
|
||||
scale+=6;
|
||||
}
|
||||
else
|
||||
{
|
||||
fraction[0][0][i] = fraction[0][1][i] = fraction[0][2][i] =
|
||||
fraction[1][0][i] = fraction[1][1][i] = fraction[1][2][i] = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
for(i=sblimit;i<SBLIMIT;i++)
|
||||
{
|
||||
for (j=0;j<stereo;j++)
|
||||
{
|
||||
fraction[j][0][i] = fraction[j][1][i] = fraction[j][2][i] = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT CodecMPEG::getIIStuff()
|
||||
{
|
||||
int translate[3][2][16] =
|
||||
{
|
||||
{
|
||||
{ 0,2,2,2,2,2,2,0,0,0,1,1,1,1,1,0 } ,
|
||||
{ 0,2,2,0,0,0,1,1,1,1,1,1,1,1,1,0 }
|
||||
} ,
|
||||
{
|
||||
{ 0,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0 } ,
|
||||
{ 0,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0 } } ,
|
||||
{
|
||||
{ 0,3,3,3,3,3,3,0,0,0,1,1,1,1,1,0 } ,
|
||||
{ 0,3,3,0,0,0,1,1,1,1,1,1,1,1,1,0 }
|
||||
}
|
||||
};
|
||||
|
||||
int table,sblim;
|
||||
struct al_table *tables[5] = { gAlloc0, gAlloc1, gAlloc2, gAlloc3 , gAlloc4 };
|
||||
int sblims[5] = { 27 , 30 , 8, 12 , 30 };
|
||||
|
||||
if (mMemoryBlock->mFrame.lsf)
|
||||
{
|
||||
table = 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
table = translate[mMemoryBlock->mFrame.sampling_frequency][2-mMemoryBlock->mFrame.stereo][mMemoryBlock->mFrame.bitrate_index];
|
||||
}
|
||||
|
||||
sblim = sblims[table];
|
||||
|
||||
mMemoryBlock->mFrame.alloc = tables[table];
|
||||
mMemoryBlock->mFrame.II_sblimit = sblim;
|
||||
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT CodecMPEG::decodeLayer2(void *pcm_sample, unsigned int *outlen)
|
||||
{
|
||||
int i,j = 0;
|
||||
int channels = mMemoryBlock->mFrame.stereo;
|
||||
float fraction[2][4][SBLIMIT]; // pick_table clears unused subbands
|
||||
unsigned int bit_alloc[64];
|
||||
int scale[192];
|
||||
int inc = SBLIMIT * sizeof(signed short);
|
||||
|
||||
II_step_one(bit_alloc, scale);
|
||||
|
||||
*outlen = 0;
|
||||
|
||||
for (i=0;i<SCALE_BLOCK;i++)
|
||||
{
|
||||
II_step_two(bit_alloc,fraction,scale,i>>2);
|
||||
|
||||
for (j=0;j<3;j++)
|
||||
{
|
||||
synth(pcm_sample, fraction[0][j], channels, waveformat->channels > 2 ? waveformat->channels : channels);
|
||||
|
||||
pcm_sample = (char *)pcm_sample + inc * waveformat->channels;
|
||||
*outlen += inc * channels;
|
||||
}
|
||||
}
|
||||
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
||||
|
||||
#endif //#ifndef FMOD_SUPPORT_MPEG_SONYDECODER
|
||||
|
||||
}
|
||||
|
||||
#endif // FMOD_SUPPORT_MPEG_LAYER2
|
||||
|
||||
#endif // FMOD_SUPPORT_MPEG
|
||||
|
||||
3126
src/fmod_codec_mpeg_layer3.cpp
Executable file
3126
src/fmod_codec_mpeg_layer3.cpp
Executable file
File diff suppressed because it is too large
Load diff
823
src/fmod_codec_oggvorbis.cpp
Executable file
823
src/fmod_codec_oggvorbis.cpp
Executable file
|
|
@ -0,0 +1,823 @@
|
|||
#include "fmod_settings.h"
|
||||
|
||||
#ifdef FMOD_SUPPORT_OGGVORBIS
|
||||
|
||||
#include "fmod.h"
|
||||
#include "fmod_codec_oggvorbis.h"
|
||||
#include "fmod_codec_wav.h"
|
||||
#include "fmod_debug.h"
|
||||
#include "fmod_file.h"
|
||||
#include "fmod_metadata.h"
|
||||
#include "fmod_string.h"
|
||||
|
||||
#include "../lib/ogg_vorbis/vorbis/lib/window.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
|
||||
void * FMOD_OggVorbis_Malloc(void *context, int size)
|
||||
{
|
||||
void *mem = FMOD_Memory_Alloc(size);
|
||||
|
||||
if (mem && context)
|
||||
{
|
||||
FMOD::CodecOggVorbis *ogg = (FMOD::CodecOggVorbis *)context;
|
||||
|
||||
ogg->mMemUsed += size;
|
||||
}
|
||||
|
||||
return mem;
|
||||
}
|
||||
void * FMOD_OggVorbis_Calloc(void *context, int count, int size)
|
||||
{
|
||||
void *mem = FMOD_Memory_Calloc(count * size);
|
||||
|
||||
if (mem && context)
|
||||
{
|
||||
FMOD::CodecOggVorbis *ogg = (FMOD::CodecOggVorbis *)context;
|
||||
ogg->mMemUsed += (count * size);
|
||||
}
|
||||
|
||||
return mem;
|
||||
}
|
||||
void * FMOD_OggVorbis_ReAlloc(void *context, void *ptr, int size)
|
||||
{
|
||||
void *mem;
|
||||
FMOD::CodecOggVorbis *ogg = (FMOD::CodecOggVorbis *)context;
|
||||
|
||||
if (ptr && ogg)
|
||||
{
|
||||
FMOD::MemBlockHeader *block = (FMOD::MemBlockHeader *)ptr;
|
||||
|
||||
block--;
|
||||
|
||||
ogg->mMemUsed -= block->mSize;
|
||||
}
|
||||
|
||||
mem = FMOD_Memory_ReAlloc(ptr, size);
|
||||
if (mem && ogg)
|
||||
{
|
||||
ogg->mMemUsed += size;
|
||||
}
|
||||
|
||||
return mem;
|
||||
}
|
||||
void FMOD_OggVorbis_Free(void *context, void *ptr)
|
||||
{
|
||||
if (ptr && context)
|
||||
{
|
||||
FMOD::MemBlockHeader *block = (FMOD::MemBlockHeader *)ptr;
|
||||
FMOD::CodecOggVorbis *ogg = (FMOD::CodecOggVorbis *)context;
|
||||
|
||||
block--;
|
||||
|
||||
ogg->mMemUsed -= block->mSize;
|
||||
}
|
||||
|
||||
FMOD_Memory_Free(ptr);
|
||||
}
|
||||
|
||||
|
||||
namespace FMOD
|
||||
{
|
||||
|
||||
|
||||
FMOD_CODEC_DESCRIPTION_EX oggvorbiscodec;
|
||||
|
||||
#ifdef PLUGIN_EXPORTS
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
FMODGetCodecDescription is mandantory for every fmod plugin. This is the symbol the registerplugin function searches for.
|
||||
Must be declared with F_API to make it export as stdcall.
|
||||
*/
|
||||
F_DECLSPEC F_DLLEXPORT FMOD_CODEC_DESCRIPTION_EX * F_API FMODGetCodecDescriptionEx()
|
||||
{
|
||||
return CodecOggVorbis::getDescriptionEx();
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* PLUGIN_EXPORTS */
|
||||
|
||||
/*
|
||||
Globals
|
||||
*/
|
||||
|
||||
bool CodecOggVorbis::gInitialized = false;
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
size_t FMOD_OggVorbis_ReadCallback(void *ptr, size_t size, size_t nmemb, void *datasource)
|
||||
{
|
||||
FMOD_RESULT result;
|
||||
unsigned int rd;
|
||||
File *fp;
|
||||
|
||||
fp = (File *)datasource;
|
||||
|
||||
result = fp->read(ptr, (unsigned int)size, (unsigned int)nmemb, &rd);
|
||||
if (result != FMOD_OK && result != FMOD_ERR_FILE_EOF)
|
||||
{
|
||||
return (size_t)-1;
|
||||
}
|
||||
|
||||
return rd;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
int FMOD_OggVorbis_SeekCallback(void *datasource, ogg_int64_t offset, int whence)
|
||||
{
|
||||
File *fp = (File *)datasource;
|
||||
|
||||
if (fp->mFlags & FMOD_FILE_SEEKABLE)
|
||||
{
|
||||
return fp->seek((int)offset, (signed char)whence);
|
||||
}
|
||||
else
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
ogg_int32_t FMOD_OggVorbis_TellCallback(void *datasource)
|
||||
{
|
||||
File *fp = (File *)datasource;
|
||||
unsigned int pos;
|
||||
|
||||
fp->tell(&pos);
|
||||
|
||||
return (ogg_int32_t)pos;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_CODEC_DESCRIPTION_EX *CodecOggVorbis::getDescriptionEx()
|
||||
{
|
||||
FMOD_memset(&oggvorbiscodec, 0, sizeof(FMOD_CODEC_DESCRIPTION_EX));
|
||||
|
||||
oggvorbiscodec.name = "FMOD Ogg Vorbis Codec";
|
||||
oggvorbiscodec.version = 0x00010100;
|
||||
oggvorbiscodec.timeunits = FMOD_TIMEUNIT_PCM;
|
||||
oggvorbiscodec.open = &CodecOggVorbis::openCallback;
|
||||
oggvorbiscodec.close = &CodecOggVorbis::closeCallback;
|
||||
oggvorbiscodec.read = &CodecOggVorbis::readCallback;
|
||||
oggvorbiscodec.setposition = &CodecOggVorbis::setPositionCallback;
|
||||
#ifdef FMOD_SUPPORT_MEMORYTRACKER
|
||||
oggvorbiscodec.getmemoryused = &CodecOggVorbis::getMemoryUsedCallback;
|
||||
#endif
|
||||
|
||||
oggvorbiscodec.mType = FMOD_SOUND_TYPE_OGGVORBIS;
|
||||
oggvorbiscodec.mSize = sizeof(CodecOggVorbis);
|
||||
|
||||
return &oggvorbiscodec;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT CodecOggVorbis::openInternal(FMOD_MODE usermode, FMOD_CREATESOUNDEXINFO *userexinfo)
|
||||
{
|
||||
FMOD_RESULT result = FMOD_OK;
|
||||
vorbis_info *vi;
|
||||
char str[4];
|
||||
unsigned int lengthbytes = 0;
|
||||
int oggresult;
|
||||
ov_callbacks callbacks =
|
||||
{
|
||||
FMOD_OggVorbis_ReadCallback, /* size_t (*read_func) (void *ptr, size_t size, size_t nmemb, void *datasource); */
|
||||
FMOD_OggVorbis_SeekCallback, /* int (*seek_func) (void *datasource, ogg_int64_t offset, int whence); */
|
||||
0, /* int (*close_func) (void *datasource); */
|
||||
FMOD_OggVorbis_TellCallback, /* int (*tell_func) (void *datasource); */
|
||||
};
|
||||
bool manualsizecalc = false;
|
||||
|
||||
init(FMOD_SOUND_TYPE_OGGVORBIS);
|
||||
|
||||
FLOG((FMOD_DEBUG_LEVEL_LOG, __FILE__, __LINE__, "CodecOggVorbis::openInternal", "attempting to open as OGG..\n"));
|
||||
|
||||
result = mFile->seek(0, SEEK_SET);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
mSrcDataOffset = 0;
|
||||
|
||||
/*
|
||||
Support RIFF wrapped MP3?
|
||||
*/
|
||||
{
|
||||
CodecWav tempwav;
|
||||
WAVE_CHUNK chunk;
|
||||
FMOD_CODEC_WAVEFORMAT tempwaveformat;
|
||||
|
||||
FMOD_memset(&tempwav, 0, sizeof(CodecWav));
|
||||
FMOD_memset(&tempwaveformat, 0, sizeof(FMOD_CODEC_WAVEFORMAT));
|
||||
|
||||
tempwav.mFile = mFile;
|
||||
tempwav.mSrcDataOffset = (unsigned int)-1;
|
||||
tempwav.waveformat = &tempwaveformat;
|
||||
|
||||
/*
|
||||
Read header
|
||||
*/
|
||||
result = mFile->read(&chunk, 1, sizeof(WAVE_CHUNK), 0);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
if (!FMOD_strncmp((const char *)chunk.id, "RIFF", 4))
|
||||
{
|
||||
char wave[4];
|
||||
|
||||
result = mFile->read(wave, 1, 4, 0);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
if (!FMOD_strncmp(wave, "WAVE", 4))
|
||||
{
|
||||
#ifdef PLATFORM_ENDIAN_BIG
|
||||
chunk.size = FMOD_SWAPENDIAN_DWORD(chunk.size);
|
||||
#endif
|
||||
|
||||
result = tempwav.parseChunk(chunk.size);
|
||||
if (result == FMOD_OK && tempwav.mSrcFormat && tempwav.mSrcDataOffset == (unsigned int)-1)
|
||||
{
|
||||
int format = tempwav.mSrcFormat->Format.wFormatTag;
|
||||
|
||||
if (format == WAVE_FORMAT_OGGVORBIS)
|
||||
{
|
||||
mSrcDataOffset = tempwav.mSrcDataOffset;
|
||||
lengthbytes = tempwav.waveformat[0].lengthbytes;
|
||||
mLoopPoints[0] = tempwav.mLoopPoints[0];
|
||||
mLoopPoints[1] = tempwav.mLoopPoints[1];
|
||||
mSyncPoint = tempwav.mSyncPoint;
|
||||
mNumSyncPoints = tempwav.mNumSyncPoints;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = FMOD_ERR_FORMAT;
|
||||
}
|
||||
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
if (tempwav.mSrcFormat)
|
||||
{
|
||||
FMOD_Memory_Free(tempwav.mSrcFormat);
|
||||
tempwav.mSrcFormat = 0;
|
||||
}
|
||||
if (tempwav.mSyncPoint && mSyncPoint != tempwav.mSyncPoint)
|
||||
{
|
||||
FMOD_Memory_Free(tempwav.mSyncPoint);
|
||||
tempwav.mSyncPoint = 0;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
if (tempwav.mSrcFormat)
|
||||
{
|
||||
FMOD_Memory_Free(tempwav.mSrcFormat);
|
||||
tempwav.mSrcFormat = 0;
|
||||
}
|
||||
if (tempwav.mSyncPoint && mSyncPoint != tempwav.mSyncPoint)
|
||||
{
|
||||
FMOD_Memory_Free(tempwav.mSyncPoint);
|
||||
tempwav.mSyncPoint = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
result = mFile->seek(mSrcDataOffset, SEEK_SET);
|
||||
}
|
||||
|
||||
result = mFile->read(str, 1, 4, 0);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
if (FMOD_strncmp(str, "OggS", 4))
|
||||
{
|
||||
FLOG((FMOD_DEBUG_LEVEL_LOG, __FILE__, __LINE__, "CodecOggVorbis::openInternal", "failed to open as ogg\n"));
|
||||
|
||||
return FMOD_ERR_FORMAT;
|
||||
}
|
||||
|
||||
if (!gInitialized)
|
||||
{
|
||||
_FMOD_vorbis_window_init();
|
||||
gInitialized = true;
|
||||
}
|
||||
|
||||
/*
|
||||
Get size of ogg file in bytes
|
||||
*/
|
||||
/*
|
||||
If there wasnt a riff size chunk
|
||||
*/
|
||||
if (!lengthbytes)
|
||||
{
|
||||
result = mFile->getSize(&lengthbytes);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
manualsizecalc = true;
|
||||
}
|
||||
|
||||
result = mFile->seek(mSrcDataOffset, SEEK_SET);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
memset(&mVf, 0, sizeof(OggVorbis_File)); /* Just in case of an error code, it wont crash on invalid pointers trying to clean up. */
|
||||
|
||||
oggresult = ov_open_callbacks(this, mFile, &mVf, 0, 0, callbacks);
|
||||
if (oggresult < 0)
|
||||
{
|
||||
FLOG((FMOD_DEBUG_LEVEL_LOG, __FILE__, __LINE__, "CodecOggVorbis::openInternal", "failed to open as ogg, format error.\n"));
|
||||
|
||||
if (oggresult == OV_EVERSION)
|
||||
{
|
||||
FLOG((FMOD_DEBUG_LEVEL_LOG, __FILE__, __LINE__, "CodecOggVorbis::openInternal", "OLD FLOOR0 TYPE OGG FILE. Please re-encode sound with a newer encoder.\n"));
|
||||
return FMOD_ERR_FORMAT;
|
||||
}
|
||||
else if (oggresult == OV_EMEMORY)
|
||||
{
|
||||
return FMOD_ERR_MEMORY;
|
||||
}
|
||||
return FMOD_ERR_FORMAT;
|
||||
}
|
||||
|
||||
vi = ov_info(&mVf,-1);
|
||||
|
||||
result = readVorbisComments();
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
waveformat = &mWaveFormat;
|
||||
waveformat[0].lengthbytes = lengthbytes;
|
||||
waveformat[0].format = FMOD_SOUND_FORMAT_PCM16;
|
||||
waveformat[0].channels = vi->channels;
|
||||
waveformat[0].frequency = vi->rate;
|
||||
waveformat[0].blockalign = waveformat[0].channels * 2; /* THIS SHOULD BE EQUIVALENT TO THE OGG DECODE BUFFER SIZE? */
|
||||
|
||||
if (manualsizecalc && waveformat[0].lengthbytes != (unsigned int)-1)
|
||||
{
|
||||
waveformat[0].lengthbytes -= mSrcDataOffset;
|
||||
}
|
||||
|
||||
if (mFile->mFlags & FMOD_FILE_SEEKABLE)
|
||||
{
|
||||
int count, streams = ov_streams(&mVf);
|
||||
|
||||
waveformat[0].lengthpcm = 0;
|
||||
|
||||
for (count = 0; count < streams; count++)
|
||||
{
|
||||
waveformat[0].lengthpcm += (int)ov_pcm_total(&mVf, count);
|
||||
}
|
||||
|
||||
if (waveformat[0].lengthpcm <= 0)
|
||||
{
|
||||
FLOG((FMOD_DEBUG_LEVEL_LOG, __FILE__, __LINE__, "CodecOggVorbis::openInternal", "failed to open as ogg\n"));
|
||||
|
||||
waveformat[0].lengthpcm = 0;
|
||||
|
||||
return FMOD_ERR_FORMAT;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
waveformat[0].lengthpcm = 0x7fffffff;
|
||||
}
|
||||
|
||||
if (!mSrcDataOffset)
|
||||
{
|
||||
mSrcDataOffset = (unsigned int)ov_raw_tell(&mVf);
|
||||
}
|
||||
|
||||
/*
|
||||
Fill out base class members, also pointing to or allocating storage for them.
|
||||
*/
|
||||
numsubsounds = 0;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT CodecOggVorbis::closeInternal()
|
||||
{
|
||||
mVf.datasource = 0; /* this stops vorbis from trying to close our file */
|
||||
|
||||
ov_clear(this, &mVf);
|
||||
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT CodecOggVorbis::readInternal(void *buffer, unsigned int sizebytes, unsigned int *bytesread)
|
||||
{
|
||||
int bigendian;
|
||||
vorbis_comment *vc;
|
||||
char *name, *value;
|
||||
int i;
|
||||
|
||||
#ifdef PLATFORM_ENDIAN_BIG
|
||||
bigendian = 1;
|
||||
#else
|
||||
bigendian = 0;
|
||||
#endif
|
||||
|
||||
*bytesread = ov_read(this, &mVf, (char *)buffer, sizebytes, bigendian, 2, 1, 0);
|
||||
if (((int)(*bytesread)) <= 0)
|
||||
{
|
||||
if ((int)*bytesread == OV_EINVAL)
|
||||
{
|
||||
*bytesread = 0;
|
||||
return FMOD_ERR_INVALID_PARAM;
|
||||
}
|
||||
else if ((int)*bytesread == OV_EMEMORY)
|
||||
{
|
||||
return FMOD_ERR_MEMORY;
|
||||
}
|
||||
else if ((int)*bytesread != OV_HOLE) /* Don't bail if we encounter a hole. */
|
||||
{
|
||||
*bytesread = 0;
|
||||
return FMOD_ERR_FILE_EOF;
|
||||
}
|
||||
*bytesread = 0;
|
||||
}
|
||||
|
||||
vc = ov_comment(&mVf, -1);
|
||||
|
||||
if (vc && vc->comments)
|
||||
{
|
||||
for (i=0;i < vc->comments;i++)
|
||||
{
|
||||
name = vc->user_comments[i];
|
||||
value = name;
|
||||
for (;*value && (*value != '=');value++) ;
|
||||
|
||||
if (*value == '=')
|
||||
{
|
||||
*value++ = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
value = name;
|
||||
name = (char *)"NONAME";
|
||||
}
|
||||
|
||||
metadata((FMOD_CODEC_STATE *)this, FMOD_TAGTYPE_VORBISCOMMENT, name, value, FMOD_strlen(value) + 1, FMOD_TAGDATATYPE_STRING, true);
|
||||
}
|
||||
|
||||
FMOD_vorbis_comment_clear(this, vc);
|
||||
}
|
||||
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT CodecOggVorbis::setPositionInternal(int subsound, unsigned int position, FMOD_TIMEUNIT postype)
|
||||
{
|
||||
int ret = ov_pcm_seek(this, &mVf, position);
|
||||
if (ret < 0)
|
||||
{
|
||||
if (ret == OV_EMEMORY)
|
||||
{
|
||||
return FMOD_ERR_MEMORY;
|
||||
}
|
||||
return FMOD_ERR_FILE_COULDNOTSEEK;
|
||||
}
|
||||
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT CodecOggVorbis::readVorbisComments()
|
||||
{
|
||||
FMOD_RESULT result;
|
||||
char *p;
|
||||
int count, i;
|
||||
vorbis_comment *vc;
|
||||
|
||||
vc = ov_comment(&mVf, -1);
|
||||
if (!vc)
|
||||
{
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
||||
for (count = 0; count < vc->comments; count++)
|
||||
{
|
||||
if (vc->comment_lengths[count])
|
||||
{
|
||||
p = vc->user_comments[count];
|
||||
for (i=0;*p && (*p != '=');i++, p++) ;
|
||||
if (*p == '=')
|
||||
{
|
||||
*p++ = 0;
|
||||
result = metaData(FMOD_TAGTYPE_VORBISCOMMENT, vc->user_comments[count], p, FMOD_strlen(p) + 1, FMOD_TAGDATATYPE_STRING, false);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
||||
|
||||
#ifdef FMOD_SUPPORT_MEMORYTRACKER
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT CodecOggVorbis::getMemoryUsedImpl(MemoryTracker *tracker)
|
||||
{
|
||||
tracker->add(false, FMOD_MEMBITS_CODEC, mMemUsed);
|
||||
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT F_CALLBACK CodecOggVorbis::openCallback(FMOD_CODEC_STATE *codec, FMOD_MODE usermode, FMOD_CREATESOUNDEXINFO *userexinfo)
|
||||
{
|
||||
CodecOggVorbis *ogg = (CodecOggVorbis *)codec;
|
||||
|
||||
return ogg->openInternal(usermode, userexinfo);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT F_CALLBACK CodecOggVorbis::closeCallback(FMOD_CODEC_STATE *codec)
|
||||
{
|
||||
CodecOggVorbis *ogg = (CodecOggVorbis *)codec;
|
||||
|
||||
return ogg->closeInternal();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT F_CALLBACK CodecOggVorbis::readCallback(FMOD_CODEC_STATE *codec, void *buffer, unsigned int sizebytes, unsigned int *bytesread)
|
||||
{
|
||||
CodecOggVorbis *ogg = (CodecOggVorbis *)codec;
|
||||
|
||||
return ogg->readInternal(buffer, sizebytes, bytesread);
|
||||
}
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT F_CALLBACK CodecOggVorbis::setPositionCallback(FMOD_CODEC_STATE *codec, int subsound, unsigned int position, FMOD_TIMEUNIT postype)
|
||||
{
|
||||
CodecOggVorbis *ogg = (CodecOggVorbis *)codec;
|
||||
|
||||
return ogg->setPositionInternal(subsound, position, postype);
|
||||
}
|
||||
|
||||
|
||||
#ifdef FMOD_SUPPORT_MEMORYTRACKER
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT F_CALLBACK CodecOggVorbis::getMemoryUsedCallback(FMOD_CODEC_STATE *codec, MemoryTracker *tracker)
|
||||
{
|
||||
CodecOggVorbis *ogg = (CodecOggVorbis *)codec;
|
||||
|
||||
return ogg->getMemoryUsed(tracker);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
54
src/fmod_codec_oggvorbis.h
Executable file
54
src/fmod_codec_oggvorbis.h
Executable file
|
|
@ -0,0 +1,54 @@
|
|||
#ifndef _FMOD_CODEC_OGGVORBIS_H
|
||||
#define _FMOD_CODEC_OGGVORBIS_H
|
||||
|
||||
#include "fmod_settings.h"
|
||||
|
||||
#ifdef FMOD_SUPPORT_OGGVORBIS
|
||||
|
||||
#include "fmod_codeci.h"
|
||||
|
||||
#include "../lib/ogg_vorbis/vorbis/include/vorbis/vorbisfile.h"
|
||||
|
||||
namespace FMOD
|
||||
{
|
||||
class SyncPointNamed;
|
||||
|
||||
class CodecOggVorbis : public Codec
|
||||
{
|
||||
DECLARE_MEMORYTRACKER_NONVIRTUAL
|
||||
|
||||
private:
|
||||
|
||||
OggVorbis_File mVf;
|
||||
static bool gInitialized;
|
||||
|
||||
SyncPointNamed *mSyncPoint;
|
||||
int mNumSyncPoints;
|
||||
FMOD_CODEC_WAVEFORMAT mWaveFormat;
|
||||
|
||||
FMOD_RESULT openInternal(FMOD_MODE usermode, FMOD_CREATESOUNDEXINFO *userexinfo);
|
||||
FMOD_RESULT closeInternal();
|
||||
FMOD_RESULT readInternal(void *buffer, unsigned int size, unsigned int *read);
|
||||
FMOD_RESULT setPositionInternal(int subsound, unsigned int position, FMOD_TIMEUNIT postype);
|
||||
FMOD_RESULT readVorbisComments();
|
||||
|
||||
public:
|
||||
|
||||
unsigned int mMemUsed;
|
||||
|
||||
static FMOD_RESULT F_CALLBACK openCallback(FMOD_CODEC_STATE *codec, FMOD_MODE usermode, FMOD_CREATESOUNDEXINFO *userexinfo);
|
||||
static FMOD_RESULT F_CALLBACK closeCallback(FMOD_CODEC_STATE *codec);
|
||||
static FMOD_RESULT F_CALLBACK readCallback(FMOD_CODEC_STATE *codec, void *buffer, unsigned int size, unsigned int *read);
|
||||
static FMOD_RESULT F_CALLBACK setPositionCallback(FMOD_CODEC_STATE *codec, int subsound, unsigned int position, FMOD_TIMEUNIT postype);
|
||||
#ifdef FMOD_SUPPORT_MEMORYTRACKER
|
||||
static FMOD_RESULT F_CALLBACK getMemoryUsedCallback(FMOD_CODEC_STATE *codec, MemoryTracker *tracker);
|
||||
#endif
|
||||
|
||||
static FMOD_CODEC_DESCRIPTION_EX *getDescriptionEx();
|
||||
};
|
||||
}
|
||||
|
||||
#endif /* FMOD_SUPPORT_OGGVORBIS */
|
||||
|
||||
#endif
|
||||
|
||||
1580
src/fmod_codec_playlist.cpp
Executable file
1580
src/fmod_codec_playlist.cpp
Executable file
File diff suppressed because it is too large
Load diff
53
src/fmod_codec_playlist.h
Executable file
53
src/fmod_codec_playlist.h
Executable file
|
|
@ -0,0 +1,53 @@
|
|||
#ifndef _FMOD_CODEC_PLAYLIST_H
|
||||
#define _FMOD_CODEC_PLAYLIST_H
|
||||
|
||||
#include "fmod_settings.h"
|
||||
|
||||
#ifdef FMOD_SUPPORT_PLAYLIST
|
||||
|
||||
#include "fmod_codeci.h"
|
||||
|
||||
namespace FMOD
|
||||
{
|
||||
class CodecPlaylist : public Codec
|
||||
{
|
||||
private:
|
||||
|
||||
FMOD_RESULT openInternal(FMOD_MODE usermode, FMOD_CREATESOUNDEXINFO *userexinfo);
|
||||
FMOD_RESULT closeInternal();
|
||||
|
||||
FMOD_RESULT readASX();
|
||||
FMOD_RESULT readWPL();
|
||||
FMOD_RESULT readM3U();
|
||||
FMOD_RESULT readPLS();
|
||||
FMOD_RESULT readB4S();
|
||||
FMOD_RESULT readSimple();
|
||||
|
||||
FMOD_RESULT getNextXMLTag(char *tagname, int *tagnamesize, char *tagdata, int *tagdatasize);
|
||||
FMOD_RESULT getPLSToken(char *buffer, int length, int *tokensize);
|
||||
FMOD_RESULT readLine(char *buffer, int length, int *linelength);
|
||||
FMOD_RESULT skipSimpleComments();
|
||||
FMOD_RESULT getQuoteData(const char *tag, char *buffer, int *datasize);
|
||||
|
||||
FMOD_RESULT skipWhiteSpace(int *numwhitespaces);
|
||||
bool isNewLine(char c);
|
||||
|
||||
FMOD_CODEC_WAVEFORMAT mWaveFormat;
|
||||
|
||||
public:
|
||||
|
||||
static FMOD_RESULT F_CALLBACK openCallback(FMOD_CODEC_STATE *codec, FMOD_MODE usermode, FMOD_CREATESOUNDEXINFO *userexinfo);
|
||||
static FMOD_RESULT F_CALLBACK closeCallback(FMOD_CODEC_STATE *codec);
|
||||
static FMOD_RESULT F_CALLBACK readCallback(FMOD_CODEC_STATE *codec, void *buffer, unsigned int sizebytes, unsigned int *bytesread);
|
||||
static FMOD_RESULT F_CALLBACK setPositionCallback(FMOD_CODEC_STATE *codec, int subsound, unsigned int position, FMOD_TIMEUNIT postype);
|
||||
static FMOD_RESULT F_CALLBACK soundcreateCallback(FMOD_CODEC_STATE *codec, int subsound, FMOD_SOUND *sound);
|
||||
|
||||
static FMOD_CODEC_DESCRIPTION_EX *getDescriptionEx();
|
||||
};
|
||||
}
|
||||
|
||||
#endif /* FMOD_SUPPORT_PLAYLIST */
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
458
src/fmod_codec_raw.cpp
Executable file
458
src/fmod_codec_raw.cpp
Executable file
|
|
@ -0,0 +1,458 @@
|
|||
#include "fmod_settings.h"
|
||||
|
||||
#ifdef FMOD_SUPPORT_RAW
|
||||
|
||||
#include "fmod.h"
|
||||
#include "fmod_codec_raw.h"
|
||||
#include "fmod_codec_wav.h"
|
||||
#include "fmod_codec_wav_imaadpcm.h"
|
||||
#include "fmod_dsp_codec.h"
|
||||
#include "fmod_debug.h"
|
||||
#include "fmod_file.h"
|
||||
#include "fmod_soundi.h"
|
||||
#include "fmod_string.h"
|
||||
|
||||
#ifdef PLATFORM_PS3_SPU
|
||||
#include "fmod_systemi_spu.h"
|
||||
#else
|
||||
#include "fmod_systemi.h"
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef PLATFORM_PS3
|
||||
extern unsigned int _binary_spu_fmod_codec_raw_pic_start[];
|
||||
#endif
|
||||
|
||||
|
||||
namespace FMOD
|
||||
{
|
||||
|
||||
|
||||
FMOD_CODEC_DESCRIPTION_EX rawcodec;
|
||||
|
||||
#ifdef PLUGIN_EXPORTS
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
FMODGetCodecDescription is mandantory for every fmod plugin. This is the symbol the registerplugin function searches for.
|
||||
Must be declared with F_API to make it export as stdcall.
|
||||
*/
|
||||
F_DECLSPEC F_DLLEXPORT FMOD_CODEC_DESCRIPTION_EX * F_API FMODGetCodecDescriptionEx()
|
||||
{
|
||||
return CodecRaw::getDescriptionEx();
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* PLUGIN_EXPORTS */
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_CODEC_DESCRIPTION_EX *CodecRaw::getDescriptionEx()
|
||||
{
|
||||
#ifndef PLATFORM_PS3_SPU
|
||||
FMOD_memset(&rawcodec, 0, sizeof(FMOD_CODEC_DESCRIPTION_EX));
|
||||
|
||||
rawcodec.name = "FMOD Raw Codec";
|
||||
rawcodec.version = 0x00010100;
|
||||
rawcodec.timeunits = FMOD_TIMEUNIT_PCM | FMOD_TIMEUNIT_RAWBYTES;
|
||||
rawcodec.open = &CodecRaw::openCallback;
|
||||
rawcodec.close = &CodecRaw::closeCallback;
|
||||
rawcodec.read = &CodecRaw::readCallback;
|
||||
rawcodec.setposition = &CodecRaw::setPositionCallback;
|
||||
rawcodec.canpoint = &CodecRaw::canPointCallback;
|
||||
|
||||
rawcodec.mType = FMOD_SOUND_TYPE_RAW;
|
||||
rawcodec.mSize = sizeof(CodecRaw);
|
||||
|
||||
#ifdef PLATFORM_PS3
|
||||
rawcodec.mModule = (FMOD_OS_LIBRARY *)_binary_spu_fmod_codec_raw_pic_start;
|
||||
#endif
|
||||
#else
|
||||
rawcodec.read = &CodecRaw::readCallback;
|
||||
rawcodec.setposition = &CodecRaw::setPositionCallback;
|
||||
#endif
|
||||
|
||||
return &rawcodec;
|
||||
}
|
||||
|
||||
#ifndef PLATFORM_PS3_SPU
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT CodecRaw::openInternal(FMOD_MODE usermode, FMOD_CREATESOUNDEXINFO *userexinfo)
|
||||
{
|
||||
FMOD_RESULT result = FMOD_OK;
|
||||
|
||||
init(FMOD_SOUND_TYPE_RAW);
|
||||
|
||||
FLOG((FMOD_DEBUG_LEVEL_LOG, __FILE__, __LINE__, "CodecRaw::openInternal", "attempting to open as RAW..\n"));
|
||||
|
||||
result = mFile->seek(0, SEEK_SET);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
waveformat = &mWaveFormat;
|
||||
|
||||
/*
|
||||
Get size of file in bytes
|
||||
*/
|
||||
result = mFile->getSize(&waveformat[0].lengthbytes);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
mSrcDataOffset = 0;
|
||||
|
||||
if (usermode & FMOD_SOFTWARE)
|
||||
{
|
||||
if (usermode & FMOD_CREATECOMPRESSEDSAMPLE)
|
||||
{
|
||||
if (1
|
||||
#if defined(FMOD_SUPPORT_IMAADPCM)
|
||||
&& userexinfo->format != FMOD_SOUND_FORMAT_IMAADPCM
|
||||
#endif
|
||||
)
|
||||
{
|
||||
return FMOD_ERR_FORMAT;
|
||||
}
|
||||
}
|
||||
else if (userexinfo->format < FMOD_SOUND_FORMAT_PCM8 || userexinfo->format > FMOD_SOUND_FORMAT_PCMFLOAT)
|
||||
{
|
||||
return FMOD_ERR_FORMAT;
|
||||
}
|
||||
}
|
||||
|
||||
waveformat[0].format = userexinfo->format;
|
||||
waveformat[0].channels = userexinfo->numchannels;
|
||||
waveformat[0].frequency = userexinfo->defaultfrequency;
|
||||
SoundI::getSamplesFromBytes(waveformat[0].lengthbytes, &waveformat[0].lengthpcm, userexinfo->numchannels, userexinfo->format);
|
||||
waveformat[0].blockalign = waveformat[0].channels * 16 / 8;
|
||||
|
||||
/*
|
||||
Fill out base class members, also pointing to or allocating storage for them.
|
||||
*/
|
||||
numsubsounds = 0;
|
||||
|
||||
#if defined(FMOD_SUPPORT_IMAADPCM) && defined(FMOD_SUPPORT_DSPCODEC)
|
||||
if (waveformat[0].format == FMOD_SOUND_FORMAT_IMAADPCM)
|
||||
{
|
||||
int count;
|
||||
|
||||
if (waveformat[0].channels > 2)
|
||||
{
|
||||
return FMOD_ERR_TOOMANYCHANNELS; /* Sorry we're only allocating memory for a pool of maximum stereo voices. */
|
||||
}
|
||||
|
||||
mSamplesPerADPCMBlock = 64;
|
||||
mReadBufferLength = 36 * waveformat[0].channels;
|
||||
|
||||
if (!mSystem->mDSPCodecPool_ADPCM.mNumDSPCodecs)
|
||||
{
|
||||
result = mSystem->mDSPCodecPool_ADPCM.init(FMOD_DSP_CATEGORY_DSPCODECADPCM, 64, mSystem->mAdvancedSettings.maxADPCMcodecs ? mSystem->mAdvancedSettings.maxADPCMcodecs : FMOD_ADVANCEDSETTINGS_MAXADPCMCODECS);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
for (count = 0; count < mSystem->mDSPCodecPool_ADPCM.mNumDSPCodecs; count++)
|
||||
{
|
||||
DSPCodec *dspcodec = SAFE_CAST(DSPCodec, mSystem->mDSPCodecPool_ADPCM.mPool[count]);
|
||||
CodecWav *wav = (CodecWav *)dspcodec->mCodec;
|
||||
|
||||
wav->mSrcFormat = &wav->mSrcFormatMemory;
|
||||
wav->mReadBuffer = mSystem->mDSPCodecPool_ADPCM.mReadBuffer;
|
||||
wav->mSrcFormat->Format.wFormatTag = WAVE_FORMAT_IMA_ADPCM;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT CodecRaw::closeInternal()
|
||||
{
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT CodecRaw::readInternal(void *buffer, unsigned int sizebytes, unsigned int *bytesread)
|
||||
{
|
||||
FMOD_RESULT result;
|
||||
|
||||
if (waveformat[0].format == FMOD_SOUND_FORMAT_PCM16)
|
||||
{
|
||||
result = mFile->read(buffer, 2, sizebytes / 2, bytesread);
|
||||
|
||||
*bytesread *= 2; /* convert from 16bit words back to bytes */
|
||||
}
|
||||
else
|
||||
{
|
||||
result = mFile->read(buffer, 1, sizebytes, bytesread);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT CodecRaw::setPositionInternal(int subsound, unsigned int position, FMOD_TIMEUNIT postype)
|
||||
{
|
||||
FMOD_RESULT result;
|
||||
unsigned int raw;
|
||||
|
||||
if (postype == FMOD_TIMEUNIT_RAWBYTES)
|
||||
{
|
||||
raw = position;
|
||||
}
|
||||
else
|
||||
{
|
||||
raw = (unsigned int)((FMOD_UINT64)position * (FMOD_UINT64)waveformat[0].lengthbytes / (FMOD_UINT64)waveformat[0].lengthpcm);
|
||||
raw /= waveformat[0].blockalign;
|
||||
raw *= waveformat[0].blockalign;
|
||||
}
|
||||
|
||||
result = mFile->seek(mSrcDataOffset + raw, SEEK_SET);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
||||
|
||||
#ifndef PLATFORM_PS3_SPU
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT CodecRaw::canPointInternal()
|
||||
{
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT F_CALLBACK CodecRaw::openCallback(FMOD_CODEC_STATE *codec, FMOD_MODE usermode, FMOD_CREATESOUNDEXINFO *userexinfo)
|
||||
{
|
||||
CodecRaw *raw = (CodecRaw *)codec;
|
||||
|
||||
return raw->openInternal(usermode, userexinfo);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT F_CALLBACK CodecRaw::closeCallback(FMOD_CODEC_STATE *codec)
|
||||
{
|
||||
CodecRaw *raw = (CodecRaw *)codec;
|
||||
|
||||
return raw->closeInternal();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT F_CALLBACK CodecRaw::readCallback(FMOD_CODEC_STATE *codec, void *buffer, unsigned int sizebytes, unsigned int *bytesread)
|
||||
{
|
||||
CodecRaw *raw = (CodecRaw *)codec;
|
||||
|
||||
return raw->readInternal(buffer, sizebytes, bytesread);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT F_CALLBACK CodecRaw::setPositionCallback(FMOD_CODEC_STATE *codec, int subsound, unsigned int position, FMOD_TIMEUNIT postype)
|
||||
{
|
||||
CodecRaw *raw = (CodecRaw *)codec;
|
||||
|
||||
return raw->setPositionInternal(subsound, position, postype);
|
||||
}
|
||||
|
||||
|
||||
#ifndef PLATFORM_PS3_SPU
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT F_CALLBACK CodecRaw::canPointCallback(FMOD_CODEC_STATE *codec)
|
||||
{
|
||||
CodecRaw *raw = (CodecRaw *)codec;
|
||||
|
||||
return raw->canPointInternal();
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
44
src/fmod_codec_raw.h
Executable file
44
src/fmod_codec_raw.h
Executable file
|
|
@ -0,0 +1,44 @@
|
|||
#ifndef _FMOD_CODEC_RAW_H
|
||||
#define _FMOD_CODEC_RAW_H
|
||||
|
||||
#include "fmod_settings.h"
|
||||
|
||||
#ifdef FMOD_SUPPORT_RAW
|
||||
|
||||
#include "fmod_codeci.h"
|
||||
|
||||
namespace FMOD
|
||||
{
|
||||
class CodecRaw : public Codec
|
||||
{
|
||||
friend class ChannelSoftware;
|
||||
friend class ChannelOpenAL;
|
||||
friend class DSPCodec;
|
||||
|
||||
private:
|
||||
|
||||
FMOD_CODEC_WAVEFORMAT mWaveFormat;
|
||||
int mSamplesPerADPCMBlock;
|
||||
|
||||
FMOD_RESULT openInternal(FMOD_MODE usermode, FMOD_CREATESOUNDEXINFO *userexinfo);
|
||||
FMOD_RESULT closeInternal();
|
||||
FMOD_RESULT readInternal(void *buffer, unsigned int size, unsigned int *read);
|
||||
FMOD_RESULT setPositionInternal(int subsound, unsigned int position, FMOD_TIMEUNIT postype);
|
||||
FMOD_RESULT canPointInternal();
|
||||
|
||||
public:
|
||||
|
||||
static FMOD_RESULT F_CALLBACK openCallback(FMOD_CODEC_STATE *codec, FMOD_MODE usermode, FMOD_CREATESOUNDEXINFO *userexinfo);
|
||||
static FMOD_RESULT F_CALLBACK closeCallback(FMOD_CODEC_STATE *codec);
|
||||
static FMOD_RESULT F_CALLBACK readCallback(FMOD_CODEC_STATE *codec, void *buffer, unsigned int sizebytes, unsigned int *bytesread);
|
||||
static FMOD_RESULT F_CALLBACK setPositionCallback(FMOD_CODEC_STATE *codec, int subsound, unsigned int position, FMOD_TIMEUNIT postype);
|
||||
static FMOD_RESULT F_CALLBACK canPointCallback(FMOD_CODEC_STATE *codec);
|
||||
|
||||
static FMOD_CODEC_DESCRIPTION_EX *getDescriptionEx();
|
||||
};
|
||||
}
|
||||
|
||||
#endif /* FMOD_SUPPORT_RAW */
|
||||
|
||||
#endif
|
||||
|
||||
2856
src/fmod_codec_s3m.cpp
Executable file
2856
src/fmod_codec_s3m.cpp
Executable file
File diff suppressed because it is too large
Load diff
111
src/fmod_codec_s3m.h
Executable file
111
src/fmod_codec_s3m.h
Executable file
|
|
@ -0,0 +1,111 @@
|
|||
#ifndef _FMOD_CODEC_S3M_H
|
||||
#define _FMOD_CODEC_S3M_H
|
||||
|
||||
#include "fmod_settings.h"
|
||||
|
||||
#ifdef FMOD_SUPPORT_S3M
|
||||
|
||||
#include "fmod_music.h"
|
||||
|
||||
namespace FMOD
|
||||
{
|
||||
class DSPI;
|
||||
class ChannelPool;
|
||||
|
||||
enum FMUSIC_S3MCOMMANDS
|
||||
{
|
||||
FMUSIC_S3M_SETSPEED = 1,
|
||||
FMUSIC_S3M_PATTERNJUMP,
|
||||
FMUSIC_S3M_PATTERNBREAK,
|
||||
FMUSIC_S3M_VOLUMESLIDE,
|
||||
FMUSIC_S3M_PORTADOWN,
|
||||
FMUSIC_S3M_PORTAUP,
|
||||
FMUSIC_S3M_PORTATO,
|
||||
FMUSIC_S3M_VIBRATO,
|
||||
FMUSIC_S3M_TREMOR,
|
||||
FMUSIC_S3M_ARPEGGIO,
|
||||
FMUSIC_S3M_VIBRATOVOLSLIDE,
|
||||
FMUSIC_S3M_PORTATOVOLSLIDE,
|
||||
FMUSIC_S3M_M,
|
||||
FMUSIC_S3M_N,
|
||||
FMUSIC_S3M_SETSAMPLEOFFSET,
|
||||
FMUSIC_S3M_P,
|
||||
FMUSIC_S3M_RETRIGVOLSLIDE,
|
||||
FMUSIC_S3M_TREMOLO,
|
||||
FMUSIC_S3M_SPECIAL,
|
||||
FMUSIC_S3M_SETTEMPO,
|
||||
FMUSIC_S3M_FINEVIBRATO,
|
||||
FMUSIC_S3M_GLOBALVOLUME,
|
||||
FMUSIC_S3M_W,
|
||||
FMUSIC_S3M_SETPAN,
|
||||
FMUSIC_S3M_Y,
|
||||
FMUSIC_S3M_Z
|
||||
};
|
||||
|
||||
enum FMUSIC_S3MCOMMANDSSPECIAL
|
||||
{
|
||||
FMUSIC_S3M_SETFILTER,
|
||||
FMUSIC_S3M_SETGLISSANDO,
|
||||
FMUSIC_S3M_SETFINETUNE,
|
||||
FMUSIC_S3M_SETVIBRATOWAVE,
|
||||
FMUSIC_S3M_SETTREMOLOWAVE,
|
||||
FMUSIC_S3M_S5,
|
||||
FMUSIC_S3M_S6,
|
||||
FMUSIC_S3M_S7,
|
||||
FMUSIC_S3M_SETPANPOSITION16,
|
||||
FMUSIC_S3M_S9,
|
||||
FMUSIC_S3M_STEREOCONTROL,
|
||||
FMUSIC_S3M_PATTERNLOOP,
|
||||
FMUSIC_S3M_NOTECUT,
|
||||
FMUSIC_S3M_NOTEDELAY,
|
||||
FMUSIC_S3M_PATTERNDELAY,
|
||||
FMUSIC_S3M_FUNKREPEAT
|
||||
};
|
||||
|
||||
const int S3M_MAXROWS = 64;
|
||||
const int S3M_MAXSAMPLES = 99;
|
||||
|
||||
class MusicChannelS3M : public MusicChannel
|
||||
{
|
||||
public:
|
||||
FMOD_RESULT volumeSlide();
|
||||
FMOD_RESULT portamento();
|
||||
FMOD_RESULT vibrato();
|
||||
FMOD_RESULT tremolo();
|
||||
FMOD_RESULT fineVibrato();
|
||||
};
|
||||
|
||||
class CodecS3M : public MusicSong
|
||||
{
|
||||
private:
|
||||
|
||||
MusicSample mSample[S3M_MAXSAMPLES];
|
||||
|
||||
FMOD_RESULT calculateLength();
|
||||
|
||||
FMOD_RESULT updateNote(bool audible);
|
||||
FMOD_RESULT updateEffects();
|
||||
FMOD_RESULT update(bool audible);
|
||||
|
||||
FMOD_RESULT openInternal(FMOD_MODE usermode, FMOD_CREATESOUNDEXINFO *userexinfo);
|
||||
FMOD_RESULT closeInternal();
|
||||
FMOD_RESULT readInternal(void *buffer, unsigned int size, unsigned int *read);
|
||||
FMOD_RESULT setPositionInternal(int subsound, unsigned int position, FMOD_TIMEUNIT postype);
|
||||
|
||||
public:
|
||||
|
||||
static FMOD_RESULT F_CALLBACK openCallback(FMOD_CODEC_STATE *codec, FMOD_MODE usermode, FMOD_CREATESOUNDEXINFO *userexinfo);
|
||||
static FMOD_RESULT F_CALLBACK closeCallback(FMOD_CODEC_STATE *codec);
|
||||
static FMOD_RESULT F_CALLBACK readCallback(FMOD_CODEC_STATE *codec, void *buffer, unsigned int sizebytes, unsigned int *bytesread);
|
||||
static FMOD_RESULT F_CALLBACK setPositionCallback(FMOD_CODEC_STATE *codec, int subsound, unsigned int position, FMOD_TIMEUNIT postype);
|
||||
|
||||
static FMOD_CODEC_DESCRIPTION_EX *getDescriptionEx();
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
#endif /* FMOD_SUPPORT_S3M */
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
410
src/fmod_codec_sf2.cpp
Executable file
410
src/fmod_codec_sf2.cpp
Executable file
|
|
@ -0,0 +1,410 @@
|
|||
#include "fmod_settings.h"
|
||||
|
||||
#ifdef FMOD_SUPPORT_SF2
|
||||
|
||||
#include "fmod.h"
|
||||
#include "fmod_codec_sf2.h"
|
||||
#include "fmod_debug.h"
|
||||
#include "fmod_file.h"
|
||||
#include "fmod_metadata.h"
|
||||
#include "fmod_soundi.h"
|
||||
#include "fmod_string.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
namespace FMOD
|
||||
{
|
||||
|
||||
FMOD_CODEC_DESCRIPTION_EX sf2codec;
|
||||
|
||||
|
||||
#ifdef PLUGIN_EXPORTS
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
FMODGetCodecDescription is mandatory for every fmod plugin. This is the symbol the registerplugin function searches for.
|
||||
Must be declared with F_API to make it export as stdcall.
|
||||
*/
|
||||
F_DECLSPEC F_DLLEXPORT FMOD_CODEC_DESCRIPTION_EX * F_API FMODGetCodecDescriptionEx()
|
||||
{
|
||||
return CodecSF2::getDescriptionEx();
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* PLUGIN_EXPORTS */
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_CODEC_DESCRIPTION_EX *CodecSF2::getDescriptionEx()
|
||||
{
|
||||
FMOD_memset(&sf2codec, 0, sizeof(FMOD_CODEC_DESCRIPTION_EX));
|
||||
|
||||
sf2codec.name = "FMOD SoundFont 2.0 Codec";
|
||||
sf2codec.version = 0x00010100;
|
||||
sf2codec.timeunits = FMOD_TIMEUNIT_PCM;
|
||||
sf2codec.open = &CodecSF2::openCallback;
|
||||
sf2codec.close = &CodecSF2::closeCallback;
|
||||
sf2codec.read = &CodecSF2::readCallback;
|
||||
sf2codec.setposition = &CodecSF2::setPositionCallback;
|
||||
sf2codec.soundcreate = &CodecSF2::soundcreateCallback;
|
||||
|
||||
sf2codec.mType = FMOD_SOUND_TYPE_SF2;
|
||||
sf2codec.mSize = sizeof(CodecSF2);
|
||||
|
||||
return &sf2codec;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT CodecSF2::openInternal(FMOD_MODE usermode, FMOD_CREATESOUNDEXINFO *userexinfo)
|
||||
{
|
||||
FMOD_RESULT result = FMOD_OK;
|
||||
|
||||
init(FMOD_SOUND_TYPE_SF2);
|
||||
|
||||
FLOG((LOG_NORMAL, __FILE__, __LINE__, "CodecSF2::openInternal", "attempting to open as SF2..\n"));
|
||||
|
||||
result = mFile->seek(0, SEEK_SET);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
mSrcDataOffset = 0;
|
||||
|
||||
// if (mHeader.numsamples < 1)
|
||||
{
|
||||
return FMOD_ERR_FORMAT;
|
||||
}
|
||||
|
||||
// mShdr = (FMOD_SF2_SAMPLE_HEADER **)FMOD_Memory_Calloc(sizeof(void *) * mHeader.numsamples);
|
||||
// if (!mShdr)
|
||||
{
|
||||
return FMOD_ERR_MEMORY;
|
||||
}
|
||||
|
||||
// numsubsounds = mHeader.numsamples;
|
||||
waveformat = mWaveFormat;
|
||||
|
||||
/*
|
||||
Get size of file in bytes
|
||||
*/
|
||||
result = mFile->getSize(&mSrcDataSize);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT CodecSF2::closeInternal()
|
||||
{
|
||||
if (waveformat)
|
||||
{
|
||||
FMOD_Memory_Free(waveformat);
|
||||
waveformat = 0;
|
||||
}
|
||||
|
||||
if (mDataOffset)
|
||||
{
|
||||
FMOD_Memory_Free(mDataOffset);
|
||||
mDataOffset = 0;
|
||||
}
|
||||
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT CodecSF2::readInternal(void *buffer, unsigned int sizebytes, unsigned int *bytesread)
|
||||
{
|
||||
FMOD_RESULT result = FMOD_OK;
|
||||
|
||||
result = mFile->read(buffer, 1, sizebytes, bytesread);
|
||||
if (result != FMOD_OK && result != FMOD_ERR_FILE_EOF)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifdef PLATFORM_ENDIAN_BIG
|
||||
{
|
||||
unsigned int count;
|
||||
signed short *wptr = (signed short *)buffer;
|
||||
|
||||
for (count=0; count < *bytesread >> 1; count++)
|
||||
{
|
||||
wptr[count] = FMOD_SWAPENDIAN_WORD(wptr[count]);
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT CodecSF2::setPositionInternal(int subsound, unsigned int position, FMOD_TIMEUNIT postype)
|
||||
{
|
||||
FMOD_RESULT result = FMOD_OK;
|
||||
|
||||
if (subsound < 0 || (numsubsounds && subsound >= numsubsounds))
|
||||
{
|
||||
return FMOD_ERR_INVALID_PARAM;
|
||||
}
|
||||
|
||||
if (mFile->mSeekable)
|
||||
{
|
||||
unsigned int posbytes;
|
||||
|
||||
if (subsound != mCurrentIndex)
|
||||
{
|
||||
mCurrentIndex = subsound;
|
||||
}
|
||||
|
||||
result = SoundI::getBytesFromSamples(position, &posbytes, waveformat[mCurrentIndex].channels, waveformat[mCurrentIndex].format);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
posbytes += mDataOffset[mCurrentIndex];
|
||||
|
||||
result = mFile->seek(posbytes, SEEK_SET);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT CodecSF2::soundcreateInternal(int subsound, FMOD_SOUND *sound)
|
||||
{
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT F_CALLBACK CodecSF2::openCallback(FMOD_CODEC_STATE *codec, FMOD_MODE usermode, FMOD_CREATESOUNDEXINFO *userexinfo)
|
||||
{
|
||||
CodecSF2 *sf2 = (CodecSF2 *)codec;
|
||||
|
||||
return sf2->openInternal(usermode, userexinfo);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT F_CALLBACK CodecSF2::closeCallback(FMOD_CODEC_STATE *codec)
|
||||
{
|
||||
CodecSF2 *sf2 = (CodecSF2 *)codec;
|
||||
|
||||
return sf2->closeInternal();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT F_CALLBACK CodecSF2::readCallback(FMOD_CODEC_STATE *codec, void *buffer, unsigned int sizebytes, unsigned int *bytesread)
|
||||
{
|
||||
CodecSF2 *sf2 = (CodecSF2 *)codec;
|
||||
|
||||
return sf2->readInternal(buffer, sizebytes, bytesread);
|
||||
}
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT F_CALLBACK CodecSF2::setPositionCallback(FMOD_CODEC_STATE *codec, int subsound, unsigned int position, FMOD_TIMEUNIT postype)
|
||||
{
|
||||
CodecSF2 *sf2 = (CodecSF2 *)codec;
|
||||
|
||||
return sf2->setPositionInternal(subsound, position, postype);
|
||||
}
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT F_CALLBACK CodecSF2::soundcreateCallback(FMOD_CODEC_STATE *codec, int subsound, FMOD_SOUND *sound)
|
||||
{
|
||||
CodecSF2 *sf2 = (CodecSF2 *)codec;
|
||||
|
||||
return sf2->soundcreateInternal(subsound, sound);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
40
src/fmod_codec_sf2.h
Executable file
40
src/fmod_codec_sf2.h
Executable file
|
|
@ -0,0 +1,40 @@
|
|||
#ifndef _FMOD_CODEC_SF2_H
|
||||
#define _FMOD_CODEC_SF2_H
|
||||
|
||||
#include "fmod_settings.h"
|
||||
|
||||
#ifdef FMOD_SUPPORT_SF2
|
||||
|
||||
#include "fmod_codeci.h"
|
||||
|
||||
namespace FMOD
|
||||
{
|
||||
class CodecSF2 : public Codec
|
||||
{
|
||||
private:
|
||||
|
||||
unsigned int *mDataOffset; /* array of offsets to raw sample data */
|
||||
int mCurrentIndex; /* current SF2 index */
|
||||
|
||||
FMOD_RESULT openInternal(FMOD_MODE usermode, FMOD_CREATESOUNDEXINFO *userexinfo);
|
||||
FMOD_RESULT closeInternal();
|
||||
FMOD_RESULT readInternal(void *buffer, unsigned int size, unsigned int *read);
|
||||
FMOD_RESULT setPositionInternal(int subsound, unsigned int position, FMOD_TIMEUNIT postype);
|
||||
FMOD_RESULT soundcreateInternal(int subsound, FMOD_SOUND *sound);
|
||||
|
||||
public:
|
||||
|
||||
static FMOD_RESULT F_CALLBACK openCallback(FMOD_CODEC_STATE *codec, FMOD_MODE usermode, FMOD_CREATESOUNDEXINFO *userexinfo);
|
||||
static FMOD_RESULT F_CALLBACK closeCallback(FMOD_CODEC_STATE *codec);
|
||||
static FMOD_RESULT F_CALLBACK readCallback(FMOD_CODEC_STATE *codec, void *buffer, unsigned int sizebytes, unsigned int *bytesread);
|
||||
static FMOD_RESULT F_CALLBACK setPositionCallback(FMOD_CODEC_STATE *codec, int subsound, unsigned int position, FMOD_TIMEUNIT postype);
|
||||
static FMOD_RESULT F_CALLBACK soundcreateCallback(FMOD_CODEC_STATE *codec, int subsound, FMOD_SOUND *sound);
|
||||
|
||||
static FMOD_CODEC_DESCRIPTION_EX *getDescriptionEx();
|
||||
};
|
||||
}
|
||||
|
||||
#endif /* FMOD_SUPPORT_SF2 */
|
||||
|
||||
#endif
|
||||
|
||||
455
src/fmod_codec_swvag.cpp
Executable file
455
src/fmod_codec_swvag.cpp
Executable file
|
|
@ -0,0 +1,455 @@
|
|||
#include "fmod_settings.h"
|
||||
|
||||
#ifdef FMOD_SUPPORT_VAG
|
||||
|
||||
#include "fmod.h"
|
||||
#include "fmod_codec_swvag.h"
|
||||
#include "fmod_debug.h"
|
||||
#include "fmod_file.h"
|
||||
#include "fmod_soundi.h"
|
||||
#include "fmod_string.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
namespace FMOD
|
||||
{
|
||||
|
||||
|
||||
FMOD_CODEC_DESCRIPTION_EX vagcodec;
|
||||
|
||||
#if defined(PLUGIN_EXPORTS) && !defined(PLUGIN_FSB)
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
FMODGetCodecDescriptionEx is mandantory for every fmod plugin. This is the symbol the registerplugin function searches for.
|
||||
Must be declared with F_API to make it export as stdcall.
|
||||
*/
|
||||
F_DECLSPEC F_DLLEXPORT FMOD_CODEC_DESCRIPTION_EX * F_API FMODGetCodecDescriptionEx()
|
||||
{
|
||||
return CodecVAG::getDescriptionEx();
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* PLUGIN_EXPORTS */
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_CODEC_DESCRIPTION_EX *CodecVAG::getDescriptionEx()
|
||||
{
|
||||
FMOD_memset(&vagcodec, 0, sizeof(FMOD_CODEC_DESCRIPTION_EX));
|
||||
|
||||
vagcodec.name = "FMOD VAG Codec";
|
||||
vagcodec.version = 0x00010100;
|
||||
vagcodec.timeunits = FMOD_TIMEUNIT_PCM;
|
||||
vagcodec.open = &CodecVAG::openCallback;
|
||||
vagcodec.close = &CodecVAG::closeCallback;
|
||||
vagcodec.read = &CodecVAG::readCallback;
|
||||
vagcodec.setposition = &CodecVAG::setPositionCallback;
|
||||
|
||||
vagcodec.mType = FMOD_SOUND_TYPE_VAG;
|
||||
vagcodec.mSize = sizeof(CodecVAG);
|
||||
|
||||
return &vagcodec;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT CodecVAG::openInternal(FMOD_MODE usermode, FMOD_CREATESOUNDEXINFO *userexinfo)
|
||||
{
|
||||
FMOD_RESULT result = FMOD_OK;
|
||||
FMOD_VAG_HDR hdr;
|
||||
|
||||
init(FMOD_SOUND_TYPE_VAG);
|
||||
|
||||
FLOG((FMOD_DEBUG_LEVEL_LOG, __FILE__, __LINE__, "CodecVAG::openInternal", "attempting to open as VAG..\n"));
|
||||
|
||||
result = mFile->seek(0, SEEK_SET);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
result = mFile->read(&hdr, 1, sizeof(FMOD_VAG_HDR));
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
if (FMOD_strncmp((char *)hdr.format, "VAG", 3))
|
||||
{
|
||||
FLOG((FMOD_DEBUG_LEVEL_LOG, __FILE__, __LINE__, "CodecVAG::openInternal", "'VAG' ID check failed [%c%c%c]\n", hdr.format[0], hdr.format[1], hdr.format[2]));
|
||||
|
||||
return FMOD_ERR_FORMAT;
|
||||
}
|
||||
|
||||
#ifdef PLATFORM_ENDIAN_LITTLE
|
||||
hdr.fs = FMOD_SWAPENDIAN_DWORD(hdr.fs);
|
||||
hdr.size = FMOD_SWAPENDIAN_DWORD(hdr.size);
|
||||
#endif
|
||||
|
||||
mSrcDataOffset = sizeof(FMOD_VAG_HDR);
|
||||
|
||||
waveformat = &mWaveFormat;
|
||||
|
||||
waveformat[0].format = FMOD_SOUND_FORMAT_PCM16;
|
||||
waveformat[0].channels = 1;
|
||||
waveformat[0].frequency = hdr.fs;
|
||||
waveformat[0].lengthbytes= hdr.size;
|
||||
waveformat[0].lengthpcm = waveformat[0].lengthbytes * 28 / 16;
|
||||
|
||||
mPCMBufferLength = 28;
|
||||
mPCMBufferLengthBytes = 56;
|
||||
|
||||
#ifdef PLATFORM_PS3
|
||||
mPCMBuffer = (unsigned char *)FMOD_ALIGNPOINTER(mPCMBlock, 16);
|
||||
#else
|
||||
mPCMBuffer = (unsigned char *)mPCMBlock;
|
||||
#endif
|
||||
|
||||
numsubsounds = 0;
|
||||
|
||||
FLOG((FMOD_DEBUG_LEVEL_LOG, __FILE__, __LINE__, "CodecVAG::openInternal", "successfully opened vag file..\n"));
|
||||
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT CodecVAG::closeInternal()
|
||||
{
|
||||
if (mWaveFormatMemory)
|
||||
{
|
||||
FMOD_Memory_Free(mWaveFormatMemory);
|
||||
mWaveFormatMemory = 0;
|
||||
}
|
||||
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT CodecVAG::readInternal(void *buffer, unsigned int sizebytes, unsigned int *bytesread)
|
||||
{
|
||||
FMOD_RESULT result;
|
||||
char src[16];
|
||||
unsigned char *dest = (unsigned char *)buffer;
|
||||
int channel;
|
||||
|
||||
static float f[5][2] =
|
||||
{
|
||||
{ 0.0f, 0.0f },
|
||||
{ 60.0f / 64.0f, 0.0f },
|
||||
{ 115.0f / 64.0f, -52.0f / 64.0f },
|
||||
{ 98.0f / 64.0f, -55.0f / 64.0f },
|
||||
{ 122.0f / 64.0f, -60.0f / 64.0f }
|
||||
};
|
||||
|
||||
channel = 0;
|
||||
while (sizebytes)
|
||||
{
|
||||
unsigned char *p;
|
||||
int predict_nr, shift_factor, flags;
|
||||
int i;
|
||||
int d, s;
|
||||
float samples[28];
|
||||
|
||||
result = mFile->read(src, 16, 1, 0);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
p=(unsigned char *)src;
|
||||
|
||||
predict_nr = *p++;
|
||||
shift_factor = predict_nr & 0xf;
|
||||
predict_nr >>= 4;
|
||||
|
||||
flags = *p++;
|
||||
|
||||
#if 0
|
||||
/*
|
||||
Doesn't make sense to break out because certain things are set.
|
||||
*/
|
||||
if ( flags == (FMOD_VAG_LOOP | FMOD_VAG_START | FMOD_VAG_END) )
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (flags == (FMOD_VAG_LOOP | FMOD_VAG_END))
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (flags == FMOD_VAG_START)
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (flags == (FMOD_VAG_START | FMOD_VAG_LOOP))
|
||||
{
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
for ( i = 0; i < 28; i += 2 )
|
||||
{
|
||||
d = *p++;
|
||||
s = ( d & 0xf ) << 12;
|
||||
if ( s & 0x8000 )
|
||||
{
|
||||
s |= 0xffff0000;
|
||||
}
|
||||
samples[i] = (float) ( s >> shift_factor);
|
||||
s = ( d & 0xf0 ) << 8;
|
||||
if ( s & 0x8000 )
|
||||
{
|
||||
s |= 0xffff0000;
|
||||
}
|
||||
samples[i+1] = (float) ( s >> shift_factor);
|
||||
}
|
||||
|
||||
unsigned char *destptr = dest + (channel * sizeof(signed short));
|
||||
|
||||
for ( i = 0; i < 28; i++ )
|
||||
{
|
||||
samples[i] = samples[i] + mContext[channel].mS1 * f[predict_nr][0] + mContext[channel].mS2 * f[predict_nr][1];
|
||||
mContext[channel].mS2 = mContext[channel].mS1;
|
||||
mContext[channel].mS1 = samples[i];
|
||||
d = (int) ( samples[i] + 0.5f );
|
||||
destptr[0]=(d & 0xff);
|
||||
destptr[1]=(d >> 8);
|
||||
destptr += waveformat->channels * sizeof(signed short);
|
||||
}
|
||||
|
||||
sizebytes -= 56;
|
||||
*bytesread += 56;
|
||||
channel ++;
|
||||
if (channel >= waveformat->channels)
|
||||
{
|
||||
channel = 0;
|
||||
dest += 28 * sizeof(short) * waveformat->channels;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef PLATFORM_ENDIAN_BIG
|
||||
|
||||
signed short *wptr = (signed short *)buffer;
|
||||
|
||||
int count = *bytesread / 2;
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
wptr[i] = FMOD_SWAPENDIAN_WORD(wptr[i]);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT CodecVAG::setPositionInternal(int subsound, unsigned int position, FMOD_TIMEUNIT postype)
|
||||
{
|
||||
FMOD_RESULT result;
|
||||
int bits, count;
|
||||
unsigned int bytes;
|
||||
|
||||
result = SoundI::getBitsFromFormat(waveformat[0].format, &bits);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
SoundI::getBytesFromSamples(position, &bytes, waveformat[0].channels, FMOD_SOUND_FORMAT_VAG);
|
||||
|
||||
result = mFile->seek(mSrcDataOffset + bytes, SEEK_SET);
|
||||
|
||||
for (count = 0; count < 16; count++)
|
||||
{
|
||||
mContext[count].mS1 = mContext[count].mS2 = 0;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT F_CALLBACK CodecVAG::openCallback(FMOD_CODEC_STATE *codec, FMOD_MODE usermode, FMOD_CREATESOUNDEXINFO *userexinfo)
|
||||
{
|
||||
CodecVAG *vag = (CodecVAG *)codec;
|
||||
|
||||
return vag->openInternal(usermode, userexinfo);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT F_CALLBACK CodecVAG::closeCallback(FMOD_CODEC_STATE *codec)
|
||||
{
|
||||
CodecVAG *vag = (CodecVAG *)codec;
|
||||
|
||||
return vag->closeInternal();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT F_CALLBACK CodecVAG::readCallback(FMOD_CODEC_STATE *codec, void *buffer, unsigned int sizebytes, unsigned int *bytesread)
|
||||
{
|
||||
CodecVAG *vag = (CodecVAG *)codec;
|
||||
|
||||
return vag->readInternal(buffer, sizebytes, bytesread);
|
||||
}
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT F_CALLBACK CodecVAG::setPositionCallback(FMOD_CODEC_STATE *codec, int subsound, unsigned int position, FMOD_TIMEUNIT postype)
|
||||
{
|
||||
CodecVAG *vag = (CodecVAG *)codec;
|
||||
|
||||
return vag->setPositionInternal(subsound, position, postype);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
90
src/fmod_codec_swvag.h
Executable file
90
src/fmod_codec_swvag.h
Executable file
|
|
@ -0,0 +1,90 @@
|
|||
#ifndef _FMOD_CODEC_VAG_H
|
||||
#define _FMOD_CODEC_VAG_H
|
||||
|
||||
#include "fmod_settings.h"
|
||||
|
||||
#ifdef FMOD_SUPPORT_VAG
|
||||
|
||||
#include "fmod_codeci.h"
|
||||
#include "fmod_types.h"
|
||||
|
||||
namespace FMOD
|
||||
{
|
||||
|
||||
#define FMOD_VAG_START 0x04
|
||||
#define FMOD_VAG_LOOP 0x02
|
||||
#define FMOD_VAG_END 0x01
|
||||
|
||||
#ifdef FMOD_SUPPORT_PRAGMAPACK
|
||||
#pragma pack(1)
|
||||
#endif
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned char format[4] FMOD_PACKED_INTERNAL; /* always 'VAGp' for identifying*/
|
||||
unsigned int ver FMOD_PACKED_INTERNAL; /* format version (2) */
|
||||
unsigned int ssa FMOD_PACKED_INTERNAL; /* Source Start Address, always 0 (reserved for VAB format) */
|
||||
unsigned int size FMOD_PACKED_INTERNAL; /* Sound Data Size in byte */
|
||||
|
||||
unsigned int fs FMOD_PACKED_INTERNAL; /* sampling frequency, 44100(>pt1000), 32000(>pt), 22000(>pt0800)... */
|
||||
unsigned short volL FMOD_PACKED_INTERNAL; /* base volume for Left channel */
|
||||
unsigned short volR FMOD_PACKED_INTERNAL; /* base volume for Right channel */
|
||||
unsigned short pitch FMOD_PACKED_INTERNAL; /* base pitch (includes fs modulation)*/
|
||||
unsigned short ADSR1 FMOD_PACKED_INTERNAL; /* base ADSR1 (see SPU manual) */
|
||||
unsigned short ADSR2 FMOD_PACKED_INTERNAL; /* base ADSR2 (see SPU manual) */
|
||||
unsigned short reserved FMOD_PACKED_INTERNAL; /* not in use */
|
||||
|
||||
char name[16] FMOD_PACKED_INTERNAL;
|
||||
|
||||
} FMOD_PACKED FMOD_VAG_HDR;
|
||||
|
||||
#ifdef FMOD_SUPPORT_PRAGMAPACK
|
||||
#ifdef CODEWARRIOR
|
||||
#pragma pack(0)
|
||||
#else
|
||||
#pragma pack()
|
||||
#endif
|
||||
#endif
|
||||
|
||||
struct CodecVAG_Context
|
||||
{
|
||||
float mS1, mS2;
|
||||
};
|
||||
|
||||
class CodecVAG : public Codec
|
||||
{
|
||||
friend class CodecFSB;
|
||||
|
||||
private:
|
||||
|
||||
FMOD_CODEC_WAVEFORMAT mWaveFormat;
|
||||
|
||||
#ifdef PLATFORM_PS3
|
||||
unsigned char mPCMBlock[56 + 16]; /* +16 for alignment */
|
||||
#else
|
||||
unsigned char mPCMBlock[56];
|
||||
#endif
|
||||
|
||||
CodecVAG_Context mContext[16];
|
||||
|
||||
FMOD_RESULT openInternal(FMOD_MODE usermode, FMOD_CREATESOUNDEXINFO *userexinfo);
|
||||
FMOD_RESULT closeInternal();
|
||||
FMOD_RESULT readInternal(void *buffer, unsigned int size, unsigned int *read);
|
||||
FMOD_RESULT setPositionInternal(int subsound, unsigned int position, FMOD_TIMEUNIT postype);
|
||||
|
||||
public:
|
||||
|
||||
static FMOD_RESULT F_CALLBACK openCallback(FMOD_CODEC_STATE *codec, FMOD_MODE usermode, FMOD_CREATESOUNDEXINFO *userexinfo);
|
||||
static FMOD_RESULT F_CALLBACK closeCallback(FMOD_CODEC_STATE *codec);
|
||||
static FMOD_RESULT F_CALLBACK readCallback(FMOD_CODEC_STATE *codec, void *buffer, unsigned int sizebytes, unsigned int *bytesread);
|
||||
static FMOD_RESULT F_CALLBACK setPositionCallback(FMOD_CODEC_STATE *codec, int subsound, unsigned int position, FMOD_TIMEUNIT postype);
|
||||
|
||||
static FMOD_CODEC_DESCRIPTION_EX *getDescriptionEx();
|
||||
};
|
||||
}
|
||||
|
||||
#endif /* FMOD_SUPPORT_VAG */
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
1337
src/fmod_codec_tag.cpp
Executable file
1337
src/fmod_codec_tag.cpp
Executable file
File diff suppressed because it is too large
Load diff
42
src/fmod_codec_tag.h
Executable file
42
src/fmod_codec_tag.h
Executable file
|
|
@ -0,0 +1,42 @@
|
|||
#ifndef _FMOD_CODEC_TAG_H
|
||||
#define _FMOD_CODEC_TAG_H
|
||||
|
||||
#include "fmod_settings.h"
|
||||
|
||||
#ifdef FMOD_SUPPORT_TAGS
|
||||
|
||||
#include "fmod_codeci.h"
|
||||
|
||||
namespace FMOD
|
||||
{
|
||||
const FMOD_SOUND_TYPE FMOD_SOUND_TYPE_TAG = (FMOD_SOUND_TYPE)1000;
|
||||
|
||||
class CodecTag : public Codec
|
||||
{
|
||||
private:
|
||||
|
||||
FMOD_RESULT openInternal(FMOD_MODE usermode, FMOD_CREATESOUNDEXINFO *userexinfo);
|
||||
FMOD_RESULT closeInternal();
|
||||
FMOD_RESULT readTags();
|
||||
FMOD_RESULT readID3v1();
|
||||
FMOD_RESULT readID3v2();
|
||||
FMOD_RESULT readID3v2FromFooter();
|
||||
FMOD_RESULT readASF();
|
||||
|
||||
public:
|
||||
|
||||
static FMOD_RESULT F_CALLBACK openCallback(FMOD_CODEC_STATE *codec, FMOD_MODE usermode, FMOD_CREATESOUNDEXINFO *userexinfo);
|
||||
static FMOD_RESULT F_CALLBACK closeCallback(FMOD_CODEC_STATE *codec);
|
||||
static FMOD_RESULT F_CALLBACK readCallback(FMOD_CODEC_STATE *codec, void *buffer, unsigned int sizebytes, unsigned int *bytesread);
|
||||
static FMOD_RESULT F_CALLBACK setPositionCallback(FMOD_CODEC_STATE *codec, int subsound, unsigned int position, FMOD_TIMEUNIT postype);
|
||||
static FMOD_RESULT F_CALLBACK soundcreateCallback(FMOD_CODEC_STATE *codec, int subsound, FMOD_SOUND *sound);
|
||||
|
||||
static FMOD_CODEC_DESCRIPTION_EX *getDescriptionEx();
|
||||
};
|
||||
}
|
||||
|
||||
#endif /* FMOD_SUPPORT_TAGS */
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
826
src/fmod_codec_tremor.cpp
Executable file
826
src/fmod_codec_tremor.cpp
Executable file
|
|
@ -0,0 +1,826 @@
|
|||
#include "fmod_settings.h"
|
||||
|
||||
#ifdef FMOD_SUPPORT_TREMOR
|
||||
|
||||
#include "fmod.h"
|
||||
#include "fmod_codec_tremor.h"
|
||||
#include "fmod_codec_wav.h"
|
||||
#include "fmod_debug.h"
|
||||
#include "fmod_file.h"
|
||||
#include "fmod_metadata.h"
|
||||
#include "fmod_string.h"
|
||||
|
||||
//#include "../lib/ogg_vorbis/vorbis/lib/window.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
|
||||
/*
|
||||
***************************************************************************************************************
|
||||
***************************************************************************************************************
|
||||
***************************************************************************************************************
|
||||
|
||||
NOTES ON OPTIMIZATION
|
||||
---------------------
|
||||
|
||||
- Throw away floor0 and res0 and res1. Only keep floor1 and res2.
|
||||
- Special case all the transform stuff to the two blocksizes used (if you use two of-em at all).
|
||||
- You can also make smaller or algoritmically decodable Huffman tables instead of the big lookups,
|
||||
if you so choose (you'll have to tune the encoder to generate correct streams for you, in that case, though).
|
||||
- You can even hardwire the modes into the decoder (no headers needed anymore --> good for small samples, no setup
|
||||
overhead).
|
||||
|
||||
- Remove floor 0: Floor 0 is not to be considered deprecated, but it is of
|
||||
limited modern use. No known Vorbis encoder past Xiph.Org's own beta
|
||||
4 makes use of floor 0. Floor 1 is also considerably less expensive to
|
||||
decode than floor 0 [9]. Removing support for floor 0 will preserve
|
||||
memory.
|
||||
- Window sizes: Remove all look-up tables for IMDCT support of
|
||||
window lengths other than 256 and 2048. This is possible since these are
|
||||
the only windows lengths that is used by most (if not all) encoders. Since
|
||||
the current Vorbis standard features window lengths of up to 8192
|
||||
samples the memory preserve is significant.
|
||||
- Low accuracy: If Tremor is compiled with _LOW_ACCURACY_
|
||||
defined it will run in low accuracy mode, which means that all
|
||||
calculations during decode is limited to a maximum of 32 bit precision.
|
||||
Otherwise, 64 bit values are used to store intermediate 32-bit multiply
|
||||
results. And the look up tables for windows and IMDCT are converted
|
||||
from 32 bits to 8 bits. Sound quality will be reduced but the processor
|
||||
load will be reduced.
|
||||
- Rewrite data structures: To further reduce memory usage, and possibly
|
||||
gain some speed, data structures can be optimized by determining the
|
||||
actual needed sizes as well as removing unnecessary or redundant
|
||||
members. And due to the alignment restrictions of some processor
|
||||
architectures, struct members can be rearranged to not wasted memory
|
||||
due to padding. For example. when an odd number of int is followed by a
|
||||
long. This has also been done in a preciously thesis projects and it gained
|
||||
some memory [2].
|
||||
|
||||
|
||||
***************************************************************************************************************
|
||||
***************************************************************************************************************
|
||||
***************************************************************************************************************
|
||||
*/
|
||||
|
||||
|
||||
namespace FMOD
|
||||
{
|
||||
|
||||
|
||||
FMOD_CODEC_DESCRIPTION_EX tremorcodec;
|
||||
|
||||
#ifdef PLUGIN_EXPORTS
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
FMODGetCodecDescription is mandantory for every fmod plugin. This is the symbol the registerplugin function searches for.
|
||||
Must be declared with F_API to make it export as stdcall.
|
||||
*/
|
||||
F_DECLSPEC F_DLLEXPORT FMOD_CODEC_DESCRIPTION_EX * F_API FMODGetCodecDescriptionEx()
|
||||
{
|
||||
return CodecTremor::getDescriptionEx();
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* PLUGIN_EXPORTS */
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
size_t FMOD_Tremor_ReadCallback(void *ptr, size_t size, size_t nmemb, void *datasource)
|
||||
{
|
||||
FMOD_RESULT result;
|
||||
unsigned int rd;
|
||||
File *fp;
|
||||
|
||||
fp = (File *)datasource;
|
||||
|
||||
result = fp->read(ptr, (unsigned int)size, (unsigned int)nmemb, &rd);
|
||||
if (result != FMOD_OK && result != FMOD_ERR_FILE_EOF)
|
||||
{
|
||||
return (size_t)-1;
|
||||
}
|
||||
|
||||
return rd;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
int FMOD_Tremor_SeekCallback(void *datasource, ogg_int64_t offset, int whence)
|
||||
{
|
||||
File *fp = (File *)datasource;
|
||||
|
||||
if (fp->mFlags & FMOD_FILE_SEEKABLE)
|
||||
{
|
||||
return fp->seek((int)offset, (signed char)whence);
|
||||
}
|
||||
else
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
int FMOD_Tremor_TellCallback(void *datasource)
|
||||
{
|
||||
File *fp = (File *)datasource;
|
||||
unsigned int pos;
|
||||
|
||||
fp->tell(&pos);
|
||||
|
||||
return (ogg_int32_t)pos;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
void * FMOD_Tremor_Malloc(int size)
|
||||
{
|
||||
return FMOD_Memory_Alloc(size);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
void * FMOD_Tremor_Calloc(int count, int size)
|
||||
{
|
||||
return FMOD_Memory_Calloc(count * size);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
void * FMOD_Tremor_ReAlloc(void *ptr, int size)
|
||||
{
|
||||
return FMOD_Memory_ReAlloc(ptr, size);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
void FMOD_Tremor_Free(void *ptr)
|
||||
{
|
||||
FMOD_Memory_Free(ptr);
|
||||
}
|
||||
|
||||
extern "C"
|
||||
{
|
||||
void * (*_ogg_malloc) (int size) = FMOD_Tremor_Malloc;
|
||||
void * (*_ogg_calloc) (int count, int size) = FMOD_Tremor_Calloc;
|
||||
void * (*_ogg_realloc) (void *ptr, int size) = FMOD_Tremor_ReAlloc;
|
||||
void (*_ogg_free) (void *ptr) = FMOD_Tremor_Free;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_CODEC_DESCRIPTION_EX *CodecTremor::getDescriptionEx()
|
||||
{
|
||||
memset(&tremorcodec, 0, sizeof(FMOD_CODEC_DESCRIPTION_EX));
|
||||
|
||||
tremorcodec.name = "FMOD Tremor Codec";
|
||||
tremorcodec.version = 0x00010100;
|
||||
tremorcodec.timeunits = FMOD_TIMEUNIT_PCM;
|
||||
tremorcodec.open = &CodecTremor::openCallback;
|
||||
tremorcodec.close = &CodecTremor::closeCallback;
|
||||
tremorcodec.read = &CodecTremor::readCallback;
|
||||
tremorcodec.setposition = &CodecTremor::setPositionCallback;
|
||||
|
||||
tremorcodec.mType = FMOD_SOUND_TYPE_OGGVORBIS;
|
||||
tremorcodec.mSize = sizeof(CodecTremor);
|
||||
|
||||
return &tremorcodec;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT CodecTremor::openInternal(FMOD_MODE usermode, FMOD_CREATESOUNDEXINFO *userexinfo)
|
||||
{
|
||||
FMOD_RESULT result = FMOD_OK;
|
||||
vorbis_info *vi;
|
||||
char str[4];
|
||||
unsigned int lengthbytes = 0;
|
||||
int oggresult;
|
||||
ov_callbacks callbacks =
|
||||
{
|
||||
FMOD_Tremor_ReadCallback, /* size_t (*read_func) (void *ptr, size_t size, size_t nmemb, void *datasource); */
|
||||
FMOD_Tremor_SeekCallback, /* int (*seek_func) (void *datasource, ogg_int64_t offset, int whence); */
|
||||
0, /* int (*close_func) (void *datasource); */
|
||||
FMOD_Tremor_TellCallback, /* int (*tell_func) (void *datasource); */
|
||||
};
|
||||
bool manualsizecalc = false;
|
||||
|
||||
init(FMOD_SOUND_TYPE_OGGVORBIS);
|
||||
|
||||
FLOG((FMOD_DEBUG_LEVEL_LOG, __FILE__, __LINE__, "CodecTremor::openInternal", "attempting to open as OGG..\n"));
|
||||
|
||||
result = mFile->seek(0, SEEK_SET);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
mSrcDataOffset = 0;
|
||||
|
||||
/*
|
||||
Support RIFF wrapped MP3?
|
||||
*/
|
||||
{
|
||||
CodecWav tempwav;
|
||||
WAVE_CHUNK chunk;
|
||||
FMOD_CODEC_WAVEFORMAT tempwaveformat;
|
||||
|
||||
memset(&tempwav, 0, sizeof(CodecWav));
|
||||
memset(&tempwaveformat, 0, sizeof(FMOD_CODEC_WAVEFORMAT));
|
||||
|
||||
tempwav.mFile = mFile;
|
||||
tempwav.mSrcDataOffset = (unsigned int)-1;
|
||||
tempwav.waveformat = &tempwaveformat;
|
||||
|
||||
/*
|
||||
Read header
|
||||
*/
|
||||
result = mFile->read(&chunk, 1, sizeof(WAVE_CHUNK), 0);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
if (!FMOD_strncmp((const char *)chunk.id, "RIFF", 4))
|
||||
{
|
||||
char wave[4];
|
||||
|
||||
result = mFile->read(wave, 1, 4, 0);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
if (!FMOD_strncmp(wave, "WAVE", 4))
|
||||
{
|
||||
#ifdef PLATFORM_ENDIAN_BIG
|
||||
chunk.size = FMOD_SWAPENDIAN_DWORD(chunk.size);
|
||||
#endif
|
||||
|
||||
result = tempwav.parseChunk(chunk.size);
|
||||
if (result == FMOD_OK && tempwav.mSrcFormat && tempwav.mSrcDataOffset == (unsigned int)-1)
|
||||
{
|
||||
int format = tempwav.mSrcFormat->Format.wFormatTag;
|
||||
|
||||
if (format == WAVE_FORMAT_OGGVORBIS)
|
||||
{
|
||||
mSrcDataOffset = tempwav.mSrcDataOffset;
|
||||
lengthbytes = tempwav.waveformat[0].lengthbytes;
|
||||
mLoopPoints[0] = tempwav.mLoopPoints[0];
|
||||
mLoopPoints[1] = tempwav.mLoopPoints[1];
|
||||
mSyncPoint = tempwav.mSyncPoint;
|
||||
mNumSyncPoints = tempwav.mNumSyncPoints;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = FMOD_ERR_FORMAT;
|
||||
}
|
||||
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
if (tempwav.mSrcFormat)
|
||||
{
|
||||
FMOD_Memory_Free(tempwav.mSrcFormat);
|
||||
tempwav.mSrcFormat = 0;
|
||||
}
|
||||
if (tempwav.mSyncPoint && mSyncPoint != tempwav.mSyncPoint)
|
||||
{
|
||||
FMOD_Memory_Free(tempwav.mSyncPoint);
|
||||
tempwav.mSyncPoint = 0;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
if (tempwav.mSrcFormat)
|
||||
{
|
||||
FMOD_Memory_Free(tempwav.mSrcFormat);
|
||||
tempwav.mSrcFormat = 0;
|
||||
}
|
||||
if (tempwav.mSyncPoint && mSyncPoint != tempwav.mSyncPoint)
|
||||
{
|
||||
FMOD_Memory_Free(tempwav.mSyncPoint);
|
||||
tempwav.mSyncPoint = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
result = mFile->seek(mSrcDataOffset, SEEK_SET);
|
||||
}
|
||||
|
||||
result = mFile->read(str, 1, 4, 0);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
if (FMOD_strncmp(str, "OggS", 4))
|
||||
{
|
||||
FLOG((FMOD_DEBUG_LEVEL_LOG, __FILE__, __LINE__, "CodecTremor::openInternal", "failed to open as ogg\n"));
|
||||
|
||||
return FMOD_ERR_FORMAT;
|
||||
}
|
||||
|
||||
/*
|
||||
Get size of ogg file in bytes
|
||||
*/
|
||||
/*
|
||||
If there wasnt a riff size chunk
|
||||
*/
|
||||
if (!lengthbytes)
|
||||
{
|
||||
result = mFile->getSize(&lengthbytes);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
manualsizecalc = true;
|
||||
}
|
||||
|
||||
result = mFile->seek(mSrcDataOffset, SEEK_SET);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
oggresult = ov_open_callbacks(mFile, &mVf, 0, 0, callbacks);
|
||||
if (oggresult < 0)
|
||||
{
|
||||
FLOG((FMOD_DEBUG_LEVEL_LOG, __FILE__, __LINE__, "CodecTremor::openInternal", "failed to open as ogg\n"));
|
||||
|
||||
if (oggresult == -139) //OV_EMEMORY)
|
||||
{
|
||||
return FMOD_ERR_MEMORY;
|
||||
}
|
||||
return FMOD_ERR_FORMAT;
|
||||
}
|
||||
|
||||
vi = ov_info(&mVf,-1);
|
||||
|
||||
result = readVorbisComments();
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
waveformat = &mWaveFormat;
|
||||
waveformat[0].lengthbytes = lengthbytes;
|
||||
waveformat[0].format = FMOD_SOUND_FORMAT_PCM16;
|
||||
waveformat[0].channels = vi->channels;
|
||||
waveformat[0].frequency = vi->rate;
|
||||
waveformat[0].blockalign = waveformat[0].channels * 2; /* THIS SHOULD BE EQUIVALENT TO THE OGG DECODE BUFFER SIZE? */
|
||||
|
||||
if (manualsizecalc && waveformat[0].lengthbytes != (unsigned int)-1)
|
||||
{
|
||||
waveformat[0].lengthbytes -= mSrcDataOffset;
|
||||
}
|
||||
|
||||
if (mFile->mFlags & FMOD_FILE_SEEKABLE)
|
||||
{
|
||||
int count, streams = ov_streams(&mVf);
|
||||
|
||||
waveformat[0].lengthpcm = 0;
|
||||
|
||||
for (count = 0; count < streams; count++)
|
||||
{
|
||||
waveformat[0].lengthpcm += (int)ov_pcm_total(&mVf, count);
|
||||
}
|
||||
|
||||
if (waveformat[0].lengthpcm <= 0)
|
||||
{
|
||||
FLOG((FMOD_DEBUG_LEVEL_LOG, __FILE__, __LINE__, "CodecTremor::openInternal", "failed to open as ogg\n"));
|
||||
|
||||
waveformat[0].lengthpcm = 0;
|
||||
|
||||
return FMOD_ERR_FORMAT;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
waveformat[0].lengthpcm = 0x7fffffff;
|
||||
}
|
||||
|
||||
if (!mSrcDataOffset)
|
||||
{
|
||||
mSrcDataOffset = (unsigned int)ov_raw_tell(&mVf);
|
||||
}
|
||||
|
||||
/*
|
||||
Fill out base class members, also pointing to or allocating storage for them.
|
||||
*/
|
||||
numsubsounds = 0;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT CodecTremor::closeInternal()
|
||||
{
|
||||
mVf.datasource = 0; /* this stops vorbis from trying to close our file */
|
||||
|
||||
ov_clear(&mVf);
|
||||
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT CodecTremor::readInternal(void *buffer, unsigned int sizebytes, unsigned int *bytesread)
|
||||
{
|
||||
int bigendian;
|
||||
vorbis_comment *vc;
|
||||
char *name, *value;
|
||||
int i;
|
||||
|
||||
#ifdef PLATFORM_ENDIAN_BIG
|
||||
bigendian = 1;
|
||||
#else
|
||||
bigendian = 0;
|
||||
#endif
|
||||
|
||||
*bytesread = ov_read(&mVf, buffer, sizebytes, 0);
|
||||
if (!*bytesread)
|
||||
{
|
||||
return FMOD_ERR_FILE_EOF;
|
||||
}
|
||||
|
||||
vc = ov_comment(&mVf, -1);
|
||||
|
||||
if (vc && vc->comments)
|
||||
{
|
||||
for (i=0;i < vc->comments;i++)
|
||||
{
|
||||
name = vc->user_comments[i];
|
||||
value = name;
|
||||
for (;*value && (*value != '=');value++) ;
|
||||
|
||||
if (*value == '=')
|
||||
{
|
||||
*value++ = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
value = name;
|
||||
name = "NONAME";
|
||||
}
|
||||
|
||||
metadata((FMOD_CODEC_STATE *)this, FMOD_TAGTYPE_VORBISCOMMENT, name, value, FMOD_strlen(value) + 1, FMOD_TAGDATATYPE_STRING, true);
|
||||
}
|
||||
|
||||
#ifndef FMOD_MODIFIED
|
||||
vorbis_comment_clear(vc);
|
||||
#endif
|
||||
}
|
||||
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT CodecTremor::setPositionInternal(int subsound, unsigned int position, FMOD_TIMEUNIT postype)
|
||||
{
|
||||
FMOD_RESULT result = FMOD_OK;
|
||||
|
||||
if (ov_pcm_seek(&mVf, position) < 0)
|
||||
{
|
||||
return FMOD_ERR_MEMORY;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT CodecTremor::readVorbisComments()
|
||||
{
|
||||
FMOD_RESULT result;
|
||||
char *p;
|
||||
int count, i;
|
||||
vorbis_comment *vc;
|
||||
|
||||
vc = ov_comment(&mVf, -1);
|
||||
if (!vc)
|
||||
{
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
||||
for (count = 0; count < vc->comments; count++)
|
||||
{
|
||||
if (vc->comment_lengths[count])
|
||||
{
|
||||
p = vc->user_comments[count];
|
||||
for (i=0;*p && (*p != '=');i++, p++) ;
|
||||
if (*p == '=')
|
||||
{
|
||||
*p++ = 0;
|
||||
result = metaData(FMOD_TAGTYPE_VORBISCOMMENT, vc->user_comments[count], p, FMOD_strlen(p) + 1, FMOD_TAGDATATYPE_STRING, false);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT F_CALLBACK CodecTremor::openCallback(FMOD_CODEC_STATE *codec, FMOD_MODE usermode, FMOD_CREATESOUNDEXINFO *userexinfo)
|
||||
{
|
||||
CodecTremor *ogg = (CodecTremor *)codec;
|
||||
|
||||
return ogg->openInternal(usermode, userexinfo);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT F_CALLBACK CodecTremor::closeCallback(FMOD_CODEC_STATE *codec)
|
||||
{
|
||||
CodecTremor *ogg = (CodecTremor *)codec;
|
||||
|
||||
return ogg->closeInternal();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT F_CALLBACK CodecTremor::readCallback(FMOD_CODEC_STATE *codec, void *buffer, unsigned int sizebytes, unsigned int *bytesread)
|
||||
{
|
||||
CodecTremor *ogg = (CodecTremor *)codec;
|
||||
|
||||
return ogg->readInternal(buffer, sizebytes, bytesread);
|
||||
}
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT F_CALLBACK CodecTremor::setPositionCallback(FMOD_CODEC_STATE *codec, int subsound, unsigned int position, FMOD_TIMEUNIT postype)
|
||||
{
|
||||
CodecTremor *ogg = (CodecTremor *)codec;
|
||||
|
||||
return ogg->setPositionInternal(subsound, position, postype);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
47
src/fmod_codec_tremor.h
Executable file
47
src/fmod_codec_tremor.h
Executable file
|
|
@ -0,0 +1,47 @@
|
|||
#ifndef _FMOD_CODEC_TREMOR_H
|
||||
#define _FMOD_CODEC_TREMOR_H
|
||||
|
||||
#include "fmod_settings.h"
|
||||
|
||||
#ifdef FMOD_SUPPORT_TREMOR
|
||||
|
||||
#include "fmod_codeci.h"
|
||||
|
||||
#include "../lib/tremor_lowmem/ivorbisfile.h"
|
||||
|
||||
namespace FMOD
|
||||
{
|
||||
class SyncPointNamed;
|
||||
|
||||
class CodecTremor : public Codec
|
||||
{
|
||||
private:
|
||||
|
||||
OggVorbis_File mVf;
|
||||
static bool gInitialized;
|
||||
|
||||
SyncPointNamed *mSyncPoint;
|
||||
int mNumSyncPoints;
|
||||
FMOD_CODEC_WAVEFORMAT mWaveFormat;
|
||||
|
||||
FMOD_RESULT openInternal(FMOD_MODE usermode, FMOD_CREATESOUNDEXINFO *userexinfo);
|
||||
FMOD_RESULT closeInternal();
|
||||
FMOD_RESULT readInternal(void *buffer, unsigned int size, unsigned int *read);
|
||||
FMOD_RESULT setPositionInternal(int subsound, unsigned int position, FMOD_TIMEUNIT postype);
|
||||
FMOD_RESULT readVorbisComments();
|
||||
|
||||
public:
|
||||
|
||||
static FMOD_RESULT F_CALLBACK openCallback(FMOD_CODEC_STATE *codec, FMOD_MODE usermode, FMOD_CREATESOUNDEXINFO *userexinfo);
|
||||
static FMOD_RESULT F_CALLBACK closeCallback(FMOD_CODEC_STATE *codec);
|
||||
static FMOD_RESULT F_CALLBACK readCallback(FMOD_CODEC_STATE *codec, void *buffer, unsigned int size, unsigned int *read);
|
||||
static FMOD_RESULT F_CALLBACK setPositionCallback(FMOD_CODEC_STATE *codec, int subsound, unsigned int position, FMOD_TIMEUNIT postype);
|
||||
|
||||
static FMOD_CODEC_DESCRIPTION_EX *getDescriptionEx();
|
||||
};
|
||||
}
|
||||
|
||||
#endif /* FMOD_SUPPORT_TREMOR */
|
||||
|
||||
#endif
|
||||
|
||||
330
src/fmod_codec_user.cpp
Executable file
330
src/fmod_codec_user.cpp
Executable file
|
|
@ -0,0 +1,330 @@
|
|||
#include "fmod_settings.h"
|
||||
|
||||
#ifdef FMOD_SUPPORT_USERCODEC
|
||||
|
||||
#include "fmod.h"
|
||||
#include "fmod_codec_user.h"
|
||||
#include "fmod_debug.h"
|
||||
#include "fmod_file.h"
|
||||
#include "fmod_soundi.h"
|
||||
#include "fmod_string.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
namespace FMOD
|
||||
{
|
||||
|
||||
|
||||
FMOD_CODEC_DESCRIPTION_EX usercodec;
|
||||
|
||||
#ifdef PLUGIN_EXPORTS
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
FMODGetCodecDescription is mandantory for every fmod plugin. This is the symbol the registerplugin function searches for.
|
||||
Must be declared with F_API to make it export as stdcall.
|
||||
*/
|
||||
F_DECLSPEC F_DLLEXPORT FMOD_CODEC_DESCRIPTION_EX * F_API FMODGetCodecDescriptionEx()
|
||||
{
|
||||
return CodecUser::getDescriptionEx();
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* PLUGIN_EXPORTS */
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_CODEC_DESCRIPTION_EX *CodecUser::getDescriptionEx()
|
||||
{
|
||||
FMOD_memset(&usercodec, 0, sizeof(FMOD_CODEC_DESCRIPTION_EX));
|
||||
|
||||
usercodec.name = "FMOD User Reader Codec";
|
||||
usercodec.version = 0x00010100;
|
||||
usercodec.timeunits = FMOD_TIMEUNIT_PCM;
|
||||
usercodec.open = &CodecUser::openCallback;
|
||||
usercodec.close = &CodecUser::closeCallback;
|
||||
usercodec.read = &CodecUser::readCallback;
|
||||
usercodec.setposition = &CodecUser::setPositionCallback;
|
||||
|
||||
usercodec.mType = FMOD_SOUND_TYPE_USER;
|
||||
usercodec.mSize = sizeof(CodecUser);
|
||||
|
||||
return &usercodec;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT CodecUser::openInternal(FMOD_MODE usermode, FMOD_CREATESOUNDEXINFO *userexinfo)
|
||||
{
|
||||
FMOD_RESULT result = FMOD_OK;
|
||||
|
||||
init(FMOD_SOUND_TYPE_USER);
|
||||
|
||||
FLOG((FMOD_DEBUG_LEVEL_LOG, __FILE__, __LINE__, "CodecUser::openInternal", "attempting to open user codec..\n"));
|
||||
|
||||
result = mFile->seek(0, SEEK_SET);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
waveformat = &mWaveFormat;
|
||||
|
||||
#if defined(PLATFORM_PS2) || defined(PLATFORM_PSP)
|
||||
if (userexinfo->format == FMOD_SOUND_FORMAT_VAG)
|
||||
{
|
||||
/* Do nothing */
|
||||
}
|
||||
else
|
||||
#endif
|
||||
if (userexinfo->format < FMOD_SOUND_FORMAT_PCM8 || userexinfo->format > FMOD_SOUND_FORMAT_PCMFLOAT)
|
||||
{
|
||||
return FMOD_ERR_FORMAT;
|
||||
}
|
||||
|
||||
/*
|
||||
Get size of file in bytes
|
||||
*/
|
||||
result = mFile->getSize(&waveformat[0].lengthbytes);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
TODO : Open and fill in needed codec values
|
||||
*/
|
||||
mSrcDataOffset = 0;
|
||||
|
||||
if (userexinfo->length)
|
||||
{
|
||||
mFlags |= FMOD_CODEC_USERLENGTH;
|
||||
}
|
||||
|
||||
waveformat[0].format = userexinfo->format;
|
||||
waveformat[0].channels = userexinfo->numchannels;
|
||||
waveformat[0].frequency = userexinfo->defaultfrequency;
|
||||
SoundI::getSamplesFromBytes(userexinfo->length, &waveformat[0].lengthpcm, userexinfo->numchannels, userexinfo->format);
|
||||
SoundI::getBytesFromSamples(1, (unsigned int *)&waveformat[0].blockalign, userexinfo->numchannels, userexinfo->format);
|
||||
|
||||
/*
|
||||
Fill out base class members, also pointing to or allocating storage for them.
|
||||
*/
|
||||
numsubsounds = 0;
|
||||
|
||||
FLOG((FMOD_DEBUG_LEVEL_LOG, __FILE__, __LINE__, "CodecUser::openInternal", "Done. format = %d, channels %d, frequency %d, lengthpcm %d, blockalign %d.\n", waveformat[0].format, waveformat[0].channels, waveformat[0].frequency, waveformat[0].lengthpcm, waveformat[0].blockalign));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT CodecUser::closeInternal()
|
||||
{
|
||||
/*
|
||||
TODO : Close codec / cleanup
|
||||
*/
|
||||
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT CodecUser::readInternal(void *buffer, unsigned int sizebytes, unsigned int *bytesread)
|
||||
{
|
||||
FMOD_RESULT result = FMOD_OK;
|
||||
|
||||
*bytesread = sizebytes;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT CodecUser::setPositionInternal(int subsound, unsigned int position, FMOD_TIMEUNIT postype)
|
||||
{
|
||||
FMOD_RESULT result = FMOD_OK;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT F_CALLBACK CodecUser::openCallback(FMOD_CODEC_STATE *codec, FMOD_MODE usermode, FMOD_CREATESOUNDEXINFO *userexinfo)
|
||||
{
|
||||
CodecUser *cuser = (CodecUser *)codec;
|
||||
|
||||
return cuser->openInternal(usermode, userexinfo);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT F_CALLBACK CodecUser::closeCallback(FMOD_CODEC_STATE *codec)
|
||||
{
|
||||
CodecUser *cuser = (CodecUser *)codec;
|
||||
|
||||
return cuser->closeInternal();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT F_CALLBACK CodecUser::readCallback(FMOD_CODEC_STATE *codec, void *buffer, unsigned int sizebytes, unsigned int *bytesread)
|
||||
{
|
||||
CodecUser *cuser = (CodecUser *)codec;
|
||||
|
||||
return cuser->readInternal(buffer, sizebytes, bytesread);
|
||||
}
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT F_CALLBACK CodecUser::setPositionCallback(FMOD_CODEC_STATE *codec, int subsound, unsigned int position, FMOD_TIMEUNIT postype)
|
||||
{
|
||||
CodecUser *cuser = (CodecUser *)codec;
|
||||
|
||||
return cuser->setPositionInternal(subsound, position, postype);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
37
src/fmod_codec_user.h
Executable file
37
src/fmod_codec_user.h
Executable file
|
|
@ -0,0 +1,37 @@
|
|||
#ifndef _FMOD_CODEC_USER_H
|
||||
#define _FMOD_CODEC_USER_H
|
||||
|
||||
#include "fmod_settings.h"
|
||||
|
||||
#ifdef FMOD_SUPPORT_USERCODEC
|
||||
|
||||
#include "fmod_codeci.h"
|
||||
|
||||
namespace FMOD
|
||||
{
|
||||
class CodecUser : public Codec
|
||||
{
|
||||
private:
|
||||
|
||||
FMOD_CODEC_WAVEFORMAT mWaveFormat;
|
||||
|
||||
FMOD_RESULT openInternal(FMOD_MODE usermode, FMOD_CREATESOUNDEXINFO *userexinfo);
|
||||
FMOD_RESULT closeInternal();
|
||||
FMOD_RESULT readInternal(void *buffer, unsigned int size, unsigned int *read);
|
||||
FMOD_RESULT setPositionInternal(int subsound, unsigned int position, FMOD_TIMEUNIT postype);
|
||||
|
||||
public:
|
||||
|
||||
static FMOD_RESULT F_CALLBACK openCallback(FMOD_CODEC_STATE *codec, FMOD_MODE usermode, FMOD_CREATESOUNDEXINFO *userexinfo);
|
||||
static FMOD_RESULT F_CALLBACK closeCallback(FMOD_CODEC_STATE *codec);
|
||||
static FMOD_RESULT F_CALLBACK readCallback(FMOD_CODEC_STATE *codec, void *buffer, unsigned int sizebytes, unsigned int *bytesread);
|
||||
static FMOD_RESULT F_CALLBACK setPositionCallback(FMOD_CODEC_STATE *codec, int subsound, unsigned int position, FMOD_TIMEUNIT postype);
|
||||
|
||||
static FMOD_CODEC_DESCRIPTION_EX *getDescriptionEx();
|
||||
};
|
||||
}
|
||||
|
||||
#endif /* FMOD_SUPPORT_USERCODEC */
|
||||
|
||||
#endif
|
||||
|
||||
1120
src/fmod_codec_wav.cpp
Executable file
1120
src/fmod_codec_wav.cpp
Executable file
File diff suppressed because it is too large
Load diff
180
src/fmod_codec_wav.h
Executable file
180
src/fmod_codec_wav.h
Executable file
|
|
@ -0,0 +1,180 @@
|
|||
#ifndef _FMOD_CODEC_WAV_H
|
||||
#define _FMOD_CODEC_WAV_H
|
||||
|
||||
#include "fmod_settings.h"
|
||||
|
||||
#if defined(FMOD_SUPPORT_WAV) || defined(FMOD_SUPPORT_IMAADPCM)
|
||||
|
||||
#include "fmod_codeci.h"
|
||||
#include "fmod_memory.h"
|
||||
#include "fmod_types.h"
|
||||
|
||||
#if defined(PLATFORM_WINDOWS)
|
||||
#include <windows.h>
|
||||
#include <mmreg.h>
|
||||
#include <msacm.h>
|
||||
#endif
|
||||
|
||||
namespace FMOD
|
||||
{
|
||||
#ifndef WAVE_FORMAT_PCM
|
||||
#define WAVE_FORMAT_PCM 1
|
||||
#endif
|
||||
|
||||
#ifndef WAVE_FORMAT_IEEE_FLOAT
|
||||
#define WAVE_FORMAT_IEEE_FLOAT 3
|
||||
#endif
|
||||
|
||||
#ifndef WAVE_FORMAT_MPEG
|
||||
#define WAVE_FORMAT_MPEG 0x0050 /* Microsoft Corporation */
|
||||
#endif
|
||||
|
||||
#ifndef WAVE_FORMAT_MPEGLAYER3
|
||||
#define WAVE_FORMAT_MPEGLAYER3 0x0055
|
||||
#endif
|
||||
|
||||
#ifndef WAVE_FORMAT_OGGVORBIS
|
||||
#define WAVE_FORMAT_OGGVORBIS 0x6750
|
||||
#endif
|
||||
|
||||
#ifndef WAVE_FORMAT_EXTENSIBLE
|
||||
#define WAVE_FORMAT_EXTENSIBLE 0xFFFE
|
||||
#endif
|
||||
|
||||
#ifdef FMOD_SUPPORT_PRAGMAPACK
|
||||
#pragma pack(1)
|
||||
#endif
|
||||
|
||||
#define F_WSMP_NO_TRUNCATION 0x0001
|
||||
#define F_WSMP_NO_COMPRESSION 0x0002
|
||||
#define WLOOP_TYPE_FORWARD 0
|
||||
|
||||
typedef struct
|
||||
{
|
||||
signed char id[4] FMOD_PACKED_INTERNAL;
|
||||
unsigned int size FMOD_PACKED_INTERNAL;
|
||||
} FMOD_PACKED WAVE_CHUNK;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned short wFormatTag FMOD_PACKED_INTERNAL; /* format type */
|
||||
unsigned short nChannels FMOD_PACKED_INTERNAL; /* number of channels (i.e. mono, stereo...) */
|
||||
unsigned int nSamplesPerSec FMOD_PACKED_INTERNAL; /* sample rate */
|
||||
unsigned int nAvgBytesPerSec FMOD_PACKED_INTERNAL; /* for buffer estimation */
|
||||
unsigned short nBlockAlign FMOD_PACKED_INTERNAL; /* block size of data */
|
||||
unsigned short wBitsPerSample FMOD_PACKED_INTERNAL; /* number of bits per sample of mono data */
|
||||
unsigned short cbSize FMOD_PACKED_INTERNAL; /* the count in bytes of the size of extra information (after cbSize) */
|
||||
} FMOD_PACKED WAVE_FORMATEX;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
WAVE_FORMATEX Format FMOD_PACKED_INTERNAL;
|
||||
union
|
||||
{
|
||||
unsigned short wValidBitsPerSample FMOD_PACKED_INTERNAL; /* bits of precision */
|
||||
unsigned short wSamplesPerBlock FMOD_PACKED_INTERNAL; /* valid if wBitsPerSample==0 */
|
||||
unsigned short wReserved FMOD_PACKED_INTERNAL; /* If neither applies, set to zero. */
|
||||
} FMOD_PACKED Samples;
|
||||
unsigned int dwChannelMask FMOD_PACKED_INTERNAL; /* which channels are */
|
||||
FMOD_GUID SubFormat FMOD_PACKED_INTERNAL;
|
||||
} FMOD_PACKED WAVE_FORMATEXTENSIBLE;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned int Manufacturer FMOD_PACKED_INTERNAL;
|
||||
unsigned int Product FMOD_PACKED_INTERNAL;
|
||||
unsigned int SamplePeriod FMOD_PACKED_INTERNAL;
|
||||
unsigned int Note FMOD_PACKED_INTERNAL;
|
||||
unsigned int FineTune FMOD_PACKED_INTERNAL;
|
||||
unsigned int SMPTEFormat FMOD_PACKED_INTERNAL;
|
||||
unsigned int SMPTEOffset FMOD_PACKED_INTERNAL;
|
||||
unsigned int Loops FMOD_PACKED_INTERNAL;
|
||||
unsigned int SamplerData FMOD_PACKED_INTERNAL;
|
||||
struct
|
||||
{
|
||||
unsigned int Identifier FMOD_PACKED_INTERNAL;
|
||||
unsigned int Type FMOD_PACKED_INTERNAL;
|
||||
unsigned int Start FMOD_PACKED_INTERNAL;
|
||||
unsigned int End FMOD_PACKED_INTERNAL;
|
||||
unsigned int Fraction FMOD_PACKED_INTERNAL;
|
||||
unsigned int Count FMOD_PACKED_INTERNAL;
|
||||
} FMOD_PACKED Loop;
|
||||
} FMOD_PACKED WAVE_SMPLHEADER;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int dwIdentifier FMOD_PACKED_INTERNAL;
|
||||
int dwPosition FMOD_PACKED_INTERNAL;
|
||||
char fccChunk[4] FMOD_PACKED_INTERNAL;
|
||||
int dwChunkStart FMOD_PACKED_INTERNAL;
|
||||
int dwBlockStart FMOD_PACKED_INTERNAL;
|
||||
int dwSampleOffset FMOD_PACKED_INTERNAL;
|
||||
} FMOD_PACKED WAVE_CUEPOINT;
|
||||
|
||||
#ifdef FMOD_SUPPORT_PRAGMAPACK
|
||||
#ifdef CODEWARRIOR
|
||||
#pragma pack(0)
|
||||
#else
|
||||
#pragma pack()
|
||||
#endif
|
||||
#endif
|
||||
|
||||
class SyncPointNamed;
|
||||
class ChannelSoftware;
|
||||
class ChannelOpenAL;
|
||||
|
||||
class CodecWav : public Codec
|
||||
{
|
||||
friend class CodecMPEG;
|
||||
friend class CodecMPEGPSP;
|
||||
friend class CodecOggVorbis;
|
||||
friend class CodecTremor;
|
||||
friend class CodecDLS;
|
||||
friend class CodecFSB;
|
||||
friend class ChannelSoftware;
|
||||
friend class ChannelOpenAL;
|
||||
friend class DSPCodec;
|
||||
friend class DSPCodecPool;
|
||||
friend class SystemI;
|
||||
|
||||
private:
|
||||
|
||||
#if defined(PLATFORM_WINDOWS) && !defined(__MINGW32__)
|
||||
HACMSTREAM mACMCodec;
|
||||
#endif
|
||||
|
||||
WAVE_FORMATEXTENSIBLE mDestFormat;
|
||||
|
||||
int mNumSyncPoints;
|
||||
SyncPointNamed *mSyncPoint;
|
||||
int mSamplesPerADPCMBlock;
|
||||
|
||||
FMOD_RESULT parseChunk(unsigned int chunksize);
|
||||
FMOD_RESULT openInternal(FMOD_MODE usermode, FMOD_CREATESOUNDEXINFO *userexinfo);
|
||||
FMOD_RESULT closeInternal();
|
||||
FMOD_RESULT readInternal(void *buffer, unsigned int size, unsigned int *read);
|
||||
FMOD_RESULT setPositionInternal(int subsound, unsigned int position, FMOD_TIMEUNIT postype);
|
||||
FMOD_RESULT soundCreateInternal(int subsound, FMOD_SOUND *sound);
|
||||
FMOD_RESULT canPointInternal();
|
||||
|
||||
public:
|
||||
|
||||
WAVE_FORMATEXTENSIBLE mSrcFormatMemory;
|
||||
WAVE_FORMATEXTENSIBLE *mSrcFormat;
|
||||
|
||||
static FMOD_RESULT F_CALLBACK openCallback(FMOD_CODEC_STATE *codec, FMOD_MODE usermode, FMOD_CREATESOUNDEXINFO *userexinfo);
|
||||
static FMOD_RESULT F_CALLBACK closeCallback(FMOD_CODEC_STATE *codec);
|
||||
static FMOD_RESULT F_CALLBACK readCallback(FMOD_CODEC_STATE *codec, void *buffer, unsigned int size, unsigned int *read);
|
||||
static FMOD_RESULT F_CALLBACK setPositionCallback(FMOD_CODEC_STATE *codec, int subsound, unsigned int position, FMOD_TIMEUNIT postype);
|
||||
static FMOD_RESULT F_CALLBACK soundCreateCallback(FMOD_CODEC_STATE *codec, int subsound, FMOD_SOUND *sound);
|
||||
static FMOD_RESULT F_CALLBACK canPointCallback(FMOD_CODEC_STATE *codec);
|
||||
|
||||
static FMOD_CODEC_DESCRIPTION_EX *getDescriptionEx();
|
||||
};
|
||||
}
|
||||
|
||||
#endif /* FMOD_SUPPORT_WAV */
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
787
src/fmod_codec_wav_imaadpcm.cpp
Executable file
787
src/fmod_codec_wav_imaadpcm.cpp
Executable file
|
|
@ -0,0 +1,787 @@
|
|||
#include "fmod_settings.h"
|
||||
|
||||
#ifdef FMOD_SUPPORT_IMAADPCM
|
||||
|
||||
#include "fmod_codec_wav_imaadpcm.h"
|
||||
|
||||
namespace FMOD
|
||||
{
|
||||
|
||||
#undef LOWORD
|
||||
#undef HIWORD
|
||||
|
||||
#undef LOWORD
|
||||
#undef HIWORD
|
||||
#undef MAKEULONG
|
||||
#undef MAKELONG
|
||||
|
||||
#define LOWORD(_l) ((unsigned short)(_l))
|
||||
#define HIWORD(_l) ((unsigned short)(((unsigned int)(_l) >> 16) & 0xFFFF))
|
||||
|
||||
#ifdef PLATFORM_ENDIAN_BIG
|
||||
#define MAKEULONG(l, h) ((unsigned int)(((unsigned short)(h)) | ((unsigned int)((unsigned short)(l))) << 16))
|
||||
#else
|
||||
#define MAKEULONG(l, h) ((unsigned int)(((unsigned short)(l)) | ((unsigned int)((unsigned short)(h))) << 16))
|
||||
#endif
|
||||
|
||||
#define MAKELONG(l, h) ((int)MAKEULONG(l, h))
|
||||
|
||||
#define NUMELMS(a) (sizeof(a) / sizeof(a[0]))
|
||||
|
||||
static const int IMAAdpcm_IndexTab[16] =
|
||||
{
|
||||
-1, -1, -1, -1, 2, 4, 6, 8,
|
||||
-1, -1, -1, -1, 2, 4, 6, 8
|
||||
};
|
||||
|
||||
//
|
||||
// This array contains the array of step sizes used to encode the ADPCM
|
||||
// samples. The step index in each ADPCM block is an index to this array.
|
||||
//
|
||||
static const short IMAAdpcm_StepTab[89] =
|
||||
{
|
||||
7, 8, 9, 10, 11, 12, 13,
|
||||
14, 16, 17, 19, 21, 23, 25,
|
||||
28, 31, 34, 37, 41, 45, 50,
|
||||
55, 60, 66, 73, 80, 88, 97,
|
||||
107, 118, 130, 143, 157, 173, 190,
|
||||
209, 230, 253, 279, 307, 337, 371,
|
||||
408, 449, 494, 544, 598, 658, 724,
|
||||
796, 876, 963, 1060, 1166, 1282, 1411,
|
||||
1552, 1707, 1878, 2066, 2272, 2499, 2749,
|
||||
3024, 3327, 3660, 4026, 4428, 4871, 5358,
|
||||
5894, 6484, 7132, 7845, 8630, 9493, 10442,
|
||||
11487, 12635, 13899, 15289, 16818, 18500, 20350,
|
||||
22385, 24623, 27086, 29794, 32767
|
||||
};
|
||||
|
||||
|
||||
FMOD_INLINE int IMAAdpcm_NextStepIndex(int nEncodedSample, int nStepIndex)
|
||||
{
|
||||
nStepIndex += IMAAdpcm_IndexTab[nEncodedSample];
|
||||
|
||||
if(nStepIndex < 0)
|
||||
{
|
||||
nStepIndex = 0;
|
||||
}
|
||||
else if (nStepIndex >= (int)NUMELMS(IMAAdpcm_StepTab))
|
||||
{
|
||||
nStepIndex = NUMELMS(IMAAdpcm_StepTab) - 1;
|
||||
}
|
||||
|
||||
return nStepIndex;
|
||||
}
|
||||
|
||||
FMOD_INLINE signed char ValidStepIndex(int nStepIndex)
|
||||
{
|
||||
return (nStepIndex >= 0) && (nStepIndex < (int)NUMELMS(IMAAdpcm_StepTab));
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
*
|
||||
* IMAAdpcm_DecodeSample
|
||||
*
|
||||
* Description:
|
||||
* Decodes an encoded sample.
|
||||
*
|
||||
* Arguments:
|
||||
* int [in]: the sample to be decoded.
|
||||
* int [in]: the predicted value of the sample.
|
||||
* int [i]: the quantization step size used to encode the sample.
|
||||
*
|
||||
* Returns:
|
||||
* int: the decoded PCM sample.
|
||||
*
|
||||
****************************************************************************/
|
||||
FMOD_INLINE int IMAAdpcm_DecodeSample(int nEncodedSample, int nPredictedSample, int nStepSize)
|
||||
{
|
||||
int lDifference;
|
||||
int lNewSample;
|
||||
|
||||
lDifference = nStepSize >> 3;
|
||||
|
||||
#if 1
|
||||
|
||||
switch (nEncodedSample)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
break;
|
||||
}
|
||||
case 1:
|
||||
{
|
||||
lDifference += nStepSize >> 2;
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
lDifference += nStepSize >> 1;
|
||||
break;
|
||||
}
|
||||
case 3:
|
||||
{
|
||||
lDifference += nStepSize >> 1;
|
||||
lDifference += nStepSize >> 2;
|
||||
break;
|
||||
}
|
||||
case 4:
|
||||
{
|
||||
lDifference += nStepSize;
|
||||
break;
|
||||
}
|
||||
case 5:
|
||||
{
|
||||
lDifference += nStepSize;
|
||||
lDifference += nStepSize >> 2;
|
||||
break;
|
||||
}
|
||||
case 6:
|
||||
{
|
||||
lDifference += nStepSize;
|
||||
lDifference += nStepSize >> 1;
|
||||
break;
|
||||
}
|
||||
case 7:
|
||||
{
|
||||
lDifference += nStepSize;
|
||||
lDifference += nStepSize >> 1;
|
||||
lDifference += nStepSize >> 2;
|
||||
break;
|
||||
}
|
||||
case 8:
|
||||
{
|
||||
lDifference = -lDifference;
|
||||
break;
|
||||
}
|
||||
case 9:
|
||||
{
|
||||
lDifference += nStepSize >> 2;
|
||||
lDifference = -lDifference;
|
||||
break;
|
||||
}
|
||||
case 10:
|
||||
{
|
||||
lDifference += nStepSize >> 1;
|
||||
lDifference = -lDifference;
|
||||
break;
|
||||
}
|
||||
case 11:
|
||||
{
|
||||
lDifference += nStepSize >> 1;
|
||||
lDifference += nStepSize >> 2;
|
||||
lDifference = -lDifference;
|
||||
break;
|
||||
}
|
||||
case 12:
|
||||
{
|
||||
lDifference += nStepSize;
|
||||
lDifference = -lDifference;
|
||||
break;
|
||||
}
|
||||
case 13:
|
||||
{
|
||||
lDifference += nStepSize;
|
||||
lDifference += nStepSize >> 2;
|
||||
lDifference = -lDifference;
|
||||
break;
|
||||
}
|
||||
case 14:
|
||||
{
|
||||
lDifference += nStepSize;
|
||||
lDifference += nStepSize >> 1;
|
||||
lDifference = -lDifference;
|
||||
break;
|
||||
}
|
||||
case 15:
|
||||
{
|
||||
lDifference += nStepSize;
|
||||
lDifference += nStepSize >> 1;
|
||||
lDifference += nStepSize >> 2;
|
||||
lDifference = -lDifference;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
#else
|
||||
if(nEncodedSample & 4)
|
||||
{
|
||||
lDifference += nStepSize;
|
||||
}
|
||||
|
||||
if(nEncodedSample & 2)
|
||||
{
|
||||
lDifference += nStepSize >> 1;
|
||||
}
|
||||
|
||||
if(nEncodedSample & 1)
|
||||
{
|
||||
lDifference += nStepSize >> 2;
|
||||
}
|
||||
|
||||
if(nEncodedSample & 8)
|
||||
{
|
||||
lDifference = -lDifference;
|
||||
}
|
||||
#endif
|
||||
|
||||
lNewSample = nPredictedSample + lDifference;
|
||||
|
||||
if((int)(short)lNewSample != lNewSample)
|
||||
{
|
||||
if(lNewSample < -32768)
|
||||
{
|
||||
lNewSample = -32768;
|
||||
}
|
||||
else
|
||||
{
|
||||
lNewSample = 32767;
|
||||
}
|
||||
}
|
||||
|
||||
return (int)lNewSample;
|
||||
}
|
||||
|
||||
|
||||
|
||||
FMOD_RESULT IMAAdpcm_DecodeM16(unsigned char *pbSrc, signed short *pbDst, unsigned int cBlocks, unsigned int nBlockAlignment, unsigned int cSamplesPerBlock, int channels)
|
||||
{
|
||||
FMOD_RESULT result = FMOD_OK;
|
||||
unsigned char *pbBlock;
|
||||
unsigned int cSamples;
|
||||
unsigned char bSample;
|
||||
int nStepSize;
|
||||
int nEncSample;
|
||||
int nPredSample;
|
||||
int nStepIndex;
|
||||
unsigned int dwHeader;
|
||||
|
||||
//
|
||||
// Enter the main loop
|
||||
//
|
||||
|
||||
while(cBlocks--)
|
||||
{
|
||||
pbBlock = pbSrc;
|
||||
cSamples = cSamplesPerBlock - 1;
|
||||
|
||||
//
|
||||
// Block header
|
||||
//
|
||||
|
||||
dwHeader = *(unsigned int *)pbBlock;
|
||||
#ifdef PLATFORM_ENDIAN_BIG
|
||||
dwHeader = FMOD_SWAPENDIAN_DWORD(dwHeader);
|
||||
#endif
|
||||
pbBlock += sizeof(unsigned int);
|
||||
|
||||
nPredSample = (int)(short)LOWORD(dwHeader);
|
||||
nStepIndex = (int)(unsigned char)HIWORD(dwHeader);
|
||||
|
||||
if(!ValidStepIndex(nStepIndex))
|
||||
{
|
||||
//
|
||||
// The step index is out of range - this is considered a fatal
|
||||
// error as the input stream is corrupted. We fail by returning
|
||||
// zero chars converted.
|
||||
//
|
||||
|
||||
result = FMOD_ERR_FILE_BAD;
|
||||
break;
|
||||
}
|
||||
|
||||
//
|
||||
// Write out first sample
|
||||
//
|
||||
|
||||
*pbDst = (short)nPredSample;
|
||||
pbDst += channels;
|
||||
|
||||
//
|
||||
// Enter the block loop
|
||||
//
|
||||
|
||||
while(cSamples)
|
||||
{
|
||||
bSample = *pbBlock++;
|
||||
|
||||
//
|
||||
// Sample 1
|
||||
//
|
||||
|
||||
nEncSample = (bSample & (unsigned char)0x0F);
|
||||
nStepSize = IMAAdpcm_StepTab[nStepIndex];
|
||||
nPredSample = IMAAdpcm_DecodeSample(nEncSample, nPredSample, nStepSize);
|
||||
nStepIndex = IMAAdpcm_NextStepIndex(nEncSample, nStepIndex);
|
||||
|
||||
*pbDst = (short)nPredSample;
|
||||
pbDst += channels;
|
||||
|
||||
cSamples--;
|
||||
|
||||
//
|
||||
// Sample 2
|
||||
//
|
||||
|
||||
if(cSamples)
|
||||
{
|
||||
nEncSample = (bSample >> 4);
|
||||
nStepSize = IMAAdpcm_StepTab[nStepIndex];
|
||||
nPredSample = IMAAdpcm_DecodeSample(nEncSample, nPredSample, nStepSize);
|
||||
nStepIndex = IMAAdpcm_NextStepIndex(nEncSample, nStepIndex);
|
||||
|
||||
*pbDst = (short)nPredSample;
|
||||
pbDst += channels;
|
||||
|
||||
cSamples--;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Skip padding
|
||||
//
|
||||
|
||||
pbSrc += nBlockAlignment;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
FMOD_RESULT IMAAdpcm_DecodeS16(unsigned char *pbSrc, signed short *pbDst, unsigned int cBlocks, unsigned int nBlockAlignment, unsigned int cSamplesPerBlock)
|
||||
{
|
||||
FMOD_RESULT result = FMOD_OK;
|
||||
unsigned char *pbBlock;
|
||||
unsigned int cSamples;
|
||||
unsigned int cSubSamples;
|
||||
int nStepSize;
|
||||
unsigned int dwHeader;
|
||||
unsigned int dwLeft;
|
||||
unsigned int dwRight;
|
||||
int nEncSampleL;
|
||||
int nPredSampleL;
|
||||
int nStepIndexL;
|
||||
int nEncSampleR;
|
||||
int nPredSampleR;
|
||||
int nStepIndexR;
|
||||
unsigned int i;
|
||||
|
||||
//
|
||||
// Enter the main loop
|
||||
//
|
||||
|
||||
while(cBlocks--)
|
||||
{
|
||||
pbBlock = pbSrc;
|
||||
cSamples = cSamplesPerBlock - 1;
|
||||
|
||||
//
|
||||
// LEFT channel header
|
||||
//
|
||||
|
||||
dwHeader = *(unsigned int *)pbBlock;
|
||||
#ifdef PLATFORM_ENDIAN_BIG
|
||||
dwHeader = FMOD_SWAPENDIAN_DWORD(dwHeader);
|
||||
#endif
|
||||
pbBlock += sizeof(unsigned int);
|
||||
|
||||
nPredSampleL = (int)(short)LOWORD(dwHeader);
|
||||
nStepIndexL = (int)(unsigned char)HIWORD(dwHeader);
|
||||
|
||||
if(!ValidStepIndex(nStepIndexL))
|
||||
{
|
||||
//
|
||||
// The step index is out of range - this is considered a fatal
|
||||
// error as the input stream is corrupted. We fail by returning
|
||||
// zero bytes converted.
|
||||
//
|
||||
|
||||
result = FMOD_ERR_FILE_BAD;
|
||||
break;
|
||||
}
|
||||
|
||||
//
|
||||
// RIGHT channel header
|
||||
//
|
||||
|
||||
dwHeader = *(unsigned int *)pbBlock;
|
||||
#ifdef PLATFORM_ENDIAN_BIG
|
||||
dwHeader = FMOD_SWAPENDIAN_DWORD(dwHeader);
|
||||
#endif
|
||||
pbBlock += sizeof(unsigned int);
|
||||
|
||||
nPredSampleR = (int)(short)LOWORD(dwHeader);
|
||||
nStepIndexR = (int)(unsigned char)HIWORD(dwHeader);
|
||||
|
||||
if(!ValidStepIndex(nStepIndexR))
|
||||
{
|
||||
//
|
||||
// The step index is out of range - this is considered a fatal
|
||||
// error as the input stream is corrupted. We fail by returning
|
||||
// zero bytes converted.
|
||||
//
|
||||
|
||||
result = FMOD_ERR_FILE_BAD;
|
||||
break;
|
||||
}
|
||||
|
||||
//
|
||||
// Write out first sample
|
||||
//
|
||||
|
||||
*pbDst++ = nPredSampleL;
|
||||
*pbDst++ = nPredSampleR;
|
||||
|
||||
//
|
||||
// The first DWORD contains 4 left samples, the second DWORD
|
||||
// contains 4 right samples. We process the source in 8-byte
|
||||
// chunks to make it easy to interleave the output correctly.
|
||||
//
|
||||
|
||||
while(cSamples)
|
||||
{
|
||||
dwLeft = *(unsigned int *)pbBlock;
|
||||
#ifdef PLATFORM_ENDIAN_BIG
|
||||
dwLeft = FMOD_SWAPENDIAN_DWORD(dwLeft);
|
||||
#endif
|
||||
pbBlock += sizeof(unsigned int);
|
||||
dwRight = *(unsigned int *)pbBlock;
|
||||
#ifdef PLATFORM_ENDIAN_BIG
|
||||
dwRight = FMOD_SWAPENDIAN_DWORD(dwRight);
|
||||
#endif
|
||||
pbBlock += sizeof(unsigned int);
|
||||
|
||||
// cSubSamples = min(cSamples, 8);
|
||||
cSubSamples = 8;
|
||||
if (cSamples < cSubSamples)
|
||||
{
|
||||
cSubSamples = cSamples;
|
||||
}
|
||||
|
||||
for(i = 0; i < cSubSamples; i++)
|
||||
{
|
||||
//
|
||||
// LEFT channel
|
||||
//
|
||||
|
||||
nEncSampleL = (dwLeft & 0x0F);
|
||||
nStepSize = IMAAdpcm_StepTab[nStepIndexL];
|
||||
nPredSampleL = IMAAdpcm_DecodeSample(nEncSampleL, nPredSampleL, nStepSize);
|
||||
nStepIndexL = IMAAdpcm_NextStepIndex(nEncSampleL, nStepIndexL);
|
||||
|
||||
//
|
||||
// RIGHT channel
|
||||
//
|
||||
|
||||
nEncSampleR = (dwRight & 0x0F);
|
||||
nStepSize = IMAAdpcm_StepTab[nStepIndexR];
|
||||
nPredSampleR = IMAAdpcm_DecodeSample(nEncSampleR, nPredSampleR, nStepSize);
|
||||
nStepIndexR = IMAAdpcm_NextStepIndex(nEncSampleR, nStepIndexR);
|
||||
|
||||
//
|
||||
// Write out sample
|
||||
//
|
||||
|
||||
*pbDst++ = nPredSampleL;
|
||||
*pbDst++ = nPredSampleR;
|
||||
|
||||
//
|
||||
// Shift the next input sample into the low-order 4 bits.
|
||||
//
|
||||
|
||||
dwLeft >>= 4;
|
||||
dwRight >>= 4;
|
||||
}
|
||||
|
||||
cSamples -= cSubSamples;
|
||||
}
|
||||
|
||||
//
|
||||
// Skip padding
|
||||
//
|
||||
|
||||
pbSrc += nBlockAlignment;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
FMOD_RESULT IMAAdpcm_DecodeM16(unsigned char *pbSrc, float *pbDst, unsigned int cBlocks, unsigned int nBlockAlignment, unsigned int cSamplesPerBlock, int channels)
|
||||
{
|
||||
FMOD_RESULT result = FMOD_OK;
|
||||
unsigned char *pbBlock;
|
||||
unsigned int cSamples;
|
||||
unsigned char bSample;
|
||||
int nStepSize;
|
||||
int nEncSample;
|
||||
int nPredSample;
|
||||
int nStepIndex;
|
||||
unsigned int dwHeader;
|
||||
|
||||
//
|
||||
// Enter the main loop
|
||||
//
|
||||
|
||||
while(cBlocks--)
|
||||
{
|
||||
pbBlock = pbSrc;
|
||||
cSamples = cSamplesPerBlock - 1;
|
||||
|
||||
//
|
||||
// Block header
|
||||
//
|
||||
|
||||
dwHeader = *(unsigned int *)pbBlock;
|
||||
#ifdef PLATFORM_ENDIAN_BIG
|
||||
dwHeader = FMOD_SWAPENDIAN_DWORD(dwHeader);
|
||||
#endif
|
||||
pbBlock += sizeof(unsigned int);
|
||||
|
||||
nPredSample = (int)(short)LOWORD(dwHeader);
|
||||
nStepIndex = (int)(unsigned char)HIWORD(dwHeader);
|
||||
|
||||
if(!ValidStepIndex(nStepIndex))
|
||||
{
|
||||
//
|
||||
// The step index is out of range - this is considered a fatal
|
||||
// error as the input stream is corrupted. We fail by returning
|
||||
// zero chars converted.
|
||||
//
|
||||
|
||||
result = FMOD_ERR_FILE_BAD;
|
||||
break;
|
||||
}
|
||||
|
||||
//
|
||||
// Write out first sample
|
||||
//
|
||||
|
||||
*pbDst = nPredSample * (1.0f / 32768.0f);
|
||||
pbDst += channels;
|
||||
|
||||
//
|
||||
// Enter the block loop
|
||||
//
|
||||
while(cSamples > 1)
|
||||
{
|
||||
bSample = *pbBlock++;
|
||||
|
||||
//
|
||||
// Sample 1
|
||||
//
|
||||
|
||||
nEncSample = (bSample & (unsigned char)0x0F);
|
||||
nStepSize = IMAAdpcm_StepTab[nStepIndex];
|
||||
nPredSample = IMAAdpcm_DecodeSample(nEncSample, nPredSample, nStepSize);
|
||||
nStepIndex = IMAAdpcm_NextStepIndex(nEncSample, nStepIndex);
|
||||
|
||||
pbDst[0] = nPredSample * (1.0f / 32768.0f);
|
||||
|
||||
//
|
||||
// Sample 2
|
||||
//
|
||||
nEncSample = (bSample >> 4);
|
||||
nStepSize = IMAAdpcm_StepTab[nStepIndex];
|
||||
nPredSample = IMAAdpcm_DecodeSample(nEncSample, nPredSample, nStepSize);
|
||||
nStepIndex = IMAAdpcm_NextStepIndex(nEncSample, nStepIndex);
|
||||
|
||||
pbDst[channels] = nPredSample * (1.0f / 32768.0f);
|
||||
|
||||
cSamples -=2;
|
||||
pbDst += channels*2;
|
||||
}
|
||||
|
||||
if (cSamples)
|
||||
{
|
||||
bSample = *pbBlock++;
|
||||
|
||||
//
|
||||
// Sample 1
|
||||
//
|
||||
|
||||
nEncSample = (bSample & (unsigned char)0x0F);
|
||||
nStepSize = IMAAdpcm_StepTab[nStepIndex];
|
||||
nPredSample = IMAAdpcm_DecodeSample(nEncSample, nPredSample, nStepSize);
|
||||
nStepIndex = IMAAdpcm_NextStepIndex(nEncSample, nStepIndex);
|
||||
|
||||
pbDst[0] = nPredSample * (1.0f / 32768.0f);
|
||||
cSamples --;
|
||||
pbDst += channels;
|
||||
}
|
||||
|
||||
//
|
||||
// Skip padding
|
||||
//
|
||||
|
||||
pbSrc += nBlockAlignment;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
FMOD_RESULT IMAAdpcm_DecodeS16(unsigned char *pbSrc, float *pbDst, unsigned int cBlocks, unsigned int nBlockAlignment, unsigned int cSamplesPerBlock)
|
||||
{
|
||||
FMOD_RESULT result = FMOD_OK;
|
||||
unsigned char *pbBlock;
|
||||
unsigned int cSamples;
|
||||
unsigned int cSubSamples;
|
||||
int nStepSize;
|
||||
unsigned int dwHeader;
|
||||
unsigned int dwLeft;
|
||||
unsigned int dwRight;
|
||||
int nEncSampleL;
|
||||
int nPredSampleL;
|
||||
int nStepIndexL;
|
||||
int nEncSampleR;
|
||||
int nPredSampleR;
|
||||
int nStepIndexR;
|
||||
unsigned int i;
|
||||
|
||||
//
|
||||
// Enter the main loop
|
||||
//
|
||||
|
||||
while(cBlocks--)
|
||||
{
|
||||
pbBlock = pbSrc;
|
||||
cSamples = cSamplesPerBlock - 1;
|
||||
|
||||
//
|
||||
// LEFT channel header
|
||||
//
|
||||
|
||||
dwHeader = *(unsigned int *)pbBlock;
|
||||
#ifdef PLATFORM_ENDIAN_BIG
|
||||
dwHeader = FMOD_SWAPENDIAN_DWORD(dwHeader);
|
||||
#endif
|
||||
pbBlock += sizeof(unsigned int);
|
||||
|
||||
nPredSampleL = (int)(short)LOWORD(dwHeader);
|
||||
nStepIndexL = (int)(unsigned char)HIWORD(dwHeader);
|
||||
|
||||
if(!ValidStepIndex(nStepIndexL))
|
||||
{
|
||||
//
|
||||
// The step index is out of range - this is considered a fatal
|
||||
// error as the input stream is corrupted. We fail by returning
|
||||
// zero bytes converted.
|
||||
//
|
||||
|
||||
result = FMOD_ERR_FILE_BAD;
|
||||
break;
|
||||
}
|
||||
|
||||
//
|
||||
// RIGHT channel header
|
||||
//
|
||||
|
||||
dwHeader = *(unsigned int *)pbBlock;
|
||||
#ifdef PLATFORM_ENDIAN_BIG
|
||||
dwHeader = FMOD_SWAPENDIAN_DWORD(dwHeader);
|
||||
#endif
|
||||
pbBlock += sizeof(unsigned int);
|
||||
|
||||
nPredSampleR = (int)(short)LOWORD(dwHeader);
|
||||
nStepIndexR = (int)(unsigned char)HIWORD(dwHeader);
|
||||
|
||||
if(!ValidStepIndex(nStepIndexR))
|
||||
{
|
||||
//
|
||||
// The step index is out of range - this is considered a fatal
|
||||
// error as the input stream is corrupted. We fail by returning
|
||||
// zero bytes converted.
|
||||
//
|
||||
|
||||
result = FMOD_ERR_FILE_BAD;
|
||||
break;
|
||||
}
|
||||
|
||||
//
|
||||
// Write out first sample
|
||||
//
|
||||
|
||||
*pbDst++ = nPredSampleL * (1.0f / 32768.0f);
|
||||
*pbDst++ = nPredSampleR * (1.0f / 32768.0f);
|
||||
|
||||
//
|
||||
// The first DWORD contains 4 left samples, the second DWORD
|
||||
// contains 4 right samples. We process the source in 8-byte
|
||||
// chunks to make it easy to interleave the output correctly.
|
||||
//
|
||||
|
||||
while(cSamples)
|
||||
{
|
||||
dwLeft = *(unsigned int *)pbBlock;
|
||||
#ifdef PLATFORM_ENDIAN_BIG
|
||||
dwLeft = FMOD_SWAPENDIAN_DWORD(dwLeft);
|
||||
#endif
|
||||
pbBlock += sizeof(unsigned int);
|
||||
dwRight = *(unsigned int *)pbBlock;
|
||||
#ifdef PLATFORM_ENDIAN_BIG
|
||||
dwRight = FMOD_SWAPENDIAN_DWORD(dwRight);
|
||||
#endif
|
||||
pbBlock += sizeof(unsigned int);
|
||||
|
||||
// cSubSamples = min(cSamples, 8);
|
||||
cSubSamples = 8;
|
||||
if (cSamples < cSubSamples)
|
||||
{
|
||||
cSubSamples = cSamples;
|
||||
}
|
||||
|
||||
for(i = 0; i < cSubSamples; i++)
|
||||
{
|
||||
//
|
||||
// LEFT channel
|
||||
//
|
||||
|
||||
nEncSampleL = (dwLeft & 0x0F);
|
||||
nStepSize = IMAAdpcm_StepTab[nStepIndexL];
|
||||
nPredSampleL = IMAAdpcm_DecodeSample(nEncSampleL, nPredSampleL, nStepSize);
|
||||
nStepIndexL = IMAAdpcm_NextStepIndex(nEncSampleL, nStepIndexL);
|
||||
|
||||
//
|
||||
// RIGHT channel
|
||||
//
|
||||
|
||||
nEncSampleR = (dwRight & 0x0F);
|
||||
nStepSize = IMAAdpcm_StepTab[nStepIndexR];
|
||||
nPredSampleR = IMAAdpcm_DecodeSample(nEncSampleR, nPredSampleR, nStepSize);
|
||||
nStepIndexR = IMAAdpcm_NextStepIndex(nEncSampleR, nStepIndexR);
|
||||
|
||||
//
|
||||
// Write out sample
|
||||
//
|
||||
|
||||
*pbDst++ = nPredSampleL * (1.0f / 32768.0f);
|
||||
*pbDst++ = nPredSampleR * (1.0f / 32768.0f);
|
||||
|
||||
//
|
||||
// Shift the next input sample into the low-order 4 bits.
|
||||
//
|
||||
|
||||
dwLeft >>= 4;
|
||||
dwRight >>= 4;
|
||||
}
|
||||
|
||||
cSamples -= cSubSamples;
|
||||
}
|
||||
|
||||
//
|
||||
// Skip padding
|
||||
//
|
||||
|
||||
pbSrc += nBlockAlignment;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
47
src/fmod_codec_wav_imaadpcm.h
Executable file
47
src/fmod_codec_wav_imaadpcm.h
Executable file
|
|
@ -0,0 +1,47 @@
|
|||
#ifndef _FORMAT_IMAADPCM_H
|
||||
#define _FORMAT_IMAADPCM_H
|
||||
|
||||
#include "fmod_settings.h"
|
||||
|
||||
#ifdef FMOD_SUPPORT_IMAADPCM
|
||||
|
||||
#include "fmod_codec_wav.h"
|
||||
|
||||
namespace FMOD
|
||||
{
|
||||
#ifndef WAVE_FORMAT_IMA_ADPCM
|
||||
#define WAVE_FORMAT_IMA_ADPCM 0x0011
|
||||
#endif
|
||||
#ifndef WAVE_FORMAT_XBOX_ADPCM
|
||||
#define WAVE_FORMAT_XBOX_ADPCM 0x0069
|
||||
#endif
|
||||
|
||||
#ifdef FMOD_SUPPORT_PRAGMAPACK
|
||||
#pragma pack(1)
|
||||
#endif
|
||||
|
||||
typedef struct
|
||||
{
|
||||
WAVE_FORMATEX wfx FMOD_PACKED_INTERNAL;
|
||||
unsigned short wSamplesPerBlock FMOD_PACKED_INTERNAL;
|
||||
} FMOD_PACKED WAVE_FORMAT_IMAADPCM;
|
||||
|
||||
#ifdef FMOD_SUPPORT_PRAGMAPACK
|
||||
#ifdef CODEWARRIOR
|
||||
#pragma pack(0)
|
||||
#else
|
||||
#pragma pack()
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
FMOD_RESULT IMAAdpcm_DecodeM16(unsigned char *pbSrc, signed short *pbDst, unsigned int cBlocks, unsigned int nBlockAlignment, unsigned int cSamplesPerBlock, int channels);
|
||||
FMOD_RESULT IMAAdpcm_DecodeS16(unsigned char *pbSrc, signed short *pbDst, unsigned int cBlocks, unsigned int nBlockAlignment, unsigned int cSamplesPerBlock);
|
||||
}
|
||||
|
||||
|
||||
#endif /* FMOD_SUPPORT_IMAADPCM */
|
||||
|
||||
#endif /* _FORMAT_IMAADPCM_H */
|
||||
|
||||
|
||||
337
src/fmod_codec_wav_riff.cpp
Executable file
337
src/fmod_codec_wav_riff.cpp
Executable file
|
|
@ -0,0 +1,337 @@
|
|||
#include "fmod_settings.h"
|
||||
|
||||
#if defined(FMOD_SUPPORT_WAV) || defined(FMOD_SUPPORT_MPEG)
|
||||
|
||||
#include "fmod_codec_wav.h"
|
||||
#include "fmod_file.h"
|
||||
#include "fmod_syncpoint.h"
|
||||
|
||||
namespace FMOD
|
||||
{
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT CodecWav::parseChunk(unsigned int chunksize)
|
||||
{
|
||||
unsigned int offset, fileoffset;
|
||||
FMOD_RESULT result;
|
||||
bool done = false;
|
||||
|
||||
result = mFile->tell(&fileoffset);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
offset = 4;
|
||||
fileoffset -= sizeof(WAVE_CHUNK);
|
||||
|
||||
/*
|
||||
Decode chunks
|
||||
*/
|
||||
do
|
||||
{
|
||||
WAVE_CHUNK chunk;
|
||||
|
||||
result = mFile->seek(fileoffset + sizeof(WAVE_CHUNK), SEEK_SET);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
result = mFile->read(&chunk, 1, sizeof(WAVE_CHUNK), 0);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef PLATFORM_ENDIAN_BIG
|
||||
chunk.size = FMOD_SWAPENDIAN_DWORD(chunk.size);
|
||||
#endif
|
||||
|
||||
FLOG((FMOD_DEBUG_LEVEL_LOG, __FILE__, __LINE__, "CodecWav::parseRIFF","chunk : id %c%c%c%c size %d\n", chunk.id[0],chunk.id[1],chunk.id[2],chunk.id[3], chunk.size));
|
||||
|
||||
/*
|
||||
FORMAT CHUNK
|
||||
*/
|
||||
if (!FMOD_strncmp((const char *)chunk.id, "fmt ", 4))
|
||||
{
|
||||
mSrcFormat = (WAVE_FORMATEXTENSIBLE *)FMOD_Memory_Calloc(chunk.size < sizeof(WAVE_FORMATEXTENSIBLE) ? sizeof(WAVE_FORMATEXTENSIBLE) : chunk.size);
|
||||
if (!mSrcFormat)
|
||||
{
|
||||
return FMOD_ERR_MEMORY;
|
||||
}
|
||||
|
||||
result = mFile->read(mSrcFormat, 1, chunk.size, 0);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef PLATFORM_ENDIAN_BIG
|
||||
mSrcFormat->Format.wFormatTag = FMOD_SWAPENDIAN_WORD(mSrcFormat->Format.wFormatTag);
|
||||
mSrcFormat->Format.nChannels = FMOD_SWAPENDIAN_WORD(mSrcFormat->Format.nChannels);
|
||||
mSrcFormat->Format.nSamplesPerSec = FMOD_SWAPENDIAN_DWORD(mSrcFormat->Format.nSamplesPerSec);
|
||||
mSrcFormat->Format.nAvgBytesPerSec = FMOD_SWAPENDIAN_DWORD(mSrcFormat->Format.nAvgBytesPerSec);
|
||||
mSrcFormat->Format.nBlockAlign = FMOD_SWAPENDIAN_WORD(mSrcFormat->Format.nBlockAlign);
|
||||
mSrcFormat->Format.wBitsPerSample = FMOD_SWAPENDIAN_WORD(mSrcFormat->Format.wBitsPerSample);
|
||||
mSrcFormat->Format.cbSize = FMOD_SWAPENDIAN_WORD(mSrcFormat->Format.cbSize);
|
||||
|
||||
mSrcFormat->Samples.wValidBitsPerSample = FMOD_SWAPENDIAN_WORD(mSrcFormat->Samples.wValidBitsPerSample);
|
||||
mSrcFormat->dwChannelMask = FMOD_SWAPENDIAN_DWORD(mSrcFormat->dwChannelMask);
|
||||
|
||||
if (mSrcFormat->Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE)
|
||||
{
|
||||
mSrcFormat->SubFormat.Data1 = FMOD_SWAPENDIAN_DWORD(mSrcFormat->SubFormat.Data1);
|
||||
mSrcFormat->SubFormat.Data2 = FMOD_SWAPENDIAN_WORD(mSrcFormat->SubFormat.Data2);
|
||||
mSrcFormat->SubFormat.Data3 = FMOD_SWAPENDIAN_WORD(mSrcFormat->SubFormat.Data3);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
CUE CHUNK
|
||||
*/
|
||||
else if (!FMOD_strncmp((const char *)chunk.id, "cue ", 4))
|
||||
{
|
||||
result = mFile->read(&mNumSyncPoints, 4, 1, 0);
|
||||
if (mNumSyncPoints)
|
||||
{
|
||||
int count;
|
||||
|
||||
if (mSyncPoint)
|
||||
{
|
||||
FMOD_Memory_Free(mSyncPoint);
|
||||
}
|
||||
|
||||
mSyncPoint = (SyncPointNamed *)FMOD_Memory_Calloc(mNumSyncPoints * sizeof(SyncPointNamed));
|
||||
if (!mSyncPoint)
|
||||
{
|
||||
return FMOD_ERR_MEMORY;
|
||||
}
|
||||
|
||||
for (count=0; count < mNumSyncPoints; count++)
|
||||
{
|
||||
WAVE_CUEPOINT cue;
|
||||
SyncPointNamed *point = &mSyncPoint[count];
|
||||
|
||||
result = mFile->read(&cue, 1, sizeof(WAVE_CUEPOINT), 0);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
point->mName = point->mNameMemory;
|
||||
|
||||
#ifdef PLATFORM_ENDIAN_BIG
|
||||
cue.dwSampleOffset = FMOD_SWAPENDIAN_DWORD(cue.dwSampleOffset);
|
||||
cue.dwIdentifier = FMOD_SWAPENDIAN_DWORD(cue.dwIdentifier);
|
||||
#endif
|
||||
|
||||
point->mOffset = cue.dwSampleOffset;
|
||||
point->mIndex = cue.dwIdentifier;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
FACT CHUNK
|
||||
*/
|
||||
else if (!FMOD_strncmp((const char *)chunk.id, "fact", 4))
|
||||
{
|
||||
unsigned int fact;
|
||||
|
||||
result = mFile->read(&fact, 4, 1, 0);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
waveformat[0].lengthpcm = fact;
|
||||
}
|
||||
|
||||
/*
|
||||
LIST CHUNK
|
||||
*/
|
||||
else if (!FMOD_strncmp((const char *)chunk.id, "LIST", 4))
|
||||
{
|
||||
char listid[4];
|
||||
|
||||
result = mFile->read(listid, 1, 4, 0);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
result = parseChunk(chunk.size);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
LABL CHUNK
|
||||
*/
|
||||
else if (!FMOD_strncmp((const char *)chunk.id, "labl", 4))
|
||||
{
|
||||
if (mSyncPoint)
|
||||
{
|
||||
int id, count;
|
||||
|
||||
result = mFile->read(&id, 4, 1, 0);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
for (count = 0; count < mNumSyncPoints; count++)
|
||||
{
|
||||
SyncPoint *p = &mSyncPoint[count];
|
||||
|
||||
if (p->mIndex == id)
|
||||
{
|
||||
result = mFile->read(p->mName, 1, chunk.size-4);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
SAMPLER CHUNK
|
||||
*/
|
||||
else if (!FMOD_strncmp((const char *)chunk.id, "smpl", 4))
|
||||
{
|
||||
WAVE_SMPLHEADER smpl;
|
||||
unsigned int rd;
|
||||
|
||||
result = mFile->read(&smpl, 1, sizeof(WAVE_SMPLHEADER), &rd);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (rd == sizeof(WAVE_SMPLHEADER))
|
||||
{
|
||||
#ifdef PLATFORM_ENDIAN_BIG
|
||||
smpl.Manufacturer = FMOD_SWAPENDIAN_DWORD(smpl.Manufacturer);
|
||||
smpl.Product = FMOD_SWAPENDIAN_DWORD(smpl.Product);
|
||||
smpl.SamplePeriod = FMOD_SWAPENDIAN_DWORD(smpl.SamplePeriod);
|
||||
smpl.Note = FMOD_SWAPENDIAN_DWORD(smpl.Note);
|
||||
smpl.FineTune = FMOD_SWAPENDIAN_DWORD(smpl.FineTune);
|
||||
smpl.SMPTEFormat = FMOD_SWAPENDIAN_DWORD(smpl.SMPTEFormat);
|
||||
smpl.SMPTEOffset = FMOD_SWAPENDIAN_DWORD(smpl.SMPTEOffset);
|
||||
smpl.Loops = FMOD_SWAPENDIAN_DWORD(smpl.Loops);
|
||||
smpl.SamplerData = FMOD_SWAPENDIAN_DWORD(smpl.SamplerData);
|
||||
|
||||
smpl.Loop.Identifier = FMOD_SWAPENDIAN_DWORD(smpl.Loop.Identifier);
|
||||
smpl.Loop.Type = FMOD_SWAPENDIAN_DWORD(smpl.Loop.Type);
|
||||
smpl.Loop.Start = FMOD_SWAPENDIAN_DWORD(smpl.Loop.Start);
|
||||
smpl.Loop.End = FMOD_SWAPENDIAN_DWORD(smpl.Loop.End);
|
||||
smpl.Loop.Fraction = FMOD_SWAPENDIAN_DWORD(smpl.Loop.Fraction);
|
||||
smpl.Loop.Count = FMOD_SWAPENDIAN_DWORD(smpl.Loop.Count);
|
||||
#endif
|
||||
|
||||
if (smpl.Loops)
|
||||
{
|
||||
mLoopPoints[0] = smpl.Loop.Start;
|
||||
mLoopPoints[1] = smpl.Loop.End;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
DATA CHUNK
|
||||
*/
|
||||
else if (!FMOD_strncmp((const char *)chunk.id, "data", 4))
|
||||
{
|
||||
if (mSrcDataOffset == (unsigned int)-1)
|
||||
{
|
||||
waveformat[0].lengthbytes = chunk.size;
|
||||
|
||||
result = mFile->tell(&mSrcDataOffset);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (mFile->mFlags & FMOD_FILE_SEEKABLE)
|
||||
{
|
||||
result = mFile->seek(chunk.size, SEEK_CUR);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
done = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mFile->seek(chunk.size, SEEK_CUR);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
offset += (chunk.size+sizeof(WAVE_CHUNK));
|
||||
fileoffset += (chunk.size+sizeof(WAVE_CHUNK));
|
||||
|
||||
if (chunk.size & 1)
|
||||
{
|
||||
offset++;
|
||||
fileoffset++;
|
||||
}
|
||||
|
||||
if (chunk.size < 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
FLOG((FMOD_DEBUG_LEVEL_LOG, __FILE__, __LINE__, "CodecWav::parseRIFF", "offset = %d / %d\n", offset, chunksize));
|
||||
|
||||
} while (offset < chunksize && offset > 0 && !done);
|
||||
|
||||
|
||||
/*
|
||||
There is a data chunk, but we had a truncated wav.. we will still load what's there.
|
||||
*/
|
||||
if (result == FMOD_ERR_FILE_EOF)
|
||||
{
|
||||
result = FMOD_OK;
|
||||
}
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
3962
src/fmod_codec_xm.cpp
Executable file
3962
src/fmod_codec_xm.cpp
Executable file
File diff suppressed because it is too large
Load diff
172
src/fmod_codec_xm.h
Executable file
172
src/fmod_codec_xm.h
Executable file
|
|
@ -0,0 +1,172 @@
|
|||
#ifndef _FMOD_CODEC_XM_H
|
||||
#define _FMOD_CODEC_XM_H
|
||||
|
||||
#include "fmod_settings.h"
|
||||
|
||||
#ifdef FMOD_SUPPORT_XM
|
||||
|
||||
#include "fmod_music.h"
|
||||
|
||||
namespace FMOD
|
||||
{
|
||||
class DSPI;
|
||||
class ChannelPool;
|
||||
|
||||
enum FMUSIC_XMCOMMANDS
|
||||
{
|
||||
FMUSIC_XM_ARPEGGIO,
|
||||
FMUSIC_XM_PORTAUP,
|
||||
FMUSIC_XM_PORTADOWN,
|
||||
FMUSIC_XM_PORTATO,
|
||||
FMUSIC_XM_VIBRATO,
|
||||
FMUSIC_XM_PORTATOVOLSLIDE,
|
||||
FMUSIC_XM_VIBRATOVOLSLIDE,
|
||||
FMUSIC_XM_TREMOLO,
|
||||
FMUSIC_XM_SETPANPOSITION,
|
||||
FMUSIC_XM_SETSAMPLEOFFSET,
|
||||
FMUSIC_XM_VOLUMESLIDE,
|
||||
FMUSIC_XM_PATTERNJUMP,
|
||||
FMUSIC_XM_SETVOLUME,
|
||||
FMUSIC_XM_PATTERNBREAK,
|
||||
FMUSIC_XM_SPECIAL,
|
||||
FMUSIC_XM_SETSPEED,
|
||||
FMUSIC_XM_SETGLOBALVOLUME,
|
||||
FMUSIC_XM_GLOBALVOLSLIDE,
|
||||
FMUSIC_XM_I,
|
||||
FMUSIC_XM_J,
|
||||
FMUSIC_XM_KEYOFF,
|
||||
FMUSIC_XM_SETENVELOPEPOS,
|
||||
FMUSIC_XM_M,
|
||||
FMUSIC_XM_N,
|
||||
FMUSIC_XM_O,
|
||||
FMUSIC_XM_PANSLIDE,
|
||||
FMUSIC_XM_Q,
|
||||
FMUSIC_XM_MULTIRETRIG,
|
||||
FMUSIC_XM_S,
|
||||
FMUSIC_XM_TREMOR,
|
||||
FMUSIC_XM_U,
|
||||
FMUSIC_XM_V,
|
||||
FMUSIC_XM_W,
|
||||
FMUSIC_XM_EXTRAFINEPORTA,
|
||||
FMUSIC_XM_Y,
|
||||
FMUSIC_XM_Z
|
||||
};
|
||||
|
||||
|
||||
enum FMUSIC_XMCOMMANDSSPECIAL
|
||||
{
|
||||
FMUSIC_XM_SETFILTER,
|
||||
FMUSIC_XM_FINEPORTAUP,
|
||||
FMUSIC_XM_FINEPORTADOWN,
|
||||
FMUSIC_XM_SETGLISSANDO,
|
||||
FMUSIC_XM_SETVIBRATOWAVE,
|
||||
FMUSIC_XM_SETFINETUNE,
|
||||
FMUSIC_XM_PATTERNLOOP,
|
||||
FMUSIC_XM_SETTREMOLOWAVE,
|
||||
FMUSIC_XM_SETPANPOSITION16,
|
||||
FMUSIC_XM_RETRIG,
|
||||
FMUSIC_XM_FINEVOLUMESLIDEUP,
|
||||
FMUSIC_XM_FINEVOLUMESLIDEDOWN,
|
||||
FMUSIC_XM_NOTECUT,
|
||||
FMUSIC_XM_NOTEDELAY,
|
||||
FMUSIC_XM_PATTERNDELAY,
|
||||
FMUSIC_XM_FUNKREPEAT
|
||||
};
|
||||
|
||||
#define FMUSIC_XMFLAGS_LINEARFREQUENCY 1
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned int instSize; /* instrument size */
|
||||
signed char instName[22]; /* instrument filename */
|
||||
unsigned char instType; /* instrument type (now 0) */
|
||||
unsigned short numSamples; /* number of samples in instrument */
|
||||
} FMUSIC_XM_INSTHEADER;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned int headerSize; /* sample header size */
|
||||
unsigned char noteSmpNums[96]; /* sample numbers for notes */
|
||||
unsigned short volEnvelope[2*12]; /* volume envelope points */
|
||||
unsigned short panEnvelope[2*12]; /* panning envelope points */
|
||||
unsigned char numVolPoints; /* number of volume envelope points */
|
||||
unsigned char numPanPoints; /* number of panning env. points */
|
||||
unsigned char volSustain; /* volume sustain point */
|
||||
unsigned char volLoopStart; /* volume loop start point */
|
||||
unsigned char volLoopEnd; /* volume loop end point */
|
||||
unsigned char panSustain; /* panning sustain point */
|
||||
unsigned char panLoopStart; /* panning loop start point */
|
||||
unsigned char panLoopEnd; /* panning loop end point */
|
||||
unsigned char volEnvFlags; /* volume envelope flags */
|
||||
unsigned char panEnvFlags; /* panning envelope flags */
|
||||
|
||||
unsigned char vibType; /* vibrato type */
|
||||
unsigned char vibSweep; /* vibrato sweep */
|
||||
unsigned char vibDepth; /* vibrato depth */
|
||||
unsigned char vibRate; /* vibrato rate */
|
||||
unsigned short volFadeout; /* volume fadeout */
|
||||
unsigned short reserved;
|
||||
} FMUSIC_XM_INSTSAMPLEHEADER;
|
||||
|
||||
const int XM_MAXROWS = 256;
|
||||
const int XM_MAXSAMPLES = 256;
|
||||
|
||||
class MusicChannelXM : public MusicChannel
|
||||
{
|
||||
public:
|
||||
FMOD_RESULT volumeSlide();
|
||||
FMOD_RESULT portamento();
|
||||
FMOD_RESULT vibrato();
|
||||
FMOD_RESULT tremolo();
|
||||
FMOD_RESULT fineVibrato();
|
||||
FMOD_RESULT processVolumeByte(unsigned char volume);
|
||||
FMOD_RESULT instrumentVibrato(MusicInstrument *iptr);
|
||||
};
|
||||
|
||||
class CodecXM : public MusicSong
|
||||
{
|
||||
private:
|
||||
|
||||
MusicSample **mSample;
|
||||
ChannelPool *mChannelPoolMemory; /* ChannelPool */
|
||||
|
||||
FMOD_RESULT calculateLength();
|
||||
|
||||
FMOD_RESULT updateNote(bool audible);
|
||||
FMOD_RESULT updateEffects();
|
||||
FMOD_RESULT update(bool audible);
|
||||
|
||||
FMOD_RESULT spawnNewChannel(MusicChannel *cptr, MusicVirtualChannel *oldvcptr, MusicSample *sptr, MusicVirtualChannel **newvcptr);
|
||||
FMOD_RESULT processEnvelope(MusicEnvelopeState *env, MusicVirtualChannel *vcptr, int Inumpoints, unsigned short *points, int type, int loopstart, int loopend, unsigned char ISustain, unsigned char control);
|
||||
FMOD_RESULT getAmigaPeriod(int note, int finetune, int *period);
|
||||
FMOD_RESULT processNote(MusicNote *current, MusicChannelXM *cptr, MusicVirtualChannel *vcptr, MusicInstrument *iptr, MusicSample *sptr);
|
||||
FMOD_RESULT updateFlags(MusicChannel *cptr, MusicVirtualChannel *vcptr, MusicSample *sptr);
|
||||
|
||||
#ifdef FMOD_SUPPORT_VAG
|
||||
void EncodeVAG_FindPredict( short *samples, float *d_samples, int *predict_nr, int *shift_factor );
|
||||
static void EncodeVAG_pack( float *d_samples, short *four_bit, int predict_nr, int shift_factor );
|
||||
int EncodeVAG_pcm2vag(unsigned char *vag, short *wave, int sample_len, int wavebits);
|
||||
#endif
|
||||
|
||||
FMOD_RESULT openInternal(FMOD_MODE usermode, FMOD_CREATESOUNDEXINFO *userexinfo);
|
||||
FMOD_RESULT closeInternal();
|
||||
FMOD_RESULT readInternal(void *buffer, unsigned int size, unsigned int *read);
|
||||
FMOD_RESULT setPositionInternal(int subsound, unsigned int position, FMOD_TIMEUNIT postype);
|
||||
|
||||
public:
|
||||
|
||||
static FMOD_CODEC_DESCRIPTION_EX *getDescriptionEx();
|
||||
|
||||
static FMOD_RESULT F_CALLBACK openCallback(FMOD_CODEC_STATE *codec, FMOD_MODE usermode, FMOD_CREATESOUNDEXINFO *userexinfo);
|
||||
static FMOD_RESULT F_CALLBACK closeCallback(FMOD_CODEC_STATE *codec);
|
||||
static FMOD_RESULT F_CALLBACK readCallback(FMOD_CODEC_STATE *codec, void *buffer, unsigned int sizebytes, unsigned int *bytesread);
|
||||
static FMOD_RESULT F_CALLBACK setPositionCallback(FMOD_CODEC_STATE *codec, int subsound, unsigned int position, FMOD_TIMEUNIT postype);
|
||||
static FMOD_RESULT F_CALLBACK updateCallback(FMOD_CODEC_STATE *codec);
|
||||
};
|
||||
}
|
||||
|
||||
#endif /* FMOD_SUPPORT_XM */
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
216
src/fmod_codeci.h
Executable file
216
src/fmod_codeci.h
Executable file
|
|
@ -0,0 +1,216 @@
|
|||
#ifndef _FMOD_CODECI_H
|
||||
#define _FMOD_CODECI_H
|
||||
|
||||
#include "fmod_settings.h"
|
||||
|
||||
#include "fmod.h"
|
||||
#include "fmod_debug.h"
|
||||
#include "fmod_file.h"
|
||||
#include "fmod_file_memory.h"
|
||||
#include "fmod_memory.h"
|
||||
#include "fmod_os_misc.h"
|
||||
#include "fmod_plugin.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
namespace FMOD
|
||||
{
|
||||
class Metadata;
|
||||
class ChannelReal;
|
||||
class MemoryTracker;
|
||||
|
||||
typedef FMOD_RESULT (F_CALLBACK *FMOD_CODEC_INITCALLBACK) (FMOD_CODEC_STATE *codec, int numstreams);
|
||||
typedef FMOD_RESULT (F_CALLBACK *FMOD_CODEC_RESETCALLBACK)(FMOD_CODEC_STATE *codec);
|
||||
typedef FMOD_RESULT (F_CALLBACK *FMOD_CODEC_CANPOINTCALLBACK)(FMOD_CODEC_STATE *codec);
|
||||
typedef FMOD_RESULT (F_CALLBACK *FMOD_CODEC_GETMUSICNUMCHANNELS)(FMOD_CODEC_STATE *codec, int *numchannels);
|
||||
typedef FMOD_RESULT (F_CALLBACK *FMOD_CODEC_SETMUSICCHANNELVOLUME)(FMOD_CODEC_STATE *codec, int channel, float volume);
|
||||
typedef FMOD_RESULT (F_CALLBACK *FMOD_CODEC_GETMUSICCHANNELVOLUME)(FMOD_CODEC_STATE *codec, int channel, float *volume);
|
||||
typedef FMOD_RESULT (F_CALLBACK *FMOD_CODEC_GETHARDWAREMUSICHANNEL)(FMOD_CODEC_STATE *codec, ChannelReal **realchannel);
|
||||
typedef FMOD_RESULT (F_CALLBACK *FMOD_CODEC_UPDATE)(FMOD_CODEC_STATE *codec);
|
||||
typedef FMOD_RESULT (F_CALLBACK *FMOD_CODEC_GETMEMORYUSED)(FMOD_CODEC_STATE *codec, MemoryTracker *tracker);
|
||||
|
||||
struct FMOD_CODEC_DESCRIPTION_EX : public FMOD_CODEC_DESCRIPTION, public SortedLinkedListNode
|
||||
{
|
||||
FMOD_SOUND_TYPE mType;
|
||||
int mSize;
|
||||
FMOD_OS_LIBRARY *mModule;
|
||||
unsigned int mHandle;
|
||||
|
||||
FMOD_CODEC_INITCALLBACK init;
|
||||
FMOD_CODEC_RESETCALLBACK reset;
|
||||
FMOD_CODEC_CANPOINTCALLBACK canpoint;
|
||||
FMOD_CODEC_GETMUSICNUMCHANNELS getmusicnumchannels;
|
||||
FMOD_CODEC_SETMUSICCHANNELVOLUME setmusicchannelvolume;
|
||||
FMOD_CODEC_GETMUSICCHANNELVOLUME getmusicchannelvolume;
|
||||
FMOD_CODEC_GETHARDWAREMUSICHANNEL gethardwaremusicchannel;
|
||||
FMOD_CODEC_UPDATE update;
|
||||
FMOD_CODEC_GETMEMORYUSED getmemoryused;
|
||||
};
|
||||
|
||||
|
||||
typedef unsigned int FMOD_CODEC_FLAG;
|
||||
|
||||
#define FMOD_CODEC_ACCURATELENGTH 0x00000001
|
||||
#define FMOD_CODEC_FROMFSB 0x00000002
|
||||
#define FMOD_CODEC_SEEKING 0x00000004
|
||||
#define FMOD_CODEC_PADDED 0x00000008
|
||||
#define FMOD_CODEC_USERLENGTH 0x00000010
|
||||
#define FMOD_CODEC_HARDWAREMUSICVOICES 0x00000020
|
||||
#define FMOD_CODEC_FSBXMAMIXEDCHANNELS 0x00000040
|
||||
#define FMOD_CODEC_PADDED4 0x00000080
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned int offset;
|
||||
char name[256];
|
||||
} SYNCDATA;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned int offset;
|
||||
} SYNCDATA_NONAME;
|
||||
|
||||
class ChannelReal;
|
||||
|
||||
class Codec : public Plugin, public FMOD_CODEC_STATE
|
||||
{
|
||||
DECLARE_MEMORYTRACKER_NONVIRTUAL /* Codecs are plugins and go through mDescription callback interface. */
|
||||
|
||||
public:
|
||||
|
||||
FMOD_CODEC_WAVEFORMAT *mWaveFormatMemory; /* NULL for FMOD_CREATECOMPRESSED codecs (they point to the sound's wave format), but alloced for each sound codec. */
|
||||
|
||||
FMOD_SOUND_TYPE mType;
|
||||
FMOD_CODEC_DESCRIPTION_EX mDescription;
|
||||
unsigned int mSrcDataOffset;
|
||||
unsigned int mLoopPoints[2];
|
||||
int mSubSoundIndex;
|
||||
FMOD_CODEC_FLAG mFlags;
|
||||
unsigned int mBlockAlign;
|
||||
|
||||
/*
|
||||
Temporary buffer for reading compressed data into. Not used on all codecs.
|
||||
*/
|
||||
unsigned char *mReadBuffer; /* For reading one block worth of compressed data into */
|
||||
unsigned int mReadBufferLength;
|
||||
|
||||
/*
|
||||
Buffer Logic for decompressing chunks of data into a temporary PCM buffer;
|
||||
*/
|
||||
unsigned char *mPCMBuffer; /* For decompressing that one block of data into */
|
||||
unsigned char *mPCMBufferMemory;
|
||||
unsigned int mPCMBufferLength;
|
||||
unsigned int mPCMBufferLengthBytes;
|
||||
unsigned int mPCMBufferOffsetBytes;
|
||||
unsigned int mPCMBufferFilledBytes;
|
||||
|
||||
/*
|
||||
Stuff that is passed into the driver for internal use
|
||||
*/
|
||||
FMOD_MODE mMode; /* This mode may have been changed by createSound */
|
||||
FMOD_MODE mOriginalMode; /* Original mode as passed in to createSound by user */
|
||||
Metadata *mMetadata;
|
||||
File *mFile;
|
||||
bool mNonInterleaved;
|
||||
|
||||
#ifdef FMOD_SUPPORT_XMA
|
||||
bool mXMASeekable;
|
||||
#endif
|
||||
|
||||
static FMOD_INLINE FMOD_RESULT F_CALLBACK defaultFileRead (void *handle, void *buffer, unsigned int size, unsigned int *read, void *userdata) { return ((File *)handle)->read(buffer, 1, size, read); }
|
||||
static FMOD_INLINE FMOD_RESULT F_CALLBACK defaultFileSeek (void *handle, unsigned int pos, void *userdata) { return ((File *)handle)->seek(pos, SEEK_SET); }
|
||||
#ifndef PLATFORM_PS3_SPU
|
||||
static FMOD_INLINE FMOD_RESULT F_CALLBACK defaultMetaData (FMOD_CODEC_STATE *codec, FMOD_TAGTYPE type, char *name, void *data, unsigned int datalen, FMOD_TAGDATATYPE datatype, int unique) { return ((Codec *)codec)->metaData(type, name, data, datalen, datatype, unique == 1 ? true : false); }
|
||||
#endif
|
||||
static FMOD_INLINE FMOD_RESULT F_CALLBACK defaultGetWaveFormat(FMOD_CODEC_STATE *codec, int index, FMOD_CODEC_WAVEFORMAT *waveformat_out)
|
||||
{
|
||||
if (!codec->waveformat)
|
||||
{
|
||||
return FMOD_ERR_INTERNAL;
|
||||
}
|
||||
|
||||
if (index < 0 || (codec->numsubsounds == 0 && index > 0) || (codec->numsubsounds > 0 && index >= codec->numsubsounds))
|
||||
{
|
||||
return FMOD_ERR_INVALID_PARAM;
|
||||
}
|
||||
|
||||
FMOD_memcpy(waveformat_out, &codec->waveformat[index], sizeof(FMOD_CODEC_WAVEFORMAT));
|
||||
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
Codec()
|
||||
{
|
||||
mType = FMOD_SOUND_TYPE_UNKNOWN;
|
||||
mMetadata = 0;
|
||||
fileread = &defaultFileRead;
|
||||
fileseek = &defaultFileSeek;
|
||||
#ifndef PLATFORM_PS3_SPU
|
||||
metadata = &defaultMetaData;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef PLATFORM_PS3_SPU
|
||||
FMOD_RESULT init(FMOD_SOUND_TYPE type)
|
||||
{
|
||||
Plugin::init();
|
||||
|
||||
mType = type;
|
||||
mMetadata = 0;
|
||||
numsubsounds = 0;
|
||||
waveformat = 0;
|
||||
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
||||
FMOD_RESULT release();
|
||||
FMOD_RESULT getLength(unsigned int *length, FMOD_TIMEUNIT lengthtype);
|
||||
FMOD_RESULT getPosition(unsigned int *position, FMOD_TIMEUNIT postype);
|
||||
FMOD_RESULT metaData(FMOD_TAGTYPE type, const char *name, void *data, unsigned int datalen, FMOD_TAGDATATYPE datatype, bool unique);
|
||||
FMOD_RESULT getMetadataFromFile();
|
||||
FMOD_RESULT canPointTo()
|
||||
{
|
||||
if (mDescription.canpoint)
|
||||
{
|
||||
return mDescription.canpoint(this);
|
||||
}
|
||||
else
|
||||
{
|
||||
return FMOD_ERR_MEMORY_CANTPOINT;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
FMOD_RESULT reset()
|
||||
{
|
||||
mPCMBufferOffsetBytes = 0;
|
||||
if (mPCMBuffer)
|
||||
{
|
||||
FMOD_memset(mPCMBuffer, 0, mPCMBufferLengthBytes);
|
||||
}
|
||||
if (mDescription.reset)
|
||||
{
|
||||
return mDescription.reset(this);
|
||||
}
|
||||
return FMOD_OK;
|
||||
}
|
||||
FMOD_RESULT read(void *buffer, unsigned int size, unsigned int *bytesread);
|
||||
FMOD_RESULT setPosition(int subsound, unsigned int position, FMOD_TIMEUNIT postype);
|
||||
FMOD_RESULT getHardwareMusicChannel(ChannelReal **realchannel)
|
||||
{
|
||||
if (mDescription.gethardwaremusicchannel)
|
||||
{
|
||||
return mDescription.gethardwaremusicchannel(this, realchannel);
|
||||
}
|
||||
else
|
||||
{
|
||||
return FMOD_ERR_INVALID_HANDLE;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
397
src/fmod_debug.cpp
Executable file
397
src/fmod_debug.cpp
Executable file
|
|
@ -0,0 +1,397 @@
|
|||
#include "fmod_settings.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "fmod.h"
|
||||
#include "fmod_debug.h"
|
||||
#include "fmod_globals.h"
|
||||
#include "fmod_os_misc.h"
|
||||
#include "fmod_time.h"
|
||||
#include "fmod_string.h"
|
||||
#include "fmod_systemi.h"
|
||||
|
||||
extern "C"
|
||||
{
|
||||
|
||||
/*
|
||||
[API]
|
||||
[
|
||||
[DESCRIPTION]
|
||||
Sets the level of debug logging to the tty / output for logging versions of FMOD Ex.
|
||||
|
||||
[PARAMETERS]
|
||||
'level' Logging level to set.
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
This only has an effect with 'logging' versions of FMOD Ex. For example on windows it must be via fmodexL.dll, not fmodex.dll.<br>
|
||||
On Xbox it would be fmodxboxL.lib not fmodxbox.lib.<br>
|
||||
FMOD_ERR_UNSUPPORTED will be returned on non logging versions of FMOD Ex (ie full release).<br>
|
||||
|
||||
[PLATFORMS]
|
||||
Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation 2, PlayStation Portable, PlayStation 3, Wii, Solaris, iPhone
|
||||
|
||||
[SEE_ALSO]
|
||||
Debug_GetLevel
|
||||
FMOD_DEBUGLEVEL
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT F_API FMOD_Debug_SetLevel(FMOD_DEBUGLEVEL level)
|
||||
{
|
||||
#ifdef FMOD_DEBUG
|
||||
if (!FMOD::gGlobal)
|
||||
{
|
||||
#if !defined(FMOD_STATICFORPLUGINS) && !defined(PLATFORM_PS2_IOP)
|
||||
FMOD::SystemI::getGlobals(&FMOD::gGlobal);
|
||||
#else
|
||||
return FMOD_ERR_UNINITIALIZED;
|
||||
#endif
|
||||
}
|
||||
FMOD::gGlobal->gDebugLevel = (FMOD_DEBUGLEVEL)level;
|
||||
return FMOD_OK;
|
||||
#else
|
||||
return FMOD_ERR_UNSUPPORTED;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
[API]
|
||||
[
|
||||
[DESCRIPTION]
|
||||
Retrieves the current debug logging level.
|
||||
|
||||
[PARAMETERS]
|
||||
'level' Address of a variable to receieve current debug level.
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
This only has an effect with 'logging' versions of FMOD Ex. For example on windows it must be via fmodexL.dll, not fmodex.dll.<br>
|
||||
On Xbox it would be fmodxboxL.lib not fmodxbox.lib.<br>
|
||||
FMOD_ERR_UNSUPPORTED will be returned on non logging versions of FMOD Ex (ie full release).<br>
|
||||
|
||||
[PLATFORMS]
|
||||
Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation 2, PlayStation Portable, PlayStation 3, Wii, Solaris, iPhone
|
||||
|
||||
[SEE_ALSO]
|
||||
Debug_SetLevel
|
||||
FMOD_DEBUGLEVEL
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT F_API FMOD_Debug_GetLevel(FMOD_DEBUGLEVEL *level)
|
||||
{
|
||||
if (!level)
|
||||
{
|
||||
return FMOD_ERR_INVALID_PARAM;
|
||||
}
|
||||
#ifdef FMOD_DEBUG
|
||||
*level = FMOD::gGlobal->gDebugLevel;
|
||||
return FMOD_OK;
|
||||
#else
|
||||
*level = 0;
|
||||
return FMOD_ERR_UNSUPPORTED;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
'mode' Bitfield containing debug settings.
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation 2, PlayStation Portable, PlayStation 3, Wii, Solaris, iPhone
|
||||
|
||||
[SEE_ALSO]
|
||||
Debug_GetMode
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT F_API FMOD_Debug_SetMode(unsigned int mode)
|
||||
{
|
||||
#ifdef FMOD_DEBUG
|
||||
if (!FMOD::gGlobal)
|
||||
{
|
||||
return FMOD_ERR_UNINITIALIZED;
|
||||
}
|
||||
FMOD::gGlobal->gDebugMode = (FMOD::FMOD_DEBUGMODE)mode;
|
||||
#endif
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
'mode' Bitfield containing debug settings.
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation 2, PlayStation Portable, PlayStation 3, Wii, Solaris, iPhone
|
||||
|
||||
[SEE_ALSO]
|
||||
Debug_SetMode
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT F_API FMOD_Debug_GetMode(unsigned int *mode)
|
||||
{
|
||||
if (!mode)
|
||||
{
|
||||
return FMOD_ERR_INVALID_PARAM;
|
||||
}
|
||||
#ifdef FMOD_DEBUG
|
||||
*mode = (unsigned int )FMOD::gGlobal->gDebugMode;
|
||||
#endif
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
#ifdef FMOD_DEBUG
|
||||
|
||||
namespace FMOD
|
||||
{
|
||||
|
||||
static int gDebugMemory = 0;
|
||||
int *gDebugIndent = &gDebugMemory;
|
||||
|
||||
|
||||
#ifndef PLATFORM_PS2_IOP
|
||||
|
||||
#ifdef PLATFORM_PS2_EE
|
||||
|
||||
#include <eekernel.h>
|
||||
#include <sifdev.h>
|
||||
|
||||
void DebugFile(const char *s)
|
||||
{
|
||||
static int debugFP = -666;
|
||||
static bool debugfirsttime = true;
|
||||
|
||||
if (debugfirsttime)
|
||||
{
|
||||
debugFP = sceOpen(FMOD::gGlobal->gDebugFilename, SCE_CREAT | SCE_RDWR);
|
||||
debugfirsttime = false;
|
||||
}
|
||||
|
||||
if (debugFP >= 0)
|
||||
{
|
||||
sceWrite(debugFP, s, FMOD_strlen(s));
|
||||
}
|
||||
else
|
||||
{
|
||||
char s[256];
|
||||
|
||||
sprintf(s, "ERROR - failed to open %s! (result = %d)\n", FMOD::gGlobal->gDebugFilename, debugFP);
|
||||
FMOD_OS_Debug_OutputStr(s);
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
void DebugFile(const char *s)
|
||||
{
|
||||
FILE *debugFP;
|
||||
const char *openstr = "atc";
|
||||
static bool debugfirstfime = true;
|
||||
|
||||
if (debugfirstfime)
|
||||
{
|
||||
debugfirstfime = false;
|
||||
openstr = "wt";
|
||||
}
|
||||
|
||||
debugFP = fopen(FMOD::gGlobal->gDebugFilename, openstr);
|
||||
if (debugFP)
|
||||
{
|
||||
fputs(s, debugFP);
|
||||
fflush(debugFP);
|
||||
fclose(debugFP);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
void Debug(FMOD_DEBUGLEVEL type, const char *file, const int line, const char *fnname, const char *format, ...)
|
||||
{
|
||||
va_list arglist;
|
||||
unsigned int now;
|
||||
static unsigned int oldtime = 0;
|
||||
const int BUFFER_SIZE = 256;
|
||||
const int INDENT_SIZE = 64;
|
||||
char s[BUFFER_SIZE], tmp[BUFFER_SIZE], indent[INDENT_SIZE];
|
||||
|
||||
if (!(type & FMOD::gGlobal->gDebugLevel))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
Filter out users if one is specified.
|
||||
*/
|
||||
if (FMOD::gGlobal->gDebugLevel & FMOD_DEBUG_USER_ALL && type & FMOD_DEBUG_USER_ALL)
|
||||
{
|
||||
if (!((type & FMOD_DEBUG_USER_ALL) & (FMOD::gGlobal->gDebugLevel & FMOD_DEBUG_USER_ALL)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
FMOD_OS_Time_GetMs(&now);
|
||||
if (oldtime == 0)
|
||||
{
|
||||
oldtime = now;
|
||||
}
|
||||
|
||||
va_start(arglist, format);
|
||||
|
||||
FMOD_vsnprintf(s, BUFFER_SIZE, format, arglist);
|
||||
|
||||
FMOD_snprintf(indent, INDENT_SIZE, "%*s", *gDebugIndent, "");
|
||||
|
||||
if (FMOD::gGlobal->gDebugLevel & FMOD_DEBUG_DISPLAY_LINENUMBERS)
|
||||
{
|
||||
char tmp2[BUFFER_SIZE];
|
||||
|
||||
FMOD_snprintf(tmp, BUFFER_SIZE, "%s(%d)", file, line);
|
||||
|
||||
#ifdef PLATFORM_PS2
|
||||
#define LEADINGSPACES 40
|
||||
#else
|
||||
#define LEADINGSPACES 60
|
||||
#endif
|
||||
|
||||
if (FMOD_strlen(tmp) < LEADINGSPACES)
|
||||
{
|
||||
FMOD_strncat(tmp, " ", LEADINGSPACES - FMOD_strlen(tmp));
|
||||
}
|
||||
|
||||
if (FMOD::gGlobal->gDebugLevel & FMOD_DEBUG_DISPLAY_TIMESTAMPS)
|
||||
{
|
||||
if (FMOD::gGlobal->gDebugLevel & FMOD_DEBUG_DISPLAY_THREAD)
|
||||
{
|
||||
FMOD_UINT_NATIVE id;
|
||||
FMOD_OS_Thread_GetCurrentID(&id),
|
||||
FMOD_snprintf(tmp2, BUFFER_SIZE, ": [THREADID %d] [%8d ms delta = %4d] %-30s : %s%s", id, now, now - oldtime, fnname, indent, s);
|
||||
}
|
||||
else
|
||||
{
|
||||
FMOD_snprintf(tmp2, BUFFER_SIZE, ": [%8d ms delta = %4d] %-30s : %s%s", now, now - oldtime, fnname, indent, s);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (FMOD::gGlobal->gDebugLevel & FMOD_DEBUG_DISPLAY_THREAD)
|
||||
{
|
||||
FMOD_UINT_NATIVE id;
|
||||
FMOD_OS_Thread_GetCurrentID(&id),
|
||||
FMOD_snprintf(tmp2, BUFFER_SIZE, ": [THREADID %d] %-30s : %s%s", id, fnname, indent, s);
|
||||
}
|
||||
else
|
||||
{
|
||||
FMOD_snprintf(tmp2, BUFFER_SIZE, ": %-30s : %s%s", fnname, indent, s);
|
||||
}
|
||||
}
|
||||
|
||||
FMOD_strncat(tmp, tmp2, BUFFER_SIZE - FMOD_strlen(tmp) - 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (FMOD::gGlobal->gDebugLevel & FMOD_DEBUG_DISPLAY_TIMESTAMPS)
|
||||
{
|
||||
if (FMOD::gGlobal->gDebugLevel & FMOD_DEBUG_DISPLAY_THREAD)
|
||||
{
|
||||
FMOD_UINT_NATIVE id;
|
||||
FMOD_OS_Thread_GetCurrentID(&id),
|
||||
FMOD_snprintf(tmp, BUFFER_SIZE, "FMOD: [THREADID %d] [%8d ms delta = %4d] %-30s : %s%s", id, now, now - oldtime, fnname, indent, s);
|
||||
}
|
||||
else
|
||||
{
|
||||
FMOD_snprintf(tmp, BUFFER_SIZE, "FMOD: [%8d ms delta = %4d] %-30s : %s%s", now, now - oldtime, fnname, indent, s);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (FMOD::gGlobal->gDebugLevel & FMOD_DEBUG_DISPLAY_THREAD)
|
||||
{
|
||||
FMOD_UINT_NATIVE id;
|
||||
FMOD_OS_Thread_GetCurrentID(&id),
|
||||
FMOD_snprintf(tmp, BUFFER_SIZE, "FMOD: [THREADID %d] %-30s : %s%s", id, fnname, indent, s);
|
||||
}
|
||||
else
|
||||
{
|
||||
FMOD_snprintf(tmp, BUFFER_SIZE, "FMOD: %-30s : %s%s", fnname, indent, s);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (FMOD::gGlobal->gDebugLevel & FMOD_DEBUG_DISPLAY_COMPRESS)
|
||||
{
|
||||
static char lastmessage[BUFFER_SIZE] = "";
|
||||
static char lasts[BUFFER_SIZE] = "";
|
||||
static int numrepeats = 0;
|
||||
|
||||
if (!FMOD_strcmp(lasts, s) && (numrepeats < 100))
|
||||
{
|
||||
numrepeats++;
|
||||
if (numrepeats > 5)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (numrepeats > 5)
|
||||
{
|
||||
char p[64];
|
||||
FMOD_snprintf(p, 64, "FMOD: Last message repeated %d times\n", numrepeats);
|
||||
#ifndef PLATFORM_PS2_IOP
|
||||
if (FMOD::gGlobal->gDebugMode == DEBUG_FILE)
|
||||
{
|
||||
DebugFile(p);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
FMOD_OS_Debug_OutputStr(p);
|
||||
}
|
||||
}
|
||||
|
||||
FMOD_strcpy(lasts, s);
|
||||
FMOD_strcpy(lastmessage, tmp);
|
||||
numrepeats = 0;
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef PLATFORM_PS2_IOP
|
||||
if (FMOD::gGlobal->gDebugMode == DEBUG_FILE)
|
||||
{
|
||||
DebugFile(tmp);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
FMOD_OS_Debug_OutputStr(tmp);
|
||||
}
|
||||
|
||||
va_end( arglist );
|
||||
|
||||
oldtime = now;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
42
src/fmod_debug.h
Executable file
42
src/fmod_debug.h
Executable file
|
|
@ -0,0 +1,42 @@
|
|||
#ifndef _FMOD_DEBUG_H
|
||||
#define _FMOD_DEBUG_H
|
||||
|
||||
#include "fmod_settings.h"
|
||||
|
||||
#ifdef FMOD_DEBUG
|
||||
|
||||
#include "fmod.h"
|
||||
|
||||
namespace FMOD
|
||||
{
|
||||
typedef enum
|
||||
{
|
||||
DEBUG_STDOUT,
|
||||
DEBUG_FILE
|
||||
} FMOD_DEBUGMODE;
|
||||
|
||||
#define FMOD_DEBUG_USER_BRETT 0x10000000
|
||||
#define FMOD_DEBUG_USER_ANDREW 0x20000000
|
||||
#define FMOD_DEBUG_USER_CHENPO 0x40000000
|
||||
#define FMOD_DEBUG_USER_PETER 0x80000000
|
||||
#define FMOD_DEBUG_USER_ALL 0xF0000000
|
||||
|
||||
void Debug(FMOD_DEBUGLEVEL level, const char *file, const int line, const char *fnname, const char *format, ...);
|
||||
|
||||
extern int *gDebugIndent;
|
||||
|
||||
#define FLOG(_x) Debug _x
|
||||
#define FLOGC(_x) FMOD::Debug _x
|
||||
#define FLOG_INDENT(_x) (*gDebugIndent) += (_x)
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#define FLOG(_x) ;
|
||||
#define FLOGC(_x) ;
|
||||
#define FLOG_INDENT(_x) ;
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
49
src/fmod_downmix.h
Executable file
49
src/fmod_downmix.h
Executable file
|
|
@ -0,0 +1,49 @@
|
|||
#ifndef _FMOD_DOWNMIX_H
|
||||
#define _FMOD_DOWNMIX_H
|
||||
|
||||
#include "fmod_settings.h"
|
||||
|
||||
#include "fmod.h"
|
||||
|
||||
namespace FMOD
|
||||
{
|
||||
class Downmix
|
||||
{
|
||||
public:
|
||||
virtual FMOD_RESULT init (unsigned int dspbuffersize, unsigned int rate, FMOD_SPEAKERMODE outputspeakermode, void *extradata = 0) = 0;
|
||||
virtual FMOD_RESULT shutdown () { return FMOD_OK; }
|
||||
virtual FMOD_RESULT encode (float *inbuffer, float *outbuffer, unsigned int numsamples) = 0;
|
||||
|
||||
FMOD_RESULT getOutputChannels (int *outputchannels)
|
||||
{
|
||||
if (outputchannels)
|
||||
{
|
||||
*outputchannels = mNumOutputChannels;
|
||||
}
|
||||
return FMOD_OK;
|
||||
}
|
||||
FMOD_RESULT getInputChannels (int *inputchannels)
|
||||
{
|
||||
if (inputchannels)
|
||||
{
|
||||
*inputchannels = mNumInputChannels;
|
||||
}
|
||||
return FMOD_OK;
|
||||
}
|
||||
FMOD_RESULT getOutputSpeakerMode (FMOD_SPEAKERMODE *speakermode)
|
||||
{
|
||||
if (speakermode)
|
||||
{
|
||||
*speakermode = mOutputSpeakerMode;
|
||||
}
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
||||
protected:
|
||||
int mNumInputChannels;
|
||||
int mNumOutputChannels;
|
||||
FMOD_SPEAKERMODE mOutputSpeakerMode;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // _FMOD_DOWNMIX_H
|
||||
756
src/fmod_downmix_myears.cpp
Executable file
756
src/fmod_downmix_myears.cpp
Executable file
|
|
@ -0,0 +1,756 @@
|
|||
#include "fmod_settings.h"
|
||||
|
||||
#ifdef FMOD_SUPPORT_MYEARS
|
||||
|
||||
#include "fmod_downmix_myears.h"
|
||||
#include "fmod_memory.h"
|
||||
#include <memory.h>
|
||||
|
||||
#define MYEARS_LOGGING
|
||||
#define MYEARS_SUPPORT_EXTERNALISE_FILTERS
|
||||
//#define MYEARS_5POINT1_MODE
|
||||
|
||||
#if defined(PLATFORM_WINDOWS) || defined(PLATFORM_WINDOWS64)
|
||||
#define MYEARS_DATA_FILE "\\myears\\data.myears"
|
||||
#define MYEARS_LOG_FILE "\\myears\\myears.log"
|
||||
#elif defined(PLATFORM_MAC)
|
||||
#define MYEARS_DATA_FILE "" // <- todo
|
||||
#undef MYEARS_LOGGING
|
||||
#elif defined(PLATFORM_IPHONE)
|
||||
#define MYEARS_DATA_FILE "" // <- todo
|
||||
#undef MYEARS_LOGGING
|
||||
#endif
|
||||
|
||||
#ifdef MYEARS_LOGGING
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <time.h>
|
||||
|
||||
#ifdef PLATFORM_WINDOWS
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#ifdef PLATFORM_WINDOWS64
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#endif // MYEARS_LOGGING
|
||||
|
||||
|
||||
|
||||
namespace FMOD
|
||||
{
|
||||
|
||||
const int DownmixMyEars::MYEARS_EXTERNALISE_DELAY = 1056; // 22ms @ 48kHz
|
||||
const float DownmixMyEars::MYEARS_EXTERNALISE_GAIN = 0.031622f; // -30dB
|
||||
const float DownmixMyEars::MYEARS_LFE_CUTOFF = 120.0f;
|
||||
const float DownmixMyEars::MYEARS_LFE_GAIN = 1.0f;
|
||||
|
||||
bool DownmixMyEars::dataExists()
|
||||
{
|
||||
char filename[256];
|
||||
|
||||
#if defined(PLATFORM_WINDOWS) || defined(PLATFORM_WINDOWS64)
|
||||
// Hack!
|
||||
GetSystemDirectory(filename, 256);
|
||||
filename[2] = 0;
|
||||
strcat(filename, MYEARS_DATA_FILE);
|
||||
|
||||
FILE* file = fopen(filename, "r");
|
||||
if (file)
|
||||
{
|
||||
fclose(file);
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int DownmixMyEars::getSampleRate()
|
||||
{
|
||||
return MYEARS_SAMPLE_RATE;
|
||||
}
|
||||
|
||||
bool DownmixMyEars::log(char* fmtstr, ...)
|
||||
{
|
||||
#ifdef MYEARS_LOGGING
|
||||
char dirname[256];
|
||||
|
||||
#if defined(PLATFORM_WINDOWS) || defined(PLATFORM_WINDOWS64)
|
||||
GetSystemDirectory(dirname, 256);
|
||||
dirname[2] = 0;
|
||||
strcat(dirname, MYEARS_LOG_FILE);
|
||||
|
||||
FILE* logfile = fopen(dirname, "a");
|
||||
if (logfile)
|
||||
{
|
||||
char str[256];
|
||||
va_list argptr;
|
||||
va_start(argptr, fmtstr);
|
||||
vsprintf(str, fmtstr, argptr);
|
||||
|
||||
fprintf(logfile, str);
|
||||
fclose(logfile);
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
return false;
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT DownmixMyEars::init(unsigned int dspbuffersize, unsigned int rate, FMOD_SPEAKERMODE outputspeakermode, void *extradata)
|
||||
{
|
||||
FMOD_RESULT result;
|
||||
|
||||
FLOG((FMOD_DEBUG_LEVEL_LOG, __FILE__, __LINE__, "DownmixMyEars::init", "dspbuffersize: %d rate: %d.\n", dspbuffersize, rate));
|
||||
|
||||
mOutputSpeakerMode = outputspeakermode;
|
||||
for (int i = 0; i < MYEARS_SPEAKER_COUNT; ++i)
|
||||
{
|
||||
mLeftFilter[i] = 0;
|
||||
mRightFilter[i] = 0;
|
||||
mLeftFilterExt[i] = 0;
|
||||
mRightFilterExt[i] = 0;
|
||||
}
|
||||
mUseExtFilters = false;
|
||||
|
||||
if (outputspeakermode != FMOD_SPEAKERMODE_STEREO)
|
||||
{
|
||||
FLOG((FMOD_DEBUG_LEVEL_ERROR, __FILE__, __LINE__, "DownmixMyEars::init", "outputspeakermode must be FMOD_SPEAKERMODE_STEREO\n"));
|
||||
|
||||
return FMOD_ERR_INVALID_PARAM;
|
||||
}
|
||||
|
||||
if (rate != MYEARS_SAMPLE_RATE)
|
||||
{
|
||||
FLOG((FMOD_DEBUG_LEVEL_ERROR, __FILE__, __LINE__, "DownmixMyEars::init", "rate must be %d\n", MYEARS_SAMPLE_RATE));
|
||||
|
||||
return FMOD_ERR_INVALID_PARAM;
|
||||
}
|
||||
|
||||
#ifdef MYEARS_5POINT1_MODE
|
||||
mNumInputChannels = 6;
|
||||
#else
|
||||
mNumInputChannels = 8;
|
||||
#endif
|
||||
mNumOutputChannels = 2;
|
||||
|
||||
mLFECutoff = MYEARS_LFE_CUTOFF;
|
||||
mLFEGain = MYEARS_LFE_GAIN;
|
||||
|
||||
if (extradata)
|
||||
{
|
||||
MyEarsExtraData *myearsdata = (MyEarsExtraData *)extradata;
|
||||
// read initialisation data here
|
||||
}
|
||||
|
||||
if ((result = loadFile(MYEARS_DATA_FILE)) != FMOD_OK)
|
||||
{
|
||||
FLOG((FMOD_DEBUG_LEVEL_ERROR, __FILE__, __LINE__, "DownmixMyEars::init", "Error opening MyEars file: %s\n", MYEARS_DATA_FILE));
|
||||
|
||||
return result;
|
||||
}
|
||||
FLOG((FMOD_DEBUG_LEVEL_LOG, __FILE__, __LINE__, "DownmixMyEars::init", "Successfully loaded MyEars file: %s\n", MYEARS_DATA_FILE));
|
||||
|
||||
initLFEFilter();
|
||||
|
||||
#ifdef MYEARS_LOGGING
|
||||
time_t now = time(0);
|
||||
log("%s Loaded '%s'\n Externalisation = %s\n LFEGain = %f\n", ctime(&now), MYEARS_DATA_FILE, mUseExtFilters ? "On" : "Off", mLFEGain);
|
||||
#endif
|
||||
|
||||
FLOG((FMOD_DEBUG_LEVEL_LOG, __FILE__, __LINE__, "DownmixMyEars::init", "done.\n"));
|
||||
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT DownmixMyEars::shutdown()
|
||||
{
|
||||
for (int i = 0; i < MYEARS_SPEAKER_COUNT; ++i)
|
||||
{
|
||||
unloadFilter(mLeftFilter[i]);
|
||||
unloadFilter(mRightFilter[i]);
|
||||
unloadFilter(mLeftFilterExt[i]);
|
||||
unloadFilter(mRightFilterExt[i]);
|
||||
|
||||
mLeftFilter[i] = 0;
|
||||
mRightFilter[i] = 0;
|
||||
mLeftFilterExt[i] = 0;
|
||||
mRightFilterExt[i] = 0;
|
||||
}
|
||||
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
||||
|
||||
void DownmixMyEars::initFilter(MyEarsFilter *filter)
|
||||
{
|
||||
if (filter->buffer)
|
||||
{
|
||||
FMOD_memset(filter->buffer, 0, filter->delay * sizeof(float));
|
||||
filter->bufferpos = filter->buffer;
|
||||
}
|
||||
FMOD_memset(filter->state, 0, MYEARS_FILTER_ORDER * sizeof(float));
|
||||
}
|
||||
|
||||
|
||||
float DownmixMyEars::applyFilter(float sample, MyEarsFilter *filter)
|
||||
{
|
||||
// apply tiny dc offset to prevent float denorm values
|
||||
|
||||
sample += 1.0e-20f;
|
||||
|
||||
// apply ITD delay
|
||||
|
||||
if (filter->buffer)
|
||||
{
|
||||
*filter->bufferpos = sample;
|
||||
if (++filter->bufferpos >= filter->bufferend)
|
||||
{
|
||||
filter->bufferpos = filter->buffer;
|
||||
}
|
||||
sample = *filter->bufferpos;
|
||||
}
|
||||
|
||||
float *state = filter->state;
|
||||
float *nextstate = state + 1;
|
||||
float *a = filter->a + 1;
|
||||
float *b = filter->b;
|
||||
|
||||
// apply filter in transposed Direct Form II
|
||||
|
||||
float y = *(b++) * sample + *state; // 0
|
||||
*(state++) = *(b++) * sample - *(a++) * y + *(nextstate++); // 1
|
||||
*(state++) = *(b++) * sample - *(a++) * y + *(nextstate++); // 2
|
||||
*(state++) = *(b++) * sample - *(a++) * y + *(nextstate++); // 3
|
||||
*(state++) = *(b++) * sample - *(a++) * y + *(nextstate++); // 4
|
||||
*(state++) = *(b++) * sample - *(a++) * y + *(nextstate++); // 5
|
||||
*(state++) = *(b++) * sample - *(a++) * y + *(nextstate++); // 6
|
||||
*(state++) = *(b++) * sample - *(a++) * y + *(nextstate++); // 7
|
||||
*(state++) = *(b++) * sample - *(a++) * y + *(nextstate++); // 8
|
||||
*(state++) = *(b++) * sample - *(a++) * y + *(nextstate++); // 9
|
||||
*(state++) = *(b++) * sample - *(a++) * y + *(nextstate++); // 10
|
||||
*(state++) = *(b++) * sample - *(a++) * y + *(nextstate++); // 11
|
||||
*(state++) = *(b++) * sample - *(a++) * y + *(nextstate++); // 12
|
||||
*(state++) = *(b++) * sample - *(a++) * y + *nextstate; // 13
|
||||
*state = *b * sample - *a * y; // 14
|
||||
|
||||
return y;
|
||||
}
|
||||
|
||||
|
||||
#if MYEARS_LFE_ORDER == 2
|
||||
|
||||
void DownmixMyEars::initLFEFilter()
|
||||
{
|
||||
float damp = sqrtf(0.5f);
|
||||
float c = 1.0f / FMOD_TAN(FMOD_PI * mLFECutoff / ((float)MYEARS_SAMPLE_RATE));
|
||||
float cc = c * c;
|
||||
|
||||
mLFEFilter.b[0] = 1.0f / (1.0f + 2.0f*damp*c + cc) * mLFEGain;
|
||||
mLFEFilter.b[1] = 2.0f * mLFEFilter.b[0];
|
||||
mLFEFilter.b[2] = mLFEFilter.b[0];
|
||||
|
||||
mLFEFilter.a[0] = 1.0f;
|
||||
mLFEFilter.a[1] = 2.0f * mLFEFilter.b[0] * (1.0f - cc);
|
||||
mLFEFilter.a[2] = mLFEFilter.b[0] * (1.0f - 2.0f * damp*c + cc);
|
||||
|
||||
mLFEFilter.state[0] = 0.0f;
|
||||
mLFEFilter.state[1] = 0.0f;
|
||||
}
|
||||
|
||||
|
||||
float DownmixMyEars::applyLFEFilter(float sample)
|
||||
{
|
||||
// apply tiny dc offset to prevent float denorm values
|
||||
|
||||
sample += 1.0e-20f;
|
||||
|
||||
// apply filter in transposed Direct Form II
|
||||
|
||||
float y = mLFEFilter.b[0] * sample + mLFEFilter.state[0]; // 0
|
||||
mLFEFilter.state[0] = mLFEFilter.b[1] * sample - mLFEFilter.a[1] * y + mLFEFilter.state[1]; // 1
|
||||
mLFEFilter.state[1] = mLFEFilter.b[2] * sample - mLFEFilter.a[2] * y; // 2
|
||||
|
||||
return y;
|
||||
}
|
||||
|
||||
#elif MYEARS_LFE_ORDER == 4
|
||||
|
||||
static int convolve(float *in1, int len1, float *in2, int len2, float *out)
|
||||
{
|
||||
int convlen = len1 + len2 - 1;
|
||||
|
||||
for (int i = 0; i < convlen; i++)
|
||||
{
|
||||
float sum = 0.0f;
|
||||
|
||||
int n_lo = i - len2 + 1;
|
||||
if (n_lo < 0)
|
||||
{
|
||||
n_lo = 0;
|
||||
}
|
||||
|
||||
int n_hi = len1 - 1;
|
||||
if (n_hi > i)
|
||||
{
|
||||
n_hi = i;
|
||||
}
|
||||
|
||||
float *p1 = in1 + n_lo;
|
||||
float *p2 = in2 + i - n_lo;
|
||||
for (int n = n_lo; n <= n_hi; n++)
|
||||
{
|
||||
sum += *p1 * *p2;
|
||||
p1++;
|
||||
p2--;
|
||||
}
|
||||
|
||||
*out++ = sum;
|
||||
}
|
||||
|
||||
return convlen;
|
||||
}
|
||||
|
||||
// 4th order Linkwitz-Riley
|
||||
void DownmixMyEars::initLFEFilter()
|
||||
{
|
||||
float damp = sqrtf(0.5f);
|
||||
float c = 1.0f / FMOD_TAN(FMOD_PI * mLFECutoff / ((float)MYEARS_SAMPLE_RATE));
|
||||
float cc = c * c;
|
||||
|
||||
float b[3];
|
||||
float a[3];
|
||||
|
||||
b[0] = 1.0f / (1.0f + 2.0f * damp * c + cc);
|
||||
b[1] = 2.0f * b[0];
|
||||
b[2] = b[0];
|
||||
|
||||
a[0] = 1.0f;
|
||||
a[1] = 2.0f * b[0] * (1.0f - cc);
|
||||
a[2] = b[0] * (1.0f - 2.0f * damp*c + cc);
|
||||
|
||||
convolve(b, 3, b, 3, mLFEFilter.b);
|
||||
convolve(a, 3, a, 3, mLFEFilter.a);
|
||||
|
||||
for (int i = 0; i < MYEARS_LFE_ORDER; i++)
|
||||
{
|
||||
mLFEFilter.state[i] = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
float DownmixMyEars::applyLFEFilter(float sample)
|
||||
{
|
||||
// apply tiny dc offset to prevent float denorm values
|
||||
static float dither = 1.0e-20f;
|
||||
|
||||
sample += dither;
|
||||
dither = -dither;
|
||||
|
||||
float *state = mLFEFilter.state;
|
||||
float *nextstate = state + 1;
|
||||
float *b = mLFEFilter.b;
|
||||
float *a = mLFEFilter.a + 1;
|
||||
|
||||
// apply filter in transposed Direct Form II
|
||||
|
||||
float y = *(b++) * sample + *state; // 0
|
||||
*(state++) = *(b++) * sample - *(a++) * y + *(nextstate++); // 1
|
||||
*(state++) = *(b++) * sample - *(a++) * y + *(nextstate++); // 2
|
||||
*(state++) = *(b++) * sample - *(a++) * y + *nextstate; // 3
|
||||
*state = *b * sample - *a * y; // 4
|
||||
|
||||
return y * mLFEGain;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT DownmixMyEars::encode(float *inbuffer, float *outbuffer, unsigned int numsamples)
|
||||
{
|
||||
float *in = inbuffer;
|
||||
float *out = outbuffer;
|
||||
|
||||
#ifdef MYEARS_SUPPORT_EXTERNALISE_FILTERS
|
||||
if (mUseExtFilters)
|
||||
{
|
||||
switch(mNumInputChannels)
|
||||
{
|
||||
case 8:
|
||||
for (unsigned int i = 0; i < numsamples; i++)
|
||||
{
|
||||
float extleft;
|
||||
float extright;
|
||||
float lfe;
|
||||
|
||||
out[0] = applyFilter(*in , mLeftFilter[FMOD_SPEAKER_FRONT_LEFT]);
|
||||
out[1] = applyFilter(*in , mRightFilter[FMOD_SPEAKER_FRONT_LEFT]);
|
||||
extleft = applyFilter(*in , mLeftFilterExt[FMOD_SPEAKER_FRONT_LEFT]);
|
||||
extright = applyFilter(*in++, mRightFilterExt[FMOD_SPEAKER_FRONT_LEFT]);
|
||||
out[0] += applyFilter(*in , mLeftFilter[FMOD_SPEAKER_FRONT_RIGHT]);
|
||||
out[1] += applyFilter(*in , mRightFilter[FMOD_SPEAKER_FRONT_RIGHT]);
|
||||
extleft += applyFilter(*in , mLeftFilterExt[FMOD_SPEAKER_FRONT_RIGHT]);
|
||||
extright += applyFilter(*in++, mRightFilterExt[FMOD_SPEAKER_FRONT_RIGHT]);
|
||||
out[0] += applyFilter(*in , mLeftFilter[FMOD_SPEAKER_FRONT_CENTER]);
|
||||
out[1] += applyFilter(*in , mRightFilter[FMOD_SPEAKER_FRONT_CENTER]);
|
||||
extleft += applyFilter(*in , mLeftFilterExt[FMOD_SPEAKER_FRONT_CENTER]);
|
||||
extright += applyFilter(*in++, mRightFilterExt[FMOD_SPEAKER_FRONT_CENTER]);
|
||||
lfe = applyLFEFilter(*in++);
|
||||
out[0] += lfe;
|
||||
out[1] += lfe;
|
||||
out[0] += applyFilter(*in , mLeftFilter[FMOD_SPEAKER_BACK_LEFT]);
|
||||
out[1] += applyFilter(*in , mRightFilter[FMOD_SPEAKER_BACK_LEFT]);
|
||||
extleft += applyFilter(*in , mLeftFilterExt[FMOD_SPEAKER_BACK_LEFT]);
|
||||
extright += applyFilter(*in++, mRightFilterExt[FMOD_SPEAKER_BACK_LEFT]);
|
||||
out[0] += applyFilter(*in , mLeftFilter[FMOD_SPEAKER_BACK_RIGHT]);
|
||||
out[1] += applyFilter(*in , mRightFilter[FMOD_SPEAKER_BACK_RIGHT]);
|
||||
extleft += applyFilter(*in , mLeftFilterExt[FMOD_SPEAKER_BACK_RIGHT]);
|
||||
extright += applyFilter(*in++, mRightFilterExt[FMOD_SPEAKER_BACK_RIGHT]);
|
||||
out[0] += applyFilter(*in , mLeftFilter[FMOD_SPEAKER_SIDE_LEFT]);
|
||||
out[1] += applyFilter(*in , mRightFilter[FMOD_SPEAKER_SIDE_LEFT]);
|
||||
extleft += applyFilter(*in , mLeftFilterExt[FMOD_SPEAKER_SIDE_LEFT]);
|
||||
extright += applyFilter(*in++, mRightFilterExt[FMOD_SPEAKER_SIDE_LEFT]);
|
||||
out[0] += applyFilter(*in , mLeftFilter[FMOD_SPEAKER_SIDE_RIGHT]);
|
||||
out[1] += applyFilter(*in , mRightFilter[FMOD_SPEAKER_SIDE_RIGHT]);
|
||||
extleft += applyFilter(*in , mLeftFilterExt[FMOD_SPEAKER_SIDE_RIGHT]);
|
||||
extright += applyFilter(*in++, mRightFilterExt[FMOD_SPEAKER_SIDE_RIGHT]);
|
||||
|
||||
out[0] += extleft * MYEARS_EXTERNALISE_GAIN;
|
||||
out[1] += extright * MYEARS_EXTERNALISE_GAIN;
|
||||
|
||||
out[0] *= 0.5f;
|
||||
out[1] *= 0.5f;
|
||||
|
||||
out += 2;
|
||||
}
|
||||
break;
|
||||
|
||||
case 6:
|
||||
for (unsigned int i = 0; i < numsamples; i++)
|
||||
{
|
||||
float extleft;
|
||||
float extright;
|
||||
float lfe;
|
||||
|
||||
out[0] = applyFilter(*in , mLeftFilter[FMOD_SPEAKER_FRONT_LEFT]);
|
||||
out[1] = applyFilter(*in , mRightFilter[FMOD_SPEAKER_FRONT_LEFT]);
|
||||
extleft = applyFilter(*in , mLeftFilterExt[FMOD_SPEAKER_FRONT_LEFT]);
|
||||
extright = applyFilter(*in++, mRightFilterExt[FMOD_SPEAKER_FRONT_LEFT]);
|
||||
out[0] += applyFilter(*in , mLeftFilter[FMOD_SPEAKER_FRONT_RIGHT]);
|
||||
out[1] += applyFilter(*in , mRightFilter[FMOD_SPEAKER_FRONT_RIGHT]);
|
||||
extleft += applyFilter(*in , mLeftFilterExt[FMOD_SPEAKER_FRONT_RIGHT]);
|
||||
extright += applyFilter(*in++, mRightFilterExt[FMOD_SPEAKER_FRONT_RIGHT]);
|
||||
out[0] += applyFilter(*in , mLeftFilter[FMOD_SPEAKER_FRONT_CENTER]);
|
||||
out[1] += applyFilter(*in , mRightFilter[FMOD_SPEAKER_FRONT_CENTER]);
|
||||
extleft += applyFilter(*in , mLeftFilterExt[FMOD_SPEAKER_FRONT_CENTER]);
|
||||
extright += applyFilter(*in++, mRightFilterExt[FMOD_SPEAKER_FRONT_CENTER]);
|
||||
lfe = applyLFEFilter(*in++);
|
||||
out[0] += lfe;
|
||||
out[1] += lfe;
|
||||
out[0] += applyFilter(*in , mLeftFilter[FMOD_SPEAKER_BACK_LEFT]);
|
||||
out[1] += applyFilter(*in , mRightFilter[FMOD_SPEAKER_BACK_LEFT]);
|
||||
extleft += applyFilter(*in , mLeftFilterExt[FMOD_SPEAKER_BACK_LEFT]);
|
||||
extright += applyFilter(*in++, mRightFilterExt[FMOD_SPEAKER_BACK_LEFT]);
|
||||
out[0] += applyFilter(*in , mLeftFilter[FMOD_SPEAKER_BACK_RIGHT]);
|
||||
out[1] += applyFilter(*in , mRightFilter[FMOD_SPEAKER_BACK_RIGHT]);
|
||||
extleft += applyFilter(*in , mLeftFilterExt[FMOD_SPEAKER_BACK_RIGHT]);
|
||||
extright += applyFilter(*in++, mRightFilterExt[FMOD_SPEAKER_BACK_RIGHT]);
|
||||
|
||||
out[0] += extleft * MYEARS_EXTERNALISE_GAIN;
|
||||
out[1] += extright * MYEARS_EXTERNALISE_GAIN;
|
||||
|
||||
out[0] *= 0.5f;
|
||||
out[1] *= 0.5f;
|
||||
|
||||
out += 2;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
return FMOD_ERR_INTERNAL;
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
switch(mNumInputChannels)
|
||||
{
|
||||
case 8:
|
||||
for (unsigned int i = 0; i < numsamples; i++)
|
||||
{
|
||||
float lfe;
|
||||
|
||||
out[0] = applyFilter(*in , mLeftFilter[FMOD_SPEAKER_FRONT_LEFT]);
|
||||
out[1] = applyFilter(*in++, mRightFilter[FMOD_SPEAKER_FRONT_LEFT]);
|
||||
out[0] += applyFilter(*in , mLeftFilter[FMOD_SPEAKER_FRONT_RIGHT]);
|
||||
out[1] += applyFilter(*in++, mRightFilter[FMOD_SPEAKER_FRONT_RIGHT]);
|
||||
out[0] += applyFilter(*in , mLeftFilter[FMOD_SPEAKER_FRONT_CENTER]);
|
||||
out[1] += applyFilter(*in++, mRightFilter[FMOD_SPEAKER_FRONT_CENTER]);
|
||||
lfe = applyLFEFilter(*in++);
|
||||
out[0] += lfe;
|
||||
out[1] += lfe;
|
||||
out[0] += applyFilter(*in , mLeftFilter[FMOD_SPEAKER_BACK_LEFT]);
|
||||
out[1] += applyFilter(*in++, mRightFilter[FMOD_SPEAKER_BACK_LEFT]);
|
||||
out[0] += applyFilter(*in , mLeftFilter[FMOD_SPEAKER_BACK_RIGHT]);
|
||||
out[1] += applyFilter(*in++, mRightFilter[FMOD_SPEAKER_BACK_RIGHT]);
|
||||
out[0] += applyFilter(*in , mLeftFilter[FMOD_SPEAKER_SIDE_LEFT]);
|
||||
out[1] += applyFilter(*in++, mRightFilter[FMOD_SPEAKER_SIDE_LEFT]);
|
||||
out[0] += applyFilter(*in , mLeftFilter[FMOD_SPEAKER_SIDE_RIGHT]);
|
||||
out[1] += applyFilter(*in++, mRightFilter[FMOD_SPEAKER_SIDE_RIGHT]);
|
||||
|
||||
out[0] *= 0.5f;
|
||||
out[1] *= 0.5f;
|
||||
|
||||
out += 2;
|
||||
}
|
||||
break;
|
||||
|
||||
case 6:
|
||||
for (unsigned int i = 0; i < numsamples; i++)
|
||||
{
|
||||
float lfe;
|
||||
|
||||
out[0] = applyFilter(*in , mLeftFilter[FMOD_SPEAKER_FRONT_LEFT]);
|
||||
out[1] = applyFilter(*in++, mRightFilter[FMOD_SPEAKER_FRONT_LEFT]);
|
||||
out[0] += applyFilter(*in , mLeftFilter[FMOD_SPEAKER_FRONT_RIGHT]);
|
||||
out[1] += applyFilter(*in++, mRightFilter[FMOD_SPEAKER_FRONT_RIGHT]);
|
||||
out[0] += applyFilter(*in , mLeftFilter[FMOD_SPEAKER_FRONT_CENTER]);
|
||||
out[1] += applyFilter(*in++, mRightFilter[FMOD_SPEAKER_FRONT_CENTER]);
|
||||
lfe = applyLFEFilter(*in++);
|
||||
out[0] += lfe;
|
||||
out[1] += lfe;
|
||||
out[0] += applyFilter(*in , mLeftFilter[FMOD_SPEAKER_BACK_LEFT]);
|
||||
out[1] += applyFilter(*in++, mRightFilter[FMOD_SPEAKER_BACK_LEFT]);
|
||||
out[0] += applyFilter(*in , mLeftFilter[FMOD_SPEAKER_BACK_RIGHT]);
|
||||
out[1] += applyFilter(*in++, mRightFilter[FMOD_SPEAKER_BACK_RIGHT]);
|
||||
|
||||
out[0] *= 0.5f;
|
||||
out[1] *= 0.5f;
|
||||
|
||||
out += 2;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
return FMOD_ERR_INTERNAL;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
||||
|
||||
FMOD_RESULT DownmixMyEars::loadFile(const char *filename)
|
||||
{
|
||||
FMOD_RESULT result;
|
||||
|
||||
FILE* file = fopen(filename, "r");
|
||||
if (!file)
|
||||
{
|
||||
return FMOD_ERR_FILE_NOTFOUND;
|
||||
}
|
||||
|
||||
for(int i = 0; i < MYEARS_SPEAKER_COUNT; ++i)
|
||||
{
|
||||
if (i != FMOD_SPEAKER_LOW_FREQUENCY)
|
||||
{
|
||||
if ((result = loadFilter(file, &mRightFilter[i])) != FMOD_OK)
|
||||
{
|
||||
fclose(file);
|
||||
return result;
|
||||
}
|
||||
if ((result = loadFilter(file, &mLeftFilter[i])) != FMOD_OK)
|
||||
{
|
||||
fclose(file);
|
||||
return result;
|
||||
}
|
||||
if ((result = loadFilter(file, &mRightFilterExt[i], true)) != FMOD_OK)
|
||||
{
|
||||
fclose(file);
|
||||
return result;
|
||||
}
|
||||
if ((result = loadFilter(file, &mLeftFilterExt[i], true)) != FMOD_OK)
|
||||
{
|
||||
fclose(file);
|
||||
return result;
|
||||
}
|
||||
|
||||
initFilter(mRightFilter[i]);
|
||||
initFilter(mLeftFilter[i]);
|
||||
initFilter(mRightFilterExt[i]);
|
||||
initFilter(mLeftFilterExt[i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
mRightFilter[i] = 0;
|
||||
mLeftFilter[i] = 0;
|
||||
mRightFilterExt[i] = 0;
|
||||
mLeftFilterExt[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
int ext;
|
||||
if (fscanf(file, "%d", &ext) == EOF) // enable externalisation filters
|
||||
{
|
||||
fclose(file);
|
||||
return FMOD_ERR_FORMAT;
|
||||
}
|
||||
|
||||
if (fscanf(file, ",%f", &mLFEGain) == EOF) // LFE gain (optional)
|
||||
{
|
||||
mLFEGain = MYEARS_LFE_GAIN;
|
||||
}
|
||||
|
||||
mUseExtFilters = (ext != 0);
|
||||
|
||||
fclose(file);
|
||||
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
||||
|
||||
FMOD_RESULT DownmixMyEars::loadFilter(FILE *file, MyEarsFilter **filter, bool externaliser)
|
||||
{
|
||||
int dummy;
|
||||
int i;
|
||||
|
||||
*filter = (MyEarsFilter *)FMOD_Memory_Calloc(sizeof(MyEarsFilter));
|
||||
if (!filter)
|
||||
{
|
||||
return FMOD_ERR_MEMORY;
|
||||
}
|
||||
|
||||
// 'a' coefficients
|
||||
if (fscanf(file, "%d,", &dummy) == EOF) // ignore 'a' coefficient delays
|
||||
{
|
||||
goto MYEARS_FILTER_LOAD_ERROR;
|
||||
}
|
||||
for (i = 0; i < MYEARS_FILTER_ORDER; ++i)
|
||||
{
|
||||
if (fscanf(file, "%f,", &(*filter)->a[i]) == EOF)
|
||||
{
|
||||
goto MYEARS_FILTER_LOAD_ERROR;
|
||||
}
|
||||
}
|
||||
if (fscanf(file, "%f\n", &(*filter)->a[i]) == EOF)
|
||||
{
|
||||
goto MYEARS_FILTER_LOAD_ERROR;
|
||||
}
|
||||
|
||||
// 'b' coefficients
|
||||
if (fscanf(file, "%d,", &(*filter)->delay) == EOF)
|
||||
{
|
||||
goto MYEARS_FILTER_LOAD_ERROR;
|
||||
}
|
||||
for (i = 0; i < MYEARS_FILTER_ORDER; ++i)
|
||||
{
|
||||
if (fscanf(file, "%f,", &(*filter)->b[i]) == EOF)
|
||||
{
|
||||
goto MYEARS_FILTER_LOAD_ERROR;
|
||||
}
|
||||
}
|
||||
if (fscanf(file, "%f\n", &(*filter)->b[i]) == EOF)
|
||||
{
|
||||
goto MYEARS_FILTER_LOAD_ERROR;
|
||||
}
|
||||
|
||||
if (externaliser)
|
||||
{
|
||||
(*filter)->delay += MYEARS_EXTERNALISE_DELAY;
|
||||
}
|
||||
|
||||
if ((*filter)->delay)
|
||||
{
|
||||
(*filter)->buffer = (float *)FMOD_Memory_Calloc((*filter)->delay * sizeof(float));
|
||||
if (!(*filter)->buffer)
|
||||
{
|
||||
FMOD_Memory_Free(*filter);
|
||||
return FMOD_ERR_MEMORY;
|
||||
}
|
||||
|
||||
(*filter)->bufferend = (*filter)->buffer + (*filter)->delay;
|
||||
}
|
||||
else
|
||||
{
|
||||
(*filter)->buffer = 0;
|
||||
}
|
||||
|
||||
return FMOD_OK;
|
||||
|
||||
MYEARS_FILTER_LOAD_ERROR:
|
||||
FMOD_Memory_Free(*filter);
|
||||
return FMOD_ERR_FORMAT;
|
||||
}
|
||||
|
||||
|
||||
void DownmixMyEars::unloadFilter(MyEarsFilter *filter)
|
||||
{
|
||||
if (filter)
|
||||
{
|
||||
if (filter->buffer)
|
||||
{
|
||||
FMOD_Memory_Free(filter->buffer);
|
||||
}
|
||||
FMOD_Memory_Free(filter);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif //FMOD_SUPPORT_MYEARS
|
||||
83
src/fmod_downmix_myears.h
Executable file
83
src/fmod_downmix_myears.h
Executable file
|
|
@ -0,0 +1,83 @@
|
|||
#ifndef _FMOD_DOWNMIX_MYEARS_H
|
||||
#define _FMOD_DOWNMIX_MYEARS_H
|
||||
|
||||
#include "fmod_settings.h"
|
||||
|
||||
#ifdef FMOD_SUPPORT_MYEARS
|
||||
|
||||
#include "fmod_downmix.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#define MYEARS_FILTER_ORDER 14
|
||||
#define MYEARS_LFE_ORDER 4
|
||||
#define MYEARS_SPEAKER_COUNT 8
|
||||
#define MYEARS_SAMPLE_RATE 48000
|
||||
|
||||
|
||||
namespace FMOD
|
||||
{
|
||||
class DownmixMyEars : public Downmix
|
||||
{
|
||||
public:
|
||||
FMOD_RESULT init (unsigned int dspbuffersize, unsigned int rate, FMOD_SPEAKERMODE outputspeakermode, void *extradata = 0);
|
||||
FMOD_RESULT shutdown ();
|
||||
FMOD_RESULT encode (float *inbuffer, float *outbuffer, unsigned int numsamples);
|
||||
|
||||
static bool dataExists ();
|
||||
static int getSampleRate ();
|
||||
|
||||
typedef struct MyEarsFilter
|
||||
{
|
||||
float a[MYEARS_FILTER_ORDER + 1];
|
||||
float b[MYEARS_FILTER_ORDER + 1];
|
||||
float state[MYEARS_FILTER_ORDER];
|
||||
int delay;
|
||||
float *buffer;
|
||||
float *bufferend;
|
||||
float *bufferpos;
|
||||
};
|
||||
|
||||
typedef struct LFEFilter
|
||||
{
|
||||
float a[MYEARS_LFE_ORDER + 1];
|
||||
float b[MYEARS_LFE_ORDER + 1];
|
||||
float state[MYEARS_LFE_ORDER];
|
||||
};
|
||||
|
||||
typedef struct MyEarsExtraData
|
||||
{
|
||||
// data for Downmix::init()
|
||||
};
|
||||
|
||||
private:
|
||||
static const int MYEARS_EXTERNALISE_DELAY;
|
||||
static const float MYEARS_EXTERNALISE_GAIN;
|
||||
static const float MYEARS_LFE_CUTOFF;
|
||||
static const float MYEARS_LFE_GAIN;
|
||||
|
||||
bool mUseExtFilters;
|
||||
float mLFEGain;
|
||||
float mLFECutoff;
|
||||
|
||||
MyEarsFilter *mLeftFilter[MYEARS_SPEAKER_COUNT];
|
||||
MyEarsFilter *mRightFilter[MYEARS_SPEAKER_COUNT];
|
||||
MyEarsFilter *mLeftFilterExt[MYEARS_SPEAKER_COUNT];
|
||||
MyEarsFilter *mRightFilterExt[MYEARS_SPEAKER_COUNT];
|
||||
LFEFilter mLFEFilter;
|
||||
|
||||
static bool log(char* str, ...);
|
||||
|
||||
FMOD_RESULT loadFile(const char *filename);
|
||||
FMOD_RESULT loadFilter(FILE *file, MyEarsFilter **filter, bool externaliser = false);
|
||||
void unloadFilter(MyEarsFilter *filter);
|
||||
void initFilter(MyEarsFilter *filter);
|
||||
void initLFEFilter();
|
||||
__forceinline float applyFilter(float sample, MyEarsFilter *filter);
|
||||
__forceinline float applyLFEFilter(float sample);
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif // _FMOD_DOWNMIX_MYEARS_H
|
||||
231
src/fmod_downmix_neuralthx.cpp
Executable file
231
src/fmod_downmix_neuralthx.cpp
Executable file
|
|
@ -0,0 +1,231 @@
|
|||
#include "fmod_settings.h"
|
||||
|
||||
#ifdef FMOD_SUPPORT_NEURAL
|
||||
|
||||
#include "fmod_downmix_neuralthx.h"
|
||||
#include "fmod_memory.h"
|
||||
|
||||
namespace FMOD
|
||||
{
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT DownmixNeural::init(unsigned int dspbuffersize, unsigned int rate, FMOD_SPEAKERMODE outputspeakermode, void *extradata)
|
||||
{
|
||||
int err;
|
||||
|
||||
FLOG((FMOD_DEBUG_LEVEL_LOG, __FILE__, __LINE__, "DownmixNeural::init", "dspbuffersize: %d rate: %d.\n", dspbuffersize, rate));
|
||||
|
||||
if (dspbuffersize % NEURAL_FRAMESIZE)
|
||||
{
|
||||
FLOG((FMOD_DEBUG_LEVEL_ERROR, __FILE__, __LINE__, "DownmixNeural::init", "dspbuffersize: %d must be multiple of 256\n", dspbuffersize));
|
||||
|
||||
return FMOD_ERR_INVALID_PARAM;
|
||||
}
|
||||
|
||||
mOutputSpeakerMode = outputspeakermode;
|
||||
switch(mOutputSpeakerMode)
|
||||
{
|
||||
case FMOD_SPEAKERMODE_STEREO:
|
||||
{
|
||||
mNeuralMode = NEURAL_THX_7_2_GAMING;
|
||||
mNumInputChannels = 8;
|
||||
mNumOutputChannels = 2;
|
||||
|
||||
FLOG((FMOD_DEBUG_LEVEL_LOG, __FILE__, __LINE__, "DownmixNeural::init", "Initialising to NEURAL_7_2_GAMING.\n"));
|
||||
|
||||
break;
|
||||
}
|
||||
case FMOD_SPEAKERMODE_5POINT1:
|
||||
{
|
||||
mNeuralMode = NEURAL_THX_7_5_GAMING;
|
||||
mNumInputChannels = 8;
|
||||
mNumOutputChannels = 6;
|
||||
|
||||
FLOG((FMOD_DEBUG_LEVEL_LOG, __FILE__, __LINE__, "DownmixNeural::init", "Initialising to NEURAL_7_5_GAMING.\n"));
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
FLOG((FMOD_DEBUG_LEVEL_ERROR, __FILE__, __LINE__, "DownmixNeural::init", "outputspeakermode must be FMOD_SPEAKERMODE_STEREO or FMOD_SPEAKERMODE_5POINT1\n"));
|
||||
return FMOD_ERR_INVALID_PARAM;
|
||||
}
|
||||
}
|
||||
|
||||
bool usefinallimiting = false;
|
||||
float lfecutoff = 0.0f;
|
||||
|
||||
if (extradata)
|
||||
{
|
||||
NeuralExtraData *neuraldata = (NeuralExtraData *)extradata;
|
||||
|
||||
usefinallimiting = neuraldata->usefinallimiting;
|
||||
lfecutoff = neuraldata->lfecutoff;
|
||||
}
|
||||
|
||||
mNeuralParameters.Init(mNeuralMode);
|
||||
mNeuralSettings.nChanConfig = mNeuralMode;
|
||||
mNeuralSettings.nSampleRate = rate;
|
||||
|
||||
err = mNeuralEncoder.Init(mNeuralSettings, mNeuralParameters);
|
||||
if (err != NRLTHX_OK)
|
||||
{
|
||||
FLOG((FMOD_DEBUG_LEVEL_ERROR, __FILE__, __LINE__, "DownmixNeural::init", "Neural Init returned: %d\n", err));
|
||||
return FMOD_ERR_OUTPUT_INIT;
|
||||
}
|
||||
|
||||
FLOG((FMOD_DEBUG_LEVEL_LOG, __FILE__, __LINE__, "DownmixNeural::init", "done.\n"));
|
||||
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT DownmixNeural::shutdown()
|
||||
{
|
||||
mNeuralEncoder.Shutdown();
|
||||
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT DownmixNeural::encode(float *inbuffer, float *outbuffer, unsigned int numsamples)
|
||||
{
|
||||
int err;
|
||||
Neural_THX_Channel_Format channels_in, channels_out;
|
||||
int numiterations = numsamples / NEURAL_FRAMESIZE;
|
||||
|
||||
float *in = inbuffer;
|
||||
float *out = outbuffer;
|
||||
|
||||
for (int i = 0; i < numiterations; i++)
|
||||
{
|
||||
if (mNumInputChannels == 8)
|
||||
{
|
||||
for (int j = 0; j < NEURAL_FRAMESIZE; j++)
|
||||
{
|
||||
channels_in.m_fL [j] = in[0]; // front left
|
||||
channels_in.m_fR [j] = in[1]; // front right
|
||||
channels_in.m_fC [j] = in[2]; // center
|
||||
channels_in.m_fLFE[j] = in[3]; // lfe
|
||||
|
||||
#ifdef PLATFORM_PS3
|
||||
/*
|
||||
Back and sides swapped around on PS3
|
||||
*/
|
||||
channels_in.m_fLs [j] = in[4]; // surround left
|
||||
channels_in.m_fRs [j] = in[5]; // surround right
|
||||
|
||||
channels_in.m_fLb [j] = in[6]; // back left
|
||||
channels_in.m_fRb [j] = in[7]; // back right
|
||||
#else
|
||||
channels_in.m_fLb [j] = in[4]; // back left
|
||||
channels_in.m_fRb [j] = in[5]; // back right
|
||||
|
||||
channels_in.m_fLs [j] = in[6]; // side left
|
||||
channels_in.m_fRs [j] = in[7]; // side right
|
||||
#endif
|
||||
|
||||
in += 8;
|
||||
}
|
||||
}
|
||||
else if (mNumInputChannels == 6)
|
||||
{
|
||||
for (int j = 0; j < NEURAL_FRAMESIZE; j++)
|
||||
{
|
||||
channels_in.m_fL [j] = in[0]; // front left
|
||||
channels_in.m_fR [j] = in[1]; // front right
|
||||
channels_in.m_fC [j] = in[2]; // center
|
||||
channels_in.m_fLFE[j] = in[3]; // lfe
|
||||
channels_in.m_fLs [j] = in[4]; // surround left
|
||||
channels_in.m_fRs [j] = in[5]; // surround right
|
||||
|
||||
in += 6;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Encode
|
||||
*/
|
||||
err = mNeuralEncoder.Encode(channels_in, channels_out, mNeuralSettings, mNeuralParameters);
|
||||
if (err != NRLTHX_OK)
|
||||
{
|
||||
FLOG((FMOD_DEBUG_LEVEL_ERROR, __FILE__, __LINE__, "DownmixNeural::init", "Neural Encode returned: %d\n", err));
|
||||
return FMOD_ERR_INVALID_PARAM;
|
||||
}
|
||||
|
||||
if (mNumOutputChannels == 6)
|
||||
{
|
||||
for (int j = 0; j < NEURAL_FRAMESIZE; j++)
|
||||
{
|
||||
out[0] = channels_out.m_fL [j]; // front left
|
||||
out[1] = channels_out.m_fR [j]; // front right
|
||||
out[2] = channels_out.m_fC [j]; // center
|
||||
out[3] = channels_out.m_fLFE[j]; // lfe
|
||||
out[4] = channels_out.m_fLs [j]; // surround left
|
||||
out[5] = channels_out.m_fRs [j]; // surround right
|
||||
|
||||
out += 6;
|
||||
}
|
||||
}
|
||||
else if (mNumOutputChannels == 2)
|
||||
{
|
||||
for (int j = 0; j < NEURAL_FRAMESIZE; j++)
|
||||
{
|
||||
out[0] = channels_out.m_fL [j]; // front left
|
||||
out[1] = channels_out.m_fR [j]; // front right
|
||||
|
||||
out += 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif //FMOD_INIT_DTS_NEURALSURROUND
|
||||
39
src/fmod_downmix_neuralthx.h
Executable file
39
src/fmod_downmix_neuralthx.h
Executable file
|
|
@ -0,0 +1,39 @@
|
|||
#ifndef _FMOD_DOWNMIX_NEURAL_H
|
||||
#define _FMOD_DOWNMIX_NEURAL_H
|
||||
|
||||
#include "fmod_settings.h"
|
||||
|
||||
#ifdef FMOD_SUPPORT_NEURAL
|
||||
|
||||
#include "fmod.h"
|
||||
|
||||
#include "fmod_downmix.h"
|
||||
#include "../lib/neural_thx/Neural_THX_Interface.h"
|
||||
|
||||
namespace FMOD
|
||||
{
|
||||
class DownmixNeural : public Downmix
|
||||
{
|
||||
public:
|
||||
FMOD_RESULT init (unsigned int dspbuffersize, unsigned int rate, FMOD_SPEAKERMODE outputspeakermode, void *extradata = 0);
|
||||
FMOD_RESULT shutdown ();
|
||||
FMOD_RESULT encode (float *inbuffer, float *outbuffer, unsigned int numsamples);
|
||||
|
||||
typedef struct NeuralExtraData
|
||||
{
|
||||
bool usefinallimiting;
|
||||
float lfecutoff;
|
||||
};
|
||||
|
||||
private:
|
||||
NEURAL_THX_ENCODER mNeuralEncoder;
|
||||
Neural_THX_Encoder_Settings mNeuralSettings;
|
||||
Neural_THX_Encoder_Params mNeuralParameters;
|
||||
|
||||
unsigned int mNeuralMode;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif // _FMOD_DOWNMIX_NEURAL_H
|
||||
507
src/fmod_dsp.cpp
Executable file
507
src/fmod_dsp.cpp
Executable file
|
|
@ -0,0 +1,507 @@
|
|||
/*$ preserve start $*/
|
||||
|
||||
#include "fmod_settings.h"
|
||||
|
||||
#include "fmod_dspi.h"
|
||||
|
||||
namespace FMOD
|
||||
{
|
||||
/*$ preserve end $*/
|
||||
|
||||
|
||||
FMOD_RESULT DSP::release()
|
||||
{
|
||||
FMOD_RESULT result;
|
||||
DSPI *dspi;
|
||||
|
||||
result = DSPI::validate(this, &dspi);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
return dspi->release();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
FMOD_RESULT DSP::getSystemObject(System **system)
|
||||
{
|
||||
FMOD_RESULT result;
|
||||
DSPI *dspi;
|
||||
|
||||
result = DSPI::validate(this, &dspi);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
return dspi->getSystemObject(system);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
FMOD_RESULT DSP::addInput(DSP *target, DSPConnection **connection)
|
||||
{
|
||||
FMOD_RESULT result;
|
||||
DSPI *dspi;
|
||||
|
||||
result = DSPI::validate(this, &dspi);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
return dspi->addInput((DSPI *)target, (DSPConnectionI **)connection);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
FMOD_RESULT DSP::disconnectFrom(DSP *target)
|
||||
{
|
||||
FMOD_RESULT result;
|
||||
DSPI *dspi;
|
||||
|
||||
result = DSPI::validate(this, &dspi);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
return dspi->disconnectFrom((DSPI *)target);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
FMOD_RESULT DSP::disconnectAll(bool inputs, bool outputs)
|
||||
{
|
||||
FMOD_RESULT result;
|
||||
DSPI *dspi;
|
||||
|
||||
result = DSPI::validate(this, &dspi);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
return dspi->disconnectAll(inputs, outputs);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
FMOD_RESULT DSP::remove()
|
||||
{
|
||||
FMOD_RESULT result;
|
||||
DSPI *dspi;
|
||||
|
||||
result = DSPI::validate(this, &dspi);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
return dspi->remove();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
FMOD_RESULT DSP::getNumInputs(int *numinputs)
|
||||
{
|
||||
FMOD_RESULT result;
|
||||
DSPI *dspi;
|
||||
|
||||
result = DSPI::validate(this, &dspi);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
return dspi->getNumInputs(numinputs);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
FMOD_RESULT DSP::getNumOutputs(int *numoutputs)
|
||||
{
|
||||
FMOD_RESULT result;
|
||||
DSPI *dspi;
|
||||
|
||||
result = DSPI::validate(this, &dspi);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
return dspi->getNumOutputs(numoutputs);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
FMOD_RESULT DSP::getInput(int index, DSP **input, DSPConnection **inputconnection)
|
||||
{
|
||||
FMOD_RESULT result;
|
||||
DSPI *dspi;
|
||||
|
||||
result = DSPI::validate(this, &dspi);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
return dspi->getInput(index, (DSPI **)input, (DSPConnectionI **)inputconnection);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
FMOD_RESULT DSP::getOutput(int index, DSP **output, DSPConnection **outputconnection)
|
||||
{
|
||||
FMOD_RESULT result;
|
||||
DSPI *dspi;
|
||||
|
||||
result = DSPI::validate(this, &dspi);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
return dspi->getOutput(index, (DSPI **)output, (DSPConnectionI **)outputconnection);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
FMOD_RESULT DSP::setActive(bool active)
|
||||
{
|
||||
FMOD_RESULT result;
|
||||
DSPI *dspi;
|
||||
|
||||
result = DSPI::validate(this, &dspi);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
return dspi->setActive(active);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
FMOD_RESULT DSP::getActive(bool *active)
|
||||
{
|
||||
FMOD_RESULT result;
|
||||
DSPI *dspi;
|
||||
|
||||
result = DSPI::validate(this, &dspi);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
return dspi->getActive(active);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
FMOD_RESULT DSP::setBypass(bool bypass)
|
||||
{
|
||||
FMOD_RESULT result;
|
||||
DSPI *dspi;
|
||||
|
||||
result = DSPI::validate(this, &dspi);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
return dspi->setBypass(bypass);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
FMOD_RESULT DSP::getBypass(bool *bypass)
|
||||
{
|
||||
FMOD_RESULT result;
|
||||
DSPI *dspi;
|
||||
|
||||
result = DSPI::validate(this, &dspi);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
return dspi->getBypass(bypass);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
FMOD_RESULT DSP::setSpeakerActive(FMOD_SPEAKER speaker, bool active)
|
||||
{
|
||||
FMOD_RESULT result;
|
||||
DSPI *dspi;
|
||||
|
||||
result = DSPI::validate(this, &dspi);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
return dspi->setSpeakerActive(speaker, active);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
FMOD_RESULT DSP::getSpeakerActive(FMOD_SPEAKER speaker, bool *active)
|
||||
{
|
||||
FMOD_RESULT result;
|
||||
DSPI *dspi;
|
||||
|
||||
result = DSPI::validate(this, &dspi);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
return dspi->getSpeakerActive(speaker, active);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
FMOD_RESULT DSP::reset()
|
||||
{
|
||||
FMOD_RESULT result;
|
||||
DSPI *dspi;
|
||||
|
||||
result = DSPI::validate(this, &dspi);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
return dspi->reset();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
FMOD_RESULT DSP::setParameter(int index, float value)
|
||||
{
|
||||
FMOD_RESULT result;
|
||||
DSPI *dspi;
|
||||
|
||||
result = DSPI::validate(this, &dspi);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
return dspi->setParameter(index, value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
FMOD_RESULT DSP::getParameter(int index, float *value, char *valuestr, int valuestrlen)
|
||||
{
|
||||
FMOD_RESULT result;
|
||||
DSPI *dspi;
|
||||
|
||||
result = DSPI::validate(this, &dspi);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
return dspi->getParameter(index, value, valuestr, valuestrlen);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
FMOD_RESULT DSP::getNumParameters(int *numparams)
|
||||
{
|
||||
FMOD_RESULT result;
|
||||
DSPI *dspi;
|
||||
|
||||
result = DSPI::validate(this, &dspi);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
return dspi->getNumParameters(numparams);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
FMOD_RESULT DSP::getParameterInfo(int index, char *name, char *label, char *description, int descriptionlen, float *min, float *max)
|
||||
{
|
||||
FMOD_RESULT result;
|
||||
DSPI *dspi;
|
||||
|
||||
result = DSPI::validate(this, &dspi);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
return dspi->getParameterInfo(index, name, label, description, descriptionlen, min, max);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
FMOD_RESULT DSP::showConfigDialog(void *hwnd, bool show)
|
||||
{
|
||||
FMOD_RESULT result;
|
||||
DSPI *dspi;
|
||||
|
||||
result = DSPI::validate(this, &dspi);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
return dspi->showConfigDialog(hwnd, show);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
FMOD_RESULT DSP::getInfo(char *name, unsigned int *version, int *channels, int *configwidth, int *configheight)
|
||||
{
|
||||
FMOD_RESULT result;
|
||||
DSPI *dspi;
|
||||
|
||||
result = DSPI::validate(this, &dspi);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
return dspi->getInfo(name, version, channels, configwidth, configheight);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
FMOD_RESULT DSP::getType(FMOD_DSP_TYPE *type)
|
||||
{
|
||||
FMOD_RESULT result;
|
||||
DSPI *dspi;
|
||||
|
||||
result = DSPI::validate(this, &dspi);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
return dspi->getType(type);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
FMOD_RESULT DSP::setDefaults(float frequency, float volume, float pan, int priority)
|
||||
{
|
||||
FMOD_RESULT result;
|
||||
DSPI *dspi;
|
||||
|
||||
result = DSPI::validate(this, &dspi);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
return dspi->setDefaults(frequency, volume, pan, priority);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
FMOD_RESULT DSP::getDefaults(float *frequency, float *volume, float *pan, int *priority)
|
||||
{
|
||||
FMOD_RESULT result;
|
||||
DSPI *dspi;
|
||||
|
||||
result = DSPI::validate(this, &dspi);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
return dspi->getDefaults(frequency, volume, pan, priority);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
FMOD_RESULT DSP::setUserData(void *_userdata)
|
||||
{
|
||||
FMOD_RESULT result;
|
||||
DSPI *dspi;
|
||||
|
||||
result = DSPI::validate(this, &dspi);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
return dspi->setUserData(_userdata);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
FMOD_RESULT DSP::getUserData(void **_userdata)
|
||||
{
|
||||
FMOD_RESULT result;
|
||||
DSPI *dspi;
|
||||
|
||||
result = DSPI::validate(this, &dspi);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
return dspi->getUserData(_userdata);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
FMOD_RESULT DSP::getMemoryInfo(unsigned int memorybits, unsigned int event_memorybits, unsigned int *memoryused, FMOD_MEMORY_USAGE_DETAILS *memoryused_details)
|
||||
{
|
||||
FMOD_RESULT result;
|
||||
DSPI *dspi;
|
||||
|
||||
result = DSPI::validate(this, &dspi);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
return dspi->getMemoryInfo(memorybits, event_memorybits, memoryused, memoryused_details);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*$ preserve start $*/
|
||||
}
|
||||
/*$ preserve end $*/
|
||||
771
src/fmod_dsp_chorus.cpp
Executable file
771
src/fmod_dsp_chorus.cpp
Executable file
|
|
@ -0,0 +1,771 @@
|
|||
#include "fmod_settings.h"
|
||||
|
||||
#ifdef FMOD_SUPPORT_CHORUS
|
||||
|
||||
#include "fmod.h"
|
||||
#include "fmod_dspi.h"
|
||||
#include "fmod_dsp_chorus.h"
|
||||
#include "fmod_systemi.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
namespace FMOD
|
||||
{
|
||||
|
||||
FMOD_DSP_DESCRIPTION_EX dspchorus;
|
||||
|
||||
#ifdef PLUGIN_EXPORTS
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
FMODGetDSPDescription is mandantory for every fmod plugin. This is the symbol the registerplugin function searches for.
|
||||
Must be declared with F_API to make it export as stdcall.
|
||||
*/
|
||||
F_DECLSPEC F_DLLEXPORT FMOD_DSP_DESCRIPTION_EX * F_API FMODGetDSPDescriptionEx()
|
||||
{
|
||||
return DSPChorus::getDescriptionEx();
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* PLUGIN_EXPORTS */
|
||||
|
||||
|
||||
FMOD_DSP_PARAMETERDESC dspchorus_param[8] =
|
||||
{
|
||||
{ 0.0f, 1.0f, 0.50f, "Dry mix", "", "Volume of original signal to pass to output. 0.0 to 1.0. Default = 0.5." },
|
||||
{ 0.0f, 1.0f, 0.50f, "Wet mix tap 1", "", "Volume of 1st chorus tap. 0.0 to 1.0. Default = 0.5." },
|
||||
{ 0.0f, 1.0f, 0.50f, "Wet mix tap 2", "", "Volume of 2nd chorus tap. This tap is 90 degrees out of phase of the first tap. 0.0 to 1.0. Default = 0.5." },
|
||||
{ 0.0f, 1.0f, 0.50f, "Wet mix tap 3", "", "Volume of 3rd chorus tap. This tap is 90 degrees out of phase of the second tap. 0.0 to 1.0. Default = 0.5." },
|
||||
{ 0.0f, 100.0f, 40.00f, "Delay", "ms", "Chorus delay in ms. 0.1 to 100.0. Default = 40.0 ms." },
|
||||
{ 0.0f, 20.0f, 0.80f, "Rate", "hz", "Chorus modulation rate in hz. 0.0 to 20.0. Default = 0.8 hz." },
|
||||
{ 0.0f, 1.0f, 0.03f, "Depth", "", "Chorus modulation depth. 0.0 to 1.0. Default = 0.03." },
|
||||
{ 0.0f, 1.0f, 0.00f, "Feedback", "", "Chorus feedback. Controls how much of the wet signal gets fed back into the chorus buffer. 0.0 to 1.0. Default = 0.0." }
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_DSP_DESCRIPTION_EX *DSPChorus::getDescriptionEx()
|
||||
{
|
||||
FMOD_memset(&dspchorus, 0, sizeof(FMOD_DSP_DESCRIPTION_EX));
|
||||
|
||||
FMOD_strcpy(dspchorus.name, "FMOD Chorus");
|
||||
dspchorus.version = 0x00010100;
|
||||
dspchorus.create = DSPChorus::createCallback;
|
||||
dspchorus.release = DSPChorus::releaseCallback;
|
||||
dspchorus.reset = DSPChorus::resetCallback;
|
||||
dspchorus.read = DSPChorus::readCallback;
|
||||
|
||||
dspchorus.numparameters = sizeof(dspchorus_param) / sizeof(dspchorus_param[0]);
|
||||
dspchorus.paramdesc = dspchorus_param;
|
||||
dspchorus.setparameter = DSPChorus::setParameterCallback;
|
||||
dspchorus.getparameter = DSPChorus::getParameterCallback;
|
||||
#ifdef FMOD_SUPPORT_MEMORYTRACKER
|
||||
dspchorus.getmemoryused = &DSPChorus::getMemoryUsedCallback;
|
||||
#endif
|
||||
|
||||
dspchorus.mType = FMOD_DSP_TYPE_CHORUS;
|
||||
dspchorus.mCategory = FMOD_DSP_CATEGORY_FILTER;
|
||||
dspchorus.mSize = sizeof(DSPChorus);
|
||||
|
||||
return &dspchorus;
|
||||
}
|
||||
|
||||
#ifdef DSP_CHORUS_USECOSTAB
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_INLINE const float DSPChorus::cosine(float x)
|
||||
{
|
||||
int y;
|
||||
|
||||
x *= DSP_CHORUS_TABLERANGE;
|
||||
y = (int)x;
|
||||
if (y < 0)
|
||||
{
|
||||
y = -y;
|
||||
}
|
||||
|
||||
y &= DSP_CHORUS_TABLEMASK;
|
||||
switch (y >> DSP_CHORUS_COSTABBITS)
|
||||
{
|
||||
case 0 : return mCosTab[y];
|
||||
case 1 : return -mCosTab[(DSP_CHORUS_COSTABSIZE - 1) - (y - (DSP_CHORUS_COSTABSIZE * 1))];
|
||||
case 2 : return -mCosTab[ (y - (DSP_CHORUS_COSTABSIZE * 2))];
|
||||
case 3 : return mCosTab[(DSP_CHORUS_COSTABSIZE - 1) - (y - (DSP_CHORUS_COSTABSIZE * 3))];
|
||||
}
|
||||
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_INLINE const float DSPChorus::sine(float x)
|
||||
{
|
||||
return cosine(x - 0.25f);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT DSPChorus::createInternal()
|
||||
{
|
||||
FMOD_RESULT result;
|
||||
int inchannels, outchannels, channels, count;
|
||||
|
||||
init();
|
||||
mOldSpeakerMask = 0xFFFF;
|
||||
|
||||
#ifdef DSP_CHORUS_USECOSTAB
|
||||
{
|
||||
int count;
|
||||
|
||||
for (count = 0; count < DSP_CHORUS_COSTABSIZE; count++)
|
||||
{
|
||||
mCosTab[count] = (float)FMOD_COS(FMOD_PI_2 * (float)count / (float)DSP_CHORUS_COSTABSIZE);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
result = mSystem->getSoftwareFormat(&mOutputRate, 0, &outchannels, &inchannels, 0, 0);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
channels = inchannels > outchannels ? inchannels : outchannels;
|
||||
|
||||
mChorusBufferLengthBytes = (int)((float)mOutputRate * DSP_CHORUS_MAXBUFFERLENGTHMS) / 1000;
|
||||
mChorusBufferLengthBytes *= channels;
|
||||
mChorusBufferLengthBytes *= sizeof(signed short);
|
||||
mChorusBufferLengthBytes += 1024;
|
||||
|
||||
mChorusBuffer = (signed short *)FMOD_Memory_Calloc(mChorusBufferLengthBytes);
|
||||
if (!mChorusBuffer)
|
||||
{
|
||||
return FMOD_ERR_MEMORY;
|
||||
}
|
||||
|
||||
mChorusTick = 0;
|
||||
|
||||
for (count = 0; count < mDescription.numparameters; count++)
|
||||
{
|
||||
result = setParameter(count, mDescription.paramdesc[count].defaultval);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT DSPChorus::releaseInternal()
|
||||
{
|
||||
if (mChorusBuffer)
|
||||
{
|
||||
FMOD_Memory_Free(mChorusBuffer);
|
||||
mChorusBuffer = 0;
|
||||
}
|
||||
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT DSPChorus::resetInternal()
|
||||
{
|
||||
mChorusBufferPosition = 0;
|
||||
|
||||
if (mChorusBuffer)
|
||||
{
|
||||
FMOD_memset(mChorusBuffer, 0, mChorusBufferLengthBytes);
|
||||
}
|
||||
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT DSPChorus::readInternal(float *inbuffer, float *outbuffer, unsigned int length, int inchannels, int outchannels)
|
||||
{
|
||||
unsigned int count;
|
||||
int halfchorusbufferlength = mChorusBufferLength / 2;
|
||||
float halfdepth = mDepth * 0.5f;
|
||||
|
||||
if (!inbuffer)
|
||||
{
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
||||
if (speakermask != mOldSpeakerMask) /* a channel has been deactivated: clear the buffer for that channels so that there isn't any artifacts if/when it is reenabled. */
|
||||
{
|
||||
unsigned int diff = mOldSpeakerMask ^ speakermask;
|
||||
for (count = 0; count < (unsigned int)inchannels; count++)
|
||||
{
|
||||
if (diff & (1 << count))
|
||||
{
|
||||
short *buff = mChorusBuffer + count;
|
||||
for (count=0; count < mChorusBufferLength; count++)
|
||||
{
|
||||
buff[0]=0;
|
||||
buff += inchannels;
|
||||
}
|
||||
}
|
||||
}
|
||||
mOldSpeakerMask = speakermask;
|
||||
}
|
||||
|
||||
if (!(speakermask & ((1 << inchannels)-1))) /*No channels are active, copy in buffer to out buffer and skip the DSP*/
|
||||
{
|
||||
FMOD_memcpy(outbuffer, inbuffer, sizeof(float)*length*inchannels);
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
||||
for (count=0; count < length; count++)
|
||||
{
|
||||
unsigned int p1[3], p2[3];
|
||||
float frac[3];
|
||||
int count2;
|
||||
|
||||
p1[0] = (mChorusBufferPosition + (unsigned int)mChorusPosition[0]) % mChorusBufferLength;
|
||||
p1[1] = (mChorusBufferPosition + (unsigned int)mChorusPosition[1]) % mChorusBufferLength;
|
||||
p1[2] = (mChorusBufferPosition + (unsigned int)mChorusPosition[2]) % mChorusBufferLength;
|
||||
p2[0] = p1[0] + 1; /* the first sample of the buffer has been duplicated to the end so it wont click. */
|
||||
p2[1] = p1[1] + 1; /* the first sample of the buffer has been duplicated to the end so it wont click. */
|
||||
p2[2] = p1[2] + 1; /* the first sample of the buffer has been duplicated to the end so it wont click. */
|
||||
|
||||
frac[0] = mChorusPosition[0] - (int)mChorusPosition[0];
|
||||
frac[1] = mChorusPosition[1] - (int)mChorusPosition[1];
|
||||
frac[2] = mChorusPosition[2] - (int)mChorusPosition[2];
|
||||
|
||||
for (count2 = 0; count2 < inchannels; count2++)
|
||||
{
|
||||
int offset = (count * inchannels) + count2;
|
||||
|
||||
if (!((1 << count2) & speakermask))
|
||||
{
|
||||
outbuffer[offset] = inbuffer[offset];
|
||||
}
|
||||
else
|
||||
{
|
||||
float val;
|
||||
float chorusval;
|
||||
|
||||
val = inbuffer[offset] * mDryMix * 32768.0f;
|
||||
|
||||
val += ((mChorusBuffer[(p1[0] * inchannels) + count2] * (1.0f - frac[0])) + (mChorusBuffer[(p2[0] * inchannels) + count2] * frac[0])) * mWetMix1;
|
||||
val += ((mChorusBuffer[(p1[1] * inchannels) + count2] * (1.0f - frac[1])) + (mChorusBuffer[(p2[1] * inchannels) + count2] * frac[1])) * mWetMix2;
|
||||
val += ((mChorusBuffer[(p1[2] * inchannels) + count2] * (1.0f - frac[2])) + (mChorusBuffer[(p2[2] * inchannels) + count2] * frac[2])) * mWetMix3;
|
||||
|
||||
chorusval = (inbuffer[offset] * 32767.0f) + val * mFeedback;
|
||||
|
||||
mChorusBuffer[(mChorusBufferPosition * inchannels) + count2] = chorusval < -32768.0f ? -32768 : chorusval > 32767.0f ? 32767 : (signed short)chorusval;
|
||||
|
||||
outbuffer[offset] = val / 32767.0f;
|
||||
}
|
||||
}
|
||||
|
||||
if (!mChorusBufferPosition)
|
||||
{
|
||||
for (count2 = 0; count2 < inchannels; count2++)
|
||||
{
|
||||
if ((1 << count2) & speakermask)
|
||||
{
|
||||
mChorusBuffer[(mChorusBufferLength * inchannels) + count2] = mChorusBuffer[count2];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mChorusBufferPosition++;
|
||||
if (mChorusBufferPosition >= mChorusBufferLength)
|
||||
{
|
||||
mChorusBufferPosition = 0;
|
||||
}
|
||||
|
||||
#ifdef DSP_CHORUS_USECOSTAB
|
||||
mChorusPosition[0] = (1.0f + sine(mChorusTick + 0.00f)) * halfdepth;
|
||||
mChorusPosition[1] = (1.0f + sine(mChorusTick + 0.25f)) * halfdepth;
|
||||
mChorusPosition[2] = (1.0f + sine(mChorusTick + 0.50f)) * halfdepth;
|
||||
#else
|
||||
mChorusPosition[0] = (1.0f + sine((mChorusTick + 0.00f) * FMOD_PI2)) * halfdepth;
|
||||
mChorusPosition[1] = (1.0f + sine((mChorusTick + 0.25f) * FMOD_PI2)) * halfdepth;
|
||||
mChorusPosition[2] = (1.0f + sine((mChorusTick + 0.50f) * FMOD_PI2)) * halfdepth;
|
||||
#endif
|
||||
|
||||
mChorusPosition[0] = halfchorusbufferlength + (mChorusPosition[0] * mChorusBufferLength);
|
||||
mChorusPosition[1] = halfchorusbufferlength + (mChorusPosition[1] * mChorusBufferLength);
|
||||
mChorusPosition[2] = halfchorusbufferlength + (mChorusPosition[2] * mChorusBufferLength);
|
||||
|
||||
mChorusTick += mChorusSpeed;
|
||||
}
|
||||
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT DSPChorus::setParameterInternal(int index, float value)
|
||||
{
|
||||
float olddelay;
|
||||
|
||||
olddelay = mDelay;
|
||||
|
||||
mSystem->lockDSP();
|
||||
|
||||
switch (index)
|
||||
{
|
||||
case FMOD_DSP_CHORUS_DRYMIX:
|
||||
{
|
||||
mDryMix = value;
|
||||
break;
|
||||
}
|
||||
case FMOD_DSP_CHORUS_WETMIX1:
|
||||
{
|
||||
mWetMix1 = value;
|
||||
break;
|
||||
}
|
||||
case FMOD_DSP_CHORUS_WETMIX2:
|
||||
{
|
||||
mWetMix2 = value;
|
||||
break;
|
||||
}
|
||||
case FMOD_DSP_CHORUS_WETMIX3:
|
||||
{
|
||||
mWetMix3 = value;
|
||||
break;
|
||||
}
|
||||
case FMOD_DSP_CHORUS_DELAY:
|
||||
{
|
||||
mDelay = value;
|
||||
break;
|
||||
}
|
||||
case FMOD_DSP_CHORUS_RATE:
|
||||
{
|
||||
mRateHz = value;
|
||||
break;
|
||||
}
|
||||
case FMOD_DSP_CHORUS_DEPTH:
|
||||
{
|
||||
mDepth = value;
|
||||
break;
|
||||
}
|
||||
case FMOD_DSP_CHORUS_FEEDBACK:
|
||||
{
|
||||
mFeedback = value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (mDelay != olddelay)
|
||||
{
|
||||
mChorusBufferLength = (int)((float)mOutputRate * mDelay / 1000.0f) * 2;
|
||||
if (mChorusBufferLength < 4)
|
||||
{
|
||||
mChorusBufferLength = 4;
|
||||
}
|
||||
|
||||
resetInternal();
|
||||
}
|
||||
|
||||
mChorusSpeed = mRateHz / (float)mOutputRate;
|
||||
|
||||
mSystem->unlockDSP();
|
||||
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT DSPChorus::getParameterInternal(int index, float *value, char *valuestr)
|
||||
{
|
||||
switch (index)
|
||||
{
|
||||
case FMOD_DSP_CHORUS_DRYMIX:
|
||||
{
|
||||
*value = mDryMix;
|
||||
sprintf(valuestr, "%.02f", mDryMix);
|
||||
break;
|
||||
}
|
||||
case FMOD_DSP_CHORUS_WETMIX1:
|
||||
{
|
||||
*value = mWetMix1;
|
||||
sprintf(valuestr, "%.02f", mWetMix1);
|
||||
break;
|
||||
}
|
||||
case FMOD_DSP_CHORUS_WETMIX2:
|
||||
{
|
||||
*value = mWetMix2;
|
||||
sprintf(valuestr, "%.02f", mWetMix2);
|
||||
break;
|
||||
}
|
||||
case FMOD_DSP_CHORUS_WETMIX3:
|
||||
{
|
||||
*value = mWetMix3;
|
||||
sprintf(valuestr, "%.02f", mWetMix3);
|
||||
break;
|
||||
}
|
||||
case FMOD_DSP_CHORUS_DELAY:
|
||||
{
|
||||
*value = mDelay;
|
||||
sprintf(valuestr, "%.02f", mDelay);
|
||||
break;
|
||||
}
|
||||
case FMOD_DSP_CHORUS_RATE:
|
||||
{
|
||||
*value = mRateHz;
|
||||
sprintf(valuestr, "%.02f", mRateHz);
|
||||
break;
|
||||
}
|
||||
case FMOD_DSP_CHORUS_DEPTH:
|
||||
{
|
||||
*value = mDepth;
|
||||
sprintf(valuestr, "%.02f", mDepth);
|
||||
break;
|
||||
}
|
||||
case FMOD_DSP_CHORUS_FEEDBACK:
|
||||
{
|
||||
*value = mFeedback;
|
||||
sprintf(valuestr, "%.02f", mFeedback);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
|
||||
#ifdef FMOD_SUPPORT_MEMORYTRACKER
|
||||
|
||||
FMOD_RESULT DSPChorus::getMemoryUsedImpl(MemoryTracker *tracker)
|
||||
{
|
||||
// Size of this class is already accounted for (via description.mSize). Just add extra allocated memory here.
|
||||
|
||||
if (mChorusBuffer)
|
||||
{
|
||||
tracker->add(false, FMOD_MEMBITS_DSP, mChorusBufferLengthBytes);
|
||||
}
|
||||
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
==============================================================================================================
|
||||
|
||||
CALLBACK INTERFACE
|
||||
|
||||
==============================================================================================================
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT F_CALLBACK DSPChorus::createCallback(FMOD_DSP_STATE *dsp)
|
||||
{
|
||||
DSPChorus *chorus = (DSPChorus *)dsp;
|
||||
|
||||
return chorus->createInternal();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT F_CALLBACK DSPChorus::releaseCallback(FMOD_DSP_STATE *dsp)
|
||||
{
|
||||
DSPChorus *chorus = (DSPChorus *)dsp;
|
||||
|
||||
return chorus->releaseInternal();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT F_CALLBACK DSPChorus::resetCallback(FMOD_DSP_STATE *dsp)
|
||||
{
|
||||
DSPChorus *chorus = (DSPChorus *)dsp;
|
||||
|
||||
return chorus->resetInternal();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT F_CALLBACK DSPChorus::readCallback(FMOD_DSP_STATE *dsp, float *inbuffer, float *outbuffer, unsigned int length, int inchannels, int outchannels)
|
||||
{
|
||||
DSPChorus *chorus = (DSPChorus *)dsp;
|
||||
|
||||
return chorus->readInternal(inbuffer, outbuffer, length, inchannels, outchannels);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT F_CALLBACK DSPChorus::setParameterCallback(FMOD_DSP_STATE *dsp, int index, float value)
|
||||
{
|
||||
DSPChorus *chorus = (DSPChorus *)dsp;
|
||||
|
||||
return chorus->setParameterInternal(index, value);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT F_CALLBACK DSPChorus::getParameterCallback(FMOD_DSP_STATE *dsp, int index, float *value, char *valuestr)
|
||||
{
|
||||
DSPChorus *chorus = (DSPChorus *)dsp;
|
||||
|
||||
return chorus->getParameterInternal(index, value, valuestr);
|
||||
}
|
||||
|
||||
|
||||
#ifdef FMOD_SUPPORT_MEMORYTRACKER
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT F_CALLBACK DSPChorus::getMemoryUsedCallback(FMOD_DSP_STATE *dsp, MemoryTracker *tracker)
|
||||
{
|
||||
DSPChorus *chorus = (DSPChorus *)dsp;
|
||||
|
||||
return chorus->DSPChorus::getMemoryUsed(tracker);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
105
src/fmod_dsp_chorus.h
Executable file
105
src/fmod_dsp_chorus.h
Executable file
|
|
@ -0,0 +1,105 @@
|
|||
#ifndef _FMOD_DSP_CHORUS_H
|
||||
#define _FMOD_DSP_CHORUS_H
|
||||
|
||||
#include "fmod_settings.h"
|
||||
|
||||
#ifdef FMOD_SUPPORT_CHORUS
|
||||
|
||||
#include "fmod.h"
|
||||
#include "fmod_dsp_filter.h"
|
||||
|
||||
namespace FMOD
|
||||
{
|
||||
const int DSP_CHORUS_COSTABBITS = 13;
|
||||
const int DSP_CHORUS_COSTABSIZE = (1 << DSP_CHORUS_COSTABBITS);
|
||||
const int DSP_CHORUS_TABLERANGE = (DSP_CHORUS_COSTABSIZE * 4);
|
||||
const int DSP_CHORUS_TABLEMASK = (DSP_CHORUS_TABLERANGE - 1);
|
||||
const float DSP_CHORUS_MAXBUFFERLENGTHMS = 200.0f;
|
||||
|
||||
#define TEMPBUFFSAMPLES 256
|
||||
#define TEMPBUFFHALFSAMPLES TEMPBUFFSAMPLES / 2
|
||||
|
||||
#if !defined(PLATFORM_PS3) && !defined(PLATFORM_WINDOWS_PS3MODE)
|
||||
#define DSP_CHORUS_USECOSTAB
|
||||
#endif
|
||||
|
||||
class DSPChorus : public DSPFilter
|
||||
{
|
||||
DECLARE_MEMORYTRACKER_NONVIRTUAL
|
||||
|
||||
private:
|
||||
|
||||
FMOD_PPCALIGN16(float mDepth);
|
||||
FMOD_PPCALIGN16(float mDryMix);
|
||||
FMOD_PPCALIGN16(float mWetMix1);
|
||||
FMOD_PPCALIGN16(float mWetMix2);
|
||||
FMOD_PPCALIGN16(float mWetMix3);
|
||||
FMOD_PPCALIGN16(float mFeedback);
|
||||
FMOD_PPCALIGN16(float mDelay);
|
||||
FMOD_PPCALIGN16(float mRateHz);
|
||||
FMOD_PPCALIGN16(signed short *mChorusBuffer);
|
||||
FMOD_PPCALIGN16(signed short *mChorusBufferMemory);
|
||||
FMOD_PPCALIGN16(unsigned int mChorusBufferLength);
|
||||
FMOD_PPCALIGN16(unsigned int mChorusBufferLengthBytes);
|
||||
FMOD_PPCALIGN16(unsigned int mChorusBufferPosition);
|
||||
FMOD_PPCALIGN16(float mChorusPosition[3]);
|
||||
FMOD_PPCALIGN16(float mChorusTick);
|
||||
FMOD_PPCALIGN16(float mChorusSpeed);
|
||||
FMOD_PPCALIGN16(int mOutputRate);
|
||||
unsigned short mOldSpeakerMask;
|
||||
|
||||
#if defined(PLATFORM_PS3) || defined(PLATFORM_WINDOWS_PS3MODE)
|
||||
FMOD_PPCALIGN16(int mMinPos0_A);
|
||||
FMOD_PPCALIGN16(int mMaxPos0_A);
|
||||
FMOD_PPCALIGN16(int mMinPos0_B);
|
||||
FMOD_PPCALIGN16(int mMaxPos0_B);
|
||||
FMOD_PPCALIGN16(int mMinPos1_A);
|
||||
FMOD_PPCALIGN16(int mMaxPos1_A);
|
||||
FMOD_PPCALIGN16(int mMinPos1_B);
|
||||
FMOD_PPCALIGN16(int mMaxPos1_B);
|
||||
FMOD_PPCALIGN16(int mMinPos2_A);
|
||||
FMOD_PPCALIGN16(int mMaxPos2_A);
|
||||
FMOD_PPCALIGN16(int mMinPos2_B);
|
||||
FMOD_PPCALIGN16(int mMaxPos2_B);
|
||||
FMOD_PPCALIGN16(signed short mTempBuff0[4096 + 8]);
|
||||
FMOD_PPCALIGN16(signed short mTempBuff1[4096 + 8]);
|
||||
FMOD_PPCALIGN16(signed short mTempBuff2[4096 + 8]);
|
||||
#endif
|
||||
|
||||
#ifdef DSP_CHORUS_USECOSTAB
|
||||
float mCosTab[DSP_CHORUS_COSTABSIZE];
|
||||
|
||||
FMOD_INLINE const float cosine(float x);
|
||||
FMOD_INLINE const float sine(float x);
|
||||
#else
|
||||
FMOD_INLINE const float cosine(float x) { return FMOD_COS(x); }
|
||||
FMOD_INLINE const float sine(float x) { return FMOD_SIN(x); }
|
||||
#endif
|
||||
|
||||
FMOD_RESULT createInternal();
|
||||
FMOD_RESULT releaseInternal();
|
||||
FMOD_RESULT resetInternal();
|
||||
FMOD_RESULT readInternal(float *inbuffer, float *outbuffer, unsigned int length, int inchannels, int outchannels);
|
||||
FMOD_RESULT setParameterInternal(int index, float value);
|
||||
FMOD_RESULT getParameterInternal(int index, float *value, char *valuestr);
|
||||
|
||||
public:
|
||||
|
||||
static FMOD_DSP_DESCRIPTION_EX *getDescriptionEx();
|
||||
|
||||
static FMOD_RESULT F_CALLBACK createCallback(FMOD_DSP_STATE *dsp);
|
||||
static FMOD_RESULT F_CALLBACK releaseCallback(FMOD_DSP_STATE *dsp);
|
||||
static FMOD_RESULT F_CALLBACK resetCallback(FMOD_DSP_STATE *dsp);
|
||||
static FMOD_RESULT F_CALLBACK readCallback(FMOD_DSP_STATE *dsp, float *inbuffer, float *outbuffer, unsigned int length, int inchannels, int outchannels);
|
||||
static FMOD_RESULT F_CALLBACK setParameterCallback(FMOD_DSP_STATE *dsp, int index, float value);
|
||||
static FMOD_RESULT F_CALLBACK getParameterCallback(FMOD_DSP_STATE *dsp, int index, float *value, char *valuestr);
|
||||
#ifdef FMOD_SUPPORT_MEMORYTRACKER
|
||||
static FMOD_RESULT F_CALLBACK getMemoryUsedCallback(FMOD_DSP_STATE *dsp, MemoryTracker *tracker);
|
||||
#endif
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
1124
src/fmod_dsp_codec.cpp
Executable file
1124
src/fmod_dsp_codec.cpp
Executable file
File diff suppressed because it is too large
Load diff
170
src/fmod_dsp_codec.h
Executable file
170
src/fmod_dsp_codec.h
Executable file
|
|
@ -0,0 +1,170 @@
|
|||
#ifndef _FMOD_DSP_CODEC_H
|
||||
#define _FMOD_DSP_CODEC_H
|
||||
|
||||
#include "fmod_settings.h"
|
||||
|
||||
#ifdef FMOD_SUPPORT_DSPCODEC
|
||||
|
||||
#include "fmod.h"
|
||||
#include "fmod_dsp_codecpool.h"
|
||||
#include "fmod_dsp_resampler.h"
|
||||
|
||||
#ifdef PLATFORM_PS3
|
||||
#include "fmod_file_dma.h"
|
||||
#else
|
||||
#include "fmod_file_memory.h"
|
||||
#endif
|
||||
|
||||
#ifdef FMOD_SUPPORT_MPEG
|
||||
#include "fmod_codec_mpeg.h"
|
||||
#endif
|
||||
|
||||
#ifdef FMOD_SUPPORT_IMAADPCM
|
||||
#include "fmod_codec_wav.h"
|
||||
#endif
|
||||
|
||||
#ifdef FMOD_SUPPORT_XMA
|
||||
#include "fmod_codec_xma.h"
|
||||
#endif
|
||||
|
||||
#ifdef FMOD_SUPPORT_CELT
|
||||
#include "fmod_codec_celt.h"
|
||||
#endif
|
||||
|
||||
#include "fmod_codec_raw.h"
|
||||
|
||||
#ifndef _FMOD_MEMORYTRACKER_H
|
||||
#include "fmod_memorytracker.h"
|
||||
#endif
|
||||
|
||||
namespace FMOD
|
||||
{
|
||||
class DSPCodecPool;
|
||||
class DSPCodecPoolInitCleanup;
|
||||
class SoundI;
|
||||
|
||||
class DSPCodec : public DSPResampler
|
||||
{
|
||||
DECLARE_MEMORYTRACKER_NONVIRTUAL
|
||||
|
||||
friend class DSPCodecPool;
|
||||
friend class DSPResampler;
|
||||
friend class DSPCodecPoolInitCleanup;
|
||||
|
||||
private:
|
||||
|
||||
FMOD_RESULT createInternal();
|
||||
FMOD_RESULT release(bool freethis = true);
|
||||
FMOD_RESULT releaseInternal();
|
||||
FMOD_RESULT resetInternal();
|
||||
FMOD_RESULT readInternal(signed short *inbuffer, signed short *outbuffer, unsigned int length, int inchannels, int outchannels);
|
||||
FMOD_RESULT setPositionInternal(unsigned int pos, bool fromspu = false);
|
||||
FMOD_RESULT getPositionInternal(unsigned int *pos);
|
||||
FMOD_RESULT setParameterInternal(int index, float value);
|
||||
FMOD_RESULT getParameterInternal(int index, float *value, char *valuestr);
|
||||
#ifdef FMOD_SUPPORT_SENTENCING
|
||||
FMOD_RESULT updateDSPCodec(SoundI *sound, int subsoundindex);
|
||||
#endif
|
||||
|
||||
public:
|
||||
|
||||
DSPCodecPool *mPool;
|
||||
|
||||
#ifdef PLATFORM_PS3
|
||||
DMAFile mMemoryFile;
|
||||
#else
|
||||
MemoryFile mMemoryFile;
|
||||
#endif
|
||||
|
||||
FMOD_PPCALIGN16(unsigned int mPosition);
|
||||
FMOD_PPCALIGN16(unsigned int mNewPosition);
|
||||
FMOD_PPCALIGN16(unsigned int mSetPosIncrementPrev);
|
||||
FMOD_PPCALIGN16(unsigned int mLoopCountIncrementPrev);
|
||||
FMOD_PPCALIGN16(int mPoolIndex);
|
||||
FMOD_PPCALIGN16(int mSubSoundListCurrent);
|
||||
FMOD_PPCALIGN16(int mSubSoundListNum);
|
||||
|
||||
FMOD_CODEC_WAVEFORMAT mWaveFormat;
|
||||
Codec *mCodec;
|
||||
|
||||
FMOD_RESULT freeFromPool() { mPool->mAllocated[mPoolIndex] = false; return FMOD_OK; }
|
||||
|
||||
static FMOD_DSP_DESCRIPTION_EX *getDescriptionEx();
|
||||
|
||||
static FMOD_RESULT F_CALLBACK createCallback(FMOD_DSP_STATE *dsp);
|
||||
static FMOD_RESULT F_CALLBACK releaseCallback(FMOD_DSP_STATE *dsp);
|
||||
static FMOD_RESULT F_CALLBACK resetCallback(FMOD_DSP_STATE *dsp);
|
||||
static FMOD_RESULT F_CALLBACK readCallback(FMOD_DSP_STATE *dsp, float *inbuffer, float *outbuffer, unsigned int length, int inchannels, int outchannels);
|
||||
static FMOD_RESULT F_CALLBACK setPositionCallback(FMOD_DSP_STATE *dsp, unsigned int pos);
|
||||
static FMOD_RESULT F_CALLBACK getPositionCallback(FMOD_DSP_STATE *dsp, unsigned int *pos);
|
||||
static FMOD_RESULT F_CALLBACK setParameterCallback(FMOD_DSP_STATE *dsp, int index, float value);
|
||||
static FMOD_RESULT F_CALLBACK getParameterCallback(FMOD_DSP_STATE *dsp, int index, float *value, char *valuestr);
|
||||
};
|
||||
|
||||
#ifdef FMOD_SUPPORT_MPEG
|
||||
class DSPCodecMPEG : public DSPCodec
|
||||
{
|
||||
DECLARE_MEMORYTRACKER_NONVIRTUAL
|
||||
|
||||
public:
|
||||
char mResampleBufferMemory[((1152 + (FMOD_DSP_RESAMPLER_OVERFLOWLENGTH * 4)) * sizeof(short) * 2 * 2) + 16]; // *2 = stereo max. *2 = double buffer.
|
||||
CodecMPEG mCodecMemory;
|
||||
FMOD_PPCALIGN16(CodecMPEG_MemoryBlock mCodecMemoryBlock); /* CellMP3Context for Sony decoder needs to be 16 byte aligned */
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef FMOD_SUPPORT_IMAADPCM
|
||||
class DSPCodecADPCM : public DSPCodec
|
||||
{
|
||||
DECLARE_MEMORYTRACKER_NONVIRTUAL
|
||||
|
||||
public:
|
||||
char mResampleBufferMemory[((64 + (FMOD_DSP_RESAMPLER_OVERFLOWLENGTH * 4)) * sizeof(short) * 2 * 2) + 16]; // *2 = stereo max. *2 = double buffer.
|
||||
CodecWav mCodecMemory;
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef FMOD_SUPPORT_XMA
|
||||
class DSPCodecXMA : public DSPCodec
|
||||
{
|
||||
DECLARE_MEMORYTRACKER_NONVIRTUAL
|
||||
|
||||
public:
|
||||
char mResampleBufferMemory[((512 + (FMOD_DSP_RESAMPLER_OVERFLOWLENGTH * 4)) * sizeof(short) * 2 * 2) + 16]; // *2 = stereo max. *2 = double buffer.
|
||||
CodecXMA mCodecMemory;
|
||||
#ifdef FMOD_SUPPORT_XMA_NEWHAL
|
||||
CodecXMA_DecoderData mCodecMemoryBlock;
|
||||
#else
|
||||
CodecXMA_DecoderHW mCodecMemoryBlock;
|
||||
#endif
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef FMOD_SUPPORT_CELT
|
||||
class DSPCodecCELT : public DSPCodec
|
||||
{
|
||||
DECLARE_MEMORYTRACKER_NONVIRTUAL
|
||||
|
||||
public:
|
||||
char mResampleBufferMemory[((FMOD_CELT_FRAMESIZESAMPLES + (FMOD_DSP_RESAMPLER_OVERFLOWLENGTH * 4)) * sizeof(short) * 2 * 2) + 16]; // *2 = stereo max. *2 = double buffer.
|
||||
CodecCELT mCodecMemory;
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef FMOD_SUPPORT_RAW
|
||||
class DSPCodecRaw : public DSPCodec
|
||||
{
|
||||
DECLARE_MEMORYTRACKER_NONVIRTUAL
|
||||
|
||||
public:
|
||||
char mResampleBufferMemory[((256 + (FMOD_DSP_RESAMPLER_OVERFLOWLENGTH * 4)) * sizeof(short) * 16 * 2) + 16]; // *16 = 16 channel max. *2 = double buffer.
|
||||
CodecRaw mCodecMemory;
|
||||
};
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
520
src/fmod_dsp_codecpool.cpp
Executable file
520
src/fmod_dsp_codecpool.cpp
Executable file
|
|
@ -0,0 +1,520 @@
|
|||
#include "fmod_settings.h"
|
||||
|
||||
#ifdef FMOD_SUPPORT_DSPCODEC
|
||||
|
||||
#include "fmod_channel_software.h"
|
||||
#ifdef FMOD_SUPPORT_MPEG
|
||||
#include "fmod_codec_mpeg.h"
|
||||
#endif
|
||||
#ifdef FMOD_SUPPORT_XMA
|
||||
#include "fmod_codec_xma.h"
|
||||
#endif
|
||||
#ifdef FMOD_SUPPORT_IMAADPCM
|
||||
#include "fmod_codec_wav_imaadpcm.h"
|
||||
#endif
|
||||
#include "fmod_autocleanup.h"
|
||||
#include "fmod_codeci.h"
|
||||
#include "fmod_dspi.h"
|
||||
#include "fmod_dsp_codec.h"
|
||||
#include "fmod_dsp_codecpool.h"
|
||||
#include "fmod_pluginfactory.h"
|
||||
#include "fmod_systemi.h"
|
||||
#include "fmod_localcriticalsection.h"
|
||||
|
||||
namespace FMOD
|
||||
{
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
|
||||
class DSPCodecPoolInitCleanup
|
||||
{
|
||||
public:
|
||||
DSPCodecPoolInitCleanup()
|
||||
: mPool(0), mPoolSize(0)
|
||||
{ }
|
||||
|
||||
void setPool(DSPCodec **pool, int poolsize)
|
||||
{
|
||||
mPool = pool;
|
||||
mPoolSize = poolsize;
|
||||
}
|
||||
|
||||
void cleanup(bool)
|
||||
{
|
||||
if (mPool)
|
||||
{
|
||||
for (int i = 0; i < mPoolSize; ++i)
|
||||
{
|
||||
if (mPool[i])
|
||||
{
|
||||
mPool[i]->release();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
DSPCodec **mPool;
|
||||
int mPoolSize;
|
||||
};
|
||||
|
||||
FMOD_RESULT DSPCodecPool::init(FMOD_DSP_CATEGORY category, int resamplerpcmblocksize, int numdspcodecs)
|
||||
{
|
||||
int count;
|
||||
FMOD_DSP_DESCRIPTION_EX descriptionex;
|
||||
AutoCleanup<bool, DSPCodecPoolInitCleanup> initCleanup(true);
|
||||
|
||||
if (!mSystem->mSoftware)
|
||||
{
|
||||
return FMOD_ERR_NEEDSSOFTWARE;
|
||||
}
|
||||
|
||||
if (numdspcodecs >= FMOD_DSP_CODECPOOL_MAXCODECS)
|
||||
{
|
||||
return FMOD_ERR_INVALID_PARAM;
|
||||
}
|
||||
|
||||
LocalCriticalSection crit(mSystem->mDSPCodecPoolInitCrit, true);
|
||||
|
||||
if (mNumDSPCodecs > 0)
|
||||
{
|
||||
// already initialised (probably by another thread)
|
||||
if(mNumDSPCodecs != numdspcodecs)
|
||||
{
|
||||
return FMOD_ERR_INTERNAL;
|
||||
}
|
||||
else
|
||||
{
|
||||
return FMOD_OK;
|
||||
}
|
||||
}
|
||||
|
||||
mPool = (DSPCodec **)FMOD_Memory_CallocType(sizeof(DSPCodec *) * numdspcodecs, FMOD_MEMORY_PERSISTENT);
|
||||
if (!mPool)
|
||||
{
|
||||
return FMOD_ERR_MEMORY;
|
||||
}
|
||||
initCleanup.setPool(mPool, numdspcodecs);
|
||||
|
||||
#if defined(FMOD_SUPPORT_XMA) && defined(FMOD_SUPPORT_XMA_NEWHAL)
|
||||
if (category == FMOD_DSP_CATEGORY_DSPCODECXMA)
|
||||
{
|
||||
mFileBufferPool = (unsigned char *)FMOD_Memory_CallocType(((2048 * 2) * numdspcodecs) + 2048, FMOD_MEMORY_PERSISTENT | FMOD_MEMORY_XBOX360_PHYSICAL); /* + 2048 for alignment. */
|
||||
if (!mFileBufferPool)
|
||||
{
|
||||
return FMOD_ERR_MEMORY;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
descriptionex = *DSPCodec::getDescriptionEx();
|
||||
|
||||
for (count = 0; count < numdspcodecs; count++)
|
||||
{
|
||||
FMOD_RESULT result;
|
||||
DSPI *dsp;
|
||||
DSPCodec *dspcodec;
|
||||
|
||||
descriptionex.channels = 2; // Maximum possible stereo? This is for memory allocation.
|
||||
descriptionex.mFormat = FMOD_SOUND_FORMAT_PCM16;
|
||||
descriptionex.mCategory = category;
|
||||
descriptionex.mResamplerBlockLength = resamplerpcmblocksize;
|
||||
|
||||
if (0)
|
||||
{
|
||||
}
|
||||
#ifdef FMOD_SUPPORT_MPEG
|
||||
if (category == FMOD_DSP_CATEGORY_DSPCODECMPEG)
|
||||
{
|
||||
descriptionex.mSize = sizeof(DSPCodecMPEG);
|
||||
}
|
||||
#endif
|
||||
#ifdef FMOD_SUPPORT_XMA
|
||||
else if (category == FMOD_DSP_CATEGORY_DSPCODECXMA)
|
||||
{
|
||||
descriptionex.mSize = sizeof(DSPCodecXMA);
|
||||
}
|
||||
#endif
|
||||
#ifdef FMOD_SUPPORT_IMAADPCM
|
||||
else if (category == FMOD_DSP_CATEGORY_DSPCODECADPCM)
|
||||
{
|
||||
descriptionex.mSize = sizeof(DSPCodecADPCM);
|
||||
}
|
||||
#endif
|
||||
#ifdef FMOD_SUPPORT_CELT
|
||||
else if (category == FMOD_DSP_CATEGORY_DSPCODECCELT)
|
||||
{
|
||||
descriptionex.mSize = sizeof(DSPCodecCELT);
|
||||
}
|
||||
#endif
|
||||
#ifdef FMOD_SUPPORT_RAW
|
||||
else if (category == FMOD_DSP_CATEGORY_DSPCODECRAW)
|
||||
{
|
||||
descriptionex.mResamplerBlockLength = 256;
|
||||
descriptionex.mSize = sizeof(DSPCodecRaw);
|
||||
}
|
||||
#endif
|
||||
else
|
||||
{
|
||||
return FMOD_ERR_FORMAT;
|
||||
}
|
||||
|
||||
result = mSystem->createDSP(&descriptionex, &dsp);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
AutoRelease<DSPI> dsp_cleanup(dsp);
|
||||
|
||||
dspcodec = SAFE_CAST(DSPCodec, dsp);
|
||||
|
||||
dspcodec->mFlags = 0;
|
||||
|
||||
if (0)
|
||||
{
|
||||
}
|
||||
#ifdef FMOD_SUPPORT_MPEG
|
||||
if (category == FMOD_DSP_CATEGORY_DSPCODECMPEG)
|
||||
{
|
||||
DSPCodecMPEG *dspcodecmpeg = SAFE_CAST(DSPCodecMPEG, dspcodec);
|
||||
CodecMPEG *mpeg = &dspcodecmpeg->mCodecMemory;
|
||||
FMOD_CODEC_DESCRIPTION_EX *desc;
|
||||
|
||||
result = mSystem->mPluginFactory->getCodec(mSystem->mMPEGPluginHandle, &desc);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
FMOD_memcpy(&mpeg->mDescription, desc, sizeof(FMOD_CODEC_DESCRIPTION_EX));
|
||||
mpeg->mDescription.getwaveformat = &Codec::defaultGetWaveFormat;
|
||||
|
||||
dspcodec->mCodec = mpeg;
|
||||
dspcodec->mWaveFormat.format = FMOD_SOUND_FORMAT_MPEG;
|
||||
|
||||
mpeg->mMemoryBlock = &dspcodecmpeg->mCodecMemoryBlock;
|
||||
}
|
||||
#endif
|
||||
#ifdef FMOD_SUPPORT_XMA
|
||||
else if (category == FMOD_DSP_CATEGORY_DSPCODECXMA)
|
||||
{
|
||||
DSPCodecXMA *dspcodecxma = SAFE_CAST(DSPCodecXMA, dspcodec);
|
||||
CodecXMA *xma = &dspcodecxma->mCodecMemory;
|
||||
|
||||
FMOD_memcpy(&xma->mDescription, CodecXMA::getDescriptionEx(), sizeof(FMOD_CODEC_DESCRIPTION_EX));
|
||||
xma->mDescription.getwaveformat = &Codec::defaultGetWaveFormat;
|
||||
dspcodec->mCodec = xma;
|
||||
dspcodec->mWaveFormat.format = FMOD_SOUND_FORMAT_XMA;
|
||||
|
||||
#ifdef FMOD_SUPPORT_XMA_NEWHAL
|
||||
xma->mDecoder = &dspcodecxma->mCodecMemoryBlock;
|
||||
xma->mDecoder->mFileBuffer = (unsigned char *)(FMOD_ALIGNPOINTER(mFileBufferPool, 2048) + (2048 * 2 * count));
|
||||
#else
|
||||
xma->mDecoder = xma->mDecoderHW = &dspcodecxma->mCodecMemoryBlock;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
#ifdef FMOD_SUPPORT_IMAADPCM
|
||||
else if (category == FMOD_DSP_CATEGORY_DSPCODECADPCM)
|
||||
{
|
||||
DSPCodecADPCM *dspcodecadpcm = SAFE_CAST(DSPCodecADPCM, dspcodec);
|
||||
CodecWav *wav = &dspcodecadpcm->mCodecMemory;
|
||||
FMOD_CODEC_DESCRIPTION_EX *desc;
|
||||
|
||||
result = mSystem->mPluginFactory->getCodec(mSystem->mWAVPluginHandle, &desc);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
FMOD_memcpy(&wav->mDescription, desc, sizeof(FMOD_CODEC_DESCRIPTION_EX));
|
||||
wav->mDescription.getwaveformat = &Codec::defaultGetWaveFormat;
|
||||
|
||||
dspcodec->mCodec = wav;
|
||||
dspcodec->mWaveFormat.format = FMOD_SOUND_FORMAT_IMAADPCM;
|
||||
}
|
||||
#endif
|
||||
#ifdef FMOD_SUPPORT_CELT
|
||||
else if (category == FMOD_DSP_CATEGORY_DSPCODECCELT)
|
||||
{
|
||||
DSPCodecCELT *dspcodeccelt = SAFE_CAST(DSPCodecCELT, dspcodec);
|
||||
CodecCELT *celt = &dspcodeccelt->mCodecMemory;
|
||||
FMOD_CODEC_DESCRIPTION_EX *desc;
|
||||
|
||||
result = mSystem->mPluginFactory->getCodec(mSystem->mCELTPluginHandle, &desc);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
FMOD_memcpy(&celt->mDescription, desc, sizeof(FMOD_CODEC_DESCRIPTION_EX));
|
||||
celt->mDescription.getwaveformat = &Codec::defaultGetWaveFormat;
|
||||
|
||||
dspcodec->mCodec = celt;
|
||||
dspcodec->mWaveFormat.format = FMOD_SOUND_FORMAT_CELT;
|
||||
}
|
||||
#endif
|
||||
#ifdef FMOD_SUPPORT_RAW
|
||||
else if (category == FMOD_DSP_CATEGORY_DSPCODECRAW)
|
||||
{
|
||||
DSPCodecRaw *dspcodecraw = SAFE_CAST(DSPCodecRaw, dspcodec);
|
||||
CodecRaw *raw = &dspcodecraw->mCodecMemory;
|
||||
|
||||
FMOD_memcpy(&raw->mDescription, CodecRaw::getDescriptionEx(), sizeof(FMOD_CODEC_DESCRIPTION_EX));
|
||||
raw->mDescription.getwaveformat = &Codec::defaultGetWaveFormat;
|
||||
|
||||
dspcodec->mCodec = raw;
|
||||
dspcodec->mWaveFormat.format = FMOD_SOUND_FORMAT_PCM16;
|
||||
}
|
||||
#endif
|
||||
else
|
||||
{
|
||||
return FMOD_ERR_FORMAT;
|
||||
}
|
||||
|
||||
dspcodec->mCodec->mFile = &dspcodec->mMemoryFile;
|
||||
dspcodec->mCodec->waveformat = &dspcodec->mWaveFormat;
|
||||
dspcodec->mCodec->mSrcDataOffset = 0; /* Raw data is going to be placed right at the start. */
|
||||
dspcodec->mCodec->mFlags |= FMOD_CODEC_ACCURATELENGTH;
|
||||
dspcodec->mPool = this;
|
||||
dspcodec->mPoolIndex = count;
|
||||
dspcodec->setFinished(true, true); /* Start off finished so that it can be allocated. */
|
||||
mAllocated[count] = false;
|
||||
|
||||
dsp_cleanup.releasePtr();
|
||||
mPool[count] = dspcodec;
|
||||
}
|
||||
|
||||
// set this last so places that access it don't jump in too early
|
||||
mNumDSPCodecs = numdspcodecs;
|
||||
|
||||
initCleanup.releasePtr();
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT DSPCodecPool::close()
|
||||
{
|
||||
if (mPool)
|
||||
{
|
||||
int count;
|
||||
|
||||
for (count = 0; count < mNumDSPCodecs; count++)
|
||||
{
|
||||
DSPCodec *dspcodec = SAFE_CAST(DSPCodec, mPool[count]);
|
||||
|
||||
if (dspcodec)
|
||||
{
|
||||
dspcodec->mCodec->mFile = 0; /* Stop it trying to free our static memory file. */
|
||||
dspcodec->mCodec->mReadBuffer = 0; /* Stop it trying to free the global read buffer multiple times if it happens to be pointing to it. */
|
||||
dspcodec->mCodec->mWaveFormatMemory = 0; /* Stop it trying to free the sound's wave format if it happens to be pointing to it. */
|
||||
|
||||
mPool[count]->release();
|
||||
}
|
||||
}
|
||||
|
||||
FMOD_Memory_Free(mPool);
|
||||
mPool = 0;
|
||||
mNumDSPCodecs = 0;
|
||||
}
|
||||
|
||||
if (mReadBuffer)
|
||||
{
|
||||
FMOD_Memory_Free(mReadBuffer);
|
||||
mReadBuffer = 0;
|
||||
}
|
||||
|
||||
#if defined(FMOD_SUPPORT_XMA) && defined(FMOD_SUPPORT_XMA_NEWHAL)
|
||||
if (mFileBufferPool)
|
||||
{
|
||||
FMOD_Memory_FreeType(mFileBufferPool, FMOD_MEMORY_PERSISTENT | FMOD_MEMORY_XBOX360_PHYSICAL);
|
||||
mFileBufferPool = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT DSPCodecPool::alloc(DSPCodec **dspcodec)
|
||||
{
|
||||
int count;
|
||||
|
||||
for (count = 0; count < mNumDSPCodecs; count++)
|
||||
{
|
||||
bool finished;
|
||||
|
||||
mPool[count]->getFinished(&finished);
|
||||
|
||||
if (!mAllocated[count] && finished)
|
||||
{
|
||||
mAllocated[count] = true;
|
||||
*dspcodec = mPool[count];
|
||||
return FMOD_OK;
|
||||
}
|
||||
}
|
||||
|
||||
return FMOD_ERR_CHANNEL_ALLOC;
|
||||
}
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT DSPCodecPool::areAnyFree()
|
||||
{
|
||||
int count;
|
||||
|
||||
for (count = 0; count < mNumDSPCodecs; count++)
|
||||
{
|
||||
bool finished;
|
||||
|
||||
mPool[count]->getFinished(&finished);
|
||||
|
||||
if (!mAllocated[count] && finished)
|
||||
{
|
||||
return FMOD_OK;
|
||||
}
|
||||
}
|
||||
|
||||
return FMOD_ERR_CHANNEL_ALLOC;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
|
||||
#ifdef FMOD_SUPPORT_MEMORYTRACKER
|
||||
|
||||
FMOD_RESULT DSPCodecPool::getMemoryUsedImpl(MemoryTracker *tracker)
|
||||
{
|
||||
if (mPool)
|
||||
{
|
||||
tracker->add(false, FMOD_MEMBITS_DSPCODEC, sizeof(DSPCodec *) * mNumDSPCodecs);
|
||||
|
||||
for (int i=0; i < mNumDSPCodecs; i++)
|
||||
{
|
||||
if (mPool[i])
|
||||
{
|
||||
switch (mPool[i]->mDescription.mCategory)
|
||||
{
|
||||
#ifdef FMOD_SUPPORT_MPEG
|
||||
case FMOD_DSP_CATEGORY_DSPCODECMPEG :
|
||||
{
|
||||
CHECK_RESULT(((DSPCodecMPEG *)mPool[i])->getMemoryUsed(tracker));
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef FMOD_SUPPORT_IMAADPCM
|
||||
case FMOD_DSP_CATEGORY_DSPCODECADPCM :
|
||||
{
|
||||
CHECK_RESULT(((DSPCodecADPCM *)mPool[i])->getMemoryUsed(tracker));
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef FMOD_SUPPORT_XMA
|
||||
case FMOD_DSP_CATEGORY_DSPCODECXMA :
|
||||
{
|
||||
CHECK_RESULT(((DSPCodecXMA *)mPool[i])->getMemoryUsed(tracker));
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef FMOD_SUPPORT_CELT
|
||||
case FMOD_DSP_CATEGORY_DSPCODECCELT :
|
||||
{
|
||||
CHECK_RESULT(((DSPCodecCELT *)mPool[i])->getMemoryUsed(tracker));
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef FMOD_SUPPORT_RAW
|
||||
case FMOD_DSP_CATEGORY_DSPCODECRAW :
|
||||
{
|
||||
CHECK_RESULT(((DSPCodecRaw *)mPool[i])->getMemoryUsed(tracker));
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
default :
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
50
src/fmod_dsp_codecpool.h
Executable file
50
src/fmod_dsp_codecpool.h
Executable file
|
|
@ -0,0 +1,50 @@
|
|||
#ifndef _FMOD_DSP_CODECPOOL_H
|
||||
#define _FMOD_DSP_CODECPOOL_H
|
||||
|
||||
#include "fmod_settings.h"
|
||||
|
||||
#ifdef FMOD_SUPPORT_DSPCODEC
|
||||
|
||||
#include "fmod_dspi.h"
|
||||
|
||||
#ifndef _FMOD_MEMORYTRACKER_H
|
||||
#include "fmod_memorytracker.h"
|
||||
#endif
|
||||
|
||||
namespace FMOD
|
||||
{
|
||||
class DSPI;
|
||||
class SystemI;
|
||||
class DSPCodec;
|
||||
|
||||
#define FMOD_DSP_CODECPOOL_MAXCODECS 256
|
||||
|
||||
class DSPCodecPool
|
||||
{
|
||||
DECLARE_MEMORYTRACKER_NONVIRTUAL
|
||||
|
||||
friend class DSPCodec;
|
||||
|
||||
public:
|
||||
|
||||
SystemI *mSystem;
|
||||
int mNumDSPCodecs;
|
||||
DSPCodec **mPool;
|
||||
bool mAllocated[FMOD_DSP_CODECPOOL_MAXCODECS];
|
||||
unsigned char *mReadBuffer;
|
||||
#if defined(FMOD_SUPPORT_XMA) && defined(FMOD_SUPPORT_XMA_NEWHAL)
|
||||
unsigned char *mFileBufferPool;
|
||||
#endif
|
||||
|
||||
FMOD_RESULT init(FMOD_DSP_CATEGORY category, int resamplerpcmblocksize, int numdspcodecs);
|
||||
FMOD_RESULT close();
|
||||
|
||||
FMOD_RESULT alloc(DSPCodec **dspcodec);
|
||||
FMOD_RESULT areAnyFree();
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
655
src/fmod_dsp_compressor.cpp
Executable file
655
src/fmod_dsp_compressor.cpp
Executable file
|
|
@ -0,0 +1,655 @@
|
|||
#include "fmod_settings.h"
|
||||
|
||||
#ifdef FMOD_SUPPORT_COMPRESSOR
|
||||
|
||||
#include "fmod.h"
|
||||
#include "fmod_dspi.h"
|
||||
#include "fmod_dsp_compressor.h"
|
||||
|
||||
#ifdef PLATFORM_PS3_SPU
|
||||
#include "fmod_systemi_spu.h"
|
||||
#else
|
||||
#include "fmod_systemi.h"
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef PLATFORM_PS3
|
||||
extern unsigned int _binary_spu_fmod_dsp_compressor_pic_start[];
|
||||
#endif
|
||||
|
||||
namespace FMOD
|
||||
{
|
||||
|
||||
FMOD_DSP_DESCRIPTION_EX dspcompressor;
|
||||
|
||||
#ifdef PLUGIN_EXPORTS
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
FMODGetDSPDescription is mandantory for every fmod plugin. This is the symbol the registerplugin function searches for.
|
||||
Must be declared with F_API to make it export as stdcall.
|
||||
*/
|
||||
F_DECLSPEC F_DLLEXPORT FMOD_DSP_DESCRIPTION_EX * F_API FMODGetDSPDescriptionEx()
|
||||
{
|
||||
return DSPCompressor::getDescriptionEx();
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* PLUGIN_EXPORTS */
|
||||
|
||||
#define hold_constant (0.0025f)
|
||||
|
||||
#ifndef PLATFORM_PS3_SPU
|
||||
|
||||
FMOD_DSP_PARAMETERDESC dspcompressor_param[4] =
|
||||
{
|
||||
{ -60.0f, 0.0f, 0.0f, "Threshold", "dB", "Compressor threshold [-60dB, 0dB] Default = 0dB." },
|
||||
{ 10.0f, 200.0f, 50.0f, "Attack", "ms", "Compressor attack time. [10ms,200ms] Default = 50ms." },
|
||||
{ 20.0f, 1000.0f, 50.0f, "Release", "ms", "Compressor release time. [10ms,1000ms] Default = 50ms." },
|
||||
{ 0.0f, 30.0f, 0.0f, "Make up gain", "dB", "Compressor make up gain [0dB, 30dB] Default = 0dB." }
|
||||
};
|
||||
|
||||
#endif // PLATFORM_PS3_SPU
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_DSP_DESCRIPTION_EX *DSPCompressor::getDescriptionEx()
|
||||
{
|
||||
#ifndef PLATFORM_PS3_SPU
|
||||
FMOD_memset(&dspcompressor, 0, sizeof(FMOD_DSP_DESCRIPTION_EX));
|
||||
|
||||
FMOD_strcpy(dspcompressor.name, "FMOD Compressor");
|
||||
dspcompressor.version = 0x00010100;
|
||||
dspcompressor.create = DSPCompressor::createCallback;
|
||||
|
||||
#ifdef PLATFORM_PS3
|
||||
dspcompressor.read = (FMOD_DSP_READCALLBACK)_binary_spu_fmod_dsp_compressor_pic_start; /* SPU PIC entry address */
|
||||
#else
|
||||
dspcompressor.read = DSPCompressor::readCallback;
|
||||
#endif
|
||||
|
||||
dspcompressor.numparameters = sizeof(dspcompressor_param) / sizeof(dspcompressor_param[0]);
|
||||
dspcompressor.paramdesc = dspcompressor_param;
|
||||
dspcompressor.setparameter = DSPCompressor::setParameterCallback;
|
||||
dspcompressor.getparameter = DSPCompressor::getParameterCallback;
|
||||
#ifdef FMOD_SUPPORT_MEMORYTRACKER
|
||||
dspcompressor.getmemoryused = &DSPCompressor::getMemoryUsedCallback;
|
||||
#endif
|
||||
|
||||
dspcompressor.mType = FMOD_DSP_TYPE_COMPRESSOR;
|
||||
dspcompressor.mCategory = FMOD_DSP_CATEGORY_FILTER;
|
||||
dspcompressor.mSize = sizeof(DSPCompressor);
|
||||
#else
|
||||
dspcompressor.read = DSPCompressor::readCallback; /* We only care about read function on SPU */
|
||||
#endif
|
||||
return &dspcompressor;
|
||||
}
|
||||
|
||||
#ifndef PLATFORM_PS3_SPU
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT DSPCompressor::createInternal()
|
||||
{
|
||||
init();
|
||||
|
||||
int count;
|
||||
/*
|
||||
Setup ...
|
||||
*/
|
||||
for (count = 0; count < mDescription.numparameters; count++)
|
||||
{
|
||||
setParameter(count, mDescription.paramdesc[count].defaultval);
|
||||
}
|
||||
|
||||
for(count = 0; count < DSP_MAXLEVELS_MAX; count++)
|
||||
{
|
||||
mMaxChannelIn[count] = 0.0f;
|
||||
}
|
||||
mGain = 1.0f;
|
||||
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
||||
#endif //!PLATFORM_PS3_SPU
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
FMOD_OK
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT DSPCompressor::readInternal(float *inbuffer, float *outbuffer, unsigned int length, int inchannels, int outchannels)
|
||||
{
|
||||
unsigned int sample;
|
||||
int channel;
|
||||
float in_abs, x;
|
||||
float holdconstant = mHoldConstant; /* Copy members for better thread safety. */
|
||||
float threshold_lin = mThreshold_lin;
|
||||
float attack_constant = mAttack_constant;
|
||||
float release_constant = mRelease_constant;
|
||||
float gainmakeup_lin = mGainMakeup_lin;
|
||||
|
||||
if (!inbuffer)
|
||||
{
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
||||
if (!(speakermask & ((1 << inchannels)-1))) /*No speaker channels are active, copy in buffer to out buffer and skip the DSP*/
|
||||
{
|
||||
FMOD_memcpy(outbuffer, inbuffer, sizeof(float)*length*inchannels);
|
||||
return FMOD_OK;
|
||||
}
|
||||
/*
|
||||
if ( (++peakTimer_ >= peakHold_) || (keyLink > maxPeak_) ) {
|
||||
// if either condition is met:
|
||||
peakTimer_ = 0; // reset peak timer
|
||||
maxPeak_ = keyLink; // assign new peak to max peak
|
||||
}
|
||||
// attack/release
|
||||
if ( maxPeak_ > env_ )
|
||||
att_.run( maxPeak_, env_ ); // run attack phase
|
||||
else
|
||||
rel_.run( maxPeak_, env_ ); // run release phase
|
||||
*/
|
||||
|
||||
if ((speakermask & ((1 << inchannels)-1)) != ((1 << inchannels)-1))
|
||||
{
|
||||
for (sample = 0; sample < length; sample++)
|
||||
{
|
||||
unsigned int base = sample * inchannels;
|
||||
float *sample_in = &(inbuffer[base]);
|
||||
float *sample_out = &(outbuffer[base]);
|
||||
float in_max = 0.0f;
|
||||
float over;
|
||||
|
||||
for (channel = 0; channel < inchannels; channel++)
|
||||
{
|
||||
if ((1 << channel) & speakermask)
|
||||
{
|
||||
float *m;
|
||||
|
||||
x = sample_in[channel];
|
||||
m = &(mMaxChannelIn[channel]);
|
||||
|
||||
in_abs = (x<0.0f) ? -x : x; // ABS input
|
||||
|
||||
*m -= holdconstant; // Leak hold
|
||||
|
||||
if (in_abs > *m) // Hold new max
|
||||
{
|
||||
*m = in_abs;
|
||||
}
|
||||
|
||||
if (*m > in_max) // Update total max
|
||||
{
|
||||
in_max = *m;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Note: This uses linear gain curves, not dB
|
||||
// dB is better but more costly
|
||||
|
||||
// Over = linear ratio of input:threshold
|
||||
over = in_max/threshold_lin;
|
||||
|
||||
// Apply attack or release curve to over
|
||||
// to obtain gain reduction
|
||||
if (over > 1.0f)
|
||||
{
|
||||
mGain = over + attack_constant * (mGain-over);
|
||||
}
|
||||
else
|
||||
{
|
||||
mGain = over + release_constant * (mGain-over);
|
||||
}
|
||||
|
||||
// Apply gain reduction to output if reduction exists.
|
||||
if (mGain > 1.0f)
|
||||
{
|
||||
for (channel = 0; channel < inchannels; channel++)
|
||||
{
|
||||
if (!((1 << channel) & speakermask))
|
||||
{
|
||||
sample_out[channel] = sample_in[channel];
|
||||
}
|
||||
else
|
||||
{
|
||||
sample_out[channel] = gainmakeup_lin * sample_in[channel] / mGain;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (channel = 0; channel < inchannels; channel++)
|
||||
{
|
||||
if (!((1 << channel) & speakermask))
|
||||
{
|
||||
sample_out[channel] = sample_in[channel];
|
||||
}
|
||||
else
|
||||
{
|
||||
sample_out[channel] = gainmakeup_lin * sample_in[channel];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (sample = 0; sample < length; sample++)
|
||||
{
|
||||
unsigned int base = sample * inchannels;
|
||||
float *sample_in = &(inbuffer[base]);
|
||||
float *sample_out = &(outbuffer[base]);
|
||||
float in_max = 0.0f;
|
||||
float over;
|
||||
|
||||
for (channel = 0; channel < inchannels; channel++)
|
||||
{
|
||||
float *m;
|
||||
|
||||
x = sample_in[channel];
|
||||
m = &(mMaxChannelIn[channel]);
|
||||
|
||||
in_abs = (x<0.0f) ? -x : x; // ABS input
|
||||
|
||||
*m -= holdconstant; // Leak hold
|
||||
|
||||
if (in_abs > *m) // Hold new max
|
||||
{
|
||||
*m = in_abs;
|
||||
}
|
||||
|
||||
if (*m > in_max) // Update total max
|
||||
{
|
||||
in_max = *m;
|
||||
}
|
||||
}
|
||||
|
||||
// Note: This uses linear gain curves, not dB
|
||||
// dB is better but more costly
|
||||
|
||||
// Over = linear ratio of input:threshold
|
||||
over = in_max/threshold_lin;
|
||||
|
||||
// Apply attack or release curve to over
|
||||
// to obtain gain reduction
|
||||
if (over > 1.0f)
|
||||
{
|
||||
mGain = over + attack_constant * (mGain-over);
|
||||
}
|
||||
else
|
||||
{
|
||||
mGain = over + release_constant * (mGain-over);
|
||||
}
|
||||
|
||||
// Apply gain reduction to output if reduction exists.
|
||||
if (mGain > 1.0f)
|
||||
{
|
||||
for (channel = 0; channel < inchannels; channel++)
|
||||
{
|
||||
sample_out[channel] = gainmakeup_lin * sample_in[channel] / mGain;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (channel = 0; channel < inchannels; channel++)
|
||||
{
|
||||
sample_out[channel] = gainmakeup_lin * sample_in[channel];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
||||
#ifndef PLATFORM_PS3_SPU
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
FMOD_OK
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT DSPCompressor::setParameterInternal(int index, float value)
|
||||
{
|
||||
FMOD_RESULT result;
|
||||
int outputrate;
|
||||
|
||||
result = mSystem->getSoftwareFormat(&outputrate, 0, 0, 0, 0, 0);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
mHoldConstant = 10.0f / (float)outputrate; // 10Hz
|
||||
|
||||
switch (index)
|
||||
{
|
||||
|
||||
case FMOD_DSP_COMPRESSOR_THRESHOLD:
|
||||
{
|
||||
mThreshold_dB = value;
|
||||
mThreshold_lin = FMOD_POW(10.0f, mThreshold_dB/20.0f);
|
||||
break;
|
||||
}
|
||||
case FMOD_DSP_COMPRESSOR_ATTACK:
|
||||
{
|
||||
mAttack_ms = value;
|
||||
mAttack_constant = FMOD_EXP(-1000.0f / (mAttack_ms * outputrate) );
|
||||
break;
|
||||
}
|
||||
case FMOD_DSP_COMPRESSOR_RELEASE:
|
||||
{
|
||||
mRelease_ms = value;
|
||||
mRelease_constant = FMOD_EXP(-1000.0f / (mRelease_ms * outputrate) );
|
||||
break;
|
||||
}
|
||||
case FMOD_DSP_COMPRESSOR_GAINMAKEUP:
|
||||
{
|
||||
mGainMakeup_dB = value;
|
||||
mGainMakeup_lin = FMOD_POW(10.0f, mGainMakeup_dB/20.0f);
|
||||
break;
|
||||
}
|
||||
}
|
||||
/*
|
||||
if (mResonance >= 1.0f)
|
||||
{
|
||||
unsigned int nInd;
|
||||
float a0, a1, a2, b0, b1, b2;
|
||||
float fs; // Sampling frequency, cutoff frequency
|
||||
float k[2]; // overall gain factor
|
||||
float ktotal;
|
||||
float *coef;
|
||||
|
||||
k[0] = 1.0f; // Set overall filter gain
|
||||
k[1] = 1.0f;
|
||||
ktotal = 1.0f;
|
||||
coef = mCoefficients + 1; // Skip k, or gain
|
||||
fs = (float)outputrate; // Sampling frequency (Hz)
|
||||
|
||||
|
||||
|
||||
// Update overall filter gain in coef array
|
||||
mCoefficients[0] = ktotal;
|
||||
}
|
||||
*/
|
||||
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT DSPCompressor::getParameterInternal(int index, float *value, char *valuestr)
|
||||
{
|
||||
|
||||
switch (index)
|
||||
{
|
||||
case FMOD_DSP_COMPRESSOR_THRESHOLD:
|
||||
{
|
||||
*value = mThreshold_dB;
|
||||
sprintf(valuestr, "%.02f", mThreshold_dB);
|
||||
break;
|
||||
}
|
||||
case FMOD_DSP_COMPRESSOR_ATTACK:
|
||||
{
|
||||
*value = mAttack_ms;
|
||||
sprintf(valuestr, "%.02f", mAttack_ms);
|
||||
break;
|
||||
}
|
||||
case FMOD_DSP_COMPRESSOR_RELEASE:
|
||||
{
|
||||
*value = mRelease_ms;
|
||||
sprintf(valuestr, "%.02f", mRelease_ms);
|
||||
break;
|
||||
}
|
||||
case FMOD_DSP_COMPRESSOR_GAINMAKEUP:
|
||||
{
|
||||
*value = mGainMakeup_dB;
|
||||
sprintf(valuestr, "%.02f", mGainMakeup_dB);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
|
||||
#ifdef FMOD_SUPPORT_MEMORYTRACKER
|
||||
|
||||
FMOD_RESULT DSPCompressor::getMemoryUsedImpl(MemoryTracker *tracker)
|
||||
{
|
||||
// Size of this class is already accounted for (via description.mSize). Just add extra allocated memory here.
|
||||
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
==============================================================================================================
|
||||
|
||||
CALLBACK INTERFACE
|
||||
|
||||
==============================================================================================================
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT F_CALLBACK DSPCompressor::createCallback(FMOD_DSP_STATE *dsp)
|
||||
{
|
||||
DSPCompressor *compressor = (DSPCompressor *)dsp;
|
||||
|
||||
return compressor->createInternal();
|
||||
}
|
||||
|
||||
#endif //!PLATFORM_PS3_SPU
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT F_CALLBACK DSPCompressor::readCallback(FMOD_DSP_STATE *dsp, float *inbuffer, float *outbuffer, unsigned int length, int inchannels, int outchannels)
|
||||
{
|
||||
DSPCompressor *compressor = (DSPCompressor *)dsp;
|
||||
|
||||
return compressor->readInternal(inbuffer, outbuffer, length, inchannels, outchannels);
|
||||
}
|
||||
|
||||
#ifndef PLATFORM_PS3_SPU
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT F_CALLBACK DSPCompressor::setParameterCallback(FMOD_DSP_STATE *dsp, int index, float value)
|
||||
{
|
||||
DSPCompressor *compressor = (DSPCompressor *)dsp;
|
||||
|
||||
return compressor->setParameterInternal(index, value);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
Win32, Win64, Linux, Macintosh, XBox, PlayStation 2, GameCube
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT F_CALLBACK DSPCompressor::getParameterCallback(FMOD_DSP_STATE *dsp, int index, float *value, char *valuestr)
|
||||
{
|
||||
DSPCompressor *compressor = (DSPCompressor *)dsp;
|
||||
|
||||
return compressor->getParameterInternal(index, value, valuestr);
|
||||
}
|
||||
|
||||
|
||||
#ifdef FMOD_SUPPORT_MEMORYTRACKER
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT F_CALLBACK DSPCompressor::getMemoryUsedCallback(FMOD_DSP_STATE *dsp, MemoryTracker *tracker)
|
||||
{
|
||||
DSPCompressor *compressor = (DSPCompressor *)dsp;
|
||||
|
||||
return compressor->DSPCompressor::getMemoryUsed(tracker);
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif //!PLATFORM_PS3_SPU
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
55
src/fmod_dsp_compressor.h
Executable file
55
src/fmod_dsp_compressor.h
Executable file
|
|
@ -0,0 +1,55 @@
|
|||
#ifndef _FMOD_DSP_COMPRESSOR_H
|
||||
#define _FMOD_DSP_COMPRESSOR_H
|
||||
|
||||
#include "fmod_settings.h"
|
||||
|
||||
#ifdef FMOD_SUPPORT_COMPRESSOR
|
||||
|
||||
#include "fmod.h"
|
||||
#include "fmod_dsp_filter.h"
|
||||
|
||||
namespace FMOD
|
||||
{
|
||||
class DSPCompressor : public DSPFilter
|
||||
{
|
||||
DECLARE_MEMORYTRACKER_NONVIRTUAL
|
||||
|
||||
private:
|
||||
FMOD_RESULT createInternal();
|
||||
FMOD_RESULT readInternal(float *inbuffer, float *outbuffer, unsigned int length, int inchannels, int outchannels);
|
||||
FMOD_RESULT setParameterInternal(int index, float value);
|
||||
FMOD_RESULT getParameterInternal(int index, float *value, char *valuestr);
|
||||
|
||||
// Parameters with internal units versions
|
||||
float mHoldConstant;
|
||||
float mAttack_ms;
|
||||
float mAttack_constant;
|
||||
float mRelease_ms;
|
||||
float mRelease_constant;
|
||||
float mThreshold_dB;
|
||||
float mThreshold_lin;
|
||||
float mGainMakeup_dB;
|
||||
float mGainMakeup_lin;
|
||||
|
||||
// Internal state
|
||||
float mGain;
|
||||
float mMaxChannelIn[DSP_MAXLEVELS_MAX];
|
||||
public:
|
||||
|
||||
static FMOD_DSP_DESCRIPTION_EX *getDescriptionEx();
|
||||
|
||||
static FMOD_RESULT F_CALLBACK createCallback(FMOD_DSP_STATE *dsp);
|
||||
static FMOD_RESULT F_CALLBACK readCallback(FMOD_DSP_STATE *dsp, float *inbuffer, float *outbuffer, unsigned int length, int inchannels, int outchannels);
|
||||
static FMOD_RESULT F_CALLBACK seekCallback(FMOD_DSP_STATE *dsp, unsigned int seeklen);
|
||||
static FMOD_RESULT F_CALLBACK setParameterCallback(FMOD_DSP_STATE *dsp, int index, float value);
|
||||
static FMOD_RESULT F_CALLBACK getParameterCallback(FMOD_DSP_STATE *dsp, int index, float *value, char *valuestr);
|
||||
#ifdef FMOD_SUPPORT_MEMORYTRACKER
|
||||
static FMOD_RESULT F_CALLBACK getMemoryUsedCallback(FMOD_DSP_STATE *dsp, MemoryTracker *tracker);
|
||||
#endif
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
169
src/fmod_dsp_connection.cpp
Executable file
169
src/fmod_dsp_connection.cpp
Executable file
|
|
@ -0,0 +1,169 @@
|
|||
/*$ preserve start $*/
|
||||
|
||||
#include "fmod_settings.h"
|
||||
|
||||
#include "fmod.hpp"
|
||||
#include "fmod_dsp_connectioni.h"
|
||||
#include "fmod_systemi.h"
|
||||
|
||||
namespace FMOD
|
||||
{
|
||||
/*$ preserve end $*/
|
||||
|
||||
|
||||
FMOD_RESULT DSPConnection::getInput(DSP **input)
|
||||
{
|
||||
FMOD_RESULT result;
|
||||
DSPConnectionI *dspconnectioni;
|
||||
|
||||
result = DSPConnectionI::validate(this, &dspconnectioni);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
return dspconnectioni->getInput((DSPI **)input);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
FMOD_RESULT DSPConnection::getOutput(DSP **output)
|
||||
{
|
||||
FMOD_RESULT result;
|
||||
DSPConnectionI *dspconnectioni;
|
||||
|
||||
result = DSPConnectionI::validate(this, &dspconnectioni);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
return dspconnectioni->getOutput((DSPI **)output);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
FMOD_RESULT DSPConnection::setMix(float volume)
|
||||
{
|
||||
FMOD_RESULT result;
|
||||
DSPConnectionI *dspconnectioni;
|
||||
|
||||
result = DSPConnectionI::validate(this, &dspconnectioni);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
return dspconnectioni->setMix(volume);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
FMOD_RESULT DSPConnection::getMix(float *volume)
|
||||
{
|
||||
FMOD_RESULT result;
|
||||
DSPConnectionI *dspconnectioni;
|
||||
|
||||
result = DSPConnectionI::validate(this, &dspconnectioni);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
return dspconnectioni->getMix(volume);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
FMOD_RESULT DSPConnection::setLevels(FMOD_SPEAKER speaker, float *levels, int numlevels)
|
||||
{
|
||||
FMOD_RESULT result;
|
||||
DSPConnectionI *dspconnectioni;
|
||||
|
||||
result = DSPConnectionI::validate(this, &dspconnectioni);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
return dspconnectioni->setLevels(speaker, levels, numlevels);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
FMOD_RESULT DSPConnection::getLevels(FMOD_SPEAKER speaker, float *levels, int numlevels)
|
||||
{
|
||||
FMOD_RESULT result;
|
||||
DSPConnectionI *dspconnectioni;
|
||||
|
||||
result = DSPConnectionI::validate(this, &dspconnectioni);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
return dspconnectioni->getLevels(speaker, levels, numlevels);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
FMOD_RESULT DSPConnection::setUserData(void *_userdata)
|
||||
{
|
||||
FMOD_RESULT result;
|
||||
DSPConnectionI *dspconnectioni;
|
||||
|
||||
result = DSPConnectionI::validate(this, &dspconnectioni);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
return dspconnectioni->setUserData(_userdata);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
FMOD_RESULT DSPConnection::getUserData(void **_userdata)
|
||||
{
|
||||
FMOD_RESULT result;
|
||||
DSPConnectionI *dspconnectioni;
|
||||
|
||||
result = DSPConnectionI::validate(this, &dspconnectioni);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
return dspconnectioni->getUserData(_userdata);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
FMOD_RESULT DSPConnection::getMemoryInfo(unsigned int memorybits, unsigned int event_memorybits, unsigned int *memoryused, FMOD_MEMORY_USAGE_DETAILS *memoryused_details)
|
||||
{
|
||||
FMOD_RESULT result;
|
||||
DSPConnectionI *dspconnectioni;
|
||||
|
||||
result = DSPConnectionI::validate(this, &dspconnectioni);
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
return dspconnectioni->getMemoryInfo(memorybits, event_memorybits, memoryused, memoryused_details);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*$ preserve start $*/
|
||||
}
|
||||
/*$ preserve end $*/
|
||||
2613
src/fmod_dsp_connectioni.cpp
Executable file
2613
src/fmod_dsp_connectioni.cpp
Executable file
File diff suppressed because it is too large
Load diff
143
src/fmod_dsp_connectioni.h
Executable file
143
src/fmod_dsp_connectioni.h
Executable file
|
|
@ -0,0 +1,143 @@
|
|||
#ifndef _FMOD_DSP_CONNECTION_H
|
||||
#define _FMOD_DSP_CONNECTION_H
|
||||
|
||||
#include "fmod_settings.h"
|
||||
#include "fmod.hpp"
|
||||
#include "fmod_channeli.h"
|
||||
#include "fmod_linkedlist.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifndef _FMOD_MEMORYTRACKER_H
|
||||
#include "fmod_memorytracker.h"
|
||||
#endif
|
||||
|
||||
namespace FMOD
|
||||
{
|
||||
#if defined(PLATFORM_PSP) || defined(PLATFORM_PS2) || defined(PLATFORM_GC) || defined(PLATFORM_IPHONE)
|
||||
#define DSP_MAXLEVELS_OUT 2 /* Save memory on these platforms. They'll never see more than stereo. */
|
||||
#elif (defined(PLATFORM_XENON) && !defined(FMOD_SUPPORT_NEURAL)) || defined(PLATFORM_XBOX) || defined(PLATFORM_WII) /* DPL2 for Wii */
|
||||
#define DSP_MAXLEVELS_OUT 6 /* Never see more than 5.1. */
|
||||
#elif defined(PLATFORM_PS3) || defined(PLATFORM_WINDOWS_PS3MODE) || (defined(PLATFORM_XENON) && defined(FMOD_SUPPORT_NEURAL))
|
||||
#define DSP_MAXLEVELS_OUT 8 /* Never see more than 7.1. */
|
||||
#else
|
||||
#define DSP_MAXLEVELS_OUT 16
|
||||
#endif
|
||||
|
||||
#define DSP_MAXLEVELS_IN FMOD_CHANNEL_MAXINPUTCHANNELS
|
||||
#define DSP_MAXLEVELS_MAX 16 /* This should be whatever is the largest out of DSP_MAXLEVELS_IN and DSP_MAXLEVELS_OUT */
|
||||
|
||||
#define DSP_DEFAULTLEVELS_IN 6 /* Enough for a 5.1 input sound. */
|
||||
|
||||
const int DSP_RAMPCOUNT = 64; /* All volume ramps will happen over this number of samples to remove clicks. */
|
||||
|
||||
#ifdef PLATFORM_XENON
|
||||
#define DSP_LEVEL_PRECISION 16 /* Half floats - 5 bit exponent, 15bit mantissa. */
|
||||
#else
|
||||
#define DSP_LEVEL_PRECISION 32
|
||||
#endif
|
||||
|
||||
#define DSP_LEVEL_SMALLVAL 0.00002f
|
||||
|
||||
#if (DSP_LEVEL_PRECISION == 32)
|
||||
#define DSP_LEVEL_TYPE float
|
||||
|
||||
#define DSP_LEVEL_COMPRESS(_val) _val
|
||||
#define DSP_LEVEL_DECOMPRESS(_val) _val
|
||||
#else
|
||||
#define DSP_LEVEL_TYPE unsigned short
|
||||
|
||||
#ifdef PLATFORM_XENON
|
||||
FMOD_INLINE unsigned short FMOD_DSP_ConnectionI_Single2HalfP(float source)
|
||||
{
|
||||
__vector4 a;
|
||||
a.y = source;
|
||||
return __vpkd3d( a, a, VPACK_FLOAT16_4, VPACK_64LO, 0 ).u[2];
|
||||
}
|
||||
FMOD_INLINE float FMOD_DSP_ConnectionI_HalfP2Single(unsigned short h)
|
||||
{
|
||||
__vector4 a;
|
||||
a.u[3] = h;
|
||||
return __vupkd3d( a, VPACK_FLOAT16_4).w;
|
||||
}
|
||||
#else
|
||||
unsigned short FMOD_DSP_ConnectionI_Single2HalfP(float source);
|
||||
float FMOD_DSP_ConnectionI_HalfP2Single(unsigned short h);
|
||||
#endif
|
||||
|
||||
#define DSP_LEVEL_COMPRESS(_val) FMOD_DSP_ConnectionI_Single2HalfP(_val)
|
||||
#define DSP_LEVEL_DECOMPRESS(_val) FMOD_DSP_ConnectionI_HalfP2Single(_val)
|
||||
#endif
|
||||
|
||||
class DSPI;
|
||||
|
||||
class DSPConnectionI
|
||||
{
|
||||
DECLARE_MEMORYTRACKER
|
||||
|
||||
public:
|
||||
|
||||
LinkedListNode mInputNode;
|
||||
LinkedListNode mOutputNode;
|
||||
LinkedListNode *mNode; /* Make it a pointer so we can store the node data externally. PS3 will corrupt it otherwise. */
|
||||
|
||||
short mMaxOutputLevels FMOD_PACKED;
|
||||
short mMaxInputLevels FMOD_PACKED;
|
||||
|
||||
DSP_LEVEL_TYPE *mLevel[DSP_MAXLEVELS_OUT];
|
||||
DSP_LEVEL_TYPE *mLevelCurrent[DSP_MAXLEVELS_OUT];
|
||||
DSP_LEVEL_TYPE *mLevelDelta[DSP_MAXLEVELS_OUT];
|
||||
|
||||
public:
|
||||
|
||||
DSPI *mInputUnit;
|
||||
DSPI *mOutputUnit;
|
||||
|
||||
short mRampCount FMOD_PACKED;
|
||||
short mSetLevelsUsed FMOD_PACKED;
|
||||
|
||||
#ifdef PLATFORM_PS3
|
||||
unsigned short mInputUnitSize FMOD_PACKED;
|
||||
unsigned short mOutputUnitSize FMOD_PACKED;
|
||||
|
||||
FMOD_PPCALIGN16(unsigned int mMramAddress);
|
||||
FMOD_PPCALIGN16(unsigned int mMramAddressLevels);
|
||||
|
||||
#endif
|
||||
|
||||
float mVolume;
|
||||
void *mUserData;
|
||||
|
||||
static FMOD_RESULT validate (DSPConnection *dspconnection, DSPConnectionI **dspconnectioni);
|
||||
|
||||
FMOD_RESULT init (DSP_LEVEL_TYPE * &levelmemory, int maxoutputlevels, int maxinputlevels);
|
||||
|
||||
FMOD_RESULT mix (float * FMOD_RESTRICT outbuffer, float * FMOD_RESTRICT inbuffer, int outchannels, int inchannels, unsigned int length);
|
||||
FMOD_RESULT mixAndRamp (float * FMOD_RESTRICT outbuffer, float * FMOD_RESTRICT inbuffer, int outchannels, int inchannels, unsigned int length);
|
||||
|
||||
FMOD_RESULT getInput (DSPI **input);
|
||||
FMOD_RESULT getOutput (DSPI **output);
|
||||
FMOD_RESULT reset ();
|
||||
FMOD_RESULT setUnity ();
|
||||
FMOD_RESULT rampTo ();
|
||||
FMOD_RESULT checkUnity (int outchannels, int inchannels);
|
||||
FMOD_RESULT checkMono (int outchannels, int inchannels);
|
||||
FMOD_RESULT setPan (float pan, int outchannels, int inchannels, FMOD_SPEAKERMODE speakermode);
|
||||
FMOD_RESULT setMix (float volume);
|
||||
FMOD_RESULT getMix (float *volume);
|
||||
FMOD_RESULT setLevels (float *levels, int numinputlevels);
|
||||
FMOD_RESULT getLevels (float *levels, int numinputlevels);
|
||||
FMOD_RESULT setLevels (FMOD_SPEAKER speaker, float *levels, int numlevels);
|
||||
FMOD_RESULT getLevels (FMOD_SPEAKER speaker, float *levels, int numlevels);
|
||||
FMOD_RESULT setUserData (void *userdata);
|
||||
FMOD_RESULT getUserData (void **userdata);
|
||||
|
||||
FMOD_RESULT copy (DSPConnectionI *source);
|
||||
|
||||
FMOD_RESULT getMemoryInfo(unsigned int memorybits, unsigned int event_memorybits, unsigned int *memoryused, FMOD_MEMORY_USAGE_DETAILS *memoryused_details);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
381
src/fmod_dsp_connectionpool.cpp
Executable file
381
src/fmod_dsp_connectionpool.cpp
Executable file
|
|
@ -0,0 +1,381 @@
|
|||
#include "fmod_settings.h"
|
||||
|
||||
#ifdef FMOD_SUPPORT_SOFTWARE
|
||||
|
||||
#include "fmod_dsp_connectionpool.h"
|
||||
#include "fmod_localcriticalsection.h"
|
||||
#include "fmod_memory.h"
|
||||
#include "fmod_systemi.h"
|
||||
|
||||
namespace FMOD
|
||||
{
|
||||
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT DSPConnectionPool::init(SystemI *system, int numconnections, int numoutputlevels, int numinputlevels)
|
||||
{
|
||||
DSP_LEVEL_TYPE *leveldata;
|
||||
int count;
|
||||
unsigned int alignment = 0;
|
||||
|
||||
if (numconnections < 0)
|
||||
{
|
||||
return FMOD_ERR_INVALID_PARAM;
|
||||
}
|
||||
|
||||
for (int i=0; i < DSP_MAX_CONNECTION_BLOCKS; i++)
|
||||
{
|
||||
mConnection[i] = 0;
|
||||
mLevelData[i] = 0;
|
||||
}
|
||||
|
||||
numconnections += 128;
|
||||
numconnections /= 128;
|
||||
numconnections *= 128;
|
||||
|
||||
mNumConnections = numconnections;
|
||||
mConnectionMemory[0] = (DSPConnectionI *)FMOD_Memory_Calloc(mNumConnections * sizeof(DSPConnectionI) + 16);
|
||||
if (!mConnectionMemory[0])
|
||||
{
|
||||
return FMOD_ERR_MEMORY;
|
||||
}
|
||||
mConnection[0] = (DSPConnectionI *)FMOD_ALIGNPOINTER(mConnectionMemory[0], 16);
|
||||
|
||||
mNodeMemory[0] = (LinkedListNode *)FMOD_Memory_Calloc(mNumConnections * sizeof(LinkedListNode));
|
||||
if (!mNodeMemory[0])
|
||||
{
|
||||
return FMOD_ERR_MEMORY;
|
||||
}
|
||||
|
||||
mNumOutputLevels = numoutputlevels;
|
||||
mNumInputLevels = numinputlevels;
|
||||
|
||||
#ifdef PLATFORM_PS3
|
||||
alignment = 128;
|
||||
#endif
|
||||
mLevelDataMemory[0] = (DSP_LEVEL_TYPE *)FMOD_Memory_Calloc(mNumConnections /* How many connections are we going to allow maximum. */
|
||||
* (mNumOutputLevels < 2 ? 2 : mNumOutputLevels) /* Number of rows. This should be at least 2 for panning. */
|
||||
* (mNumInputLevels < mNumOutputLevels ? mNumOutputLevels : mNumInputLevels) /* Because pan matricies can be [outputlevels][outputlevels] we need to have at least this */
|
||||
* sizeof(DSP_LEVEL_TYPE) /* Float values of course. Maybe lower? */
|
||||
* 3 /* *3 = mLevel, mLevelCurrent, mLevelDelta */
|
||||
+ alignment /* PS3 - 128 byte aligned for DMA */
|
||||
);
|
||||
if (!mLevelDataMemory[0])
|
||||
{
|
||||
return FMOD_ERR_MEMORY;
|
||||
}
|
||||
#ifdef PLATFORM_PS3
|
||||
mLevelData[0] = (DSP_LEVEL_TYPE *)FMOD_ALIGNPOINTER(mLevelDataMemory[0], 128);
|
||||
#else
|
||||
mLevelData[0] = mLevelDataMemory[0];
|
||||
#endif
|
||||
leveldata = mLevelData[0];
|
||||
|
||||
mFreeListHead.initNode();
|
||||
for (count = 0; count < mNumConnections; count++)
|
||||
{
|
||||
DSPConnectionI *conn = &mConnection[0][count];
|
||||
|
||||
new (conn) DSPConnectionI;
|
||||
|
||||
conn->init(leveldata, numoutputlevels, numinputlevels);
|
||||
conn->mNode = &mNodeMemory[0][count];
|
||||
conn->mNode->setData(conn);
|
||||
conn->mNode->addAfter(&mFreeListHead);
|
||||
}
|
||||
|
||||
mSystem = system;
|
||||
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT DSPConnectionPool::close()
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < DSP_MAX_CONNECTION_BLOCKS; i++)
|
||||
{
|
||||
if (mConnectionMemory[i])
|
||||
{
|
||||
FMOD_Memory_Free(mConnectionMemory[i]);
|
||||
mConnectionMemory[i] = 0;
|
||||
}
|
||||
mConnection[i] = 0;
|
||||
|
||||
if (mLevelDataMemory[i])
|
||||
{
|
||||
FMOD_Memory_Free(mLevelDataMemory[i]);
|
||||
mLevelDataMemory[i] = 0;
|
||||
}
|
||||
mLevelData[i] = 0;
|
||||
|
||||
if (mNodeMemory[i])
|
||||
{
|
||||
FMOD_Memory_Free(mNodeMemory[i]);
|
||||
mNodeMemory[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT DSPConnectionPool::alloc(DSPConnectionI **connection, bool protect)
|
||||
{
|
||||
LocalCriticalSection crit(mSystem->mDSPConnectionCrit);
|
||||
DSPConnectionI *newconnection;
|
||||
unsigned int alignment = 0;
|
||||
|
||||
if (!mSystem)
|
||||
{
|
||||
return FMOD_ERR_UNINITIALIZED;
|
||||
}
|
||||
|
||||
if (!connection)
|
||||
{
|
||||
return FMOD_ERR_INVALID_PARAM;
|
||||
}
|
||||
|
||||
if (protect)
|
||||
{
|
||||
crit.enter();
|
||||
}
|
||||
|
||||
if (mFreeListHead.isEmpty())
|
||||
{
|
||||
int newblock, count;
|
||||
DSP_LEVEL_TYPE *leveldata = 0;
|
||||
|
||||
for (newblock = 0; newblock < DSP_MAX_CONNECTION_BLOCKS; newblock++)
|
||||
{
|
||||
if (!mConnectionMemory[newblock])
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (newblock >= DSP_MAX_CONNECTION_BLOCKS)
|
||||
{
|
||||
FLOG((FMOD_DEBUG_LEVEL_LOG, __FILE__, __LINE__, "DSPConnectionPool::alloc", "DSP_MAX_CONNECTION_BLOCKS exceeded! Memory will leak!\n"));
|
||||
return FMOD_ERR_INTERNAL;
|
||||
}
|
||||
|
||||
mConnectionMemory[newblock] = (DSPConnectionI *)FMOD_Memory_Calloc(mNumConnections * sizeof(DSPConnectionI) + 16);
|
||||
if (!mConnectionMemory[newblock])
|
||||
{
|
||||
return FMOD_ERR_MEMORY;
|
||||
}
|
||||
mConnection[newblock] = (DSPConnectionI *)FMOD_ALIGNPOINTER(mConnectionMemory[newblock], 16);
|
||||
|
||||
#ifdef PLATFORM_PS3
|
||||
alignment = 128;
|
||||
#endif
|
||||
mNodeMemory[newblock] = (LinkedListNode *)FMOD_Memory_Calloc(mNumConnections * sizeof(LinkedListNode));
|
||||
if (!mNodeMemory[newblock])
|
||||
{
|
||||
return FMOD_ERR_MEMORY;
|
||||
}
|
||||
|
||||
mLevelDataMemory[newblock] = (DSP_LEVEL_TYPE *)FMOD_Memory_Calloc(mNumConnections /* How many connections are we going to allow maximum. */
|
||||
* (mNumOutputLevels < 2 ? 2 : mNumOutputLevels) /* Number of rows. This should be at least 2 for panning. */
|
||||
* (mNumInputLevels < mNumOutputLevels ? mNumOutputLevels : mNumInputLevels) /* Because pan matricies can be [outputlevels][outputlevels] we need to have at least this */
|
||||
* sizeof(DSP_LEVEL_TYPE) /* Float values of course. Maybe lower? */
|
||||
* 3 /* *3 = mLevel, mLevelCurrent, mLevelDelta */
|
||||
+ alignment /* PS3 - 128 byte aligned for DMA */
|
||||
);
|
||||
if (!mLevelDataMemory[newblock])
|
||||
{
|
||||
return FMOD_ERR_MEMORY;
|
||||
}
|
||||
#ifdef PLATFORM_PS3
|
||||
mLevelData[newblock] = (DSP_LEVEL_TYPE *)FMOD_ALIGNPOINTER(mLevelDataMemory[newblock], 128);
|
||||
#else
|
||||
mLevelData[newblock] = mLevelDataMemory[newblock];
|
||||
#endif
|
||||
|
||||
leveldata = mLevelData[newblock];
|
||||
|
||||
for (count = 0; count < mNumConnections; count++)
|
||||
{
|
||||
DSPConnectionI *conn = &mConnection[newblock][count];
|
||||
|
||||
new (conn) DSPConnectionI;
|
||||
|
||||
conn->init(leveldata, mNumOutputLevels, mNumInputLevels);
|
||||
conn->mNode = &mNodeMemory[newblock][count];
|
||||
conn->mNode->setData(conn);
|
||||
conn->mNode->addAfter(&mFreeListHead);
|
||||
}
|
||||
}
|
||||
|
||||
newconnection = (DSPConnectionI *)mFreeListHead.getNext()->getData();
|
||||
|
||||
newconnection->mInputNode.setData(newconnection);
|
||||
newconnection->mOutputNode.setData(newconnection);
|
||||
|
||||
newconnection->mNode->removeNode();
|
||||
newconnection->mNode->addAfter(&mUsedListHead);
|
||||
|
||||
if (protect)
|
||||
{
|
||||
crit.leave();
|
||||
}
|
||||
|
||||
*connection = newconnection;
|
||||
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT DSPConnectionPool::free(DSPConnectionI *connection, bool protect)
|
||||
{
|
||||
LocalCriticalSection crit(mSystem->mDSPConnectionCrit);
|
||||
|
||||
if (!connection)
|
||||
{
|
||||
return FMOD_ERR_INVALID_PARAM;
|
||||
}
|
||||
|
||||
if (protect)
|
||||
{
|
||||
crit.enter();
|
||||
}
|
||||
|
||||
connection->mInputNode.removeNode();
|
||||
connection->mOutputNode.removeNode();
|
||||
|
||||
connection->mInputUnit = 0;
|
||||
connection->mOutputUnit = 0;
|
||||
|
||||
connection->mNode->removeNode();
|
||||
connection->mNode->addAfter(&mFreeListHead);
|
||||
connection->mNode->setData(connection);
|
||||
|
||||
if (protect)
|
||||
{
|
||||
crit.leave();
|
||||
}
|
||||
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
|
||||
#ifdef FMOD_SUPPORT_MEMORYTRACKER
|
||||
|
||||
FMOD_RESULT DSPConnectionPool::getMemoryUsedImpl(MemoryTracker *tracker)
|
||||
{
|
||||
for (int i=0; i < DSP_MAX_CONNECTION_BLOCKS; i++)
|
||||
{
|
||||
if (mConnectionMemory[i])
|
||||
{
|
||||
tracker->add(false, FMOD_MEMBITS_DSPCONNECTION, mNumConnections * sizeof(DSPConnectionI) + 16);
|
||||
}
|
||||
|
||||
if (mNodeMemory[i])
|
||||
{
|
||||
tracker->add(false, FMOD_MEMBITS_DSPCONNECTION, mNumConnections * sizeof(LinkedListNode));
|
||||
}
|
||||
|
||||
if (mLevelDataMemory[i])
|
||||
{
|
||||
unsigned int alignment = 0;
|
||||
|
||||
#ifdef PLATFORM_PS3
|
||||
alignment = 128;
|
||||
#endif
|
||||
|
||||
tracker->add(false, FMOD_MEMBITS_DSPCONNECTION, mNumConnections /* How many connections are we going to allow maximum. */
|
||||
* (mNumOutputLevels < 2 ? 2 : mNumOutputLevels) /* Number of rows. This should be at least 2 for panning. */
|
||||
* (mNumInputLevels < mNumOutputLevels ? mNumOutputLevels : mNumInputLevels) /* Because pan matricies can be [outputlevels][outputlevels] we need to have at least this */
|
||||
* sizeof(DSP_LEVEL_TYPE) /* Float values of course. Maybe lower? */
|
||||
* 3 /* *3 = mLevel, mLevelCurrent, mLevelDelta */
|
||||
+ alignment /* PS3 - 128 byte aligned for DMA */
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
48
src/fmod_dsp_connectionpool.h
Executable file
48
src/fmod_dsp_connectionpool.h
Executable file
|
|
@ -0,0 +1,48 @@
|
|||
#ifndef _FMOD_DSP_CONNECTIONPOOL_H
|
||||
#define _FMOD_DSP_CONNECTIONPOOL_H
|
||||
|
||||
#include "fmod_settings.h"
|
||||
|
||||
#include "fmod_dsp_connectioni.h"
|
||||
|
||||
#ifndef _FMOD_MEMORYTRACKER_H
|
||||
#include "fmod_memorytracker.h"
|
||||
#endif
|
||||
|
||||
#define DSP_MAX_CONNECTION_BLOCKS 128
|
||||
|
||||
namespace FMOD
|
||||
{
|
||||
class SystemI;
|
||||
class DSPConnectionI;
|
||||
|
||||
class DSPConnectionPool
|
||||
{
|
||||
DECLARE_MEMORYTRACKER
|
||||
|
||||
private:
|
||||
|
||||
SystemI *mSystem;
|
||||
DSPConnectionI *mConnection[DSP_MAX_CONNECTION_BLOCKS];
|
||||
DSPConnectionI *mConnectionMemory[DSP_MAX_CONNECTION_BLOCKS];
|
||||
LinkedListNode *mNodeMemory[DSP_MAX_CONNECTION_BLOCKS];
|
||||
int mNumInputLevels;
|
||||
int mNumOutputLevels;
|
||||
int mNumConnections;
|
||||
LinkedListNode mUsedListHead;
|
||||
LinkedListNode mFreeListHead;
|
||||
DSP_LEVEL_TYPE *mLevelData[DSP_MAX_CONNECTION_BLOCKS];
|
||||
DSP_LEVEL_TYPE *mLevelDataMemory[DSP_MAX_CONNECTION_BLOCKS];
|
||||
|
||||
public:
|
||||
|
||||
FMOD_RESULT init(SystemI *system, int numconnections, int numoutputlevels, int numinputlevels);
|
||||
FMOD_RESULT close();
|
||||
|
||||
FMOD_RESULT alloc(DSPConnectionI **connection, bool protect = true);
|
||||
FMOD_RESULT free(DSPConnectionI *connection, bool protect = true);
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
373
src/fmod_dsp_convert.cpp
Executable file
373
src/fmod_dsp_convert.cpp
Executable file
|
|
@ -0,0 +1,373 @@
|
|||
#include "fmod_settings.h"
|
||||
|
||||
#include "fmod_dspi.h"
|
||||
#include "fmod_dsp_filter.h"
|
||||
#include "fmod_dsp_resampler.h"
|
||||
#include "fmod_dsp_soundcard.h"
|
||||
#include "fmod_localcriticalsection.h"
|
||||
#include "fmod_memory.h"
|
||||
#include "fmod_soundi.h"
|
||||
#include "fmod_string.h"
|
||||
#include "fmod_systemi.h"
|
||||
|
||||
#ifdef FMOD_SUPPORT_SIMD
|
||||
extern "C"
|
||||
{
|
||||
void FMOD_DSP_Convert_FloatToPCM16(short *outbuffer, float *inbuffer, unsigned int length, int destchannelstep, int srcchannelstep, float volume);
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace FMOD
|
||||
{
|
||||
|
||||
|
||||
/*
|
||||
[
|
||||
[DESCRIPTION]
|
||||
|
||||
[PARAMETERS]
|
||||
|
||||
[RETURN_VALUE]
|
||||
FMOD_OK
|
||||
|
||||
[REMARKS]
|
||||
|
||||
[PLATFORMS]
|
||||
|
||||
[SEE_ALSO]
|
||||
]
|
||||
*/
|
||||
FMOD_RESULT DSPI::convert(void *outbuffer, void *inbuffer, FMOD_SOUND_FORMAT outformat, FMOD_SOUND_FORMAT informat, unsigned int length, int destchannelstep, int srcchannelstep, float volume)
|
||||
{
|
||||
bool supportssimd;
|
||||
|
||||
supportssimd = FMOD_OS_SupportsSIMD();
|
||||
|
||||
if (outformat == FMOD_SOUND_FORMAT_PCMFLOAT)
|
||||
{
|
||||
float *destptr = (float *)outbuffer;
|
||||
|
||||
switch (informat)
|
||||
{
|
||||
case FMOD_SOUND_FORMAT_PCM8:
|
||||
{
|
||||
signed char *srcptr = (signed char *)inbuffer;
|
||||
unsigned int len;
|
||||
|
||||
volume /= (float)(1<<7);
|
||||
|
||||
len = length >> 3;
|
||||
while (len)
|
||||
{
|
||||
destptr[0 * destchannelstep] = (float)srcptr[0 * srcchannelstep] * volume;
|
||||
destptr[1 * destchannelstep] = (float)srcptr[1 * srcchannelstep] * volume;
|
||||
destptr[2 * destchannelstep] = (float)srcptr[2 * srcchannelstep] * volume;
|
||||
destptr[3 * destchannelstep] = (float)srcptr[3 * srcchannelstep] * volume;
|
||||
destptr[4 * destchannelstep] = (float)srcptr[4 * srcchannelstep] * volume;
|
||||
destptr[5 * destchannelstep] = (float)srcptr[5 * srcchannelstep] * volume;
|
||||
destptr[6 * destchannelstep] = (float)srcptr[6 * srcchannelstep] * volume;
|
||||
destptr[7 * destchannelstep] = (float)srcptr[7 * srcchannelstep] * volume;
|
||||
destptr += (8 * destchannelstep);
|
||||
srcptr += (8 * srcchannelstep);
|
||||
len--;
|
||||
}
|
||||
len = length & 7;
|
||||
while (len)
|
||||
{
|
||||
destptr[0] = (float)srcptr[0 * srcchannelstep] * volume;
|
||||
destptr += destchannelstep;
|
||||
srcptr += srcchannelstep;
|
||||
len--;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case FMOD_SOUND_FORMAT_PCM16:
|
||||
{
|
||||
signed short *srcptr = (signed short *)inbuffer;
|
||||
unsigned int len;
|
||||
|
||||
volume /= (float)(1<<15);
|
||||
|
||||
len = length >> 3;
|
||||
while (len)
|
||||
{
|
||||
destptr[0 * destchannelstep] = (float)srcptr[0 * srcchannelstep] * volume;
|
||||
destptr[1 * destchannelstep] = (float)srcptr[1 * srcchannelstep] * volume;
|
||||
destptr[2 * destchannelstep] = (float)srcptr[2 * srcchannelstep] * volume;
|
||||
destptr[3 * destchannelstep] = (float)srcptr[3 * srcchannelstep] * volume;
|
||||
destptr[4 * destchannelstep] = (float)srcptr[4 * srcchannelstep] * volume;
|
||||
destptr[5 * destchannelstep] = (float)srcptr[5 * srcchannelstep] * volume;
|
||||
destptr[6 * destchannelstep] = (float)srcptr[6 * srcchannelstep] * volume;
|
||||
destptr[7 * destchannelstep] = (float)srcptr[7 * srcchannelstep] * volume;
|
||||
destptr += (8 * destchannelstep);
|
||||
srcptr += (8 * srcchannelstep);
|
||||
len--;
|
||||
}
|
||||
len = length & 7;
|
||||
while (len)
|
||||
{
|
||||
destptr[0] = (float)srcptr[0] * volume;
|
||||
destptr += destchannelstep;
|
||||
srcptr += srcchannelstep;
|
||||
len--;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case FMOD_SOUND_FORMAT_PCM24:
|
||||
{
|
||||
FMOD_INT24 *srcptr = (FMOD_INT24 *)inbuffer;
|
||||
unsigned int count;
|
||||
|
||||
volume /= (float)(1<<23);
|
||||
|
||||
for (count = 0; count < length; count++)
|
||||
{
|
||||
signed int val;
|
||||
|
||||
val = ((unsigned int)srcptr->val[0 * srcchannelstep] << 8);
|
||||
val |= ((unsigned int)srcptr->val[1 * srcchannelstep] << 16);
|
||||
val |= ((unsigned int)srcptr->val[2 * srcchannelstep] << 24);
|
||||
val >>= 8;
|
||||
|
||||
destptr[0] = (float)val * volume;
|
||||
srcptr += srcchannelstep;
|
||||
destptr += destchannelstep;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case FMOD_SOUND_FORMAT_PCM32:
|
||||
{
|
||||
signed int *srcptr = (signed int *)inbuffer;
|
||||
unsigned int len;
|
||||
|
||||
volume /= (float)(1U<<31);
|
||||
|
||||
len = length >> 2;
|
||||
while (len)
|
||||
{
|
||||
destptr[0 * destchannelstep] = (float)(srcptr[0 * srcchannelstep]) * volume;
|
||||
destptr[1 * destchannelstep] = (float)(srcptr[1 * srcchannelstep]) * volume;
|
||||
destptr[2 * destchannelstep] = (float)(srcptr[2 * srcchannelstep]) * volume;
|
||||
destptr[3 * destchannelstep] = (float)(srcptr[3 * srcchannelstep]) * volume;
|
||||
destptr += (4 * destchannelstep);
|
||||
srcptr += (4 * srcchannelstep);
|
||||
len--;
|
||||
}
|
||||
len = length & 3;
|
||||
while (len)
|
||||
{
|
||||
destptr[0] = (float)(srcptr[0]) * volume;
|
||||
destptr += destchannelstep;
|
||||
srcptr += srcchannelstep;
|
||||
len--;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case FMOD_SOUND_FORMAT_PCMFLOAT:
|
||||
{
|
||||
float *srcptr = (float *)inbuffer;
|
||||
unsigned int len;
|
||||
|
||||
len = length >> 2;
|
||||
while (len)
|
||||
{
|
||||
destptr[0 * destchannelstep] = srcptr[0 * srcchannelstep] * volume;
|
||||
destptr[1 * destchannelstep] = srcptr[1 * srcchannelstep] * volume;
|
||||
destptr[2 * destchannelstep] = srcptr[2 * srcchannelstep] * volume;
|
||||
destptr[3 * destchannelstep] = srcptr[3 * srcchannelstep] * volume;
|
||||
destptr += (4 * destchannelstep);
|
||||
srcptr += (4 * srcchannelstep);
|
||||
len--;
|
||||
}
|
||||
|
||||
len = length & 3;
|
||||
while (len)
|
||||
{
|
||||
destptr[0] = srcptr[0] * volume;
|
||||
destptr += destchannelstep;
|
||||
srcptr += srcchannelstep;
|
||||
len--;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
float *srcptr = (float *)inbuffer;
|
||||
|
||||
/*
|
||||
Source must be float!
|
||||
*/
|
||||
if (informat != FMOD_SOUND_FORMAT_PCMFLOAT)
|
||||
{
|
||||
return FMOD_ERR_DSP_FORMAT;
|
||||
}
|
||||
|
||||
switch (outformat)
|
||||
{
|
||||
case FMOD_SOUND_FORMAT_PCM8:
|
||||
{
|
||||
signed char *destptr = (signed char *)outbuffer;
|
||||
unsigned int len;
|
||||
|
||||
volume *= (float)(1<<7);
|
||||
|
||||
len = length >> 2;
|
||||
while (len)
|
||||
{
|
||||
signed int val[4];
|
||||
|
||||
val[0] = (signed int)(srcptr[0 * srcchannelstep] * volume);
|
||||
val[1] = (signed int)(srcptr[1 * srcchannelstep] * volume);
|
||||
val[2] = (signed int)(srcptr[2 * srcchannelstep] * volume);
|
||||
val[3] = (signed int)(srcptr[3 * srcchannelstep] * volume);
|
||||
|
||||
destptr[0 * destchannelstep] = val[0] < -128 ? -128 : val[0] > 127 ? 127 : (signed char)val[0];
|
||||
destptr[1 * destchannelstep] = val[1] < -128 ? -128 : val[1] > 127 ? 127 : (signed char)val[1];
|
||||
destptr[2 * destchannelstep] = val[2] < -128 ? -128 : val[2] > 127 ? 127 : (signed char)val[2];
|
||||
destptr[3 * destchannelstep] = val[3] < -128 ? -128 : val[3] > 127 ? 127 : (signed char)val[3];
|
||||
|
||||
srcptr += (4 * srcchannelstep);
|
||||
destptr += (4 * destchannelstep);
|
||||
len--;
|
||||
}
|
||||
|
||||
len = length & 3;
|
||||
while (len)
|
||||
{
|
||||
signed int val;
|
||||
|
||||
val = (signed int)(srcptr[0] * volume);
|
||||
|
||||
destptr[0] = val < -128 ? -128 : val > 127 ? 127 : (signed char)val;
|
||||
|
||||
srcptr += srcchannelstep;
|
||||
destptr += destchannelstep;
|
||||
len--;
|
||||
}
|
||||
break;
|
||||
break;
|
||||
}
|
||||
case FMOD_SOUND_FORMAT_PCM16:
|
||||
{
|
||||
volume *= (float)(1<<15);
|
||||
|
||||
#ifdef FMOD_SUPPORT_SIMD
|
||||
if (supportssimd)
|
||||
{
|
||||
FMOD_DSP_Convert_FloatToPCM16((short *)outbuffer, (float *)inbuffer, length, destchannelstep, srcchannelstep, volume);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
signed short *destptr = (signed short *)outbuffer;
|
||||
unsigned int len;
|
||||
|
||||
len = length >> 2;
|
||||
while (len)
|
||||
{
|
||||
signed int val[4];
|
||||
|
||||
val[0] = (signed int)(srcptr[0 * srcchannelstep] * volume);
|
||||
val[1] = (signed int)(srcptr[1 * srcchannelstep] * volume);
|
||||
val[2] = (signed int)(srcptr[2 * srcchannelstep] * volume);
|
||||
val[3] = (signed int)(srcptr[3 * srcchannelstep] * volume);
|
||||
|
||||
destptr[0 * destchannelstep] = val[0] < -32768 ? -32768 : val[0] > 32767 ? 32767 : (signed short)val[0];
|
||||
destptr[1 * destchannelstep] = val[1] < -32768 ? -32768 : val[1] > 32767 ? 32767 : (signed short)val[1];
|
||||
destptr[2 * destchannelstep] = val[2] < -32768 ? -32768 : val[2] > 32767 ? 32767 : (signed short)val[2];
|
||||
destptr[3 * destchannelstep] = val[3] < -32768 ? -32768 : val[3] > 32767 ? 32767 : (signed short)val[3];
|
||||
|
||||
srcptr += (4 * srcchannelstep);
|
||||
destptr += (4 * destchannelstep);
|
||||
len--;
|
||||
}
|
||||
|
||||
len = length & 3;
|
||||
while (len)
|
||||
{
|
||||
signed int val;
|
||||
|
||||
val = (signed int)(srcptr[0] * volume);
|
||||
|
||||
destptr[0] = val < -32768 ? -32768 : val > 32767 ? 32767 : (signed short)val;
|
||||
|
||||
srcptr += srcchannelstep;
|
||||
destptr += destchannelstep;
|
||||
len--;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case FMOD_SOUND_FORMAT_PCM24:
|
||||
{
|
||||
FMOD_INT24 *destptr = (FMOD_INT24 *)outbuffer;
|
||||
unsigned int count;
|
||||
|
||||
volume *= (float)(1<<23);
|
||||
|
||||
for (count = 0; count < length; count++)
|
||||
{
|
||||
signed int val;
|
||||
|
||||
val = (signed int)(srcptr[0] * volume);
|
||||
val = val < -8388608 ? -8388608 : val > 8388607 ? 8388607 : val;
|
||||
|
||||
destptr->val[0] = (val >> 0) & 0xFF;
|
||||
destptr->val[1] = (val >> 8) & 0xFF;
|
||||
destptr->val[2] = (val >> 16) & 0xFF;
|
||||
destptr += destchannelstep;
|
||||
srcptr += srcchannelstep;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case FMOD_SOUND_FORMAT_PCM32:
|
||||
{
|
||||
signed int *destptr = (signed int *)outbuffer;
|
||||
unsigned int count;
|
||||
|
||||
volume *= (float)(1U<<31);
|
||||
|
||||
for (count = 0; count < length; count++)
|
||||
{
|
||||
float val = srcptr[0] * volume;
|
||||
destptr[0] = val < -2147483648.0f ? -(signed int)2147483647 : val > 2147483647.0f ? 2147483647 : (signed int)val;
|
||||
|
||||
destptr += destchannelstep;
|
||||
srcptr += srcchannelstep;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case FMOD_SOUND_FORMAT_PCMFLOAT:
|
||||
{
|
||||
float *destptr = (float *)outbuffer;
|
||||
unsigned int count;
|
||||
|
||||
for (count = 0; count < length; count++)
|
||||
{
|
||||
float val = srcptr[0] * volume;
|
||||
destptr[0] = val < -1.0f ? -1.0f : val > 1.0f ? 1.0f : val;
|
||||
|
||||
destptr += destchannelstep;
|
||||
srcptr += srcchannelstep;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
1575
src/fmod_dsp_delay.cpp
Executable file
1575
src/fmod_dsp_delay.cpp
Executable file
File diff suppressed because it is too large
Load diff
87
src/fmod_dsp_delay.h
Executable file
87
src/fmod_dsp_delay.h
Executable file
|
|
@ -0,0 +1,87 @@
|
|||
#ifndef _FMOD_DSP_DELAY_H
|
||||
#define _FMOD_DSP_DELAY_H
|
||||
|
||||
#include "fmod_settings.h"
|
||||
|
||||
#ifdef FMOD_SUPPORT_DELAY
|
||||
|
||||
#include "fmod.h"
|
||||
#include "fmod_dsp_filter.h"
|
||||
|
||||
#if !defined(PLATFORM_PS3) && !defined(PLATFORM_WINDOWS_PS3MODE)
|
||||
#define DELAY_INTERLEAVED
|
||||
#define DELAY_USEFLOAT
|
||||
#endif
|
||||
#define DELAY_MAX_CHANNELS 16
|
||||
|
||||
namespace FMOD
|
||||
{
|
||||
#if defined(PLATFORM_PS3) || defined(PLATFORM_WINDOWS_PS3MODE)
|
||||
class DSPDelay : public DSPI
|
||||
#else
|
||||
class DSPDelay : public DSPFilter
|
||||
#endif
|
||||
{
|
||||
DECLARE_MEMORYTRACKER_NONVIRTUAL
|
||||
|
||||
private:
|
||||
|
||||
float FMOD_PPCALIGN16(mMaxDelay);
|
||||
float FMOD_PPCALIGN16(mMaxDelayUpdate);
|
||||
float FMOD_PPCALIGN16(mDelay[DELAY_MAX_CHANNELS]);
|
||||
float FMOD_PPCALIGN16(mDelayUpdate[DELAY_MAX_CHANNELS]);
|
||||
int FMOD_PPCALIGN16(mOffset[DELAY_MAX_CHANNELS]);
|
||||
|
||||
#ifdef DELAY_USEFLOAT
|
||||
float *FMOD_PPCALIGN16(mDelayBuffer);
|
||||
float *FMOD_PPCALIGN16(mDelayBufferMemory);
|
||||
#else
|
||||
signed short *FMOD_PPCALIGN16(mDelayBuffer);
|
||||
signed short *FMOD_PPCALIGN16(mDelayBufferMemory);
|
||||
#endif
|
||||
unsigned int FMOD_PPCALIGN16(mDelayBufferLengthBytes);
|
||||
int FMOD_PPCALIGN16(mDelayBufferLength);
|
||||
#ifdef DELAY_INTERLEAVED
|
||||
int FMOD_PPCALIGN16(mWritePosition);
|
||||
#else
|
||||
int FMOD_PPCALIGN16(mWritePosition[DELAY_MAX_CHANNELS]);
|
||||
int FMOD_PPCALIGN16(mBufferStart[DELAY_MAX_CHANNELS+1]);
|
||||
#endif
|
||||
int FMOD_PPCALIGN16(mReadPosition[DELAY_MAX_CHANNELS]);
|
||||
int FMOD_PPCALIGN16(mOutputRate);
|
||||
int FMOD_PPCALIGN16(mChannels);
|
||||
|
||||
#ifdef PLATFORM_PS3
|
||||
short FMOD_PPCALIGN16(mTempWriteMem[DELAY_MAX_CHANNELS][256]); // 8192 bytes
|
||||
short FMOD_PPCALIGN16(mTempReadMem [DELAY_MAX_CHANNELS][256]); // 8192 bytes
|
||||
#endif
|
||||
|
||||
unsigned short mOldSpeakerMask;
|
||||
|
||||
FMOD_RESULT createInternal();
|
||||
FMOD_RESULT releaseInternal();
|
||||
FMOD_RESULT resetInternal();
|
||||
FMOD_RESULT readInternal(float *inbuffer, float *outbuffer, unsigned int length, int inchannels, int outchannels);
|
||||
FMOD_RESULT setParameterInternal(int index, float value);
|
||||
FMOD_RESULT getParameterInternal(int index, float *value, char *valuestr);
|
||||
|
||||
public:
|
||||
|
||||
static FMOD_DSP_DESCRIPTION_EX *getDescriptionEx();
|
||||
|
||||
static FMOD_RESULT F_CALLBACK createCallback(FMOD_DSP_STATE *dsp);
|
||||
static FMOD_RESULT F_CALLBACK releaseCallback(FMOD_DSP_STATE *dsp);
|
||||
static FMOD_RESULT F_CALLBACK resetCallback(FMOD_DSP_STATE *dsp);
|
||||
static FMOD_RESULT F_CALLBACK readCallback(FMOD_DSP_STATE *dsp, float *inbuffer, float *outbuffer, unsigned int length, int inchannels, int outchannels);
|
||||
static FMOD_RESULT F_CALLBACK setParameterCallback(FMOD_DSP_STATE *dsp, int index, float value);
|
||||
static FMOD_RESULT F_CALLBACK getParameterCallback(FMOD_DSP_STATE *dsp, int index, float *value, char *valuestr);
|
||||
#ifdef FMOD_SUPPORT_MEMORYTRACKER
|
||||
static FMOD_RESULT F_CALLBACK getMemoryUsedCallback(FMOD_DSP_STATE *dsp, MemoryTracker *tracker);
|
||||
#endif
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
48
src/fmod_dsp_distortion.h
Executable file
48
src/fmod_dsp_distortion.h
Executable file
|
|
@ -0,0 +1,48 @@
|
|||
#ifndef _FMOD_DSP_DISTORTION_H
|
||||
#define _FMOD_DSP_DISTORTION_H
|
||||
|
||||
#include "fmod_settings.h"
|
||||
|
||||
#ifdef FMOD_SUPPORT_DISTORTION
|
||||
|
||||
#include "fmod.h"
|
||||
#include "fmod_dsp_filter.h"
|
||||
|
||||
namespace FMOD
|
||||
{
|
||||
class DSPDistortion : public DSPFilter
|
||||
{
|
||||
DECLARE_MEMORYTRACKER_NONVIRTUAL
|
||||
|
||||
private:
|
||||
|
||||
float mLevel;
|
||||
bool mSupportsSIMD;
|
||||
|
||||
FMOD_RESULT createInternal();
|
||||
FMOD_RESULT releaseInternal();
|
||||
FMOD_RESULT resetInternal();
|
||||
FMOD_RESULT readInternal(float *inbuffer, float *outbuffer, unsigned int length, int inchannels, int outchannels);
|
||||
FMOD_RESULT setParameterInternal(int index, float value);
|
||||
FMOD_RESULT getParameterInternal(int index, float *value, char *valuestr);
|
||||
|
||||
public:
|
||||
|
||||
static FMOD_DSP_DESCRIPTION_EX *getDescriptionEx();
|
||||
|
||||
static FMOD_RESULT F_CALLBACK createCallback(FMOD_DSP_STATE *dsp);
|
||||
static FMOD_RESULT F_CALLBACK releaseCallback(FMOD_DSP_STATE *dsp);
|
||||
static FMOD_RESULT F_CALLBACK resetCallback(FMOD_DSP_STATE *dsp);
|
||||
static FMOD_RESULT F_CALLBACK readCallback(FMOD_DSP_STATE *dsp, float *inbuffer, float *outbuffer, unsigned int length, int inchannels, int outchannels);
|
||||
static FMOD_RESULT F_CALLBACK setParameterCallback(FMOD_DSP_STATE *dsp, int index, float value);
|
||||
static FMOD_RESULT F_CALLBACK getParameterCallback(FMOD_DSP_STATE *dsp, int index, float *value, char *valuestr);
|
||||
#ifdef FMOD_SUPPORT_MEMORYTRACKER
|
||||
static FMOD_RESULT F_CALLBACK getMemoryUsedCallback(FMOD_DSP_STATE *dsp, MemoryTracker *tracker);
|
||||
#endif
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
1062
src/fmod_dsp_echo.cpp
Executable file
1062
src/fmod_dsp_echo.cpp
Executable file
File diff suppressed because it is too large
Load diff
76
src/fmod_dsp_echo.h
Executable file
76
src/fmod_dsp_echo.h
Executable file
|
|
@ -0,0 +1,76 @@
|
|||
#ifndef _FMOD_DSP_ECHO_H
|
||||
#define _FMOD_DSP_ECHO_H
|
||||
|
||||
#include "fmod_settings.h"
|
||||
|
||||
#ifdef FMOD_SUPPORT_ECHO
|
||||
|
||||
#include "fmod.h"
|
||||
#include "fmod_dsp_filter.h"
|
||||
|
||||
namespace FMOD
|
||||
{
|
||||
#if defined(PLATFORM_PS3) || defined(PLATFORM_WINDOWS_PS3MODE)
|
||||
class DSPEcho : public DSPI
|
||||
#else
|
||||
class DSPEcho : public DSPFilter
|
||||
#endif
|
||||
{
|
||||
DECLARE_MEMORYTRACKER_NONVIRTUAL
|
||||
|
||||
private:
|
||||
|
||||
float FMOD_PPCALIGN16(mDelay);
|
||||
float FMOD_PPCALIGN16(mDecayRatio);
|
||||
float FMOD_PPCALIGN16(mDryMix);
|
||||
float FMOD_PPCALIGN16(mWetMix);
|
||||
int FMOD_PPCALIGN16(mMaxChannels);
|
||||
|
||||
float FMOD_PPCALIGN16(mDelayUpdate);
|
||||
float FMOD_PPCALIGN16(mDecayRatioUpdate);
|
||||
float FMOD_PPCALIGN16(mDryMixUpdate);
|
||||
float FMOD_PPCALIGN16(mWetMixUpdate);
|
||||
#ifdef ECHO_USEFLOAT
|
||||
float *FMOD_PPCALIGN16(mEchoBuffer);
|
||||
float *FMOD_PPCALIGN16(mEchoBufferMemory);
|
||||
#else
|
||||
signed short *FMOD_PPCALIGN16(mEchoBuffer);
|
||||
signed short *FMOD_PPCALIGN16(mEchoBufferMemory);
|
||||
#endif
|
||||
unsigned int FMOD_PPCALIGN16(mEchoBufferLengthBytes);
|
||||
unsigned int FMOD_PPCALIGN16(mEchoPosition);
|
||||
unsigned int FMOD_PPCALIGN16(mEchoLength);
|
||||
unsigned int FMOD_PPCALIGN16(mMaxLength);
|
||||
int FMOD_PPCALIGN16(mOutputRate);
|
||||
int FMOD_PPCALIGN16(mChannels);
|
||||
int FMOD_PPCALIGN16(mChannelsUpdate);
|
||||
|
||||
unsigned short mOldSpeakerMask;
|
||||
|
||||
FMOD_RESULT createInternal();
|
||||
FMOD_RESULT releaseInternal();
|
||||
FMOD_RESULT resetInternal();
|
||||
FMOD_RESULT readInternal(float *inbuffer, float *outbuffer, unsigned int length, int inchannels, int outchannels);
|
||||
FMOD_RESULT setParameterInternal(int index, float value);
|
||||
FMOD_RESULT getParameterInternal(int index, float *value, char *valuestr);
|
||||
|
||||
public:
|
||||
|
||||
static FMOD_DSP_DESCRIPTION_EX *getDescriptionEx();
|
||||
|
||||
static FMOD_RESULT F_CALLBACK createCallback(FMOD_DSP_STATE *dsp);
|
||||
static FMOD_RESULT F_CALLBACK releaseCallback(FMOD_DSP_STATE *dsp);
|
||||
static FMOD_RESULT F_CALLBACK resetCallback(FMOD_DSP_STATE *dsp);
|
||||
static FMOD_RESULT F_CALLBACK readCallback(FMOD_DSP_STATE *dsp, float *inbuffer, float *outbuffer, unsigned int length, int inchannels, int outchannels);
|
||||
static FMOD_RESULT F_CALLBACK setParameterCallback(FMOD_DSP_STATE *dsp, int index, float value);
|
||||
static FMOD_RESULT F_CALLBACK getParameterCallback(FMOD_DSP_STATE *dsp, int index, float *value, char *valuestr);
|
||||
#ifdef FMOD_SUPPORT_MEMORYTRACKER
|
||||
static FMOD_RESULT F_CALLBACK getMemoryUsedCallback(FMOD_DSP_STATE *dsp, MemoryTracker *tracker);
|
||||
#endif
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue