1 #include "dosbox/dbopl.h"
2 #include "dosbox/nukedopl.h"
3 #include "sound_dbopl.h"
4 
5 static struct
6 {
7         DBOPL::Chip chip;
8         struct opl3_chip opl3chip;
9         int addr;
10         int timer[2];
11         uint8_t timer_ctrl;
12         uint8_t status_mask;
13         uint8_t status;
14         int is_opl3;
15         int opl_emu;
16 
17         void (*timer_callback)(void *param, int timer, int64_t period);
18         void *timer_param;
19 } opl[2];
20 
21 enum
22 {
23         STATUS_TIMER_1 = 0x40,
24         STATUS_TIMER_2 = 0x20,
25         STATUS_TIMER_ALL = 0x80
26 };
27 
28 enum
29 {
30         CTRL_IRQ_RESET   = 0x80,
31         CTRL_TIMER1_MASK = 0x40,
32         CTRL_TIMER2_MASK = 0x20,
33         CTRL_TIMER2_CTRL = 0x02,
34         CTRL_TIMER1_CTRL = 0x01
35 };
36 
opl_init(void (* timer_callback)(void * param,int timer,int64_t period),void * timer_param,int nr,int is_opl3,int opl_emu)37 void opl_init(void (*timer_callback)(void *param, int timer, int64_t period), void *timer_param, int nr, int is_opl3, int opl_emu)
38 {
39 	if (!is_opl3 || !opl_emu)
40 	{
41                 DBOPL::InitTables();
42                 opl[nr].chip.Setup(48000, is_opl3);
43                 opl[nr].timer_callback = timer_callback;
44                 opl[nr].timer_param = timer_param;
45                 opl[nr].is_opl3 = is_opl3;
46                 opl[nr].opl_emu = opl_emu;
47 	}
48 	else
49 	{
50                 OPL3_Reset(&opl[nr].opl3chip, 48000);
51                 opl[nr].timer_callback = timer_callback;
52                 opl[nr].timer_param = timer_param;
53                 opl[nr].is_opl3 = is_opl3;
54                 opl[nr].opl_emu = opl_emu;
55 	}
56 }
57 
opl_status_update(int nr)58 void opl_status_update(int nr)
59 {
60         if (opl[nr].status & (STATUS_TIMER_1 | STATUS_TIMER_2) & opl[nr].status_mask)
61                 opl[nr].status |= STATUS_TIMER_ALL;
62         else
63                 opl[nr].status &= ~STATUS_TIMER_ALL;
64 }
65 
opl_timer_over(int nr,int timer)66 void opl_timer_over(int nr, int timer)
67 {
68         if (!timer)
69         {
70                 opl[nr].status |= STATUS_TIMER_1;
71                 opl[nr].timer_callback(opl[nr].timer_param, 0, opl[nr].timer[0] * 4);
72         }
73         else
74         {
75                 opl[nr].status |= STATUS_TIMER_2;
76                 opl[nr].timer_callback(opl[nr].timer_param, 1, opl[nr].timer[1] * 16);
77         }
78 
79         opl_status_update(nr);
80 }
81 
opl_write(int nr,uint16_t addr,uint8_t val)82 void opl_write(int nr, uint16_t addr, uint8_t val)
83 {
84         if (!(addr & 1))
85 	{
86 		if (!opl[nr].is_opl3 || !opl[nr].opl_emu)
87 			opl[nr].addr = (int)opl[nr].chip.WriteAddr(addr, val) & (opl[nr].is_opl3 ? 0x1ff : 0xff);
88 		else
89 			opl[nr].addr = (int)OPL3_WriteAddr(&opl[nr].opl3chip, addr, val) & 0x1ff;
90 	}
91         else
92         {
93 		if (!opl[nr].is_opl3 || !opl[nr].opl_emu)
94 			opl[nr].chip.WriteReg(opl[nr].addr, val);
95 		else
96 			OPL3_WriteReg(&opl[nr].opl3chip, opl[nr].addr, val);
97 
98                 switch (opl[nr].addr)
99                 {
100                         case 0x02: /*Timer 1*/
101                         opl[nr].timer[0] = 256 - val;
102                         break;
103                         case 0x03: /*Timer 2*/
104                         opl[nr].timer[1] = 256 - val;
105                         break;
106                         case 0x04: /*Timer control*/
107                         if (val & CTRL_IRQ_RESET) /*IRQ reset*/
108                         {
109                                 opl[nr].status &= ~(STATUS_TIMER_1 | STATUS_TIMER_2);
110                                 opl_status_update(nr);
111                                 return;
112                         }
113                         if ((val ^ opl[nr].timer_ctrl) & CTRL_TIMER1_CTRL)
114                         {
115                                 if (val & CTRL_TIMER1_CTRL)
116                                         opl[nr].timer_callback(opl[nr].timer_param, 0, opl[nr].timer[0] * 4);
117                                 else
118                                         opl[nr].timer_callback(opl[nr].timer_param, 0, 0);
119                         }
120                         if ((val ^ opl[nr].timer_ctrl) & CTRL_TIMER2_CTRL)
121                         {
122                                 if (val & CTRL_TIMER2_CTRL)
123                                         opl[nr].timer_callback(opl[nr].timer_param, 1, opl[nr].timer[1] * 16);
124                                 else
125                                         opl[nr].timer_callback(opl[nr].timer_param, 1, 0);
126                         }
127                         opl[nr].status_mask = (~val & (CTRL_TIMER1_MASK | CTRL_TIMER2_MASK)) | 0x80;
128                         opl[nr].timer_ctrl = val;
129                         break;
130                 }
131         }
132 
133 }
134 
opl_read(int nr,uint16_t addr)135 uint8_t opl_read(int nr, uint16_t addr)
136 {
137         if (!(addr & 1))
138         {
139                 return (opl[nr].status & opl[nr].status_mask) | (opl[nr].is_opl3 ? 0 : 0x06);
140         }
141         return opl[nr].is_opl3 ? 0 : 0xff;
142 }
143 
opl2_update(int nr,int16_t * buffer,int samples)144 void opl2_update(int nr, int16_t *buffer, int samples)
145 {
146         int c;
147         Bit32s buffer_32[samples];
148 
149         opl[nr].chip.GenerateBlock2(samples, buffer_32);
150 
151         for (c = 0; c < samples; c++)
152                 buffer[c*2] = (int16_t)buffer_32[c];
153 }
154 
opl3_update(int nr,int16_t * buffer,int samples)155 void opl3_update(int nr, int16_t *buffer, int samples)
156 {
157         int c;
158         Bit32s buffer_32[samples*2];
159 
160 	if (opl[nr].opl_emu)
161 	{
162 		OPL3_GenerateStream(&opl[nr].opl3chip, buffer, samples);
163 	}
164 	else
165 	{
166 		opl[nr].chip.GenerateBlock3(samples, buffer_32);
167 
168 		for (c = 0; c < samples*2; c++)
169 			buffer[c] = (int16_t)buffer_32[c];
170 	}
171 }
172