OSDN Git Service

[VM][FM77AV][VRAM] Fix crash with opening of LUXOL.
[csp-qt/common_source_project-fm7.git] / source / src / vm / fm7 / sound.cpp
1 /*
2  * FM-7 Main I/O [sound.cpp]
3  *  - PSG, OPN, and Buzzer.
4  *
5  * Author: K.Ohta <whatisthis.sowhat _at_ gmail.com>
6  * License: GPLv2
7  * History:
8  *   Mar 19, 2015 : Initial, split from fm7_mainio.cpp.
9  *
10  */
11
12 #include "../pcm1bit.h"
13 #include "../datarec.h"
14 #include "../ym2203.h"
15 #include "fm7_mainio.h"
16 #include "../ay_3_891x.h"
17 #include "../../config.h"
18 #include "./joystick.h"
19
20
21 namespace FM7 {
22
23 void FM7_MAINIO::reset_opn_psg(int ch_num)
24 {
25         if((ch_num < 0) || (ch_num > 3)) return;
26         opn_data[ch_num]= 0;
27         opn_cmdreg[ch_num] = 0;
28         opn_address[ch_num] = 0;
29         opn_stat[ch_num] = 0;
30         opn_prescaler_type[ch_num] = 1;
31         memset(opn_regs[ch_num], 0x00, 0x100 * sizeof(uint8_t));
32         if(ch_num == 3) {
33 #if !defined(_FM77AV_VARIANTS)
34                 if(psg != NULL) {
35                         psg->reset();
36                         write_opn_reg(3, 0x2e, 0);
37                         write_opn_reg(3, 0x27, 0);
38                         write_opn_reg(3, 0, 0);
39                 }
40 #endif
41                 return;
42         }
43         if(opn[ch_num] != NULL) {
44                 opn[ch_num]->reset();
45                 write_opn_reg(ch_num, 0x2e, 0);
46                 write_opn_reg(ch_num, 0x27, 0);
47         }
48         return;
49 }
50         
51 void FM7_MAINIO::reset_sound(void)
52 {
53         int i, j;
54
55         for(i = 0; i < 4; i++) {
56                 reset_opn_psg(i);
57         }
58
59  #if defined(_FM77AV_VARIANTS)
60         opn_psg_77av = true;
61  #else
62         opn_psg_77av = false;
63  #endif
64         connect_opn = connect_whg = connect_thg = false;
65         if(opn_psg_77av) connect_opn = true;
66
67         connect_thg = false;
68         connect_whg = false;
69 #if defined(_FM77AV_VARIANTS)   
70         connect_opn = true;
71 #else
72         connect_opn = false;
73 #endif
74         switch(config.sound_type) {
75                 case 0:
76                         break;
77                 case 1:
78                         connect_opn = true;
79                         break;
80                 case 2:
81                         connect_whg = true;
82                         break;
83                 case 3:
84                         connect_whg = true;
85                         connect_opn = true;
86                         break;
87                 case 4:
88                         connect_thg = true;
89                         break;
90                 case 5:
91                         connect_thg = true;
92                         connect_opn = true;
93                         break;
94                 case 6:
95                         connect_thg = true;
96                         connect_whg = true;
97                         break;
98                 case 7:
99                         connect_thg = true;
100                         connect_whg = true;
101                         connect_opn = true;
102                         break;
103         }
104         pcm1bit->write_signal(SIG_PCM1BIT_MUTE, 0x01, 0x01);
105         pcm1bit->write_signal(SIG_PCM1BIT_ON, 0x00, 0x01);
106         
107         opn[0]->write_signal(SIG_YM2203_MUTE, !connect_opn ? 0xffffffff : 0x00000000, 0xffffffff);
108         opn[1]->write_signal(SIG_YM2203_MUTE, !connect_whg ? 0xffffffff : 0x00000000, 0xffffffff);
109         opn[2]->write_signal(SIG_YM2203_MUTE, !connect_thg ? 0xffffffff : 0x00000000, 0xffffffff);
110 # if !defined(_FM77AV_VARIANTS)
111 #  if defined(USE_AY_3_8910_AS_PSG)
112         psg->write_signal(SIG_AY_3_891X_MUTE, 0x00000000, 0xffffffff);
113 #  else
114         psg->write_signal(SIG_YM2203_MUTE, 0x00000000, 0xffffffff);
115 #  endif
116 # endif
117 }
118
119
120 void FM7_MAINIO::set_psg(uint8_t val)
121 {
122         if(opn_psg_77av) return set_opn(0, val); // 77AV ETC
123         set_opn(3, val);
124 }
125
126 uint8_t FM7_MAINIO::get_psg(void)
127 {
128         if(opn_psg_77av) {
129                 return get_opn(0);
130         }
131         return get_opn(3);
132 }
133
134 /*
135  * $fd0d : After 77AV, this is OPN.
136  */
137 void FM7_MAINIO::set_psg_cmd(uint8_t cmd)
138 {
139         cmd = cmd & 0x03;
140         if(opn_psg_77av) {
141                 set_opn_cmd(0, cmd);
142                 return;
143         }
144         set_opn_cmd(3, cmd);
145         return;
146 }
147
148 // OPN
149 // Write to FD16, same as 
150 void FM7_MAINIO::write_opn_reg(int index, uint32_t addr, uint32_t data)
151 {
152         //out_debug_log("OPN_WRITE: #%d REG=%02x VAL=%02x\n", index, addr, data);
153         static const uint32_t mask[16] = { // Parameter is related by XM7. Thanks Ryu.
154                 0xff, 0x0f, 0xff, 0x0f,
155                 0xff, 0x0f, 0x1f, 0xff,
156                 0x1f, 0x1f, 0x1f, 0xff,
157                 0xff, 0x0f, 0xff, 0xff
158         };
159 #if 1
160 #  if !defined(_FM77AV_VARIANTS)
161         if(index == 3) { // PSG
162                 data = data & mask[addr & 0x0f];
163                 psg->write_io8(0, addr & 0x0f);
164                 psg->write_io8(1, data);
165                 opn_regs[index][addr & 0x0f] = data;
166                 return;
167         }
168 #  endif
169         if(addr < 0x10) { // PSG part
170                 data = data & mask[addr]; // Right?
171         } else  if((addr >= 0x2d) && (addr < 0x30)) {  // Prescaler
172                 switch(addr) {
173                 case 0x2d:
174                         if(opn_prescaler_type[index] != 1) {
175                                 opn_prescaler_type[index] = 0;
176                                 opn[index]->write_io8(0, addr);
177                                 for(int ii = 0x2d; ii <= 0x2f; ii++) opn_regs[index][ii] = 0;
178                                 opn_regs[index][addr] = 0xff;
179                         }
180                         break;
181                 default: // 0x2e, 0x2f
182                         opn_prescaler_type[index] = addr - 0x2d;
183                         opn[index]->write_io8(0, addr);
184                         for(int ii = 0x2d; ii <= 0x2f; ii++) opn_regs[index][ii] = 0;
185                         opn_regs[index][addr] = 0xff;
186                         break;
187                 }                       
188                 return;
189         }/* else if(addr == 0xff) { // Check : from XM7.
190                 if((opn_regs[index][0x27] & 0xc0) != 0x80) {
191                         opn_regs[index][addr] = data;
192                         return;
193                 }
194                 }*/
195
196         opn[index]->write_io8(0, addr);
197         opn[index]->write_io8(1, data);
198         opn_regs[index][addr] = data;
199 #else
200 #  if !defined(_FM77AV_VARIANTS)
201         if(index == 3) {
202                 if(psg != NULL) psg->set_reg(addr & 0x0f, data);
203         } else
204 #  endif
205         {
206                 if(opn[index] != NULL) opn[index]->set_reg(addr, data);
207         }
208         opn_regs[index][addr] = data;
209 #endif  
210         return;
211 }
212
213 void FM7_MAINIO::set_opn(int index, uint8_t val)
214 {
215         if((index > 3) || (index < 0)) return;
216         if((index == 0) && (!connect_opn)) return;
217         if((index == 1) && (!connect_whg)) return;
218         if((index == 2) && (!connect_thg)) return;
219         if((index == 3) && (opn_psg_77av)) return;
220 # if !defined(_FM77AV_VARIANTS) 
221         if(index == 3) {
222                 if(psg == NULL) return;
223         } else
224 # endif
225         if(opn[index] == NULL) {
226                 return;
227         }
228         opn_data[index] = val;
229         switch(opn_cmdreg[index]) {
230                 case 2: // Write data
231                         write_opn_reg(index, opn_address[index], opn_data[index]);
232                         break;
233                 case 3: // Register address
234 # if !defined(_FM77AV_VARIANTS)
235                         if(index == 3) {
236                                 opn_address[index] = val & 0x0f;
237                                 if(psg != NULL) psg->write_io8(0, opn_address[index]);
238                         } else
239 # endif
240                         {
241                                 opn_address[index] = val;
242                                 if(opn[index] != NULL) opn[index]->write_io8(0, opn_address[index]);
243                         }
244                         break;
245                 default:
246                         break;
247         }
248 }
249
250 uint8_t FM7_MAINIO::get_opn(int index)
251 {
252         uint8_t val = 0xff;
253         if((index > 3) || (index < 0)) return val;
254         if((index == 0) && (!connect_opn)) return val;
255         if((index == 1) && (!connect_whg)) return val;
256         if((index == 2) && (!connect_thg)) return val;
257         if((index == 3) && (opn_psg_77av)) return val;
258 # if !defined(_FM77AV_VARIANTS) 
259         if(index == 3) {
260                 if(psg == NULL) return val;
261         } else
262 # endif
263         if(opn[index] == NULL) {
264                 return val;
265         }
266         // 20190922 from XM7 3477a.
267         static const uint8_t opn_bitmask[16] = {
268                 0xff,   0x0f,   0xff,   0x0f,
269                 0xff,   0x0f,   0x1f,   0xff,
270                 0x1f,   0x1f,   0x1f,   0xff,
271                 0xff,   0x0f,   0xff,   0xff,
272         };
273
274         if(index == 3) opn_cmdreg[index] = opn_cmdreg[index] & 0x03;
275
276         switch(opn_cmdreg[index]) {
277                 case 0: // Unavailable
278                         val = 0xff;
279                         break;
280                 case 1: // read from
281 //                      val = opn_data[index];
282                         if((opn_address[index] == 14) || (opn_address[index] == 15)) {
283                                 if(index != 3) {
284                                         val = opn_data[index]; // OK?
285                                 }
286                         } else {
287 # if !defined(_FM77AV_VARIANTS)
288                                 if(index == 3) {
289 //                                      if(opn_address[index] < 0x10) {
290                                                 val = psg->read_io8(1) & opn_bitmask[opn_address[index] & 15];
291 //                                      }
292                                 } else
293 # endif
294                                 {
295                                         val = opn[index]->read_io8(1);
296                                 }
297                         }
298                         break;
299                 case 2: // Write address
300                         val = opn_data[index];
301                         break;
302                 case 3: // Write to reg
303                         val = opn_data[index];
304                         break;
305 //#if !defined(_FM8)
306                 case 4: // STATUS
307                         if(index != 3) {
308                                 //opn_stat[index] = opn[index]->read_io8(0) & 0x03;
309                                 opn_stat[index] = opn[index]->read_io8(0);
310                                 val = opn_stat[index];
311                         }
312                         break;
313                 case 0x09: // Joystick
314                         if(index != 0) return 0xff;
315                         if(opn_address[0] == 0x0e) {
316                                 //return opn[0]->read_signal(SIG_YM2203_PORT_A);
317                                 return joystick->read_data8(0);
318                         }
319                         return 0x00;
320                         break;
321 //#endif
322                 default:
323                         break;
324                 }
325         
326                 return val;
327 }
328   /*
329    * $fd16?
330    */
331 void FM7_MAINIO::set_opn_cmd(int index, uint8_t cmd)
332 {
333         if((index >= 4) || (index < 0)) return;
334         if((index == 0) && (!connect_opn)) return;
335         if((index == 1) && (!connect_whg)) return;
336         if((index == 2) && (!connect_thg)) return;
337         if((index == 3) && (opn_psg_77av)) return ;
338 # if !defined(_FM77AV_VARIANTS) 
339         if(index == 3) {
340                 if(psg == NULL) return;
341         }
342 # endif
343         opn_cmdreg[index] = cmd & 0x0f;
344         if(index == 3) opn_cmdreg[index] = opn_cmdreg[index] & 0x03;
345
346         uint8_t val = opn_data[index];
347         switch(opn_cmdreg[index]) {
348                 case 0: // Inactive
349                 case 1: // Read
350                         break;
351                 case 2: // Write data
352                         write_opn_reg(index, opn_address[index], opn_data[index]);
353                         break;
354                 case 3: // Register address
355 # if !defined(_FM77AV_VARIANTS)
356                         if(index == 3) {
357                                 opn_address[index] = val & 0x0f;
358                                 if(psg != NULL) psg->write_io8(0, opn_address[index]);
359                         } else
360 # endif
361                         {
362                                 opn_address[index] = val;
363                                 if(opn[index] != NULL) opn[index]->write_io8(0, opn_address[index]);
364                         }
365                         break;
366                 default:
367                         break;
368         }
369
370         return;
371 }
372
373 uint8_t FM7_MAINIO::get_extirq_whg(void)
374 {
375         uint8_t val = 0xff;
376         if(intstat_whg && connect_whg) val &= ~0x08;
377         return val;
378 }
379
380 uint8_t FM7_MAINIO::get_extirq_thg(void)
381 {
382         uint8_t val = 0xff;
383         if(intstat_thg && connect_thg) val &= ~0x08;
384         return val;
385 }
386
387
388 void FM7_MAINIO::set_beep(uint32_t data) // fd03
389 {
390         bool flag = ((data & 0xc0) != 0);
391         pcm1bit->write_signal(SIG_PCM1BIT_MUTE, ~data, 0x01);
392 #if 0   
393         if(flag != beep_flag) {
394                 if(flag) {
395                         beep_snd = true;
396                         pcm1bit->write_signal(SIG_PCM1BIT_SIGNAL, 1, 1);
397                         pcm1bit->write_signal(SIG_PCM1BIT_ON, 1, 1);
398                 } else {
399                         beep_snd = false;
400                         pcm1bit->write_signal(SIG_PCM1BIT_SIGNAL, 0, 1);
401                         pcm1bit->write_signal(SIG_PCM1BIT_ON, 0, 1);
402                 }
403                 beep_flag = flag;
404         }
405 #else
406         if(flag != beep_flag) {
407                 beep_snd = flag;
408                 beep_flag = flag;
409                 pcm1bit->write_signal(SIG_PCM1BIT_SIGNAL, data, 0xc0);
410                 pcm1bit->write_signal(SIG_PCM1BIT_ON, data, 0xc0);
411         }
412 #endif
413         if((data & 0x40) != 0) {
414                 // BEEP ON, after 205ms, BEEP OFF.  
415                 set_beep_oneshot();
416         }
417 }
418
419 // SIGNAL / FM7_MAINIO_BEEP
420 void FM7_MAINIO::set_beep_oneshot(void) // SUB:D4xx
421 {
422         beep_snd = true;
423         beep_flag = true;
424         pcm1bit->write_signal(SIG_PCM1BIT_ON, 1, 1);
425         if(event_beep_oneshot >= 0) cancel_event(this, event_beep_oneshot);
426         register_event(this, EVENT_BEEP_OFF, 205.0 * 1000.0, false, &event_beep_oneshot); // NEXT CYCLE
427         //if(event_beep <= -1) {
428         //      register_event(this, EVENT_BEEP_CYCLE, (1000.0 * 1000.0) / (1200.0 * 2.0), true, &event_beep);
429         //}             
430 }
431
432 // EVENT_BEEP_OFF
433 void FM7_MAINIO::event_beep_off(void)
434 {
435         beep_flag = false;
436         beep_snd = false;
437         pcm1bit->write_signal(SIG_PCM1BIT_ON, 0, 1);
438         event_beep_oneshot = -1;
439 }
440
441 // EVENT_BEEP_CYCLE
442 void FM7_MAINIO::event_beep_cycle(void)
443 {
444         beep_snd = !beep_snd;
445         if(beep_flag) {
446                 pcm1bit->write_signal(SIG_PCM1BIT_SIGNAL, beep_snd ? 1 : 0, 1);
447         }
448 }
449
450 bool FM7_MAINIO::load_state_opn(FILEIO *state_fio, bool loading)
451 {
452         state_fio->StateValue(connect_opn);
453         state_fio->StateValue(connect_whg);
454         state_fio->StateValue(connect_thg);
455
456         state_fio->StateValue(opn_psg_77av);
457         state_fio->StateArray(opn_address, sizeof(opn_address), 1);
458         state_fio->StateArray(opn_data, sizeof(opn_data), 1);
459         state_fio->StateArray(opn_stat, sizeof(opn_stat), 1);
460         state_fio->StateArray(opn_cmdreg, sizeof(opn_cmdreg), 1);
461         state_fio->StateArray(opn_prescaler_type, sizeof(opn_prescaler_type), 1);
462         state_fio->StateArray(&opn_regs[0][0], sizeof(opn_regs), 1);
463
464         return true;
465 }
466
467 }