692 lines
16 KiB
C
692 lines
16 KiB
C
/*************************************************************************
|
|
* *
|
|
* This file contains the tables and definitions for *
|
|
* the synthesis specific DEVice *
|
|
* The device tables are in devtab.c *
|
|
**************************************************************************
|
|
*
|
|
* The following variables and tables must be defined:
|
|
*
|
|
* max_tracks: 1 byte, max # of synthesis channels
|
|
* dev_init: function called to initialize device
|
|
* do_watchdog function called to kick watchdog timer
|
|
* dtimer_int function called to disable timer interrupt
|
|
* etimer_int function called to enable timer interrupt
|
|
* send_dev_function:
|
|
* function called to send a byte of data to the synthesis
|
|
* device (sound call callable)
|
|
* The data is in the global, "a_value" and the address is
|
|
* in the global, "b_value."
|
|
**************************************************************************/
|
|
|
|
#define _base_
|
|
|
|
extern struct DSPpatch *Patches[];
|
|
extern unsigned short Noise8192[];
|
|
|
|
#include <dsound.h>
|
|
#include "sosdsp.h"
|
|
#include "sos.h"
|
|
#include "bootsnd.h"
|
|
#include <xtl.h>
|
|
#include "dsptables.h"
|
|
|
|
#define MAX_BUFFERS 16
|
|
|
|
#ifdef STARTUPANIMATION
|
|
#pragma data_seg("INIT_RW")
|
|
#pragma code_seg("INIT")
|
|
#pragma bss_seg("INIT_RW")
|
|
#pragma const_seg("INIT_RD")
|
|
|
|
#pragma comment(linker, "/merge:INIT_RD=INIT")
|
|
#pragma comment(linker, "/merge:INIT_RW=INIT")
|
|
|
|
#endif
|
|
|
|
LPDIRECTSOUND8 m_pDSound; // DirectSound object
|
|
LPDIRECTSOUNDBUFFER8 m_pDSBuffer[MAX_BUFFERS]; // DirectSoundBuffer
|
|
extern WCHAR StringBuffer[];
|
|
|
|
#define MIN(a,b) (((signed) a) < ((signed) b) ? (a) : (b))
|
|
|
|
/*
|
|
* track_status has the necessary items to restore the state of
|
|
* a track after a track of a higher level on the same channel
|
|
* ends
|
|
*/
|
|
|
|
#define MAX_TRACKS 16
|
|
#define MAX_PROCESSES 30
|
|
#define MAX_LEVELS 2
|
|
|
|
uchar channel_level[MAX_TRACKS];/* current level for each chan*/
|
|
struct track_info track_status[(MAX_LEVELS) * MAX_TRACKS];
|
|
struct process queue_list[MAX_PROCESSES]; /* pre-allocated process packets */
|
|
extern struct sound * _base_ current_call; /* pointer to current sound call */
|
|
extern uchar sound_call_table;
|
|
|
|
|
|
const unsigned short max_processes = MAX_PROCESSES;
|
|
|
|
extern uchar a_value, b_value;
|
|
unsigned int dsp_address;
|
|
unsigned int dsp_data;
|
|
extern ushort value_16_bit;
|
|
extern uchar current_channel;
|
|
extern uchar master_music_volume; /* main attenuation for music */
|
|
extern uchar master_effect_volume; /* main attenuation for f/x */
|
|
extern uchar music_atten; /* music attenuation */
|
|
extern uchar init_call;
|
|
extern uchar current_level; /* global level of current process */
|
|
extern struct track_info * _base_ ti; /* track info pointer */
|
|
extern uchar pan_table[]; /* panning table (8-bit) */
|
|
void put_dsp(void);
|
|
extern reset_dsp();
|
|
void init_dsp(void);
|
|
void put_fifo(unsigned char);
|
|
const unsigned char max_tracks = MAX_TRACKS;
|
|
|
|
extern void (* const call_fcns[])();
|
|
|
|
int volume_dsp(uchar, uchar, uchar *,uchar);
|
|
int silence_dsp(uchar);
|
|
int note_on_dsp();
|
|
int slur_dsp();
|
|
int note_off_dsp();
|
|
int patch_dsp(unsigned short);
|
|
int pan_dsp(uchar , signed char, uchar *);
|
|
int vp_filter();
|
|
|
|
|
|
|
|
int (* const filter_functions[])() = {
|
|
vp_filter,
|
|
vp_filter,
|
|
vp_filter,
|
|
vp_filter,
|
|
vp_filter,
|
|
vp_filter,
|
|
vp_filter,
|
|
vp_filter,
|
|
vp_filter,
|
|
vp_filter,
|
|
vp_filter,
|
|
vp_filter,
|
|
vp_filter,
|
|
vp_filter,
|
|
vp_filter,
|
|
vp_filter
|
|
};
|
|
|
|
|
|
int (* const silence_functions[])() = {
|
|
silence_dsp,
|
|
silence_dsp,
|
|
silence_dsp,
|
|
silence_dsp,
|
|
silence_dsp,
|
|
silence_dsp,
|
|
silence_dsp,
|
|
silence_dsp,
|
|
silence_dsp,
|
|
silence_dsp,
|
|
silence_dsp,
|
|
silence_dsp,
|
|
silence_dsp,
|
|
silence_dsp,
|
|
silence_dsp,
|
|
silence_dsp,
|
|
|
|
};
|
|
|
|
/**************************************************************************
|
|
* *
|
|
* The note_on functions turn a note on. They assume that *
|
|
* the global, "a_value" has the current channel # and that *
|
|
* the global "value_16_bit" has the 16 bit pitch (iiiiiiii.ffffffff *
|
|
* and "b_value" has the integer part of the pitch *
|
|
*************************************************************************/
|
|
int (* const note_on_functions[])() = {
|
|
note_on_dsp,
|
|
note_on_dsp,
|
|
note_on_dsp,
|
|
note_on_dsp,
|
|
note_on_dsp,
|
|
note_on_dsp,
|
|
note_on_dsp,
|
|
note_on_dsp,
|
|
note_on_dsp,
|
|
note_on_dsp,
|
|
note_on_dsp,
|
|
note_on_dsp,
|
|
note_on_dsp,
|
|
note_on_dsp,
|
|
note_on_dsp,
|
|
note_on_dsp,
|
|
};
|
|
|
|
|
|
|
|
int (* const slur_functions[])() = {
|
|
slur_dsp,
|
|
slur_dsp,
|
|
slur_dsp,
|
|
slur_dsp,
|
|
slur_dsp,
|
|
slur_dsp,
|
|
slur_dsp,
|
|
slur_dsp,
|
|
slur_dsp,
|
|
slur_dsp,
|
|
slur_dsp,
|
|
slur_dsp,
|
|
slur_dsp,
|
|
slur_dsp,
|
|
slur_dsp,
|
|
slur_dsp,
|
|
};
|
|
|
|
|
|
/*************************************************************************
|
|
* *
|
|
* The note_off functions turn a note off. They assume that *
|
|
* the global, "a_value" has the current channel. *
|
|
*************************************************************************/
|
|
int (* const note_off_functions[])() = {
|
|
note_off_dsp,
|
|
note_off_dsp,
|
|
note_off_dsp,
|
|
note_off_dsp,
|
|
note_off_dsp,
|
|
note_off_dsp,
|
|
note_off_dsp,
|
|
note_off_dsp,
|
|
note_off_dsp,
|
|
note_off_dsp,
|
|
note_off_dsp,
|
|
note_off_dsp,
|
|
note_off_dsp,
|
|
note_off_dsp,
|
|
note_off_dsp,
|
|
note_off_dsp,
|
|
};
|
|
int (* const patch_functions[]) () = {
|
|
patch_dsp,
|
|
patch_dsp,
|
|
patch_dsp,
|
|
patch_dsp,
|
|
patch_dsp,
|
|
patch_dsp,
|
|
patch_dsp,
|
|
patch_dsp,
|
|
patch_dsp,
|
|
patch_dsp,
|
|
patch_dsp,
|
|
patch_dsp,
|
|
patch_dsp,
|
|
patch_dsp,
|
|
patch_dsp,
|
|
patch_dsp,
|
|
|
|
};
|
|
|
|
|
|
int (* const volume_functions[])() = {
|
|
volume_dsp,
|
|
volume_dsp,
|
|
volume_dsp,
|
|
volume_dsp,
|
|
volume_dsp,
|
|
volume_dsp,
|
|
volume_dsp,
|
|
volume_dsp,
|
|
volume_dsp,
|
|
volume_dsp,
|
|
volume_dsp,
|
|
volume_dsp,
|
|
volume_dsp,
|
|
volume_dsp,
|
|
volume_dsp,
|
|
volume_dsp,
|
|
|
|
};
|
|
int (* const pan_functions[])() = {
|
|
pan_dsp,
|
|
pan_dsp,
|
|
pan_dsp,
|
|
pan_dsp,
|
|
pan_dsp,
|
|
pan_dsp,
|
|
pan_dsp,
|
|
pan_dsp,
|
|
pan_dsp,
|
|
pan_dsp,
|
|
pan_dsp,
|
|
pan_dsp,
|
|
pan_dsp,
|
|
pan_dsp,
|
|
pan_dsp,
|
|
pan_dsp,
|
|
|
|
};
|
|
|
|
|
|
int (* const user_1_var_evf_functions[])() = {
|
|
pan_dsp
|
|
};
|
|
int (* const user_2_var_evf_functions[])() = {
|
|
pan_dsp
|
|
};
|
|
|
|
//
|
|
// write data from global var dsp_data to x memory space "dsp_address"
|
|
//
|
|
|
|
void put_dsp()
|
|
{
|
|
|
|
// LPVOID pvXramBuffer;
|
|
// pvXramBuffer = (LPVOID) (dsp_address);
|
|
|
|
// memcpy(pvXramBuffer,pvData,dwDataSize);
|
|
|
|
// *(PDWORD) (GPXMEM + dsp_address) = dsp_data;
|
|
|
|
}
|
|
|
|
|
|
WriteDSPDatablock
|
|
(
|
|
DWORD dwDSPAddress,
|
|
LPCVOID pvData,
|
|
DWORD dwDataSize
|
|
)
|
|
{
|
|
LPVOID pvXramBuffer;
|
|
|
|
//
|
|
// poke directly the XRAM offset
|
|
//
|
|
|
|
pvXramBuffer = (LPVOID) (GPXMEM + dwDSPAddress);
|
|
memcpy(pvXramBuffer,pvData,dwDataSize);
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
ReadDSPDatablock
|
|
(
|
|
DWORD dwDSPAddress,
|
|
LPVOID pvData,
|
|
DWORD dwDataSize
|
|
)
|
|
{
|
|
LPVOID pvXramBuffer;
|
|
//
|
|
// copy fx data
|
|
//
|
|
pvXramBuffer = (LPVOID) (GPXMEM + dwDSPAddress);
|
|
memcpy(pvData,pvXramBuffer,dwDataSize);
|
|
|
|
return 1;
|
|
}
|
|
|
|
ReadDSPProgblock
|
|
(
|
|
DWORD dwDSPAddress,
|
|
LPVOID pvData,
|
|
DWORD dwDataSize
|
|
)
|
|
{
|
|
LPVOID pvXramBuffer;
|
|
//
|
|
// copy fx data
|
|
//
|
|
pvXramBuffer = (LPVOID) (GPPMEM + dwDSPAddress);
|
|
memcpy(pvData,pvXramBuffer,dwDataSize);
|
|
|
|
return 1;
|
|
}
|
|
|
|
// return dsp data
|
|
int get_dsp(unsigned int addr)
|
|
{
|
|
// return( (*PDWORD) (GPXMEM + dsp_address) );
|
|
return(1);
|
|
}
|
|
|
|
silence_dsp(unsigned char chan)
|
|
{
|
|
|
|
return(1);
|
|
}
|
|
|
|
|
|
note_on_dsp()
|
|
{
|
|
DWORD dwFreq;
|
|
struct DSPpatch *addr;
|
|
|
|
#if DBG
|
|
|
|
// dwFreq = pitch_table_dsp[value_16_bit>>8];
|
|
// swprintf( StringBuffer, L"Current Pitch: 0x%x", dwFreq);
|
|
|
|
#endif
|
|
|
|
dwFreq = (DWORD) ( ((value_16_bit >> 8) - 60) * (4096/12) );
|
|
dwFreq += ((((DWORD) value_16_bit & 0xff) * 341) / 255);
|
|
// IDirectSoundBuffer_StopEx(m_pDSBuffer[current_channel], 0, DSBSTOPEX_ENVELOPE);
|
|
IDirectSoundBuffer_SetPitch(m_pDSBuffer[current_channel], dwFreq);
|
|
|
|
addr = Patches[ti->patch];
|
|
if (addr->LoopEnable)
|
|
IDirectSoundBuffer_Play(m_pDSBuffer[current_channel], 0,0,DSBPLAY_LOOPING);
|
|
else
|
|
IDirectSoundBuffer_Play(m_pDSBuffer[current_channel], 0,0,0);
|
|
|
|
return(1);
|
|
|
|
}
|
|
slur_dsp()
|
|
{
|
|
DWORD dwFreq;
|
|
|
|
dwFreq = (DWORD) ( ((value_16_bit >> 8) - 60) * (4096/12) );
|
|
dwFreq += ((((DWORD) value_16_bit & 0xff) * 341) / 255);
|
|
|
|
#if DBG
|
|
// swprintf( StringBuffer, L"Current Pitch Slur: 0x%x", dwFreq);
|
|
#endif
|
|
|
|
IDirectSoundBuffer_SetPitch(m_pDSBuffer[current_channel], dwFreq);
|
|
|
|
return(1);
|
|
}
|
|
|
|
note_off_dsp()
|
|
{
|
|
IDirectSoundBuffer_StopEx(m_pDSBuffer[current_channel], 0, DSBSTOPEX_ENVELOPE);
|
|
return(1);
|
|
|
|
}
|
|
|
|
vp_filter()
|
|
{
|
|
DSFILTERDESC fdesc;
|
|
|
|
|
|
fdesc.dwMode = DSFILTER_MODE_DLS2;
|
|
fdesc.dwQCoefficient = 0;
|
|
fdesc.adwCoefficients[0] = ti->filtercutoff + 32768;
|
|
fdesc.adwCoefficients[1] = ti->filterres;
|
|
fdesc.adwCoefficients[2] = ti->filtercutoff + 32768;
|
|
fdesc.adwCoefficients[3] = ti->filterres;
|
|
IDirectSoundBuffer_SetFilter(m_pDSBuffer[current_channel], &fdesc);
|
|
return(1);
|
|
}
|
|
|
|
|
|
|
|
patch_dsp(unsigned short pat)
|
|
{
|
|
struct DSPpatch *addr;
|
|
|
|
addr = Patches[pat];
|
|
|
|
IDirectSoundBuffer_SetEG(m_pDSBuffer[current_channel], addr->lpAmpEnvelope);
|
|
IDirectSoundBuffer_SetEG(m_pDSBuffer[current_channel], addr->lpMultiEnvelope);
|
|
IDirectSoundBuffer_SetBufferData(m_pDSBuffer[current_channel], addr->Start, addr->Length );
|
|
IDirectSoundBuffer_SetLoopRegion( m_pDSBuffer[current_channel],0, addr->Length );
|
|
IDirectSoundBuffer_SetCurrentPosition(m_pDSBuffer[current_channel], 0 );
|
|
|
|
return(1);
|
|
}
|
|
|
|
|
|
|
|
pan_dsp(uchar chan, signed char pan, uchar *patch)
|
|
{
|
|
uchar mod;
|
|
unsigned int vol_mul;
|
|
unsigned int tmp;
|
|
char tmp_pan;
|
|
|
|
vol_mul = 0x7fff;
|
|
if (current_level >= 1) {
|
|
/* mod = master_effect_volume;*/
|
|
// vol_mul = volume_table_dsp[master_music_volume];
|
|
}
|
|
else {
|
|
/* mod = 0;*/
|
|
// tmp = volume_table_dsp[music_atten];
|
|
// vol_mul = volume_table_dsp[master_music_volume];
|
|
|
|
// vol_mul = (long)((long)tmp * (long)vol_mul) >>15;
|
|
|
|
}
|
|
|
|
mod = 0;
|
|
|
|
tmp_pan = ti->pan >> 3;
|
|
|
|
tmp_pan += 16; /* set range 0 - 31 */
|
|
tmp = 1;
|
|
// tmp = volume_table_dsp[MIN(127,ti->volume + mod)];
|
|
tmp = (long)((long)tmp * (long)vol_mul) >>15;
|
|
|
|
/* tmp >>= 7;*/
|
|
dsp_data = (long) ((long)tmp * (long)pan_table[tmp_pan]) >> 7;
|
|
/* dsp_data = (char)tmp * pan_table[tmp_pan];*/
|
|
// a_value = VOLUME_L_ADDRESS(chan);
|
|
put_dsp();
|
|
|
|
dsp_data = (long) ((long)tmp * (long)pan_table[31 - tmp_pan]) >> 7;
|
|
/* dsp_data = (char)tmp * pan_table[31 - tmp_pan];*/
|
|
// a_value = VOLUME_R_ADDRESS(chan);
|
|
put_dsp();
|
|
|
|
return(1);
|
|
|
|
}
|
|
|
|
|
|
// initialize stuff for the dsp.
|
|
// write sine wave into high x memory.
|
|
// also create 16 dsound buffers that we'll use
|
|
// for our sounds.
|
|
|
|
|
|
static long holdrand = 1L;
|
|
|
|
void __cdecl srand(unsigned int seed)
|
|
{
|
|
holdrand = (long)seed;
|
|
}
|
|
|
|
int __cdecl rand(void)
|
|
{
|
|
return(((holdrand = holdrand * 214013L + 2531011L) >> 16) & 0x7fff);
|
|
}
|
|
|
|
dev_init()
|
|
{
|
|
|
|
DSBUFFERDESC dsbdesc;
|
|
WAVEFORMATEX wfFirst;
|
|
DWORD dwMixBinMask = DSMIXBIN_FRONT_LEFT | DSMIXBIN_FRONT_RIGHT | DSMIXBIN_FXSEND_0;
|
|
long lVolumes[3];
|
|
int j;
|
|
double dtmp;
|
|
double FMc = 4.0;
|
|
double FMm = 2.0;
|
|
|
|
|
|
int i;
|
|
|
|
srand(1003);
|
|
for (i = 0; i < 8192; i++) {
|
|
Noise8192[i] = (unsigned short) rand();
|
|
}
|
|
|
|
for (i = 0; i < 128; i++) {
|
|
Sin128[i] = (unsigned short)(32767*sin(2.0*3.14159*(double)i/128.0));
|
|
}
|
|
j = 0;
|
|
for (i = 0; i < 32768; i++) {
|
|
if (i < 16384)
|
|
j++;
|
|
else
|
|
j--;
|
|
dtmp = (double)j/16384.0 * sin(FMm * 2.0*3.14159*(double)i/128.0);
|
|
FM32768[i] = (unsigned short)(32767*sin(dtmp + FMc * 2.0*3.14159*(double)i/128.0));
|
|
}
|
|
|
|
for (i = 0; i < 128; i++) { // create sawtooth wave
|
|
Saw128[i] = (unsigned short) (65536 * ((float)(i-64) /128.0));
|
|
}
|
|
|
|
for (i = 0; i < 0x5540; i++) { // size of glock sound..make 16-bit
|
|
ThunEl16[i] = (ThunEl16Data[i]) << 8;
|
|
}
|
|
for (i = 0,j=0x5540; i < 0x5540; i++,j--) { // size of glock sound..make 16-bit
|
|
ReverseThunEl16[i] = ThunEl16[j];
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < 3768; i++) { // size of glock sound..make 16-bit
|
|
Glock[i] = (GlockData[i]^0x80) << 8;
|
|
}
|
|
|
|
for (i = 0; i < 6719; i++) { // size of glock sound..make 16-bit
|
|
Bubble[i] = (BubbleData[i]^0x80) << 8;
|
|
}
|
|
|
|
|
|
if( FAILED( DirectSoundCreate( NULL, &m_pDSound, NULL ) ) )
|
|
return (0);
|
|
|
|
|
|
ZeroMemory( &dsbdesc, sizeof( DSBUFFERDESC ) );
|
|
dsbdesc.dwSize = sizeof( DSBUFFERDESC );
|
|
|
|
wfFirst.wFormatTag = WAVE_FORMAT_PCM;
|
|
wfFirst.nChannels = 1;
|
|
wfFirst.nSamplesPerSec = 48000;
|
|
wfFirst.wBitsPerSample = 16;
|
|
wfFirst.nBlockAlign = wfFirst.nChannels * wfFirst.wBitsPerSample/8;
|
|
wfFirst.nAvgBytesPerSec = wfFirst.nSamplesPerSec * wfFirst.nBlockAlign;
|
|
|
|
dsbdesc.dwFlags = 0;
|
|
dsbdesc.dwBufferBytes = 0;
|
|
dsbdesc.lpwfxFormat = &wfFirst;
|
|
dsbdesc.dwMixBinMask = dwMixBinMask;
|
|
|
|
|
|
for (i = 0; i < MAX_BUFFERS; i++) {
|
|
|
|
|
|
if (i%2) {
|
|
lVolumes[0] = -600;
|
|
lVolumes[1] = 0;
|
|
lVolumes[2] = -2800;
|
|
dwMixBinMask = DSMIXBIN_FRONT_LEFT | DSMIXBIN_FRONT_RIGHT;
|
|
dsbdesc.dwMixBinMask = dwMixBinMask;
|
|
}
|
|
else {
|
|
lVolumes[0] = 0;
|
|
lVolumes[1] = -600;
|
|
lVolumes[2] = -2800;
|
|
dwMixBinMask = DSMIXBIN_FRONT_LEFT | DSMIXBIN_FRONT_RIGHT;
|
|
dsbdesc.dwMixBinMask = dwMixBinMask;
|
|
}
|
|
if ((i == 3) || (i == 5)) {
|
|
lVolumes[0] = 0;
|
|
lVolumes[1] = -100;
|
|
lVolumes[2] = 00;
|
|
dwMixBinMask = DSMIXBIN_FRONT_LEFT | DSMIXBIN_FRONT_RIGHT | DSMIXBIN_FXSEND_0;
|
|
dsbdesc.dwMixBinMask = dwMixBinMask;
|
|
}
|
|
|
|
if( FAILED( DirectSoundCreateBuffer( &dsbdesc, &m_pDSBuffer[i]) ) )
|
|
return E_FAIL;
|
|
|
|
IDirectSoundBuffer_SetMixBinVolumes(m_pDSBuffer[i], dwMixBinMask, lVolumes);
|
|
}
|
|
|
|
// ReadDSPDatablock(0xa00*4, databack, sizeof(databack) );
|
|
|
|
put_fifo(0x1);
|
|
return(1);
|
|
}
|
|
//
|
|
// free dsound buffers and dsound object we created
|
|
//
|
|
dev_cleanup()
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < MAX_BUFFERS; i++) {
|
|
IDirectSoundBuffer_Release(m_pDSBuffer[i]);
|
|
}
|
|
IDirectSound_Release(m_pDSound);
|
|
|
|
}
|
|
|
|
|
|
do_watchdog()
|
|
{
|
|
}
|
|
dtimer_int()
|
|
{
|
|
}
|
|
etimer_int()
|
|
{
|
|
}
|
|
send_dev_function()
|
|
{
|
|
}
|
|
/*************************************************************************
|
|
* *
|
|
* Adjust the volume of that patch, "patch_addr" on channel, *
|
|
* "chan" by the amount volume + whatever the global volume is *
|
|
* for "level" *
|
|
* *
|
|
*************************************************************************/
|
|
|
|
volume_dsp(
|
|
uchar op_level,
|
|
uchar sound_level,
|
|
uchar *patch_addr,
|
|
uchar chan)
|
|
{
|
|
|
|
IDirectSoundBuffer_SetVolume(m_pDSBuffer[current_channel], (-1*op_level*30) + 200);
|
|
return(1);
|
|
}
|
|
|
|
call_user_function()
|
|
{
|
|
|
|
}
|
|
|
|
extern f_end();
|
|
|
|
|
|
user_silence_function()
|
|
{
|
|
#if DBG
|
|
// swprintf( StringBuffer, L"Current Sound: %S", "SilenceFunction");
|
|
#endif
|
|
}
|
|
|
|
uchar pan_table[] = {
|
|
1,2,3,4,5,6,7,8
|
|
};
|
|
|
|
|