Mercurial > repos > blastem
comparison ym2612.c @ 1301:babff81e4cfd
Initial implementation of YM2612 SSG-EG mode
author | Michael Pavone <pavone@retrodev.com> |
---|---|
date | Mon, 27 Mar 2017 00:40:10 -0700 |
parents | 4b893b02444e |
children | 1b3fe6e03e7b |
comparison
equal
deleted
inserted
replaced
1300:4b893b02444e | 1301:babff81e4cfd |
---|---|
252 #define TIMER_A_MAX 1023 | 252 #define TIMER_A_MAX 1023 |
253 #define TIMER_B_MAX 255 | 253 #define TIMER_B_MAX 255 |
254 | 254 |
255 #define CSM_MODE 0x80 | 255 #define CSM_MODE 0x80 |
256 | 256 |
257 static void keyon(ym_operator *op, ym_channel *channel) | 257 #define SSG_ENABLE 8 |
258 #define SSG_INVERT 4 | |
259 #define SSG_ALTERNATE 2 | |
260 #define SSG_HOLD 1 | |
261 | |
262 #define SSG_CENTER 0x800 | |
263 | |
264 static void start_envelope(ym_operator *op, ym_channel *channel) | |
258 { | 265 { |
259 //Deal with "infinite" attack rates | 266 //Deal with "infinite" attack rates |
260 uint8_t rate = op->rates[PHASE_ATTACK]; | 267 uint8_t rate = op->rates[PHASE_ATTACK]; |
261 if (rate) { | 268 if (rate) { |
262 uint8_t ks = channel->keycode >> op->key_scaling;; | 269 uint8_t ks = channel->keycode >> op->key_scaling;; |
266 op->env_phase = PHASE_DECAY; | 273 op->env_phase = PHASE_DECAY; |
267 op->envelope = 0; | 274 op->envelope = 0; |
268 } else { | 275 } else { |
269 op->env_phase = PHASE_ATTACK; | 276 op->env_phase = PHASE_ATTACK; |
270 } | 277 } |
278 } | |
279 | |
280 static void keyon(ym_operator *op, ym_channel *channel) | |
281 { | |
282 start_envelope(op, channel); | |
271 op->phase_counter = 0; | 283 op->phase_counter = 0; |
284 op->inverted = op->ssg & SSG_INVERT; | |
272 } | 285 } |
273 | 286 |
274 static const uint8_t keyon_bits[] = {0x10, 0x40, 0x20, 0x80}; | 287 static const uint8_t keyon_bits[] = {0x10, 0x40, 0x20, 0x80}; |
288 | |
289 static void keyoff(ym_operator *op) | |
290 { | |
291 op->env_phase = PHASE_RELEASE; | |
292 if (op->inverted) { | |
293 //Nemesis says the inversion state doesn't change here, but I don't see how that is observable either way | |
294 op->inverted = 0; | |
295 op->envelope = (SSG_CENTER - op->envelope) & MAX_ENVELOPE; | |
296 } | |
297 } | |
275 | 298 |
276 static void csm_keyoff(ym2612_context *context) | 299 static void csm_keyoff(ym2612_context *context) |
277 { | 300 { |
278 context->csm_keyon = 0; | 301 context->csm_keyon = 0; |
279 uint8_t changes = 0xF0 ^ context->channels[2].keyon; | 302 uint8_t changes = 0xF0 ^ context->channels[2].keyon; |
280 for (uint8_t op = 2*4, bit = 0; op < 3*4; op++, bit++) | 303 for (uint8_t op = 2*4, bit = 0; op < 3*4; op++, bit++) |
281 { | 304 { |
282 if (changes & keyon_bits[bit]) { | 305 if (changes & keyon_bits[bit]) { |
283 context->operators[op].env_phase = PHASE_RELEASE; | 306 keyoff(context->operators + op); |
284 } | 307 } |
285 } | 308 } |
286 } | 309 } |
287 | 310 |
288 void ym_run(ym2612_context * context, uint32_t to_cycle) | 311 void ym_run(ym2612_context * context, uint32_t to_cycle) |
387 } else { | 410 } else { |
388 if (first_key_on) { | 411 if (first_key_on) { |
389 dfprintf(debug_file, "Changing op %d envelope %d by %d in %s phase\n", op, operator->envelope, envelope_inc, | 412 dfprintf(debug_file, "Changing op %d envelope %d by %d in %s phase\n", op, operator->envelope, envelope_inc, |
390 operator->env_phase == PHASE_SUSTAIN ? "sustain" : (operator->env_phase == PHASE_DECAY ? "decay": "release")); | 413 operator->env_phase == PHASE_SUSTAIN ? "sustain" : (operator->env_phase == PHASE_DECAY ? "decay": "release")); |
391 } | 414 } |
415 if (operator->ssg) { | |
416 if (operator->envelope < SSG_CENTER) { | |
417 envelope_inc *= 4; | |
418 } else { | |
419 envelope_inc = 0; | |
420 } | |
421 } | |
392 //envelope value is 10-bits, but it will be used as a 4.8 value | 422 //envelope value is 10-bits, but it will be used as a 4.8 value |
393 operator->envelope += envelope_inc << 2; | 423 operator->envelope += envelope_inc << 2; |
394 //clamp to max attenuation value | 424 //clamp to max attenuation value |
395 if (operator->envelope > MAX_ENVELOPE) { | 425 if ( |
426 operator->envelope > MAX_ENVELOPE | |
427 || (operator->env_phase == PHASE_RELEASE && operator->envelope >= SSG_CENTER) | |
428 ) { | |
396 operator->envelope = MAX_ENVELOPE; | 429 operator->envelope = MAX_ENVELOPE; |
397 } | 430 } |
398 } | 431 } |
399 } | 432 } |
400 context->current_env_op++; | 433 context->current_env_op++; |
466 mod = context->operators[op-3].output >> YM_MOD_SHIFT; | 499 mod = context->operators[op-3].output >> YM_MOD_SHIFT; |
467 break; | 500 break; |
468 } | 501 } |
469 break; | 502 break; |
470 } | 503 } |
471 uint16_t env = operator->envelope + operator->total_level; | 504 uint16_t env = operator->envelope; |
505 if (operator->ssg) { | |
506 if (env >= SSG_CENTER) { | |
507 if (operator->ssg & SSG_ALTERNATE) { | |
508 if (operator->env_phase != PHASE_RELEASE && ( | |
509 !(operator->ssg & SSG_HOLD) || ((operator->ssg ^ operator->inverted) & SSG_INVERT) == 0 | |
510 )) { | |
511 operator->inverted ^= SSG_INVERT; | |
512 } | |
513 } else if (!(operator->ssg & SSG_HOLD)) { | |
514 phase = operator->phase_counter = 0; | |
515 } | |
516 if ( | |
517 (operator->env_phase == PHASE_DECAY || operator->env_phase == PHASE_SUSTAIN) | |
518 && !(operator->ssg & SSG_HOLD) | |
519 ) { | |
520 start_envelope(operator, chan); | |
521 env = operator->envelope; | |
522 } | |
523 } | |
524 if (operator->inverted) { | |
525 env = (SSG_CENTER - env) & MAX_ENVELOPE; | |
526 } | |
527 } | |
528 env += operator->total_level; | |
472 if (operator->am) { | 529 if (operator->am) { |
473 uint16_t base_am = (context->lfo_am_step & 0x80 ? context->lfo_am_step : ~context->lfo_am_step) & 0x7E; | 530 uint16_t base_am = (context->lfo_am_step & 0x80 ? context->lfo_am_step : ~context->lfo_am_step) & 0x7E; |
474 if (ams_shift[chan->ams] >= 0) { | 531 if (ams_shift[chan->ams] >= 0) { |
475 env += base_am >> ams_shift[chan->ams]; | 532 env += base_am >> ams_shift[chan->ams]; |
476 } else { | 533 } else { |
785 first_key_on = 1; | 842 first_key_on = 1; |
786 //printf("Key On for operator %d in channel %d\n", op, channel); | 843 //printf("Key On for operator %d in channel %d\n", op, channel); |
787 keyon(context->operators + op, context->channels + channel); | 844 keyon(context->operators + op, context->channels + channel); |
788 } else { | 845 } else { |
789 //printf("Key Off for operator %d in channel %d\n", op, channel); | 846 //printf("Key Off for operator %d in channel %d\n", op, channel); |
790 context->operators[op].env_phase = PHASE_RELEASE; | 847 keyoff(context->operators + op); |
791 } | 848 } |
792 } | 849 } |
793 } | 850 } |
794 } | 851 } |
795 break; | 852 break; |
838 operator->rates[PHASE_RELEASE] = (value & 0xF) << 1 | 1; | 895 operator->rates[PHASE_RELEASE] = (value & 0xF) << 1 | 1; |
839 operator->sustain_level = (value & 0xF0) << 3; | 896 operator->sustain_level = (value & 0xF0) << 3; |
840 if (operator->sustain_level == 0x780) { | 897 if (operator->sustain_level == 0x780) { |
841 operator->sustain_level = MAX_ENVELOPE; | 898 operator->sustain_level = MAX_ENVELOPE; |
842 } | 899 } |
900 break; | |
901 case REG_SSG_EG: | |
902 if (!(value & SSG_ENABLE)) { | |
903 value = 0; | |
904 } | |
905 if ((value ^ operator->ssg) & SSG_INVERT) { | |
906 operator->inverted ^= SSG_INVERT; | |
907 } | |
908 operator->ssg = value; | |
843 break; | 909 break; |
844 } | 910 } |
845 } | 911 } |
846 } else { | 912 } else { |
847 uint8_t channel = context->selected_reg & 0x3; | 913 uint8_t channel = context->selected_reg & 0x3; |