Mercurial > repos > blastem
annotate ym2612.c @ 406:b1bc1947d949
Fix modulation condition for operator 2
author | Mike Pavone <pavone@retrodev.com> |
---|---|
date | Sun, 16 Jun 2013 13:42:13 -0700 |
parents | f0a3f86595ae |
children | c3abc4ada43d |
rev | line source |
---|---|
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
|
1 #include <string.h> |
359
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
2 #include <math.h> |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
3 #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
|
4 #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
|
5 #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
|
6 #include "render.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
|
7 |
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
|
8 //#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
|
9 #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
|
10 #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
|
11 #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
|
12 #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
|
13 #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
|
14 #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
|
15 #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
|
16 |
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
|
17 #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
|
18 #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
|
19 |
362 | 20 enum { |
21 REG_TIMERA_HIGH = 0x24, | |
22 REG_TIMERA_LOW, | |
23 REG_TIMERB, | |
24 REG_TIME_CTRL, | |
25 REG_KEY_ONOFF, | |
26 REG_DAC = 0x2A, | |
27 REG_DAC_ENABLE, | |
359
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
28 |
362 | 29 REG_DETUNE_MULT = 0x30, |
30 REG_TOTAL_LEVEL = 0x40, | |
31 REG_ATTACK_KS = 0x50, | |
32 REG_DECAY_AM = 0x60, | |
33 REG_SUSTAIN_RATE = 0x70, | |
34 REG_S_LVL_R_RATE = 0x80, | |
359
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
35 |
362 | 36 REG_FNUM_LOW = 0xA0, |
37 REG_BLOCK_FNUM_H = 0xA4, | |
38 REG_FNUM_LOW_CH3 = 0xA8, | |
39 REG_BLOCK_FN_CH3 = 0xAC, | |
40 REG_ALG_FEEDBACK = 0xB0, | |
41 REG_LR_AMS_PMS = 0xB4 | |
42 }; | |
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
|
43 |
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
|
44 #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
|
45 #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
|
46 #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
|
47 #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
|
48 #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
|
49 #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
|
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_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
|
52 #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
|
53 |
359
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
54 enum { |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
55 PHASE_ATTACK, |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
56 PHASE_DECAY, |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
57 PHASE_SUSTAIN, |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
58 PHASE_RELEASE |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
59 }; |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
60 |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
61 uint8_t did_tbl_init = 0; |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
62 //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
|
63 //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
|
64 //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
|
65 #define SINE_TABLE_SIZE 512 |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
66 uint16_t sine_table[SINE_TABLE_SIZE]; |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
67 //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
|
68 //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
|
69 //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
|
70 #define POW_TABLE_SIZE (1 << 13) |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
71 uint16_t pow_table[POW_TABLE_SIZE]; |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
72 |
362 | 73 uint16_t rate_table_base[] = { |
74 //main portion | |
75 0,1,0,1,0,1,0,1, | |
76 0,1,0,1,1,1,0,1, | |
77 0,1,1,1,0,1,1,1, | |
78 0,1,1,1,1,1,1,1, | |
79 //top end | |
80 1,1,1,1,1,1,1,1, | |
81 1,1,1,2,1,1,1,2, | |
82 1,2,1,2,1,2,1,2, | |
83 1,2,2,2,1,2,2,2, | |
84 }; | |
85 | |
365
3ba3b6656fff
Actually save the shifted phase inc after applying the block shift
Mike Pavone <pavone@retrodev.com>
parents:
364
diff
changeset
|
86 uint16_t rate_table[64*8]; |
362 | 87 |
88 #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
|
89 #define YM_DIVIDER 2 |
374 | 90 #define CYCLE_NEVER 0xFFFFFFFF |
359
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
91 |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
92 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
|
93 { |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
94 return value * (1 << dec_bits) + 0.5; |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
95 } |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
96 |
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
|
97 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
|
98 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
|
99 |
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
|
100 void ym_init(ym2612_context * context, uint32_t sample_rate, uint32_t master_clock, uint32_t clock_div, uint32_t sample_limit) |
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
|
101 { |
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
|
102 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
|
103 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
|
104 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
|
105 context->back_buffer = malloc(sizeof(*context->audio_buffer) * sample_limit*2); |
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
|
106 context->buffer_inc = ((double)sample_rate / (double)master_clock) * clock_div * 6; |
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
|
107 context->clock_inc = clock_div * 6; |
364
62177cc39049
Incredibly broken YM2612 support plus a fix to Z80 bus request
Mike Pavone <pavone@retrodev.com>
parents:
362
diff
changeset
|
108 context->sample_limit = sample_limit*2; |
374 | 109 context->write_cycle = CYCLE_NEVER; |
362 | 110 for (int i = 0; i < NUM_OPERATORS; i++) { |
111 context->operators[i].envelope = MAX_ENVELOPE; | |
112 context->operators[i].env_phase = PHASE_RELEASE; | |
113 } | |
369
fc820ab1394b
Fix left/right enable default value
Mike Pavone <pavone@retrodev.com>
parents:
365
diff
changeset
|
114 //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
|
115 for (int i = 0; i < NUM_CHANNELS; i++) { |
fc820ab1394b
Fix left/right enable default value
Mike Pavone <pavone@retrodev.com>
parents:
365
diff
changeset
|
116 context->channels[i].lr = 0xC0; |
fc820ab1394b
Fix left/right enable default value
Mike Pavone <pavone@retrodev.com>
parents:
365
diff
changeset
|
117 } |
359
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
118 if (!did_tbl_init) { |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
119 //populate sine table |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
120 for (int32_t i = 0; i < 512; i++) { |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
121 double sine = sin( ((double)(i*2+1) / SINE_TABLE_SIZE) * M_PI_2 ); |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
122 |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
123 //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
|
124 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
|
125 } |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
126 //populate power table |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
127 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
|
128 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
|
129 int32_t tmp = round_fixed_point(linear, 11); |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
130 int32_t shift = (i >> 8) - 2; |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
131 if (shift < 0) { |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
132 tmp <<= 0-shift; |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
133 } else { |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
134 tmp >>= shift; |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
135 } |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
136 pow_table[i] = tmp; |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
137 } |
362 | 138 //populate envelope generator rate table, from small base table |
139 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
|
140 for (int cycle = 0; cycle < 8; cycle++) { |
362 | 141 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
|
142 if (rate < 2) { |
362 | 143 value = 0; |
365
3ba3b6656fff
Actually save the shifted phase inc after applying the block shift
Mike Pavone <pavone@retrodev.com>
parents:
364
diff
changeset
|
144 } else if (rate >= 60) { |
362 | 145 value = 8; |
365
3ba3b6656fff
Actually save the shifted phase inc after applying the block shift
Mike Pavone <pavone@retrodev.com>
parents:
364
diff
changeset
|
146 } 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
|
147 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
|
148 } else if (rate < 48) { |
362 | 149 value = rate_table_base[(rate & 0x3) * 8 + cycle]; |
150 } 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
|
151 value = rate_table_base[32 + (rate & 0x3) * 8 + cycle] << ((rate - 48) >> 2); |
362 | 152 } |
365
3ba3b6656fff
Actually save the shifted phase inc after applying the block shift
Mike Pavone <pavone@retrodev.com>
parents:
364
diff
changeset
|
153 rate_table[rate * 8 + cycle] = value; |
362 | 154 } |
155 } | |
359
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
156 } |
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
|
157 } |
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
|
158 |
377 | 159 #define YM_VOLUME_DIVIDER 2 |
381
7815ebbbd705
Fix modulation shift value
Mike Pavone <pavone@retrodev.com>
parents:
380
diff
changeset
|
160 #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
|
161 |
403 | 162 #define TIMER_A_MAX 1023 |
163 #define TIMER_B_MAX (255*16) | |
164 | |
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
|
165 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
|
166 { |
362 | 167 //printf("Running YM2612 from cycle %d to cycle %d\n", context->current_cycle, to_cycle); |
168 //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
|
169 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
|
170 //Update timers at beginning of 144 cycle period |
403 | 171 if (!context->current_op) { |
172 if (context->timer_control & BIT_TIMERA_ENABLE) { | |
173 if (context->timer_a != TIMER_A_MAX) { | |
174 context->timer_a++; | |
175 } else { | |
176 if (context->timer_control & BIT_TIMERA_OVEREN) { | |
177 context->status |= BIT_STATUS_TIMERA; | |
178 } | |
179 context->timer_a = context->timer_a_load; | |
359
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
180 } |
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
|
181 } |
362 | 182 if (context->timer_control & BIT_TIMERB_ENABLE) { |
403 | 183 if (context->timer_b != TIMER_B_MAX) { |
184 context->timer_b++; | |
185 } else { | |
186 if (context->timer_control & BIT_TIMERB_OVEREN) { | |
187 context->status |= BIT_STATUS_TIMERB; | |
359
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
188 } |
403 | 189 context->timer_b = context->timer_b_load; |
359
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
190 } |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
191 } |
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
|
192 } |
359
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
193 //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
|
194 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
|
195 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
|
196 uint32_t op = context->current_env_op; |
362 | 197 ym_operator * operator = context->operators + op; |
198 ym_channel * channel = context->channels + op/4; | |
359
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
199 uint8_t rate; |
362 | 200 for(;;) { |
201 rate = operator->rates[operator->env_phase]; | |
202 if (rate) { | |
203 uint8_t ks = channel->keycode >> operator->key_scaling;; | |
204 rate = rate*2 + ks; | |
205 if (rate > 63) { | |
206 rate = 63; | |
207 } | |
208 } | |
209 //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
|
210 //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
|
211 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
|
212 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
|
213 operator->envelope = 0; |
362 | 214 } else { |
215 break; | |
216 } | |
217 } | |
218 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
|
219 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
|
220 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
|
221 } |
362 | 222 if (!(env_cyc & ((1 << cycle_shift) - 1))) { |
223 uint32_t update_cycle = env_cyc >> cycle_shift & 0x7; | |
224 //envelope value is 10-bits, but it will be used as a 4.8 value | |
225 uint16_t envelope_inc = rate_table[rate * 8 + update_cycle] << 2; | |
226 if (operator->env_phase == PHASE_ATTACK) { | |
227 //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
|
228 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
|
229 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
|
230 } |
362 | 231 operator->envelope += (~operator->envelope * envelope_inc) >> 4; |
232 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
|
233 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
|
234 operator->envelope = 0; |
362 | 235 operator->env_phase = PHASE_DECAY; |
236 } | |
237 } 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
|
238 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
|
239 dfprintf(debug_file, "Changing op %d envelope %d by %d in %s phase\n", op, 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
|
240 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
|
241 } |
362 | 242 operator->envelope += envelope_inc; |
243 //clamp to max attenuation value | |
244 if (operator->envelope > MAX_ENVELOPE) { | |
245 operator->envelope = MAX_ENVELOPE; | |
246 } | |
247 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
|
248 //operator->envelope = operator->sustain_level; |
362 | 249 operator->env_phase = PHASE_SUSTAIN; |
250 } | |
251 } | |
364
62177cc39049
Incredibly broken YM2612 support plus a fix to Z80 bus request
Mike Pavone <pavone@retrodev.com>
parents:
362
diff
changeset
|
252 } |
62177cc39049
Incredibly broken YM2612 support plus a fix to Z80 bus request
Mike Pavone <pavone@retrodev.com>
parents:
362
diff
changeset
|
253 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
|
254 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
|
255 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
|
256 context->env_counter++; |
362 | 257 } |
258 } | |
259 | |
260 //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
|
261 uint32_t channel = context->current_op / 4; |
362 | 262 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
|
263 uint32_t op = context->current_op; |
362 | 264 //printf("updating operator %d of channel %d\n", op, channel); |
265 ym_operator * operator = context->operators + op; | |
266 ym_channel * chan = context->channels + channel; | |
267 //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
|
268 uint16_t phase = operator->phase_counter >> 10 & 0x3FF; |
362 | 269 operator->phase_counter += operator->phase_inc; |
371
0f8a759f1ff4
Use signed ints for things that represent signed values in YM2612 core
Mike Pavone <pavone@retrodev.com>
parents:
370
diff
changeset
|
270 int16_t mod = 0; |
362 | 271 switch (op % 4) |
359
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
272 { |
362 | 273 case 0://Operator 1 |
377 | 274 if (chan->feedback) { |
378
92947faa258a
Adjust shift for feedback
Mike Pavone <pavone@retrodev.com>
parents:
377
diff
changeset
|
275 mod = operator->output >> (9-chan->feedback); |
377 | 276 } |
359
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
277 break; |
362 | 278 case 1://Operator 3 |
279 switch(chan->algorithm) | |
280 { | |
281 case 0: | |
282 case 2: | |
283 //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
|
284 mod = context->operators[op+1].output >> YM_MOD_SHIFT; |
362 | 285 break; |
286 case 1: | |
287 //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
|
288 mod = (context->operators[op-1].output + context->operators[op+1].output) >> YM_MOD_SHIFT; |
362 | 289 break; |
290 case 5: | |
291 //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
|
292 mod = context->operators[op-1].output >> YM_MOD_SHIFT; |
362 | 293 } |
294 break; | |
295 case 2://Operator 2 | |
406
b1bc1947d949
Fix modulation condition for operator 2
Mike Pavone <pavone@retrodev.com>
parents:
403
diff
changeset
|
296 if (chan->algorithm != 1 && chan->algorithm != 2 && chan->algorithm != 7) { |
362 | 297 //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
|
298 mod = context->operators[op-2].output >> YM_MOD_SHIFT; |
362 | 299 } |
359
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
300 break; |
362 | 301 case 3://Operator 4 |
302 switch(chan->algorithm) | |
303 { | |
304 case 0: | |
305 case 1: | |
306 case 4: | |
307 //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
|
308 mod = context->operators[op-2].output >> YM_MOD_SHIFT; |
362 | 309 break; |
310 case 2: | |
311 //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
|
312 mod = (context->operators[op-3].output + context->operators[op-2].output) >> YM_MOD_SHIFT; |
362 | 313 break; |
314 case 3: | |
315 //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
|
316 mod = (context->operators[op-1].output + context->operators[op-2].output) >> YM_MOD_SHIFT; |
362 | 317 break; |
318 case 5: | |
319 //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
|
320 mod = context->operators[op-3].output >> YM_MOD_SHIFT; |
362 | 321 break; |
322 } | |
359
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
323 break; |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
324 } |
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
|
325 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
|
326 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
|
327 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
|
328 } |
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
|
329 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
|
330 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
|
331 } |
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
|
332 phase += mod; |
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
|
333 |
371
0f8a759f1ff4
Use signed ints for things that represent signed values in YM2612 core
Mike Pavone <pavone@retrodev.com>
parents:
370
diff
changeset
|
334 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
|
335 if (phase & 0x200) { |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
336 output = -output; |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
337 } |
362 | 338 operator->output = output; |
359
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
339 //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
|
340 if (op % 4 == 3) { |
362 | 341 if (chan->algorithm < 4) { |
342 chan->output = operator->output; | |
343 } 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
|
344 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
|
345 } else { |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
346 output = 0; |
362 | 347 for (uint32_t op = ((chan->algorithm == 7) ? 0 : 1) + channel*4; op < (channel+1)*4; op++) { |
348 output += context->operators[op].output; | |
359
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
349 } |
362 | 350 chan->output = output; |
359
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
351 } |
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
|
352 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
|
353 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
|
354 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
|
355 value |= 0xC000; |
0f8a759f1ff4
Use signed ints for things that represent signed values in YM2612 core
Mike Pavone <pavone@retrodev.com>
parents:
370
diff
changeset
|
356 } |
0f8a759f1ff4
Use signed ints for things that represent signed values in YM2612 core
Mike Pavone <pavone@retrodev.com>
parents:
370
diff
changeset
|
357 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
|
358 } |
359
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
359 } |
362 | 360 //puts("operator update done"); |
359
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
361 } |
364
62177cc39049
Incredibly broken YM2612 support plus a fix to Z80 bus request
Mike Pavone <pavone@retrodev.com>
parents:
362
diff
changeset
|
362 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
|
363 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
|
364 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
|
365 context->current_op = 0; |
09328dbe6700
Fix output of algorithm 4 and make some other minor YM2612 core improvements
Mike Pavone <pavone@retrodev.com>
parents:
386
diff
changeset
|
366 if (context->buffer_fraction > 1.0) { |
09328dbe6700
Fix output of algorithm 4 and make some other minor YM2612 core improvements
Mike Pavone <pavone@retrodev.com>
parents:
386
diff
changeset
|
367 context->buffer_fraction -= 1.0; |
09328dbe6700
Fix output of algorithm 4 and make some other minor YM2612 core improvements
Mike Pavone <pavone@retrodev.com>
parents:
386
diff
changeset
|
368 context->audio_buffer[context->buffer_pos] = 0; |
09328dbe6700
Fix output of algorithm 4 and make some other minor YM2612 core improvements
Mike Pavone <pavone@retrodev.com>
parents:
386
diff
changeset
|
369 context->audio_buffer[context->buffer_pos + 1] = 0; |
09328dbe6700
Fix output of algorithm 4 and make some other minor YM2612 core improvements
Mike Pavone <pavone@retrodev.com>
parents:
386
diff
changeset
|
370 for (int i = 0; i < NUM_CHANNELS; i++) { |
09328dbe6700
Fix output of algorithm 4 and make some other minor YM2612 core improvements
Mike Pavone <pavone@retrodev.com>
parents:
386
diff
changeset
|
371 int16_t value = context->channels[i].output & 0x3FE0; |
09328dbe6700
Fix output of algorithm 4 and make some other minor YM2612 core improvements
Mike Pavone <pavone@retrodev.com>
parents:
386
diff
changeset
|
372 if (value & 0x2000) { |
09328dbe6700
Fix output of algorithm 4 and make some other minor YM2612 core improvements
Mike Pavone <pavone@retrodev.com>
parents:
386
diff
changeset
|
373 value |= 0xC000; |
09328dbe6700
Fix output of algorithm 4 and make some other minor YM2612 core improvements
Mike Pavone <pavone@retrodev.com>
parents:
386
diff
changeset
|
374 } |
09328dbe6700
Fix output of algorithm 4 and make some other minor YM2612 core improvements
Mike Pavone <pavone@retrodev.com>
parents:
386
diff
changeset
|
375 if (context->channels[i].lr & 0x80) { |
09328dbe6700
Fix output of algorithm 4 and make some other minor YM2612 core improvements
Mike Pavone <pavone@retrodev.com>
parents:
386
diff
changeset
|
376 context->audio_buffer[context->buffer_pos] += value / YM_VOLUME_DIVIDER; |
09328dbe6700
Fix output of algorithm 4 and make some other minor YM2612 core improvements
Mike Pavone <pavone@retrodev.com>
parents:
386
diff
changeset
|
377 } |
09328dbe6700
Fix output of algorithm 4 and make some other minor YM2612 core improvements
Mike Pavone <pavone@retrodev.com>
parents:
386
diff
changeset
|
378 if (context->channels[i].lr & 0x40) { |
09328dbe6700
Fix output of algorithm 4 and make some other minor YM2612 core improvements
Mike Pavone <pavone@retrodev.com>
parents:
386
diff
changeset
|
379 context->audio_buffer[context->buffer_pos+1] += value / YM_VOLUME_DIVIDER; |
09328dbe6700
Fix output of algorithm 4 and make some other minor YM2612 core improvements
Mike Pavone <pavone@retrodev.com>
parents:
386
diff
changeset
|
380 } |
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
|
381 } |
396
09328dbe6700
Fix output of algorithm 4 and make some other minor YM2612 core improvements
Mike Pavone <pavone@retrodev.com>
parents:
386
diff
changeset
|
382 context->buffer_pos += 2; |
09328dbe6700
Fix output of algorithm 4 and make some other minor YM2612 core improvements
Mike Pavone <pavone@retrodev.com>
parents:
386
diff
changeset
|
383 if (context->buffer_pos == context->sample_limit) { |
09328dbe6700
Fix output of algorithm 4 and make some other minor YM2612 core improvements
Mike Pavone <pavone@retrodev.com>
parents:
386
diff
changeset
|
384 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
|
385 } |
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
|
386 } |
364
62177cc39049
Incredibly broken YM2612 support plus a fix to Z80 bus request
Mike Pavone <pavone@retrodev.com>
parents:
362
diff
changeset
|
387 } |
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
|
388 } |
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
|
389 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
|
390 context->status &= 0x7F; |
374 | 391 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
|
392 } |
362 | 393 //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
|
394 } |
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
|
395 |
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
|
396 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
|
397 { |
364
62177cc39049
Incredibly broken YM2612 support plus a fix to Z80 bus request
Mike Pavone <pavone@retrodev.com>
parents:
362
diff
changeset
|
398 //printf("address_write_part1: %X\n", address); |
362 | 399 context->selected_reg = address; |
400 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
|
401 } |
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
|
402 |
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
|
403 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
|
404 { |
364
62177cc39049
Incredibly broken YM2612 support plus a fix to Z80 bus request
Mike Pavone <pavone@retrodev.com>
parents:
362
diff
changeset
|
405 //printf("address_write_part2: %X\n", address); |
362 | 406 context->selected_reg = address; |
407 context->selected_part = 1; | |
408 } | |
409 | |
410 uint8_t fnum_to_keycode[] = { | |
411 //F11 = 0 | |
412 0,0,0,0,0,0,0,1, | |
413 //F11 = 1 | |
414 2,3,3,3,3,3,3,3 | |
415 }; | |
416 | |
417 //table courtesy of Nemesis | |
418 uint32_t detune_table[][4] = { | |
419 {0, 0, 1, 2}, //0 (0x00) | |
420 {0, 0, 1, 2}, //1 (0x01) | |
421 {0, 0, 1, 2}, //2 (0x02) | |
422 {0, 0, 1, 2}, //3 (0x03) | |
423 {0, 1, 2, 2}, //4 (0x04) | |
424 {0, 1, 2, 3}, //5 (0x05) | |
425 {0, 1, 2, 3}, //6 (0x06) | |
426 {0, 1, 2, 3}, //7 (0x07) | |
427 {0, 1, 2, 4}, //8 (0x08) | |
428 {0, 1, 3, 4}, //9 (0x09) | |
429 {0, 1, 3, 4}, //10 (0x0A) | |
430 {0, 1, 3, 5}, //11 (0x0B) | |
431 {0, 2, 4, 5}, //12 (0x0C) | |
432 {0, 2, 4, 6}, //13 (0x0D) | |
433 {0, 2, 4, 6}, //14 (0x0E) | |
434 {0, 2, 5, 7}, //15 (0x0F) | |
435 {0, 2, 5, 8}, //16 (0x10) | |
436 {0, 3, 6, 8}, //17 (0x11) | |
437 {0, 3, 6, 9}, //18 (0x12) | |
438 {0, 3, 7,10}, //19 (0x13) | |
439 {0, 4, 8,11}, //20 (0x14) | |
440 {0, 4, 8,12}, //21 (0x15) | |
441 {0, 4, 9,13}, //22 (0x16) | |
442 {0, 5,10,14}, //23 (0x17) | |
443 {0, 5,11,16}, //24 (0x18) | |
444 {0, 6,12,17}, //25 (0x19) | |
445 {0, 6,13,19}, //26 (0x1A) | |
446 {0, 7,14,20}, //27 (0x1B) | |
447 {0, 8,16,22}, //28 (0x1C) | |
448 {0, 8,16,22}, //29 (0x1D) | |
449 {0, 8,16,22}, //30 (0x1E) | |
450 {0, 8,16,22} | |
451 }; //31 (0x1F) | |
452 | |
453 void ym_update_phase_inc(ym2612_context * context, ym_operator * operator, uint32_t op) | |
454 { | |
455 uint32_t chan_num = op / 4; | |
456 //printf("ym_update_phase_inc | channel: %d, op: %d\n", chan_num, op); | |
457 //base frequency | |
458 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
|
459 uint32_t inc, detune; |
72933100c55c
Initial implementation of channel 3 special mode
Mike Pavone <pavone@retrodev.com>
parents:
382
diff
changeset
|
460 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
|
461 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
|
462 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
|
463 inc >>= 1; |
72933100c55c
Initial implementation of channel 3 special mode
Mike Pavone <pavone@retrodev.com>
parents:
382
diff
changeset
|
464 } else { |
72933100c55c
Initial implementation of channel 3 special mode
Mike Pavone <pavone@retrodev.com>
parents:
382
diff
changeset
|
465 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
|
466 } |
72933100c55c
Initial implementation of channel 3 special mode
Mike Pavone <pavone@retrodev.com>
parents:
382
diff
changeset
|
467 //detune |
72933100c55c
Initial implementation of channel 3 special mode
Mike Pavone <pavone@retrodev.com>
parents:
382
diff
changeset
|
468 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
|
469 } else { |
383
72933100c55c
Initial implementation of channel 3 special mode
Mike Pavone <pavone@retrodev.com>
parents:
382
diff
changeset
|
470 inc = channel->fnum; |
72933100c55c
Initial implementation of channel 3 special mode
Mike Pavone <pavone@retrodev.com>
parents:
382
diff
changeset
|
471 if (!channel->block) { |
72933100c55c
Initial implementation of channel 3 special mode
Mike Pavone <pavone@retrodev.com>
parents:
382
diff
changeset
|
472 inc >>= 1; |
72933100c55c
Initial implementation of channel 3 special mode
Mike Pavone <pavone@retrodev.com>
parents:
382
diff
changeset
|
473 } else { |
72933100c55c
Initial implementation of channel 3 special mode
Mike Pavone <pavone@retrodev.com>
parents:
382
diff
changeset
|
474 inc <<= (channel->block-1); |
72933100c55c
Initial implementation of channel 3 special mode
Mike Pavone <pavone@retrodev.com>
parents:
382
diff
changeset
|
475 } |
72933100c55c
Initial implementation of channel 3 special mode
Mike Pavone <pavone@retrodev.com>
parents:
382
diff
changeset
|
476 //detune |
72933100c55c
Initial implementation of channel 3 special mode
Mike Pavone <pavone@retrodev.com>
parents:
382
diff
changeset
|
477 detune = detune_table[channel->keycode][operator->detune & 0x3]; |
72933100c55c
Initial implementation of channel 3 special mode
Mike Pavone <pavone@retrodev.com>
parents:
382
diff
changeset
|
478 } |
362 | 479 if (operator->detune & 0x40) { |
480 inc -= detune; | |
481 //this can underflow, mask to 17-bit result | |
482 inc &= 0x1FFFF; | |
483 } else { | |
484 inc += detune; | |
485 } | |
486 //multiple | |
487 if (operator->multiple) { | |
488 inc *= operator->multiple; | |
489 } else { | |
490 //0.5 | |
491 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
|
492 } |
365
3ba3b6656fff
Actually save the shifted phase inc after applying the block shift
Mike Pavone <pavone@retrodev.com>
parents:
364
diff
changeset
|
493 //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
|
494 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
|
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 |
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 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
|
498 { |
362 | 499 if (context->selected_reg < 0x21 || context->selected_reg > 0xB6 || (context->selected_reg < 0x30 && context->selected_part)) { |
500 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
|
501 } |
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
|
502 dfprintf(debug_file, "write of %X to reg %X in part %d\n", value, context->selected_reg, context->selected_part+1); |
362 | 503 if (context->selected_reg < 0x30) { |
504 //Shared regs | |
505 switch (context->selected_reg) | |
506 { | |
507 //TODO: Test reg and LFO | |
508 case REG_TIMERA_HIGH: | |
509 context->timer_a_load &= 0x3; | |
510 context->timer_a_load |= value << 2; | |
511 break; | |
512 case REG_TIMERA_LOW: | |
513 context->timer_a_load &= 0xFFFC; | |
514 context->timer_a_load |= value & 0x3; | |
515 break; | |
516 case REG_TIMERB: | |
403 | 517 context->timer_b_load = value * 16; |
362 | 518 break; |
383
72933100c55c
Initial implementation of channel 3 special mode
Mike Pavone <pavone@retrodev.com>
parents:
382
diff
changeset
|
519 case REG_TIME_CTRL: { |
403 | 520 if (value & BIT_TIMERA_ENABLE && !(context->timer_control & BIT_TIMERA_ENABLE)) { |
521 context->timer_a = context->timer_a_load; | |
522 } | |
523 if (value & BIT_TIMERB_ENABLE && !(context->timer_control & BIT_TIMERB_ENABLE)) { | |
524 context->timer_b = context->timer_b_load; | |
525 } | |
526 context->timer_control = value & 0xF; | |
527 if (value & BIT_TIMERA_RESET) { | |
528 context->status &= ~BIT_STATUS_TIMERA; | |
529 } | |
530 if (value & BIT_TIMERB_RESET) { | |
531 context->status &= ~BIT_STATUS_TIMERB; | |
532 } | |
383
72933100c55c
Initial implementation of channel 3 special mode
Mike Pavone <pavone@retrodev.com>
parents:
382
diff
changeset
|
533 uint8_t old_mode = context->ch3_mode; |
72933100c55c
Initial implementation of channel 3 special mode
Mike Pavone <pavone@retrodev.com>
parents:
382
diff
changeset
|
534 context->ch3_mode = value & 0xC0; |
72933100c55c
Initial implementation of channel 3 special mode
Mike Pavone <pavone@retrodev.com>
parents:
382
diff
changeset
|
535 if (context->ch3_mode != old_mode) { |
72933100c55c
Initial implementation of channel 3 special mode
Mike Pavone <pavone@retrodev.com>
parents:
382
diff
changeset
|
536 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
|
537 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
|
538 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
|
539 } |
362 | 540 break; |
383
72933100c55c
Initial implementation of channel 3 special mode
Mike Pavone <pavone@retrodev.com>
parents:
382
diff
changeset
|
541 } |
362 | 542 case REG_KEY_ONOFF: { |
543 uint8_t channel = value & 0x7; | |
386
6e5c4f3ab0e2
Fix channel mapping in key on/off register
Mike Pavone <pavone@retrodev.com>
parents:
383
diff
changeset
|
544 if (channel != 3 && channel != 7) { |
6e5c4f3ab0e2
Fix channel mapping in key on/off register
Mike Pavone <pavone@retrodev.com>
parents:
383
diff
changeset
|
545 if (channel > 2) { |
6e5c4f3ab0e2
Fix channel mapping in key on/off register
Mike Pavone <pavone@retrodev.com>
parents:
383
diff
changeset
|
546 channel--; |
6e5c4f3ab0e2
Fix channel mapping in key on/off register
Mike Pavone <pavone@retrodev.com>
parents:
383
diff
changeset
|
547 } |
362 | 548 for (uint8_t op = channel * 4, bit = 0x10; op < (channel + 1) * 4; op++, bit <<= 1) { |
549 if (value & bit) { | |
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
|
550 first_key_on = 1; |
362 | 551 //printf("Key On for operator %d in channel %d\n", op, channel); |
552 context->operators[op].phase_counter = 0; | |
553 context->operators[op].env_phase = PHASE_ATTACK; | |
554 context->operators[op].envelope = MAX_ENVELOPE; | |
555 } else { | |
556 //printf("Key Off for operator %d in channel %d\n", op, channel); | |
557 context->operators[op].env_phase = PHASE_RELEASE; | |
558 } | |
559 } | |
560 } | |
561 break; | |
562 } | |
563 case REG_DAC: | |
564 if (context->dac_enable) { | |
565 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
|
566 //printf("DAC Write %X(%d) @ %d\n", value, context->channels[5].output, context->current_cycle); |
362 | 567 } |
568 break; | |
569 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
|
570 //printf("DAC Enable: %X\n", value); |
362 | 571 context->dac_enable = value & 0x80; |
572 break; | |
573 } | |
574 } else if (context->selected_reg < 0xA0) { | |
575 //part | |
576 uint8_t op = context->selected_part ? (NUM_OPERATORS/2) : 0; | |
577 //channel in part | |
578 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
|
579 op += 4 * (context->selected_reg & 0x3) + ((context->selected_reg & 0xC) / 4); |
362 | 580 //printf("write targets operator %d (%d of channel %d)\n", op, op % 4, op / 4); |
581 ym_operator * operator = context->operators + op; | |
582 switch (context->selected_reg & 0xF0) | |
583 { | |
584 case REG_DETUNE_MULT: | |
585 operator->detune = value >> 4 & 0x7; | |
586 operator->multiple = value & 0xF; | |
587 ym_update_phase_inc(context, operator, op); | |
588 break; | |
589 case REG_TOTAL_LEVEL: | |
590 operator->total_level = (value & 0x7F) << 5; | |
591 break; | |
592 case REG_ATTACK_KS: | |
376 | 593 operator->key_scaling = 3 - (value >> 6); |
362 | 594 operator->rates[PHASE_ATTACK] = value & 0x1F; |
595 break; | |
596 case REG_DECAY_AM: | |
597 //TODO: AM flag for LFO | |
598 operator->rates[PHASE_DECAY] = value & 0x1F; | |
599 break; | |
600 case REG_SUSTAIN_RATE: | |
601 operator->rates[PHASE_SUSTAIN] = value & 0x1F; | |
602 break; | |
603 case REG_S_LVL_R_RATE: | |
604 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
|
605 operator->sustain_level = (value & 0xF0) << 4; |
362 | 606 break; |
607 } | |
608 } | |
609 } else { | |
610 uint8_t channel = context->selected_reg & 0x3; | |
611 if (channel != 3) { | |
612 if (context->selected_part) { | |
613 channel += 3; | |
614 } | |
615 //printf("write targets channel %d\n", channel); | |
616 switch (context->selected_reg & 0xFC) | |
617 { | |
618 case REG_FNUM_LOW: | |
619 context->channels[channel].block = context->channels[channel].block_fnum_latch >> 3 & 0x7; | |
620 context->channels[channel].fnum = (context->channels[channel].block_fnum_latch & 0x7) << 8 | value; | |
621 context->channels[channel].keycode = context->channels[channel].block << 2 | fnum_to_keycode[context->channels[channel].fnum >> 7]; | |
622 ym_update_phase_inc(context, context->operators + channel*4, channel*4); | |
623 ym_update_phase_inc(context, context->operators + channel*4+1, channel*4+1); | |
624 ym_update_phase_inc(context, context->operators + channel*4+2, channel*4+2); | |
625 ym_update_phase_inc(context, context->operators + channel*4+3, channel*4+3); | |
626 break; | |
627 case REG_BLOCK_FNUM_H:{ | |
628 context->channels[channel].block_fnum_latch = value; | |
629 break; | |
630 } | |
383
72933100c55c
Initial implementation of channel 3 special mode
Mike Pavone <pavone@retrodev.com>
parents:
382
diff
changeset
|
631 case REG_FNUM_LOW_CH3: |
72933100c55c
Initial implementation of channel 3 special mode
Mike Pavone <pavone@retrodev.com>
parents:
382
diff
changeset
|
632 if (channel < 3) { |
72933100c55c
Initial implementation of channel 3 special mode
Mike Pavone <pavone@retrodev.com>
parents:
382
diff
changeset
|
633 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
|
634 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
|
635 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
|
636 if (context->ch3_mode) { |
72933100c55c
Initial implementation of channel 3 special mode
Mike Pavone <pavone@retrodev.com>
parents:
382
diff
changeset
|
637 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
|
638 } |
72933100c55c
Initial implementation of channel 3 special mode
Mike Pavone <pavone@retrodev.com>
parents:
382
diff
changeset
|
639 } |
72933100c55c
Initial implementation of channel 3 special mode
Mike Pavone <pavone@retrodev.com>
parents:
382
diff
changeset
|
640 break; |
72933100c55c
Initial implementation of channel 3 special mode
Mike Pavone <pavone@retrodev.com>
parents:
382
diff
changeset
|
641 case REG_BLOCK_FN_CH3: |
72933100c55c
Initial implementation of channel 3 special mode
Mike Pavone <pavone@retrodev.com>
parents:
382
diff
changeset
|
642 if (channel < 3) { |
72933100c55c
Initial implementation of channel 3 special mode
Mike Pavone <pavone@retrodev.com>
parents:
382
diff
changeset
|
643 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
|
644 } |
72933100c55c
Initial implementation of channel 3 special mode
Mike Pavone <pavone@retrodev.com>
parents:
382
diff
changeset
|
645 break; |
362 | 646 case REG_ALG_FEEDBACK: |
647 context->channels[channel].algorithm = value & 0x7; | |
648 context->channels[channel].feedback = value >> 3 & 0x7; | |
649 break; | |
650 case REG_LR_AMS_PMS: | |
651 context->channels[channel].pms = value & 0x7; | |
652 context->channels[channel].ams = value >> 4 & 0x3; | |
653 context->channels[channel].lr = value & 0xC0; | |
369
fc820ab1394b
Fix left/right enable default value
Mike Pavone <pavone@retrodev.com>
parents:
365
diff
changeset
|
654 //printf("Write of %X to LR_AMS_PMS reg for channel %d\n", value, channel); |
362 | 655 break; |
656 } | |
657 } | |
658 } | |
659 | |
660 context->write_cycle = context->current_cycle; | |
374 | 661 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
|
662 } |
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
|
663 |
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
|
664 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
|
665 { |
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
|
666 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
|
667 } |
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
|
668 |