1 // license:BSD-3-Clause
2 // copyright-holders:Olivier Galibert, R. Belmont, hap, superctr
3 /*
4 ZOOM ZSG-2 custom wavetable synthesizer
5
6 Written by Olivier Galibert
7 MAME conversion by R. Belmont
8 Working emulation by The Talentuous Hands Of The Popularious hap
9 Properly working emulation by superctr
10 ---------------------------------------------------------
11
12 Register map:
13 000-5fe : Channel specific registers (48 channels)
14 (high) (low)
15 +000 : xxxxxxxx -------- : Start address (low)
16 +000 : -------- xxxxxxxx : Unknown register (usually cleared)
17 +002 : xxxxxxxx -------- : Address page
18 : -------- xxxxxxxx : Start address (high)
19 +004 : -------- -------- : Unknown register (usually cleared)
20 +006 : -----x-- -------- : Unknown bit, always set
21 +008 : xxxxxxxx xxxxxxxx : Frequency
22 +00a : xxxxxxxx -------- : DSP ch 3 (right) output gain
23 : -------- xxxxxxxx : Loop address (low)
24 +00c : xxxxxxxx xxxxxxxx : End address
25 +00e : xxxxxxxx -------- : DSP ch 2 (Left) output gain
26 : -------- xxxxxxxx : Loop address (high)
27 +010 : xxxxxxxx xxxxxxxx : Initial filter time constant
28 +012 : xxxxxxxx xxxxxxxx : Current filter time constant
29 +014 : xxxxxxxx xxxxxxxx : Initial volume
30 +016 : xxxxxxxx xxxxxxxx : Current volume?
31 +018 : xxxxxxxx xxxxxxxx : Target filter time constant
32 +01a : xxxxxxxx -------- : DSP ch 1 (chorus) output gain
33 : -------- xxxxxxxx : Filter ramping speed
34 +01c : xxxxxxxx xxxxxxxx : Target volume
35 +01e : xxxxxxxx -------- : DSP ch 0 (reverb) output gain
36 : -------- xxxxxxxx : Filter ramping speed
37 600-604 : Key on flags (each bit corresponds to a channel)
38 608-60c : Key off flags (each bit corresponds to a channel)
39 618 : Unknown register (usually 0x5cbc is written)
40 61a : Unknown register (usually 0x5cbc is written)
41 620 : Unknown register (usually 0x0128 is written)
42 628 : Unknown register (usually 0x0066 is written)
43 630 : Unknown register (usually 0x0001 is written)
44 638 : ROM readback address low
45 63a : ROM readback address high
46 63c : ROM readback word low
47 63e : ROM readback word high
48
49 ---------------------------------------------------------
50
51 Additional notes on the sample format, reverse-engineered
52 by Olivier Galibert and David Haywood:
53
54 The zoom sample rom is decomposed in 0x40000 bytes pages. Each page
55 starts by a header and is followed by compressed samples.
56
57 The header is a vector of 16 bytes structures composed of 4 32bits
58 little-endian values representing:
59 - sample start position in bytes, always a multiple of 4
60 - sample end position in bytes, minus 4, always...
61 - loop position in bytes, always....
62 - flags, probably
63
64 It is interesting to note that this header is *not* parsed by the
65 ZSG. The main program reads the rom through appropriate ZSG
66 commands, and use the results in subsequent register setups. It's
67 not even obvious that the ZSG cares about the pages, it may just
68 see the address space as linear. In the same line, the
69 interpretation of the flags is obviously dependent on the main
70 program, not the ZSG, but some of the bits are directly copied to
71 some of the registers.
72
73 The samples are compressed with a 2:1 ratio. Each block of 4-bytes
74 becomes 4 16-bits samples. Reading the 4 bytes as a *little-endian*
75 32bits values, the structure is:
76
77 42222222 51111111 60000000 ssss3333
78
79 's' is a 4-bit scale value. '0000000', '1111111', '2222222' and
80 '6543333' are signed 7-bits values corresponding to the 4 samples.
81 To compute the final 16bits value, left-align and shift right by s.
82 Yes, that simple.
83
84 ---------------------------------------------------------
85
86 TODO:
87 - Filter and ramping behavior might not be perfect.
88 - clicking / popping noises in gdarius, raystorm: maybe the sample ROMs are bad dumps?
89 - memory reads out of range sometimes
90
91 */
92
93 #include "emu.h"
94 #include "zsg2.h"
95
96 #include <algorithm>
97 #include <fstream>
98 #include <cmath>
99
100 #define EMPHASIS_INITIAL_BIAS 0
101 // Adjusts the cutoff constant of the filter by right-shifting the filter state.
102 // The current value gives a -6dB cutoff frequency at about 81.5 Hz, assuming
103 // sample playback at 32.552 kHz.
104 #define EMPHASIS_FILTER_SHIFT (16-10)
105 #define EMPHASIS_ROUNDING 0x20
106 // Adjusts the output amplitude by right-shifting the filtered output. Should be
107 // kept relative to the filter shift. A too low value will cause clipping, while
108 // too high will cause quantization noise.
109 #define EMPHASIS_OUTPUT_SHIFT 1
110
111 // device type definition
112 DEFINE_DEVICE_TYPE(ZSG2, zsg2_device, "zsg2", "ZOOM ZSG-2")
113
114 //-------------------------------------------------
115 // zsg2_device - constructor
116 //-------------------------------------------------
117
zsg2_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)118 zsg2_device::zsg2_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
119 : device_t(mconfig, ZSG2, tag, owner, clock)
120 , device_sound_interface(mconfig, *this)
121 , m_mem_base(*this, DEVICE_SELF)
122 , m_read_address(0)
123 , m_ext_read_handler(*this)
124 {
125 }
126
127 //-------------------------------------------------
128 // device_start - device-specific startup
129 //-------------------------------------------------
130
device_start()131 void zsg2_device::device_start()
132 {
133 m_ext_read_handler.resolve();
134
135 memset(&m_chan, 0, sizeof(m_chan));
136
137 m_stream = stream_alloc(0, 4, clock() / 768);
138
139 m_mem_blocks = m_mem_base.length();
140 m_mem_copy = make_unique_clear<uint32_t[]>(m_mem_blocks);
141 m_full_samples = make_unique_clear<int16_t[]>(m_mem_blocks * 4 + 4); // +4 is for empty block
142
143 // register for savestates
144 save_pointer(NAME(m_mem_copy), m_mem_blocks / sizeof(uint32_t));
145 save_pointer(NAME(m_full_samples), (m_mem_blocks * 4 + 4) / sizeof(int16_t));
146 save_item(NAME(m_read_address));
147
148 // Generate the output gain table. Assuming -1dB per step for now.
149 for (int i = 1; i < 32; i++)
150 {
151 double val = pow(10, -(31 - i) / 20.) * 65535.;
152 m_gain_tab[i] = val;
153 }
154 m_gain_tab[0] = 0;
155
156 for (int ch = 0; ch < 48; ch++)
157 {
158 save_item(NAME(m_chan[ch].v), ch);
159 save_item(NAME(m_chan[ch].status), ch);
160 save_item(NAME(m_chan[ch].cur_pos), ch);
161 save_item(NAME(m_chan[ch].step_ptr), ch);
162 save_item(NAME(m_chan[ch].step), ch);
163 save_item(NAME(m_chan[ch].start_pos), ch);
164 save_item(NAME(m_chan[ch].end_pos), ch);
165 save_item(NAME(m_chan[ch].loop_pos), ch);
166 save_item(NAME(m_chan[ch].page), ch);
167
168 save_item(NAME(m_chan[ch].vol), ch);
169 save_item(NAME(m_chan[ch].vol_initial), ch);
170 save_item(NAME(m_chan[ch].vol_target), ch);
171 save_item(NAME(m_chan[ch].vol_delta), ch);
172
173 save_item(NAME(m_chan[ch].output_cutoff), ch);
174 save_item(NAME(m_chan[ch].output_cutoff_initial), ch);
175 save_item(NAME(m_chan[ch].output_cutoff_target), ch);
176 save_item(NAME(m_chan[ch].output_cutoff_delta), ch);
177
178 save_item(NAME(m_chan[ch].emphasis_filter_state), ch);
179 save_item(NAME(m_chan[ch].output_filter_state), ch);
180
181 save_item(NAME(m_chan[ch].output_gain), ch);
182
183 save_item(NAME(m_chan[ch].samples), ch);
184 }
185
186 save_item(NAME(m_sample_count));
187 }
188
189 //-------------------------------------------------
190 // device_reset - device-specific reset
191 //-------------------------------------------------
192
device_reset()193 void zsg2_device::device_reset()
194 {
195 m_read_address = 0;
196
197 // stop playing and clear all channels
198 control_w(4, 0xffff);
199 control_w(5, 0xffff);
200 control_w(6, 0xffff);
201
202 for (int ch = 0; ch < 48; ch++)
203 for (int reg = 0; reg < 0x10; reg++)
204 chan_w(ch, reg, 0);
205 m_sample_count = 0;
206
207 #if 0
208 for (int i = 0; i < m_mem_blocks; i++)
209 prepare_samples(i);
210
211 FILE* f;
212
213 f = fopen("zoom_samples.bin","wb");
214 fwrite(m_mem_copy.get(),1,m_mem_blocks*4,f);
215 fclose(f);
216
217 f = fopen("zoom_samples.raw","wb");
218 fwrite(m_full_samples.get(),2,m_mem_blocks*4,f);
219 fclose(f);
220 #endif
221 }
222
223 /******************************************************************************/
224
read_memory(uint32_t offset)225 uint32_t zsg2_device::read_memory(uint32_t offset)
226 {
227 if (offset >= m_mem_blocks)
228 return 0;
229
230 if (m_ext_read_handler.isnull())
231 return m_mem_base[offset];
232
233 return m_ext_read_handler(offset);
234 }
235
prepare_samples(uint32_t offset)236 int16_t *zsg2_device::prepare_samples(uint32_t offset)
237 {
238 uint32_t block = read_memory(offset);
239
240 if (block == 0)
241 return &m_full_samples[m_mem_blocks]; // overflow or 0
242
243 if (block == m_mem_copy[offset])
244 return &m_full_samples[offset * 4]; // cached
245
246 m_mem_copy[offset] = block;
247 offset *= 4;
248
249 // decompress 32 bit block to 4 16-bit samples
250 // 42222222 51111111 60000000 ssss3333
251 m_full_samples[offset|0] = block >> 8 & 0x7f;
252 m_full_samples[offset|1] = block >> 16 & 0x7f;
253 m_full_samples[offset|2] = block >> 24 & 0x7f;
254 m_full_samples[offset|3] = (block >> (8+1) & 0x40) | (block >> (16+2) & 0x20) | (block >> (24+3) & 0x10) | (block & 0xf);
255
256 // sign-extend and shift
257 uint8_t shift = block >> 4 & 0xf;
258 for (int i = offset; i < (offset + 4); i++)
259 {
260 m_full_samples[i] <<= 9;
261 m_full_samples[i] >>= shift;
262 }
263
264 return &m_full_samples[offset];
265 }
266
267 // Fill the buffer with filtered samples
filter_samples(zchan * ch)268 void zsg2_device::filter_samples(zchan *ch)
269 {
270 int16_t *raw_samples = prepare_samples(ch->page | ch->cur_pos);
271 ch->samples[0] = ch->samples[4]; // we want to remember the last sample
272
273 for (int i = 0; i < 4; i++)
274 {
275 ch->emphasis_filter_state += raw_samples[i]-((ch->emphasis_filter_state+EMPHASIS_ROUNDING)>>EMPHASIS_FILTER_SHIFT);
276
277 int32_t sample = ch->emphasis_filter_state >> EMPHASIS_OUTPUT_SHIFT;
278 ch->samples[i+1] = std::min<int32_t>(std::max<int32_t>(sample, -32768), 32767);
279 }
280 }
281
282 //-------------------------------------------------
283 // sound_stream_update - handle a stream update
284 //-------------------------------------------------
285
sound_stream_update(sound_stream & stream,std::vector<read_stream_view> const & inputs,std::vector<write_stream_view> & outputs)286 void zsg2_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
287 {
288 for (int i = 0; i < outputs[0].samples(); i++)
289 {
290 int32_t mix[4] = {};
291
292 // loop over all channels
293 for (auto & elem : m_chan)
294 {
295 if(~elem.status & STATUS_ACTIVE)
296 continue;
297
298 elem.step_ptr += elem.step;
299 if (elem.step_ptr & 0xffff0000)
300 {
301 if (++elem.cur_pos >= elem.end_pos)
302 {
303 // loop sample
304 elem.cur_pos = elem.loop_pos;
305 if ((elem.cur_pos + 1) >= elem.end_pos)
306 {
307 // end of sample
308 elem.vol = 0; //this should help the channel allocation just a bit
309 elem.status &= ~STATUS_ACTIVE;
310 continue;
311 }
312 }
313
314 if(elem.cur_pos == elem.start_pos)
315 elem.emphasis_filter_state = EMPHASIS_INITIAL_BIAS;
316
317 elem.step_ptr &= 0xffff;
318 filter_samples(&elem);
319 }
320
321 uint8_t sample_pos = elem.step_ptr >> 14 & 3;
322 int32_t sample = elem.samples[sample_pos];
323
324 // linear interpolation (hardware certainly does something similar)
325 sample += ((uint16_t)(elem.step_ptr<<2&0xffff) * (int16_t)(elem.samples[sample_pos+1] - sample))>>16;
326
327 // another filter...
328 elem.output_filter_state += (sample - (elem.output_filter_state>>16)) * elem.output_cutoff;
329 sample = elem.output_filter_state >> 16;
330
331 // To prevent DC bias, we need to slowly discharge the filter when the output filter cutoff is 0
332 if(!elem.output_cutoff)
333 elem.output_filter_state >>= 1;
334
335 sample = (sample * elem.vol)>>16;
336
337 for(int output=0; output<4; output++)
338 {
339 int output_gain = elem.output_gain[output] & 0x1f; // left / right
340 int32_t output_sample = sample;
341
342 if (elem.output_gain[output] & 0x80) // perhaps ?
343 output_sample = -output_sample;
344
345 mix[output] += (output_sample * m_gain_tab[output_gain&0x1f]) >> 16;
346 }
347
348 // Apply ramping every other update
349 // It's possible key on is handled on the other sample
350 if(m_sample_count & 1)
351 {
352 elem.vol = ramp(elem.vol, elem.vol_target, elem.vol_delta);
353 elem.output_cutoff = ramp(elem.output_cutoff, elem.output_cutoff_target, elem.output_cutoff_delta);
354 }
355 }
356
357 for(int output=0; output<4; output++)
358 outputs[output].put_int_clamp(i, mix[output], 32768);
359 }
360 m_sample_count++;
361 }
362
363 /******************************************************************************/
364
chan_w(int ch,int reg,uint16_t data)365 void zsg2_device::chan_w(int ch, int reg, uint16_t data)
366 {
367 switch (reg)
368 {
369 case 0x0:
370 // lo byte: unknown, 0 on most games
371 // hi byte: start address low
372 m_chan[ch].start_pos = (m_chan[ch].start_pos & 0xff00) | (data >> 8 & 0xff);
373 break;
374
375 case 0x1:
376 // lo byte: start address high
377 // hi byte: address page
378 m_chan[ch].start_pos = (m_chan[ch].start_pos & 0x00ff) | (data << 8 & 0xff00);
379 m_chan[ch].page = data << 8 & 0xff0000;
380 break;
381
382 case 0x2:
383 // no function? always 0
384 break;
385
386 case 0x3:
387 // unknown, always 0x0400. is this a flag?
388 m_chan[ch].status &= 0x8000;
389 m_chan[ch].status |= data & 0x7fff;
390 break;
391
392 case 0x4:
393 // frequency
394 m_chan[ch].step = data + 1;
395 break;
396
397 case 0x5:
398 // lo byte: loop address low
399 // hi byte: right output gain (direct)
400 m_chan[ch].loop_pos = (m_chan[ch].loop_pos & 0xff00) | (data & 0xff);
401 m_chan[ch].output_gain[3] = data >> 8;
402 break;
403
404 case 0x6:
405 // end address
406 m_chan[ch].end_pos = data;
407 break;
408
409 case 0x7:
410 // lo byte: loop address high
411 // hi byte: left output gain (direct)
412 m_chan[ch].loop_pos = (m_chan[ch].loop_pos & 0x00ff) | (data << 8 & 0xff00);
413 m_chan[ch].output_gain[2] = data >> 8;
414 break;
415
416 case 0x8:
417 // IIR lowpass time constant (initial, latched on key on)
418 m_chan[ch].output_cutoff_initial = data;
419 break;
420
421 case 0x9:
422 // writes 0 at key on
423 m_chan[ch].output_cutoff = data;
424 break;
425
426 case 0xa:
427 // volume (initial, latched on key on)
428 m_chan[ch].vol_initial = data;
429 break;
430
431 case 0xb:
432 // writes 0 at key on
433 m_chan[ch].vol = data;
434 break;
435
436 case 0xc:
437 // IIR lowpass time constant (target)
438 m_chan[ch].output_cutoff_target = data;
439 break;
440
441 case 0xd:
442 // hi byte: DSP channel 1 (chorus) gain
443 // lo byte: Filter ramping speed
444 m_chan[ch].output_gain[1] = data >> 8;
445 m_chan[ch].output_cutoff_delta = get_ramp(data & 0xff);
446 break;
447
448 case 0xe:
449 // volume target
450 m_chan[ch].vol_target = data;
451 break;
452
453 case 0xf:
454 // hi byte: DSP channel 0 (reverb) gain
455 // lo byte: Volume ramping speed
456 m_chan[ch].output_gain[0] = data >> 8;
457 m_chan[ch].vol_delta = get_ramp(data & 0xff);
458 break;
459
460 default:
461 break;
462 }
463
464 m_chan[ch].v[reg] = data;
465 }
466
chan_r(int ch,int reg)467 uint16_t zsg2_device::chan_r(int ch, int reg)
468 {
469 switch (reg)
470 {
471 case 0x3:
472 // no games read from this.
473 return m_chan[ch].status;
474 case 0x9:
475 // pretty certain, though no games actually read from this.
476 return m_chan[ch].output_cutoff;
477 case 0xb: // Only later games (taitogn) read this register...
478 // GNet games use some of the flags to decide which channels to kill when
479 // all the channels are busy. (take raycris song #23 as an example)
480 return m_chan[ch].vol;
481 default:
482 break;
483 }
484
485 return m_chan[ch].v[reg];
486 }
487
488 // Convert ramping register value to something more usable.
489 // Upper 4 bits is a shift amount, lower 4 bits is a 2's complement value.
490 // Get ramp amount by sign extending the low 4 bits, XOR by 8, then
491 // shifting it by the upper 4 bits.
492 // CPU uses a lookup table (stored in gdarius sound cpu ROM at 0x6332) to
493 // calculate this value, for now I'm generating an opproximate inverse.
get_ramp(uint8_t val)494 int16_t zsg2_device::get_ramp(uint8_t val)
495 {
496 int16_t frac = val<<12; // sign extend
497 frac = ((frac>>12) ^ 8) << (val >> 4);
498 return (frac >> 4);
499 }
500
ramp(uint16_t current,uint16_t target,int16_t delta)501 inline uint16_t zsg2_device::ramp(uint16_t current, uint16_t target, int16_t delta)
502 {
503 int32_t rampval = current + delta;
504 if(delta < 0 && rampval < target)
505 rampval = target;
506 else if(delta >= 0 && rampval > target)
507 rampval = target;
508
509 return rampval;
510 }
511
512 /******************************************************************************/
513
control_w(int reg,uint16_t data)514 void zsg2_device::control_w(int reg, uint16_t data)
515 {
516 switch (reg)
517 {
518 case 0x00: case 0x01: case 0x02:
519 {
520 // key on
521 int base = (reg & 3) << 4;
522 for (int i = 0; i < 16; i++)
523 {
524 if (data & (1 << i))
525 {
526 int ch = base | i;
527 m_chan[ch].status |= STATUS_ACTIVE;
528 m_chan[ch].cur_pos = m_chan[ch].start_pos - 1;
529 m_chan[ch].step_ptr = 0x10000;
530 // Ignoring the "initial volume" for now because it causes lots of clicking
531 m_chan[ch].vol = 0; // m_chan[ch].vol_initial;
532 m_chan[ch].vol_delta = 0x0400; // register 06 ?
533 m_chan[ch].output_cutoff = m_chan[ch].output_cutoff_initial;
534 m_chan[ch].output_filter_state = 0;
535 }
536 }
537 break;
538 }
539
540 case 0x04: case 0x05: case 0x06:
541 {
542 // key off
543 int base = (reg & 3) << 4;
544 for (int i = 0; i < 16; i++)
545 {
546 if (data & (1 << i))
547 {
548 int ch = base | i;
549 m_chan[ch].vol = 0;
550 m_chan[ch].status &= ~STATUS_ACTIVE;
551 }
552 }
553 break;
554 }
555
556 // case 0x0c: //These registers are sometimes written to by the CPU. Unknown purpose.
557 // break;
558 // case 0x0d:
559 // break;
560 // case 0x10:
561 // break;
562
563 // case 0x18:
564 // break;
565
566 case 0x1c:
567 // rom readback address low (low 2 bits always 0)
568 if (data & 3) popmessage("ZSG2 address %04X, contact MAMEdev", data);
569 m_read_address = (m_read_address & 0x3fffc000) | (data >> 2 & 0x00003fff);
570 break;
571 case 0x1d:
572 // rom readback address high
573 m_read_address = (m_read_address & 0x00003fff) | (data << 14 & 0x3fffc000);
574 break;
575
576 default:
577 if(reg < 0x20)
578 m_reg[reg] = data;
579 logerror("ZSG2 control %02X = %04X\n", reg, data & 0xffff);
580 break;
581 }
582 }
583
control_r(int reg)584 uint16_t zsg2_device::control_r(int reg)
585 {
586 switch (reg)
587 {
588 case 0x14:
589 // memory bus busy?
590 // right before reading memory, it polls until low 8 bits are 0
591 return 0;
592
593 case 0x1e:
594 // rom readback word low
595 return read_memory(m_read_address) & 0xffff;
596 case 0x1f:
597 // rom readback word high
598 return read_memory(m_read_address) >> 16;
599
600 default:
601 if(reg < 0x20)
602 return m_reg[reg];
603 break;
604 }
605
606 return 0;
607 }
608
609 /******************************************************************************/
610
write(offs_t offset,uint16_t data,uint16_t mem_mask)611 void zsg2_device::write(offs_t offset, uint16_t data, uint16_t mem_mask)
612 {
613 // we only support full 16-bit accesses
614 if (mem_mask != 0xffff)
615 {
616 popmessage("ZSG2 write mask %04X, contact MAMEdev", mem_mask);
617 return;
618 }
619
620 m_stream->update();
621
622 if (offset < 0x300)
623 {
624 int chan = offset >> 4;
625 int reg = offset & 0xf;
626
627 chan_w(chan, reg, data);
628 }
629 else
630 {
631 control_w(offset - 0x300, data);
632 }
633 }
634
read(offs_t offset,uint16_t mem_mask)635 uint16_t zsg2_device::read(offs_t offset, uint16_t mem_mask)
636 {
637 // we only support full 16-bit accesses
638 if (mem_mask != 0xffff)
639 {
640 popmessage("ZSG2 read mask %04X, contact MAMEdev", mem_mask);
641 return 0;
642 }
643
644 if (offset < 0x300)
645 {
646 int chan = offset >> 4;
647 int reg = offset & 0xf;
648
649 return chan_r(chan, reg);
650 }
651 else
652 {
653 return control_r(offset - 0x300);
654 }
655 }
656