diff options
Diffstat (limited to 'lib/rbcodec/codecs/libgme/gb_oscs.h')
-rw-r--r-- | lib/rbcodec/codecs/libgme/gb_oscs.h | 187 |
1 files changed, 187 insertions, 0 deletions
diff --git a/lib/rbcodec/codecs/libgme/gb_oscs.h b/lib/rbcodec/codecs/libgme/gb_oscs.h new file mode 100644 index 0000000000..3c8dfef51f --- /dev/null +++ b/lib/rbcodec/codecs/libgme/gb_oscs.h | |||
@@ -0,0 +1,187 @@ | |||
1 | // Private oscillators used by Gb_Apu | ||
2 | |||
3 | // Gb_Snd_Emu 0.1.4 | ||
4 | #ifndef GB_OSCS_H | ||
5 | #define GB_OSCS_H | ||
6 | |||
7 | #include "blargg_common.h" | ||
8 | #include "blip_buffer.h" | ||
9 | |||
10 | #ifndef GB_APU_OVERCLOCK | ||
11 | #define GB_APU_OVERCLOCK 1 | ||
12 | #endif | ||
13 | |||
14 | #if GB_APU_OVERCLOCK & (GB_APU_OVERCLOCK - 1) | ||
15 | #error "GB_APU_OVERCLOCK must be a power of 2" | ||
16 | #endif | ||
17 | |||
18 | enum { clk_mul = GB_APU_OVERCLOCK }; | ||
19 | enum { dac_bias = 7 }; | ||
20 | |||
21 | struct Gb_Osc { | ||
22 | struct Blip_Buffer* outputs [4];// NULL, right, left, center | ||
23 | struct Blip_Buffer* output; // where to output sound | ||
24 | uint8_t* regs; // osc's 5 registers | ||
25 | int mode; // mode_dmg, mode_cgb, mode_agb | ||
26 | int dac_off_amp;// amplitude when DAC is off | ||
27 | int last_amp; // current amplitude in Blip_Buffer | ||
28 | |||
29 | struct Blip_Synth* synth; | ||
30 | |||
31 | int delay; // clocks until frequency timer expires | ||
32 | int length_ctr; // length counter | ||
33 | unsigned phase; // waveform phase (or equivalent) | ||
34 | bool enabled; // internal enabled flag | ||
35 | }; | ||
36 | |||
37 | // 11-bit frequency in NRx3 and NRx4 | ||
38 | static inline int Osc_frequency( struct Gb_Osc* this ) { return (this->regs [4] & 7) * 0x100 + this->regs [3]; } | ||
39 | |||
40 | void Osc_clock_length( struct Gb_Osc* this ); | ||
41 | void Osc_reset( struct Gb_Osc* this ); | ||
42 | |||
43 | // Square | ||
44 | |||
45 | enum { period_mask = 0x70 }; | ||
46 | enum { shift_mask = 0x07 }; | ||
47 | |||
48 | struct Gb_Square { | ||
49 | struct Gb_Osc osc; | ||
50 | |||
51 | int env_delay; | ||
52 | int volume; | ||
53 | bool env_enabled; | ||
54 | |||
55 | // Sweep square | ||
56 | int sweep_freq; | ||
57 | int sweep_delay; | ||
58 | bool sweep_enabled; | ||
59 | bool sweep_neg; | ||
60 | }; | ||
61 | |||
62 | void Square_run( struct Gb_Square* this, blip_time_t, blip_time_t ); | ||
63 | void Square_clock_envelope( struct Gb_Square* this ); | ||
64 | |||
65 | static inline void Square_reset( struct Gb_Square* this ) | ||
66 | { | ||
67 | this->env_delay = 0; | ||
68 | this->volume = 0; | ||
69 | Osc_reset( &this->osc ); | ||
70 | this->osc.delay = 0x40000000; // TODO: something less hacky (never clocked until first trigger) | ||
71 | } | ||
72 | // Frequency timer period | ||
73 | static inline int Square_period( struct Gb_Square* this ) { return (2048 - Osc_frequency( &this->osc )) * (4 * clk_mul); } | ||
74 | static inline int Square_dac_enabled( struct Gb_Square* this) { return this->osc.regs [2] & 0xF8; } | ||
75 | static inline int Square_reload_env_timer( struct Gb_Square* this ) | ||
76 | { | ||
77 | int raw = this->osc.regs [2] & 7; | ||
78 | this->env_delay = (raw ? raw : 8); | ||
79 | return raw; | ||
80 | } | ||
81 | |||
82 | // Sweep square | ||
83 | |||
84 | void clock_sweep( struct Gb_Square* this ); | ||
85 | |||
86 | static inline void Sweep_reset( struct Gb_Square* this ) | ||
87 | { | ||
88 | this->sweep_freq = 0; | ||
89 | this->sweep_delay = 0; | ||
90 | this->sweep_enabled = false; | ||
91 | this->sweep_neg = false; | ||
92 | |||
93 | this->env_delay = 0; | ||
94 | this->volume = 0; | ||
95 | Osc_reset( &this->osc ); | ||
96 | this->osc.delay = 0x40000000; // TODO: something less hacky (never clocked until first trigger) | ||
97 | } | ||
98 | |||
99 | // Noise | ||
100 | |||
101 | enum { period2_mask = 0x1FFFF }; | ||
102 | |||
103 | struct Gb_Noise { | ||
104 | struct Gb_Osc osc; | ||
105 | |||
106 | int env_delay; | ||
107 | int volume; | ||
108 | bool env_enabled; | ||
109 | |||
110 | int divider; // noise has more complex frequency divider setup | ||
111 | }; | ||
112 | |||
113 | void Noise_run( struct Gb_Noise* this, blip_time_t, blip_time_t ); | ||
114 | |||
115 | static inline void Noise_reset( struct Gb_Noise* this ) | ||
116 | { | ||
117 | this->divider = 0; | ||
118 | |||
119 | this->env_delay = 0; | ||
120 | this->volume = 0; | ||
121 | Osc_reset( &this->osc ); | ||
122 | this->osc.delay = 4 * clk_mul; // TODO: remove? | ||
123 | } | ||
124 | |||
125 | void Noise_clock_envelope( struct Gb_Noise* this ); | ||
126 | |||
127 | // Non-zero if DAC is enabled | ||
128 | static inline int Noise_dac_enabled( struct Gb_Noise* this) { return this->osc.regs [2] & 0xF8; } | ||
129 | static inline int Noise_reload_env_timer( struct Gb_Noise* this ) | ||
130 | { | ||
131 | int raw = this->osc.regs [2] & 7; | ||
132 | this->env_delay = (raw ? raw : 8); | ||
133 | return raw; | ||
134 | } | ||
135 | |||
136 | static inline int period2_index( struct Gb_Noise* this ) { return this->osc.regs [3] >> 4; } | ||
137 | static inline int period2( struct Gb_Noise* this, int base ) { return base << period2_index( this ); } | ||
138 | static inline unsigned lfsr_mask( struct Gb_Noise* this ) { return (this->osc.regs [3] & 0x08) ? ~0x4040 : ~0x4000; } | ||
139 | |||
140 | // Wave | ||
141 | |||
142 | enum { bank40_mask = 0x40 }; | ||
143 | enum { wave_bank_size = 32 }; | ||
144 | |||
145 | struct Gb_Wave { | ||
146 | struct Gb_Osc osc; | ||
147 | |||
148 | int sample_buf; // last wave RAM byte read (hardware has this as well) | ||
149 | |||
150 | int agb_mask; // 0xFF if AGB features enabled, 0 otherwise | ||
151 | uint8_t* wave_ram; // 32 bytes (64 nybbles), stored in APU | ||
152 | }; | ||
153 | |||
154 | void Wave_run( struct Gb_Wave* this, blip_time_t, blip_time_t ); | ||
155 | |||
156 | static inline void Wave_reset( struct Gb_Wave* this ) | ||
157 | { | ||
158 | this->sample_buf = 0; | ||
159 | Osc_reset( &this->osc ); | ||
160 | } | ||
161 | |||
162 | // Frequency timer period | ||
163 | static inline int Wave_period( struct Gb_Wave* this ) { return (2048 - Osc_frequency( &this->osc )) * (2 * clk_mul); } | ||
164 | |||
165 | // Non-zero if DAC is enabled | ||
166 | static inline int Wave_dac_enabled( struct Gb_Wave* this ) { return this->osc.regs [0] & 0x80; } | ||
167 | |||
168 | static inline uint8_t* wave_bank( struct Gb_Wave* this ) { return &this->wave_ram [(~this->osc.regs [0] & bank40_mask) >> 2 & this->agb_mask]; } | ||
169 | |||
170 | // Wave index that would be accessed, or -1 if no access would occur | ||
171 | int wave_access( struct Gb_Wave* this, int addr ); | ||
172 | |||
173 | // Reads/writes wave RAM | ||
174 | static inline int Wave_read( struct Gb_Wave* this, int addr ) | ||
175 | { | ||
176 | int index = wave_access( this, addr ); | ||
177 | return (index < 0 ? 0xFF : wave_bank( this ) [index]); | ||
178 | } | ||
179 | |||
180 | static inline void Wave_write( struct Gb_Wave* this, int addr, int data ) | ||
181 | { | ||
182 | int index = wave_access( this, addr ); | ||
183 | if ( index >= 0 ) | ||
184 | wave_bank( this ) [index] = data;; | ||
185 | } | ||
186 | |||
187 | #endif | ||