comparison ymf262.c @ 2565:eb588f22ec76

More work on OPL3 emulation
author Michael Pavone <pavone@retrodev.com>
date Sun, 26 Jan 2025 23:32:40 -0800
parents 3f58fec775df
children
comparison
equal deleted inserted replaced
2564:553a0b4888db 2565:eb588f22ec76
54 { 54 {
55 context->selected_reg = address; 55 context->selected_reg = address;
56 context->selected_part = 0; 56 context->selected_part = 0;
57 } 57 }
58 58
59 static void ymf262_update_connections(ymf262_context *context, uint8_t channel, uint8_t csel_bit)
60 {
61 uint8_t channel_off = channel >= 9 ? channel - 9 : channel;
62 uint8_t op = channel_off;
63 if (op > 5) {
64 op += 6;
65 } else if (op > 2) {
66 op += 3;
67 }
68 if (channel >= 9) {
69 op += 18;
70 }
71 if (context->opl3_mode && channel_off < 6 && (context->connection_sel & csel_bit)) {
72 if (channel_off > 2) {
73 channel -= 3;
74 op -= 6;
75 }
76 uint8_t alg = (context->channels[channel].algorithm & 1) << 1;
77 alg |= context->channels[channel + 3].algorithm & 1;
78 switch (alg)
79 {
80 case 0:
81 context->operators[op + 3].mod_src[0] = &context->operators[op].output;
82 context->operators[op + 6].mod_src[0] = &context->operators[op + 3].output;
83 context->operators[op + 9].mod_src[0] = &context->operators[op + 6].output;
84 break;
85 case 1:
86 context->operators[op + 3].mod_src[0] = &context->operators[op].output;
87 context->operators[op + 6].mod_src[0] = NULL;
88 context->operators[op + 9].mod_src[0] = &context->operators[op + 6].output;
89 break;
90 case 2:
91 context->operators[op + 3].mod_src[0] = NULL;
92 context->operators[op + 6].mod_src[0] = &context->operators[op + 3].output;
93 context->operators[op + 9].mod_src[0] = &context->operators[op + 6].output;
94 break;
95 case 3:
96 context->operators[op + 3].mod_src[0] = NULL;
97 context->operators[op + 6].mod_src[0] = &context->operators[op + 3].output;
98 context->operators[op + 9].mod_src[0] = NULL;
99 break;
100 }
101 } else {
102 context->operators[op].mod_src[0] = NULL;
103 context->operators[op + 3].mod_src[0] = context->channels[channel].algorithm ? NULL : &context->operators[op].output;
104 }
105 }
106
107 void ymf262_calc_phase_inc(ymf262_context *context, ym_channel *channel, ym_operator *operator)
108 {
109 int32_t inc = channel->fnum;
110 //TODO: vibrato?
111 if (!channel->block) {
112 inc >>= 1;
113 } else {
114 inc <<= (channel->block-1);
115 }
116 if (operator->multiple) {
117 inc *= operator->multiple;
118 inc &= 0xFFFFF;
119 } else {
120 //0.5
121 inc >>= 1;
122 }
123 operator->phase_inc = inc;
124 }
125
59 #define OPL3_NTS 0x08 126 #define OPL3_NTS 0x08
60 127
61 void ymf262_data_write(ymf262_context *context, uint8_t value) 128 void ymf262_data_write(ymf262_context *context, uint8_t value)
62 { 129 {
63 if (!context->selected_reg) { 130 if (!context->selected_reg) {
64 return; 131 return;
65 } 132 }
66 uint8_t old = 0; 133 uint8_t old = 0;
67 if (context->selected_reg >= OPL3_PARAM_START && context->selected_reg < OPL3_PARAM_END) { 134 if (context->selected_reg >= OPL3_PARAM_START && context->selected_reg < OPL3_PARAM_END) {
135 uint8_t channel, op;
68 if (context->selected_part) { 136 if (context->selected_part) {
69 old = context->part2_regs[context->selected_reg - OPL3_PARAM_START]; 137 old = context->part2_regs[context->selected_reg - OPL3_PARAM_START];
70 context->part2_regs[context->selected_reg - OPL3_PARAM_START] = value; 138 context->part2_regs[context->selected_reg - OPL3_PARAM_START] = value;
139 channel = 9;
140 op = 18;
71 } else { 141 } else {
72 old = context->part1_regs[context->selected_reg - OPL3_PARAM_START]; 142 old = context->part1_regs[context->selected_reg - OPL3_PARAM_START];
73 context->part1_regs[context->selected_reg - OPL3_PARAM_START] = value; 143 context->part1_regs[context->selected_reg - OPL3_PARAM_START] = value;
144 channel = 0;
145 op = 0;
146 }
147 if (context->selected_reg < 0xA0 || context->selected_reg >= 0xE0) {
148 uint8_t op_off = context->selected_reg & 0x1F;
149 if ((op_off >= 0x26 && op_off < 0x28) || (op_off >= 0x2E && op_off < 0x30) || op_off > 0x35) {
150 return;
151 }
152 if (op_off >= 0x30) {
153 op_off -= 4;
154 } else if (op_off >= 0x28) {
155 op_off -= 2;
156 }
157 op += op_off;
158 ym_operator *operator = context->operators + op;
159 switch (context->selected_reg & 0xE0)
160 {
161 case 0x20:
162 operator->multiple = value & 0xF;
163 operator->rates[PHASE_SUSTAIN] = (value & 0x20) ? 0 : operator->rates[PHASE_RELEASE];
164 operator->am = value & 0x80;
165 //TODO: KSR,VIB
166 break;
167 case 0x40:
168 operator->total_level = (value & 0x3F) << 6;
169 //TODO: KSL
170 break;
171 case 0x60:
172 //TODO: what should the LSB be?
173 operator->rates[PHASE_ATTACK] = (value & 0xF0) >> 3 | 1;
174 operator->rates[PHASE_DECAY] = (value & 0xF) << 1 | 1;
175 break;
176 case 0x80:
177 operator->rates[PHASE_RELEASE] = (value & 0xF) << 1 | 1;
178 operator->sustain_level = (value & 0xF0) << 3;
179 if (operator->sustain_level == 0x780) {
180 operator->sustain_level = MAX_ENVELOPE;
181 }
182 if (!((context->selected_part ? context->part2_regs : context->part1_regs)[context->selected_reg - 0x60] & 0x20)) {
183 operator->rates[PHASE_SUSTAIN] = operator->rates[PHASE_RELEASE];
184 }
185 break;
186 case 0xE0:
187 operator->wave = value & (context->opl3_mode ? 0x7 : 0x3);
188 break;
189 }
190 } else {
191 uint8_t channel_off = context->selected_reg & 0xF;
192 if (channel_off > 8 && context->selected_reg != 0xBD) {
193 return;
194 }
195 uint8_t csel_bit = channel_off > 2 ? channel_off - 3 : channel_off;
196 if (channel) {
197 csel_bit += 3;
198 }
199 csel_bit = 1 << csel_bit;
200 if (context->selected_reg < 0xC0 && context->opl3_mode && (channel_off > 2 && channel_off < 6) && (context->connection_sel & csel_bit)) {
201 //ignore writes to "upper" channel in 4-op mode
202 return;
203 }
204 channel += channel_off;
205 op = channel_off;
206 if (op > 5) {
207 op += 6;
208 } else if (op > 2) {
209 op += 3;
210 }
211 ym_channel *chan = context->channels + channel;
212 switch(context->selected_reg & 0xF0)
213 {
214 case 0xA0:
215 chan->fnum &= ~0xFF;
216 chan->fnum |= value;
217 ymf262_calc_phase_inc(context, chan, context->operators + op);
218 ymf262_calc_phase_inc(context, chan, context->operators + op + 3);
219 if (context->opl3_mode && channel_off < 6 && (context->connection_sel & csel_bit)) {
220 //4-op mode
221 ymf262_calc_phase_inc(context, chan, context->operators + op + 6);
222 ymf262_calc_phase_inc(context, chan, context->operators + op + 9);
223 }
224 break;
225 case 0xB0:
226 chan->fnum &= 0xFF;
227 chan->fnum |= (value & 0x3) << 8;
228 chan->block = (value >> 2) & 7;
229 ymf262_calc_phase_inc(context, chan, context->operators + op);
230 ymf262_calc_phase_inc(context, chan, context->operators + op + 3);
231 if (context->opl3_mode && channel_off < 6 && (context->connection_sel & csel_bit)) {
232 //4-op mode
233 ymf262_calc_phase_inc(context, chan, context->operators + op + 6);
234 ymf262_calc_phase_inc(context, chan, context->operators + op + 9);
235 }
236 if ((value ^ old) & 0x20) {
237 if (value & 0x20) {
238 keyon(context->operators + op, chan);
239 keyon(context->operators + op + 3, chan);
240 if (context->opl3_mode && channel_off < 6 && (context->connection_sel & csel_bit)) {
241 //4-op mode
242 keyon(context->operators + op + 6, chan);
243 keyon(context->operators + op + 9, chan);
244 }
245 } else {
246 keyoff(context->operators + op);
247 keyoff(context->operators + op + 3);
248 if (context->opl3_mode && channel_off < 6 && (context->connection_sel & csel_bit)) {
249 //4-op mode
250 keyoff(context->operators + op + 6);
251 keyoff(context->operators + op + 9);
252 }
253 }
254 }
255 break;
256 case 0xC0:
257 chan->algorithm = value & 1;
258 chan->feedback = value >> 1 & 0x7;
259 chan->lr = value & 0xF0;
260 ymf262_update_connections(context, channel, csel_bit);
261 break;
262 }
74 } 263 }
75 } else if (context->selected_part) { 264 } else if (context->selected_part) {
76 if (context->selected_reg <= sizeof(context->timer_test)) { 265 if (context->selected_reg <= sizeof(context->timer_test)) {
77 old = context->timer_test[context->selected_reg - 1]; 266 old = context->timer_test[context->selected_reg - 1];
78 context->timer_test[context->selected_reg - 1] = value; 267 context->timer_test[context->selected_reg - 1] = value;
81 context->nts = value; 270 context->nts = value;
82 } else { 271 } else {
83 return; 272 return;
84 } 273 }
85 } else { 274 } else {
275
86 switch (context->selected_reg) 276 switch (context->selected_reg)
87 { 277 {
88 case 0x01: 278 case 0x01:
89 old = context->part2_test; 279 old = context->part2_test;
90 context->part2_test = value; 280 context->part2_test = value;
91 break; 281 break;
92 case 0x04: 282 case 0x04:
93 old = context->connection_sel; 283 old = context->connection_sel;
94 context->connection_sel = value; 284 context->connection_sel = value;
285 if (context->opl3_mode) {
286 uint8_t changes = old ^ value;
287 for (uint8_t i = 0; i < 6; i++)
288 {
289 uint8_t csel_bit = 1 << i;
290 if (changes & csel_bit) {
291 uint8_t channel = i > 2 ? i + 9 : i;
292 if (value & csel_bit) {
293 //switched to 4-op mode
294 ymf262_update_connections(context, channel, csel_bit);
295 } else {
296 //switched to 2-op mode
297 ymf262_update_connections(context, channel, csel_bit);
298 ymf262_update_connections(context, channel + 3, csel_bit);
299 }
300 }
301 }
302 }
95 break; 303 break;
96 case 0x05: 304 case 0x05:
97 old = context->opl3_mode; 305 old = context->opl3_mode;
98 context->opl3_mode = value; 306 context->opl3_mode = value;
99 break; 307 break;