1 // license:BSD-3-Clause
2 // copyright-holders:Olivier Galibert, R. Belmont, MetalliC
3 /***************************************************************************
4
5 Yamaha YMZ770C "AMMS-A" and YMZ774 "AMMS2C"
6
7 Emulation by R. Belmont and MetalliC
8 AMM decode by Olivier Galibert
9
10 -----
11 TODO:
12 - What does channel ATBL mean?
13 - Simple Access mode. SACs is register / data lists same as SEQ. in 770C, when both /SEL and /CS pins goes low - will be run SAC with number set at data bus.
14 can not be used in CV1K (/SEL pin is NC, internally pulled to VCC), probably not used in PGM2 too.
15 770:
16 - sequencer timers implemented but seems unused, presumably because of design flaws or bugs, likely due to lack of automatic adding of sequencer # to register offset.
17 in result sequences uses very long chains of 32-sample wait commands instead, wasting a lot of ROM space.
18 - sequencer triggers not implemented, not sure how they works (Deathsmiles ending tune starts sequence with TGST = 01h, likely a bug and don't affect tune playback)
19 774:
20 - 4 channel output
21 - Equalizer
22 - pan delayed transition (not used in games)
23 - sequencer off trigger (not used in games)
24
25 known SPUs in this series:
26 YMZ770B AMMSL Capcom medal hardware (alien.cpp), sample format is not AMM, in other parts looks like 770C
27 YMZ770C AMMS-A Cave CV1000
28 YMZ771 SSGS3
29 YMZ773 AMMS2 Cron corp. video slots
30 YMZ775 AMMS2B
31 YMZ774 AMMS2C IGS PGM2
32 YMZ776 AMMS3 uses AM3 sample format (modified Ogg?)
33 YMZ778 AMMS3S
34 YMZ779 AMMS3D
35 YMZ870 AMMS3EX
36
37 ***************************************************************************/
38
39 #include "emu.h"
40 #include "ymz770.h"
41 #include "mpeg_audio.h"
42
43 // device type definition
44 DEFINE_DEVICE_TYPE(YMZ770, ymz770_device, "ymz770", "Yamaha YMZ770C AMMS-A")
45 DEFINE_DEVICE_TYPE(YMZ774, ymz774_device, "ymz774", "Yamaha YMZ774 AMMS2C")
46
47 //-------------------------------------------------
48 // ymz770_device - constructor
49 //-------------------------------------------------
50
ymz770_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)51 ymz770_device::ymz770_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
52 : ymz770_device(mconfig, YMZ770, tag, owner, clock, 16000)
53 {
54 }
55
ymz770_device(const machine_config & mconfig,device_type type,const char * tag,device_t * owner,uint32_t clock,uint32_t sclock)56 ymz770_device::ymz770_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, uint32_t sclock)
57 : device_t(mconfig, type, tag, owner, clock)
58 , device_sound_interface(mconfig, *this)
59 , m_stream(nullptr)
60 , m_sclock(sclock)
61 , m_cur_reg(0)
62 , m_mute(0)
63 , m_doen(0)
64 , m_vlma(0)
65 , m_vlma1(0)
66 , m_bsl(0)
67 , m_cpl(0)
68 , m_rom(*this, DEVICE_SELF)
69 {
70 }
71
72
73 //-------------------------------------------------
74 // device_start - device-specific startup
75 //-------------------------------------------------
76
device_start()77 void ymz770_device::device_start()
78 {
79 // create the stream
80 m_stream = stream_alloc(0, 2, m_sclock);
81
82 for (auto & channel : m_channels)
83 {
84 channel.is_playing = false;
85 channel.decoder = new mpeg_audio(&m_rom[0], mpeg_audio::AMM, false, 0);
86 }
87 for (auto & sequence : m_sequences)
88 sequence.is_playing = false;
89 for (auto & sqc : m_sqcs)
90 sqc.is_playing = false;
91
92 // register for save states
93 save_item(NAME(m_cur_reg));
94 save_item(NAME(m_mute));
95 save_item(NAME(m_doen));
96 save_item(NAME(m_vlma));
97 save_item(NAME(m_vlma1));
98 save_item(NAME(m_bsl));
99 save_item(NAME(m_cpl));
100
101 save_item(STRUCT_MEMBER(m_channels, phrase));
102 save_item(STRUCT_MEMBER(m_channels, pan));
103 save_item(STRUCT_MEMBER(m_channels, pan_delay));
104 save_item(STRUCT_MEMBER(m_channels, pan1));
105 save_item(STRUCT_MEMBER(m_channels, pan1_delay));
106 save_item(STRUCT_MEMBER(m_channels, volume));
107 save_item(STRUCT_MEMBER(m_channels, volume_target));
108 save_item(STRUCT_MEMBER(m_channels, volume_delay));
109 save_item(STRUCT_MEMBER(m_channels, volume2));
110 save_item(STRUCT_MEMBER(m_channels, loop));
111 save_item(STRUCT_MEMBER(m_channels, is_playing));
112 save_item(STRUCT_MEMBER(m_channels, last_block));
113 save_item(STRUCT_MEMBER(m_channels, is_paused));
114 save_item(STRUCT_MEMBER(m_channels, output_remaining));
115 save_item(STRUCT_MEMBER(m_channels, output_ptr));
116 save_item(STRUCT_MEMBER(m_channels, atbl));
117 save_item(STRUCT_MEMBER(m_channels, pptr));
118 save_item(STRUCT_MEMBER(m_channels, output_data));
119
120 save_item(STRUCT_MEMBER(m_sequences, delay));
121 save_item(STRUCT_MEMBER(m_sequences, sequence));
122 save_item(STRUCT_MEMBER(m_sequences, timer));
123 save_item(STRUCT_MEMBER(m_sequences, stopchan));
124 save_item(STRUCT_MEMBER(m_sequences, loop));
125 save_item(STRUCT_MEMBER(m_sequences, bank));
126 save_item(STRUCT_MEMBER(m_sequences, is_playing));
127 save_item(STRUCT_MEMBER(m_sequences, is_paused));
128 save_item(STRUCT_MEMBER(m_sequences, offset));
129
130 save_item(STRUCT_MEMBER(m_sqcs, sqc));
131 save_item(STRUCT_MEMBER(m_sqcs, loop));
132 save_item(STRUCT_MEMBER(m_sqcs, is_playing));
133 save_item(STRUCT_MEMBER(m_sqcs, is_waiting));
134 save_item(STRUCT_MEMBER(m_sqcs, offset));
135 }
136
137
138 //-------------------------------------------------
139 // device_reset - device-specific reset
140 //-------------------------------------------------
141
device_reset()142 void ymz770_device::device_reset()
143 {
144 for (auto & channel : m_channels)
145 {
146 channel.phrase = 0;
147 channel.pan = 64;
148 channel.pan_delay = 0;
149 channel.pan1 = 64;
150 channel.pan1_delay = 0;
151 channel.volume = 0;
152 channel.volume_target = 0;
153 channel.volume_delay = 0;
154 channel.volume2 = 0;
155 channel.loop = 0;
156 channel.is_playing = false;
157 channel.is_paused = false;
158 channel.output_remaining = 0;
159 channel.decoder->clear();
160 }
161 for (auto & sequence : m_sequences)
162 {
163 sequence.delay = 0;
164 sequence.sequence = 0;
165 sequence.timer = 0;
166 sequence.stopchan = 0;
167 sequence.loop = 0;
168 sequence.bank = 0;
169 sequence.is_playing = false;
170 sequence.is_paused = false;
171 }
172 for (auto & sqc : m_sqcs)
173 {
174 sqc.is_playing = false;
175 sqc.loop = 0;
176 }
177 }
178
179
180 //-------------------------------------------------
181 // sound_stream_update - handle update requests for
182 // our sound stream
183 //-------------------------------------------------
184
sound_stream_update(sound_stream & stream,std::vector<read_stream_view> const & inputs,std::vector<write_stream_view> & outputs)185 void ymz770_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
186 {
187 auto &outL = outputs[0];
188 auto &outR = outputs[1];
189
190 for (int i = 0; i < outL.samples(); i++)
191 {
192 sequencer();
193
194 // process channels
195 int32_t mixl = 0;
196 int32_t mixr = 0;
197
198 for (auto & channel : m_channels)
199 {
200 if (channel.output_remaining > 0)
201 {
202 // force finish current block
203 int32_t smpl = ((int32_t)channel.output_data[channel.output_ptr++] * (channel.volume >> 17)) >> 7; // volume is linear, 0 - 128 (100%)
204 smpl = (smpl * channel.volume2) >> 7;
205 mixr += (smpl * channel.pan) >> 7; // pan seems linear, 0 - 128, where 0 = 100% left, 128 = 100% right, 64 = 50% left 50% right
206 mixl += (smpl * (128 - channel.pan)) >> 7;
207 channel.output_remaining--;
208
209 if (channel.output_remaining == 0 && !channel.is_playing)
210 channel.decoder->clear();
211 }
212
213 else if (channel.is_playing && !channel.is_paused)
214 {
215 retry:
216 if (channel.last_block)
217 {
218 if (channel.loop)
219 {
220 if (channel.loop != 255)
221 --channel.loop;
222 // loop sample
223 int phrase = channel.phrase;
224 channel.atbl = m_rom[(4*phrase)+0] >> 4 & 7;
225 channel.pptr = 8 * get_phrase_offs(phrase);
226 }
227 else
228 {
229 channel.is_playing = false;
230 channel.output_remaining = 0;
231 channel.decoder->clear();
232 }
233 }
234
235 if (channel.is_playing)
236 {
237 // next block
238 int sample_rate, channel_count;
239 if (!channel.decoder->decode_buffer(channel.pptr, m_rom.bytes()*8, channel.output_data, channel.output_remaining, sample_rate, channel_count) || channel.output_remaining == 0)
240 {
241 channel.is_playing = !channel.last_block; // detect infinite retry loop
242 channel.last_block = true;
243 channel.output_remaining = 0;
244 goto retry;
245 }
246
247 channel.last_block = channel.output_remaining < 1152;
248 channel.output_remaining--;
249 channel.output_ptr = 1;
250
251 int32_t smpl = ((int32_t)channel.output_data[0] * (channel.volume >> 17)) >> 7;
252 smpl = (smpl * channel.volume2) >> 7;
253 mixr += (smpl * channel.pan) >> 7;
254 mixl += (smpl * (128 - channel.pan)) >> 7;
255 }
256 }
257 }
258
259 mixr *= m_vlma; // main volume is linear, 0 - 255, where 128 = 100%
260 mixl *= m_vlma;
261 mixr >>= 7 - m_bsl;
262 mixl >>= 7 - m_bsl;
263 // Clip limiter: 0 - off, 1 - 6.02 dB (100%), 2 - 4.86 dB (87.5%), 3 - 3.52 dB (75%)
264 constexpr int32_t ClipMax3 = 32768 * 75 / 100;
265 constexpr int32_t ClipMax2 = 32768 * 875 / 1000;
266 switch (m_cpl)
267 {
268 case 3:
269 mixl = (mixl > ClipMax3) ? ClipMax3 : (mixl < -ClipMax3) ? -ClipMax3 : mixl;
270 mixr = (mixr > ClipMax3) ? ClipMax3 : (mixr < -ClipMax3) ? -ClipMax3 : mixr;
271 break;
272 case 2:
273 mixl = (mixl > ClipMax2) ? ClipMax2 : (mixl < -ClipMax2) ? -ClipMax2 : mixl;
274 mixr = (mixr > ClipMax2) ? ClipMax2 : (mixr < -ClipMax2) ? -ClipMax2 : mixr;
275 break;
276 case 1:
277 mixl = (mixl > 32767) ? 32767 : (mixl < -32768) ? -32768 : mixl;
278 mixr = (mixr > 32767) ? 32767 : (mixr < -32768) ? -32768 : mixr;
279 break;
280 }
281 if (m_mute)
282 mixr = mixl = 0;
283 outL.put_int(i, mixl, 32768);
284 outR.put_int(i, mixr, 32768);
285 }
286 }
287
sequencer()288 void ymz770_device::sequencer()
289 {
290 for (auto & sequence : m_sequences)
291 {
292 if (sequence.is_playing)
293 {
294 if (sequence.delay > 0)
295 sequence.delay--;
296 else
297 {
298 int reg = get_rom_byte(sequence.offset++);
299 uint8_t data = get_rom_byte(sequence.offset++);
300 switch (reg)
301 {
302 case 0x0f:
303 for (int ch = 0; ch < 8; ch++) // might be wrong, ie not needed in case of loop
304 if (sequence.stopchan & (1 << ch))
305 m_channels[ch].is_playing = false;
306 if (sequence.loop)
307 sequence.offset = get_seq_offs(sequence.sequence); // loop sequence
308 else
309 sequence.is_playing = false;
310 break;
311 case 0x0e:
312 sequence.delay = sequence.timer * 32 + 32 - 1;
313 break;
314 default:
315 internal_reg_write(reg, data);
316 break;
317 }
318 }
319 }
320 }
321 }
322
323 //-------------------------------------------------
324 // write - write to the chip's registers
325 //-------------------------------------------------
326
write(offs_t offset,uint8_t data)327 void ymz770_device::write(offs_t offset, uint8_t data)
328 {
329 if (offset & 1)
330 {
331 m_stream->update();
332 internal_reg_write(m_cur_reg, data);
333 }
334 else
335 m_cur_reg = data;
336 }
337
338
internal_reg_write(uint8_t reg,uint8_t data)339 void ymz770_device::internal_reg_write(uint8_t reg, uint8_t data)
340 {
341 // global registers
342 if (reg < 0x40)
343 {
344 switch (reg)
345 {
346 case 0x00:
347 m_mute = data & 1;
348 m_doen = data >> 1 & 1;
349 break;
350
351 case 0x01:
352 m_vlma = data;
353 break;
354
355 case 0x02:
356 m_bsl = data & 7;
357 m_cpl = data >> 4 & 7;
358 break;
359
360 // unused
361 default:
362 logerror("unimplemented write %02X %02X\n", reg, data);
363 break;
364 }
365 }
366
367 // playback registers
368 else if (reg < 0x60)
369 {
370 int ch = reg >> 2 & 0x07;
371
372 switch (reg & 0x03)
373 {
374 case 0:
375 m_channels[ch].phrase = data;
376 break;
377
378 case 1:
379 m_channels[ch].volume2 = data;
380 m_channels[ch].volume = 128 << 17;
381 break;
382
383 case 2:
384 m_channels[ch].pan = data << 3;
385 break;
386
387 case 3:
388 if ((data & 6) == 2 || ((data & 6) == 6 && !m_channels[ch].is_playing)) // both KON bits is 1 = "Keep Playing", do not restart channel in this case
389 {
390 uint8_t phrase = m_channels[ch].phrase;
391 m_channels[ch].atbl = m_rom[(4*phrase)+0] >> 4 & 7;
392 m_channels[ch].pptr = 8 * get_phrase_offs(phrase);
393 m_channels[ch].last_block = false;
394
395 m_channels[ch].is_playing = true;
396 }
397 else if ((data & 6) == 0)
398 m_channels[ch].is_playing = false;
399
400 m_channels[ch].loop = (data & 1) ? 255 : 0;
401 break;
402 }
403 }
404
405 // sequencer registers
406 else if (reg >= 0x80)
407 {
408 int ch = reg >> 4 & 0x07;
409
410 switch (reg & 0x0f)
411 {
412 case 0: // SQSN
413 m_sequences[ch].sequence = data;
414 break;
415 case 1: // SQON SQLP
416 if ((data & 6) == 2 || ((data & 6) == 6 && !m_sequences[ch].is_playing)) // both KON bits 1 is "Keep Playing"
417 {
418 m_sequences[ch].offset = get_seq_offs(m_sequences[ch].sequence);
419 m_sequences[ch].delay = 0;
420 m_sequences[ch].is_playing = true;
421 }
422 else if ((data & 6) == 0 && m_sequences[ch].is_playing)
423 {
424 m_sequences[ch].is_playing = false;
425 for (int i = 0; i < 8; i++)
426 if (m_sequences[ch].stopchan & (1 << i))
427 m_channels[i].is_playing = false;
428 }
429
430 m_sequences[ch].loop = data & 1;
431 break;
432 case 2: // TMRH
433 m_sequences[ch].timer = (m_sequences[ch].timer & 0x00ff) | (data << 8);
434 break;
435 case 3: // TMRL
436 m_sequences[ch].timer = (m_sequences[ch].timer & 0xff00) | data;
437 break;
438 case 6: // SQOF
439 m_sequences[ch].stopchan = data;
440 break;
441 //case 4: // TGST "ON trigger playback channel selection bitmask"
442 //case 5: // TGEN "OFF trigger playback channel selection bitmask"
443 //case 7: // YMZ770: unused, but CV1K games write 1 here, must be game bugs or YMZ770C datasheet is wrong and have messed 7 and 8 registers ? ; YMZ771: SQOF_SSG
444 //case 8: // YMZ770: docs said "set to 01h" but CV1K games never write it, see above. ; YMZ771: TEMPO (wait timer speed control)
445 default:
446 if (data)
447 logerror("unimplemented write %02X %02X\n", reg, data);
448 break;
449 }
450 }
451 else
452 logerror("unimplemented write %02X %02X\n", reg, data);
453 }
454
455 //-------------------------------------------------
456 // ymz774_device
457 //-------------------------------------------------
458
ymz774_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)459 ymz774_device::ymz774_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
460 : ymz770_device(mconfig, YMZ774, tag, owner, clock, 44100)
461 {
462 // calculate volume increments, fixed point values, fractions of 0x20000
463 for (u32 i = 0; i < 256; i++)
464 {
465 if (i < 0x20)
466 volinc[i] = i;
467 else
468 volinc[i] = (0x20 | (i & 0x1f)) << ((i >> 5) - 1);
469 }
470 }
471
read(offs_t offset)472 uint8_t ymz774_device::read(offs_t offset)
473 {
474 if (offset & 1)
475 {
476 if (m_cur_reg == 0xe3 || m_cur_reg == 0xe4)
477 {
478 m_stream->update();
479 uint8_t res = 0;
480 int bank = (m_cur_reg == 0xe3) ? 8 : 0;
481 for (int i = 0; i < 8; i++)
482 if (m_channels[i + bank].is_playing)
483 res |= 1 << i;
484 return res;
485 }
486 }
487 logerror("unimplemented read %02X\n", m_cur_reg);
488 return 0;
489 }
490
internal_reg_write(uint8_t reg,uint8_t data)491 void ymz774_device::internal_reg_write(uint8_t reg, uint8_t data)
492 {
493 // playback registers
494 if (reg < 0x10) // phrase num H and L
495 {
496 int ch = ((reg >> 1) & 7) + m_bank * 8;
497 if (reg & 1)
498 m_channels[ch].phrase = (m_channels[ch].phrase & 0xff00) | data;
499 else
500 m_channels[ch].phrase = (m_channels[ch].phrase & 0x00ff) | ((data & 7) << 8);
501 }
502 else if (reg < 0x60)
503 {
504 int ch = (reg & 7) + m_bank * 8;
505 switch (reg & 0xf8)
506 {
507 case 0x10: // Volume 1
508 m_channels[ch].volume_target = data;
509 break;
510 case 0x18: // Volume 1 delayed transition
511 m_channels[ch].volume_delay = data;
512 break;
513 case 0x20: // Volume 2
514 m_channels[ch].volume2 = data;
515 break;
516 case 0x28: // Pan L/R
517 m_channels[ch].pan = data;
518 break;
519 case 0x30: // Pan L/R delayed transition
520 if (data) logerror("unimplemented write %02X %02X\n", reg, data);
521 m_channels[ch].pan_delay = data;
522 break;
523 case 0x38: // Pan T/B
524 m_channels[ch].pan1 = data;
525 break;
526 case 0x40: // Pan T/B delayed transition
527 if (data) logerror("unimplemented write %02X %02X\n", reg, data);
528 m_channels[ch].pan1_delay = data;
529 break;
530 case 0x48: // Loop
531 m_channels[ch].loop = data;
532 break;
533 case 0x50: // Start / Stop
534 if (data)
535 {
536 int phrase = m_channels[ch].phrase;
537 m_channels[ch].atbl = m_rom[(4 * phrase) + 0] >> 4 & 7;
538 m_channels[ch].pptr = 8 * get_phrase_offs(phrase);
539 m_channels[ch].last_block = false;
540
541 m_channels[ch].is_playing = true;
542 m_channels[ch].is_paused = false; // checkme, might be not needed
543 }
544 else
545 m_channels[ch].is_playing = false;
546 break;
547 case 0x58: // Pause / Resume
548 m_channels[ch].is_paused = data ? true : false;
549 if (data) logerror("CHECKME: CHAN pause/resume %02X %02X\n", reg, data);
550 break;
551 }
552 }
553 else if (reg < 0xd0)
554 {
555 if (m_bank == 0)
556 {
557 int sq = reg & 7;
558 switch (reg & 0xf8)
559 {
560 case 0x60: // sequence num H and L
561 case 0x68:
562 sq = (reg >> 1) & 7;
563 if (reg & 1)
564 m_sequences[sq].sequence = (m_sequences[sq].sequence & 0xff00) | data;
565 else
566 m_sequences[sq].sequence = (m_sequences[sq].sequence & 0x00ff) | ((data & 0x07) << 8);
567 break;
568 case 0x70: // Start / Stop
569 if (data)
570 {
571 //logerror("SEQ %d start (%s)\n", sq, m_sequences[sq].is_playing ? "playing":"stopped");
572 m_sequences[sq].offset = get_seq_offs(m_sequences[sq].sequence);
573 m_sequences[sq].delay = 0;
574 m_sequences[sq].is_playing = true;
575 m_sequences[sq].is_paused = false; // checkme, might be not needed
576 }
577 else
578 {
579 //logerror("SEQ %d stop (%s)\n", sq, m_sequences[sq].is_playing ? "playing" : "stopped");
580 if (m_sequences[sq].is_playing)
581 for (int ch = 0; ch < 16; ch++)
582 if (m_sequences[sq].stopchan & (1 << ch))
583 m_channels[ch].is_playing = false;
584 m_sequences[sq].is_playing = false;
585 }
586 break;
587 case 0x78: // Pause / Resume
588 m_sequences[sq].is_paused = data ? true : false;
589 if (data) logerror("CHECKME: SEQ pause/resume %02X %02X\n", reg, data);
590 break;
591 case 0x80: // Loop count, 0 = off, 255 - infinite
592 m_sequences[sq].loop = data;
593 break;
594 case 0x88: // timer H and L
595 case 0x90:
596 sq = (reg - 0x88) >> 1;
597 if (reg & 1)
598 m_sequences[sq].timer = (m_sequences[sq].timer & 0xff00) | data;
599 else
600 m_sequences[sq].timer = (m_sequences[sq].timer & 0x00ff) | (data << 8);
601 break;
602 case 0x98: // Off trigger, bit4 = on/off, bits0-3 channel (end sequence when channel playback ends)
603 if (data) logerror("SEQ Off trigger unimplemented %02X %02X\n", reg, data);
604 break;
605 case 0xa0: // stop channel mask H and L (when sequence stopped)
606 case 0xa8:
607 sq = (reg >> 1) & 7;
608 if (reg & 1)
609 m_sequences[sq].stopchan = (m_sequences[sq].stopchan & 0xff00) | data;
610 else
611 m_sequences[sq].stopchan = (m_sequences[sq].stopchan & 0x00ff) | (data << 8);
612 break;
613 case 0xb0: // SQC number
614 m_sqcs[sq].sqc = data;
615 break;
616 case 0xb8: // SQC start / stop
617 if (data)
618 {
619 //logerror("SQC %d start (%s)\n", sq, m_sqcs[sq].is_playing ? "playing" : "stopped");
620 m_sqcs[sq].offset = get_sqc_offs(m_sqcs[sq].sqc);
621 m_sqcs[sq].is_playing = true;
622 m_sqcs[sq].is_waiting = false;
623 }
624 else
625 {
626 //logerror("SQC %d stop (%s)\n", sq, m_sqcs[sq].is_playing ? "playing" : "stopped");
627 m_sqcs[sq].is_playing = false;
628 // stop SEQ too, and stop channels
629 if (m_sequences[sq].is_playing)
630 for (int ch = 0; ch < 16; ch++)
631 if (m_sequences[sq].stopchan & (1 << ch))
632 m_channels[ch].is_playing = false;
633 m_sequences[sq].is_playing = false;
634 }
635 break;
636 case 0xc0: // SQC loop (255 = infinite)
637 m_sqcs[sq].loop = data;
638 break;
639 default:
640 logerror("unimplemented write %02X %02X\n", reg, data);
641 break;
642 }
643 }
644 // else bank1 - Equalizer control
645 }
646 // global registers
647 else
648 {
649 switch (reg) {
650 case 0xd0: // Total Volume L0/R0
651 m_vlma = data;
652 break;
653 case 0xd1: // Total Volume L1/R1
654 m_vlma1 = data;
655 break;
656 case 0xd2: // Clip limit
657 m_cpl = data;
658 break;
659 //case 0xd3: // Digital/PWM output
660 //case 0xd4: // Digital audio IF/IS L0/R0
661 //case 0xd5: // Digital audio IF/IS L1/R1
662 //case 0xd8: // GPIO A
663 //case 0xdd: // GPIO B
664 //case 0xde: // GPIO C
665 case 0xf0:
666 m_bank = data & 1;
667 if (data > 1) logerror("Set bank %02X!\n", data);
668 break;
669 default:
670 logerror("unimplemented write %02X %02X\n", reg, data);
671 break;
672 }
673 }
674 }
675
sequencer()676 void ymz774_device::sequencer()
677 {
678 for (auto & chan : m_channels)
679 {
680 if (chan.is_playing && !chan.is_paused && (chan.volume >> 17) != chan.volume_target)
681 {
682 if (chan.volume_delay)
683 {
684 if ((chan.volume >> 17) < chan.volume_target)
685 chan.volume += volinc[chan.volume_delay];
686 else
687 chan.volume -= volinc[chan.volume_delay];
688 }
689 else
690 chan.volume = chan.volume_target << 17;
691 }
692 }
693
694 for (int i = 0; i < 8; i++)
695 {
696 auto & sqc = m_sqcs[i];
697 auto & sequence = m_sequences[i];
698
699 if (sqc.is_playing && !sqc.is_waiting)
700 {
701 // SQC consists of 4 byte records: SEQ num H, SEQ num L, SEQ Loop count, End flag (0xff)
702 sequence.sequence = ((get_rom_byte(sqc.offset) << 8) | get_rom_byte(sqc.offset + 1)) & 0x7ff;
703 sqc.offset += 2;
704 sequence.loop = get_rom_byte(sqc.offset++);
705 sequence.offset = get_seq_offs(sequence.sequence);
706 sequence.delay = 0;
707 sequence.is_playing = true;
708 sequence.is_paused = false; // checkme, might be not needed
709 sqc.is_waiting = true;
710 if (get_rom_byte(sqc.offset++) == 0xff)
711 {
712 if (sqc.loop)
713 {
714 if (sqc.loop != 255)
715 --sqc.loop;
716 sqc.offset = get_sqc_offs(sqc.sqc);
717 }
718 else
719 sqc.is_playing = false;
720 }
721 }
722
723 if (sequence.is_playing && !sequence.is_paused)
724 {
725 if (sequence.delay > 0)
726 --sequence.delay;
727 else
728 {
729 int reg = get_rom_byte(sequence.offset++);
730 uint8_t data = get_rom_byte(sequence.offset++);
731 switch (reg)
732 {
733 case 0xff: // end
734 for (int ch = 0; ch < 16; ch++) // might be wrong, ie not needed in case of loop
735 if (sequence.stopchan & (1 << ch))
736 m_channels[ch].is_playing = false;
737 if (sequence.loop)
738 {
739 if (sequence.loop != 255)
740 --sequence.loop;
741 sequence.offset = get_seq_offs(sequence.sequence);
742 }
743 else
744 {
745 sequence.is_playing = false;
746 sqc.is_waiting = false;
747 }
748 break;
749 case 0xfe: // timer delay
750 sequence.delay = sequence.timer * 32 + 32 - 1;
751 break;
752 case 0xf0:
753 sequence.bank = data & 1;
754 break;
755 default:
756 {
757 uint8_t temp = m_bank;
758 m_bank = sequence.bank;
759 if (m_bank == 0 && reg >= 0x60 && reg < 0xb0) // if we hit SEQ registers need to add this sequence offset
760 {
761 int sqn = i;
762 if (reg < 0x70 || (reg >= 0x88 && reg < 0x98) || reg >= 0xa0)
763 sqn = i * 2;
764 internal_reg_write(reg + sqn, data);
765 }
766 else
767 internal_reg_write(reg, data);
768 m_bank = temp;
769 }
770 break;
771 }
772 }
773 }
774 }
775 }
776