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