MCUME/MCUME_teensy/teensymsx/SCC.c

188 wiersze
6.0 KiB
C

/** EMULib Emulation Library *********************************/
/** **/
/** SCC.c **/
/** **/
/** This file contains emulation for the SCC sound chip **/
/** produced by Konami. **/
/** **/
/** Copyright (C) Marat Fayzullin 1996-2003 **/
/** You are not allowed to distribute this software **/
/** commercially. Please, notify me, if you make any **/
/** changes to this file. **/
/*************************************************************/
#include "SCC.h"
#include "Sound.h"
#include <string.h>
/** ResetSCC() ***********************************************/
/** Reset the sound chip and use sound channels from the **/
/** one given in First. **/
/*************************************************************/
void ResetSCC(register SCC *D,int First)
{
int J;
/* Reset registers */
memset(D->R,0x00,sizeof(D->R));
/* Set instruments, frequencies, volumes */
for(J=0;J<SCC_CHANNELS;J++)
{
SetSound(0+First,SND_MELODIC);
D->Freq[J]=D->Volume[J]=0;
}
D->First = First;
D->Sync = SCC_ASYNC;
D->Changed = 0x00;
D->WChanged = 0x00;
}
/** ReadSCC() ************************************************/
/** Call this function to read contents of the generic SCC **/
/** sound chip registers. **/
/*************************************************************/
byte ReadSCC(register SCC *D,register byte R)
{
return(R<0x80? D->R[R]:0xFF);
}
/** ReadSCCP() ***********************************************/
/** Call this function to read contents of the newer SCC+ **/
/** sound chip registers. **/
/*************************************************************/
byte ReadSCCP(register SCC *D,register byte R)
{
return(R<0xA0? D->R[R]:0xFF);
}
/** WriteSCC() ***********************************************/
/** Call this function to output a value V into the generic **/
/** SCC sound chip. **/
/*************************************************************/
void WriteSCC(register SCC *D,register byte R,register byte V)
{
/* Prevent rollover */
if(R>=0xE0) return;
/* Generic SCC has one waveform less than SCC+ */
if(R>=0x80) { WriteSCCP(D,R+0x20,V);return; }
/* The last waveform applies to both channels 3 and 4 */
if(R>=0x60) { WriteSCCP(D,R,V);WriteSCCP(D,R+0x20,V);return; }
/* Other waveforms are the same */
WriteSCCP(D,R,V);
}
/** WriteSCCP() **********************************************/
/** Call this function to output a value V into the newer **/
/** SCC+ sound chip. **/
/*************************************************************/
void WriteSCCP(register SCC *D,register byte R,register byte V)
{
register int J;
register byte I;
/* Exit if no change */
if(V==D->R[R]) return;
if((R&0xE0)==0xA0)
{
/* Emulate melodic features */
/* Save active channel mask in I */
I=D->R[0xAF];
/* Write to a register */
R&=0xEF;
D->R[R]=D->R[R+0x10]=V;
/* Melodic register number 0..15 */
R&=0x0F;
switch(R)
{
case 0: case 1: case 2: case 3: case 4:
case 5: case 6: case 7: case 8: case 9:
/* Exit if the channel is silenced */
if(!(I&(1<<(R>>1)))) return;
/* Go to the first register of the pair */
R=(R&0xFE)+0xA0;
/* Compute frequency */
J=((int)(D->R[R+1]&0x0F)<<8)+D->R[R];
/* Compute channel number */
R=(R&0x0F)>>1;
/* Assign frequency */
D->Freq[R]=J? SCC_BASE/J:0;
/* Compute changed channels mask */
D->Changed|=1<<R;
break;
case 10: case 11: case 12: case 13: case 14:
/* Compute channel number */
R-=10;
/* Compute and assign new volume */
D->Volume[R]=255*(V&0x0F)/15;
/* Compute changed channels mask */
D->Changed|=(1<<R)&I;
break;
case 15:
/* Find changed channels */
R=(V^I)&0x1F;
D->Changed|=R;
/* Update frequencies */
for(I=0;R&&(I<SCC_CHANNELS);I++,R>>=1,V>>=1)
if(R&1)
{
if(!(V&1)) D->Freq[I]=0;
else
{
J=I*2+0xA0;
J=((int)(D->R[J+1]&0x0F)<<8)+D->R[J];
D->Freq[I]=J? SCC_BASE/J:0;
}
}
break;
default:
/* Wrong register, do nothing */
return;
}
}
else
{
/* Emulate wave table features */
/* Write data to SCC */
D->R[R]=V;
/* Wrong register, do nothing */
if(R>=0xA0) return;
/* Mark channel waveform as changed */
D->WChanged|=1<<(R>>5);
}
/* For asynchronous mode, make Sound() calls right away */
if(!D->Sync&&(D->Changed||D->WChanged)) SyncSCC(D,SCC_FLUSH);
}
/** SyncSCC() ************************************************/
/** Flush all accumulated changes by issuing Sound() calls **/
/** and set the synchronization on/off. The second argument **/
/** should be SCC_SYNC/SCC_ASYNC to set/reset sync, or **/
/** SCC_FLUSH to leave sync mode as it is. **/
/*************************************************************/
void SyncSCC(register SCC *D,register byte Sync)
{
register int J,I;
if(Sync!=SCC_FLUSH) D->Sync=Sync;
/* Modify waveforms */
for(J=0,I=D->WChanged;I&&(J<SCC_CHANNELS);J++,I>>=1)
if(I&1) SetWave(J+D->First,(signed char *)(D->R+(J<<5)),32,0);
/* Modify frequencies and volumes */
for(J=0,I=D->Changed;I&&(J<SCC_CHANNELS);J++,I>>=1)
if(I&1) Sound(J+D->First,D->Freq[J],D->Volume[J]);
D->Changed=D->WChanged=0x00;
}