Mercurial > repos > blastem
annotate ym2612.c @ 527:7df7f493b3b6
Fix operator 1 self-feedback
author | Michael Pavone <pavone@retrodev.com> |
---|---|
date | Wed, 12 Feb 2014 22:14:11 -0800 |
parents | 6a14c5a95648 |
children | 666210adf87b |
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" |
505
b7b7a1cab44a
The local clone on my laptop got messed up and some changes had not been pushed. This commit represents the status of the working copy from that clone. It unfortunately contains some changes that I did not intend to commit yet, but this seems like the best option at the moment.
Michael Pavone <pavone@retrodev.com>
parents:
483
diff
changeset
|
13 #include "blastem.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
|
14 |
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
|
15 //#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
|
16 #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
|
17 #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
|
18 #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
|
19 #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
|
20 #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
|
21 #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
|
22 #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
|
23 |
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
|
24 #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
|
25 #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
|
26 |
362 | 27 enum { |
411
baf4688901f2
Initial stab at LFO phase modulation
Mike Pavone <pavone@retrodev.com>
parents:
407
diff
changeset
|
28 REG_LFO = 0x22, |
362 | 29 REG_TIMERA_HIGH = 0x24, |
30 REG_TIMERA_LOW, | |
31 REG_TIMERB, | |
32 REG_TIME_CTRL, | |
33 REG_KEY_ONOFF, | |
34 REG_DAC = 0x2A, | |
35 REG_DAC_ENABLE, | |
359
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
36 |
362 | 37 REG_DETUNE_MULT = 0x30, |
38 REG_TOTAL_LEVEL = 0x40, | |
39 REG_ATTACK_KS = 0x50, | |
40 REG_DECAY_AM = 0x60, | |
41 REG_SUSTAIN_RATE = 0x70, | |
42 REG_S_LVL_R_RATE = 0x80, | |
359
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
43 |
362 | 44 REG_FNUM_LOW = 0xA0, |
45 REG_BLOCK_FNUM_H = 0xA4, | |
46 REG_FNUM_LOW_CH3 = 0xA8, | |
47 REG_BLOCK_FN_CH3 = 0xAC, | |
48 REG_ALG_FEEDBACK = 0xB0, | |
49 REG_LR_AMS_PMS = 0xB4 | |
50 }; | |
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
|
51 |
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_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
|
53 #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
|
54 #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
|
55 #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
|
56 #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
|
57 #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
|
58 |
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_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
|
60 #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
|
61 |
359
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
62 enum { |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
63 PHASE_ATTACK, |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
64 PHASE_DECAY, |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
65 PHASE_SUSTAIN, |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
66 PHASE_RELEASE |
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 |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
69 uint8_t did_tbl_init = 0; |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
70 //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
|
71 //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
|
72 //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
|
73 #define SINE_TABLE_SIZE 512 |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
74 uint16_t sine_table[SINE_TABLE_SIZE]; |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
75 //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
|
76 //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
|
77 //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
|
78 #define POW_TABLE_SIZE (1 << 13) |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
79 uint16_t pow_table[POW_TABLE_SIZE]; |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
80 |
362 | 81 uint16_t rate_table_base[] = { |
82 //main portion | |
83 0,1,0,1,0,1,0,1, | |
84 0,1,0,1,1,1,0,1, | |
85 0,1,1,1,0,1,1,1, | |
86 0,1,1,1,1,1,1,1, | |
87 //top end | |
88 1,1,1,1,1,1,1,1, | |
89 1,1,1,2,1,1,1,2, | |
90 1,2,1,2,1,2,1,2, | |
91 1,2,2,2,1,2,2,2, | |
92 }; | |
93 | |
365
3ba3b6656fff
Actually save the shifted phase inc after applying the block shift
Mike Pavone <pavone@retrodev.com>
parents:
364
diff
changeset
|
94 uint16_t rate_table[64*8]; |
362 | 95 |
411
baf4688901f2
Initial stab at LFO phase modulation
Mike Pavone <pavone@retrodev.com>
parents:
407
diff
changeset
|
96 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
|
97 uint8_t lfo_pm_base[][8] = { |
baf4688901f2
Initial stab at LFO phase modulation
Mike Pavone <pavone@retrodev.com>
parents:
407
diff
changeset
|
98 {0, 0, 0, 0, 0, 0, 0, 0}, |
baf4688901f2
Initial stab at LFO phase modulation
Mike Pavone <pavone@retrodev.com>
parents:
407
diff
changeset
|
99 {0, 0, 0, 0, 4, 4, 4, 4}, |
baf4688901f2
Initial stab at LFO phase modulation
Mike Pavone <pavone@retrodev.com>
parents:
407
diff
changeset
|
100 {0, 0, 0, 4, 4, 4, 8, 8}, |
baf4688901f2
Initial stab at LFO phase modulation
Mike Pavone <pavone@retrodev.com>
parents:
407
diff
changeset
|
101 {0, 0, 4, 4, 8, 8, 0xc, 0xc}, |
baf4688901f2
Initial stab at LFO phase modulation
Mike Pavone <pavone@retrodev.com>
parents:
407
diff
changeset
|
102 {0, 0, 4, 8, 8, 8, 0xc,0x10}, |
baf4688901f2
Initial stab at LFO phase modulation
Mike Pavone <pavone@retrodev.com>
parents:
407
diff
changeset
|
103 {0, 0, 8, 0xc,0x10,0x10,0x14,0x18}, |
baf4688901f2
Initial stab at LFO phase modulation
Mike Pavone <pavone@retrodev.com>
parents:
407
diff
changeset
|
104 {0, 0,0x10,0x18,0x20,0x20,0x28,0x30}, |
baf4688901f2
Initial stab at LFO phase modulation
Mike Pavone <pavone@retrodev.com>
parents:
407
diff
changeset
|
105 {0, 0,0x20,0x30,0x40,0x40,0x50,0x60} |
baf4688901f2
Initial stab at LFO phase modulation
Mike Pavone <pavone@retrodev.com>
parents:
407
diff
changeset
|
106 }; |
baf4688901f2
Initial stab at LFO phase modulation
Mike Pavone <pavone@retrodev.com>
parents:
407
diff
changeset
|
107 int16_t lfo_pm_table[128 * 32 * 8]; |
baf4688901f2
Initial stab at LFO phase modulation
Mike Pavone <pavone@retrodev.com>
parents:
407
diff
changeset
|
108 |
362 | 109 #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
|
110 #define YM_DIVIDER 2 |
374 | 111 #define CYCLE_NEVER 0xFFFFFFFF |
359
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
112 |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
113 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
|
114 { |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
115 return value * (1 << dec_bits) + 0.5; |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
116 } |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
117 |
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
|
118 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
|
119 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
|
120 |
407
c3abc4ada43d
Add support for logging YM2612 channels to WAVE files
Mike Pavone <pavone@retrodev.com>
parents:
406
diff
changeset
|
121 ym2612_context * log_context = NULL; |
c3abc4ada43d
Add support for logging YM2612 channels to WAVE files
Mike Pavone <pavone@retrodev.com>
parents:
406
diff
changeset
|
122 |
c3abc4ada43d
Add support for logging YM2612 channels to WAVE files
Mike Pavone <pavone@retrodev.com>
parents:
406
diff
changeset
|
123 void ym_finalize_log() |
c3abc4ada43d
Add support for logging YM2612 channels to WAVE files
Mike Pavone <pavone@retrodev.com>
parents:
406
diff
changeset
|
124 { |
c3abc4ada43d
Add support for logging YM2612 channels to WAVE files
Mike Pavone <pavone@retrodev.com>
parents:
406
diff
changeset
|
125 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
|
126 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
|
127 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
|
128 } |
c3abc4ada43d
Add support for logging YM2612 channels to WAVE files
Mike Pavone <pavone@retrodev.com>
parents:
406
diff
changeset
|
129 } |
c3abc4ada43d
Add support for logging YM2612 channels to WAVE files
Mike Pavone <pavone@retrodev.com>
parents:
406
diff
changeset
|
130 } |
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
|
131 #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
|
132 |
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 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
|
134 { |
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 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
|
136 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
|
137 } |
407
c3abc4ada43d
Add support for logging YM2612 channels to WAVE files
Mike Pavone <pavone@retrodev.com>
parents:
406
diff
changeset
|
138 |
c3abc4ada43d
Add support for logging YM2612 channels to WAVE files
Mike Pavone <pavone@retrodev.com>
parents:
406
diff
changeset
|
139 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
|
140 { |
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
|
141 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
|
142 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
|
143 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
|
144 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
|
145 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
|
146 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
|
147 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
|
148 |
364
62177cc39049
Incredibly broken YM2612 support plus a fix to Z80 bus request
Mike Pavone <pavone@retrodev.com>
parents:
362
diff
changeset
|
149 context->sample_limit = sample_limit*2; |
374 | 150 context->write_cycle = CYCLE_NEVER; |
362 | 151 for (int i = 0; i < NUM_OPERATORS; i++) { |
152 context->operators[i].envelope = MAX_ENVELOPE; | |
153 context->operators[i].env_phase = PHASE_RELEASE; | |
154 } | |
369
fc820ab1394b
Fix left/right enable default value
Mike Pavone <pavone@retrodev.com>
parents:
365
diff
changeset
|
155 //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
|
156 for (int i = 0; i < NUM_CHANNELS; i++) { |
fc820ab1394b
Fix left/right enable default value
Mike Pavone <pavone@retrodev.com>
parents:
365
diff
changeset
|
157 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
|
158 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
|
159 char fname[64]; |
c3abc4ada43d
Add support for logging YM2612 channels to WAVE files
Mike Pavone <pavone@retrodev.com>
parents:
406
diff
changeset
|
160 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
|
161 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
|
162 if (!f) { |
c3abc4ada43d
Add support for logging YM2612 channels to WAVE files
Mike Pavone <pavone@retrodev.com>
parents:
406
diff
changeset
|
163 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
|
164 continue; |
c3abc4ada43d
Add support for logging YM2612 channels to WAVE files
Mike Pavone <pavone@retrodev.com>
parents:
406
diff
changeset
|
165 } |
c3abc4ada43d
Add support for logging YM2612 channels to WAVE files
Mike Pavone <pavone@retrodev.com>
parents:
406
diff
changeset
|
166 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
|
167 fclose(f); |
c3abc4ada43d
Add support for logging YM2612 channels to WAVE files
Mike Pavone <pavone@retrodev.com>
parents:
406
diff
changeset
|
168 context->channels[i].logfile = NULL; |
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 } |
c3abc4ada43d
Add support for logging YM2612 channels to WAVE files
Mike Pavone <pavone@retrodev.com>
parents:
406
diff
changeset
|
172 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
|
173 log_context = context; |
c3abc4ada43d
Add support for logging YM2612 channels to WAVE files
Mike Pavone <pavone@retrodev.com>
parents:
406
diff
changeset
|
174 atexit(ym_finalize_log); |
369
fc820ab1394b
Fix left/right enable default value
Mike Pavone <pavone@retrodev.com>
parents:
365
diff
changeset
|
175 } |
359
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
176 if (!did_tbl_init) { |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
177 //populate sine table |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
178 for (int32_t i = 0; i < 512; i++) { |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
179 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
|
180 |
359
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
181 //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
|
182 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
|
183 } |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
184 //populate power table |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
185 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
|
186 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
|
187 int32_t tmp = round_fixed_point(linear, 11); |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
188 int32_t shift = (i >> 8) - 2; |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
189 if (shift < 0) { |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
190 tmp <<= 0-shift; |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
191 } else { |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
192 tmp >>= shift; |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
193 } |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
194 pow_table[i] = tmp; |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
195 } |
362 | 196 //populate envelope generator rate table, from small base table |
197 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
|
198 for (int cycle = 0; cycle < 8; cycle++) { |
362 | 199 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
|
200 if (rate < 2) { |
362 | 201 value = 0; |
365
3ba3b6656fff
Actually save the shifted phase inc after applying the block shift
Mike Pavone <pavone@retrodev.com>
parents:
364
diff
changeset
|
202 } else if (rate >= 60) { |
362 | 203 value = 8; |
365
3ba3b6656fff
Actually save the shifted phase inc after applying the block shift
Mike Pavone <pavone@retrodev.com>
parents:
364
diff
changeset
|
204 } 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
|
205 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
|
206 } else if (rate < 48) { |
362 | 207 value = rate_table_base[(rate & 0x3) * 8 + cycle]; |
208 } 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
|
209 value = rate_table_base[32 + (rate & 0x3) * 8 + cycle] << ((rate - 48) >> 2); |
362 | 210 } |
365
3ba3b6656fff
Actually save the shifted phase inc after applying the block shift
Mike Pavone <pavone@retrodev.com>
parents:
364
diff
changeset
|
211 rate_table[rate * 8 + cycle] = value; |
362 | 212 } |
213 } | |
411
baf4688901f2
Initial stab at LFO phase modulation
Mike Pavone <pavone@retrodev.com>
parents:
407
diff
changeset
|
214 //populate LFO PM table from small base table |
baf4688901f2
Initial stab at LFO phase modulation
Mike Pavone <pavone@retrodev.com>
parents:
407
diff
changeset
|
215 //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
|
216 for (int freq = 0; freq < 128; freq++) { |
baf4688901f2
Initial stab at LFO phase modulation
Mike Pavone <pavone@retrodev.com>
parents:
407
diff
changeset
|
217 for (int pms = 0; pms < 8; pms++) { |
baf4688901f2
Initial stab at LFO phase modulation
Mike Pavone <pavone@retrodev.com>
parents:
407
diff
changeset
|
218 for (int step = 0; step < 32; step++) { |
baf4688901f2
Initial stab at LFO phase modulation
Mike Pavone <pavone@retrodev.com>
parents:
407
diff
changeset
|
219 int16_t value = 0; |
baf4688901f2
Initial stab at LFO phase modulation
Mike Pavone <pavone@retrodev.com>
parents:
407
diff
changeset
|
220 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
|
221 if (freq & bit) { |
baf4688901f2
Initial stab at LFO phase modulation
Mike Pavone <pavone@retrodev.com>
parents:
407
diff
changeset
|
222 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
|
223 } |
baf4688901f2
Initial stab at LFO phase modulation
Mike Pavone <pavone@retrodev.com>
parents:
407
diff
changeset
|
224 } |
baf4688901f2
Initial stab at LFO phase modulation
Mike Pavone <pavone@retrodev.com>
parents:
407
diff
changeset
|
225 if (step & 0x10) { |
baf4688901f2
Initial stab at LFO phase modulation
Mike Pavone <pavone@retrodev.com>
parents:
407
diff
changeset
|
226 value = -value; |
baf4688901f2
Initial stab at LFO phase modulation
Mike Pavone <pavone@retrodev.com>
parents:
407
diff
changeset
|
227 } |
baf4688901f2
Initial stab at LFO phase modulation
Mike Pavone <pavone@retrodev.com>
parents:
407
diff
changeset
|
228 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
|
229 } |
baf4688901f2
Initial stab at LFO phase modulation
Mike Pavone <pavone@retrodev.com>
parents:
407
diff
changeset
|
230 } |
baf4688901f2
Initial stab at LFO phase modulation
Mike Pavone <pavone@retrodev.com>
parents:
407
diff
changeset
|
231 } |
359
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
232 } |
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
|
233 } |
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
|
234 |
522
6a14c5a95648
Adjust PSG and YM-2612 volume to be closer to the real console
Michael Pavone <pavone@retrodev.com>
parents:
521
diff
changeset
|
235 #define YM_VOLUME_MULTIPLIER 2 |
6a14c5a95648
Adjust PSG and YM-2612 volume to be closer to the real console
Michael Pavone <pavone@retrodev.com>
parents:
521
diff
changeset
|
236 #define YM_VOLUME_DIVIDER 3 |
381
7815ebbbd705
Fix modulation shift value
Mike Pavone <pavone@retrodev.com>
parents:
380
diff
changeset
|
237 #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
|
238 |
403 | 239 #define TIMER_A_MAX 1023 |
240 #define TIMER_B_MAX (255*16) | |
241 | |
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
|
242 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
|
243 { |
362 | 244 //printf("Running YM2612 from cycle %d to cycle %d\n", context->current_cycle, to_cycle); |
245 //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
|
246 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
|
247 //Update timers at beginning of 144 cycle period |
403 | 248 if (!context->current_op) { |
249 if (context->timer_control & BIT_TIMERA_ENABLE) { | |
250 if (context->timer_a != TIMER_A_MAX) { | |
251 context->timer_a++; | |
252 } else { | |
253 if (context->timer_control & BIT_TIMERA_OVEREN) { | |
254 context->status |= BIT_STATUS_TIMERA; | |
255 } | |
256 context->timer_a = context->timer_a_load; | |
359
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
257 } |
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
|
258 } |
362 | 259 if (context->timer_control & BIT_TIMERB_ENABLE) { |
403 | 260 if (context->timer_b != TIMER_B_MAX) { |
261 context->timer_b++; | |
262 } else { | |
263 if (context->timer_control & BIT_TIMERB_OVEREN) { | |
264 context->status |= BIT_STATUS_TIMERB; | |
359
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
265 } |
403 | 266 context->timer_b = context->timer_b_load; |
359
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
267 } |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
268 } |
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
|
269 } |
411
baf4688901f2
Initial stab at LFO phase modulation
Mike Pavone <pavone@retrodev.com>
parents:
407
diff
changeset
|
270 //Update LFO |
baf4688901f2
Initial stab at LFO phase modulation
Mike Pavone <pavone@retrodev.com>
parents:
407
diff
changeset
|
271 if (context->lfo_enable) { |
baf4688901f2
Initial stab at LFO phase modulation
Mike Pavone <pavone@retrodev.com>
parents:
407
diff
changeset
|
272 if (context->lfo_counter) { |
baf4688901f2
Initial stab at LFO phase modulation
Mike Pavone <pavone@retrodev.com>
parents:
407
diff
changeset
|
273 context->lfo_counter--; |
baf4688901f2
Initial stab at LFO phase modulation
Mike Pavone <pavone@retrodev.com>
parents:
407
diff
changeset
|
274 } else { |
baf4688901f2
Initial stab at LFO phase modulation
Mike Pavone <pavone@retrodev.com>
parents:
407
diff
changeset
|
275 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
|
276 context->lfo_am_step += 2; |
baf4688901f2
Initial stab at LFO phase modulation
Mike Pavone <pavone@retrodev.com>
parents:
407
diff
changeset
|
277 context->lfo_am_step &= 0xFE; |
baf4688901f2
Initial stab at LFO phase modulation
Mike Pavone <pavone@retrodev.com>
parents:
407
diff
changeset
|
278 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
|
279 } |
baf4688901f2
Initial stab at LFO phase modulation
Mike Pavone <pavone@retrodev.com>
parents:
407
diff
changeset
|
280 } |
359
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
281 //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
|
282 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
|
283 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
|
284 uint32_t op = context->current_env_op; |
362 | 285 ym_operator * operator = context->operators + op; |
286 ym_channel * channel = context->channels + op/4; | |
359
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
287 uint8_t rate; |
362 | 288 for(;;) { |
289 rate = operator->rates[operator->env_phase]; | |
290 if (rate) { | |
291 uint8_t ks = channel->keycode >> operator->key_scaling;; | |
292 rate = rate*2 + ks; | |
293 if (rate > 63) { | |
294 rate = 63; | |
295 } | |
296 } | |
297 //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
|
298 //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
|
299 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
|
300 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
|
301 operator->envelope = 0; |
362 | 302 } else { |
303 break; | |
304 } | |
305 } | |
306 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
|
307 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
|
308 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
|
309 } |
362 | 310 if (!(env_cyc & ((1 << cycle_shift) - 1))) { |
311 uint32_t update_cycle = env_cyc >> cycle_shift & 0x7; | |
312 //envelope value is 10-bits, but it will be used as a 4.8 value | |
313 uint16_t envelope_inc = rate_table[rate * 8 + update_cycle] << 2; | |
314 if (operator->env_phase == PHASE_ATTACK) { | |
315 //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
|
316 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
|
317 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
|
318 } |
513
24ebabd89162
Properly clamp envelope value to zero when it overflows during the attack phase. This fixes a number of instruments that sounded rather wrong as well as the missing melody line from Mushroom Hill Zone in Sonic and Knuckles
Michael Pavone <pavone@retrodev.com>
parents:
505
diff
changeset
|
319 uint16_t old_env = operator->envelope; |
362 | 320 operator->envelope += (~operator->envelope * envelope_inc) >> 4; |
513
24ebabd89162
Properly clamp envelope value to zero when it overflows during the attack phase. This fixes a number of instruments that sounded rather wrong as well as the missing melody line from Mushroom Hill Zone in Sonic and Knuckles
Michael Pavone <pavone@retrodev.com>
parents:
505
diff
changeset
|
321 if (operator->envelope > old_env) { |
24ebabd89162
Properly clamp envelope value to zero when it overflows during the attack phase. This fixes a number of instruments that sounded rather wrong as well as the missing melody line from Mushroom Hill Zone in Sonic and Knuckles
Michael Pavone <pavone@retrodev.com>
parents:
505
diff
changeset
|
322 //Handle overflow |
24ebabd89162
Properly clamp envelope value to zero when it overflows during the attack phase. This fixes a number of instruments that sounded rather wrong as well as the missing melody line from Mushroom Hill Zone in Sonic and Knuckles
Michael Pavone <pavone@retrodev.com>
parents:
505
diff
changeset
|
323 operator->envelope = 0; |
24ebabd89162
Properly clamp envelope value to zero when it overflows during the attack phase. This fixes a number of instruments that sounded rather wrong as well as the missing melody line from Mushroom Hill Zone in Sonic and Knuckles
Michael Pavone <pavone@retrodev.com>
parents:
505
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 if (!operator->envelope) { |
362 | 326 operator->env_phase = PHASE_DECAY; |
327 } | |
328 } 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
|
329 if (first_key_on) { |
448
e85a107e6ec0
Fix handling of key on in YM2612 core
Mike Pavone <pavone@retrodev.com>
parents:
424
diff
changeset
|
330 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
|
331 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
|
332 } |
362 | 333 operator->envelope += envelope_inc; |
334 //clamp to max attenuation value | |
335 if (operator->envelope > MAX_ENVELOPE) { | |
336 operator->envelope = MAX_ENVELOPE; | |
337 } | |
338 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
|
339 //operator->envelope = operator->sustain_level; |
362 | 340 operator->env_phase = PHASE_SUSTAIN; |
341 } | |
342 } | |
364
62177cc39049
Incredibly broken YM2612 support plus a fix to Z80 bus request
Mike Pavone <pavone@retrodev.com>
parents:
362
diff
changeset
|
343 } |
62177cc39049
Incredibly broken YM2612 support plus a fix to Z80 bus request
Mike Pavone <pavone@retrodev.com>
parents:
362
diff
changeset
|
344 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
|
345 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
|
346 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
|
347 context->env_counter++; |
362 | 348 } |
349 } | |
448
e85a107e6ec0
Fix handling of key on in YM2612 core
Mike Pavone <pavone@retrodev.com>
parents:
424
diff
changeset
|
350 |
362 | 351 //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
|
352 uint32_t channel = context->current_op / 4; |
362 | 353 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
|
354 uint32_t op = context->current_op; |
362 | 355 //printf("updating operator %d of channel %d\n", op, channel); |
356 ym_operator * operator = context->operators + op; | |
357 ym_channel * chan = context->channels + channel; | |
358 //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
|
359 uint16_t phase = operator->phase_counter >> 10 & 0x3FF; |
362 | 360 operator->phase_counter += operator->phase_inc; |
411
baf4688901f2
Initial stab at LFO phase modulation
Mike Pavone <pavone@retrodev.com>
parents:
407
diff
changeset
|
361 if (chan->pms) { |
baf4688901f2
Initial stab at LFO phase modulation
Mike Pavone <pavone@retrodev.com>
parents:
407
diff
changeset
|
362 //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
|
363 //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
|
364 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
|
365 if (operator->multiple) { |
baf4688901f2
Initial stab at LFO phase modulation
Mike Pavone <pavone@retrodev.com>
parents:
407
diff
changeset
|
366 lfo_mod *= operator->multiple; |
baf4688901f2
Initial stab at LFO phase modulation
Mike Pavone <pavone@retrodev.com>
parents:
407
diff
changeset
|
367 } else { |
baf4688901f2
Initial stab at LFO phase modulation
Mike Pavone <pavone@retrodev.com>
parents:
407
diff
changeset
|
368 lfo_mod >>= 1; |
baf4688901f2
Initial stab at LFO phase modulation
Mike Pavone <pavone@retrodev.com>
parents:
407
diff
changeset
|
369 } |
448
e85a107e6ec0
Fix handling of key on in YM2612 core
Mike Pavone <pavone@retrodev.com>
parents:
424
diff
changeset
|
370 operator->phase_counter += lfo_mod; |
411
baf4688901f2
Initial stab at LFO phase modulation
Mike Pavone <pavone@retrodev.com>
parents:
407
diff
changeset
|
371 } |
371
0f8a759f1ff4
Use signed ints for things that represent signed values in YM2612 core
Mike Pavone <pavone@retrodev.com>
parents:
370
diff
changeset
|
372 int16_t mod = 0; |
362 | 373 switch (op % 4) |
359
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
374 { |
362 | 375 case 0://Operator 1 |
377 | 376 if (chan->feedback) { |
527
7df7f493b3b6
Fix operator 1 self-feedback
Michael Pavone <pavone@retrodev.com>
parents:
522
diff
changeset
|
377 mod = (chan->op1_old + operator->output) >> (10-chan->feedback); |
377 | 378 } |
359
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
379 break; |
362 | 380 case 1://Operator 3 |
381 switch(chan->algorithm) | |
382 { | |
383 case 0: | |
384 case 2: | |
385 //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
|
386 mod = context->operators[op+1].output >> YM_MOD_SHIFT; |
362 | 387 break; |
388 case 1: | |
389 //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
|
390 mod = (context->operators[op-1].output + context->operators[op+1].output) >> YM_MOD_SHIFT; |
362 | 391 break; |
392 case 5: | |
393 //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
|
394 mod = context->operators[op-1].output >> YM_MOD_SHIFT; |
362 | 395 } |
396 break; | |
397 case 2://Operator 2 | |
406
b1bc1947d949
Fix modulation condition for operator 2
Mike Pavone <pavone@retrodev.com>
parents:
403
diff
changeset
|
398 if (chan->algorithm != 1 && chan->algorithm != 2 && chan->algorithm != 7) { |
362 | 399 //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
|
400 mod = context->operators[op-2].output >> YM_MOD_SHIFT; |
362 | 401 } |
359
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
402 break; |
362 | 403 case 3://Operator 4 |
404 switch(chan->algorithm) | |
405 { | |
406 case 0: | |
407 case 1: | |
408 case 4: | |
409 //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
|
410 mod = context->operators[op-2].output >> YM_MOD_SHIFT; |
362 | 411 break; |
412 case 2: | |
413 //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
|
414 mod = (context->operators[op-3].output + context->operators[op-2].output) >> YM_MOD_SHIFT; |
362 | 415 break; |
416 case 3: | |
417 //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
|
418 mod = (context->operators[op-1].output + context->operators[op-2].output) >> YM_MOD_SHIFT; |
362 | 419 break; |
420 case 5: | |
421 //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
|
422 mod = context->operators[op-3].output >> YM_MOD_SHIFT; |
362 | 423 break; |
424 } | |
359
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
425 break; |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
426 } |
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
|
427 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
|
428 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
|
429 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
|
430 } |
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
|
431 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
|
432 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
|
433 } |
527
7df7f493b3b6
Fix operator 1 self-feedback
Michael Pavone <pavone@retrodev.com>
parents:
522
diff
changeset
|
434 //if ((channel != 0 && channel != 4) || chan->algorithm != 5) { |
7df7f493b3b6
Fix operator 1 self-feedback
Michael Pavone <pavone@retrodev.com>
parents:
522
diff
changeset
|
435 phase += mod; |
7df7f493b3b6
Fix operator 1 self-feedback
Michael Pavone <pavone@retrodev.com>
parents:
522
diff
changeset
|
436 //} |
448
e85a107e6ec0
Fix handling of key on in YM2612 core
Mike Pavone <pavone@retrodev.com>
parents:
424
diff
changeset
|
437 |
371
0f8a759f1ff4
Use signed ints for things that represent signed values in YM2612 core
Mike Pavone <pavone@retrodev.com>
parents:
370
diff
changeset
|
438 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
|
439 if (phase & 0x200) { |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
440 output = -output; |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
441 } |
527
7df7f493b3b6
Fix operator 1 self-feedback
Michael Pavone <pavone@retrodev.com>
parents:
522
diff
changeset
|
442 if (op % 4 == 0) { |
7df7f493b3b6
Fix operator 1 self-feedback
Michael Pavone <pavone@retrodev.com>
parents:
522
diff
changeset
|
443 chan->op1_old = operator->output; |
7df7f493b3b6
Fix operator 1 self-feedback
Michael Pavone <pavone@retrodev.com>
parents:
522
diff
changeset
|
444 } |
362 | 445 operator->output = output; |
359
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
446 //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
|
447 if (op % 4 == 3) { |
362 | 448 if (chan->algorithm < 4) { |
449 chan->output = operator->output; | |
450 } 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
|
451 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
|
452 } else { |
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
453 output = 0; |
362 | 454 for (uint32_t op = ((chan->algorithm == 7) ? 0 : 1) + channel*4; op < (channel+1)*4; op++) { |
455 output += context->operators[op].output; | |
359
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
456 } |
362 | 457 chan->output = output; |
359
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
458 } |
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
|
459 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
|
460 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
|
461 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
|
462 value |= 0xC000; |
0f8a759f1ff4
Use signed ints for things that represent signed values in YM2612 core
Mike Pavone <pavone@retrodev.com>
parents:
370
diff
changeset
|
463 } |
522
6a14c5a95648
Adjust PSG and YM-2612 volume to be closer to the real console
Michael Pavone <pavone@retrodev.com>
parents:
521
diff
changeset
|
464 dfprintf(debug_file, "channel %d output: %d\n", channel, (value * YM_VOLUME_MULTIPLIER) / 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
|
465 } |
359
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
466 } |
362 | 467 //puts("operator update done"); |
359
cc39629e8d06
YM2612 WIP snapshot before register refactor
Mike Pavone <pavone@retrodev.com>
parents:
288
diff
changeset
|
468 } |
364
62177cc39049
Incredibly broken YM2612 support plus a fix to Z80 bus request
Mike Pavone <pavone@retrodev.com>
parents:
362
diff
changeset
|
469 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
|
470 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
|
471 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
|
472 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
|
473 } |
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 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
|
475 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
|
476 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
|
477 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
|
478 for (int i = 0; i < NUM_CHANNELS; i++) { |
521
7565ec2ac652
Fix overflow handling on FM channel output
Michael Pavone <pavone@retrodev.com>
parents:
513
diff
changeset
|
479 int16_t value = context->channels[i].output; |
7565ec2ac652
Fix overflow handling on FM channel output
Michael Pavone <pavone@retrodev.com>
parents:
513
diff
changeset
|
480 if (value > 0x1FE0) { |
7565ec2ac652
Fix overflow handling on FM channel output
Michael Pavone <pavone@retrodev.com>
parents:
513
diff
changeset
|
481 value = 0x1FE0; |
7565ec2ac652
Fix overflow handling on FM channel output
Michael Pavone <pavone@retrodev.com>
parents:
513
diff
changeset
|
482 } else if (value < -0x1FF0) { |
7565ec2ac652
Fix overflow handling on FM channel output
Michael Pavone <pavone@retrodev.com>
parents:
513
diff
changeset
|
483 value = -0x1FF0; |
7565ec2ac652
Fix overflow handling on FM channel output
Michael Pavone <pavone@retrodev.com>
parents:
513
diff
changeset
|
484 } else { |
7565ec2ac652
Fix overflow handling on FM channel output
Michael Pavone <pavone@retrodev.com>
parents:
513
diff
changeset
|
485 value &= 0x3FE0; |
7565ec2ac652
Fix overflow handling on FM channel output
Michael Pavone <pavone@retrodev.com>
parents:
513
diff
changeset
|
486 if (value & 0x2000) { |
7565ec2ac652
Fix overflow handling on FM channel output
Michael Pavone <pavone@retrodev.com>
parents:
513
diff
changeset
|
487 value |= 0xC000; |
7565ec2ac652
Fix overflow handling on FM channel output
Michael Pavone <pavone@retrodev.com>
parents:
513
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 } |
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
|
490 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
|
491 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
|
492 } |
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
|
493 if (context->channels[i].lr & 0x80) { |
522
6a14c5a95648
Adjust PSG and YM-2612 volume to be closer to the real console
Michael Pavone <pavone@retrodev.com>
parents:
521
diff
changeset
|
494 context->audio_buffer[context->buffer_pos] += (value * YM_VOLUME_MULTIPLIER) / 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
|
495 } |
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
|
496 if (context->channels[i].lr & 0x40) { |
522
6a14c5a95648
Adjust PSG and YM-2612 volume to be closer to the real console
Michael Pavone <pavone@retrodev.com>
parents:
521
diff
changeset
|
497 context->audio_buffer[context->buffer_pos+1] += (value * YM_VOLUME_MULTIPLIER) / YM_VOLUME_DIVIDER; |
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
|
498 } |
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
|
499 } |
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
|
500 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
|
501 if (context->buffer_pos == context->sample_limit) { |
505
b7b7a1cab44a
The local clone on my laptop got messed up and some changes had not been pushed. This commit represents the status of the working copy from that clone. It unfortunately contains some changes that I did not intend to commit yet, but this seems like the best option at the moment.
Michael Pavone <pavone@retrodev.com>
parents:
483
diff
changeset
|
502 if (!headless) { |
b7b7a1cab44a
The local clone on my laptop got messed up and some changes had not been pushed. This commit represents the status of the working copy from that clone. It unfortunately contains some changes that I did not intend to commit yet, but this seems like the best option at the moment.
Michael Pavone <pavone@retrodev.com>
parents:
483
diff
changeset
|
503 render_wait_ym(context); |
b7b7a1cab44a
The local clone on my laptop got messed up and some changes had not been pushed. This commit represents the status of the working copy from that clone. It unfortunately contains some changes that I did not intend to commit yet, but this seems like the best option at the moment.
Michael Pavone <pavone@retrodev.com>
parents:
483
diff
changeset
|
504 } |
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
|
505 } |
364
62177cc39049
Incredibly broken YM2612 support plus a fix to Z80 bus request
Mike Pavone <pavone@retrodev.com>
parents:
362
diff
changeset
|
506 } |
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
|
507 } |
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
|
508 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
|
509 context->status &= 0x7F; |
374 | 510 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
|
511 } |
362 | 512 //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
|
513 } |
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
|
514 |
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
|
515 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
|
516 { |
364
62177cc39049
Incredibly broken YM2612 support plus a fix to Z80 bus request
Mike Pavone <pavone@retrodev.com>
parents:
362
diff
changeset
|
517 //printf("address_write_part1: %X\n", address); |
362 | 518 context->selected_reg = address; |
519 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
|
520 } |
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
|
521 |
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
|
522 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
|
523 { |
364
62177cc39049
Incredibly broken YM2612 support plus a fix to Z80 bus request
Mike Pavone <pavone@retrodev.com>
parents:
362
diff
changeset
|
524 //printf("address_write_part2: %X\n", address); |
362 | 525 context->selected_reg = address; |
526 context->selected_part = 1; | |
527 } | |
528 | |
529 uint8_t fnum_to_keycode[] = { | |
530 //F11 = 0 | |
531 0,0,0,0,0,0,0,1, | |
532 //F11 = 1 | |
533 2,3,3,3,3,3,3,3 | |
534 }; | |
535 | |
536 //table courtesy of Nemesis | |
537 uint32_t detune_table[][4] = { | |
538 {0, 0, 1, 2}, //0 (0x00) | |
539 {0, 0, 1, 2}, //1 (0x01) | |
540 {0, 0, 1, 2}, //2 (0x02) | |
541 {0, 0, 1, 2}, //3 (0x03) | |
542 {0, 1, 2, 2}, //4 (0x04) | |
543 {0, 1, 2, 3}, //5 (0x05) | |
544 {0, 1, 2, 3}, //6 (0x06) | |
545 {0, 1, 2, 3}, //7 (0x07) | |
546 {0, 1, 2, 4}, //8 (0x08) | |
547 {0, 1, 3, 4}, //9 (0x09) | |
548 {0, 1, 3, 4}, //10 (0x0A) | |
549 {0, 1, 3, 5}, //11 (0x0B) | |
550 {0, 2, 4, 5}, //12 (0x0C) | |
551 {0, 2, 4, 6}, //13 (0x0D) | |
552 {0, 2, 4, 6}, //14 (0x0E) | |
553 {0, 2, 5, 7}, //15 (0x0F) | |
554 {0, 2, 5, 8}, //16 (0x10) | |
555 {0, 3, 6, 8}, //17 (0x11) | |
556 {0, 3, 6, 9}, //18 (0x12) | |
557 {0, 3, 7,10}, //19 (0x13) | |
558 {0, 4, 8,11}, //20 (0x14) | |
559 {0, 4, 8,12}, //21 (0x15) | |
560 {0, 4, 9,13}, //22 (0x16) | |
561 {0, 5,10,14}, //23 (0x17) | |
562 {0, 5,11,16}, //24 (0x18) | |
563 {0, 6,12,17}, //25 (0x19) | |
564 {0, 6,13,19}, //26 (0x1A) | |
565 {0, 7,14,20}, //27 (0x1B) | |
566 {0, 8,16,22}, //28 (0x1C) | |
567 {0, 8,16,22}, //29 (0x1D) | |
568 {0, 8,16,22}, //30 (0x1E) | |
569 {0, 8,16,22} | |
570 }; //31 (0x1F) | |
571 | |
572 void ym_update_phase_inc(ym2612_context * context, ym_operator * operator, uint32_t op) | |
573 { | |
574 uint32_t chan_num = op / 4; | |
575 //printf("ym_update_phase_inc | channel: %d, op: %d\n", chan_num, op); | |
576 //base frequency | |
577 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
|
578 uint32_t inc, detune; |
72933100c55c
Initial implementation of channel 3 special mode
Mike Pavone <pavone@retrodev.com>
parents:
382
diff
changeset
|
579 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
|
580 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
|
581 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
|
582 inc >>= 1; |
72933100c55c
Initial implementation of channel 3 special mode
Mike Pavone <pavone@retrodev.com>
parents:
382
diff
changeset
|
583 } else { |
72933100c55c
Initial implementation of channel 3 special mode
Mike Pavone <pavone@retrodev.com>
parents:
382
diff
changeset
|
584 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
|
585 } |
72933100c55c
Initial implementation of channel 3 special mode
Mike Pavone <pavone@retrodev.com>
parents:
382
diff
changeset
|
586 //detune |
72933100c55c
Initial implementation of channel 3 special mode
Mike Pavone <pavone@retrodev.com>
parents:
382
diff
changeset
|
587 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
|
588 } else { |
383
72933100c55c
Initial implementation of channel 3 special mode
Mike Pavone <pavone@retrodev.com>
parents:
382
diff
changeset
|
589 inc = channel->fnum; |
72933100c55c
Initial implementation of channel 3 special mode
Mike Pavone <pavone@retrodev.com>
parents:
382
diff
changeset
|
590 if (!channel->block) { |
72933100c55c
Initial implementation of channel 3 special mode
Mike Pavone <pavone@retrodev.com>
parents:
382
diff
changeset
|
591 inc >>= 1; |
72933100c55c
Initial implementation of channel 3 special mode
Mike Pavone <pavone@retrodev.com>
parents:
382
diff
changeset
|
592 } else { |
72933100c55c
Initial implementation of channel 3 special mode
Mike Pavone <pavone@retrodev.com>
parents:
382
diff
changeset
|
593 inc <<= (channel->block-1); |
72933100c55c
Initial implementation of channel 3 special mode
Mike Pavone <pavone@retrodev.com>
parents:
382
diff
changeset
|
594 } |
72933100c55c
Initial implementation of channel 3 special mode
Mike Pavone <pavone@retrodev.com>
parents:
382
diff
changeset
|
595 //detune |
72933100c55c
Initial implementation of channel 3 special mode
Mike Pavone <pavone@retrodev.com>
parents:
382
diff
changeset
|
596 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
|
597 } |
362 | 598 if (operator->detune & 0x40) { |
599 inc -= detune; | |
600 //this can underflow, mask to 17-bit result | |
601 inc &= 0x1FFFF; | |
602 } else { | |
603 inc += detune; | |
604 } | |
605 //multiple | |
606 if (operator->multiple) { | |
607 inc *= operator->multiple; | |
608 } else { | |
609 //0.5 | |
610 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
|
611 } |
365
3ba3b6656fff
Actually save the shifted phase inc after applying the block shift
Mike Pavone <pavone@retrodev.com>
parents:
364
diff
changeset
|
612 //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
|
613 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
|
614 } |
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
|
615 |
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
|
616 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
|
617 { |
451
b7c3b2d22858
Added support for saving savestates. Added gst savestate format test harness
Mike Pavone <pavone@retrodev.com>
parents:
448
diff
changeset
|
618 if (context->selected_reg >= YM_REG_END) { |
362 | 619 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
|
620 } |
451
b7c3b2d22858
Added support for saving savestates. Added gst savestate format test harness
Mike Pavone <pavone@retrodev.com>
parents:
448
diff
changeset
|
621 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
|
622 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
|
623 return; |
b7c3b2d22858
Added support for saving savestates. Added gst savestate format test harness
Mike Pavone <pavone@retrodev.com>
parents:
448
diff
changeset
|
624 } |
b7c3b2d22858
Added support for saving savestates. Added gst savestate format test harness
Mike Pavone <pavone@retrodev.com>
parents:
448
diff
changeset
|
625 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
|
626 } else { |
b7c3b2d22858
Added support for saving savestates. Added gst savestate format test harness
Mike Pavone <pavone@retrodev.com>
parents:
448
diff
changeset
|
627 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
|
628 return; |
b7c3b2d22858
Added support for saving savestates. Added gst savestate format test harness
Mike Pavone <pavone@retrodev.com>
parents:
448
diff
changeset
|
629 } |
b7c3b2d22858
Added support for saving savestates. Added gst savestate format test harness
Mike Pavone <pavone@retrodev.com>
parents:
448
diff
changeset
|
630 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
|
631 } |
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
|
632 dfprintf(debug_file, "write of %X to reg %X in part %d\n", value, context->selected_reg, context->selected_part+1); |
362 | 633 if (context->selected_reg < 0x30) { |
634 //Shared regs | |
635 switch (context->selected_reg) | |
636 { | |
411
baf4688901f2
Initial stab at LFO phase modulation
Mike Pavone <pavone@retrodev.com>
parents:
407
diff
changeset
|
637 //TODO: Test reg |
baf4688901f2
Initial stab at LFO phase modulation
Mike Pavone <pavone@retrodev.com>
parents:
407
diff
changeset
|
638 case REG_LFO: |
baf4688901f2
Initial stab at LFO phase modulation
Mike Pavone <pavone@retrodev.com>
parents:
407
diff
changeset
|
639 if ((value & 0x8) && !context->lfo_enable) { |
baf4688901f2
Initial stab at LFO phase modulation
Mike Pavone <pavone@retrodev.com>
parents:
407
diff
changeset
|
640 printf("LFO Enabled, Freq: %d\n", value & 0x7); |
baf4688901f2
Initial stab at LFO phase modulation
Mike Pavone <pavone@retrodev.com>
parents:
407
diff
changeset
|
641 } |
baf4688901f2
Initial stab at LFO phase modulation
Mike Pavone <pavone@retrodev.com>
parents:
407
diff
changeset
|
642 context->lfo_enable = value & 0x8; |
baf4688901f2
Initial stab at LFO phase modulation
Mike Pavone <pavone@retrodev.com>
parents:
407
diff
changeset
|
643 if (!context->lfo_enable) { |
baf4688901f2
Initial stab at LFO phase modulation
Mike Pavone <pavone@retrodev.com>
parents:
407
diff
changeset
|
644 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
|
645 } |
baf4688901f2
Initial stab at LFO phase modulation
Mike Pavone <pavone@retrodev.com>
parents:
407
diff
changeset
|
646 context->lfo_freq = value & 0x7; |
448
e85a107e6ec0
Fix handling of key on in YM2612 core
Mike Pavone <pavone@retrodev.com>
parents:
424
diff
changeset
|
647 |
411
baf4688901f2
Initial stab at LFO phase modulation
Mike Pavone <pavone@retrodev.com>
parents:
407
diff
changeset
|
648 break; |
362 | 649 case REG_TIMERA_HIGH: |
650 context->timer_a_load &= 0x3; | |
651 context->timer_a_load |= value << 2; | |
652 break; | |
653 case REG_TIMERA_LOW: | |
654 context->timer_a_load &= 0xFFFC; | |
655 context->timer_a_load |= value & 0x3; | |
656 break; | |
657 case REG_TIMERB: | |
403 | 658 context->timer_b_load = value * 16; |
362 | 659 break; |
383
72933100c55c
Initial implementation of channel 3 special mode
Mike Pavone <pavone@retrodev.com>
parents:
382
diff
changeset
|
660 case REG_TIME_CTRL: { |
403 | 661 if (value & BIT_TIMERA_ENABLE && !(context->timer_control & BIT_TIMERA_ENABLE)) { |
662 context->timer_a = context->timer_a_load; | |
663 } | |
664 if (value & BIT_TIMERB_ENABLE && !(context->timer_control & BIT_TIMERB_ENABLE)) { | |
665 context->timer_b = context->timer_b_load; | |
666 } | |
667 context->timer_control = value & 0xF; | |
668 if (value & BIT_TIMERA_RESET) { | |
669 context->status &= ~BIT_STATUS_TIMERA; | |
670 } | |
671 if (value & BIT_TIMERB_RESET) { | |
672 context->status &= ~BIT_STATUS_TIMERB; | |
673 } | |
383
72933100c55c
Initial implementation of channel 3 special mode
Mike Pavone <pavone@retrodev.com>
parents:
382
diff
changeset
|
674 uint8_t old_mode = context->ch3_mode; |
72933100c55c
Initial implementation of channel 3 special mode
Mike Pavone <pavone@retrodev.com>
parents:
382
diff
changeset
|
675 context->ch3_mode = value & 0xC0; |
72933100c55c
Initial implementation of channel 3 special mode
Mike Pavone <pavone@retrodev.com>
parents:
382
diff
changeset
|
676 if (context->ch3_mode != old_mode) { |
72933100c55c
Initial implementation of channel 3 special mode
Mike Pavone <pavone@retrodev.com>
parents:
382
diff
changeset
|
677 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
|
678 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
|
679 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
|
680 } |
362 | 681 break; |
383
72933100c55c
Initial implementation of channel 3 special mode
Mike Pavone <pavone@retrodev.com>
parents:
382
diff
changeset
|
682 } |
362 | 683 case REG_KEY_ONOFF: { |
684 uint8_t channel = value & 0x7; | |
386
6e5c4f3ab0e2
Fix channel mapping in key on/off register
Mike Pavone <pavone@retrodev.com>
parents:
383
diff
changeset
|
685 if (channel != 3 && channel != 7) { |
6e5c4f3ab0e2
Fix channel mapping in key on/off register
Mike Pavone <pavone@retrodev.com>
parents:
383
diff
changeset
|
686 if (channel > 2) { |
6e5c4f3ab0e2
Fix channel mapping in key on/off register
Mike Pavone <pavone@retrodev.com>
parents:
383
diff
changeset
|
687 channel--; |
6e5c4f3ab0e2
Fix channel mapping in key on/off register
Mike Pavone <pavone@retrodev.com>
parents:
383
diff
changeset
|
688 } |
362 | 689 for (uint8_t op = channel * 4, bit = 0x10; op < (channel + 1) * 4; op++, bit <<= 1) { |
690 if (value & bit) { | |
448
e85a107e6ec0
Fix handling of key on in YM2612 core
Mike Pavone <pavone@retrodev.com>
parents:
424
diff
changeset
|
691 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
|
692 { |
e85a107e6ec0
Fix handling of key on in YM2612 core
Mike Pavone <pavone@retrodev.com>
parents:
424
diff
changeset
|
693 first_key_on = 1; |
e85a107e6ec0
Fix handling of key on in YM2612 core
Mike Pavone <pavone@retrodev.com>
parents:
424
diff
changeset
|
694 //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
|
695 context->operators[op].phase_counter = 0; |
e85a107e6ec0
Fix handling of key on in YM2612 core
Mike Pavone <pavone@retrodev.com>
parents:
424
diff
changeset
|
696 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
|
697 } |
362 | 698 } else { |
699 //printf("Key Off for operator %d in channel %d\n", op, channel); | |
700 context->operators[op].env_phase = PHASE_RELEASE; | |
701 } | |
702 } | |
703 } | |
704 break; | |
705 } | |
706 case REG_DAC: | |
707 if (context->dac_enable) { | |
708 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
|
709 //printf("DAC Write %X(%d) @ %d\n", value, context->channels[5].output, context->current_cycle); |
362 | 710 } |
711 break; | |
712 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
|
713 //printf("DAC Enable: %X\n", value); |
362 | 714 context->dac_enable = value & 0x80; |
715 break; | |
716 } | |
717 } else if (context->selected_reg < 0xA0) { | |
718 //part | |
719 uint8_t op = context->selected_part ? (NUM_OPERATORS/2) : 0; | |
720 //channel in part | |
721 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
|
722 op += 4 * (context->selected_reg & 0x3) + ((context->selected_reg & 0xC) / 4); |
362 | 723 //printf("write targets operator %d (%d of channel %d)\n", op, op % 4, op / 4); |
724 ym_operator * operator = context->operators + op; | |
725 switch (context->selected_reg & 0xF0) | |
726 { | |
727 case REG_DETUNE_MULT: | |
728 operator->detune = value >> 4 & 0x7; | |
729 operator->multiple = value & 0xF; | |
730 ym_update_phase_inc(context, operator, op); | |
731 break; | |
732 case REG_TOTAL_LEVEL: | |
733 operator->total_level = (value & 0x7F) << 5; | |
734 break; | |
735 case REG_ATTACK_KS: | |
376 | 736 operator->key_scaling = 3 - (value >> 6); |
362 | 737 operator->rates[PHASE_ATTACK] = value & 0x1F; |
738 break; | |
739 case REG_DECAY_AM: | |
740 //TODO: AM flag for LFO | |
741 operator->rates[PHASE_DECAY] = value & 0x1F; | |
742 break; | |
743 case REG_SUSTAIN_RATE: | |
744 operator->rates[PHASE_SUSTAIN] = value & 0x1F; | |
745 break; | |
746 case REG_S_LVL_R_RATE: | |
747 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
|
748 operator->sustain_level = (value & 0xF0) << 4; |
362 | 749 break; |
750 } | |
751 } | |
752 } else { | |
753 uint8_t channel = context->selected_reg & 0x3; | |
754 if (channel != 3) { | |
755 if (context->selected_part) { | |
756 channel += 3; | |
757 } | |
758 //printf("write targets channel %d\n", channel); | |
759 switch (context->selected_reg & 0xFC) | |
760 { | |
761 case REG_FNUM_LOW: | |
762 context->channels[channel].block = context->channels[channel].block_fnum_latch >> 3 & 0x7; | |
763 context->channels[channel].fnum = (context->channels[channel].block_fnum_latch & 0x7) << 8 | value; | |
764 context->channels[channel].keycode = context->channels[channel].block << 2 | fnum_to_keycode[context->channels[channel].fnum >> 7]; | |
765 ym_update_phase_inc(context, context->operators + channel*4, channel*4); | |
766 ym_update_phase_inc(context, context->operators + channel*4+1, channel*4+1); | |
767 ym_update_phase_inc(context, context->operators + channel*4+2, channel*4+2); | |
768 ym_update_phase_inc(context, context->operators + channel*4+3, channel*4+3); | |
769 break; | |
770 case REG_BLOCK_FNUM_H:{ | |
771 context->channels[channel].block_fnum_latch = value; | |
772 break; | |
773 } | |
383
72933100c55c
Initial implementation of channel 3 special mode
Mike Pavone <pavone@retrodev.com>
parents:
382
diff
changeset
|
774 case REG_FNUM_LOW_CH3: |
72933100c55c
Initial implementation of channel 3 special mode
Mike Pavone <pavone@retrodev.com>
parents:
382
diff
changeset
|
775 if (channel < 3) { |
72933100c55c
Initial implementation of channel 3 special mode
Mike Pavone <pavone@retrodev.com>
parents:
382
diff
changeset
|
776 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
|
777 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
|
778 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
|
779 if (context->ch3_mode) { |
72933100c55c
Initial implementation of channel 3 special mode
Mike Pavone <pavone@retrodev.com>
parents:
382
diff
changeset
|
780 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
|
781 } |
72933100c55c
Initial implementation of channel 3 special mode
Mike Pavone <pavone@retrodev.com>
parents:
382
diff
changeset
|
782 } |
72933100c55c
Initial implementation of channel 3 special mode
Mike Pavone <pavone@retrodev.com>
parents:
382
diff
changeset
|
783 break; |
72933100c55c
Initial implementation of channel 3 special mode
Mike Pavone <pavone@retrodev.com>
parents:
382
diff
changeset
|
784 case REG_BLOCK_FN_CH3: |
72933100c55c
Initial implementation of channel 3 special mode
Mike Pavone <pavone@retrodev.com>
parents:
382
diff
changeset
|
785 if (channel < 3) { |
72933100c55c
Initial implementation of channel 3 special mode
Mike Pavone <pavone@retrodev.com>
parents:
382
diff
changeset
|
786 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
|
787 } |
72933100c55c
Initial implementation of channel 3 special mode
Mike Pavone <pavone@retrodev.com>
parents:
382
diff
changeset
|
788 break; |
362 | 789 case REG_ALG_FEEDBACK: |
790 context->channels[channel].algorithm = value & 0x7; | |
791 context->channels[channel].feedback = value >> 3 & 0x7; | |
527
7df7f493b3b6
Fix operator 1 self-feedback
Michael Pavone <pavone@retrodev.com>
parents:
522
diff
changeset
|
792 //printf("Algorithm %d, feedback %d for channel %d\n", value & 0x7, value >> 3 & 0x7, channel); |
362 | 793 break; |
794 case REG_LR_AMS_PMS: | |
411
baf4688901f2
Initial stab at LFO phase modulation
Mike Pavone <pavone@retrodev.com>
parents:
407
diff
changeset
|
795 context->channels[channel].pms = (value & 0x7) * 32; |
362 | 796 context->channels[channel].ams = value >> 4 & 0x3; |
797 context->channels[channel].lr = value & 0xC0; | |
369
fc820ab1394b
Fix left/right enable default value
Mike Pavone <pavone@retrodev.com>
parents:
365
diff
changeset
|
798 //printf("Write of %X to LR_AMS_PMS reg for channel %d\n", value, channel); |
362 | 799 break; |
800 } | |
801 } | |
802 } | |
448
e85a107e6ec0
Fix handling of key on in YM2612 core
Mike Pavone <pavone@retrodev.com>
parents:
424
diff
changeset
|
803 |
362 | 804 context->write_cycle = context->current_cycle; |
374 | 805 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
|
806 } |
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
|
807 |
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
|
808 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
|
809 { |
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
|
810 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
|
811 } |
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
|
812 |