newoswan/source/audio.c
2021-04-05 14:19:35 +01:00

1540 lines
37 KiB
C

/*
* NewOswan
* audio.c:
* Based on the original Oswan-unix
* Copyright (c) 2014-2021 986-Studio. All rights reserved.
*
*/
////////////////////////////////////////////////////////////////////////////////
//
// 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 <stdint.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"
#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_t 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();
}
////////////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////////////
//
//
//
//
//
//
//
////////////////////////////////////////////////////////////////////////////////
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_t port, uint8_t value)
{
uint32_t n, i, j, k, b;
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_t)((i >> 16) & 0xFF);
DMASH = (uint8_t)((i >> 8) & 0xFF);
DMASL = (uint8_t)(i & 0xFF);
DMADB = (uint8_t)((j >> 16) & 0xFF);
DMADH = (uint8_t)((j >> 8) & 0xFF);
DMADL = (uint8_t)(j & 0xFF);
DMACH = (uint8_t)((n >> 8) & 0xFF);
DMACL = (uint8_t)(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);
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:
ws_audio_set_channel_pan(0, (value & 0xF0) >> 4, value & 0x0F);
break;
case 0x89:
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;
break;
case 0x8E:
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:
if (value & 0x01)
{
ws_audio_play_channel(0);
}
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:
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;
case 0x9A:
break;
}
}
////////////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////////////
//
//
//
//
//
//
//
////////////////////////////////////////////////////////////////////////////////
uint8_t ws_audio_port_read(uint8_t 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 = 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)
{
#if 0
int i, j;
AUDIOINFO info;
AUDIOCAPS caps;
uint32_t rc;
uint32_t 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 = 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());
#endif
return 1;
}
////////////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////////////
//
//
//
//
//
//
//
////////////////////////////////////////////////////////////////////////////////
void ws_audio_seal_done(void)
{
#if 0
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();
#endif
}
////////////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////////////
//
//
//
//
//
//
//
////////////////////////////////////////////////////////////////////////////////
void ws_audio_clear_channel(int Channel)
{
#if 0
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);
}
#endif
}
////////////////////////////////////////////////////////////////////////////////
// start playing a channel
////////////////////////////////////////////////////////////////////////////////
//
//
//
//
//
//
//
////////////////////////////////////////////////////////////////////////////////
int ws_audio_play_channel(int Channel)
{
#if 0
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]));
}
#endif
return 0;
}
////////////////////////////////////////////////////////////////////////////////
// stop playing a channel
////////////////////////////////////////////////////////////////////////////////
//
//
//
//
//
//
//
////////////////////////////////////////////////////////////////////////////////
int ws_audio_stop_channel(int Channel)
{
#if 0
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]);
}
#endif
return (0);
}
////////////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////////////
//
//
//
//
//
//
//
////////////////////////////////////////////////////////////////////////////////
void ws_audio_set_channel_frequency(int Channel, int Period)
{
#if 0
uint32_t 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);
}
#endif
}
////////////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////////////
//
//
//
//
//
//
//
////////////////////////////////////////////////////////////////////////////////
void ws_audio_set_channel_volume(int Channel, int Vol)
{
#if 0
long volume;
if(ChCurVol[Channel]==Vol)
{
return;
}
ChCurVol[Channel]=Vol;
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);
}
#endif
}
////////////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////////////
//
//
//
//
//
//
//
////////////////////////////////////////////////////////////////////////////////
void ws_audio_set_channel_pan(int Channel, int Left, int Right)
{
#if 0
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);
}
#endif
}
////////////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////////////
//
//
//
//
//
//
//
////////////////////////////////////////////////////////////////////////////////
void ws_audio_set_channel_pdata(int Channel, int Index)
{
#if 0
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);
}
#endif
}
////////////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////////////
//
//
//
//
//
//
//
////////////////////////////////////////////////////////////////////////////////
void ws_audio_set_channels_pbuf(int Addr, int Data)
{
#if 0
int i,j;
i=(Addr&0x30)>>4;
for(j=(Addr&0x0F)<<1; j<BUFSIZE; j+=32)
{
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);
}
#endif
}
////////////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////////////
//
//
//
//
//
//
//
////////////////////////////////////////////////////////////////////////////////
void ws_audio_rst_channel(int Channel)
{
#if 0
if(Channel==2)
{
ws_audio_set_channel_frequency(2,ChPerInit);
SwpCurPeriod=ChPerInit;
}
#endif
}
////////////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////////////
//
//
//
//
//
//
//
////////////////////////////////////////////////////////////////////////////////
int ws_audio_int(void)
{
#if 0
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];
#endif
return 1;
}
////////////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////////////
//
//
//
//
//
//
//
////////////////////////////////////////////////////////////////////////////////
#if 0
static uint32_t PCMPos=0;
uint32_t TickZ=0,PcmCount;
#endif
void ws_audio_set_pcm(int Data)
{
#if 0
uint32_t tick;
PDataP[PCMPos++]=(unsigned char)(Data+128);
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();
}
#endif
}
////////////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////////////
//
//
//
//
//
//
//
////////////////////////////////////////////////////////////////////////////////
void ws_audio_flash_pcm(void)
{
#if 0
uint32_t len1;
const uint32_t 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;
#endif
}
////////////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////////////
//
//
//
//
//
//
//
////////////////////////////////////////////////////////////////////////////////
void ws_audio_write_byte(uint32_t offset, uint8_t value)
{
if (!((offset - WaveMap) & 0xFFC0))
{
ws_audio_set_channels_pbuf(offset & 0x003F, value);
internalRam[offset] = value;
}
}
////////////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////////////
//
//
//
//
//
//
//
////////////////////////////////////////////////////////////////////////////////
void ws_audio_process(void)
{
uint32_t i, j, b;
i = ws_audio_int();
PCSRL = (uint8_t)(i & 0xFF);
PCSRH = (uint8_t)((i >> 8) & 0xFF);
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_t)((j >> 16) & 0xFF);
SDMASH = (uint8_t)((j >> 8) & 0xFF);
SDMASL = (uint8_t)(j & 0xFF);
SDMACH = (uint8_t)((i >> 8) & 0xFF);
SDMACL = (uint8_t)(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)
{
#if 0
long lpdwPosition;
long lpdwFrequency;
unsigned int lpnVolume;
unsigned int lpnPanning;
int lpnStatus;
unsigned char *pData;
read(fp,&PCMPos,sizeof(uint32_t));
read(fp,&TickZ,sizeof(uint32_t));
read(fp,&PcmCount,sizeof(uint32_t));
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_t)*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));
#endif
}
////////////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////////////
//
//
//
//
//
//
//
////////////////////////////////////////////////////////////////////////////////
void ws_audio_writeState(int fp)
{
#if 0
int32_t lpdwPosition;
int32_t lpdwFrequency;
uint16_t lpnVolume;
uint16_t lpnPanning;
int8_t lpnStatus;
write(fp,&PCMPos,sizeof(uint32_t));
write(fp,&TickZ,sizeof(uint32_t));
write(fp,&PcmCount,sizeof(uint32_t));
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_t)*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));
#endif
}