1 /***************************************************************************
2
3 Konami 051649 - SCC1 sound as used in Haunted Castle, City Bomber
4
5 This file is pieced together by Bryan McPhail from a combination of
6 Namco Sound, Amuse by Cab, Haunted Castle schematics and whoever first
7 figured out SCC!
8
9 The 051649 is a 5 channel sound generator, each channel gets it's
10 waveform from RAM (32 bytes per waveform, 8 bit signed data).
11
12 This sound chip is the same as the sound chip in some Konami
13 megaROM cartridges for the MSX. It is actually well researched
14 and documented:
15
16 http://www.msxnet.org/tech/scc
17
18 Thanks to Sean Young (sean@mess.org) for some bugfixes.
19
20 K052539 is equivalent to this chip except channel 5 does not share
21 waveforms with channel 4.
22
23 ***************************************************************************/
24
25 #include "burnint.h"
26 #include "k051649.h"
27
28 #define FREQBASEBITS 16
29
30 static UINT32 nUpdateStep;
31
32 /* this structure defines the parameters for a channel */
33 typedef struct
34 {
35 UINT64 counter;
36 INT32 frequency;
37 INT32 volume;
38 INT32 key;
39 INT8 waveform[32]; /* 19991207.CAB */
40 } k051649_sound_channel;
41
42 typedef struct _k051649_state k051649_state;
43 struct _k051649_state
44 {
45 k051649_sound_channel channel_list[5];
46
47 /* global sound parameters */
48 INT32 mclock,rate;
49 double gain;
50 INT32 output_dir;
51
52 /* mixer tables and internal buffers */
53 INT16 *mixer_table;
54 INT16 *mixer_lookup;
55 INT16 *mixer_buffer;
56 };
57
58 static k051649_state Chips[1]; // ok? (one is good enough)
59 static k051649_state *info;
60
61 /* build a table to divide by the number of voices */
make_mixer_table(INT32 voices)62 static void make_mixer_table(INT32 voices)
63 {
64 INT32 count = voices * 256;
65 INT32 i;
66 INT32 gain = 8;
67
68 /* allocate memory */
69 info->mixer_table = (INT16 *)BurnMalloc(512 * voices * sizeof(INT16));
70
71 /* find the middle of the table */
72 info->mixer_lookup = info->mixer_table + (256 * voices);
73
74 /* fill in the table - 16 bit case */
75 for (i = 0; i < count; i++)
76 {
77 INT32 val = i * gain * 16 / voices;
78 if (val > 32767) val = 32767;
79 info->mixer_lookup[ i] = val;
80 info->mixer_lookup[-i] = -val;
81 }
82 }
83
84
85 /* generate sound to the mix buffer */
K051649Update(INT16 * pBuf,INT32 samples)86 void K051649Update(INT16 *pBuf, INT32 samples)
87 {
88 #if defined FBA_DEBUG
89 if (!DebugSnd_K051649Initted) bprintf(PRINT_ERROR, _T("K051649Update called without init\n"));
90 #endif
91
92 info = &Chips[0];
93 k051649_sound_channel *voice=info->channel_list;
94 INT16 *mix;
95 INT32 i,v,j;
96 double gain = info->gain;
97
98 /* zap the contents of the mixer buffer */
99 memset(info->mixer_buffer, 0, samples * sizeof(INT16));
100
101 for (j=0; j<5; j++)
102 {
103 // channel is halted for freq < 9
104 if (voice[j].frequency > 8)
105 {
106 const INT8 *w = voice[j].waveform; /* 19991207.CAB */
107 v=voice[j].volume * voice[j].key;
108 INT32 c=voice[j].counter;
109 INT32 step = (INT32)((((((float)info->mclock / (float)((voice[j].frequency+1) * 16))*(float)(1<<FREQBASEBITS)) / (float)(info->rate / 32)) * nUpdateStep) / 32768);
110 mix = info->mixer_buffer;
111
112 /* add our contribution */
113 for (i = 0; i < samples; i++)
114 {
115 INT32 offs;
116
117 c+= step;
118 offs = (c >> 16) & 0x1f;
119 *mix++ += ((w[offs] * v)>>3);
120 }
121
122 /* update the counter for this voice */
123 voice[j].counter = c;
124 }
125 }
126
127 /* mix it down */
128 mix = info->mixer_buffer;
129 for (i = 0; i < samples; i++) {
130 INT32 output = info->mixer_lookup[*mix++];
131
132 output = BURN_SND_CLIP(output);
133 output = (INT32)(output * gain);
134 output = BURN_SND_CLIP(output);
135
136 INT32 nLeftSample = 0, nRightSample = 0;
137
138 if ((info->output_dir & BURN_SND_ROUTE_LEFT) == BURN_SND_ROUTE_LEFT) {
139 nLeftSample += output;
140 }
141 if ((info->output_dir & BURN_SND_ROUTE_RIGHT) == BURN_SND_ROUTE_RIGHT) {
142 nRightSample += output;
143 }
144
145 pBuf[0] = BURN_SND_CLIP(pBuf[0] + nLeftSample);
146 pBuf[1] = BURN_SND_CLIP(pBuf[1] + nRightSample);
147 pBuf += 2;
148 }
149 }
150
K051649Init(INT32 clock)151 void K051649Init(INT32 clock)
152 {
153 DebugSnd_K051649Initted = 1;
154
155 info = &Chips[0];
156
157 /* get stream channels */
158 info->rate = clock/16;
159 info->mclock = clock;
160 info->gain = 1.00;
161 info->output_dir = BURN_SND_ROUTE_BOTH;
162
163 nUpdateStep = (INT32)(((float)info->rate / nBurnSoundRate) * 32768);
164
165 /* allocate a buffer to mix into - 1 second's worth should be more than enough */
166 info->mixer_buffer = (INT16 *)BurnMalloc(2 * sizeof(INT16) * info->rate);
167 memset(info->mixer_buffer, 0, 2 * sizeof(INT16) * info->rate);
168
169 /* build the mixer table */
170 make_mixer_table(5);
171
172 K051649Reset(); // clear things on init.
173 }
174
K051649SetRoute(double nVolume,INT32 nRouteDir)175 void K051649SetRoute(double nVolume, INT32 nRouteDir)
176 {
177 info = &Chips[0];
178
179 info->gain = nVolume;
180 info->output_dir = nRouteDir;
181 }
182
K051649Exit()183 void K051649Exit()
184 {
185 #if defined FBA_DEBUG
186 if (!DebugSnd_K051649Initted) bprintf(PRINT_ERROR, _T("K051649Exit called without init\n"));
187 #endif
188
189 if (!DebugSnd_K051649Initted) return;
190
191 info = &Chips[0];
192
193 BurnFree (info->mixer_buffer);
194 BurnFree (info->mixer_table);
195
196 nUpdateStep = 0;
197
198 DebugSnd_K051649Initted = 0;
199 }
200
K051649Reset()201 void K051649Reset()
202 {
203 #if defined FBA_DEBUG
204 if (!DebugSnd_K051649Initted) bprintf(PRINT_ERROR, _T("K051649Reset called without init\n"));
205 #endif
206
207 info = &Chips[0];
208 k051649_sound_channel *voice = info->channel_list;
209 INT32 i;
210
211 /* reset all the voices */
212 for (i = 0; i < 5; i++) {
213 voice[i].frequency = 0;
214 voice[i].volume = 0;
215 voice[i].key = 0;
216 voice[i].counter = 0;
217 memset(&voice[i].waveform, 0, 32);
218 }
219 }
220
K051649Scan(INT32 nAction,INT32 * pnMin)221 void K051649Scan(INT32 nAction, INT32 *pnMin)
222 {
223 #if defined FBA_DEBUG
224 if (!DebugSnd_K051649Initted) bprintf(PRINT_ERROR, _T("K051649Scan called without init\n"));
225 #endif
226
227 struct BurnArea ba;
228
229 if ((nAction & ACB_DRIVER_DATA) == 0) {
230 return;
231 }
232
233 if (pnMin != NULL) {
234 *pnMin = 0x029705;
235 }
236
237 memset(&ba, 0, sizeof(ba));
238 ba.Data = &info->channel_list;
239 ba.nLen = sizeof(k051649_sound_channel) * 5;
240 ba.nAddress = 0;
241 ba.szName = "K051649 Channel list";
242 BurnAcb(&ba);
243 }
244
245 /********************************************************************************/
246
K051649WaveformWrite(INT32 offset,INT32 data)247 void K051649WaveformWrite(INT32 offset, INT32 data)
248 {
249 #if defined FBA_DEBUG
250 if (!DebugSnd_K051649Initted) bprintf(PRINT_ERROR, _T("K051649WaveformWrite called without init\n"));
251 #endif
252
253 info = &Chips[0];
254 info->channel_list[offset>>5].waveform[offset&0x1f]=data;
255 /* SY 20001114: Channel 5 shares the waveform with channel 4 */
256 if (offset >= 0x60)
257 info->channel_list[4].waveform[offset&0x1f]=data;
258 }
259
K051649WaveformRead(INT32 offset)260 UINT8 K051649WaveformRead(INT32 offset)
261 {
262 #if defined FBA_DEBUG
263 if (!DebugSnd_K051649Initted) bprintf(PRINT_ERROR, _T("K051649WaveformRead called without init\n"));
264 #endif
265
266 info = &Chips[0];
267 return info->channel_list[offset>>5].waveform[offset&0x1f];
268 }
269
270 /* SY 20001114: Channel 5 doesn't share the waveform with channel 4 on this chip */
K052539WaveformWrite(INT32 offset,INT32 data)271 void K052539WaveformWrite(INT32 offset, INT32 data)
272 {
273 #if defined FBA_DEBUG
274 if (!DebugSnd_K051649Initted) bprintf(PRINT_ERROR, _T("K052539WaveformWrite called without init\n"));
275 #endif
276
277 info = &Chips[0];
278
279 info->channel_list[offset>>5].waveform[offset&0x1f]=data;
280 }
281
K051649VolumeWrite(INT32 offset,INT32 data)282 void K051649VolumeWrite(INT32 offset, INT32 data)
283 {
284 #if defined FBA_DEBUG
285 if (!DebugSnd_K051649Initted) bprintf(PRINT_ERROR, _T("K051649VolumeWrite called without init\n"));
286 #endif
287
288 info = &Chips[0];
289
290 info->channel_list[offset&0x7].volume=data&0xf;
291 }
292
K051649FrequencyWrite(INT32 offset,INT32 data)293 void K051649FrequencyWrite(INT32 offset, INT32 data)
294 {
295 #if defined FBA_DEBUG
296 if (!DebugSnd_K051649Initted) bprintf(PRINT_ERROR, _T("K051649FrequencyWrite called without init\n"));
297 #endif
298 INT32 freq_hi = offset & 1;
299
300 info = &Chips[0];
301
302 if (info->channel_list[offset>>1].frequency < 9)
303 info->channel_list[offset>>1].counter |= ((1 << FREQBASEBITS) - 1);
304
305 // update frequency
306 if (freq_hi)
307 info->channel_list[offset>>1].frequency = (info->channel_list[offset>>1].frequency & 0x0ff) | (data << 8 & 0xf00);
308 else
309 info->channel_list[offset>>1].frequency = (info->channel_list[offset>>1].frequency & 0xf00) | data;
310 }
311
K051649KeyonoffWrite(INT32 data)312 void K051649KeyonoffWrite(INT32 data)
313 {
314 #if defined FBA_DEBUG
315 if (!DebugSnd_K051649Initted) bprintf(PRINT_ERROR, _T("K051649KeyonoffWrite called without init\n"));
316 #endif
317
318 info = &Chips[0];
319 info->channel_list[0].key=(data&1) ? 1 : 0;
320 info->channel_list[1].key=(data&2) ? 1 : 0;
321 info->channel_list[2].key=(data&4) ? 1 : 0;
322 info->channel_list[3].key=(data&8) ? 1 : 0;
323 info->channel_list[4].key=(data&16) ? 1 : 0;
324 }
325
326