/** EMULib Emulation Library *********************************/ /** **/ /** SCC.c **/ /** **/ /** This file contains emulation for the SCC sound chip **/ /** produced by Konami. **/ /** **/ /** Copyright (C) Marat Fayzullin 1996-2005 **/ /** 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 /** 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;JFreq[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<Volume[R]=255*(V&0x0F)/15; /* Compute changed channels mask */ D->Changed|=(1<Changed|=R; /* Update frequencies */ for(I=0;R&&(I>=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>=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>=1) if(I&1) Sound(J+D->First,D->Freq[J],D->Volume[J]); D->Changed=D->WChanged=0x00; }