SBSPSS/source/sound/xmplay.cpp

1036 lines
22 KiB
C++
Raw Normal View History

2000-10-05 16:16:09 +02:00
/*=========================================================================
2000-10-10 01:30:58 +02:00
xmplay.cpp
2000-10-05 16:16:09 +02:00
Author: PKG
Created:
Project: Spongebob
Purpose:
Copyright (c) 2000 Climax Development Ltd
===========================================================================*/
/*----------------------------------------------------------------------
Includes
-------- */
#include "xmplay.h"
#ifndef __SYSTEM_DBG_H__
#include "system\dbg.h"
#endif
#ifndef __VID_HEADER_
#include "system\vid.h"
#endif
#ifndef XMPlayer
#include "system\global.h"
#include <xmplay.h>
#endif
/* Std Lib
------- */
/* Data
---- */
/*----------------------------------------------------------------------
Tyepdefs && Defines
------------------- */
/*----------------------------------------------------------------------
Structure defintions
-------------------- */
/*----------------------------------------------------------------------
Function Prototypes
------------------- */
/*----------------------------------------------------------------------
Vars
---- */
/*----------------------------------------------------------------------
Function:
Purpose:
Params:
Returns:
---------------------------------------------------------------------- */
void CXMPlaySound::initialise()
{
int size,i;
#if defined(__TERRITORY_USA__) || defined(__TERRITORY_JAP__)
XM_OnceOffInit(XM_NTSC);
#else
XM_OnceOffInit(XM_PAL);
#endif
setStereo(true);
size=XM_GetSongSize();
for(i=0;i<MAX_SONG_HEADERS;i++)
{
2000-10-10 00:06:20 +02:00
m_songPtr[i]=(u8*)MemAlloc(size,"XMSong");
XM_SetSongAddress(m_songPtr[i]);
2000-10-05 16:16:09 +02:00
}
size=XM_GetFileHeaderSize();
for(i=0;i<MAX_XM_HEADERS;i++)
{
2000-10-10 00:06:20 +02:00
m_fhPtr[i]=(u8*)MemAlloc(size,"XMHeader");
XM_SetFileHeaderAddress(m_fhPtr[i]);
2000-10-05 16:16:09 +02:00
}
VidAddVSyncFunc(XM_Update);
// Clear internal data
for(i=0;i<MAX_XM_SONGS;i++)
{
2000-10-11 18:47:03 +02:00
XMMod *mod=&m_xmMods[i];
2000-10-10 01:30:58 +02:00
mod->m_refCount=0;
2000-10-05 16:16:09 +02:00
}
for(i=0;i<MAX_XM_VABS;i++)
{
2000-10-11 18:47:03 +02:00
XMVab *vab=&m_xmVabs[i];
2000-10-05 16:16:09 +02:00
vab->m_refCount=0;
}
2000-10-10 00:06:20 +02:00
for(i=0;i<NUM_SPU_CHANNELS;i++)
{
2000-10-12 16:35:13 +02:00
m_spuChannelUse[i].m_useType=FREE;
m_spuChannelUse[i].m_playingId=NOT_PLAYING;
m_spuChannelUse[i].m_internalId=0;
m_spuChannelUse[i].m_priority=0;
2000-10-10 00:06:20 +02:00
m_spuChannelUse[i].m_locked=false;
2000-10-12 16:35:13 +02:00
m_spuChannelUse[i].m_vol=MIN_VOLUME;
m_spuChannelUse[i].m_pan=PAN_CENTRE;
2000-10-10 00:06:20 +02:00
}
2000-10-11 18:47:03 +02:00
m_masterSongVolume=0;
m_masterSfxVolume=0;
2000-10-10 00:06:20 +02:00
2000-10-05 16:16:09 +02:00
SOUND_DBGMSG("XMPlay sound initialised");
}
/*----------------------------------------------------------------------
Function:
Purpose:
Params:
Returns:
---------------------------------------------------------------------- */
void CXMPlaySound::shutdown()
{
SOUND_DBGMSG("XMPlay sound shutdown");
}
2000-10-10 00:06:20 +02:00
/*----------------------------------------------------------------------
Function:
Purpose:
Params:
Returns:
---------------------------------------------------------------------- */
2001-07-03 18:54:25 +02:00
#include "gfx\prim.h"
2000-10-12 16:35:13 +02:00
#ifdef __USER_paul__
int dump=false;
#endif
2000-10-10 00:06:20 +02:00
void CXMPlaySound::think()
{
2000-10-12 16:35:13 +02:00
#ifdef __USER_paul__
if(dump)
{
static char *text[]={"SONG","SFX","LOOPINGSFX","SILENT","FREE","CONTINUE"};
spuChannelUse *ch=m_spuChannelUse;
PAUL_DBGMSG("=======");
for(int i=0;i<24;i++,ch++)
{
2000-10-12 17:18:47 +02:00
PAUL_DBGMSG("%02d] u:%s l:%d pid:%04x",i,text[ch->m_useType],ch->m_locked,ch->m_playingId);
2000-10-12 16:35:13 +02:00
}
PAUL_DBGMSG("=======");
dump=false;
}
#endif
2000-10-10 00:06:20 +02:00
int i;
int id;
spuChannelUse *ch;
XM_Feedback fb;
// Check to see if any of the sounds have finished
id=-1;
for(i=0;i<NUM_SPU_CHANNELS;i++)
{
2000-10-12 16:35:13 +02:00
ch=&m_spuChannelUse[i]; // I know!
switch(ch->m_useType)
2000-10-10 00:06:20 +02:00
{
2000-10-12 16:35:13 +02:00
// Silent and unlocked sounds can be freed
case SILENT:
if(!ch->m_locked)
{
2001-05-22 21:48:25 +02:00
if(XM_GetFeedback(ch->m_internalId,&fb))
2000-10-12 16:35:13 +02:00
{
2001-05-22 21:48:25 +02:00
///PAUL_DBGMSG("freeing channels:");
///int j=i;
do
{
///PAUL_DBGMSG(" %d (%d)",j++,ch->m_playingId);
ch->m_useType=FREE;
ch++;
}
while(ch->m_useType==CONTINUE);
2000-10-12 16:35:13 +02:00
}
2001-05-22 21:48:25 +02:00
/// else
///{
/// PAUL_DBGMSG("channel %d not stopped",i);
///}
2000-10-12 16:35:13 +02:00
}
break;
// See if these have finished playing
case SONG:
case SFX:
2000-10-10 00:06:20 +02:00
if(XM_GetFeedback(ch->m_internalId,&fb))
{
2001-05-22 21:48:25 +02:00
// Just mark it as silent, if it's unlocked then it'll die next frame
ch->m_useType=SILENT;
// And kill it in the player
XM_Quit(ch->m_internalId);
///PAUL_DBGMSG("marked %d (%d) as silent",i,ch->m_internalId);
2000-10-10 00:06:20 +02:00
}
2000-10-12 16:35:13 +02:00
break;
case LOOPINGSFX:
case FREE:
case CONTINUE:
break;
2000-10-10 00:06:20 +02:00
}
}
2001-07-03 18:54:25 +02:00
//////////////
{
static const int colours[6][3]=
{
{ 255,255,255 }, // SONG
{ 255, 0,255 }, // SFX
{ 0, 0,255 }, // LOOPINGSFX
{ 255,255, 0 }, // SILENT
{ 0,255, 0 }, // FREE
{ 128,128,128 }, // CONTINUE
};
int i,x,free;
spuChannelUse *ch;
POLY_F4 *f4;
x=50;
free=0;
ch=m_spuChannelUse;
for(i=0;i<NUM_SPU_CHANNELS;i++)
{
const int *colour=&colours[ch->m_useType][0];
f4=GetPrimF4();
setXYWH(f4,x,20,8,8);
setRGB0(f4,*(colour++),*(colour++),*(colour++));
AddPrimToList(f4,0);
if(ch->m_locked)
{
f4=GetPrimF4();
setXYWH(f4,x-1,20-1,8+2,8+2);
setRGB0(f4,0,0,0);
AddPrimToList(f4,0);
}
if(ch->m_useType==FREE)
{
free++;
}
x+=10;
ch++;
}
if(!free)
{
f4=GetPrimF4();
setXYWH(f4,50,30,(24*10)-2,4);
setRGB0(f4,255,0,0);
AddPrimToList(f4,0);
}
}
//////////////
2000-10-10 00:06:20 +02:00
}
2000-10-11 18:47:03 +02:00
/*----------------------------------------------------------------------
Function:
Purpose:
Params:
Returns:
---------------------------------------------------------------------- */
void CXMPlaySound::setMasterSongVolume(unsigned char _vol)
{
int i;
spuChannelUse *ch;
xmPlayingId lastId;
// New volume
if(m_masterSongVolume==_vol) return;
m_masterSongVolume=_vol;
// Now update any active songs
ch=m_spuChannelUse;
lastId=NOT_PLAYING;
for(i=0;i<NUM_SPU_CHANNELS;i++,ch++)
{
if(ch->m_playingId!=lastId&&ch->m_useType==SONG)
{
int oldLock=ch->m_locked; // hmm..
ch->m_locked=true; // not too..
setVolume(ch->m_playingId,ch->m_vol);
ch->m_locked=oldLock; // ..ugly I suppose
lastId=ch->m_playingId;
}
}
}
/*----------------------------------------------------------------------
Function:
Purpose:
Params:
Returns:
---------------------------------------------------------------------- */
void CXMPlaySound::setMasterSfxVolume(unsigned char _vol)
{
int i;
spuChannelUse *ch;
xmPlayingId lastId;
// New volume
if(m_masterSfxVolume==_vol) return;
m_masterSfxVolume=_vol;
// Now update any active sfx
ch=m_spuChannelUse;
lastId=NOT_PLAYING;
for(i=0;i<NUM_SPU_CHANNELS;i++,ch++)
{
if(ch->m_playingId!=lastId&&ch->m_useType==SFX||ch->m_useType==LOOPINGSFX)
{
int oldLock=ch->m_locked; // hmm..
ch->m_locked=true; // not too..
setVolume(ch->m_playingId,ch->m_vol);
ch->m_locked=oldLock; // ..ugly I suppose
lastId=ch->m_playingId;
}
}
}
2000-10-05 16:16:09 +02:00
/*----------------------------------------------------------------------
Function:
Purpose:
Params:
Returns:
---------------------------------------------------------------------- */
2000-10-10 00:06:20 +02:00
xmSampleId CXMPlaySound::loadSampleData(FileEquate _vhFe,FileEquate _vbFe)
2000-10-05 16:16:09 +02:00
{
int vabId;
XMVab *vab;
unsigned char *VbPtr,*VhPtr;
// Is the bank already loaded?
2000-10-11 18:47:03 +02:00
vab=m_xmVabs;
2000-10-05 16:16:09 +02:00
for(vabId=0;vabId<MAX_XM_VABS;vabId++)
{
if(vab->m_refCount&&vab->m_vhFile==_vhFe&&vab->m_vbFile==_vbFe)
{
// Yup..
vab->m_refCount++;
return(xmSampleId)vabId;
}
}
2000-10-06 00:40:39 +02:00
2000-10-05 16:16:09 +02:00
// Find next free vab slot
vabId=0;
2000-10-11 18:47:03 +02:00
vab=m_xmVabs;
2000-10-05 16:16:09 +02:00
while(1)
{
ASSERT(vabId<MAX_XM_VABS);
if(vab->m_refCount==0)
{
VhPtr=(u8*)CFileIO::loadFile(_vhFe);
VbPtr=(u8*)CFileIO::loadFile(_vbFe);
vab->m_vabId=XM_VABInit(VhPtr,VbPtr);
2001-01-30 22:38:06 +01:00
ASSERT(vab->m_vabId!=-1); // Didn't load!
2000-10-05 16:16:09 +02:00
MemFree(VhPtr);
MemFree(VbPtr);
vab->m_vhFile=_vhFe;
vab->m_vbFile=_vbFe;
vab->m_refCount=1;
break;
}
vabId++;vab++;
}
return (xmSampleId)vabId;
}
/*----------------------------------------------------------------------
Function:
Purpose:
Params:
Returns:
---------------------------------------------------------------------- */
2000-10-10 01:30:58 +02:00
xmModId CXMPlaySound::loadModData(FileEquate _modFe)
2000-10-05 16:16:09 +02:00
{
2000-10-10 01:30:58 +02:00
int modId;
XMMod *mod;
2000-10-05 16:16:09 +02:00
2000-10-10 01:30:58 +02:00
// Is the mod already loaded?
2000-10-11 18:47:03 +02:00
mod=m_xmMods;
2000-10-10 01:30:58 +02:00
for(modId=0;modId<MAX_XM_SONGS;modId++)
2000-10-05 16:16:09 +02:00
{
2000-10-10 01:30:58 +02:00
if(mod->m_refCount&&mod->m_file==_modFe)
2000-10-05 16:16:09 +02:00
{
// Yup..
2000-10-10 01:30:58 +02:00
mod->m_refCount++;
return(xmModId)modId;
2000-10-05 16:16:09 +02:00
}
}
2000-10-06 00:40:39 +02:00
2000-10-05 16:16:09 +02:00
// Find next free song slot
2000-10-11 18:47:03 +02:00
mod=m_xmMods;
2000-10-10 01:30:58 +02:00
modId=0;
2000-10-05 16:16:09 +02:00
while(1)
{
2000-10-10 01:30:58 +02:00
ASSERT(modId<MAX_XM_SONGS);
if(mod->m_refCount==0)
2000-10-05 16:16:09 +02:00
{
2000-10-10 01:30:58 +02:00
mod->m_xmData=(u8*)CFileIO::loadFile(_modFe);
2001-01-04 18:10:13 +01:00
InitXMData(mod->m_xmData,modId,XM_UseXMPanning);
2000-10-10 01:30:58 +02:00
mod->m_file=_modFe;
mod->m_refCount=1;
2000-10-05 16:16:09 +02:00
break;
}
2000-10-10 01:30:58 +02:00
modId++;mod++;
2000-10-05 16:16:09 +02:00
}
2000-10-10 01:30:58 +02:00
return (xmModId)modId;
2000-10-05 16:16:09 +02:00
}
/*----------------------------------------------------------------------
Function:
Purpose:
Params:
Returns:
---------------------------------------------------------------------- */
2000-10-10 00:06:20 +02:00
void CXMPlaySound::dumpSampleData(xmSampleId _sampleId)
2000-10-05 16:16:09 +02:00
{
XMVab *vab;
2000-10-11 18:47:03 +02:00
vab=&m_xmVabs[_sampleId];
2000-10-05 16:16:09 +02:00
vab->m_refCount--;
if(vab->m_refCount==0)
{
XM_CloseVAB(vab->m_vabId);
}
}
/*----------------------------------------------------------------------
Function:
Purpose:
Params:
Returns:
---------------------------------------------------------------------- */
2000-10-10 01:30:58 +02:00
void CXMPlaySound::dumpModData(xmModId _modId)
2000-10-05 16:16:09 +02:00
{
2000-10-10 01:30:58 +02:00
XMMod *mod;
2000-10-05 16:16:09 +02:00
2000-10-11 18:47:03 +02:00
mod=&m_xmMods[_modId];
2000-10-10 01:30:58 +02:00
mod->m_refCount--;
if(mod->m_refCount==0)
2000-10-05 16:16:09 +02:00
{
2000-10-10 01:30:58 +02:00
MemFree(mod->m_xmData);
2000-10-05 16:16:09 +02:00
}
}
/*----------------------------------------------------------------------
Function:
Purpose:
Params:
Returns:
---------------------------------------------------------------------- */
void CXMPlaySound::setStereo(int _stereo)
{
if(_stereo)
XM_SetStereo();
else
XM_SetMono();
}
/*----------------------------------------------------------------------
Function:
Purpose:
Params:
Returns:
---------------------------------------------------------------------- */
2000-10-10 01:30:58 +02:00
void CXMPlaySound::setVolume(xmPlayingId _playingId,unsigned char _volume)
2000-10-05 16:16:09 +02:00
{
2000-10-11 18:47:03 +02:00
spuChannelUse *ch;
int vol;
2000-10-12 17:18:47 +02:00
ch=&m_spuChannelUse[_playingId&0xff];
2001-05-22 21:48:25 +02:00
if(ch->m_playingId==_playingId)
2000-10-11 18:47:03 +02:00
{
2001-05-22 21:48:25 +02:00
ASSERT(ch->m_locked!=false); // Cant alter unlocked channels!
ch->m_vol=_volume; // Update volume
switch(ch->m_useType)
2000-10-11 18:47:03 +02:00
{
2001-05-22 21:48:25 +02:00
case SILENT:
break;
case SONG:
vol=(_volume*m_masterSongVolume)>>8;
XM_SetMasterVol(ch->m_internalId,vol>>1);
break;
case SFX:
vol=(_volume*m_masterSfxVolume)>>8;
XM_SetMasterVol(ch->m_internalId,vol>>1);
break;
case LOOPINGSFX:
updateLoopingSfx(ch);
break;
case FREE:
case CONTINUE:
ASSERT(0);
break;
2000-10-11 18:47:03 +02:00
}
2001-05-22 21:48:25 +02:00
return;
2000-10-11 18:47:03 +02:00
}
2001-05-22 21:48:25 +02:00
2000-10-11 18:47:03 +02:00
ASSERT(0); // Couldn't find the sound to unlock it!
2000-10-05 16:16:09 +02:00
}
/*----------------------------------------------------------------------
Function:
Purpose:
Params:
Returns:
---------------------------------------------------------------------- */
2000-10-10 01:30:58 +02:00
void CXMPlaySound::setPanning(xmPlayingId _playingId,char _pan)
2000-10-05 16:16:09 +02:00
{
2000-10-11 18:47:03 +02:00
spuChannelUse *ch;
2000-10-12 17:18:47 +02:00
ch=&m_spuChannelUse[_playingId&0xff];
2001-05-22 21:48:25 +02:00
if(ch->m_playingId==_playingId)
2000-10-11 18:47:03 +02:00
{
2001-05-22 21:48:25 +02:00
ASSERT(ch->m_locked!=false); // Cant alter unlocked channels!
ch->m_pan=_pan; // Update pan
switch(ch->m_useType)
2000-10-11 18:47:03 +02:00
{
2001-05-22 21:48:25 +02:00
case SILENT:
break;
case SONG:
XM_SetMasterPan(ch->m_internalId,_pan-128);
break;
case SFX:
XM_SetMasterPan(ch->m_internalId,_pan-128);
break;
case LOOPINGSFX:
updateLoopingSfx(ch);
break;
case FREE:
case CONTINUE:
ASSERT(0);
break;
2000-10-11 18:47:03 +02:00
}
2001-05-22 21:48:25 +02:00
return;
2000-10-11 18:47:03 +02:00
}
2001-05-22 21:48:25 +02:00
2000-10-11 18:47:03 +02:00
ASSERT(0); // Couldn't find the sound to unlock it!
2000-10-05 16:16:09 +02:00
}
2000-10-11 18:47:03 +02:00
2001-03-29 03:29:11 +02:00
/*----------------------------------------------------------------------
Function:
Purpose:
Params:
Returns:
---------------------------------------------------------------------- */
void CXMPlaySound::stopAndUnlockAllSfx()
{
int i;
spuChannelUse *ch;
ch=m_spuChannelUse;
for(i=0;i<NUM_SPU_CHANNELS;i++,ch++)
{
if(ch->m_useType==SFX||
ch->m_useType==LOOPINGSFX)
{
ch->m_locked=true; // hmm.. not too ugly I suppose
setVolume(ch->m_playingId,0);
stopPlayingId(ch->m_playingId);
// Need to unlock too
unlockPlayingId(ch->m_playingId);
}
}
}
2000-10-05 16:16:09 +02:00
/*----------------------------------------------------------------------
Function:
Purpose:
Params:
Returns:
---------------------------------------------------------------------- */
2000-10-11 18:47:03 +02:00
void CXMPlaySound::stopAndUnlockAllSound()
2000-10-05 16:16:09 +02:00
{
2000-10-11 18:47:03 +02:00
int i;
2000-10-12 16:35:13 +02:00
spuChannelUse *ch;
2000-10-11 18:47:03 +02:00
ch=m_spuChannelUse;
for(i=0;i<NUM_SPU_CHANNELS;i++,ch++)
{
2000-10-12 16:35:13 +02:00
if(ch->m_useType==SONG||
ch->m_useType==SFX||
ch->m_useType==LOOPINGSFX)
2000-10-11 18:47:03 +02:00
{
2000-10-12 16:35:13 +02:00
ch->m_locked=true; // hmm.. not too ugly I suppose
2000-10-11 18:47:03 +02:00
stopPlayingId(ch->m_playingId);
// Need to unlock too
2000-10-12 16:35:13 +02:00
unlockPlayingId(ch->m_playingId);
2000-10-11 18:47:03 +02:00
}
}
}
/*----------------------------------------------------------------------
Function:
Purpose:
Params:
Returns:
---------------------------------------------------------------------- */
2001-01-19 17:25:05 +01:00
xmPlayingId CXMPlaySound::playSong(xmSampleId _sampleId,xmModId _modId,int _startPattern)
2000-10-11 18:47:03 +02:00
{
int channelCount,baseChannel;
2000-10-10 00:06:20 +02:00
XMVab *vab;
int id;
xmPlayingId retId;
2000-10-05 16:16:09 +02:00
2000-10-11 18:47:03 +02:00
ASSERT(m_xmVabs[_sampleId].m_refCount!=0);
ASSERT(m_xmMods[_modId].m_refCount!=0);
2000-10-10 00:06:20 +02:00
2000-10-11 18:47:03 +02:00
// Let's grab the channel count from the XM data.. :)
channelCount=(short int)*(m_xmMods[_modId].m_xmData+68);
SOUND_DBGMSG("Playing song with %d channels reserved",channelCount);
baseChannel=findSpareChannels(channelCount,255);
2000-10-10 00:06:20 +02:00
if(baseChannel!=-1)
{
2000-10-12 17:18:47 +02:00
retId=getNextSparePlayingId(baseChannel);
2000-10-11 18:47:03 +02:00
vab=&m_xmVabs[_sampleId];
id=XM_Init(vab->m_vabId, // id from XM_VABInit
_modId, // XM id ( as passed to InitXMData )
-1, // Let xmplay give us a song id
baseChannel, // First channel
XM_Loop, // Play song continuously
-1, // Play all channels
XM_Music, // Music
2001-01-19 17:25:05 +01:00
_startPattern); // Where to start from
2000-10-11 18:47:03 +02:00
markChannelsAsActive(baseChannel,channelCount,SONG,retId,id,255);
setVolume(retId,MAX_VOLUME);
//PAUL_DBGMSG("playSong %d/%d ( on %d-%d )",retId,id,baseChannel,baseChannel+channelCount-1);
2000-10-10 00:06:20 +02:00
}
else
{
retId=NOT_PLAYING;
}
return retId;
2000-10-05 16:16:09 +02:00
}
2001-06-18 17:59:09 +02:00
/*----------------------------------------------------------------------
Function:
Purpose:
Params:
Returns:
---------------------------------------------------------------------- */
int CXMPlaySound::isStillPlaying(xmPlayingId _playingId)
{
spuChannelUse *ch;
ch=&m_spuChannelUse[_playingId&0xff];
if(ch->m_playingId==_playingId)
{
ASSERT(ch->m_locked!=false); // Can't do this on an unlocked sound!
return ch->m_useType!=SILENT;
}
ASSERT(0); // Couldn't find the sound to check it!
return false;
}
2000-10-10 00:06:20 +02:00
2000-10-05 16:16:09 +02:00
/*----------------------------------------------------------------------
Function:
Purpose:
Params:
Returns:
---------------------------------------------------------------------- */
2000-10-10 00:06:20 +02:00
void CXMPlaySound::unlockPlayingId(xmPlayingId _playingId)
2000-10-05 16:16:09 +02:00
{
2000-10-10 00:06:20 +02:00
spuChannelUse *ch;
2001-03-29 03:29:11 +02:00
ch=&m_spuChannelUse[_playingId&0xff];
2001-05-22 21:48:25 +02:00
if(ch->m_playingId==_playingId)
2000-10-10 00:06:20 +02:00
{
2001-05-22 21:48:25 +02:00
//PAUL_DBGMSG("unlocking %d",_playingId);
2001-06-18 17:59:09 +02:00
ASSERT(ch->m_locked!=false); // Can't do this on an unlocked sound!
2001-05-22 21:48:25 +02:00
do
2000-10-10 00:06:20 +02:00
{
2001-05-22 21:48:25 +02:00
ch->m_locked=false;
ch++;
2000-10-10 00:06:20 +02:00
}
2001-05-22 21:48:25 +02:00
while(ch->m_useType==CONTINUE);
return;
2000-10-10 00:06:20 +02:00
}
2001-05-22 21:48:25 +02:00
2000-10-10 00:06:20 +02:00
ASSERT(0); // Couldn't find the sound to unlock it!
2000-10-05 16:16:09 +02:00
}
/*----------------------------------------------------------------------
Function:
Purpose:
Params:
Returns:
---------------------------------------------------------------------- */
2000-10-10 00:06:20 +02:00
void CXMPlaySound::stopPlayingId(xmPlayingId _playingId)
2000-10-05 16:16:09 +02:00
{
2000-10-10 00:06:20 +02:00
spuChannelUse *ch;
2000-10-06 00:40:39 +02:00
2000-10-12 17:18:47 +02:00
ch=&m_spuChannelUse[_playingId&0xff];
2001-05-22 21:48:25 +02:00
if(ch->m_playingId==_playingId)
2000-10-10 00:06:20 +02:00
{
2001-05-22 21:48:25 +02:00
ASSERT(ch->m_locked!=false); // Cant stop unlocked channels!
switch(ch->m_useType)
2000-10-10 00:06:20 +02:00
{
2001-05-22 21:48:25 +02:00
case SONG:
case SFX:
{
// XM_Feedback fb;
// do
// {
XM_PlayStop(ch->m_internalId);
// XM_GetFeedback(ch->m_internalId,&fb);
// }
// while(fb.Status!=XM_STOPPED);
XM_Quit(ch->m_internalId);
}
break;
case LOOPINGSFX:
XM_StopSample(ch->m_internalId);
break;
case SILENT:
break;
case FREE:
case CONTINUE:
ASSERT(0);
break;
2000-10-10 00:06:20 +02:00
}
2001-05-22 21:48:25 +02:00
ch->m_useType=SILENT;
return;
2000-10-10 00:06:20 +02:00
}
2001-05-22 21:48:25 +02:00
2000-10-10 00:06:20 +02:00
ASSERT(0); // Couldn't find the sound to stop it!
}
/*----------------------------------------------------------------------
Function:
Purpose:
Params:
Returns:
---------------------------------------------------------------------- */
2000-10-11 18:47:03 +02:00
xmPlayingId CXMPlaySound::playSfx(xmSampleId _sampleId,xmModId _modId,int _sfxPattern,int _playMask,u8 _priority)
2000-10-10 00:06:20 +02:00
{
int i,j;
int maskCopy,channelCount;
int valid;
int baseChannel;
XMVab *vab;
int songId;
int id;
xmPlayingId retId;
2000-10-05 16:16:09 +02:00
2000-10-11 18:47:03 +02:00
ASSERT(m_xmVabs[_sampleId].m_refCount!=0);
ASSERT(m_xmMods[_modId].m_refCount!=0);
2000-10-05 16:16:09 +02:00
2000-10-10 00:06:20 +02:00
// Count channels
2000-10-05 16:16:09 +02:00
maskCopy=_playMask;
2000-10-10 00:06:20 +02:00
channelCount=0;
for(i=0;i<NUM_SPU_CHANNELS&&maskCopy;i++)
2000-10-05 16:16:09 +02:00
{
if(maskCopy&1)
channelCount++;
maskCopy>>=1;
}
2000-10-10 00:06:20 +02:00
// Play the sound
baseChannel=findSpareChannels(channelCount,_priority);
if(baseChannel!=-1)
{
2000-10-12 17:18:47 +02:00
retId=getNextSparePlayingId(baseChannel);
2000-10-11 18:47:03 +02:00
vab=&m_xmVabs[_sampleId];
2000-10-10 00:06:20 +02:00
XM_SetSFXRange(baseChannel,channelCount);
2000-10-11 18:47:03 +02:00
id=XM_Init(vab->m_vabId, // id from XM_VABInit
_modId, // XM id ( as passed to InitXMData )
-1, // Let xmplay give us a song id
-1, // Use SFX range to get first channel
XM_NoLoop, // One-shot
_playMask, // Play mask
XM_SFX, // SFX
_sfxPattern); // SFX pattern to play
2000-10-10 00:06:20 +02:00
XM_ClearSFXRange();
2000-10-11 18:47:03 +02:00
//PAUL_DBGMSG("playSfx %d/%d ( on %d-%d )",retId,id,baseChannel,baseChannel+channelCount-1);
2000-10-10 00:06:20 +02:00
markChannelsAsActive(baseChannel,channelCount,SFX,retId,id,_priority);
2000-10-11 18:47:03 +02:00
setVolume(retId,MAX_VOLUME);
2000-10-10 00:06:20 +02:00
}
else
{
retId=NOT_PLAYING;
}
return retId;
}
/*----------------------------------------------------------------------
Function:
Purpose:
Params:
Returns:
---------------------------------------------------------------------- */
2000-10-11 18:47:03 +02:00
xmPlayingId CXMPlaySound::playLoopingSfx(xmSampleId _sampleId,xmModId _modId,int _soundId,u8 _priority,int _pitch)
2000-10-10 00:06:20 +02:00
{
int baseChannel;
xmPlayingId retId;
baseChannel=findSpareChannels(1,_priority);
if(baseChannel!=-1)
{
2000-10-12 17:18:47 +02:00
retId=getNextSparePlayingId(baseChannel);
2000-10-11 18:47:03 +02:00
//PAUL_DBGMSG("playLoopingSfx %d/- ( on %d-%d )",retId,baseChannel,baseChannel);
2000-10-10 00:06:20 +02:00
XM_PlaySample(XM_GetSampleAddress(_sampleId,_soundId),baseChannel,0x3fff,0x3fff,_pitch);
markChannelsAsActive(baseChannel,1,LOOPINGSFX,retId,baseChannel,_priority);
2000-10-11 18:47:03 +02:00
setVolume(retId,MAX_VOLUME);
2000-10-10 00:06:20 +02:00
}
else
{
retId=NOT_PLAYING;
}
return retId;
}
/*----------------------------------------------------------------------
Function:
Purpose:
Params:
Returns:
---------------------------------------------------------------------- */
2000-10-12 17:18:47 +02:00
xmPlayingId CXMPlaySound::getNextSparePlayingId(int _baseChannel)
2000-10-10 00:06:20 +02:00
{
xmPlayingId validId;
int i;
spuChannelUse *ch;
static xmPlayingId nextId=(xmPlayingId)(0-1); // fudge to make first id=0
validId=NOT_PLAYING;
while(validId==NOT_PLAYING)
{
nextId=(xmPlayingId)((nextId+1)&0xff); // gives 256 unique id numbers
// Is this id still in use?
2000-10-12 17:18:47 +02:00
validId=(xmPlayingId)((nextId<<8)+_baseChannel);
2000-10-10 00:06:20 +02:00
ch=m_spuChannelUse;
for(i=0;i<NUM_SPU_CHANNELS&&validId!=NOT_PLAYING;i++)
{
if(ch->m_playingId==validId&&!(ch->m_locked==false&&ch->m_useType==SILENT))
validId=NOT_PLAYING;
ch++;
}
}
return validId;
}
/*----------------------------------------------------------------------
Function:
Purpose: Returns the base channel of a slot big enuf for the
requested number of channels
Params:
Returns: baseChannel or -1 if no space
---------------------------------------------------------------------- */
int CXMPlaySound::findSpareChannels(int _channelCount,int _priority)
{
int i,j;
int valid;
2000-10-12 16:35:13 +02:00
2000-10-10 00:06:20 +02:00
// First we search for channels that are marked as unused
valid=false;
for(i=0;i<NUM_SPU_CHANNELS-_channelCount+1&&valid==false;)
{
valid=true;
for(j=i;j<i+_channelCount&&valid;j++)
{
2000-10-12 16:35:13 +02:00
if(m_spuChannelUse[j].m_useType!=FREE) valid=false;
2000-10-10 00:06:20 +02:00
}
if(valid) return i;
i=j;
}
2000-10-10 01:30:58 +02:00
// PKG - Add priority stuff here!!
2000-10-10 00:06:20 +02:00
// Can't play it :(
return -1;
2000-10-05 16:16:09 +02:00
}
/*----------------------------------------------------------------------
Function:
Purpose:
Params:
Returns:
---------------------------------------------------------------------- */
2000-10-10 00:06:20 +02:00
void CXMPlaySound::markChannelsAsActive(int _baseChannel,int _channelCount,CHANNELUSETYPE _useType,xmPlayingId _playingId,int _internalId,u8 _priority)
2000-10-05 16:16:09 +02:00
{
2000-10-10 00:06:20 +02:00
int i;
2000-10-12 16:35:13 +02:00
spuChannelUse *ch;
2000-10-10 00:06:20 +02:00
2000-10-05 16:16:09 +02:00
2000-10-10 00:06:20 +02:00
ch=&m_spuChannelUse[_baseChannel];
2000-10-12 16:35:13 +02:00
ch->m_useType=_useType;
ch->m_internalId=_internalId;
ch->m_playingId=_playingId;
ch->m_priority=_priority;
ch->m_locked=true;
ch->m_vol=MAX_VOLUME;
ch->m_pan=PAN_CENTRE;
ch++;
2001-03-29 03:29:11 +02:00
for(i=_baseChannel;i<_baseChannel+_channelCount-1;i++,ch++)
2000-10-12 16:35:13 +02:00
{
ch->m_useType=CONTINUE;
}
2000-10-05 16:16:09 +02:00
}
/*----------------------------------------------------------------------
Function:
Purpose: Defrag SPU memory by reloading sample banks. Should mean that
bank load order isn't so vital.
Really needs to check for and pause playing sounds first.. hmm..
Params:
Returns:
---------------------------------------------------------------------- */
void CXMPlaySound::defragSpuMemory()
{
int vabId;
XMVab *vab;
unsigned char *VbPtr,*VhPtr;
SOUND_DBGMSG("CXMPlaySound is defragging..");
// Dump banks
2000-10-11 18:47:03 +02:00
vab=m_xmVabs;
2000-10-05 16:16:09 +02:00
for(vabId=0;vabId<MAX_XM_VABS;vabId++,vab++)
{
if(vab->m_refCount)
{
XM_CloseVAB(vab->m_vabId);
}
}
// Now reload them
2000-10-11 18:47:03 +02:00
vab=m_xmVabs;
2000-10-05 16:16:09 +02:00
for(vabId=0;vabId<MAX_XM_VABS;vabId++,vab++)
{
if(vab->m_refCount)
{
VhPtr=(u8*)CFileIO::loadFile(vab->m_vhFile);
VbPtr=(u8*)CFileIO::loadFile(vab->m_vbFile);
vab->m_vabId=XM_VABInit(VhPtr,VbPtr);
2001-01-30 22:38:06 +01:00
ASSERT(vab->m_vabId!=-1); // Didn't load!
2000-10-05 16:16:09 +02:00
MemFree(VhPtr);
MemFree(VbPtr);
}
}
SOUND_DBGMSG("..done!");
}
2000-10-11 18:47:03 +02:00
/*----------------------------------------------------------------------
Function:
Purpose:
Params:
Returns:
---------------------------------------------------------------------- */
void CXMPlaySound::updateLoopingSfx(spuChannelUse *ch)
{
int actualVol,actualPan;
int leftVol,rightVol;
SpuVoiceAttr attr;
actualVol=(ch->m_vol*m_masterSfxVolume)>>8; // 0=silent, 255=full vol
actualPan=ch->m_pan; // 0=hard left, 255=hard right
leftVol=(actualVol*actualPan)>>2;
rightVol=(actualVol*(255-actualPan))>>2;
ASSERT(leftVol<=0x3fff); ASSERT(leftVol>=0);
ASSERT(rightVol<=0x3fff); ASSERT(rightVol>=0);
attr.voice=(1<<ch->m_internalId);
attr.mask=(SPU_VOICE_VOLL|SPU_VOICE_VOLR);
attr.volume.left=leftVol;
attr.volume.right=rightVol;
SpuSetVoiceAttr(&attr);
}
2000-10-05 16:16:09 +02:00
/*===========================================================================
end */