OSDN Git Service

[VM][PCENGINE][ADPCM] Remove unused parts.
[csp-qt/common_source_project-fm7.git] / source / src / vm / pcengine / adpcm.cpp
1 /*
2         NEC-HE PC Engine Emulator 'ePCEngine'
3         SHARP X1twin Emulator 'eX1twin'
4
5         Origin : Ootake (joypad/cdrom)
6                : xpce (psg)
7                : MESS (vdc/vce/vpc/cdrom)
8         Author : Takeda.Toshiya
9         Date   : 2009.03.11-
10         Author : Kyuma.Ohta <whatisthis.sowhat _at_ gmail.com>
11         Date   : 2019.02.09-  Split from pce.cpp
12
13         [ PC-Engine around ADPCM]
14 */
15
16 #include "./adpcm.h"
17 #include "./pce.h"
18
19
20 #include "../msm5205.h"
21 #include "../scsi_host.h"
22 #include "../scsi_cdrom.h"
23
24
25 namespace PCEDEV {
26
27 #define ADPCM_REMAIN_READ_BUF   0x80    
28 #define ADPCM_REMAIN_WRITE_BUF  0x04    
29 #define ADPCM_PLAY_FLAG                 0x08
30 #define ADPCM_STOP_FLAG                 0x01
31
32 #define EVENT_CLEAR_ACK 1
33 #define EVENT_SET_ACK   2
34 #define EVENT_FADE_IN   3
35 #define EVENT_FADE_OUT  4
36         
37 void ADPCM::initialize()
38 {
39         adpcm_clock_divider = 1; // OK?
40         event_fader = -1;
41         event_ack = -1;
42         reg_0c = 0;
43         msm_last_cmd = 0;
44         reg_0b = 0;
45         adpcm_volume = 100.0;
46
47         memset(ram, 0x00, sizeof(ram));
48 }
49
50 void ADPCM::reset()
51 {
52         written_size = 0;
53
54         reset_adpcm();
55 }
56
57 uint32_t ADPCM::read_signal(int ch)
58 {
59         switch(ch) {
60         case SIG_ADPCM_DATA:
61                 if(read_buf > 0) {
62                         // Don't need to modify FLAGS 20190212 K.O
63 //                      reg_0c |= ADPCM_REMAIN_READ_BUF;
64                         read_buf--;
65 //                      if(read_buf == 0) {
66 //                              reg_0c &= ~ADPCM_REMAIN_READ_BUF;
67 //                      }
68                         return 0x00;
69                 } else {
70 //                      reg_0c &= ~ADPCM_REMAIN_READ_BUF;
71                         uint8_t _d = ram[read_ptr & 0xffff];
72                         read_ptr = (read_ptr + 1) & 0xffff;
73                         return _d;
74                 }
75                 break;
76         case SIG_ADPCM_DMACTRL:
77                 return reg_0b;
78                 break;
79         case SIG_ADPCM_PLAY_IN_PROGRESS:
80                 return ((play_in_progress) ? 0xffffffff : 0);
81                 break;
82         case SIG_ADPCM_STATUS_REG:
83                 {
84                         uint8_t data = reg_0c;
85                         // Hack from Ootake v2.83.
86                         if((play_in_progress)) {
87                                 data = data & ~0x85;
88                                 data = data | 0x08;
89                         } else {
90                                 data = data & ~0x0c;
91                                 data = data | 0x01;
92                         }
93                         d_pce->write_signal(SIG_PCE_ADPCM_HALF, 0x00000000, 0xffffffff);
94                         return data;
95                 }
96                 break;
97         case SIG_ADPCM_CMD_REG:
98                 return msm_last_cmd;
99                 break;
100         }
101         return 0x00;
102 }
103
104 void ADPCM::reset_adpcm()
105 {
106         touch_sound();
107         // reset ADPCM hardware
108         read_ptr = write_ptr = 0;
109         read_buf = write_buf = 0;
110         msm_data = 0x00;
111         msm_ptr = half_addr = 0;
112         msm_nibble = 0;
113         msm_last_cmd = 0x00;
114         msm_length = 0x00;
115         
116         addr_reg.w = 0x0000;
117         adpcm_length = 0;
118         half_addr = 0;
119
120         reg_0b = 0x00; // OK?
121         
122         adpcm_stream = false;
123         adpcm_repeat = false;
124         dma_enabled = false;
125         dma_connected = false;
126         play_in_progress = false;
127         adpcm_paused = false;
128         
129         if(event_fader != -1) {
130                 cancel_event(this, event_fader);
131         }
132         event_fader = -1;
133         if(event_ack != -1) {
134                 cancel_event(this, event_ack);
135         }
136         event_ack = -1;
137         
138         reg_0c |= ADPCM_STOP_FLAG;
139         reg_0c &= ~ADPCM_PLAY_FLAG;
140         
141         do_stop(true);
142         set_dma_status(false);
143         //d_msm->reset();
144         d_msm->reset_w(1);
145         
146         //d_msm->change_clock_w((ADPCM_CLOCK / 6) / adpcm_clock_divider);  // From mednafen 1.22.1
147         //adpcm_volume = 0.0;
148         d_msm->set_volume((int)adpcm_volume);
149         //memset(ram, 0x00, sizeof(ram));
150         
151         out_debug_log(_T("RESET ADPCM\n"));
152         d_pce->write_signal(SIG_PCE_ADPCM_HALF, 0x00, 0xffffffff);
153         d_pce->write_signal(SIG_PCE_ADPCM_FULL, 0x00, 0xffffffff);
154
155 }
156
157 void ADPCM::do_play()
158 {
159         reg_0c &= ~ADPCM_STOP_FLAG;
160         reg_0c |= ADPCM_PLAY_FLAG;
161         play_in_progress = true;
162         adpcm_paused = false;
163 }
164
165 void ADPCM::do_pause(bool pause)
166 {
167         //if(!(play_in_progress)) return;
168         if(pause) {
169                 reg_0c |= ADPCM_STOP_FLAG;
170                 reg_0c &= ~ADPCM_PLAY_FLAG;
171                 msm_last_cmd &= ~0x60;
172                 adpcm_paused = true;
173                 d_msm->reset_w(1);
174                 out_debug_log(_T("ADPCM PAUSE PLAY PTR=%04x\n"), msm_ptr);
175                 touch_sound();
176         } else {
177                 adpcm_paused = false;
178                 touch_sound();
179                 reg_0c &= ~ADPCM_STOP_FLAG;
180                 reg_0c |= ADPCM_PLAY_FLAG;
181                 d_msm->reset_w(0);
182                 out_debug_log(_T("ADPCM UNPAUSE PLAY PTR=%04x\n"), msm_ptr);
183         }
184 }
185
186 void ADPCM::do_stop(bool do_notify)
187 {
188         touch_sound();
189         reg_0c |= ADPCM_STOP_FLAG;
190         reg_0c &= ~ADPCM_PLAY_FLAG;
191         msm_last_cmd &= ~0x60;
192         play_in_progress = false;
193         if(do_notify) set_dma_status(false);
194         out_debug_log(_T("ADPCM STOP PLAY PTR=%04x DMA CLEAR=%s\n"), msm_ptr, (do_notify) ? _T("YES") : _T("NO"));
195         
196 }
197
198 void ADPCM::set_dma_status(bool flag)
199 {
200         dma_enabled = flag;
201         if(!(flag)) {
202                 dma_connected = false;
203         }
204         d_pce->write_signal(SIG_PCE_ADPCM_DMA, (flag) ? 0xffffffff : 0x00000000, 0xffffffff);
205 }
206
207 void ADPCM::write_signal(int ch, uint32_t data, uint32_t mask)
208 {
209         bool flag = ((data & mask) != 0);
210         //if(ch != SIG_ADPCM_VCLK) out_debug_log(_T("WRITE_SIGNAL SIG=%d DATA=%04x MASK=%04x\n"), ch, data, mask);
211         switch(ch) {
212         case SIG_ADPCM_DMACTRL:
213                 if((data & 0x03) != 0) {
214                         set_dma_status(true);
215                         //reg_0b |= 0x02;
216                 }
217                 reg_0b = data;
218                 break;
219         case SIG_ADPCM_PAUSE:
220                 //do_pause(flag);
221                 break;
222         case SIG_ADPCM_DMA_ENABLED:
223                 set_dma_status(flag);
224                 if((flag)/* && (flag != dma_enabled)*/) {
225                         dma_connected = true;
226                         reg_0c |= ADPCM_REMAIN_WRITE_BUF;
227                         if(d_pce->read_signal(SIG_PCE_CDROM_DATA_IN) != 0) {
228                                 do_dma(d_pce->read_signal(SIG_PCE_CDROM_RAW_DATA));
229                                 out_debug_log(_T("Start DMA port $0B/ALREADY READ DATA ADPCM_WRITE_PTR=%04x ADPCM_READ_PTR=%04x MSM_START_ADDR=%04x\n"),write_ptr, read_ptr, msm_ptr);
230                         } else {
231                                 out_debug_log(_T("Start DMA port $0B/WAIT FOR DATA\n"));
232                         }
233                 }
234                 break;
235         case SIG_ADPCM_RESET:
236                 if(flag) {
237                         reset_adpcm();
238                 }
239                 break;
240         case SIG_ADPCM_COMMAND: // REG $0D
241                 do_cmd(data);
242                 break;
243         case SIG_ADPCM_WRITE_DMA_DATA:
244                 do_dma(data);
245                 break;
246         case SIG_ADPCM_DO_DMA_TRANSFER:
247                 //if((play_in_progress) && ((write_ptr & 0xffff) >= (msm_ptr & 0xffff))) {
248                 //      // now streaming, wait dma not to overwrite buffer before it is played
249                 //      reg_0b = 0x00;// From Ootake v2.38.
250                 //      dma_connected = false;
251                         //set_dma_status(false);  // DON'T MODIFY PCE's DMA STATUS (HACK by K.O 20190212)
252                 //} else {
253                 //set_dma_status(true);
254                         dma_connected = true;
255                         do_dma(d_pce->read_signal(SIG_PCE_CDROM_RAW_DATA));
256                 //}
257                 break;
258         case SIG_ADPCM_FORCE_DMA_TRANSFER:
259                 if(flag) {
260                         dma_connected = true;
261                         do_dma(d_pce->read_signal(SIG_PCE_CDROM_RAW_DATA));
262                 }
263                 break;
264         case SIG_ADPCM_DMA_RELEASED:
265                 if(flag) {
266                         dma_connected = false;
267                 }
268         case SIG_ADPCM_ADDR_HI: // REG $09
269                 if((msm_last_cmd & 0x80) == 0) {
270                 addr_reg.b.h = data;
271                         if((msm_last_cmd & 0x10) != 0) {
272                                 update_length();
273                                 out_debug_log(_T("SET ADDRESS REGISTER HIGH ; UPDATE LENGTH TO %04x\n"), adpcm_length);
274                         }
275                 }
276                 break;
277         case SIG_ADPCM_ADDR_LO: // REG $08
278                 if((msm_last_cmd & 0x80) == 0) {
279                         addr_reg.b.l = data;
280                         if((msm_last_cmd & 0x10) != 0) {
281                                 update_length();
282                                 out_debug_log(_T("SET ADDRESS REGISTER LOW ; UPDATE LENGTH TO %04x\n"), adpcm_length);
283                         }
284                 }
285                 break;
286         case SIG_ADPCM_VCLK:
287                 do_vclk(flag);
288                 break;
289         case SIG_ADPCM_DATA:
290                 // Don't need to modify FLAGS 20190212 K.O
291                 if(write_buf > 0) {
292                         //reg_0c |= ADPCM_REMAIN_WRITE_BUF;
293                         write_buf--;
294                         //if(write_buf == 0) {
295                         //      reg_0c &= ~ADPCM_REMAIN_WRITE_BUF;
296                         //}
297                 } else {
298                         //reg_0c &= ~ADPCM_REMAIN_WRITE_BUF;
299                         ram[write_ptr & 0xffff] = data;
300                         write_ptr = (write_ptr + 1) & 0xffff;
301                         written_size = written_size + 1;
302                         msm_length++;
303                 }
304                 break;
305         case SIG_ADPCM_FADE_IN:
306                 fade_in(data);
307                 break;
308         case SIG_ADPCM_FADE_OUT:
309                 fade_out(data);
310                 break;
311         case SIG_ADPCM_SET_DIVIDER:
312                 adpcm_clock_divider = 0x10 - (data & 0x0f);
313                 d_msm->change_clock_w((ADPCM_CLOCK / 6) / adpcm_clock_divider);
314                 break;
315         case SIG_ADPCM_CLEAR_ACK:
316                 reg_0b &= 0xfc; // Clear status register.
317                 break;
318         }
319 }
320
321 void ADPCM::update_length()
322 {
323         adpcm_length = (uint32_t)(addr_reg.w) & 0xffff; 
324         msm_length = adpcm_length;
325         out_debug_log(_T("ADPCM SET LENGTH TO %04x\n"), adpcm_length);
326 }
327
328 void ADPCM::do_cmd(uint8_t cmd)
329 {
330         // Register 0x0d.
331         //out_debug_log(_T("ADPCM CMD=%02x\n"), cmd);
332         if(((cmd & 0x80) != 0) && ((msm_last_cmd & 0x80) == 0)) {
333                 // Reset ADPCM
334                 reset_adpcm();
335                 //msm_init(); // SAMPLE = 0x800, SSIS=0
336                 out_debug_log(_T("ADPCM CMD RESET\n"));
337                 //msm_last_cmd = cmd;
338                 //return;
339         }
340         
341         if(((cmd & 0x08) != 0) && ((msm_last_cmd & 0x08) == 0)) {
342                 // ADPCM set read address
343                 read_ptr = (uint32_t)(addr_reg.w) & 0xffff;
344                 read_buf = ((cmd & 0x04) == 0) ? 2 : 1;
345                 msm_ptr = read_ptr;
346                 msm_ptr = ((cmd & 0x04) == 0) ? ((msm_ptr - 1) & 0xffff) : msm_ptr;
347                 out_debug_log(_T("ADPCM SET READ ADDRESS ADDR=%04x BUF=%01x \n"), read_ptr, read_buf);
348         }
349         if(((cmd & 0x10) != 0) /*&& ((msm_last_cmd & 0x10) == 0)*/){
350                 // ADPCM set length
351                 update_length();
352         }
353         if(((cmd & 0x02) != 0) && ((msm_last_cmd & 0x02) == 0)) {
354                 // ADPCM set write address
355                 write_ptr = (uint32_t)(addr_reg.w) & 0xffff;
356                 write_buf = ((cmd & 0x01) == 0) ? 1 : 0;
357                 //write_ptr = (write_ptr - write_buf) & 0xffff;
358                 //written_size = 0; // OK?
359                 
360         }
361         if((cmd & 0x10) != 0) {
362                 // It's ugly... (;_;)
363                 uint32_t _clk = (ADPCM_CLOCK / 6) / adpcm_clock_divider;
364                 if(((read_ptr & 0xffff) >= 0x4000) &&
365                    ((write_ptr & 0xffff) == 0x0000) &&
366                    (adpcm_length != 0x8000) &&
367                    (adpcm_length != 0xffff) &&
368                    (_clk < 16000)) {
369                         adpcm_length = adpcm_length & 0x7fff;
370                 }
371                 out_debug_log(_T("ADPCM SET LENGTH LENGTH=%04x\n"), adpcm_length);
372         }
373         if(((cmd & 0x02) != 0) && ((msm_last_cmd & 0x02) == 0)) {
374                 if((write_ptr == 0) || (write_ptr == 0x8000) || ((write_ptr & 0x1fff) == 0x1fff)) {
375                         if((((read_ptr + adpcm_length) & 0x1fff) == 0x1fff) ||
376                            ((read_ptr == 0) && (adpcm_length == 0x8000))) {
377                                 adpcm_stream = true;
378                         }
379                 }
380                 out_debug_log(_T("ADPCM SET WRITE ADDRESS ADDR=%04x BUF=%01x STREAM=%s\n"), write_ptr, write_buf, (adpcm_stream) ? _T("YES") : _T("NO"));
381         }
382         //bool req_play = false;
383         bool req_play = play_in_progress;
384         adpcm_repeat = ((cmd & 0x20) != 0) ? true : false;
385                 
386         if((play_in_progress) && !(adpcm_stream) && !(adpcm_repeat)) {
387                 req_play = false;
388         }
389         if(!(play_in_progress) && (adpcm_repeat)) {
390                 req_play = true;
391         }
392         if((cmd & 0x40) != 0) {
393                 req_play = true;
394         } else {
395                 if(adpcm_stream) {
396                         if(written_size > 0x8000) {
397                                 req_play = false;
398                         } else {
399                                 msm_last_cmd = cmd;
400                                 return; // Exit from command. 20190212 K.O
401                         }
402                 }
403         }
404         if(req_play) {
405 //                              msm_start_addr = (adpcm_read_ptr) & 0xffff;
406                 if(((cmd & 0x40) != 0) /*&& !(adpcm_play_in_progress)*/) {
407                         // ADPCM play
408                         half_addr = (read_ptr + ((adpcm_length + 1) >> 1)) & 0xffff;
409                         write_ptr &= 0xffff;
410                         if(!(play_in_progress)) written_size = 0; // OK?
411                         msm_nibble = 0;
412                         play_in_progress = true;
413                         msm_length = adpcm_length; // OK?
414                         do_play();
415                         d_msm->reset_w(0);
416                         out_debug_log(_T("ADPCM START PLAY(%s) START=%04x LENGTH=%04x HALF=%04x STREAM=%s\n"), (dma_enabled) ? _T("DMA") : _T("PIO"), msm_ptr, msm_length, half_addr, (adpcm_stream) ? _T("YES") : _T("NO"));
417                 } else {
418                         // 20181213 K.O: Import from Ootake v2.83.Thanks to developers of Ootake.
419                         if(((adpcm_length & 0xffff) >= 0x8000) && ((adpcm_length & 0xffff) <= 0x80ff)) {
420                                 half_addr = (read_ptr + 0x85) & 0xffff;
421                         } else {
422                                 half_addr = (read_ptr + ((adpcm_length + 1) >> 1)) & 0xffff;
423                         }
424                         out_debug_log(_T("ADPCM UPDATE HALF ADDRESS HALF=%04x\n"), half_addr);
425                 }
426         
427         } else {
428                 //set_cdrom_irq_line(PCE_CD_IRQ_SAMPLE_HALF_PLAY, CLEAR_LINE);
429                 //      set_cdrom_irq_line(PCE_CD_IRQ_SAMPLE_FULL_PLAY, ASSERT_LINE);
430                 adpcm_stream = false;
431                 adpcm_repeat = false;
432                 //d_pce->write_signal(SIG_PCE_ADPCM_HALF, 0x00000000, 0xffffffff);
433                 //d_pce->write_signal(SIG_PCE_ADPCM_FULL, 0x00000000, 0xffffffff);
434                 do_stop(true); // false?
435                 out_debug_log(_T("ADPCM STATUS UPDATE PLAY=%s\n"), (play_in_progress) ? _T("YES") : _T("NO"));
436         }
437         msm_last_cmd = cmd;
438 }
439
440
441 void ADPCM::msm_init()
442 {
443         //d_msm->reset();
444         //d_msm->reset_w(1);
445         //d_msm->reset_w(0);
446 }
447
448 void ADPCM::do_vclk(bool flag)
449 {
450         if((flag)) {
451                 {
452                         if((play_in_progress) && !(adpcm_paused)) {
453                                 msm_data = (msm_nibble != 0) ? (ram[msm_ptr & 0xffff] & 0x0f) : ((ram[msm_ptr & 0xffff] & 0xf0) >> 4);
454                                 //}
455                                 d_msm->data_w(msm_data);
456                                 msm_nibble ^= 1;
457                                 bool need_wait =false;
458                                 if((msm_nibble == 0)) {
459                                         // Increment pointers.
460                                         // 20181213 K.O: Re-order sequence from Ootake v2.83.Thanks to developers of Ootake.
461                                         if(((dma_enabled) && !(dma_connected)) || !(dma_enabled)) {
462                                                 if((msm_length == 0) && ((msm_last_cmd & 0x10) == 0)) {
463                                                         if((adpcm_repeat) && ((adpcm_length >= 0x8000) && (adpcm_length <= 0x80ff))) {
464                                                                 need_wait = true;
465                                                                 msm_length++;
466                                                         } else
467                                                         {
468                                                                 //d_pce->write_signal(SIG_PCE_ADPCM_HALF, 0x00000000, 0xffffffff);
469                                                                 d_pce->write_signal(SIG_PCE_ADPCM_FULL, 0xffffffff, 0xffffffff);
470                                                                 if((msm_last_cmd & 0x40) != 0) {
471                                                                         do_stop(false); // true?
472                                                                         d_msm->reset_w(1);
473                                                                 }
474                                                                 adpcm_stream = false;
475                                                                 adpcm_repeat = false;
476                                                         }
477                                                 }
478                                         }
479                                         if((written_size > 0) /*&& !(adpcm_stopped)*/) written_size--;
480                            
481                                 __skip0:
482                                         if(!(need_wait)) {
483                                                 
484                                                 msm_ptr++;
485                                                 msm_ptr = msm_ptr & 0xffff;
486                                                 read_ptr = msm_ptr;
487                                                 if(msm_length > 0) msm_length--;
488                                                 if(msm_length < 0) msm_length = 0;
489                                                 if(msm_length > 0x10000) msm_length = 0x10000;
490                                                 if((adpcm_repeat) && (adpcm_length >= 0x8000) && (adpcm_length <= 0x80ff)) {
491                                                         if(msm_ptr == (half_addr & 0xffff)) {
492                                                                 half_addr = half_addr + 0x85;
493                                                                 d_pce->write_signal(SIG_PCE_ADPCM_HALF, 0xffffffff, 0xffffffff);
494                                                                 d_pce->write_signal(SIG_PCE_ADPCM_FULL, 0x00000000, 0xffffffff);
495                                                         }                                               
496                                                 } else if(adpcm_length < 0x7fff) {
497                                                         if(msm_ptr == (half_addr & 0xffff)) {
498                                                                 half_addr = half_addr + ((adpcm_length - 1024) & 0xffff);
499                                                                 d_pce->write_signal(SIG_PCE_ADPCM_HALF, 0xffffffff, 0xffffffff);
500                                                                 d_pce->write_signal(SIG_PCE_ADPCM_FULL, 0x00000000, 0xffffffff);
501                                                         }                                               
502                                                 } else if((msm_ptr == 0x8000) || (msm_ptr == 0x0000)) {
503                                                         d_pce->write_signal(SIG_PCE_ADPCM_HALF, 0xffffffff, 0xffffffff);
504                                                         d_pce->write_signal(SIG_PCE_ADPCM_FULL, 0x00000000, 0xffffffff);
505                                                 }
506                                         }
507 #if 1
508                         __skip1:
509                                         if(dma_enabled) {
510                                                 if(((write_ptr & 0xffff) < (msm_ptr & 0xffff)) ||
511                                                    (written_size <= 0)) { 
512                                                         if(d_pce->read_signal(SIG_PCE_CDROM_DATA_IN) != 0) {
513                                                                 //do_pause(false); // Unpause if paused && data in.
514                                                                 do_dma(d_pce->read_signal(SIG_PCE_CDROM_RAW_DATA));
515                                                         }
516                                                 }
517                                         } else {
518                                         }
519 #endif
520                                 } else { // nibble = 1
521                                 }
522                         } else {
523 //                              if((dma_enabled) && (play_in_progress) && (dma_connected)) {
524 //                                      reg_0c |= ADPCM_REMAIN_WRITE_BUF;
525 //                                      if(d_pce->read_signal(SIG_PCE_CDROM_DATA_IN) != 0) {
526 //                                              //do_pause(false); // Unpause if paused && data in.
527 //                                              do_dma(d_pce->read_signal(SIG_PCE_CDROM_RAW_DATA));
528 //                                      }
529 //                              }
530                         }
531                 }
532         }
533 }
534
535 bool ADPCM::do_dma(uint8_t data)
536 {
537         ram[write_ptr & 0xffff] = data;
538         write_ptr = (write_ptr + 1) & 0xffff;
539         if(written_size < 0) written_size = 0;
540         written_size = written_size + 1;
541         msm_length++;
542         set_ack(0);
543
544         reg_0c &= ~ADPCM_REMAIN_WRITE_BUF;
545         return true;
546 }
547
548
549 void ADPCM::set_ack(int clocks)
550 {
551         if(event_ack != -1) cancel_event(this, event_ack);
552         event_ack = -1;
553         if(clocks <= 0) {
554                 d_pce->write_signal(SIG_PCE_CDROM_SET_ACK, 0xff, 0xff);
555         } else {
556                 double us = (((double)clocks) * 1.0e6) / ((double)CPU_CLOCKS);
557                 register_event(this, EVENT_SET_ACK, us, false, &event_ack);
558         }
559 }
560
561 void ADPCM::clear_ack(int clocks)
562 {
563         if(event_ack != -1) cancel_event(this, event_ack);
564         event_ack = -1;
565         if(clocks <= 0) {
566                 d_pce->write_signal(SIG_PCE_CDROM_CLEAR_ACK, 0xff, 0xff);
567         } else {
568                 double us = (((double)clocks) * 1.0e6) / ((double)CPU_CLOCKS);
569                 register_event(this, EVENT_CLEAR_ACK, us, false, &event_ack);
570         }
571 }
572
573 void ADPCM::fade_in(int usec)
574 {
575         if(event_fader != -1) {
576                 cancel_event(this, event_fader);
577         }
578         register_event(this, EVENT_FADE_IN, (double)usec, true, &event_fader);
579         adpcm_volume = 0.0;
580         d_msm->set_volume((int)adpcm_volume);
581 }
582
583 void ADPCM::fade_out(int usec)
584 {
585         if(event_fader != -1) {
586                 cancel_event(this, event_fader);
587         }
588         register_event(this, EVENT_FADE_OUT, (double)usec, true, &event_fader);
589         adpcm_volume = 100.0;
590         d_msm->set_volume((int)adpcm_volume);
591 }
592         
593 void ADPCM::event_callback(int id, int err)
594 {
595         switch(id) {
596         case EVENT_CLEAR_ACK:
597                 event_ack = -1;
598                 d_pce->write_signal(SIG_PCE_CDROM_CLEAR_ACK, 0xff, 0xff);
599                 break;
600         case EVENT_SET_ACK:
601                 event_ack = -1;
602                 d_pce->write_signal(SIG_PCE_CDROM_SET_ACK, 0xff, 0xff);
603                 break;
604         case EVENT_FADE_IN:             
605                 if((adpcm_volume += 0.1) >= 100.0) {
606                         cancel_event(this, event_fader);
607                         event_fader = -1;
608                         adpcm_volume = 100.0;
609                 }
610                 d_msm->set_volume((int)adpcm_volume);
611                 break;
612         case EVENT_FADE_OUT:            
613                 if((adpcm_volume -= 0.1) <= 0.0) {
614                         cancel_event(this, event_fader);
615                         event_fader = -1;
616                         adpcm_volume = 0.0;
617                 }
618                 d_msm->set_volume((int)adpcm_volume);
619                 break;
620         }
621 }
622
623 void ADPCM::mix(int32_t* buffer, int cnt)
624 {
625         d_msm->mix(buffer, cnt);
626 }
627
628 #define STATE_VERSION   7
629
630 bool ADPCM::process_state(FILEIO* state_fio, bool loading)
631 {
632         if(!state_fio->StateCheckUint32(STATE_VERSION)) {
633                 return false;
634         }
635         if(!state_fio->StateCheckInt32(this_device_id)) {
636                 return false;
637         }
638         state_fio->StateValue(addr_reg);
639         state_fio->StateValue(reg_0b);
640         state_fio->StateValue(reg_0c);
641         state_fio->StateValue(msm_last_cmd);
642         
643         state_fio->StateBuffer(ram, sizeof(ram), 1);
644         
645         state_fio->StateValue(read_ptr);
646         state_fio->StateValue(read_buf);
647         state_fio->StateValue(write_ptr);
648         state_fio->StateValue(write_buf);
649         
650         state_fio->StateValue(msm_data);
651         state_fio->StateValue(msm_ptr);
652         state_fio->StateValue(msm_nibble);
653         state_fio->StateValue(msm_length);
654         state_fio->StateValue(half_addr);
655         state_fio->StateValue(adpcm_length);
656         
657         state_fio->StateValue(written_size);
658         state_fio->StateValue(dma_enabled);
659         state_fio->StateValue(dma_connected);
660         state_fio->StateValue(play_in_progress);
661         state_fio->StateValue(adpcm_paused);
662         state_fio->StateValue(adpcm_stream);
663         state_fio->StateValue(adpcm_repeat);
664         state_fio->StateValue(adpcm_volume);
665         state_fio->StateValue(event_fader);
666         state_fio->StateValue(event_ack);
667
668         return true;
669 }
670
671 }
672