OSDN Git Service

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