2006-04-13 20:47:06 +00:00
|
|
|
#include <ctype.h>
|
|
|
|
|
|
|
|
#include "compat.h"
|
|
|
|
#include "baselayer.h"
|
|
|
|
#include "cache1d.h"
|
|
|
|
|
2006-04-26 19:32:18 +00:00
|
|
|
typedef uint64 uint64_t;
|
|
|
|
#ifdef __APPLE__
|
|
|
|
# include <jfaud/jfaud.hpp>
|
|
|
|
#else
|
|
|
|
# include "jfaud.hpp"
|
|
|
|
#endif
|
|
|
|
|
2006-04-13 20:47:06 +00:00
|
|
|
extern "C" {
|
|
|
|
void initsb(char,char,long,char,char,char,char);
|
|
|
|
void uninitsb(void);
|
|
|
|
void setears(long,long,long,long);
|
|
|
|
void wsayfollow(char *,long,long,long *,long *,char);
|
|
|
|
void wsay(char *,long,long,long);
|
|
|
|
void loadwaves(void);
|
|
|
|
void loadsong(char *);
|
|
|
|
void musicon(void);
|
|
|
|
void musicoff(void);
|
|
|
|
void refreshaudio(void);
|
|
|
|
}
|
|
|
|
|
|
|
|
#define NUMCHANNELS 16
|
|
|
|
#define UNITSPERMTR 640.0
|
|
|
|
#define WAVESFILE "WAVES.KWV"
|
|
|
|
|
|
|
|
static char musistat = 0;
|
|
|
|
static char songname[BMAX_PATH] = "";
|
|
|
|
static JFAud *jfaud = NULL;
|
|
|
|
|
|
|
|
static int kwvnumwaves = 0;
|
|
|
|
static struct _kwvitem {
|
|
|
|
char instname[16];
|
|
|
|
long wavleng;
|
|
|
|
long repstart;
|
|
|
|
long repleng;
|
|
|
|
long finetune;
|
|
|
|
long datastart;
|
|
|
|
} *kwvitems = NULL;
|
|
|
|
|
|
|
|
static struct {
|
|
|
|
long *posx, *posy;
|
|
|
|
JFAudMixerChannel *handle;
|
|
|
|
} sfxchans[NUMCHANNELS];
|
|
|
|
|
|
|
|
class KenFile : public JFAudFile {
|
|
|
|
private:
|
|
|
|
int fh;
|
|
|
|
public:
|
|
|
|
KenFile(const char *filename, const char *subfilename)
|
|
|
|
: JFAudFile(filename, subfilename)
|
|
|
|
{
|
|
|
|
fh = kopen4load(const_cast<char*>(filename), 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual ~KenFile()
|
|
|
|
{
|
|
|
|
if (fh >= 0) kclose(fh);
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual bool IsOpen(void) const { return fh >= 0; }
|
|
|
|
|
|
|
|
virtual long Read(long nbytes, void *buf)
|
|
|
|
{
|
|
|
|
if (fh < 0) return -1;
|
|
|
|
return kread(fh, buf, nbytes);
|
|
|
|
}
|
|
|
|
virtual long Seek(long pos, SeekFrom where)
|
|
|
|
{
|
|
|
|
int when;
|
|
|
|
if (fh < 0) return -1;
|
|
|
|
switch (where) {
|
|
|
|
case JFAudFile::Set: when = SEEK_SET; break;
|
|
|
|
case JFAudFile::Cur: when = SEEK_CUR; break;
|
|
|
|
case JFAudFile::End: when = SEEK_END; break;
|
|
|
|
default: return -1;
|
|
|
|
}
|
|
|
|
return klseek(fh, pos, when);
|
|
|
|
}
|
|
|
|
virtual long Tell(void) const
|
|
|
|
{
|
|
|
|
if (fh < 0) return -1;
|
|
|
|
return klseek(fh, 0, SEEK_CUR);
|
|
|
|
}
|
|
|
|
virtual long Length(void) const
|
|
|
|
{
|
|
|
|
if (fh < 0) return -1;
|
|
|
|
return kfilelength(fh);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
class KWVFile : public JFAudFile {
|
|
|
|
private:
|
|
|
|
int fh;
|
|
|
|
long datastart, datalen, datapos;
|
|
|
|
public:
|
|
|
|
KWVFile(const char *filename, const char *subfilename = NULL)
|
|
|
|
: JFAudFile(filename, NULL),
|
|
|
|
datastart(-1), datalen(-1), datapos(-1)
|
|
|
|
{
|
|
|
|
long i,j;
|
|
|
|
bool found = false;
|
|
|
|
|
|
|
|
if (!subfilename) return;
|
|
|
|
|
|
|
|
for (i=0;i<kwvnumwaves;i++) {
|
|
|
|
for (j=0;j<16 && subfilename[j];j++) {
|
|
|
|
if (tolower(subfilename[j]) != tolower(kwvitems[i].instname[j])) {
|
|
|
|
found = false;
|
|
|
|
break;
|
|
|
|
} else found = true;
|
|
|
|
}
|
|
|
|
if (found) {
|
|
|
|
fh = kopen4load(const_cast<char *>(filename), 0);
|
|
|
|
if (fh < 0) return;
|
|
|
|
|
|
|
|
datastart = kwvitems[i].datastart;
|
|
|
|
datalen = kwvitems[i].wavleng;
|
|
|
|
datapos = 0;
|
|
|
|
klseek(fh, datastart, SEEK_SET);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual ~KWVFile()
|
|
|
|
{
|
|
|
|
if (fh >= 0) kclose(fh);
|
|
|
|
}
|
|
|
|
virtual bool IsOpen(void) const
|
|
|
|
{
|
|
|
|
return datalen > 0 && fh >= 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual long Read(long nbytes, void *buf)
|
|
|
|
{
|
|
|
|
if (!IsOpen()) return -1;
|
|
|
|
if (datalen - datapos < nbytes) nbytes = datalen - datapos;
|
|
|
|
if (nbytes <= 0) return 0;
|
|
|
|
nbytes = kread(fh, buf, nbytes);
|
|
|
|
if (nbytes > 0) datapos += nbytes;
|
|
|
|
return nbytes;
|
|
|
|
}
|
|
|
|
virtual long Seek(long pos, SeekFrom where)
|
|
|
|
{
|
|
|
|
long newpos;
|
|
|
|
if (!IsOpen()) return -1;
|
|
|
|
switch (where) {
|
|
|
|
case JFAudFile::Set: newpos = pos; break;
|
|
|
|
case JFAudFile::Cur: newpos = datapos + pos; break;
|
|
|
|
case JFAudFile::End: newpos = datalen + pos; break;
|
|
|
|
default: return -1;
|
|
|
|
}
|
|
|
|
if (newpos < 0) newpos = 0;
|
|
|
|
else if (newpos > datalen) newpos = datalen;
|
|
|
|
return klseek(fh, datastart + newpos, SEEK_SET);
|
|
|
|
}
|
|
|
|
virtual long Tell(void) const
|
|
|
|
{
|
|
|
|
if (!IsOpen()) return -1;
|
|
|
|
return datapos;
|
|
|
|
}
|
|
|
|
virtual long Length(void) const
|
|
|
|
{
|
|
|
|
if (!IsOpen()) return -1;
|
|
|
|
return datalen;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
static JFAudFile *openfile(const char *fn, const char *subfn)
|
|
|
|
{
|
|
|
|
char *ext;
|
|
|
|
bool loadkwv = false;
|
|
|
|
|
|
|
|
ext = Bstrrchr(fn,'.');
|
|
|
|
if (!ext || Bstrcasecmp(ext, ".kwv"))
|
|
|
|
return static_cast<JFAudFile*>(new KenFile(fn,subfn));
|
|
|
|
if (!subfn) return NULL; // KWV files need a sub name
|
|
|
|
|
|
|
|
return static_cast<JFAudFile*>(new KWVFile(fn, subfn));
|
|
|
|
}
|
|
|
|
|
|
|
|
static void logfunc(const char *s) { initprintf("%s", s); }
|
|
|
|
|
|
|
|
void loadwaves(void)
|
|
|
|
{
|
|
|
|
long fh, i, datastart;
|
|
|
|
|
|
|
|
fh = kopen4load(WAVESFILE, 0);
|
|
|
|
if (fh < 0) return;
|
|
|
|
|
|
|
|
if (kread(fh, &i, 4) != 4 || i != 0) return;
|
|
|
|
if (kread(fh, &kwvnumwaves, 4) != 4) return; kwvnumwaves = B_LITTLE32(kwvnumwaves);
|
|
|
|
|
|
|
|
kwvitems = new struct _kwvitem [kwvnumwaves];
|
|
|
|
if (!kwvitems) {
|
|
|
|
kclose(fh);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
datastart = (4+4) + kwvnumwaves * (16+4*4);
|
|
|
|
for (i=0;i<kwvnumwaves;i++) {
|
|
|
|
if (kread(fh, kwvitems[i].instname, 16) != 16) return;
|
|
|
|
if (kread(fh, &kwvitems[i].wavleng, 4) != 4) return; kwvitems[i].wavleng = B_LITTLE32(kwvitems[i].wavleng);
|
|
|
|
if (kread(fh, &kwvitems[i].repstart, 4) != 4) return; kwvitems[i].repstart = B_LITTLE32(kwvitems[i].repstart);
|
|
|
|
if (kread(fh, &kwvitems[i].repleng, 4) != 4) return; kwvitems[i].repleng = B_LITTLE32(kwvitems[i].repleng);
|
|
|
|
if (kread(fh, &kwvitems[i].finetune, 4) != 4) return; kwvitems[i].finetune = B_LITTLE32(kwvitems[i].finetune);
|
|
|
|
kwvitems[i].datastart = datastart;
|
|
|
|
datastart += kwvitems[i].wavleng;
|
|
|
|
}
|
|
|
|
|
|
|
|
kclose(fh);
|
|
|
|
}
|
|
|
|
|
|
|
|
void initsb(char dadigistat, char damusistat, long dasamplerate, char danumspeakers,
|
|
|
|
char dabytespersample, char daintspersec, char daquality)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (jfaud) return;
|
|
|
|
|
|
|
|
JFAud_SetLogFunc(logfunc);
|
|
|
|
|
|
|
|
jfaud = new JFAud();
|
|
|
|
if (!jfaud) return;
|
|
|
|
|
|
|
|
jfaud->SetUserOpenFunc(openfile);
|
|
|
|
|
|
|
|
musistat = 0;
|
|
|
|
if (!jfaud->InitWave(NULL, NUMCHANNELS, dasamplerate)) {
|
|
|
|
delete jfaud;
|
|
|
|
jfaud = NULL;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
musistat = damusistat;
|
|
|
|
|
|
|
|
for (i=NUMCHANNELS-1;i>=0;i--) sfxchans[i].handle = NULL;
|
|
|
|
|
|
|
|
loadwaves();
|
|
|
|
}
|
|
|
|
|
|
|
|
void uninitsb(void)
|
|
|
|
{
|
|
|
|
if (!jfaud) return;
|
|
|
|
|
|
|
|
delete jfaud;
|
|
|
|
jfaud = NULL;
|
|
|
|
|
|
|
|
if (kwvitems) delete [] kwvitems;
|
|
|
|
}
|
|
|
|
|
|
|
|
void setears(long daposx, long daposy, long daxvect, long dayvect)
|
|
|
|
{
|
|
|
|
JFAudMixer *mixer;
|
|
|
|
|
|
|
|
if (!jfaud) return;
|
|
|
|
mixer = jfaud->GetWave();
|
|
|
|
if (!mixer) return;
|
|
|
|
|
2006-07-02 17:33:49 +00:00
|
|
|
mixer->SetListenerPosition((float)daposx/UNITSPERMTR, 0.0, (float)daposy/UNITSPERMTR);
|
|
|
|
mixer->SetListenerOrientation((float)daxvect/UNITSPERMTR, 0.0, (float)dayvect/UNITSPERMTR, 0.0, 1.0, 0.0);
|
2006-04-13 20:47:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int storehandle(JFAudMixerChannel *handle, long *daxplc, long *dayplc)
|
|
|
|
{
|
|
|
|
int i,empty = -1;
|
|
|
|
|
|
|
|
for (i=NUMCHANNELS-1;i>=0;i--) {
|
|
|
|
if (!sfxchans[i].handle && empty<0) empty = i;
|
|
|
|
if (sfxchans[i].handle == handle) {
|
|
|
|
empty = i;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (empty < 0) return -1;
|
|
|
|
|
|
|
|
sfxchans[empty].handle = handle;
|
|
|
|
sfxchans[empty].posx = daxplc;
|
|
|
|
sfxchans[empty].posy = dayplc;
|
|
|
|
|
|
|
|
return empty;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void stopcb(int r)
|
|
|
|
{
|
|
|
|
jfaud->FreeSound(sfxchans[r].handle);
|
|
|
|
sfxchans[r].handle = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
void wsayfollow(char *dafilename, long dafreq, long davol, long *daxplc, long *dayplc, char followstat)
|
|
|
|
{
|
|
|
|
JFAudMixerChannel *handl;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
if (!jfaud) return;
|
|
|
|
|
|
|
|
handl = jfaud->PlayRawSound(WAVESFILE, dafilename, 1, 11025, 1, 1, false);
|
|
|
|
if (!handl) return;
|
|
|
|
|
|
|
|
if (followstat) r = storehandle(handl, daxplc, dayplc);
|
|
|
|
else r = storehandle(handl, NULL, NULL);
|
|
|
|
|
|
|
|
if (r >= 0) handl->SetStopCallback(stopcb, r);
|
|
|
|
|
|
|
|
handl->SetPitch((float)dafreq / 4096.0);
|
|
|
|
handl->SetGain((float)davol / 256.0);
|
2006-07-02 17:33:49 +00:00
|
|
|
handl->SetPosition((float)(*daxplc) / UNITSPERMTR, 0.0, (float)(*dayplc) / UNITSPERMTR);
|
2006-04-13 20:47:06 +00:00
|
|
|
handl->SetFollowListener(false);
|
|
|
|
handl->SetRolloff(1.0);
|
|
|
|
|
|
|
|
handl->Play();
|
|
|
|
}
|
|
|
|
|
|
|
|
void wsay(char *dafilename, long dafreq, long volume1, long volume2)
|
|
|
|
{
|
|
|
|
JFAudMixerChannel *handl;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
if (!jfaud) return;
|
|
|
|
|
|
|
|
handl = jfaud->PlayRawSound(WAVESFILE, dafilename, 1, 11025, 1, 1, false);
|
|
|
|
if (!handl) return;
|
|
|
|
|
|
|
|
r = storehandle(handl, NULL, NULL);
|
|
|
|
|
|
|
|
if (r >= 0) handl->SetStopCallback(stopcb, r);
|
|
|
|
|
|
|
|
handl->SetPitch((float)dafreq / 4096.0);
|
|
|
|
handl->SetGain((float)volume1 / 256.0);
|
|
|
|
handl->SetPosition(0.0, 0.0, 0.0);
|
|
|
|
handl->SetFollowListener(true);
|
|
|
|
handl->SetRolloff(0.0);
|
|
|
|
|
|
|
|
handl->Play();
|
|
|
|
}
|
|
|
|
|
|
|
|
void loadsong(char *filename)
|
|
|
|
{
|
|
|
|
if (!jfaud) return;
|
|
|
|
strcpy(songname,filename);
|
|
|
|
}
|
|
|
|
|
|
|
|
void musicon(void)
|
|
|
|
{
|
|
|
|
if (!jfaud || !musistat || !songname[0]) return;
|
|
|
|
|
|
|
|
jfaud->PlayMusic(songname);
|
|
|
|
}
|
|
|
|
|
|
|
|
void musicoff(void)
|
|
|
|
{
|
|
|
|
if (!jfaud || !musistat) return;
|
|
|
|
|
|
|
|
jfaud->StopMusic();
|
|
|
|
}
|
|
|
|
|
|
|
|
void refreshaudio(void)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (!jfaud) return;
|
|
|
|
for (i=NUMCHANNELS-1;i>=0;i--) {
|
|
|
|
if (!sfxchans[i].handle || !jfaud->IsValidSound(sfxchans[i].handle)) continue;
|
|
|
|
if (!sfxchans[i].posx || !sfxchans[i].posy) continue;
|
|
|
|
|
|
|
|
sfxchans[i].handle->SetPosition(
|
|
|
|
(float)(*sfxchans[i].posx)/UNITSPERMTR,
|
|
|
|
0.0,
|
2006-07-02 17:33:49 +00:00
|
|
|
(float)(*sfxchans[i].posy)/UNITSPERMTR);
|
2006-04-13 20:47:06 +00:00
|
|
|
}
|
|
|
|
jfaud->Update();
|
|
|
|
}
|