Mercurial > repos > blastem
annotate ym2612.c @ 500:251fe7a75a14
Preserve aspect ratio unless config file says otherwise
author | Mike Pavone <pavone@retrodev.com> |
---|---|
date | Tue, 29 Oct 2013 19:09:19 -0700 |
parents | 3e1573fa22cf |
children | b7b7a1cab44a |
rev | line source |
---|---|
467
140af5509ce7
Added copyright notice to source files and added GPL license text in COPYING
Mike Pavone <pavone@retrodev.com>
parents:
451
diff
changeset
|
1 /* |
140af5509ce7
Added copyright notice to source files and added GPL license text in COPYING
Mike Pavone <pavone@retrodev.com>
parents:
451
diff
changeset
|
2 Copyright 2013 Michael Pavone |
483
3e1573fa22cf
Implement turbo/slow motion feature that overclocks or underclocks the entire system at the push of a button
Mike Pavone <pavone@retrodev.com>
parents:
467
diff
changeset
|
3 This file is part of BlastEm. |
467
140af5509ce7
Added copyright notice to source files and added GPL license text in COPYING
Mike Pavone <pavone@retrodev.com>
parents:
451
diff
changeset
|
4 BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text. |
140af5509ce7
Added copyright notice to source files and added GPL license text in COPYING
Mike Pavone <pavone@retrodev.com>
parents:
451
diff
changeset
|
5 */ |
288
a8ee7934a1f8
Add a YM2612 stub implementation with just timers and status registers so that games that depend on it can run.
Mike Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
6 #include <string.h> |
359
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
7 #include <math.h> |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
8 #include <stdio.h> |
364
62177cc39049
Incredibly broken YM2612 support plus a fix to Z80 bus request
Mike Pavone <pavone@retrodev.com>
parents:
362
diff
changeset
|
9 #include <stdlib.h> |
288
a8ee7934a1f8
Add a YM2612 stub implementation with just timers and status registers so that games that depend on it can run.
Mike Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
10 #include "ym2612.h" |
364
62177cc39049
Incredibly broken YM2612 support plus a fix to Z80 bus request
Mike Pavone <pavone@retrodev.com>
parents:
362
diff
changeset
|
11 #include "render.h" |
407
c3abc4ada43d
Add support for logging YM2612 channels to WAVE files
Mike Pavone <pavone@retrodev.com>
parents:
406
diff
changeset
|
12 #include "wave.h" |
288
a8ee7934a1f8
Add a YM2612 stub implementation with just timers and status registers so that games that depend on it can run.
Mike Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
13 |
370
5f215603d001
Fix register to operator mapping. Fix rate table generation. Add TL to envelope value rather than using it as a limit for the attack phase.
Mike Pavone <pavone@retrodev.com>
parents:
369
diff
changeset
|
14 //#define DO_DEBUG_PRINT |
5f215603d001
Fix register to operator mapping. Fix rate table generation. Add TL to envelope value rather than using it as a limit for the attack phase.
Mike Pavone <pavone@retrodev.com>
parents:
369
diff
changeset
|
15 #ifdef DO_DEBUG_PRINT |
5f215603d001
Fix register to operator mapping. Fix rate table generation. Add TL to envelope value rather than using it as a limit for the attack phase.
Mike Pavone <pavone@retrodev.com>
parents:
369
diff
changeset
|
16 #define dfprintf fprintf |
5f215603d001
Fix register to operator mapping. Fix rate table generation. Add TL to envelope value rather than using it as a limit for the attack phase.
Mike Pavone <pavone@retrodev.com>
parents:
369
diff
changeset
|
17 #define dfopen(var, fname, mode) var=fopen(fname, mode) |
5f215603d001
Fix register to operator mapping. Fix rate table generation. Add TL to envelope value rather than using it as a limit for the attack phase.
Mike Pavone <pavone@retrodev.com>
parents:
369
diff
changeset
|
18 #else |
5f215603d001
Fix register to operator mapping. Fix rate table generation. Add TL to envelope value rather than using it as a limit for the attack phase.
Mike Pavone <pavone@retrodev.com>
parents:
369
diff
changeset
|
19 #define dfprintf |
5f215603d001
Fix register to operator mapping. Fix rate table generation. Add TL to envelope value rather than using it as a limit for the attack phase.
Mike Pavone <pavone@retrodev.com>
parents:
369
diff
changeset
|
20 #define dfopen(var, fname, mode) |
5f215603d001
Fix register to operator mapping. Fix rate table generation. Add TL to envelope value rather than using it as a limit for the attack phase.
Mike Pavone <pavone@retrodev.com>
parents:
369
diff
changeset
|
21 #endif |
5f215603d001
Fix register to operator mapping. Fix rate table generation. Add TL to envelope value rather than using it as a limit for the attack phase.
Mike Pavone <pavone@retrodev.com>
parents:
369
diff
changeset
|
22 |
288
a8ee7934a1f8
Add a YM2612 stub implementation with just timers and status registers so that games that depend on it can run.
Mike Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
23 #define BUSY_CYCLES 17 |
364
62177cc39049
Incredibly broken YM2612 support plus a fix to Z80 bus request
Mike Pavone <pavone@retrodev.com>
parents:
362
diff
changeset
|
24 #define OP_UPDATE_PERIOD 144 |
288
a8ee7934a1f8
Add a YM2612 stub implementation with just timers and status registers so that games that depend on it can run.
Mike Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
25 |
362 | 26 enum { |
411
baf4688901f2
Initial stab at LFO phase modulation
Mike Pavone <pavone@retrodev.com>
parents:
407
diff
changeset
|
27 REG_LFO = 0x22, |
362 | 28 REG_TIMERA_HIGH = 0x24, |
29 REG_TIMERA_LOW, | |
30 REG_TIMERB, | |
31 REG_TIME_CTRL, | |
32 REG_KEY_ONOFF, | |
33 REG_DAC = 0x2A, | |
34 REG_DAC_ENABLE, | |
359
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
35 |
362 | 36 REG_DETUNE_MULT = 0x30, |
37 REG_TOTAL_LEVEL = 0x40, | |
38 REG_ATTACK_KS = 0x50, | |
39 REG_DECAY_AM = 0x60, | |
40 REG_SUSTAIN_RATE = 0x70, | |
41 REG_S_LVL_R_RATE = 0x80, | |
359
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
42 |
362 | 43 REG_FNUM_LOW = 0xA0, |
44 REG_BLOCK_FNUM_H = 0xA4, | |
45 REG_FNUM_LOW_CH3 = 0xA8, | |
46 REG_BLOCK_FN_CH3 = 0xAC, | |
47 REG_ALG_FEEDBACK = 0xB0, | |
48 REG_LR_AMS_PMS = 0xB4 | |
49 }; | |
288
a8ee7934a1f8
Add a YM2612 stub implementation with just timers and status registers so that games that depend on it can run.
Mike Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
50 |
a8ee7934a1f8
Add a YM2612 stub implementation with just timers and status registers so that games that depend on it can run.
Mike Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
51 #define BIT_TIMERA_ENABLE 0x1 |
a8ee7934a1f8
Add a YM2612 stub implementation with just timers and status registers so that games that depend on it can run.
Mike Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
52 #define BIT_TIMERB_ENABLE 0x2 |
a8ee7934a1f8
Add a YM2612 stub implementation with just timers and status registers so that games that depend on it can run.
Mike Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
53 #define BIT_TIMERA_OVEREN 0x4 |
a8ee7934a1f8
Add a YM2612 stub implementation with just timers and status registers so that games that depend on it can run.
Mike Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
54 #define BIT_TIMERB_OVEREN 0x8 |
a8ee7934a1f8
Add a YM2612 stub implementation with just timers and status registers so that games that depend on it can run.
Mike Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
55 #define BIT_TIMERA_RESET 0x10 |
a8ee7934a1f8
Add a YM2612 stub implementation with just timers and status registers so that games that depend on it can run.
Mike Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
56 #define BIT_TIMERB_RESET 0x20 |
a8ee7934a1f8
Add a YM2612 stub implementation with just timers and status registers so that games that depend on it can run.
Mike Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
57 |
a8ee7934a1f8
Add a YM2612 stub implementation with just timers and status registers so that games that depend on it can run.
Mike Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
58 #define BIT_STATUS_TIMERA 0x1 |
a8ee7934a1f8
Add a YM2612 stub implementation with just timers and status registers so that games that depend on it can run.
Mike Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
59 #define BIT_STATUS_TIMERB 0x2 |
a8ee7934a1f8
Add a YM2612 stub implementation with just timers and status registers so that games that depend on it can run.
Mike Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
60 |
359
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
61 enum { |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
62 PHASE_ATTACK, |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
63 PHASE_DECAY, |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
64 PHASE_SUSTAIN, |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
65 PHASE_RELEASE |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
66 }; |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
67 |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
68 uint8_t did_tbl_init = 0; |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
69 //According to Nemesis, real hardware only uses a 256 entry quarter sine table; however, |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
70 //memory is cheap so using a half sine table will probably save some cycles |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
71 //a full sine table would be nice, but negative numbers don't get along with log2 |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
72 #define SINE_TABLE_SIZE 512 |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
73 uint16_t sine_table[SINE_TABLE_SIZE]; |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
74 //Similar deal here with the power table for log -> linear conversion |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
75 //According to Nemesis, real hardware only uses a 256 entry table for the fractional part |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
76 //and uses the whole part as a shift amount. |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
77 #define POW_TABLE_SIZE (1 << 13) |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
78 uint16_t pow_table[POW_TABLE_SIZE]; |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
79 |
362 | 80 uint16_t rate_table_base[] = { |
81 //main portion | |
82 0,1,0,1,0,1,0,1, | |
83 0,1,0,1,1,1,0,1, | |
84 0,1,1,1,0,1,1,1, | |
85 0,1,1,1,1,1,1,1, | |
86 //top end | |
87 1,1,1,1,1,1,1,1, | |
88 1,1,1,2,1,1,1,2, | |
89 1,2,1,2,1,2,1,2, | |
90 1,2,2,2,1,2,2,2, | |
91 }; | |
92 | |
365
3ba3b6656fff
Actually save the shifted phase inc after applying the block shift
Mike Pavone <pavone@retrodev.com>
parents:
364
diff
changeset
|
93 uint16_t rate_table[64*8]; |
362 | 94 |
411
baf4688901f2
Initial stab at LFO phase modulation
Mike Pavone <pavone@retrodev.com>
parents:
407
diff
changeset
|
95 uint8_t lfo_timer_values[] = {108, 77, 71, 67, 62, 44, 8, 5}; |
baf4688901f2
Initial stab at LFO phase modulation
Mike Pavone <pavone@retrodev.com>
parents:
407
diff
changeset
|
96 uint8_t lfo_pm_base[][8] = { |
baf4688901f2
Initial stab at LFO phase modulation
Mike Pavone <pavone@retrodev.com>
parents:
407
diff
changeset
|
97 {0, 0, 0, 0, 0, 0, 0, 0}, |
baf4688901f2
Initial stab at LFO phase modulation
Mike Pavone <pavone@retrodev.com>
parents:
407
diff
changeset
|
98 {0, 0, 0, 0, 4, 4, 4, 4}, |
baf4688901f2
Initial stab at LFO phase modulation
Mike Pavone <pavone@retrodev.com>
parents:
407
diff
changeset
|
99 {0, 0, 0, 4, 4, 4, 8, 8}, |
baf4688901f2
Initial stab at LFO phase modulation
Mike Pavone <pavone@retrodev.com>
parents:
407
diff
changeset
|
100 {0, 0, 4, 4, 8, 8, 0xc, 0xc}, |
baf4688901f2
Initial stab at LFO phase modulation
Mike Pavone <pavone@retrodev.com>
parents:
407
diff
changeset
|
101 {0, 0, 4, 8, 8, 8, 0xc,0x10}, |
baf4688901f2
Initial stab at LFO phase modulation
Mike Pavone <pavone@retrodev.com>
parents:
407
diff
changeset
|
102 {0, 0, 8, 0xc,0x10,0x10,0x14,0x18}, |
baf4688901f2
Initial stab at LFO phase modulation
Mike Pavone <pavone@retrodev.com>
parents:
407
diff
changeset
|
103 {0, 0,0x10,0x18,0x20,0x20,0x28,0x30}, |
baf4688901f2
Initial stab at LFO phase modulation
Mike Pavone <pavone@retrodev.com>
parents:
407
diff
changeset
|
104 {0, 0,0x20,0x30,0x40,0x40,0x50,0x60} |
baf4688901f2
Initial stab at LFO phase modulation
Mike Pavone <pavone@retrodev.com>
parents:
407
diff
changeset
|
105 }; |
baf4688901f2
Initial stab at LFO phase modulation
Mike Pavone <pavone@retrodev.com>
parents:
407
diff
changeset
|
106 int16_t lfo_pm_table[128 * 32 * 8]; |
baf4688901f2
Initial stab at LFO phase modulation
Mike Pavone <pavone@retrodev.com>
parents:
407
diff
changeset
|
107 |
362 | 108 #define MAX_ENVELOPE 0xFFC |
364
62177cc39049
Incredibly broken YM2612 support plus a fix to Z80 bus request
Mike Pavone <pavone@retrodev.com>
parents:
362
diff
changeset
|
109 #define YM_DIVIDER 2 |
374 | 110 #define CYCLE_NEVER 0xFFFFFFFF |
359
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
111 |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
112 uint16_t round_fixed_point(double value, int dec_bits) |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
113 { |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
114 return value * (1 << dec_bits) + 0.5; |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
115 } |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
116 |
370
5f215603d001
Fix register to operator mapping. Fix rate table generation. Add TL to envelope value rather than using it as a limit for the attack phase.
Mike Pavone <pavone@retrodev.com>
parents:
369
diff
changeset
|
117 FILE * debug_file = NULL; |
5f215603d001
Fix register to operator mapping. Fix rate table generation. Add TL to envelope value rather than using it as a limit for the attack phase.
Mike Pavone <pavone@retrodev.com>
parents:
369
diff
changeset
|
118 uint32_t first_key_on=0; |
5f215603d001
Fix register to operator mapping. Fix rate table generation. Add TL to envelope value rather than using it as a limit for the attack phase.
Mike Pavone <pavone@retrodev.com>
parents:
369
diff
changeset
|
119 |
407
c3abc4ada43d
Add support for logging YM2612 channels to WAVE files
Mike Pavone <pavone@retrodev.com>
parents:
406
diff
changeset
|
120 ym2612_context * log_context = NULL; |
c3abc4ada43d
Add support for logging YM2612 channels to WAVE files
Mike Pavone <pavone@retrodev.com>
parents:
406
diff
changeset
|
121 |
c3abc4ada43d
Add support for logging YM2612 channels to WAVE files
Mike Pavone <pavone@retrodev.com>
parents:
406
diff
changeset
|
122 void ym_finalize_log() |
c3abc4ada43d
Add support for logging YM2612 channels to WAVE files
Mike Pavone <pavone@retrodev.com>
parents:
406
diff
changeset
|
123 { |
c3abc4ada43d
Add support for logging YM2612 channels to WAVE files
Mike Pavone <pavone@retrodev.com>
parents:
406
diff
changeset
|
124 for (int i = 0; i < NUM_CHANNELS; i++) { |
c3abc4ada43d
Add support for logging YM2612 channels to WAVE files
Mike Pavone <pavone@retrodev.com>
parents:
406
diff
changeset
|
125 if (log_context->channels[i].logfile) { |
c3abc4ada43d
Add support for logging YM2612 channels to WAVE files
Mike Pavone <pavone@retrodev.com>
parents:
406
diff
changeset
|
126 wave_finalize(log_context->channels[i].logfile); |
c3abc4ada43d
Add support for logging YM2612 channels to WAVE files
Mike Pavone <pavone@retrodev.com>
parents:
406
diff
changeset
|
127 } |
c3abc4ada43d
Add support for logging YM2612 channels to WAVE files
Mike Pavone <pavone@retrodev.com>
parents:
406
diff
changeset
|
128 } |
c3abc4ada43d
Add support for logging YM2612 channels to WAVE files
Mike Pavone <pavone@retrodev.com>
parents:
406
diff
changeset
|
129 } |
483
3e1573fa22cf
Implement turbo/slow motion feature that overclocks or underclocks the entire system at the push of a button
Mike Pavone <pavone@retrodev.com>
parents:
467
diff
changeset
|
130 #define BUFFER_INC_RES 1000000000UL |
3e1573fa22cf
Implement turbo/slow motion feature that overclocks or underclocks the entire system at the push of a button
Mike Pavone <pavone@retrodev.com>
parents:
467
diff
changeset
|
131 |
3e1573fa22cf
Implement turbo/slow motion feature that overclocks or underclocks the entire system at the push of a button
Mike Pavone <pavone@retrodev.com>
parents:
467
diff
changeset
|
132 void ym_adjust_master_clock(ym2612_context * context, uint32_t master_clock) |
3e1573fa22cf
Implement turbo/slow motion feature that overclocks or underclocks the entire system at the push of a button
Mike Pavone <pavone@retrodev.com>
parents:
467
diff
changeset
|
133 { |
3e1573fa22cf
Implement turbo/slow motion feature that overclocks or underclocks the entire system at the push of a button
Mike Pavone <pavone@retrodev.com>
parents:
467
diff
changeset
|
134 uint64_t old_inc = context->buffer_inc; |
3e1573fa22cf
Implement turbo/slow motion feature that overclocks or underclocks the entire system at the push of a button
Mike Pavone <pavone@retrodev.com>
parents:
467
diff
changeset
|
135 context->buffer_inc = ((BUFFER_INC_RES * (uint64_t)context->sample_rate) / (uint64_t)master_clock) * (uint64_t)context->clock_inc; |
3e1573fa22cf
Implement turbo/slow motion feature that overclocks or underclocks the entire system at the push of a button
Mike Pavone <pavone@retrodev.com>
parents:
467
diff
changeset
|
136 } |
407
c3abc4ada43d
Add support for logging YM2612 channels to WAVE files
Mike Pavone <pavone@retrodev.com>
parents:
406
diff
changeset
|
137 |
c3abc4ada43d
Add support for logging YM2612 channels to WAVE files
Mike Pavone <pavone@retrodev.com>
parents:
406
diff
changeset
|
138 void ym_init(ym2612_context * context, uint32_t sample_rate, uint32_t master_clock, uint32_t clock_div, uint32_t sample_limit, uint32_t options) |
288
a8ee7934a1f8
Add a YM2612 stub implementation with just timers and status registers so that games that depend on it can run.
Mike Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
139 { |
370
5f215603d001
Fix register to operator mapping. Fix rate table generation. Add TL to envelope value rather than using it as a limit for the attack phase.
Mike Pavone <pavone@retrodev.com>
parents:
369
diff
changeset
|
140 dfopen(debug_file, "ym_debug.txt", "w"); |
288
a8ee7934a1f8
Add a YM2612 stub implementation with just timers and status registers so that games that depend on it can run.
Mike Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
141 memset(context, 0, sizeof(*context)); |
364
62177cc39049
Incredibly broken YM2612 support plus a fix to Z80 bus request
Mike Pavone <pavone@retrodev.com>
parents:
362
diff
changeset
|
142 context->audio_buffer = malloc(sizeof(*context->audio_buffer) * sample_limit*2); |
62177cc39049
Incredibly broken YM2612 support plus a fix to Z80 bus request
Mike Pavone <pavone@retrodev.com>
parents:
362
diff
changeset
|
143 context->back_buffer = malloc(sizeof(*context->audio_buffer) * sample_limit*2); |
483
3e1573fa22cf
Implement turbo/slow motion feature that overclocks or underclocks the entire system at the push of a button
Mike Pavone <pavone@retrodev.com>
parents:
467
diff
changeset
|
144 context->sample_rate = sample_rate; |
380
1c8d74f2ab0b
Make the PSG and YM2612 use the master clock internal with an increment based on clock divider so that they stay perflectly in sync. Run both the PSG and YM2612 whenver one of them needs to be run.
Mike Pavone <pavone@retrodev.com>
parents:
379
diff
changeset
|
145 context->clock_inc = clock_div * 6; |
483
3e1573fa22cf
Implement turbo/slow motion feature that overclocks or underclocks the entire system at the push of a button
Mike Pavone <pavone@retrodev.com>
parents:
467
diff
changeset
|
146 ym_adjust_master_clock(context, master_clock); |
3e1573fa22cf
Implement turbo/slow motion feature that overclocks or underclocks the entire system at the push of a button
Mike Pavone <pavone@retrodev.com>
parents:
467
diff
changeset
|
147 |
364
62177cc39049
Incredibly broken YM2612 support plus a fix to Z80 bus request
Mike Pavone <pavone@retrodev.com>
parents:
362
diff
changeset
|
148 context->sample_limit = sample_limit*2; |
374 | 149 context->write_cycle = CYCLE_NEVER; |
362 | 150 for (int i = 0; i < NUM_OPERATORS; i++) { |
151 context->operators[i].envelope = MAX_ENVELOPE; | |
152 context->operators[i].env_phase = PHASE_RELEASE; | |
153 } | |
369
fc820ab1394b
Fix left/right enable default value
Mike Pavone <pavone@retrodev.com>
parents:
365
diff
changeset
|
154 //some games seem to expect that the LR flags start out as 1 |
fc820ab1394b
Fix left/right enable default value
Mike Pavone <pavone@retrodev.com>
parents:
365
diff
changeset
|
155 for (int i = 0; i < NUM_CHANNELS; i++) { |
fc820ab1394b
Fix left/right enable default value
Mike Pavone <pavone@retrodev.com>
parents:
365
diff
changeset
|
156 context->channels[i].lr = 0xC0; |
407
c3abc4ada43d
Add support for logging YM2612 channels to WAVE files
Mike Pavone <pavone@retrodev.com>
parents:
406
diff
changeset
|
157 if (options & YM_OPT_WAVE_LOG) { |
c3abc4ada43d
Add support for logging YM2612 channels to WAVE files
Mike Pavone <pavone@retrodev.com>
parents:
406
diff
changeset
|
158 char fname[64]; |
c3abc4ada43d
Add support for logging YM2612 channels to WAVE files
Mike Pavone <pavone@retrodev.com>
parents:
406
diff
changeset
|
159 sprintf(fname, "ym_channel_%d.wav", i); |
c3abc4ada43d
Add support for logging YM2612 channels to WAVE files
Mike Pavone <pavone@retrodev.com>
parents:
406
diff
changeset
|
160 FILE * f = context->channels[i].logfile = fopen(fname, "wb"); |
c3abc4ada43d
Add support for logging YM2612 channels to WAVE files
Mike Pavone <pavone@retrodev.com>
parents:
406
diff
changeset
|
161 if (!f) { |
c3abc4ada43d
Add support for logging YM2612 channels to WAVE files
Mike Pavone <pavone@retrodev.com>
parents:
406
diff
changeset
|
162 fprintf(stderr, "Failed to open WAVE log file %s for writing\n", fname); |
c3abc4ada43d
Add support for logging YM2612 channels to WAVE files
Mike Pavone <pavone@retrodev.com>
parents:
406
diff
changeset
|
163 continue; |
c3abc4ada43d
Add support for logging YM2612 channels to WAVE files
Mike Pavone <pavone@retrodev.com>
parents:
406
diff
changeset
|
164 } |
c3abc4ada43d
Add support for logging YM2612 channels to WAVE files
Mike Pavone <pavone@retrodev.com>
parents:
406
diff
changeset
|
165 if (!wave_init(f, sample_rate, 16, 1)) { |
c3abc4ada43d
Add support for logging YM2612 channels to WAVE files
Mike Pavone <pavone@retrodev.com>
parents:
406
diff
changeset
|
166 fclose(f); |
c3abc4ada43d
Add support for logging YM2612 channels to WAVE files
Mike Pavone <pavone@retrodev.com>
parents:
406
diff
changeset
|
167 context->channels[i].logfile = NULL; |
c3abc4ada43d
Add support for logging YM2612 channels to WAVE files
Mike Pavone <pavone@retrodev.com>
parents:
406
diff
changeset
|
168 } |
c3abc4ada43d
Add support for logging YM2612 channels to WAVE files
Mike Pavone <pavone@retrodev.com>
parents:
406
diff
changeset
|
169 } |
c3abc4ada43d
Add support for logging YM2612 channels to WAVE files
Mike Pavone <pavone@retrodev.com>
parents:
406
diff
changeset
|
170 } |
c3abc4ada43d
Add support for logging YM2612 channels to WAVE files
Mike Pavone <pavone@retrodev.com>
parents:
406
diff
changeset
|
171 if (options & YM_OPT_WAVE_LOG) { |
c3abc4ada43d
Add support for logging YM2612 channels to WAVE files
Mike Pavone <pavone@retrodev.com>
parents:
406
diff
changeset
|
172 log_context = context; |
c3abc4ada43d
Add support for logging YM2612 channels to WAVE files
Mike Pavone <pavone@retrodev.com>
parents:
406
diff
changeset
|
173 atexit(ym_finalize_log); |
369
fc820ab1394b
Fix left/right enable default value
Mike Pavone <pavone@retrodev.com>
parents:
365
diff
changeset
|
174 } |
359
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
175 if (!did_tbl_init) { |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
176 //populate sine table |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
177 for (int32_t i = 0; i < 512; i++) { |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
178 double sine = sin( ((double)(i*2+1) / SINE_TABLE_SIZE) * M_PI_2 ); |
448
e85a107e6ec0
Fix handling of key on in YM2612 core
Mike Pavone <pavone@retrodev.com>
parents:
424
diff
changeset
|
179 |
359
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
180 //table stores 4.8 fixed pointed representation of the base 2 log |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
181 sine_table[i] = round_fixed_point(-log2(sine), 8); |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
182 } |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
183 //populate power table |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
184 for (int32_t i = 0; i < POW_TABLE_SIZE; i++) { |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
185 double linear = pow(2, -((double)((i & 0xFF)+1) / 256.0)); |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
186 int32_t tmp = round_fixed_point(linear, 11); |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
187 int32_t shift = (i >> 8) - 2; |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
188 if (shift < 0) { |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
189 tmp <<= 0-shift; |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
190 } else { |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
191 tmp >>= shift; |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
192 } |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
193 pow_table[i] = tmp; |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
194 } |
362 | 195 //populate envelope generator rate table, from small base table |
196 for (int rate = 0; rate < 64; rate++) { | |
370
5f215603d001
Fix register to operator mapping. Fix rate table generation. Add TL to envelope value rather than using it as a limit for the attack phase.
Mike Pavone <pavone@retrodev.com>
parents:
369
diff
changeset
|
197 for (int cycle = 0; cycle < 8; cycle++) { |
362 | 198 uint16_t value; |
370
5f215603d001
Fix register to operator mapping. Fix rate table generation. Add TL to envelope value rather than using it as a limit for the attack phase.
Mike Pavone <pavone@retrodev.com>
parents:
369
diff
changeset
|
199 if (rate < 2) { |
362 | 200 value = 0; |
365
3ba3b6656fff
Actually save the shifted phase inc after applying the block shift
Mike Pavone <pavone@retrodev.com>
parents:
364
diff
changeset
|
201 } else if (rate >= 60) { |
362 | 202 value = 8; |
365
3ba3b6656fff
Actually save the shifted phase inc after applying the block shift
Mike Pavone <pavone@retrodev.com>
parents:
364
diff
changeset
|
203 } else if (rate < 8) { |
370
5f215603d001
Fix register to operator mapping. Fix rate table generation. Add TL to envelope value rather than using it as a limit for the attack phase.
Mike Pavone <pavone@retrodev.com>
parents:
369
diff
changeset
|
204 value = rate_table_base[((rate & 6) == 6 ? 16 : 0) + cycle]; |
365
3ba3b6656fff
Actually save the shifted phase inc after applying the block shift
Mike Pavone <pavone@retrodev.com>
parents:
364
diff
changeset
|
205 } else if (rate < 48) { |
362 | 206 value = rate_table_base[(rate & 0x3) * 8 + cycle]; |
207 } else { | |
370
5f215603d001
Fix register to operator mapping. Fix rate table generation. Add TL to envelope value rather than using it as a limit for the attack phase.
Mike Pavone <pavone@retrodev.com>
parents:
369
diff
changeset
|
208 value = rate_table_base[32 + (rate & 0x3) * 8 + cycle] << ((rate - 48) >> 2); |
362 | 209 } |
365
3ba3b6656fff
Actually save the shifted phase inc after applying the block shift
Mike Pavone <pavone@retrodev.com>
parents:
364
diff
changeset
|
210 rate_table[rate * 8 + cycle] = value; |
362 | 211 } |
212 } | |
411
baf4688901f2
Initial stab at LFO phase modulation
Mike Pavone <pavone@retrodev.com>
parents:
407
diff
changeset
|
213 //populate LFO PM table from small base table |
baf4688901f2
Initial stab at LFO phase modulation
Mike Pavone <pavone@retrodev.com>
parents:
407
diff
changeset
|
214 //seems like there must be a better way to derive this |
baf4688901f2
Initial stab at LFO phase modulation
Mike Pavone <pavone@retrodev.com>
parents:
407
diff
changeset
|
215 for (int freq = 0; freq < 128; freq++) { |
baf4688901f2
Initial stab at LFO phase modulation
Mike Pavone <pavone@retrodev.com>
parents:
407
diff
changeset
|
216 for (int pms = 0; pms < 8; pms++) { |
baf4688901f2
Initial stab at LFO phase modulation
Mike Pavone <pavone@retrodev.com>
parents:
407
diff
changeset
|
217 for (int step = 0; step < 32; step++) { |
baf4688901f2
Initial stab at LFO phase modulation
Mike Pavone <pavone@retrodev.com>
parents:
407
diff
changeset
|
218 int16_t value = 0; |
baf4688901f2
Initial stab at LFO phase modulation
Mike Pavone <pavone@retrodev.com>
parents:
407
diff
changeset
|
219 for (int bit = 0x40, shift = 0; bit > 0; bit >>= 1, shift++) { |
baf4688901f2
Initial stab at LFO phase modulation
Mike Pavone <pavone@retrodev.com>
parents:
407
diff
changeset
|
220 if (freq & bit) { |
baf4688901f2
Initial stab at LFO phase modulation
Mike Pavone <pavone@retrodev.com>
parents:
407
diff
changeset
|
221 value += lfo_pm_base[pms][(step & 0x8) ? 7-step & 7 : step & 7] >> shift; |
baf4688901f2
Initial stab at LFO phase modulation
Mike Pavone <pavone@retrodev.com>
parents:
407
diff
changeset
|
222 } |
baf4688901f2
Initial stab at LFO phase modulation
Mike Pavone <pavone@retrodev.com>
parents:
407
diff
changeset
|
223 } |
baf4688901f2
Initial stab at LFO phase modulation
Mike Pavone <pavone@retrodev.com>
parents:
407
diff
changeset
|
224 if (step & 0x10) { |
baf4688901f2
Initial stab at LFO phase modulation
Mike Pavone <pavone@retrodev.com>
parents:
407
diff
changeset
|
225 value = -value; |
baf4688901f2
Initial stab at LFO phase modulation
Mike Pavone <pavone@retrodev.com>
parents:
407
diff
changeset
|
226 } |
baf4688901f2
Initial stab at LFO phase modulation
Mike Pavone <pavone@retrodev.com>
parents:
407
diff
changeset
|
227 lfo_pm_table[freq * 256 + pms * 32 + step] = value; |
baf4688901f2
Initial stab at LFO phase modulation
Mike Pavone <pavone@retrodev.com>
parents:
407
diff
changeset
|
228 } |
baf4688901f2
Initial stab at LFO phase modulation
Mike Pavone <pavone@retrodev.com>
parents:
407
diff
changeset
|
229 } |
baf4688901f2
Initial stab at LFO phase modulation
Mike Pavone <pavone@retrodev.com>
parents:
407
diff
changeset
|
230 } |
359
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
231 } |
288
a8ee7934a1f8
Add a YM2612 stub implementation with just timers and status registers so that games that depend on it can run.
Mike Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
232 } |
a8ee7934a1f8
Add a YM2612 stub implementation with just timers and status registers so that games that depend on it can run.
Mike Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
233 |
377 | 234 #define YM_VOLUME_DIVIDER 2 |
381
7815ebbbd705
Fix modulation shift value
Mike Pavone <pavone@retrodev.com>
parents:
380
diff
changeset
|
235 #define YM_MOD_SHIFT 1 |
370
5f215603d001
Fix register to operator mapping. Fix rate table generation. Add TL to envelope value rather than using it as a limit for the attack phase.
Mike Pavone <pavone@retrodev.com>
parents:
369
diff
changeset
|
236 |
403 | 237 #define TIMER_A_MAX 1023 |
238 #define TIMER_B_MAX (255*16) | |
239 | |
288
a8ee7934a1f8
Add a YM2612 stub implementation with just timers and status registers so that games that depend on it can run.
Mike Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
240 void ym_run(ym2612_context * context, uint32_t to_cycle) |
a8ee7934a1f8
Add a YM2612 stub implementation with just timers and status registers so that games that depend on it can run.
Mike Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
241 { |
362 | 242 //printf("Running YM2612 from cycle %d to cycle %d\n", context->current_cycle, to_cycle); |
243 //TODO: Fix channel update order OR remap channels in register write | |
380
1c8d74f2ab0b
Make the PSG and YM2612 use the master clock internal with an increment based on clock divider so that they stay perflectly in sync. Run both the PSG and YM2612 whenver one of them needs to be run.
Mike Pavone <pavone@retrodev.com>
parents:
379
diff
changeset
|
244 for (; context->current_cycle < to_cycle; context->current_cycle += context->clock_inc) { |
359
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
245 //Update timers at beginning of 144 cycle period |
403 | 246 if (!context->current_op) { |
247 if (context->timer_control & BIT_TIMERA_ENABLE) { | |
248 if (context->timer_a != TIMER_A_MAX) { | |
249 context->timer_a++; | |
250 } else { | |
251 if (context->timer_control & BIT_TIMERA_OVEREN) { | |
252 context->status |= BIT_STATUS_TIMERA; | |
253 } | |
254 context->timer_a = context->timer_a_load; | |
359
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
255 } |
288
a8ee7934a1f8
Add a YM2612 stub implementation with just timers and status registers so that games that depend on it can run.
Mike Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
256 } |
362 | 257 if (context->timer_control & BIT_TIMERB_ENABLE) { |
403 | 258 if (context->timer_b != TIMER_B_MAX) { |
259 context->timer_b++; | |
260 } else { | |
261 if (context->timer_control & BIT_TIMERB_OVEREN) { | |
262 context->status |= BIT_STATUS_TIMERB; | |
359
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
263 } |
403 | 264 context->timer_b = context->timer_b_load; |
359
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
265 } |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
266 } |
288
a8ee7934a1f8
Add a YM2612 stub implementation with just timers and status registers so that games that depend on it can run.
Mike Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
267 } |
411
baf4688901f2
Initial stab at LFO phase modulation
Mike Pavone <pavone@retrodev.com>
parents:
407
diff
changeset
|
268 //Update LFO |
baf4688901f2
Initial stab at LFO phase modulation
Mike Pavone <pavone@retrodev.com>
parents:
407
diff
changeset
|
269 if (context->lfo_enable) { |
baf4688901f2
Initial stab at LFO phase modulation
Mike Pavone <pavone@retrodev.com>
parents:
407
diff
changeset
|
270 if (context->lfo_counter) { |
baf4688901f2
Initial stab at LFO phase modulation
Mike Pavone <pavone@retrodev.com>
parents:
407
diff
changeset
|
271 context->lfo_counter--; |
baf4688901f2
Initial stab at LFO phase modulation
Mike Pavone <pavone@retrodev.com>
parents:
407
diff
changeset
|
272 } else { |
baf4688901f2
Initial stab at LFO phase modulation
Mike Pavone <pavone@retrodev.com>
parents:
407
diff
changeset
|
273 context->lfo_counter = lfo_timer_values[context->lfo_freq]; |
baf4688901f2
Initial stab at LFO phase modulation
Mike Pavone <pavone@retrodev.com>
parents:
407
diff
changeset
|
274 context->lfo_am_step += 2; |
baf4688901f2
Initial stab at LFO phase modulation
Mike Pavone <pavone@retrodev.com>
parents:
407
diff
changeset
|
275 context->lfo_am_step &= 0xFE; |
baf4688901f2
Initial stab at LFO phase modulation
Mike Pavone <pavone@retrodev.com>
parents:
407
diff
changeset
|
276 context->lfo_pm_step = context->lfo_am_step / 8; |
baf4688901f2
Initial stab at LFO phase modulation
Mike Pavone <pavone@retrodev.com>
parents:
407
diff
changeset
|
277 } |
baf4688901f2
Initial stab at LFO phase modulation
Mike Pavone <pavone@retrodev.com>
parents:
407
diff
changeset
|
278 } |
359
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
279 //Update Envelope Generator |
364
62177cc39049
Incredibly broken YM2612 support plus a fix to Z80 bus request
Mike Pavone <pavone@retrodev.com>
parents:
362
diff
changeset
|
280 if (!(context->current_op % 3)) { |
62177cc39049
Incredibly broken YM2612 support plus a fix to Z80 bus request
Mike Pavone <pavone@retrodev.com>
parents:
362
diff
changeset
|
281 uint32_t env_cyc = context->env_counter; |
62177cc39049
Incredibly broken YM2612 support plus a fix to Z80 bus request
Mike Pavone <pavone@retrodev.com>
parents:
362
diff
changeset
|
282 uint32_t op = context->current_env_op; |
362 | 283 ym_operator * operator = context->operators + op; |
284 ym_channel * channel = context->channels + op/4; | |
359
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
285 uint8_t rate; |
362 | 286 for(;;) { |
287 rate = operator->rates[operator->env_phase]; | |
288 if (rate) { | |
289 uint8_t ks = channel->keycode >> operator->key_scaling;; | |
290 rate = rate*2 + ks; | |
291 if (rate > 63) { | |
292 rate = 63; | |
293 } | |
294 } | |
295 //Deal with "infinite" rates | |
370
5f215603d001
Fix register to operator mapping. Fix rate table generation. Add TL to envelope value rather than using it as a limit for the attack phase.
Mike Pavone <pavone@retrodev.com>
parents:
369
diff
changeset
|
296 //According to Nemesis this should be handled in key-on instead |
5f215603d001
Fix register to operator mapping. Fix rate table generation. Add TL to envelope value rather than using it as a limit for the attack phase.
Mike Pavone <pavone@retrodev.com>
parents:
369
diff
changeset
|
297 if (rate >= 62 && operator->env_phase == PHASE_ATTACK) { |
5f215603d001
Fix register to operator mapping. Fix rate table generation. Add TL to envelope value rather than using it as a limit for the attack phase.
Mike Pavone <pavone@retrodev.com>
parents:
369
diff
changeset
|
298 operator->env_phase = PHASE_DECAY; |
5f215603d001
Fix register to operator mapping. Fix rate table generation. Add TL to envelope value rather than using it as a limit for the attack phase.
Mike Pavone <pavone@retrodev.com>
parents:
369
diff
changeset
|
299 operator->envelope = 0; |
362 | 300 } else { |
301 break; | |
302 } | |
303 } | |
304 uint32_t cycle_shift = rate < 0x30 ? ((0x2F - rate) >> 2) : 0; | |
370
5f215603d001
Fix register to operator mapping. Fix rate table generation. Add TL to envelope value rather than using it as a limit for the attack phase.
Mike Pavone <pavone@retrodev.com>
parents:
369
diff
changeset
|
305 if (first_key_on) { |
5f215603d001
Fix register to operator mapping. Fix rate table generation. Add TL to envelope value rather than using it as a limit for the attack phase.
Mike Pavone <pavone@retrodev.com>
parents:
369
diff
changeset
|
306 dfprintf(debug_file, "Operator: %d, env rate: %d (2*%d+%d), env_cyc: %d, cycle_shift: %d, env_cyc & ((1 << cycle_shift) - 1): %d\n", op, rate, operator->rates[operator->env_phase], channel->keycode >> operator->key_scaling,env_cyc, cycle_shift, env_cyc & ((1 << cycle_shift) - 1)); |
5f215603d001
Fix register to operator mapping. Fix rate table generation. Add TL to envelope value rather than using it as a limit for the attack phase.
Mike Pavone <pavone@retrodev.com>
parents:
369
diff
changeset
|
307 } |
362 | 308 if (!(env_cyc & ((1 << cycle_shift) - 1))) { |
309 uint32_t update_cycle = env_cyc >> cycle_shift & 0x7; | |
310 //envelope value is 10-bits, but it will be used as a 4.8 value | |
311 uint16_t envelope_inc = rate_table[rate * 8 + update_cycle] << 2; | |
312 if (operator->env_phase == PHASE_ATTACK) { | |
313 //this can probably be optimized to a single shift rather than a multiply + shift | |
370
5f215603d001
Fix register to operator mapping. Fix rate table generation. Add TL to envelope value rather than using it as a limit for the attack phase.
Mike Pavone <pavone@retrodev.com>
parents:
369
diff
changeset
|
314 if (first_key_on) { |
5f215603d001
Fix register to operator mapping. Fix rate table generation. Add TL to envelope value rather than using it as a limit for the attack phase.
Mike Pavone <pavone@retrodev.com>
parents:
369
diff
changeset
|
315 dfprintf(debug_file, "Changing op %d envelope %d by %d(%d * %d) in attack phase\n", op, operator->envelope, (~operator->envelope * envelope_inc) >> 4, ~operator->envelope, envelope_inc); |
5f215603d001
Fix register to operator mapping. Fix rate table generation. Add TL to envelope value rather than using it as a limit for the attack phase.
Mike Pavone <pavone@retrodev.com>
parents:
369
diff
changeset
|
316 } |
362 | 317 operator->envelope += (~operator->envelope * envelope_inc) >> 4; |
318 operator->envelope &= MAX_ENVELOPE; | |
370
5f215603d001
Fix register to operator mapping. Fix rate table generation. Add TL to envelope value rather than using it as a limit for the attack phase.
Mike Pavone <pavone@retrodev.com>
parents:
369
diff
changeset
|
319 if (!operator->envelope) { |
5f215603d001
Fix register to operator mapping. Fix rate table generation. Add TL to envelope value rather than using it as a limit for the attack phase.
Mike Pavone <pavone@retrodev.com>
parents:
369
diff
changeset
|
320 operator->envelope = 0; |
362 | 321 operator->env_phase = PHASE_DECAY; |
322 } | |
323 } else { | |
370
5f215603d001
Fix register to operator mapping. Fix rate table generation. Add TL to envelope value rather than using it as a limit for the attack phase.
Mike Pavone <pavone@retrodev.com>
parents:
369
diff
changeset
|
324 if (first_key_on) { |
448
e85a107e6ec0
Fix handling of key on in YM2612 core
Mike Pavone <pavone@retrodev.com>
parents:
424
diff
changeset
|
325 dfprintf(debug_file, "Changing op %d envelope %d by %d in %s phase\n", op, operator->envelope, envelope_inc, |
370
5f215603d001
Fix register to operator mapping. Fix rate table generation. Add TL to envelope value rather than using it as a limit for the attack phase.
Mike Pavone <pavone@retrodev.com>
parents:
369
diff
changeset
|
326 operator->env_phase == PHASE_SUSTAIN ? "sustain" : (operator->env_phase == PHASE_DECAY ? "decay": "release")); |
5f215603d001
Fix register to operator mapping. Fix rate table generation. Add TL to envelope value rather than using it as a limit for the attack phase.
Mike Pavone <pavone@retrodev.com>
parents:
369
diff
changeset
|
327 } |
362 | 328 operator->envelope += envelope_inc; |
329 //clamp to max attenuation value | |
330 if (operator->envelope > MAX_ENVELOPE) { | |
331 operator->envelope = MAX_ENVELOPE; | |
332 } | |
333 if (operator->env_phase == PHASE_DECAY && operator->envelope >= operator->sustain_level) { | |
370
5f215603d001
Fix register to operator mapping. Fix rate table generation. Add TL to envelope value rather than using it as a limit for the attack phase.
Mike Pavone <pavone@retrodev.com>
parents:
369
diff
changeset
|
334 //operator->envelope = operator->sustain_level; |
362 | 335 operator->env_phase = PHASE_SUSTAIN; |
336 } | |
337 } | |
364
62177cc39049
Incredibly broken YM2612 support plus a fix to Z80 bus request
Mike Pavone <pavone@retrodev.com>
parents:
362
diff
changeset
|
338 } |
62177cc39049
Incredibly broken YM2612 support plus a fix to Z80 bus request
Mike Pavone <pavone@retrodev.com>
parents:
362
diff
changeset
|
339 context->current_env_op++; |
62177cc39049
Incredibly broken YM2612 support plus a fix to Z80 bus request
Mike Pavone <pavone@retrodev.com>
parents:
362
diff
changeset
|
340 if (context->current_env_op == NUM_OPERATORS) { |
62177cc39049
Incredibly broken YM2612 support plus a fix to Z80 bus request
Mike Pavone <pavone@retrodev.com>
parents:
362
diff
changeset
|
341 context->current_env_op = 0; |
62177cc39049
Incredibly broken YM2612 support plus a fix to Z80 bus request
Mike Pavone <pavone@retrodev.com>
parents:
362
diff
changeset
|
342 context->env_counter++; |
362 | 343 } |
344 } | |
448
e85a107e6ec0
Fix handling of key on in YM2612 core
Mike Pavone <pavone@retrodev.com>
parents:
424
diff
changeset
|
345 |
362 | 346 //Update Phase Generator |
364
62177cc39049
Incredibly broken YM2612 support plus a fix to Z80 bus request
Mike Pavone <pavone@retrodev.com>
parents:
362
diff
changeset
|
347 uint32_t channel = context->current_op / 4; |
362 | 348 if (channel != 5 || !context->dac_enable) { |
364
62177cc39049
Incredibly broken YM2612 support plus a fix to Z80 bus request
Mike Pavone <pavone@retrodev.com>
parents:
362
diff
changeset
|
349 uint32_t op = context->current_op; |
362 | 350 //printf("updating operator %d of channel %d\n", op, channel); |
351 ym_operator * operator = context->operators + op; | |
352 ym_channel * chan = context->channels + channel; | |
353 //TODO: Modulate phase by LFO if necessary | |
396
09328dbe6700
Fix output of algorithm 4 and make some other minor YM2612 core improvements
Mike Pavone <pavone@retrodev.com>
parents:
386
diff
changeset
|
354 uint16_t phase = operator->phase_counter >> 10 & 0x3FF; |
362 | 355 operator->phase_counter += operator->phase_inc; |
411
baf4688901f2
Initial stab at LFO phase modulation
Mike Pavone <pavone@retrodev.com>
parents:
407
diff
changeset
|
356 if (chan->pms) { |
baf4688901f2
Initial stab at LFO phase modulation
Mike Pavone <pavone@retrodev.com>
parents:
407
diff
changeset
|
357 //not entirely sure this will get the precision correct, but I'd like to avoid recalculating phase |
baf4688901f2
Initial stab at LFO phase modulation
Mike Pavone <pavone@retrodev.com>
parents:
407
diff
changeset
|
358 //increment every update when LFO phase modulation is enabled |
baf4688901f2
Initial stab at LFO phase modulation
Mike Pavone <pavone@retrodev.com>
parents:
407
diff
changeset
|
359 int16_t lfo_mod = lfo_pm_table[(chan->fnum & 0x7F0) * 16 + chan->pms + context->lfo_pm_step]; |
baf4688901f2
Initial stab at LFO phase modulation
Mike Pavone <pavone@retrodev.com>
parents:
407
diff
changeset
|
360 if (operator->multiple) { |
baf4688901f2
Initial stab at LFO phase modulation
Mike Pavone <pavone@retrodev.com>
parents:
407
diff
changeset
|
361 lfo_mod *= operator->multiple; |
baf4688901f2
Initial stab at LFO phase modulation
Mike Pavone <pavone@retrodev.com>
parents:
407
diff
changeset
|
362 } else { |
baf4688901f2
Initial stab at LFO phase modulation
Mike Pavone <pavone@retrodev.com>
parents:
407
diff
changeset
|
363 lfo_mod >>= 1; |
baf4688901f2
Initial stab at LFO phase modulation
Mike Pavone <pavone@retrodev.com>
parents:
407
diff
changeset
|
364 } |
448
e85a107e6ec0
Fix handling of key on in YM2612 core
Mike Pavone <pavone@retrodev.com>
parents:
424
diff
changeset
|
365 operator->phase_counter += lfo_mod; |
411
baf4688901f2
Initial stab at LFO phase modulation
Mike Pavone <pavone@retrodev.com>
parents:
407
diff
changeset
|
366 } |
371
0f8a759f1ff4
Use signed ints for things that represent signed values in YM2612 core
Mike Pavone <pavone@retrodev.com>
parents:
370
diff
changeset
|
367 int16_t mod = 0; |
362 | 368 switch (op % 4) |
359
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
369 { |
362 | 370 case 0://Operator 1 |
377 | 371 if (chan->feedback) { |
378
92947faa258a
Adjust shift for feedback
Mike Pavone <pavone@retrodev.com>
parents:
377
diff
changeset
|
372 mod = operator->output >> (9-chan->feedback); |
377 | 373 } |
359
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
374 break; |
362 | 375 case 1://Operator 3 |
376 switch(chan->algorithm) | |
377 { | |
378 case 0: | |
379 case 2: | |
380 //modulate by operator 2 | |
379
3218e2f8d685
Make shift value of operator output to modulation input a define
Mike Pavone <pavone@retrodev.com>
parents:
378
diff
changeset
|
381 mod = context->operators[op+1].output >> YM_MOD_SHIFT; |
362 | 382 break; |
383 case 1: | |
384 //modulate by operator 1+2 | |
379
3218e2f8d685
Make shift value of operator output to modulation input a define
Mike Pavone <pavone@retrodev.com>
parents:
378
diff
changeset
|
385 mod = (context->operators[op-1].output + context->operators[op+1].output) >> YM_MOD_SHIFT; |
362 | 386 break; |
387 case 5: | |
388 //modulate by operator 1 | |
379
3218e2f8d685
Make shift value of operator output to modulation input a define
Mike Pavone <pavone@retrodev.com>
parents:
378
diff
changeset
|
389 mod = context->operators[op-1].output >> YM_MOD_SHIFT; |
362 | 390 } |
391 break; | |
392 case 2://Operator 2 | |
406
b1bc1947d949
Fix modulation condition for operator 2
Mike Pavone <pavone@retrodev.com>
parents:
403
diff
changeset
|
393 if (chan->algorithm != 1 && chan->algorithm != 2 && chan->algorithm != 7) { |
362 | 394 //modulate by Operator 1 |
379
3218e2f8d685
Make shift value of operator output to modulation input a define
Mike Pavone <pavone@retrodev.com>
parents:
378
diff
changeset
|
395 mod = context->operators[op-2].output >> YM_MOD_SHIFT; |
362 | 396 } |
359
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
397 break; |
362 | 398 case 3://Operator 4 |
399 switch(chan->algorithm) | |
400 { | |
401 case 0: | |
402 case 1: | |
403 case 4: | |
404 //modulate by operator 3 | |
379
3218e2f8d685
Make shift value of operator output to modulation input a define
Mike Pavone <pavone@retrodev.com>
parents:
378
diff
changeset
|
405 mod = context->operators[op-2].output >> YM_MOD_SHIFT; |
362 | 406 break; |
407 case 2: | |
408 //modulate by operator 1+3 | |
379
3218e2f8d685
Make shift value of operator output to modulation input a define
Mike Pavone <pavone@retrodev.com>
parents:
378
diff
changeset
|
409 mod = (context->operators[op-3].output + context->operators[op-2].output) >> YM_MOD_SHIFT; |
362 | 410 break; |
411 case 3: | |
412 //modulate by operator 2+3 | |
379
3218e2f8d685
Make shift value of operator output to modulation input a define
Mike Pavone <pavone@retrodev.com>
parents:
378
diff
changeset
|
413 mod = (context->operators[op-1].output + context->operators[op-2].output) >> YM_MOD_SHIFT; |
362 | 414 break; |
415 case 5: | |
416 //modulate by operator 1 | |
379
3218e2f8d685
Make shift value of operator output to modulation input a define
Mike Pavone <pavone@retrodev.com>
parents:
378
diff
changeset
|
417 mod = context->operators[op-3].output >> YM_MOD_SHIFT; |
362 | 418 break; |
419 } | |
359
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
420 break; |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
421 } |
370
5f215603d001
Fix register to operator mapping. Fix rate table generation. Add TL to envelope value rather than using it as a limit for the attack phase.
Mike Pavone <pavone@retrodev.com>
parents:
369
diff
changeset
|
422 uint16_t env = operator->envelope + operator->total_level; |
5f215603d001
Fix register to operator mapping. Fix rate table generation. Add TL to envelope value rather than using it as a limit for the attack phase.
Mike Pavone <pavone@retrodev.com>
parents:
369
diff
changeset
|
423 if (env > MAX_ENVELOPE) { |
5f215603d001
Fix register to operator mapping. Fix rate table generation. Add TL to envelope value rather than using it as a limit for the attack phase.
Mike Pavone <pavone@retrodev.com>
parents:
369
diff
changeset
|
424 env = MAX_ENVELOPE; |
5f215603d001
Fix register to operator mapping. Fix rate table generation. Add TL to envelope value rather than using it as a limit for the attack phase.
Mike Pavone <pavone@retrodev.com>
parents:
369
diff
changeset
|
425 } |
5f215603d001
Fix register to operator mapping. Fix rate table generation. Add TL to envelope value rather than using it as a limit for the attack phase.
Mike Pavone <pavone@retrodev.com>
parents:
369
diff
changeset
|
426 if (first_key_on) { |
5f215603d001
Fix register to operator mapping. Fix rate table generation. Add TL to envelope value rather than using it as a limit for the attack phase.
Mike Pavone <pavone@retrodev.com>
parents:
369
diff
changeset
|
427 dfprintf(debug_file, "op %d, base phase: %d, mod: %d, sine: %d, out: %d\n", op, phase, mod, sine_table[(phase+mod) & 0x1FF], pow_table[sine_table[phase & 0x1FF] + env]); |
5f215603d001
Fix register to operator mapping. Fix rate table generation. Add TL to envelope value rather than using it as a limit for the attack phase.
Mike Pavone <pavone@retrodev.com>
parents:
369
diff
changeset
|
428 } |
5f215603d001
Fix register to operator mapping. Fix rate table generation. Add TL to envelope value rather than using it as a limit for the attack phase.
Mike Pavone <pavone@retrodev.com>
parents:
369
diff
changeset
|
429 phase += mod; |
448
e85a107e6ec0
Fix handling of key on in YM2612 core
Mike Pavone <pavone@retrodev.com>
parents:
424
diff
changeset
|
430 |
371
0f8a759f1ff4
Use signed ints for things that represent signed values in YM2612 core
Mike Pavone <pavone@retrodev.com>
parents:
370
diff
changeset
|
431 int16_t output = pow_table[sine_table[phase & 0x1FF] + env]; |
359
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
432 if (phase & 0x200) { |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
433 output = -output; |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
434 } |
362 | 435 operator->output = output; |
359
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
436 //Update the channel output if we've updated all operators |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
437 if (op % 4 == 3) { |
362 | 438 if (chan->algorithm < 4) { |
439 chan->output = operator->output; | |
440 } else if(chan->algorithm == 4) { | |
396
09328dbe6700
Fix output of algorithm 4 and make some other minor YM2612 core improvements
Mike Pavone <pavone@retrodev.com>
parents:
386
diff
changeset
|
441 chan->output = operator->output + context->operators[channel * 4 + 2].output; |
359
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
442 } else { |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
443 output = 0; |
362 | 444 for (uint32_t op = ((chan->algorithm == 7) ? 0 : 1) + channel*4; op < (channel+1)*4; op++) { |
445 output += context->operators[op].output; | |
359
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
446 } |
362 | 447 chan->output = output; |
359
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
448 } |
370
5f215603d001
Fix register to operator mapping. Fix rate table generation. Add TL to envelope value rather than using it as a limit for the attack phase.
Mike Pavone <pavone@retrodev.com>
parents:
369
diff
changeset
|
449 if (first_key_on) { |
371
0f8a759f1ff4
Use signed ints for things that represent signed values in YM2612 core
Mike Pavone <pavone@retrodev.com>
parents:
370
diff
changeset
|
450 int16_t value = context->channels[channel].output & 0x3FE0; |
0f8a759f1ff4
Use signed ints for things that represent signed values in YM2612 core
Mike Pavone <pavone@retrodev.com>
parents:
370
diff
changeset
|
451 if (value & 0x2000) { |
0f8a759f1ff4
Use signed ints for things that represent signed values in YM2612 core
Mike Pavone <pavone@retrodev.com>
parents:
370
diff
changeset
|
452 value |= 0xC000; |
0f8a759f1ff4
Use signed ints for things that represent signed values in YM2612 core
Mike Pavone <pavone@retrodev.com>
parents:
370
diff
changeset
|
453 } |
0f8a759f1ff4
Use signed ints for things that represent signed values in YM2612 core
Mike Pavone <pavone@retrodev.com>
parents:
370
diff
changeset
|
454 dfprintf(debug_file, "channel %d output: %d\n", channel, value / YM_VOLUME_DIVIDER); |
370
5f215603d001
Fix register to operator mapping. Fix rate table generation. Add TL to envelope value rather than using it as a limit for the attack phase.
Mike Pavone <pavone@retrodev.com>
parents:
369
diff
changeset
|
455 } |
359
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
456 } |
362 | 457 //puts("operator update done"); |
359
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
458 } |
364
62177cc39049
Incredibly broken YM2612 support plus a fix to Z80 bus request
Mike Pavone <pavone@retrodev.com>
parents:
362
diff
changeset
|
459 context->current_op++; |
380
1c8d74f2ab0b
Make the PSG and YM2612 use the master clock internal with an increment based on clock divider so that they stay perflectly in sync. Run both the PSG and YM2612 whenver one of them needs to be run.
Mike Pavone <pavone@retrodev.com>
parents:
379
diff
changeset
|
460 context->buffer_fraction += context->buffer_inc; |
396
09328dbe6700
Fix output of algorithm 4 and make some other minor YM2612 core improvements
Mike Pavone <pavone@retrodev.com>
parents:
386
diff
changeset
|
461 if (context->current_op == NUM_OPERATORS) { |
09328dbe6700
Fix output of algorithm 4 and make some other minor YM2612 core improvements
Mike Pavone <pavone@retrodev.com>
parents:
386
diff
changeset
|
462 context->current_op = 0; |
483
3e1573fa22cf
Implement turbo/slow motion feature that overclocks or underclocks the entire system at the push of a button
Mike Pavone <pavone@retrodev.com>
parents:
467
diff
changeset
|
463 } |
3e1573fa22cf
Implement turbo/slow motion feature that overclocks or underclocks the entire system at the push of a button
Mike Pavone <pavone@retrodev.com>
parents:
467
diff
changeset
|
464 if (context->buffer_fraction > BUFFER_INC_RES) { |
3e1573fa22cf
Implement turbo/slow motion feature that overclocks or underclocks the entire system at the push of a button
Mike Pavone <pavone@retrodev.com>
parents:
467
diff
changeset
|
465 context->buffer_fraction -= BUFFER_INC_RES; |
3e1573fa22cf
Implement turbo/slow motion feature that overclocks or underclocks the entire system at the push of a button
Mike Pavone <pavone@retrodev.com>
parents:
467
diff
changeset
|
466 context->audio_buffer[context->buffer_pos] = 0; |
3e1573fa22cf
Implement turbo/slow motion feature that overclocks or underclocks the entire system at the push of a button
Mike Pavone <pavone@retrodev.com>
parents:
467
diff
changeset
|
467 context->audio_buffer[context->buffer_pos + 1] = 0; |
3e1573fa22cf
Implement turbo/slow motion feature that overclocks or underclocks the entire system at the push of a button
Mike Pavone <pavone@retrodev.com>
parents:
467
diff
changeset
|
468 for (int i = 0; i < NUM_CHANNELS; i++) { |
3e1573fa22cf
Implement turbo/slow motion feature that overclocks or underclocks the entire system at the push of a button
Mike Pavone <pavone@retrodev.com>
parents:
467
diff
changeset
|
469 int16_t value = context->channels[i].output & 0x3FE0; |
3e1573fa22cf
Implement turbo/slow motion feature that overclocks or underclocks the entire system at the push of a button
Mike Pavone <pavone@retrodev.com>
parents:
467
diff
changeset
|
470 if (value & 0x2000) { |
3e1573fa22cf
Implement turbo/slow motion feature that overclocks or underclocks the entire system at the push of a button
Mike Pavone <pavone@retrodev.com>
parents:
467
diff
changeset
|
471 value |= 0xC000; |
380
1c8d74f2ab0b
Make the PSG and YM2612 use the master clock internal with an increment based on clock divider so that they stay perflectly in sync. Run both the PSG and YM2612 whenver one of them needs to be run.
Mike Pavone <pavone@retrodev.com>
parents:
379
diff
changeset
|
472 } |
483
3e1573fa22cf
Implement turbo/slow motion feature that overclocks or underclocks the entire system at the push of a button
Mike Pavone <pavone@retrodev.com>
parents:
467
diff
changeset
|
473 if (context->channels[i].logfile) { |
3e1573fa22cf
Implement turbo/slow motion feature that overclocks or underclocks the entire system at the push of a button
Mike Pavone <pavone@retrodev.com>
parents:
467
diff
changeset
|
474 fwrite(&value, sizeof(value), 1, context->channels[i].logfile); |
3e1573fa22cf
Implement turbo/slow motion feature that overclocks or underclocks the entire system at the push of a button
Mike Pavone <pavone@retrodev.com>
parents:
467
diff
changeset
|
475 } |
3e1573fa22cf
Implement turbo/slow motion feature that overclocks or underclocks the entire system at the push of a button
Mike Pavone <pavone@retrodev.com>
parents:
467
diff
changeset
|
476 if (context->channels[i].lr & 0x80) { |
3e1573fa22cf
Implement turbo/slow motion feature that overclocks or underclocks the entire system at the push of a button
Mike Pavone <pavone@retrodev.com>
parents:
467
diff
changeset
|
477 context->audio_buffer[context->buffer_pos] += value / YM_VOLUME_DIVIDER; |
380
1c8d74f2ab0b
Make the PSG and YM2612 use the master clock internal with an increment based on clock divider so that they stay perflectly in sync. Run both the PSG and YM2612 whenver one of them needs to be run.
Mike Pavone <pavone@retrodev.com>
parents:
379
diff
changeset
|
478 } |
483
3e1573fa22cf
Implement turbo/slow motion feature that overclocks or underclocks the entire system at the push of a button
Mike Pavone <pavone@retrodev.com>
parents:
467
diff
changeset
|
479 if (context->channels[i].lr & 0x40) { |
3e1573fa22cf
Implement turbo/slow motion feature that overclocks or underclocks the entire system at the push of a button
Mike Pavone <pavone@retrodev.com>
parents:
467
diff
changeset
|
480 context->audio_buffer[context->buffer_pos+1] += value / YM_VOLUME_DIVIDER; |
3e1573fa22cf
Implement turbo/slow motion feature that overclocks or underclocks the entire system at the push of a button
Mike Pavone <pavone@retrodev.com>
parents:
467
diff
changeset
|
481 } |
3e1573fa22cf
Implement turbo/slow motion feature that overclocks or underclocks the entire system at the push of a button
Mike Pavone <pavone@retrodev.com>
parents:
467
diff
changeset
|
482 } |
3e1573fa22cf
Implement turbo/slow motion feature that overclocks or underclocks the entire system at the push of a button
Mike Pavone <pavone@retrodev.com>
parents:
467
diff
changeset
|
483 context->buffer_pos += 2; |
3e1573fa22cf
Implement turbo/slow motion feature that overclocks or underclocks the entire system at the push of a button
Mike Pavone <pavone@retrodev.com>
parents:
467
diff
changeset
|
484 if (context->buffer_pos == context->sample_limit) { |
3e1573fa22cf
Implement turbo/slow motion feature that overclocks or underclocks the entire system at the push of a button
Mike Pavone <pavone@retrodev.com>
parents:
467
diff
changeset
|
485 render_wait_ym(context); |
380
1c8d74f2ab0b
Make the PSG and YM2612 use the master clock internal with an increment based on clock divider so that they stay perflectly in sync. Run both the PSG and YM2612 whenver one of them needs to be run.
Mike Pavone <pavone@retrodev.com>
parents:
379
diff
changeset
|
486 } |
364
62177cc39049
Incredibly broken YM2612 support plus a fix to Z80 bus request
Mike Pavone <pavone@retrodev.com>
parents:
362
diff
changeset
|
487 } |
288
a8ee7934a1f8
Add a YM2612 stub implementation with just timers and status registers so that games that depend on it can run.
Mike Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
488 } |
380
1c8d74f2ab0b
Make the PSG and YM2612 use the master clock internal with an increment based on clock divider so that they stay perflectly in sync. Run both the PSG and YM2612 whenver one of them needs to be run.
Mike Pavone <pavone@retrodev.com>
parents:
379
diff
changeset
|
489 if (context->current_cycle >= context->write_cycle + (BUSY_CYCLES * context->clock_inc / 6)) { |
288
a8ee7934a1f8
Add a YM2612 stub implementation with just timers and status registers so that games that depend on it can run.
Mike Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
490 context->status &= 0x7F; |
374 | 491 context->write_cycle = CYCLE_NEVER; |
288
a8ee7934a1f8
Add a YM2612 stub implementation with just timers and status registers so that games that depend on it can run.
Mike Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
492 } |
362 | 493 //printf("Done running YM2612 at cycle %d\n", context->current_cycle, to_cycle); |
288
a8ee7934a1f8
Add a YM2612 stub implementation with just timers and status registers so that games that depend on it can run.
Mike Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
494 } |
a8ee7934a1f8
Add a YM2612 stub implementation with just timers and status registers so that games that depend on it can run.
Mike Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
495 |
a8ee7934a1f8
Add a YM2612 stub implementation with just timers and status registers so that games that depend on it can run.
Mike Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
496 void ym_address_write_part1(ym2612_context * context, uint8_t address) |
a8ee7934a1f8
Add a YM2612 stub implementation with just timers and status registers so that games that depend on it can run.
Mike Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
497 { |
364
62177cc39049
Incredibly broken YM2612 support plus a fix to Z80 bus request
Mike Pavone <pavone@retrodev.com>
parents:
362
diff
changeset
|
498 //printf("address_write_part1: %X\n", address); |
362 | 499 context->selected_reg = address; |
500 context->selected_part = 0; | |
288
a8ee7934a1f8
Add a YM2612 stub implementation with just timers and status registers so that games that depend on it can run.
Mike Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
501 } |
a8ee7934a1f8
Add a YM2612 stub implementation with just timers and status registers so that games that depend on it can run.
Mike Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
502 |
a8ee7934a1f8
Add a YM2612 stub implementation with just timers and status registers so that games that depend on it can run.
Mike Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
503 void ym_address_write_part2(ym2612_context * context, uint8_t address) |
a8ee7934a1f8
Add a YM2612 stub implementation with just timers and status registers so that games that depend on it can run.
Mike Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
504 { |
364
62177cc39049
Incredibly broken YM2612 support plus a fix to Z80 bus request
Mike Pavone <pavone@retrodev.com>
parents:
362
diff
changeset
|
505 //printf("address_write_part2: %X\n", address); |
362 | 506 context->selected_reg = address; |
507 context->selected_part = 1; | |
508 } | |
509 | |
510 uint8_t fnum_to_keycode[] = { | |
511 //F11 = 0 | |
512 0,0,0,0,0,0,0,1, | |
513 //F11 = 1 | |
514 2,3,3,3,3,3,3,3 | |
515 }; | |
516 | |
517 //table courtesy of Nemesis | |
518 uint32_t detune_table[][4] = { | |
519 {0, 0, 1, 2}, //0 (0x00) | |
520 {0, 0, 1, 2}, //1 (0x01) | |
521 {0, 0, 1, 2}, //2 (0x02) | |
522 {0, 0, 1, 2}, //3 (0x03) | |
523 {0, 1, 2, 2}, //4 (0x04) | |
524 {0, 1, 2, 3}, //5 (0x05) | |
525 {0, 1, 2, 3}, //6 (0x06) | |
526 {0, 1, 2, 3}, //7 (0x07) | |
527 {0, 1, 2, 4}, //8 (0x08) | |
528 {0, 1, 3, 4}, //9 (0x09) | |
529 {0, 1, 3, 4}, //10 (0x0A) | |
530 {0, 1, 3, 5}, //11 (0x0B) | |
531 {0, 2, 4, 5}, //12 (0x0C) | |
532 {0, 2, 4, 6}, //13 (0x0D) | |
533 {0, 2, 4, 6}, //14 (0x0E) | |
534 {0, 2, 5, 7}, //15 (0x0F) | |
535 {0, 2, 5, 8}, //16 (0x10) | |
536 {0, 3, 6, 8}, //17 (0x11) | |
537 {0, 3, 6, 9}, //18 (0x12) | |
538 {0, 3, 7,10}, //19 (0x13) | |
539 {0, 4, 8,11}, //20 (0x14) | |
540 {0, 4, 8,12}, //21 (0x15) | |
541 {0, 4, 9,13}, //22 (0x16) | |
542 {0, 5,10,14}, //23 (0x17) | |
543 {0, 5,11,16}, //24 (0x18) | |
544 {0, 6,12,17}, //25 (0x19) | |
545 {0, 6,13,19}, //26 (0x1A) | |
546 {0, 7,14,20}, //27 (0x1B) | |
547 {0, 8,16,22}, //28 (0x1C) | |
548 {0, 8,16,22}, //29 (0x1D) | |
549 {0, 8,16,22}, //30 (0x1E) | |
550 {0, 8,16,22} | |
551 }; //31 (0x1F) | |
552 | |
553 void ym_update_phase_inc(ym2612_context * context, ym_operator * operator, uint32_t op) | |
554 { | |
555 uint32_t chan_num = op / 4; | |
556 //printf("ym_update_phase_inc | channel: %d, op: %d\n", chan_num, op); | |
557 //base frequency | |
558 ym_channel * channel = context->channels + chan_num; | |
383
72933100c55c
Initial implementation of channel 3 special mode
Mike Pavone <pavone@retrodev.com>
parents:
382
diff
changeset
|
559 uint32_t inc, detune; |
72933100c55c
Initial implementation of channel 3 special mode
Mike Pavone <pavone@retrodev.com>
parents:
382
diff
changeset
|
560 if (chan_num == 2 && context->ch3_mode && (op < (2*4 + 3))) { |
72933100c55c
Initial implementation of channel 3 special mode
Mike Pavone <pavone@retrodev.com>
parents:
382
diff
changeset
|
561 inc = context->ch3_supp[op-2*4].fnum; |
72933100c55c
Initial implementation of channel 3 special mode
Mike Pavone <pavone@retrodev.com>
parents:
382
diff
changeset
|
562 if (!context->ch3_supp[op-2*4].block) { |
72933100c55c
Initial implementation of channel 3 special mode
Mike Pavone <pavone@retrodev.com>
parents:
382
diff
changeset
|
563 inc >>= 1; |
72933100c55c
Initial implementation of channel 3 special mode
Mike Pavone <pavone@retrodev.com>
parents:
382
diff
changeset
|
564 } else { |
72933100c55c
Initial implementation of channel 3 special mode
Mike Pavone <pavone@retrodev.com>
parents:
382
diff
changeset
|
565 inc <<= (context->ch3_supp[op-2*4].block-1); |
72933100c55c
Initial implementation of channel 3 special mode
Mike Pavone <pavone@retrodev.com>
parents:
382
diff
changeset
|
566 } |
72933100c55c
Initial implementation of channel 3 special mode
Mike Pavone <pavone@retrodev.com>
parents:
382
diff
changeset
|
567 //detune |
72933100c55c
Initial implementation of channel 3 special mode
Mike Pavone <pavone@retrodev.com>
parents:
382
diff
changeset
|
568 detune = detune_table[context->ch3_supp[op-2*4].keycode][operator->detune & 0x3]; |
288
a8ee7934a1f8
Add a YM2612 stub implementation with just timers and status registers so that games that depend on it can run.
Mike Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
569 } else { |
383
72933100c55c
Initial implementation of channel 3 special mode
Mike Pavone <pavone@retrodev.com>
parents:
382
diff
changeset
|
570 inc = channel->fnum; |
72933100c55c
Initial implementation of channel 3 special mode
Mike Pavone <pavone@retrodev.com>
parents:
382
diff
changeset
|
571 if (!channel->block) { |
72933100c55c
Initial implementation of channel 3 special mode
Mike Pavone <pavone@retrodev.com>
parents:
382
diff
changeset
|
572 inc >>= 1; |
72933100c55c
Initial implementation of channel 3 special mode
Mike Pavone <pavone@retrodev.com>
parents:
382
diff
changeset
|
573 } else { |
72933100c55c
Initial implementation of channel 3 special mode
Mike Pavone <pavone@retrodev.com>
parents:
382
diff
changeset
|
574 inc <<= (channel->block-1); |
72933100c55c
Initial implementation of channel 3 special mode
Mike Pavone <pavone@retrodev.com>
parents:
382
diff
changeset
|
575 } |
72933100c55c
Initial implementation of channel 3 special mode
Mike Pavone <pavone@retrodev.com>
parents:
382
diff
changeset
|
576 //detune |
72933100c55c
Initial implementation of channel 3 special mode
Mike Pavone <pavone@retrodev.com>
parents:
382
diff
changeset
|
577 detune = detune_table[channel->keycode][operator->detune & 0x3]; |
448
e85a107e6ec0
Fix handling of key on in YM2612 core
Mike Pavone <pavone@retrodev.com>
parents:
424
diff
changeset
|
578 } |
362 | 579 if (operator->detune & 0x40) { |
580 inc -= detune; | |
581 //this can underflow, mask to 17-bit result | |
582 inc &= 0x1FFFF; | |
583 } else { | |
584 inc += detune; | |
585 } | |
586 //multiple | |
587 if (operator->multiple) { | |
588 inc *= operator->multiple; | |
589 } else { | |
590 //0.5 | |
591 inc >>= 1; | |
288
a8ee7934a1f8
Add a YM2612 stub implementation with just timers and status registers so that games that depend on it can run.
Mike Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
592 } |
365
3ba3b6656fff
Actually save the shifted phase inc after applying the block shift
Mike Pavone <pavone@retrodev.com>
parents:
364
diff
changeset
|
593 //printf("phase_inc for operator %d: %d, block: %d, fnum: %d, detune: %d, multiple: %d\n", op, inc, channel->block, channel->fnum, detune, operator->multiple); |
364
62177cc39049
Incredibly broken YM2612 support plus a fix to Z80 bus request
Mike Pavone <pavone@retrodev.com>
parents:
362
diff
changeset
|
594 operator->phase_inc = inc; |
288
a8ee7934a1f8
Add a YM2612 stub implementation with just timers and status registers so that games that depend on it can run.
Mike Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
595 } |
a8ee7934a1f8
Add a YM2612 stub implementation with just timers and status registers so that games that depend on it can run.
Mike Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
596 |
a8ee7934a1f8
Add a YM2612 stub implementation with just timers and status registers so that games that depend on it can run.
Mike Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
597 void ym_data_write(ym2612_context * context, uint8_t value) |
a8ee7934a1f8
Add a YM2612 stub implementation with just timers and status registers so that games that depend on it can run.
Mike Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
598 { |
451
b7c3b2d22858
Added support for saving savestates. Added gst savestate format test harness
Mike Pavone <pavone@retrodev.com>
parents:
448
diff
changeset
|
599 if (context->selected_reg >= YM_REG_END) { |
362 | 600 return; |
288
a8ee7934a1f8
Add a YM2612 stub implementation with just timers and status registers so that games that depend on it can run.
Mike Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
601 } |
451
b7c3b2d22858
Added support for saving savestates. Added gst savestate format test harness
Mike Pavone <pavone@retrodev.com>
parents:
448
diff
changeset
|
602 if (context->selected_part) { |
b7c3b2d22858
Added support for saving savestates. Added gst savestate format test harness
Mike Pavone <pavone@retrodev.com>
parents:
448
diff
changeset
|
603 if (context->selected_reg < YM_PART2_START) { |
b7c3b2d22858
Added support for saving savestates. Added gst savestate format test harness
Mike Pavone <pavone@retrodev.com>
parents:
448
diff
changeset
|
604 return; |
b7c3b2d22858
Added support for saving savestates. Added gst savestate format test harness
Mike Pavone <pavone@retrodev.com>
parents:
448
diff
changeset
|
605 } |
b7c3b2d22858
Added support for saving savestates. Added gst savestate format test harness
Mike Pavone <pavone@retrodev.com>
parents:
448
diff
changeset
|
606 context->part2_regs[context->selected_reg - YM_PART2_START] = value; |
b7c3b2d22858
Added support for saving savestates. Added gst savestate format test harness
Mike Pavone <pavone@retrodev.com>
parents:
448
diff
changeset
|
607 } else { |
b7c3b2d22858
Added support for saving savestates. Added gst savestate format test harness
Mike Pavone <pavone@retrodev.com>
parents:
448
diff
changeset
|
608 if (context->selected_reg < YM_PART1_START) { |
b7c3b2d22858
Added support for saving savestates. Added gst savestate format test harness
Mike Pavone <pavone@retrodev.com>
parents:
448
diff
changeset
|
609 return; |
b7c3b2d22858
Added support for saving savestates. Added gst savestate format test harness
Mike Pavone <pavone@retrodev.com>
parents:
448
diff
changeset
|
610 } |
b7c3b2d22858
Added support for saving savestates. Added gst savestate format test harness
Mike Pavone <pavone@retrodev.com>
parents:
448
diff
changeset
|
611 context->part1_regs[context->selected_reg - YM_PART1_START] = value; |
b7c3b2d22858
Added support for saving savestates. Added gst savestate format test harness
Mike Pavone <pavone@retrodev.com>
parents:
448
diff
changeset
|
612 } |
370
5f215603d001
Fix register to operator mapping. Fix rate table generation. Add TL to envelope value rather than using it as a limit for the attack phase.
Mike Pavone <pavone@retrodev.com>
parents:
369
diff
changeset
|
613 dfprintf(debug_file, "write of %X to reg %X in part %d\n", value, context->selected_reg, context->selected_part+1); |
362 | 614 if (context->selected_reg < 0x30) { |
615 //Shared regs | |
616 switch (context->selected_reg) | |
617 { | |
411
baf4688901f2
Initial stab at LFO phase modulation
Mike Pavone <pavone@retrodev.com>
parents:
407
diff
changeset
|
618 //TODO: Test reg |
baf4688901f2
Initial stab at LFO phase modulation
Mike Pavone <pavone@retrodev.com>
parents:
407
diff
changeset
|
619 case REG_LFO: |
baf4688901f2
Initial stab at LFO phase modulation
Mike Pavone <pavone@retrodev.com>
parents:
407
diff
changeset
|
620 if ((value & 0x8) && !context->lfo_enable) { |
baf4688901f2
Initial stab at LFO phase modulation
Mike Pavone <pavone@retrodev.com>
parents:
407
diff
changeset
|
621 printf("LFO Enabled, Freq: %d\n", value & 0x7); |
baf4688901f2
Initial stab at LFO phase modulation
Mike Pavone <pavone@retrodev.com>
parents:
407
diff
changeset
|
622 } |
baf4688901f2
Initial stab at LFO phase modulation
Mike Pavone <pavone@retrodev.com>
parents:
407
diff
changeset
|
623 context->lfo_enable = value & 0x8; |
baf4688901f2
Initial stab at LFO phase modulation
Mike Pavone <pavone@retrodev.com>
parents:
407
diff
changeset
|
624 if (!context->lfo_enable) { |
baf4688901f2
Initial stab at LFO phase modulation
Mike Pavone <pavone@retrodev.com>
parents:
407
diff
changeset
|
625 context->lfo_am_step = context->lfo_pm_step = 0; |
baf4688901f2
Initial stab at LFO phase modulation
Mike Pavone <pavone@retrodev.com>
parents:
407
diff
changeset
|
626 } |
baf4688901f2
Initial stab at LFO phase modulation
Mike Pavone <pavone@retrodev.com>
parents:
407
diff
changeset
|
627 context->lfo_freq = value & 0x7; |
448
e85a107e6ec0
Fix handling of key on in YM2612 core
Mike Pavone <pavone@retrodev.com>
parents:
424
diff
changeset
|
628 |
411
baf4688901f2
Initial stab at LFO phase modulation
Mike Pavone <pavone@retrodev.com>
parents:
407
diff
changeset
|
629 break; |
362 | 630 case REG_TIMERA_HIGH: |
631 context->timer_a_load &= 0x3; | |
632 context->timer_a_load |= value << 2; | |
633 break; | |
634 case REG_TIMERA_LOW: | |
635 context->timer_a_load &= 0xFFFC; | |
636 context->timer_a_load |= value & 0x3; | |
637 break; | |
638 case REG_TIMERB: | |
403 | 639 context->timer_b_load = value * 16; |
362 | 640 break; |
383
72933100c55c
Initial implementation of channel 3 special mode
Mike Pavone <pavone@retrodev.com>
parents:
382
diff
changeset
|
641 case REG_TIME_CTRL: { |
403 | 642 if (value & BIT_TIMERA_ENABLE && !(context->timer_control & BIT_TIMERA_ENABLE)) { |
643 context->timer_a = context->timer_a_load; | |
644 } | |
645 if (value & BIT_TIMERB_ENABLE && !(context->timer_control & BIT_TIMERB_ENABLE)) { | |
646 context->timer_b = context->timer_b_load; | |
647 } | |
648 context->timer_control = value & 0xF; | |
649 if (value & BIT_TIMERA_RESET) { | |
650 context->status &= ~BIT_STATUS_TIMERA; | |
651 } | |
652 if (value & BIT_TIMERB_RESET) { | |
653 context->status &= ~BIT_STATUS_TIMERB; | |
654 } | |
383
72933100c55c
Initial implementation of channel 3 special mode
Mike Pavone <pavone@retrodev.com>
parents:
382
diff
changeset
|
655 uint8_t old_mode = context->ch3_mode; |
72933100c55c
Initial implementation of channel 3 special mode
Mike Pavone <pavone@retrodev.com>
parents:
382
diff
changeset
|
656 context->ch3_mode = value & 0xC0; |
72933100c55c
Initial implementation of channel 3 special mode
Mike Pavone <pavone@retrodev.com>
parents:
382
diff
changeset
|
657 if (context->ch3_mode != old_mode) { |
72933100c55c
Initial implementation of channel 3 special mode
Mike Pavone <pavone@retrodev.com>
parents:
382
diff
changeset
|
658 ym_update_phase_inc(context, context->operators + 2*4, 2*4); |
72933100c55c
Initial implementation of channel 3 special mode
Mike Pavone <pavone@retrodev.com>
parents:
382
diff
changeset
|
659 ym_update_phase_inc(context, context->operators + 2*4+1, 2*4+1); |
72933100c55c
Initial implementation of channel 3 special mode
Mike Pavone <pavone@retrodev.com>
parents:
382
diff
changeset
|
660 ym_update_phase_inc(context, context->operators + 2*4+2, 2*4+2); |
72933100c55c
Initial implementation of channel 3 special mode
Mike Pavone <pavone@retrodev.com>
parents:
382
diff
changeset
|
661 } |
362 | 662 break; |
383
72933100c55c
Initial implementation of channel 3 special mode
Mike Pavone <pavone@retrodev.com>
parents:
382
diff
changeset
|
663 } |
362 | 664 case REG_KEY_ONOFF: { |
665 uint8_t channel = value & 0x7; | |
386
6e5c4f3ab0e2
Fix channel mapping in key on/off register
Mike Pavone <pavone@retrodev.com>
parents:
383
diff
changeset
|
666 if (channel != 3 && channel != 7) { |
6e5c4f3ab0e2
Fix channel mapping in key on/off register
Mike Pavone <pavone@retrodev.com>
parents:
383
diff
changeset
|
667 if (channel > 2) { |
6e5c4f3ab0e2
Fix channel mapping in key on/off register
Mike Pavone <pavone@retrodev.com>
parents:
383
diff
changeset
|
668 channel--; |
6e5c4f3ab0e2
Fix channel mapping in key on/off register
Mike Pavone <pavone@retrodev.com>
parents:
383
diff
changeset
|
669 } |
362 | 670 for (uint8_t op = channel * 4, bit = 0x10; op < (channel + 1) * 4; op++, bit <<= 1) { |
671 if (value & bit) { | |
448
e85a107e6ec0
Fix handling of key on in YM2612 core
Mike Pavone <pavone@retrodev.com>
parents:
424
diff
changeset
|
672 if (context->operators[op].env_phase == PHASE_RELEASE) |
e85a107e6ec0
Fix handling of key on in YM2612 core
Mike Pavone <pavone@retrodev.com>
parents:
424
diff
changeset
|
673 { |
e85a107e6ec0
Fix handling of key on in YM2612 core
Mike Pavone <pavone@retrodev.com>
parents:
424
diff
changeset
|
674 first_key_on = 1; |
e85a107e6ec0
Fix handling of key on in YM2612 core
Mike Pavone <pavone@retrodev.com>
parents:
424
diff
changeset
|
675 //printf("Key On for operator %d in channel %d\n", op, channel); |
e85a107e6ec0
Fix handling of key on in YM2612 core
Mike Pavone <pavone@retrodev.com>
parents:
424
diff
changeset
|
676 context->operators[op].phase_counter = 0; |
e85a107e6ec0
Fix handling of key on in YM2612 core
Mike Pavone <pavone@retrodev.com>
parents:
424
diff
changeset
|
677 context->operators[op].env_phase = PHASE_ATTACK; |
e85a107e6ec0
Fix handling of key on in YM2612 core
Mike Pavone <pavone@retrodev.com>
parents:
424
diff
changeset
|
678 } |
362 | 679 } else { |
680 //printf("Key Off for operator %d in channel %d\n", op, channel); | |
681 context->operators[op].env_phase = PHASE_RELEASE; | |
682 } | |
683 } | |
684 } | |
685 break; | |
686 } | |
687 case REG_DAC: | |
688 if (context->dac_enable) { | |
689 context->channels[5].output = (((int16_t)value) - 0x80) << 6; | |
396
09328dbe6700
Fix output of algorithm 4 and make some other minor YM2612 core improvements
Mike Pavone <pavone@retrodev.com>
parents:
386
diff
changeset
|
690 //printf("DAC Write %X(%d) @ %d\n", value, context->channels[5].output, context->current_cycle); |
362 | 691 } |
692 break; | |
693 case REG_DAC_ENABLE: | |
364
62177cc39049
Incredibly broken YM2612 support plus a fix to Z80 bus request
Mike Pavone <pavone@retrodev.com>
parents:
362
diff
changeset
|
694 //printf("DAC Enable: %X\n", value); |
362 | 695 context->dac_enable = value & 0x80; |
696 break; | |
697 } | |
698 } else if (context->selected_reg < 0xA0) { | |
699 //part | |
700 uint8_t op = context->selected_part ? (NUM_OPERATORS/2) : 0; | |
701 //channel in part | |
702 if ((context->selected_reg & 0x3) != 0x3) { | |
370
5f215603d001
Fix register to operator mapping. Fix rate table generation. Add TL to envelope value rather than using it as a limit for the attack phase.
Mike Pavone <pavone@retrodev.com>
parents:
369
diff
changeset
|
703 op += 4 * (context->selected_reg & 0x3) + ((context->selected_reg & 0xC) / 4); |
362 | 704 //printf("write targets operator %d (%d of channel %d)\n", op, op % 4, op / 4); |
705 ym_operator * operator = context->operators + op; | |
706 switch (context->selected_reg & 0xF0) | |
707 { | |
708 case REG_DETUNE_MULT: | |
709 operator->detune = value >> 4 & 0x7; | |
710 operator->multiple = value & 0xF; | |
711 ym_update_phase_inc(context, operator, op); | |
712 break; | |
713 case REG_TOTAL_LEVEL: | |
714 operator->total_level = (value & 0x7F) << 5; | |
715 break; | |
716 case REG_ATTACK_KS: | |
376 | 717 operator->key_scaling = 3 - (value >> 6); |
362 | 718 operator->rates[PHASE_ATTACK] = value & 0x1F; |
719 break; | |
720 case REG_DECAY_AM: | |
721 //TODO: AM flag for LFO | |
722 operator->rates[PHASE_DECAY] = value & 0x1F; | |
723 break; | |
724 case REG_SUSTAIN_RATE: | |
725 operator->rates[PHASE_SUSTAIN] = value & 0x1F; | |
726 break; | |
727 case REG_S_LVL_R_RATE: | |
728 operator->rates[PHASE_RELEASE] = (value & 0xF) << 1 | 1; | |
382
b904859964e5
Fix operator precedence bug with sustain level
Mike Pavone <pavone@retrodev.com>
parents:
381
diff
changeset
|
729 operator->sustain_level = (value & 0xF0) << 4; |
362 | 730 break; |
731 } | |
732 } | |
733 } else { | |
734 uint8_t channel = context->selected_reg & 0x3; | |
735 if (channel != 3) { | |
736 if (context->selected_part) { | |
737 channel += 3; | |
738 } | |
739 //printf("write targets channel %d\n", channel); | |
740 switch (context->selected_reg & 0xFC) | |
741 { | |
742 case REG_FNUM_LOW: | |
743 context->channels[channel].block = context->channels[channel].block_fnum_latch >> 3 & 0x7; | |
744 context->channels[channel].fnum = (context->channels[channel].block_fnum_latch & 0x7) << 8 | value; | |
745 context->channels[channel].keycode = context->channels[channel].block << 2 | fnum_to_keycode[context->channels[channel].fnum >> 7]; | |
746 ym_update_phase_inc(context, context->operators + channel*4, channel*4); | |
747 ym_update_phase_inc(context, context->operators + channel*4+1, channel*4+1); | |
748 ym_update_phase_inc(context, context->operators + channel*4+2, channel*4+2); | |
749 ym_update_phase_inc(context, context->operators + channel*4+3, channel*4+3); | |
750 break; | |
751 case REG_BLOCK_FNUM_H:{ | |
752 context->channels[channel].block_fnum_latch = value; | |
753 break; | |
754 } | |
383
72933100c55c
Initial implementation of channel 3 special mode
Mike Pavone <pavone@retrodev.com>
parents:
382
diff
changeset
|
755 case REG_FNUM_LOW_CH3: |
72933100c55c
Initial implementation of channel 3 special mode
Mike Pavone <pavone@retrodev.com>
parents:
382
diff
changeset
|
756 if (channel < 3) { |
72933100c55c
Initial implementation of channel 3 special mode
Mike Pavone <pavone@retrodev.com>
parents:
382
diff
changeset
|
757 context->ch3_supp[channel].block = context->ch3_supp[channel].block_fnum_latch >> 3 & 0x7; |
72933100c55c
Initial implementation of channel 3 special mode
Mike Pavone <pavone@retrodev.com>
parents:
382
diff
changeset
|
758 context->ch3_supp[channel].fnum = (context->ch3_supp[channel].block_fnum_latch & 0x7) << 8 | value; |
72933100c55c
Initial implementation of channel 3 special mode
Mike Pavone <pavone@retrodev.com>
parents:
382
diff
changeset
|
759 context->ch3_supp[channel].keycode = context->ch3_supp[channel].block << 2 | fnum_to_keycode[context->ch3_supp[channel].fnum >> 7]; |
72933100c55c
Initial implementation of channel 3 special mode
Mike Pavone <pavone@retrodev.com>
parents:
382
diff
changeset
|
760 if (context->ch3_mode) { |
72933100c55c
Initial implementation of channel 3 special mode
Mike Pavone <pavone@retrodev.com>
parents:
382
diff
changeset
|
761 ym_update_phase_inc(context, context->operators + 2*4 + channel, 2*4); |
72933100c55c
Initial implementation of channel 3 special mode
Mike Pavone <pavone@retrodev.com>
parents:
382
diff
changeset
|
762 } |
72933100c55c
Initial implementation of channel 3 special mode
Mike Pavone <pavone@retrodev.com>
parents:
382
diff
changeset
|
763 } |
72933100c55c
Initial implementation of channel 3 special mode
Mike Pavone <pavone@retrodev.com>
parents:
382
diff
changeset
|
764 break; |
72933100c55c
Initial implementation of channel 3 special mode
Mike Pavone <pavone@retrodev.com>
parents:
382
diff
changeset
|
765 case REG_BLOCK_FN_CH3: |
72933100c55c
Initial implementation of channel 3 special mode
Mike Pavone <pavone@retrodev.com>
parents:
382
diff
changeset
|
766 if (channel < 3) { |
72933100c55c
Initial implementation of channel 3 special mode
Mike Pavone <pavone@retrodev.com>
parents:
382
diff
changeset
|
767 context->ch3_supp[channel].block_fnum_latch = value; |
72933100c55c
Initial implementation of channel 3 special mode
Mike Pavone <pavone@retrodev.com>
parents:
382
diff
changeset
|
768 } |
72933100c55c
Initial implementation of channel 3 special mode
Mike Pavone <pavone@retrodev.com>
parents:
382
diff
changeset
|
769 break; |
362 | 770 case REG_ALG_FEEDBACK: |
771 context->channels[channel].algorithm = value & 0x7; | |
772 context->channels[channel].feedback = value >> 3 & 0x7; | |
773 break; | |
774 case REG_LR_AMS_PMS: | |
411
baf4688901f2
Initial stab at LFO phase modulation
Mike Pavone <pavone@retrodev.com>
parents:
407
diff
changeset
|
775 context->channels[channel].pms = (value & 0x7) * 32; |
362 | 776 context->channels[channel].ams = value >> 4 & 0x3; |
777 context->channels[channel].lr = value & 0xC0; | |
369
fc820ab1394b
Fix left/right enable default value
Mike Pavone <pavone@retrodev.com>
parents:
365
diff
changeset
|
778 //printf("Write of %X to LR_AMS_PMS reg for channel %d\n", value, channel); |
362 | 779 break; |
780 } | |
781 } | |
782 } | |
448
e85a107e6ec0
Fix handling of key on in YM2612 core
Mike Pavone <pavone@retrodev.com>
parents:
424
diff
changeset
|
783 |
362 | 784 context->write_cycle = context->current_cycle; |
374 | 785 context->status |= 0x80; |
288
a8ee7934a1f8
Add a YM2612 stub implementation with just timers and status registers so that games that depend on it can run.
Mike Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
786 } |
a8ee7934a1f8
Add a YM2612 stub implementation with just timers and status registers so that games that depend on it can run.
Mike Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
787 |
a8ee7934a1f8
Add a YM2612 stub implementation with just timers and status registers so that games that depend on it can run.
Mike Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
788 uint8_t ym_read_status(ym2612_context * context) |
a8ee7934a1f8
Add a YM2612 stub implementation with just timers and status registers so that games that depend on it can run.
Mike Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
789 { |
a8ee7934a1f8
Add a YM2612 stub implementation with just timers and status registers so that games that depend on it can run.
Mike Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
790 return context->status; |
a8ee7934a1f8
Add a YM2612 stub implementation with just timers and status registers so that games that depend on it can run.
Mike Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
791 } |
a8ee7934a1f8
Add a YM2612 stub implementation with just timers and status registers so that games that depend on it can run.
Mike Pavone <pavone@retrodev.com>
parents:
diff
changeset
|
792 |