OSDN Git Service

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