newoswan/oswan/source/audio.cpp
Godzil b1abbf6bfe Reindented most of the files (still work to be done there)
Now support the BW and Color IROM
Internal EEPROM support is now nearly correct (still some odd thing
happening)
2019-09-03 17:33:29 +01:00

1550 lines
37 KiB
C++

////////////////////////////////////////////////////////////////////////////////
// Audio
////////////////////////////////////////////////////////////////////////////////
//
// Sound information thanks to toshi (wscamp wonderswan emulator)
// Note that sound is far from perfect for now.
//
// fixes by zalas 2002-08-21
//
//
//
////////////////////////////////////////////////////////////////////////////////
// alternate the commenting of the following defines to get audio port tracing
#define dbgprintf(...)
//#define dbgprintf(...) printf(...)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <time.h>
#include <unistd.h>
#include "log.h"
#include "rom.h"
#include "./nec/nec.h"
#include "memory.h"
#include "io.h"
#include "audio.h"
// seal's retarded definitions conflict with types.h
#undef DWORD
#include <audio.h>
#define SNDP ws_ioRam[0x80]
#define SNDV ws_ioRam[0x88]
#define SNDSWP ws_ioRam[0x8C]
#define SWPSTP ws_ioRam[0x8D]
#define NSCTL ws_ioRam[0x8E]
#define WAVDTP ws_ioRam[0x8F]
#define SNDMOD ws_ioRam[0x90]
#define SNDOUT ws_ioRam[0x91]
#define PCSRL ws_ioRam[0x92]
#define PCSRH ws_ioRam[0x93]
#define DMASL ws_ioRam[0x40]
#define DMASH ws_ioRam[0x41]
#define DMASB ws_ioRam[0x42]
#define DMADB ws_ioRam[0x43]
#define DMADL ws_ioRam[0x44]
#define DMADH ws_ioRam[0x45]
#define DMACL ws_ioRam[0x46]
#define DMACH ws_ioRam[0x47]
#define DMACTL ws_ioRam[0x48]
#define SDMASL ws_ioRam[0x4A]
#define SDMASH ws_ioRam[0x4B]
#define SDMASB ws_ioRam[0x4C]
#define SDMACL ws_ioRam[0x4E]
#define SDMACH ws_ioRam[0x4F]
#define SDMACTL ws_ioRam[0x52]
#define BPS 44100
#define BPSMAX AUDIO_MAX_FREQUENCY
#define BPSMIN AUDIO_MIN_FREQUENCY
#define BUFSIZE 1024
#define BUFSIZEN 0x10000
#define BUFSIZEP 159
#define PCMNUM 100
#define POFF 128
#define PDIV 3
#define PH POFF+PDIV*8
#define PL POFF-PDIV*7
int WaveMap;
int ChPerInit;
int SwpTime;
int SwpStep;
unsigned int SwpCurPeriod;
int MainVol=15;
int HardVol=3;
int ChCurVol[6]= {-1,-1,-1,-1,-1,-1};
int ChCurPer[6]= {-1,-1,-1,-1,-1,-1};
long ChCurPan[6]= {-1,-1,-1,-1,-1,-1};
unsigned char PData[4][BUFSIZE];
unsigned char PDataP[BUFSIZEP<<4];
unsigned char PDataN[8][BUFSIZEN];
int RandData[BUFSIZEN];
int CntSwp=0;
int PcmWrPos=0;
const long TblChVol[16]= // n/15 n=0~15
{
-10000,-2352,-1750,-1398,-1148,-954,-796,-662,
-546,-444,-352,-269,-194,-124,-60,0
};
const long TblMainVol[4]= // 1,1/2,1/4,1/8
{
0,-602,-1204,-1806
};
////////////////////////////////////////////////////////////////////////////////
// seal audio specific
////////////////////////////////////////////////////////////////////////////////
//
//
//
//
//
//
//
////////////////////////////////////////////////////////////////////////////////
HAC ws_audio_pcm_voice[4];
HAC ws_audio_noise_voice;
HAC ws_audio_sweep_voice;
AUDIOWAVE ws_audio_pcm_wave[4];
AUDIOWAVE ws_audio_noise_wave;
AUDIOWAVE ws_audio_sweep_wave;
UINT32 ws_audio_channel_isPlaying[6];
static unsigned int ws_audio_log;
////////////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////////////
//
//
//
//
//
//
//
////////////////////////////////////////////////////////////////////////////////
void ws_audio_init(void)
{
fprintf(log_get(), "audio init\n");
fflush(log_get());
ws_audio_log=0;
ws_audio_seal_init();
ws_audio_reset();
SDL_PauseAudio(0);
}
////////////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////////////
//
//
//
//
//
//
//
////////////////////////////////////////////////////////////////////////////////
void ws_audio_reset(void)
{
WaveMap=-1;
for (int i=0; i<6; i++)
{
ws_audio_stop_channel(i);
ws_audio_play_channel(i);
ws_audio_set_channel_frequency(i,0);
if (i!=4)
{
ws_audio_set_channel_pan(i,0,0);
}
ws_audio_clear_channel(i);
}
ws_audio_set_channel_frequency(4,0);
ws_audio_set_channel_frequency(4,1792);
}
////////////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////////////
//
//
//
//
//
//
//
////////////////////////////////////////////////////////////////////////////////
void ws_audio_port_write(Uint32 port, Uint8 value)
{
Uint32 n,i,j,k,b;
//printf("0x%2x <- 0x%2x\n", port, (Uint32)value);
ws_ioRam[port]=value;
switch (port)
{
case 0x48:
if (value&0x80)
{
n=(DMACH<<8)|DMACL;
i=(DMASB<<16)|(DMASH<<8)|DMASL;
j=(DMADH<<8)|DMADL;
for(k=0; k<n; k++)
{
b=cpu_readmem20(i);
cpu_writemem20(j,b);
i++;
j++;
}
n=0;
DMASB=(Uint8)((i>>16)&0xFF);
DMASH=(Uint8)((i>>8)&0xFF);
DMASL=(Uint8)(i&0xFF);
DMADB=(Uint8)((j>>16)&0xFF);
DMADH=(Uint8)((j>>8)&0xFF);
DMADL=(Uint8)(j&0xFF);
DMACH=(Uint8)((n>>8)&0xFF);
DMACL=(Uint8)(n&0xFF);
value&=0x7F;
}
break;
case 0x80:
case 0x81:
i=(((unsigned int)ws_ioRam[0x81])<<8)+((unsigned int)ws_ioRam[0x80]);
ws_audio_set_channel_frequency(0,i);
dbgprintf("0x%2x ... freq = 0x%x\n", port, i);
break;
case 0x82:
case 0x83:
i=(((unsigned int)ws_ioRam[0x83])<<8)+((unsigned int)ws_ioRam[0x82]);
ws_audio_set_channel_frequency(1,i);
break;
case 0x84:
case 0x85:
i=(((unsigned int)ws_ioRam[0x85])<<8)+((unsigned int)ws_ioRam[0x84]);
ws_audio_set_channel_frequency(2,i);
break;
case 0x86:
case 0x87:
i=(((unsigned int)(ws_ioRam[0x87]&0x07))<<8)+((unsigned int)ws_ioRam[0x86]);
ws_audio_set_channel_frequency(5,i);
ws_audio_set_channel_frequency(3,i);
break;
case 0x88:
dbgprintf("0x88 <- 0x%2x\n", value);
// fflush(stdout);
ws_audio_set_channel_pan(0,(value&0xF0)>>4,value&0x0F);
break;
case 0x89:
dbgprintf("0x89 <- 0x%2x\n", value);
// fflush(stdout);
ws_audio_set_channel_pan(1,(value&0xF0)>>4,value&0x0F);
break;
case 0x8A:
ws_audio_set_channel_pan(2,(value&0xF0)>>4,value&0x0F);
break;
case 0x8B:
ws_audio_set_channel_pan(5,(value&0xF0)>>4,value&0x0F);
ws_audio_set_channel_pan(3,(value&0xF0)>>4,value&0x0F);
break;
case 0x8C:
SwpStep=(signed char)value;
break;
case 0x8D:
//SwpTime=(((unsigned int)value)+1)<<5;
SwpTime=(((unsigned int)value)+1)<<5;
break;
case 0x8E:
dbgprintf("0x8E <- 0x%2x = %d %d %d %d %d %d %d %d \n", value, value & 0x80 ? 1 : 0, value & 0x40 ? 1 : 0, value & 0x20 ? 1 : 0, value & 0x10 ? 1 : 0, value & 8 ? 1 : 0, value & 4 ? 1 : 0, value & 2 ? 1 : 0, value & 1);
//fflush(stdout); /* ctl */
if (value & 0x10)
{
ws_audio_set_channel_pdata(5,value&0x07);
}
else
{
// hmmm.. shut up!
}
break;
case 0x8F:
WaveMap=((unsigned int)value)<<6;
break;
case 0x90:
dbgprintf("0x90 <- 0x%2x = %d %d %d %d %d %d %d %d \n", value, value & 0x80 ? 1 : 0, value & 0x40 ? 1 : 0, value & 0x20 ? 1 : 0, value & 0x10 ? 1 : 0, value & 8 ? 1 : 0, value & 4 ? 1 : 0, value & 2 ? 1 : 0, value & 1);
//fflush(stdout); /* ctl */
if (value&0x01)
{
ws_audio_play_channel(0);
// for(int ii=0;ii<32;ii++)
// fprintf(log_get(),"%02X ",PData[0][ii]);
// fprintf(log_get(),"\n");
}
else
{
ws_audio_stop_channel(0);
}
if ((value&0x22)==0x02)
{
ws_audio_play_channel(1);
}
else
{
ws_audio_stop_channel(1);
}
if (value&0x04)
{
ws_audio_play_channel(2);
}
else
{
ws_audio_stop_channel(2);
}
if ((value&0x88)==0x08)
{
ws_audio_play_channel(3);
}
else
{
ws_audio_stop_channel(3);
}
if ((value&0x88)==0x88)
{
ws_audio_play_channel(5);
}
else
{
ws_audio_stop_channel(5);
}
break;
case 0x91:
/* printf("Channels [ %c %c %c %c %c %c %c %c ]\n",
(value>>0)&1?'S':'M',
(value>>1)&1?'H':'l',
(value>>2)&1?'H':'l',
(value>>3)&1?'E':' ',
(value>>4)&1?'4':' ',
(value>>5)&1?'5':' ',
(value>>6)&1?'6':' ',
(value>>7)&1?'E':' ');
//0x91 <- %x\n", value);
fflush(stdout);*/
//MainVol=0;
value|=0x80;
HardVol = (value>>1)&0x3;
ws_ioRam[port]=value; // Always have external speaker
value=ws_ioRam[0x88];
ws_audio_set_channel_pan(0,(value&0xF0)>>4,value&0x0F);
value=ws_ioRam[0x89];
ws_audio_set_channel_pan(1,(value&0xF0)>>4,value&0x0F);
value=ws_ioRam[0x8A];
ws_audio_set_channel_pan(2,(value&0xF0)>>4,value&0x0F);
value=ws_ioRam[0x8B];
ws_audio_set_channel_pan(3,(value&0xF0)>>4,value&0x0F);
ws_audio_set_channel_pan(5,(value&0xF0)>>4,value&0x0F);
break;
case 0x92:
dbgprintf("0x92 <- 0x%2x\n", value);
fflush(stdout);
break;
case 0x93:
dbgprintf("0x93 <- 0x%2x\n", value);
fflush(stdout);
break;
case 0x94:
dbgprintf("0x94 <- 0x%2x\n", value);
fflush(stdout);
MainVol=(value&0x0f)>>2;
value=ws_ioRam[0x88];
ws_audio_set_channel_pan(0,(value&0xF0)>>4,value&0x0F);
value=ws_ioRam[0x89];
ws_audio_set_channel_pan(1,(value&0xF0)>>4,value&0x0F);
value=ws_ioRam[0x8A];
ws_audio_set_channel_pan(2,(value&0xF0)>>4,value&0x0F);
value=ws_ioRam[0x8B];
ws_audio_set_channel_pan(3,(value&0xF0)>>4,value&0x0F);
ws_audio_set_channel_pan(5,(value&0xF0)>>4,value&0x0F);
break;
}
}
////////////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////////////
//
//
//
//
//
//
//
////////////////////////////////////////////////////////////////////////////////
BYTE ws_audio_port_read(BYTE port)
{
return(ws_ioRam[port]);
}
////////////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////////////
//
//
//
//
//
//
//
////////////////////////////////////////////////////////////////////////////////
void ws_audio_done(void)
{
ws_audio_seal_done();
}
////////////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////////////
//
//
//
//
//
//
//
////////////////////////////////////////////////////////////////////////////////
unsigned int ws_audio_mrand(unsigned int Degree)
{
#define BIT(n) (1<<n)
typedef struct
{
unsigned int N;
int InputBit;
int Mask;
} POLYNOMIAL;
static POLYNOMIAL TblMask[]=
{
{ 2,BIT(2),BIT(0)|BIT(1)},
{ 3,BIT(3),BIT(0)|BIT(1)},
{ 4,BIT(4),BIT(0)|BIT(1)},
{ 5,BIT(5),BIT(0)|BIT(2)},
{ 6,BIT(6),BIT(0)|BIT(1)},
{ 7,BIT(7),BIT(0)|BIT(1)},
{ 8,BIT(8),BIT(0)|BIT(2)|BIT(3)|BIT(4)},
{ 9,BIT(9),BIT(0)|BIT(4)},
{10,BIT(10),BIT(0)|BIT(3)},
{11,BIT(11),BIT(0)|BIT(2)},
{12,BIT(12),BIT(0)|BIT(1)|BIT(4)|BIT(6)},
{13,BIT(13),BIT(0)|BIT(1)|BIT(3)|BIT(4)},
{14,BIT(14),BIT(0)|BIT(1)|BIT(4)|BIT(5)},
{15,BIT(15),BIT(0)|BIT(1)},
{0,0,0},
};
static POLYNOMIAL *pTbl=TblMask;
static int ShiftReg=pTbl->InputBit-1;
int XorReg=0;
int Masked;
if(pTbl->N!=Degree)
{
pTbl=TblMask;
while(pTbl->N)
{
if(pTbl->N==Degree)
{
break;
}
pTbl++;
}
if(!pTbl->N)
{
pTbl--;
}
ShiftReg&=pTbl->InputBit-1;
if(!ShiftReg)
{
ShiftReg=pTbl->InputBit-1;
}
}
Masked=ShiftReg&pTbl->Mask;
while(Masked)
{
XorReg^=Masked&0x01;
Masked>>=1;
}
if(XorReg)
{
ShiftReg|=pTbl->InputBit;
}
else
{
ShiftReg&=~pTbl->InputBit;
}
ShiftReg>>=1;
return ShiftReg;
}
////////////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////////////
//
//
//
//
//
//
//
////////////////////////////////////////////////////////////////////////////////
int ws_audio_seal_init(void)
{
int i, j;
AUDIOINFO info;
AUDIOCAPS caps;
UINT rc;
UINT nDevId;
fprintf(log_get(),"audio: using seal audio library\n");
/* initialize audio library */
AInitialize();
/* show registered device drivers */
fprintf(log_get(),"audio: registered sound devices:\n");
for (nDevId = 0; nDevId < AGetAudioNumDevs(); nDevId++)
{
AGetAudioDevCaps(nDevId, &caps);
fprintf(log_get(),"audio: %2d. %s\n", nDevId, caps.szProductName);
}
/* open audio device */
//info.nDeviceId = AUDIO_DEVICE_MAPPER;
info.nDeviceId = 0;
info.wFormat = AUDIO_FORMAT_16BITS | AUDIO_FORMAT_STEREO; // | AUDIO_MIXER_BASS;
info.nSampleRate = 44100;
if ((rc = AOpenAudio(&info)) != AUDIO_ERROR_NONE)
{
CHAR szText[80];
AGetErrorText(rc, szText, sizeof(szText) - 1);
fprintf(log_get(),"audio: error: %s\n", szText);
fflush(log_get());
return(0);
}
// open 6 voices ( 4 pcm, one noise, and one sweep)
AOpenVoices(6);
// create the 4 pcm channels
for (i=0; i<4; i++)
{
// create the channel
ACreateAudioVoice(&ws_audio_pcm_voice[i]);
ASetVoiceVolume ( ws_audio_pcm_voice[i], AUDIO_MAX_VOLUME);
ASetVoicePanning ( ws_audio_pcm_voice[i], AUDIO_MIN_PANNING);
// create a looped sound buffer
ws_audio_pcm_wave[i].nSampleRate = info.nSampleRate;
ws_audio_pcm_wave[i].dwLength = BUFSIZE;
ws_audio_pcm_wave[i].dwLoopStart = 0;
ws_audio_pcm_wave[i].dwLoopEnd = ws_audio_pcm_wave[i].dwLength;
ws_audio_pcm_wave[i].wFormat = AUDIO_FORMAT_8BITS | AUDIO_FORMAT_MONO | AUDIO_FORMAT_LOOP;
ACreateAudioData(&ws_audio_pcm_wave[i]);
// channel is not playing yet
ws_audio_channel_isPlaying[i]=0;
// clear the channel
ws_audio_clear_channel(i);
}
// create the noise channel
{
// create the channel
ACreateAudioVoice(&ws_audio_noise_voice);
ASetVoiceVolume ( ws_audio_noise_voice, AUDIO_MAX_VOLUME);
ASetVoicePanning ( ws_audio_noise_voice, AUDIO_MAX_PANNING>>1);
// create a looped sound buffer
ws_audio_noise_wave.nSampleRate = info.nSampleRate;
ws_audio_noise_wave.dwLength = (BUFSIZEP<<4);
ws_audio_noise_wave.dwLoopStart = 0;
ws_audio_noise_wave.dwLoopEnd = ws_audio_noise_wave.dwLength;
ws_audio_noise_wave.wFormat = AUDIO_FORMAT_8BITS | AUDIO_FORMAT_MONO | AUDIO_FORMAT_LOOP;
ACreateAudioData(&ws_audio_noise_wave);
// channel is not playing yet
ws_audio_channel_isPlaying[4]=0;
// clear the channel
ws_audio_clear_channel(4);
}
// create the sweep channel
{
// create the channel
ACreateAudioVoice(&ws_audio_sweep_voice);
ASetVoiceVolume ( ws_audio_sweep_voice, AUDIO_MAX_VOLUME);
ASetVoicePanning ( ws_audio_sweep_voice, AUDIO_MAX_PANNING);
// create a looped sound buffer
ws_audio_sweep_wave.nSampleRate = info.nSampleRate;
ws_audio_sweep_wave.dwLength = BUFSIZEN;
ws_audio_sweep_wave.dwLoopStart = 0;
ws_audio_sweep_wave.dwLoopEnd = ws_audio_sweep_wave.dwLength;
ws_audio_sweep_wave.wFormat = AUDIO_FORMAT_8BITS | AUDIO_FORMAT_MONO | AUDIO_FORMAT_LOOP;
ACreateAudioData(&ws_audio_sweep_wave);
// channel is not playing yet
ws_audio_channel_isPlaying[5]=0;
// clear the channel
ws_audio_clear_channel(5);
}
// initialize the noise channel data
int rand;
for(i=0; i<8; i++)
{
for(j=0; j<BUFSIZEN; j++)
{
rand=ws_audio_mrand(15-i)&1;
if(rand)
{
PDataN[i][j]=PH;
}
else
{
PDataN[i][j]=PL;
}
}
}
for(j=0; j<BUFSIZEN; j++)
{
RandData[j]=ws_audio_mrand(15);
}
ASetAudioMixerValue(AUDIO_MIXER_MASTER_VOLUME, AUDIO_MAX_VOLUME);
fflush(log_get());
return(1);
}
////////////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////////////
//
//
//
//
//
//
//
////////////////////////////////////////////////////////////////////////////////
void ws_audio_seal_done(void)
{
int i;
// stop channels
for (i=0; i<6; i++)
{
ws_audio_stop_channel(i);
}
// destroy pcm wave data
for (i=0; i<4; i++)
{
ADestroyAudioData(&ws_audio_pcm_wave[i]);
}
// destroy noise wave data
ADestroyAudioData(&ws_audio_noise_wave);
// destroy sweep wave data
ADestroyAudioData(&ws_audio_sweep_wave);
// release pcm channels
for (i=0; i<4; i++)
{
ADestroyAudioVoice(ws_audio_pcm_voice[i]);
}
// release noise channel
ADestroyAudioVoice(ws_audio_noise_voice);
// release sweep channel
ADestroyAudioVoice(ws_audio_sweep_voice);
// close A channels
ACloseVoices();
// close audio
ACloseAudio();
}
////////////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////////////
//
//
//
//
//
//
//
////////////////////////////////////////////////////////////////////////////////
void ws_audio_clear_channel(int Channel)
{
ChCurVol[Channel]=-1;
ChCurPer[Channel]=-1;
ChCurPan[Channel]=-1;
if(Channel==5)
{
memset(ws_audio_sweep_wave.lpData, 0, ws_audio_sweep_wave.dwLength);
AWriteAudioData(&ws_audio_sweep_wave, 0, ws_audio_sweep_wave.dwLength);
}
else if(Channel==4)
{
memset(ws_audio_noise_wave.lpData, 0, ws_audio_noise_wave.dwLength);
AWriteAudioData(&ws_audio_noise_wave, 0, ws_audio_noise_wave.dwLength);
}
else
{
memset(ws_audio_pcm_wave[Channel].lpData, 0, ws_audio_pcm_wave[Channel].dwLength);
AWriteAudioData(&ws_audio_pcm_wave[Channel], 0, ws_audio_pcm_wave[Channel].dwLength);
}
}
////////////////////////////////////////////////////////////////////////////////
// start playing a channel
////////////////////////////////////////////////////////////////////////////////
//
//
//
//
//
//
//
////////////////////////////////////////////////////////////////////////////////
int ws_audio_play_channel(int Channel)
{
if (ws_audio_channel_isPlaying[Channel])
{
return(0);
}
ws_audio_channel_isPlaying[Channel]=1;
if (Channel==5)
{
APlayVoice(ws_audio_sweep_voice, &ws_audio_sweep_wave);
}
else if (Channel==4)
{
APlayVoice(ws_audio_noise_voice, &ws_audio_noise_wave);
}
else
{
// ASetVoiceFrequency(ws_audio_pcm_voice[Channel],3072000/(2048-ChCurPer[Channel]));
APlayVoice(ws_audio_pcm_voice[Channel], &ws_audio_pcm_wave[Channel]);
ASetVoiceFrequency(ws_audio_pcm_voice[Channel],3072000/(2048-ChCurPer[Channel]));
}
return 0;
}
////////////////////////////////////////////////////////////////////////////////
// stop playing a channel
////////////////////////////////////////////////////////////////////////////////
//
//
//
//
//
//
//
////////////////////////////////////////////////////////////////////////////////
int ws_audio_stop_channel(int Channel)
{
if (!ws_audio_channel_isPlaying[Channel])
{
return(0);
}
ws_audio_channel_isPlaying[Channel]=0;
if (Channel==5)
{
AStopVoice(ws_audio_sweep_voice);
}
else if (Channel==4)
{
AStopVoice(ws_audio_noise_voice);
}
else
{
AStopVoice(ws_audio_pcm_voice[Channel]);
}
return(0);
}
////////////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////////////
//
//
//
//
//
//
//
////////////////////////////////////////////////////////////////////////////////
void ws_audio_set_channel_frequency(int Channel,int Period)
{
DWORD Freq;
if(ChCurPer[Channel]==Period)
{
return;
}
ChCurPer[Channel]=Period;
Freq=3072000/(2048-Period);
if(Channel==2)
{
ChPerInit=Period;
SwpCurPeriod=Period;
}
if(Freq>BPSMAX)
{
Freq=BPSMAX;
}
else if(Freq<BPSMIN)
{
Freq=BPSMIN;
}
if (Channel==5)
{
ASetVoiceFrequency(ws_audio_sweep_voice,Freq);
}
else if (Channel==4)
{
ASetVoiceFrequency(ws_audio_noise_voice,Freq);
}
else
{
ASetVoiceFrequency(ws_audio_pcm_voice[Channel],Freq);
}
// fprintf(log_get(),"Frequency of Channel[%d] is %lu\n",Channel,Freq/32);
}
////////////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////////////
//
//
//
//
//
//
//
////////////////////////////////////////////////////////////////////////////////
void ws_audio_set_channel_volume(int Channel,int Vol)
{
long volume;
if(ChCurVol[Channel]==Vol)
{
return;
}
ChCurVol[Channel]=Vol;
//volume=TblChVol[ChCurVol[Channel]]+TblMainVol[MainVol];
/* if (volume>10000) volume=10000;
volume=((volume+10000)*0x3f)/20000;
if(volume<-10000)
volume=-10000;*/
volume=(Vol+1)*(MainVol+1)*(HardVol+1)/16-1;
if (Channel==5)
{
ASetVoiceVolume(ws_audio_sweep_voice,volume);
}
else if (Channel==4)
{
ASetVoiceVolume(ws_audio_noise_voice,volume);
}
else
{
ASetVoiceVolume(ws_audio_pcm_voice[Channel],volume);
// fprintf(log_get(),"set Channel[%d] volume to %02X (%02X*%02X)\n",Channel,volume,Vol,MainVol);
}
}
////////////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////////////
//
//
//
//
//
//
//
////////////////////////////////////////////////////////////////////////////////
void ws_audio_set_channel_pan(int Channel,int Left,int Right)
{
long pan;
const long TblPan[16][16]=
{
{ 0, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000},
{-10000, 0, 602, 954, 1204, 1398, 1556, 1690, 1806, 1908, 2000, 2082, 2158, 2228, 2292, 2352},
{-10000, -602, 0, 352, 602, 796, 954, 1088, 1204, 1306, 1398, 1481, 1556, 1626, 1690, 1750},
{-10000, -954, -352, 0, 250, 444, 602, 736, 852, 954, 1046, 1129, 1204, 1274, 1338, 1398},
{-10000, -1204, -602, -250, 0, 194, 352, 486, 602, 704, 796, 879, 954, 1024, 1088, 1148},
{-10000, -1398, -796, -444, -194, 0, 158, 292, 408, 511, 602, 685, 760, 830, 894, 954},
{-10000, -1556, -954, -602, -352, -158, 0, 134, 250, 352, 444, 526, 602, 672, 736, 796},
{-10000, -1690, -1088, -736, -486, -292, -134, 0, 116, 218, 310, 393, 468, 538, 602, 662},
{-10000, -1806, -1204, -852, -602, -408, -250, -116, 0, 102, 194, 277, 352, 422, 486, 546},
{-10000, -1908, -1306, -954, -704, -511, -352, -218, -102, 0, 92, 174, 250, 319, 384, 444},
{-10000, -2000, -1398, -1046, -796, -602, -444, -310, -194, -92, 0, 83, 158, 228, 292, 352},
{-10000, -2082, -1481, -1129, -879, -685, -526, -393, -277, -174, -83, 0, 76, 145, 209, 269},
{-10000, -2158, -1556, -1204, -954, -760, -602, -468, -352, -250, -158, -76, 0, 70, 134, 194},
{-10000, -2228, -1626, -1274, -1024, -830, -672, -538, -422, -319, -228, -145, -70, 0, 64, 124},
{-10000, -2292, -1690, -1338, -1088, -894, -736, -602, -486, -384, -292, -209, -134, -64, 0, 60},
{-10000, -2352, -1750, -1398, -1148, -954, -796, -662, -546, -444, -352, -269, -194, -124, -60, 0},
};
if(Left>Right)
{
ws_audio_set_channel_volume(Channel,Left);
}
else
{
ws_audio_set_channel_volume(Channel,Right);
}
pan=TblPan[Left][Right];
if(ChCurPan[Channel]==pan)
{
return;
}
ChCurPan[Channel]=pan;
if (pan>10000)
{
pan=10000;
}
pan=((pan+10000)*AUDIO_MAX_PANNING)/20000;
if (Channel==5)
{
ASetVoicePanning(ws_audio_sweep_voice,pan);
}
else if (Channel==4)
{
ASetVoicePanning(ws_audio_noise_voice,pan);
}
else
{
ASetVoicePanning(ws_audio_pcm_voice[Channel],pan);
}
}
////////////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////////////
//
//
//
//
//
//
//
////////////////////////////////////////////////////////////////////////////////
void ws_audio_set_channel_pdata(int Channel,int Index)
{
unsigned char *pData;
if(Channel==5)
{
pData=PDataN[Index];
memcpy(ws_audio_sweep_wave.lpData, pData, ws_audio_sweep_wave.dwLength);
AWriteAudioData(&ws_audio_sweep_wave, 0, ws_audio_sweep_wave.dwLength);
}
else if(Channel==4)
{
pData=PDataP;
memcpy(ws_audio_noise_wave.lpData, pData, ws_audio_noise_wave.dwLength);
AWriteAudioData(&ws_audio_noise_wave, 0, ws_audio_noise_wave.dwLength);
}
else
{
pData=PData[Channel];
memcpy(ws_audio_pcm_wave[Channel].lpData, pData, ws_audio_pcm_wave[Channel].dwLength);
AWriteAudioData(&ws_audio_pcm_wave[Channel], 0, ws_audio_pcm_wave[Channel].dwLength);
}
}
////////////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////////////
//
//
//
//
//
//
//
////////////////////////////////////////////////////////////////////////////////
void ws_audio_set_channels_pbuf(int Addr,int Data)
{
int i,j;
i=(Addr&0x30)>>4;
for(j=(Addr&0x0F)<<1; j<BUFSIZE; j+=32)
{
// PData[i][j] = (unsigned char)(POFF+PDIV*((Data&0x0F)-7));
// PData[i][j+1] = (unsigned char)(POFF+PDIV*(((Data&0xF0)>>4)-7));
PData[i][j] = (Data&0x0f)*17-128;
PData[i][j+1] = ((Data>>4)&0x0f)*17-128;
}
if((Addr&0x0F)==0x0F)
{
ws_audio_set_channel_pdata(i,0);
}
}
////////////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////////////
//
//
//
//
//
//
//
////////////////////////////////////////////////////////////////////////////////
void ws_audio_rst_channel(int Channel)
{
if(Channel==2)
{
ws_audio_set_channel_frequency(2,ChPerInit);
SwpCurPeriod=ChPerInit;
}
}
////////////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////////////
//
//
//
//
//
//
//
////////////////////////////////////////////////////////////////////////////////
int ws_audio_int(void)
{
unsigned int value;
static int i;
if((SwpStep)&&(SNDMOD&0x40))
{
if(CntSwp<0)
{
CntSwp=SwpTime;
SwpCurPeriod+=SwpStep;
SwpCurPeriod&=0x7FF;
value=3072000/(2048-SwpCurPeriod);
if(value>100000)
{
value=100000;
ws_audio_set_channel_volume(2,0);
}
if(value<100)
{
value=100;
}
ASetVoiceFrequency(ws_audio_pcm_voice[2],value);
}
CntSwp--;
}
i++;
if(i>=BUFSIZEN)
{
i=0;
}
return RandData[i];
}
////////////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////////////
//
//
//
//
//
//
//
////////////////////////////////////////////////////////////////////////////////
static DWORD PCMPos=0;
DWORD TickZ=0,PcmCount;
void ws_audio_set_pcm(int Data)
{
DWORD tick;
PDataP[PCMPos++]=(unsigned char)(Data+128);
//tick=GetTickCount();
tick=SDL_GetTicks();
PcmCount++;
if(tick>=TickZ)
{
TickZ=tick+125;
PcmCount<<=3;
if(PcmCount>=10000)
{
PcmCount=12000;
}
ASetVoiceFrequency(ws_audio_noise_voice,PcmCount);
PcmCount=0;
}
if(PCMPos>=BUFSIZEP)
{
ws_audio_flash_pcm();
}
}
////////////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////////////
//
//
//
//
//
//
//
////////////////////////////////////////////////////////////////////////////////
void ws_audio_flash_pcm(void)
{
//int result;
//void *ptr1,*ptr2;
DWORD len1; //,len2;
const DWORD WrPos[16]=
{
BUFSIZEP*0,BUFSIZEP*1,BUFSIZEP*2,BUFSIZEP*3,
BUFSIZEP*4,BUFSIZEP*5,BUFSIZEP*6,BUFSIZEP*7,
BUFSIZEP*8,BUFSIZEP*9,BUFSIZEP*10,BUFSIZEP*11,
BUFSIZEP*12,BUFSIZEP*13,BUFSIZEP*14,BUFSIZEP*15,
};
len1=BUFSIZEP;
if (ws_audio_noise_wave.lpData == NULL)
{
return;
}
memcpy(&ws_audio_noise_wave.lpData[WrPos[PcmWrPos]], PDataP, len1);
AWriteAudioData(&ws_audio_noise_wave, 0, ws_audio_noise_wave.dwLength);
PcmWrPos++;
PcmWrPos&=0xF;
memset(PDataP,PL,sizeof(PDataP));
PCMPos=0;
}
////////////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////////////
//
//
//
//
//
//
//
////////////////////////////////////////////////////////////////////////////////
void ws_audio_write_byte(Uint32 offset, Uint8 value)
{
if (!((offset-WaveMap)&0xFFC0))
{
ws_audio_set_channels_pbuf(offset&0x003F,value);
internalRam[offset]=value;
}
}
////////////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////////////
//
//
//
//
//
//
//
////////////////////////////////////////////////////////////////////////////////
void ws_audio_process(void)
{
Uint32 i, j, b;
i=ws_audio_int();
PCSRL=(Uint8)(i&0xFF);
PCSRH=(Uint8)((i>>8)&0xFF);
/*if ((SDMACTL & 0x98) == 0x98)
{ // Hyper voice
v = Page[SDMASB + b][SDMASA + index++];
if ((SDMASA + index) == 0)
{
b++;
}
if (v < 0x80)
{
v += 0x80;
}
else
{
v -= 0x80;
}
if (SDMACNT <= index)
{
index = 0;
b = 0;
}
return v;
}
else */
if((SDMACTL&0x88)==0x80)
{
i=(SDMACH<<8)|SDMACL;
j=(SDMASB<<16)|(SDMASH<<8)|SDMASL;
b=cpu_readmem20(j);
if(!ws_audio_channel_isPlaying[5])
{
b=0x80;
}
ws_ioRam[0x89]=b;
i--;
j++;
if(i<32)
{
i=0;
SDMACTL&=0x7F;
}
SDMASB=(Uint8)((j>>16)&0xFF);
SDMASH=(Uint8)((j>>8)&0xFF);
SDMASL=(Uint8)(j&0xFF);
SDMACH=(Uint8)((i>>8)&0xFF);
SDMACL=(Uint8)(i&0xFF);
}
else if((SNDMOD&0x22)==0x22)
{
b=ws_ioRam[0x89];
if(!ws_audio_channel_isPlaying[4])
{
b=0x80;
}
}
else
{
b=0x80;
}
b>>=1;
b+=0x40;
if(b>0xAA)
{
b=0xAA;
}
else if(b<0x55)
{
b=0x55;
}
ws_audio_set_pcm(b);
}
////////////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////////////
//
//
//
//
//
//
//
////////////////////////////////////////////////////////////////////////////////
void ws_audio_readState(int fp)
{
long lpdwPosition;
long lpdwFrequency;
unsigned int lpnVolume;
unsigned int lpnPanning;
int lpnStatus;
unsigned char *pData;
read(fp,&PCMPos,sizeof(DWORD));
read(fp,&TickZ,sizeof(DWORD));
read(fp,&PcmCount,sizeof(DWORD));
read(fp,&WaveMap,sizeof(int));
read(fp,&ChPerInit,sizeof(int));
read(fp,&SwpTime,sizeof(int));
read(fp,&SwpStep,sizeof(int));
read(fp,&SwpCurPeriod,sizeof(int));
read(fp,&MainVol,sizeof(int));
read(fp,&CntSwp,sizeof(int));
read(fp,&PcmWrPos,sizeof(int));
read(fp,ws_audio_channel_isPlaying,sizeof(UINT32)*6);
read(fp,PData,sizeof(unsigned char)*4*BUFSIZE);
read(fp,PDataP,sizeof(unsigned char)*(BUFSIZEP<<4));
read(fp,PDataN,sizeof(unsigned char)*8*BUFSIZEN);
read(fp,PDataN,sizeof(int)*BUFSIZEN);
for (int i=0; i<4; i++)
{
read(fp,&lpdwPosition,sizeof(long));
read(fp,&lpdwFrequency,sizeof(long));
read(fp,&lpnVolume,sizeof(unsigned int));
read(fp,&lpnPanning,sizeof(unsigned int));
read(fp,&lpnStatus,sizeof(int));
ASetVoicePosition(ws_audio_pcm_voice[i],lpdwPosition);
ASetVoiceFrequency(ws_audio_pcm_voice[i], lpdwFrequency);
ASetVoiceVolume(ws_audio_pcm_voice[i], lpnVolume);
ASetVoicePanning(ws_audio_pcm_voice[i], lpnPanning);
pData=PData[i];
memcpy(ws_audio_pcm_wave[i].lpData, pData, ws_audio_pcm_wave[i].dwLength);
AWriteAudioData(&ws_audio_pcm_wave[i], 0, ws_audio_pcm_wave[i].dwLength);
if (ws_audio_channel_isPlaying[i])
{
APlayVoice(ws_audio_pcm_voice[i], &ws_audio_pcm_wave[i]);
}
}
ASetVoicePosition(ws_audio_noise_voice,lpdwPosition);
ASetVoiceFrequency(ws_audio_noise_voice, lpdwFrequency);
ASetVoiceVolume(ws_audio_noise_voice, lpnVolume);
ASetVoicePanning(ws_audio_noise_voice, lpnPanning);
pData=PDataP;
memcpy(ws_audio_noise_wave.lpData, pData, ws_audio_noise_wave.dwLength);
AWriteAudioData(&ws_audio_noise_wave, 0, ws_audio_noise_wave.dwLength);
if (ws_audio_channel_isPlaying[4])
{
APlayVoice(ws_audio_noise_voice, &ws_audio_noise_wave);
}
read(fp,&lpdwPosition,sizeof(long));
read(fp,&lpdwFrequency,sizeof(long));
read(fp,&lpnVolume,sizeof(unsigned int));
read(fp,&lpnPanning,sizeof(unsigned int));
read(fp,&lpnStatus,sizeof(int));
ASetVoicePosition(ws_audio_sweep_voice,lpdwPosition);
ASetVoiceFrequency(ws_audio_sweep_voice, lpdwFrequency);
ASetVoiceVolume(ws_audio_sweep_voice, lpnVolume);
ASetVoicePanning(ws_audio_sweep_voice, lpnPanning);
pData=PDataN[0];
memcpy(ws_audio_sweep_wave.lpData, pData, ws_audio_sweep_wave.dwLength);
AWriteAudioData(&ws_audio_sweep_wave, 0, ws_audio_sweep_wave.dwLength);
if (ws_audio_channel_isPlaying[5])
{
APlayVoice(ws_audio_sweep_voice, &ws_audio_sweep_wave);
}
read(fp,&lpdwPosition,sizeof(long));
read(fp,&lpdwFrequency,sizeof(long));
read(fp,&lpnVolume,sizeof(unsigned int));
read(fp,&lpnPanning,sizeof(unsigned int));
read(fp,&lpnStatus,sizeof(int));
}
////////////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////////////
//
//
//
//
//
//
//
////////////////////////////////////////////////////////////////////////////////
void ws_audio_writeState(int fp)
{
int32_t lpdwPosition;
int32_t lpdwFrequency;
uint16_t lpnVolume;
uint16_t lpnPanning;
int8_t lpnStatus;
write(fp,&PCMPos,sizeof(DWORD));
write(fp,&TickZ,sizeof(DWORD));
write(fp,&PcmCount,sizeof(DWORD));
write(fp,&WaveMap,sizeof(int));
write(fp,&ChPerInit,sizeof(int));
write(fp,&SwpTime,sizeof(int));
write(fp,&SwpStep,sizeof(int));
write(fp,&SwpCurPeriod,sizeof(int));
write(fp,&MainVol,sizeof(int));
write(fp,&CntSwp,sizeof(int));
write(fp,&PcmWrPos,sizeof(int));
write(fp,ws_audio_channel_isPlaying,sizeof(UINT32)*6);
write(fp,PData,sizeof(unsigned char)*4*BUFSIZE);
write(fp,PDataP,sizeof(unsigned char)*(BUFSIZEP<<4));
write(fp,PDataN,sizeof(unsigned char)*8*BUFSIZEN);
write(fp,PDataN,sizeof(int)*BUFSIZEN);
for (int i=0; i<4; i++)
{
AGetVoicePosition(ws_audio_pcm_voice[i],&lpdwPosition);
AGetVoiceFrequency(ws_audio_pcm_voice[i], &lpdwFrequency);
AGetVoiceVolume(ws_audio_pcm_voice[i], &lpnVolume);
AGetVoicePanning(ws_audio_pcm_voice[i], &lpnPanning);
AGetVoiceStatus(ws_audio_pcm_voice[i], &lpnStatus);
write(fp,&lpdwPosition,sizeof(long));
write(fp,&lpdwFrequency,sizeof(long));
write(fp,&lpnVolume,sizeof(unsigned int));
write(fp,&lpnPanning,sizeof(unsigned int));
write(fp,&lpnStatus,sizeof(int));
}
AGetVoicePosition(ws_audio_noise_voice,&lpdwPosition);
AGetVoiceFrequency(ws_audio_noise_voice, &lpdwFrequency);
AGetVoiceVolume(ws_audio_noise_voice, &lpnVolume);
AGetVoicePanning(ws_audio_noise_voice, &lpnPanning);
AGetVoiceStatus(ws_audio_noise_voice, &lpnStatus);
write(fp,&lpdwPosition,sizeof(long));
write(fp,&lpdwFrequency,sizeof(long));
write(fp,&lpnVolume,sizeof(unsigned int));
write(fp,&lpnPanning,sizeof(unsigned int));
write(fp,&lpnStatus,sizeof(int));
AGetVoicePosition(ws_audio_sweep_voice,&lpdwPosition);
AGetVoiceFrequency(ws_audio_sweep_voice, &lpdwFrequency);
AGetVoiceVolume(ws_audio_sweep_voice, &lpnVolume);
AGetVoicePanning(ws_audio_sweep_voice, &lpnPanning);
AGetVoiceStatus(ws_audio_sweep_voice, &lpnStatus);
write(fp,&lpdwPosition,sizeof(long));
write(fp,&lpdwFrequency,sizeof(long));
write(fp,&lpnVolume,sizeof(unsigned int));
write(fp,&lpnPanning,sizeof(unsigned int));
write(fp,&lpnStatus,sizeof(int));
}