1 /* Clarue Flower sound driver.
2 Initial version was based on the Wiping sound driver, which was based on the old namco.c sound driver.
3 */
4
5 #include "burnint.h"
6 #include "flower.h"
7 #include <stddef.h>
8
9 static const INT32 samplerate = 48000;
10
11 struct flower_sound_channel
12 {
13 UINT32 start;
14 UINT32 pos;
15 UINT16 freq;
16 UINT8 volume;
17 UINT8 voltab;
18 UINT8 oneshot;
19 UINT8 active;
20 UINT8 effect;
21 UINT32 ecount;
22 };
23
24 static flower_sound_channel m_channel_list[8];
25 static flower_sound_channel *m_last_channel;
26
27 /* global sound parameters */
28 static const UINT8 *m_sample_rom;
29 static const UINT8 *m_volume_rom;
30
31 /* mixer tables and internal buffers */
32 static INT16 *m_mixer_table;
33 static INT16 *m_mixer_lookup;
34 static INT16 *m_mixer_buffer;
35
36 static UINT8 m_soundregs1[0x40];
37 static UINT8 m_soundregs2[0x40];
38
39 /* build a table to divide by the number of voices; gain is specified as gain*16 */
make_mixer_table(INT32 voices,INT32 gain)40 static void make_mixer_table(INT32 voices, INT32 gain)
41 {
42 INT32 count = voices * 128;
43
44 /* allocate memory */
45 m_mixer_table = (INT16 *)BurnMalloc(sizeof(INT16) * 256 * voices);
46
47 /* find the middle of the table */
48 m_mixer_lookup = m_mixer_table + (128 * voices);
49
50 /* fill in the table - 16 bit case */
51 for (INT32 i = 0; i < count; i++)
52 {
53 INT32 val = i * gain * 16 / voices;
54 if (val > 32767) val = 32767;
55 m_mixer_lookup[ i] = val;
56 m_mixer_lookup[-i] =-val;
57 }
58 }
59
60 //-------------------------------------------------
61 // device_start - device-specific startup
62 //-------------------------------------------------
63
flower_sound_init(UINT8 * rom_sample,UINT8 * rom_volume)64 void flower_sound_init(UINT8 *rom_sample, UINT8 *rom_volume)
65 {
66 m_mixer_buffer = (INT16 *)BurnMalloc(sizeof(INT16) * 2 * samplerate);
67 make_mixer_table(8, 48);
68
69 m_sample_rom = rom_sample;
70 m_volume_rom = rom_volume;
71
72 m_last_channel = m_channel_list + 8;
73 }
74
flower_sound_exit()75 void flower_sound_exit()
76 {
77 BurnFree(m_mixer_buffer);
78 BurnFree(m_mixer_table);
79 }
80
flower_sound_scan()81 void flower_sound_scan()
82 {
83 SCAN_VAR(m_channel_list);
84 SCAN_VAR(m_soundregs1);
85 SCAN_VAR(m_soundregs2);
86 }
87
88 //-------------------------------------------------
89 // device_reset - device-specific reset
90 //-------------------------------------------------
91
flower_sound_reset()92 void flower_sound_reset()
93 {
94 /* reset all the voices */
95 for (INT32 i = 0; i < 8; i++)
96 {
97 flower_sound_channel *voice = &m_channel_list[i];
98
99 voice->freq = 0;
100 voice->pos = 0;
101 voice->volume = 0;
102 voice->voltab = 0;
103 voice->effect = 0;
104 voice->ecount = 0;
105 voice->oneshot = 1;
106 voice->active = 0;
107 voice->start = 0;
108 }
109
110 memset(m_soundregs1, 0, 0x40);
111 memset(m_soundregs2, 0, 0x40);
112 }
113
114 /********************************************************************************/
115 /* register functions (preliminary):
116 offset: cccrrr c=channel, r=register
117
118 set 1:
119 R 76543210
120 0 xxxxxxxx frequency (which nibble?)
121 1 xxxxxxxx *
122 2 xxxxxxxx *
123 3 xxxxxxxx *
124 4 ...x.... one-shot sample
125 5 ...x.... ??? same as R4?
126 6 ........ unused
127 7 xxxx.... volume
128
129 set 2:
130 R 76543210
131 0 ....xxxx start address
132 1 ....xxxx *
133 2 ....xxxx *
134 3 ....xxxx *
135 4 xxxx assume it's channel pitch/volume effects
136 xxxx start address
137 5 x... ???
138 xxxx start address
139 6 ........ unused
140 7 ......xx volume table + start trigger
141
142 */
143
flower_sound1_w(UINT16 offset,UINT8 data)144 void flower_sound1_w(UINT16 offset, UINT8 data)
145 {
146 flower_sound_channel *voice = &m_channel_list[offset >> 3 & 7];
147 INT32 c = offset & 0xf8;
148 UINT8 *base1 = m_soundregs1;
149
150 base1[offset] = data;
151
152 // recompute voice parameters
153 voice->freq = (base1[c+2] & 0xf) << 12 | (base1[c+3] & 0xf) << 8 | (base1[c+0] & 0xf) << 4 | (base1[c+1] & 0xf);
154 voice->volume = base1[c+7] >> 4;
155 }
156
flower_sound2_w(UINT16 offset,UINT8 data)157 void flower_sound2_w(UINT16 offset, UINT8 data)
158 {
159 flower_sound_channel *voice = &m_channel_list[offset >> 3 & 7];
160 INT32 i, c = offset & 0xf8;
161 UINT8 *base1 = m_soundregs1;
162 UINT8 *base2 = m_soundregs2;
163
164 base2[offset] = data;
165
166 // reg 7 is start trigger!
167 if ((offset & 7) != 7)
168 return;
169
170 voice->voltab = (base2[c+7] & 3) << 4;
171 voice->oneshot = (~base1[c+4] & 0x10) >> 4;
172 voice->effect = base2[c+4] >> 4;
173 voice->ecount = 0;
174 voice->pos = 0;
175 voice->active = 1;
176
177 // full start address is 6 nibbles
178 voice->start = 0;
179 for (i = 5; i >= 0; i--)
180 voice->start = (voice->start << 4) | (base2[c+i] & 0xf);
181 }
182
update_effects()183 static void update_effects()
184 {
185 flower_sound_channel *voice;
186
187 for (voice = m_channel_list; voice < m_last_channel; voice++)
188 voice->ecount += (voice->ecount < (1<<22));
189 }
190
191 //-------------------------------------------------
192 // sound_stream_update - handle a stream update
193 //-------------------------------------------------
194
flower_sound_update(INT16 * outputs,INT32 samples_len)195 void flower_sound_update(INT16 *outputs, INT32 samples_len)
196 {
197 INT16 *mix;
198
199 // compute # of samples @ soundcore native (48khz) rate
200 INT32 samples = (((((samplerate*1000) / nBurnFPS) * samples_len) / nBurnSoundLen)) / 10;
201
202 if (samples > samplerate) samples = samplerate;
203
204 /* zap the contents of the mixer buffer */
205 memset(m_mixer_buffer, 0, samples * sizeof(INT16));
206
207 update_effects(); // once per frame
208
209 /* loop over each voice and add its contribution */
210 for (flower_sound_channel *voice = m_channel_list; voice < m_last_channel; voice++)
211 {
212 INT32 f = voice->freq;
213 INT32 v = voice->volume;
214
215 if (!voice->active)
216 continue;
217
218 // effects
219 // bit 0: volume slide down?
220 if (voice->effect & 1 && !voice->oneshot)
221 {
222 // note: one-shot samples are fixed volume
223 v -= (voice->ecount >> 4);
224 if (v < 0) v = 0;
225 }
226 // bit 1: used often, but hard to figure out what for
227 // bit 2: probably pitch slide
228 if (voice->effect & 4)
229 {
230 f -= (voice->ecount << 7);
231 if (f < 0) f = 0;
232 }
233 // bit 3: not used much, maybe pitch slide the other way?
234
235 v |= voice->voltab;
236
237 mix = m_mixer_buffer;
238
239 for (INT32 i = 0; i < samples; i++)
240 {
241 // add sample
242 if (voice->oneshot)
243 {
244 UINT8 sample = m_sample_rom[(voice->start + voice->pos) >> 7 & 0x7fff];
245 if (sample == 0xff)
246 {
247 voice->active = 0;
248 break;
249 }
250 else
251 *mix++ += m_volume_rom[v << 8 | sample] - 0x80;
252 }
253 else
254 {
255 UINT8 sample = m_sample_rom[(voice->start >> 7 & 0x7e00) | (voice->pos >> 7 & 0x1ff)];
256 *mix++ += m_volume_rom[v << 8 | sample] - 0x80;
257 }
258
259 // update counter
260 voice->pos += f;
261 }
262 }
263
264 // resample native (48khz) -> our rate
265 for (INT32 j = 0; j < samples_len; j++)
266 {
267 INT32 k = (((((samplerate*1000) / nBurnFPS) * j) / nBurnSoundLen)) / 10;
268
269 INT32 lr = (INT32)(m_mixer_lookup[m_mixer_buffer[k]] * 0.50);
270
271 outputs[0] = BURN_SND_CLIP(lr);
272 outputs[1] = BURN_SND_CLIP(lr);
273 outputs += 2;
274 }
275
276 }
277