-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathSCC.c
More file actions
187 lines (164 loc) · 6.04 KB
/
Copy pathSCC.c
File metadata and controls
187 lines (164 loc) · 6.04 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
/** EMULib Emulation Library *********************************/
/** **/
/** SCC.c **/
/** **/
/** This file contains emulation for the SCC sound chip **/
/** produced by Konami. **/
/** **/
/** Copyright (C) Marat Fayzullin 1996-2021 **/
/** 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;
}