Mercurial > repos > blastem
comparison ym2612.c @ 362:b7c3facee762
YM2612 WIP update
author | Mike Pavone <pavone@retrodev.com> |
---|---|
date | Mon, 27 May 2013 22:19:11 -0700 |
parents | cc39629e8d06 |
children | 62177cc39049 |
comparison
equal
deleted
inserted
replaced
361:946ae3749260 | 362:b7c3facee762 |
---|---|
4 #include "ym2612.h" | 4 #include "ym2612.h" |
5 | 5 |
6 #define BUSY_CYCLES 17 | 6 #define BUSY_CYCLES 17 |
7 #define TIMERA_UPDATE_PERIOD 144 | 7 #define TIMERA_UPDATE_PERIOD 144 |
8 | 8 |
9 #define REG_TIMERA_HIGH 0x03 // 0x24 | 9 enum { |
10 #define REG_TIMERA_LOW 0x04 // 0x25 | 10 REG_TIMERA_HIGH = 0x24, |
11 #define REG_TIMERB 0x05 // 0x26 | 11 REG_TIMERA_LOW, |
12 #define REG_TIME_CTRL 0x06 // 0x27 | 12 REG_TIMERB, |
13 #define REG_DAC 0x0A // 0x2A | 13 REG_TIME_CTRL, |
14 #define REG_DAC_ENABLE 0x0B // 0x2B | 14 REG_KEY_ONOFF, |
15 | 15 REG_DAC = 0x2A, |
16 //offset to add to "shared" regs when looking for them in Part I | 16 REG_DAC_ENABLE, |
17 #define REG_SHARED 0x10 | 17 |
18 | 18 REG_DETUNE_MULT = 0x30, |
19 | 19 REG_TOTAL_LEVEL = 0x40, |
20 #define REG_ALG_FEEDBACK (0xB0-0x30) | 20 REG_ATTACK_KS = 0x50, |
21 #define REG_ATTACK_KS (0x50-0x30) | 21 REG_DECAY_AM = 0x60, |
22 #define REG_DECAY_AM (0x60-0x30) | 22 REG_SUSTAIN_RATE = 0x70, |
23 #define REG_SUSTAIN_RATE (0x70-0x30) | 23 REG_S_LVL_R_RATE = 0x80, |
24 | 24 |
25 REG_FNUM_LOW = 0xA0, | |
26 REG_BLOCK_FNUM_H = 0xA4, | |
27 REG_FNUM_LOW_CH3 = 0xA8, | |
28 REG_BLOCK_FN_CH3 = 0xAC, | |
29 REG_ALG_FEEDBACK = 0xB0, | |
30 REG_LR_AMS_PMS = 0xB4 | |
31 }; | |
25 | 32 |
26 #define BIT_TIMERA_ENABLE 0x1 | 33 #define BIT_TIMERA_ENABLE 0x1 |
27 #define BIT_TIMERB_ENABLE 0x2 | 34 #define BIT_TIMERB_ENABLE 0x2 |
28 #define BIT_TIMERA_OVEREN 0x4 | 35 #define BIT_TIMERA_OVEREN 0x4 |
29 #define BIT_TIMERB_OVEREN 0x8 | 36 #define BIT_TIMERB_OVEREN 0x8 |
50 //According to Nemesis, real hardware only uses a 256 entry table for the fractional part | 57 //According to Nemesis, real hardware only uses a 256 entry table for the fractional part |
51 //and uses the whole part as a shift amount. | 58 //and uses the whole part as a shift amount. |
52 #define POW_TABLE_SIZE (1 << 13) | 59 #define POW_TABLE_SIZE (1 << 13) |
53 uint16_t pow_table[POW_TABLE_SIZE]; | 60 uint16_t pow_table[POW_TABLE_SIZE]; |
54 | 61 |
62 uint16_t rate_table_base[] = { | |
63 //main portion | |
64 0,1,0,1,0,1,0,1, | |
65 0,1,0,1,1,1,0,1, | |
66 0,1,1,1,0,1,1,1, | |
67 0,1,1,1,1,1,1,1, | |
68 //top end | |
69 1,1,1,1,1,1,1,1, | |
70 1,1,1,2,1,1,1,2, | |
71 1,2,1,2,1,2,1,2, | |
72 1,2,2,2,1,2,2,2, | |
73 }; | |
74 | |
75 uint16_t rate_table[64]; | |
76 | |
77 #define MAX_ENVELOPE 0xFFC | |
78 | |
55 | 79 |
56 uint16_t round_fixed_point(double value, int dec_bits) | 80 uint16_t round_fixed_point(double value, int dec_bits) |
57 { | 81 { |
58 return value * (1 << dec_bits) + 0.5; | 82 return value * (1 << dec_bits) + 0.5; |
59 } | 83 } |
60 | 84 |
61 void ym_init(ym2612_context * context) | 85 void ym_init(ym2612_context * context) |
62 { | 86 { |
63 memset(context, 0, sizeof(*context)); | 87 memset(context, 0, sizeof(*context)); |
88 for (int i = 0; i < NUM_OPERATORS; i++) { | |
89 context->operators[i].envelope = MAX_ENVELOPE; | |
90 context->operators[i].env_phase = PHASE_RELEASE; | |
91 } | |
64 if (!did_tbl_init) { | 92 if (!did_tbl_init) { |
65 //populate sine table | 93 //populate sine table |
66 for (int32_t i = 0; i < 512; i++) { | 94 for (int32_t i = 0; i < 512; i++) { |
67 double sine = sin( ((double)(i*2+1) / SINE_TABLE_SIZE) * M_PI_2 ); | 95 double sine = sin( ((double)(i*2+1) / SINE_TABLE_SIZE) * M_PI_2 ); |
68 | 96 |
79 } else { | 107 } else { |
80 tmp >>= shift; | 108 tmp >>= shift; |
81 } | 109 } |
82 pow_table[i] = tmp; | 110 pow_table[i] = tmp; |
83 } | 111 } |
112 //populate envelope generator rate table, from small base table | |
113 for (int rate = 0; rate < 64; rate++) { | |
114 for (int cycle = 0; cycle < 7; cycle++) { | |
115 uint16_t value; | |
116 if (rate < 3) { | |
117 value = 0; | |
118 } else if (value >= 60) { | |
119 value = 8; | |
120 } else if (value < 8) { | |
121 value = rate_table_base[((rate & 6) == 6 ? 16 : 8) + cycle]; | |
122 } else if (value < 48) { | |
123 value = rate_table_base[(rate & 0x3) * 8 + cycle]; | |
124 } else { | |
125 value = rate_table_base[32 + (rate & 0x3) * 8 + cycle] << (rate >> 2); | |
126 } | |
127 } | |
128 } | |
84 } | 129 } |
85 } | 130 } |
86 | 131 |
87 void ym_run(ym2612_context * context, uint32_t to_cycle) | 132 void ym_run(ym2612_context * context, uint32_t to_cycle) |
88 { | 133 { |
134 //printf("Running YM2612 from cycle %d to cycle %d\n", context->current_cycle, to_cycle); | |
135 //TODO: Fix channel update order OR remap channels in register write | |
89 for (; context->current_cycle < to_cycle; context->current_cycle += 6) { | 136 for (; context->current_cycle < to_cycle; context->current_cycle += 6) { |
90 uint32_t update_cyc = context->current_cycle % 144; | 137 uint32_t update_cyc = context->current_cycle % 144; |
91 //Update timers at beginning of 144 cycle period | 138 //Update timers at beginning of 144 cycle period |
92 if (!update_cyc && context->part1_regs[REG_TIME_CTRL] & BIT_TIMERA_ENABLE) { | 139 if (!update_cyc && context->timer_control & BIT_TIMERA_ENABLE) { |
93 if (context->timer_a) { | 140 if (context->timer_a) { |
94 context->timer_a--; | 141 context->timer_a--; |
95 } else { | 142 } else { |
96 if (context->part1_regs[REG_TIME_CTRL] & BIT_TIMERA_OVEREN) { | 143 if (context->timer_control & BIT_TIMERA_OVEREN) { |
97 context->status |= BIT_STATUS_TIMERA; | 144 context->status |= BIT_STATUS_TIMERA; |
98 } | 145 } |
99 context->timer_a = (context->part1_regs[REG_TIMERA_HIGH] << 2) | (context->part1_regs[REG_TIMERA_LOW] & 0x3); | 146 context->timer_a = context->timer_a_load; |
100 } | 147 } |
101 if (context->part1_regs[REG_TIME_CTRL] & BIT_TIMERB_ENABLE) { | 148 if (context->timer_control & BIT_TIMERB_ENABLE) { |
102 uint32_t b_cyc = (context->current_cycle / 144) % 16; | 149 uint32_t b_cyc = (context->current_cycle / 144) % 16; |
103 if (!b_cyc) { | 150 if (!b_cyc) { |
104 if (context->timer_b) { | 151 if (context->timer_b) { |
105 context->timer_b--; | 152 context->timer_b--; |
106 } else { | 153 } else { |
107 if (context->part1_regs[REG_TIME_CTRL] & BIT_TIMERB_OVEREN) { | 154 if (context->timer_control & BIT_TIMERB_OVEREN) { |
108 context->status |= BIT_STATUS_TIMERB; | 155 context->status |= BIT_STATUS_TIMERB; |
109 } | 156 } |
110 context->timer_b = context->part1_regs[REG_TIMERB]; | 157 context->timer_b = context->timer_b_load; |
111 } | 158 } |
112 } | 159 } |
113 } | 160 } |
114 } | 161 } |
115 //Update Envelope Generator | 162 //Update Envelope Generator |
116 if (update_cyc == 0 || update_cyc == 72) { | 163 if (update_cyc == 0 || update_cyc == 72) { |
117 uint32_t env_cyc = context->current_cycle / 72; | 164 uint32_t env_cyc = context->current_cycle / 72; |
118 uint32_t op = env_cyc % 24; | 165 uint32_t op = env_cyc % 24; |
119 env_cyc /= 24; | 166 env_cyc /= 24; |
167 ym_operator * operator = context->operators + op; | |
168 ym_channel * channel = context->channels + op/4; | |
120 uint8_t rate; | 169 uint8_t rate; |
121 switch(context->env_phase[op]) | 170 for(;;) { |
122 { | 171 rate = operator->rates[operator->env_phase]; |
123 case PHASE_ATTACK: | 172 if (rate) { |
124 rate = (op < 3 ? context->part1_regs[REG_SHARED + REG_ATTACK_KS + op] : context->part2_regs[REG_ATTACK_KS + op - 3]) & 0x1F; | 173 uint8_t ks = channel->keycode >> operator->key_scaling;; |
125 break; | 174 rate = rate*2 + ks; |
126 case PHASE_DECAY: | 175 if (rate > 63) { |
127 rate = (op < 3 ? context->part1_regs[REG_SHARED + REG_DECAY_AM + op] : context->part2_regs[REG_DECAY_AM + op - 3]) & 0x1F; | 176 rate = 63; |
128 break; | 177 } |
129 case PHASE_SUSTAIN: | 178 } |
130 rate = (op < 3 ? context->part1_regs[REG_SHARED + REG_SUSTAIN_RATE + op] : context->part2_regs[REG_SUSTAIN_RATE + op - 3]) & 0x1F; | 179 //Deal with "infinite" rates |
131 break; | 180 //It's possible this should be handled in key-on as well |
132 case PHASE_RELEASE: | 181 if (rate == 63 && operator->env_phase < PHASE_SUSTAIN) { |
133 rate = (op < 3 ? context->part1_regs[REG_SHARED + REG_DECAY_AM + op] : context->part2_regs[REG_DECAY_AM + op - 3]) << 1 & 0x1E | 1; | 182 if (operator->env_phase == PHASE_ATTACK) { |
134 break; | 183 operator->env_phase = PHASE_DECAY; |
135 } | 184 operator->envelope = operator->total_level; |
136 if (rate) { | 185 } else { |
137 //apply key scaling | 186 operator->env_phase = PHASE_SUSTAIN; |
138 uint8_t shift = (op < 3 ? | 187 operator->envelope = operator->sustain_level; |
139 context->part1_regs[REG_SHARED + REG_ATTACK_KS + op] : | 188 } |
140 context->part2_regs[REG_ATTACK_KS + op - 3] | 189 } else { |
141 ) >> 6; | 190 break; |
142 uint8_t ks = context->keycode[op] >> (3 - shift); | 191 } |
143 rate = rate*2 + ks; | 192 } |
144 if (rate > 63) { | 193 uint32_t cycle_shift = rate < 0x30 ? ((0x2F - rate) >> 2) : 0; |
145 rate = 63; | 194 if (!(env_cyc & ((1 << cycle_shift) - 1))) { |
146 } | 195 uint32_t update_cycle = env_cyc >> cycle_shift & 0x7; |
147 } | 196 //envelope value is 10-bits, but it will be used as a 4.8 value |
148 } | 197 uint16_t envelope_inc = rate_table[rate * 8 + update_cycle] << 2; |
198 if (operator->env_phase == PHASE_ATTACK) { | |
199 //this can probably be optimized to a single shift rather than a multiply + shift | |
200 operator->envelope += (~operator->envelope * envelope_inc) >> 4; | |
201 operator->envelope &= MAX_ENVELOPE; | |
202 if (operator->envelope <= operator->total_level) { | |
203 operator->envelope = operator->total_level; | |
204 operator->env_phase = PHASE_DECAY; | |
205 } | |
206 } else { | |
207 operator->envelope += envelope_inc; | |
208 //clamp to max attenuation value | |
209 if (operator->envelope > MAX_ENVELOPE) { | |
210 operator->envelope = MAX_ENVELOPE; | |
211 } | |
212 if (operator->env_phase == PHASE_DECAY && operator->envelope >= operator->sustain_level) { | |
213 operator->envelope = operator->sustain_level; | |
214 operator->env_phase = PHASE_SUSTAIN; | |
215 } | |
216 } | |
217 | |
218 | |
219 } | |
220 } | |
221 | |
149 //Update Phase Generator | 222 //Update Phase Generator |
150 uint32_t channel = update_cyc / 24; | 223 uint32_t channel = update_cyc / 24; |
151 if (channel != 6 || !(context->part1_regs[REG_DAC_ENABLE] & 0x80)) { | 224 if (channel != 5 || !context->dac_enable) { |
152 uint32_t op = (update_cyc) / 6; | 225 uint32_t op = (update_cyc) / 6; |
153 uint8_t alg; | 226 //printf("updating operator %d of channel %d\n", op, channel); |
154 if (op < 3) { | 227 ym_operator * operator = context->operators + op; |
155 alg = context->part1_regs[REG_SHARED + REG_ALG_FEEDBACK + op] & 0x7; | 228 ym_channel * chan = context->channels + channel; |
156 } else { | 229 //TODO: Modulate phase by LFO if necessary |
157 alg = context->part2_regs[REG_ALG_FEEDBACK + op-3] & 0x7; | 230 operator->phase_counter += operator->phase_inc; |
158 } | 231 uint16_t phase = operator->phase_counter >> 10 & 0x3FF; |
159 context->phase_counter[op] += context->phase_inc[op]; | 232 switch (op % 4) |
160 uint16_t phase = context->phase_counter[op] >> 10 & 0x3FF; | 233 { |
161 //TODO: Modulate phase if necessary | 234 case 0://Operator 1 |
162 uint16_t output = pow_table[sine_table[phase & 0x1FF] + context->envelope[op]]; | 235 //TODO: Feedback |
236 break; | |
237 case 1://Operator 3 | |
238 switch(chan->algorithm) | |
239 { | |
240 case 0: | |
241 case 2: | |
242 //modulate by operator 2 | |
243 phase += context->operators[op+1].output >> 4; | |
244 break; | |
245 case 1: | |
246 //modulate by operator 1+2 | |
247 phase += (context->operators[op-1].output + context->operators[op+1].output) >> 4; | |
248 break; | |
249 case 5: | |
250 //modulate by operator 1 | |
251 phase += context->operators[op-1].output >> 4; | |
252 } | |
253 break; | |
254 case 2://Operator 2 | |
255 if (chan->algorithm != 1 && chan->algorithm != 2 || chan->algorithm != 7) { | |
256 //modulate by Operator 1 | |
257 phase += context->operators[op-2].output >> 4; | |
258 } | |
259 break; | |
260 case 3://Operator 4 | |
261 switch(chan->algorithm) | |
262 { | |
263 case 0: | |
264 case 1: | |
265 case 4: | |
266 //modulate by operator 3 | |
267 phase += context->operators[op-2].output >> 4; | |
268 break; | |
269 case 2: | |
270 //modulate by operator 1+3 | |
271 phase += (context->operators[op-3].output + context->operators[op-2].output) >> 4; | |
272 break; | |
273 case 3: | |
274 //modulate by operator 2+3 | |
275 phase += (context->operators[op-1].output + context->operators[op-2].output) >> 4; | |
276 break; | |
277 case 5: | |
278 //modulate by operator 1 | |
279 phase += context->operators[op-3].output >> 4; | |
280 break; | |
281 } | |
282 break; | |
283 } | |
284 //printf("sine_table[%X] + %X = %X, sizeof(pow_table)/sizeof(*pow_table) = %X\n", phase & 0x1FF, operator->envelope, sine_table[phase & 0x1FF] + operator->envelope, sizeof(pow_table)/ sizeof(*pow_table)); | |
285 uint16_t output = pow_table[sine_table[phase & 0x1FF] + operator->envelope]; | |
163 if (phase & 0x200) { | 286 if (phase & 0x200) { |
164 output = -output; | 287 output = -output; |
165 } | 288 } |
166 context->op_out[op] = output; | 289 operator->output = output; |
167 //Update the channel output if we've updated all operators | 290 //Update the channel output if we've updated all operators |
168 if (op % 4 == 3) { | 291 if (op % 4 == 3) { |
169 if (alg < 4) { | 292 if (chan->algorithm < 4) { |
170 context->channel_out[channel] = context->op_out[channel * 4 + 3]; | 293 chan->output = operator->output; |
171 } else if(alg == 4) { | 294 } else if(chan->algorithm == 4) { |
172 context->channel_out[channel] = context->op_out[channel * 4 + 3] + context->op_out[channel * 4 + 1]; | 295 chan->output = operator->output + context->operators[channel * 4 + 1].output; |
173 } else { | 296 } else { |
174 output = 0; | 297 output = 0; |
175 for (uint32_t op = ((alg == 7) ? 0 : 1) + channel*4; op < (channel+1)*4; op++) { | 298 for (uint32_t op = ((chan->algorithm == 7) ? 0 : 1) + channel*4; op < (channel+1)*4; op++) { |
176 output += context->op_out[op]; | 299 output += context->operators[op].output; |
177 } | 300 } |
178 context->channel_out[channel] = output; | 301 chan->output = output; |
179 } | 302 } |
180 } | 303 } |
181 } | 304 //puts("operator update done"); |
182 | 305 } |
183 } | 306 } |
184 if (context->current_cycle >= context->write_cycle + BUSY_CYCLES) { | 307 if (context->current_cycle >= context->write_cycle + BUSY_CYCLES) { |
185 context->status &= 0x7F; | 308 context->status &= 0x7F; |
186 } | 309 } |
310 //printf("Done running YM2612 at cycle %d\n", context->current_cycle, to_cycle); | |
187 } | 311 } |
188 | 312 |
189 void ym_address_write_part1(ym2612_context * context, uint8_t address) | 313 void ym_address_write_part1(ym2612_context * context, uint8_t address) |
190 { | 314 { |
191 if (address >= 0x21 && address < 0xB7) { | 315 context->selected_reg = address; |
192 context->selected_reg = context->part1_regs + address - 0x21; | 316 context->selected_part = 0; |
317 } | |
318 | |
319 void ym_address_write_part2(ym2612_context * context, uint8_t address) | |
320 { | |
321 context->selected_reg = address; | |
322 context->selected_part = 1; | |
323 } | |
324 | |
325 uint8_t fnum_to_keycode[] = { | |
326 //F11 = 0 | |
327 0,0,0,0,0,0,0,1, | |
328 //F11 = 1 | |
329 2,3,3,3,3,3,3,3 | |
330 }; | |
331 | |
332 //table courtesy of Nemesis | |
333 uint32_t detune_table[][4] = { | |
334 {0, 0, 1, 2}, //0 (0x00) | |
335 {0, 0, 1, 2}, //1 (0x01) | |
336 {0, 0, 1, 2}, //2 (0x02) | |
337 {0, 0, 1, 2}, //3 (0x03) | |
338 {0, 1, 2, 2}, //4 (0x04) | |
339 {0, 1, 2, 3}, //5 (0x05) | |
340 {0, 1, 2, 3}, //6 (0x06) | |
341 {0, 1, 2, 3}, //7 (0x07) | |
342 {0, 1, 2, 4}, //8 (0x08) | |
343 {0, 1, 3, 4}, //9 (0x09) | |
344 {0, 1, 3, 4}, //10 (0x0A) | |
345 {0, 1, 3, 5}, //11 (0x0B) | |
346 {0, 2, 4, 5}, //12 (0x0C) | |
347 {0, 2, 4, 6}, //13 (0x0D) | |
348 {0, 2, 4, 6}, //14 (0x0E) | |
349 {0, 2, 5, 7}, //15 (0x0F) | |
350 {0, 2, 5, 8}, //16 (0x10) | |
351 {0, 3, 6, 8}, //17 (0x11) | |
352 {0, 3, 6, 9}, //18 (0x12) | |
353 {0, 3, 7,10}, //19 (0x13) | |
354 {0, 4, 8,11}, //20 (0x14) | |
355 {0, 4, 8,12}, //21 (0x15) | |
356 {0, 4, 9,13}, //22 (0x16) | |
357 {0, 5,10,14}, //23 (0x17) | |
358 {0, 5,11,16}, //24 (0x18) | |
359 {0, 6,12,17}, //25 (0x19) | |
360 {0, 6,13,19}, //26 (0x1A) | |
361 {0, 7,14,20}, //27 (0x1B) | |
362 {0, 8,16,22}, //28 (0x1C) | |
363 {0, 8,16,22}, //29 (0x1D) | |
364 {0, 8,16,22}, //30 (0x1E) | |
365 {0, 8,16,22} | |
366 }; //31 (0x1F) | |
367 | |
368 void ym_update_phase_inc(ym2612_context * context, ym_operator * operator, uint32_t op) | |
369 { | |
370 uint32_t chan_num = op / 4; | |
371 //printf("ym_update_phase_inc | channel: %d, op: %d\n", chan_num, op); | |
372 //base frequency | |
373 ym_channel * channel = context->channels + chan_num; | |
374 uint32_t inc = channel->fnum; | |
375 if (!channel->block) { | |
376 inc >> 1; | |
193 } else { | 377 } else { |
194 context->selected_reg = NULL; | 378 inc << (channel->block-1); |
195 } | 379 } |
196 } | 380 //detune |
197 | 381 uint32_t detune = detune_table[channel->keycode][operator->detune & 0x3]; |
198 void ym_address_write_part2(ym2612_context * context, uint8_t address) | 382 if (operator->detune & 0x40) { |
199 { | 383 inc -= detune; |
200 if (address >= 0x30 && address < 0xB7) { | 384 //this can underflow, mask to 17-bit result |
201 context->selected_reg = context->part1_regs + address - 0x30; | 385 inc &= 0x1FFFF; |
202 } else { | 386 } else { |
203 context->selected_reg = NULL; | 387 inc += detune; |
388 } | |
389 //multiple | |
390 if (operator->multiple) { | |
391 inc *= operator->multiple; | |
392 } else { | |
393 //0.5 | |
394 inc >>= 1; | |
204 } | 395 } |
205 } | 396 } |
206 | 397 |
207 void ym_data_write(ym2612_context * context, uint8_t value) | 398 void ym_data_write(ym2612_context * context, uint8_t value) |
208 { | 399 { |
209 if (context->selected_reg && !(context->status & 0x80)) { | 400 if (context->selected_reg < 0x21 || context->selected_reg > 0xB6 || (context->selected_reg < 0x30 && context->selected_part)) { |
210 *context->selected_reg = value; | 401 return; |
211 context->write_cycle = context->current_cycle; | 402 } |
212 context->selected_reg = NULL;//TODO: Verify this | 403 //printf("write to reg %X in part %d\n", context->selected_reg, context->selected_part+1); |
213 } | 404 if (context->selected_reg < 0x30) { |
405 //Shared regs | |
406 switch (context->selected_reg) | |
407 { | |
408 //TODO: Test reg and LFO | |
409 case REG_TIMERA_HIGH: | |
410 context->timer_a_load &= 0x3; | |
411 context->timer_a_load |= value << 2; | |
412 break; | |
413 case REG_TIMERA_LOW: | |
414 context->timer_a_load &= 0xFFFC; | |
415 context->timer_a_load |= value & 0x3; | |
416 break; | |
417 case REG_TIMERB: | |
418 context->timer_b_load = value; | |
419 break; | |
420 case REG_TIME_CTRL: | |
421 context->timer_control = value; | |
422 break; | |
423 case REG_KEY_ONOFF: { | |
424 uint8_t channel = value & 0x7; | |
425 if (channel < NUM_CHANNELS) { | |
426 for (uint8_t op = channel * 4, bit = 0x10; op < (channel + 1) * 4; op++, bit <<= 1) { | |
427 if (value & bit) { | |
428 //printf("Key On for operator %d in channel %d\n", op, channel); | |
429 context->operators[op].phase_counter = 0; | |
430 context->operators[op].env_phase = PHASE_ATTACK; | |
431 context->operators[op].envelope = MAX_ENVELOPE; | |
432 } else { | |
433 //printf("Key Off for operator %d in channel %d\n", op, channel); | |
434 context->operators[op].env_phase = PHASE_RELEASE; | |
435 } | |
436 } | |
437 } | |
438 break; | |
439 } | |
440 case REG_DAC: | |
441 if (context->dac_enable) { | |
442 context->channels[5].output = (((int16_t)value) - 0x80) << 6; | |
443 } | |
444 break; | |
445 case REG_DAC_ENABLE: | |
446 context->dac_enable = value & 0x80; | |
447 break; | |
448 } | |
449 } else if (context->selected_reg < 0xA0) { | |
450 //part | |
451 uint8_t op = context->selected_part ? (NUM_OPERATORS/2) : 0; | |
452 //channel in part | |
453 if ((context->selected_reg & 0x3) != 0x3) { | |
454 op += 4 * (context->selected_reg & 0x3); | |
455 //operator in channel | |
456 switch (context->selected_reg & 0xC) | |
457 { | |
458 case 0: | |
459 break; | |
460 case 4: | |
461 op += 2; | |
462 break; | |
463 case 8: | |
464 op += 1; | |
465 break; | |
466 case 0xC: | |
467 op += 3; | |
468 break; | |
469 } | |
470 //printf("write targets operator %d (%d of channel %d)\n", op, op % 4, op / 4); | |
471 ym_operator * operator = context->operators + op; | |
472 switch (context->selected_reg & 0xF0) | |
473 { | |
474 case REG_DETUNE_MULT: | |
475 operator->detune = value >> 4 & 0x7; | |
476 operator->multiple = value & 0xF; | |
477 ym_update_phase_inc(context, operator, op); | |
478 break; | |
479 case REG_TOTAL_LEVEL: | |
480 operator->total_level = (value & 0x7F) << 5; | |
481 break; | |
482 case REG_ATTACK_KS: | |
483 operator->key_scaling = value >> 6; | |
484 operator->rates[PHASE_ATTACK] = value & 0x1F; | |
485 break; | |
486 case REG_DECAY_AM: | |
487 //TODO: AM flag for LFO | |
488 operator->rates[PHASE_DECAY] = value & 0x1F; | |
489 break; | |
490 case REG_SUSTAIN_RATE: | |
491 operator->rates[PHASE_SUSTAIN] = value & 0x1F; | |
492 break; | |
493 case REG_S_LVL_R_RATE: | |
494 operator->rates[PHASE_RELEASE] = (value & 0xF) << 1 | 1; | |
495 operator->sustain_level = value & 0xF0 << 4; | |
496 break; | |
497 } | |
498 } | |
499 } else { | |
500 uint8_t channel = context->selected_reg & 0x3; | |
501 if (channel != 3) { | |
502 if (context->selected_part) { | |
503 channel += 3; | |
504 } | |
505 //printf("write targets channel %d\n", channel); | |
506 switch (context->selected_reg & 0xFC) | |
507 { | |
508 case REG_FNUM_LOW: | |
509 context->channels[channel].block = context->channels[channel].block_fnum_latch >> 3 & 0x7; | |
510 context->channels[channel].fnum = (context->channels[channel].block_fnum_latch & 0x7) << 8 | value; | |
511 context->channels[channel].keycode = context->channels[channel].block << 2 | fnum_to_keycode[context->channels[channel].fnum >> 7]; | |
512 ym_update_phase_inc(context, context->operators + channel*4, channel*4); | |
513 ym_update_phase_inc(context, context->operators + channel*4+1, channel*4+1); | |
514 ym_update_phase_inc(context, context->operators + channel*4+2, channel*4+2); | |
515 ym_update_phase_inc(context, context->operators + channel*4+3, channel*4+3); | |
516 break; | |
517 case REG_BLOCK_FNUM_H:{ | |
518 context->channels[channel].block_fnum_latch = value; | |
519 break; | |
520 } | |
521 //TODO: Channel 3 special/CSM modes | |
522 case REG_ALG_FEEDBACK: | |
523 context->channels[channel].algorithm = value & 0x7; | |
524 context->channels[channel].feedback = value >> 3 & 0x7; | |
525 break; | |
526 case REG_LR_AMS_PMS: | |
527 context->channels[channel].pms = value & 0x7; | |
528 context->channels[channel].ams = value >> 4 & 0x3; | |
529 context->channels[channel].lr = value & 0xC0; | |
530 break; | |
531 } | |
532 } | |
533 } | |
534 | |
535 context->write_cycle = context->current_cycle; | |
536 context->selected_reg = 0;//TODO: Verify this | |
214 } | 537 } |
215 | 538 |
216 uint8_t ym_read_status(ym2612_context * context) | 539 uint8_t ym_read_status(ym2612_context * context) |
217 { | 540 { |
218 return context->status; | 541 return context->status; |