diff options
Diffstat (limited to 'apps/codecs/libgme/gb_oscs.h')
-rw-r--r-- | apps/codecs/libgme/gb_oscs.h | 198 |
1 files changed, 198 insertions, 0 deletions
diff --git a/apps/codecs/libgme/gb_oscs.h b/apps/codecs/libgme/gb_oscs.h new file mode 100644 index 0000000000..0cc9d3f567 --- /dev/null +++ b/apps/codecs/libgme/gb_oscs.h | |||
@@ -0,0 +1,198 @@ | |||
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_update_amp( struct Gb_Osc* this, blip_time_t, int new_amp ) ICODE_ATTR; | ||
41 | int Osc_write_trig( struct Gb_Osc* this, int frame_phase, int max_len, int old_data ) ICODE_ATTR; | ||
42 | void Osc_clock_length( struct Gb_Osc* this ) ICODE_ATTR; | ||
43 | void Osc_reset( struct Gb_Osc* this ); | ||
44 | |||
45 | // Square | ||
46 | |||
47 | enum { period_mask = 0x70 }; | ||
48 | enum { shift_mask = 0x07 }; | ||
49 | |||
50 | struct Gb_Square { | ||
51 | struct Gb_Osc osc; | ||
52 | |||
53 | int env_delay; | ||
54 | int volume; | ||
55 | bool env_enabled; | ||
56 | |||
57 | // Sweep square | ||
58 | int sweep_freq; | ||
59 | int sweep_delay; | ||
60 | bool sweep_enabled; | ||
61 | bool sweep_neg; | ||
62 | }; | ||
63 | |||
64 | bool Square_write_register( struct Gb_Square* this, int frame_phase, int reg, int old_data, int data ) ICODE_ATTR; | ||
65 | void Square_run( struct Gb_Square* this, blip_time_t, blip_time_t ) ICODE_ATTR; | ||
66 | void Square_clock_envelope( struct Gb_Square* this ) ICODE_ATTR; | ||
67 | |||
68 | static inline void Square_reset( struct Gb_Square* this ) | ||
69 | { | ||
70 | this->env_delay = 0; | ||
71 | this->volume = 0; | ||
72 | Osc_reset( &this->osc ); | ||
73 | this->osc.delay = 0x40000000; // TODO: something less hacky (never clocked until first trigger) | ||
74 | } | ||
75 | // Frequency timer period | ||
76 | static inline int Square_period( struct Gb_Square* this ) { return (2048 - Osc_frequency( &this->osc )) * (4 * clk_mul); } | ||
77 | static inline int Square_dac_enabled( struct Gb_Square* this) { return this->osc.regs [2] & 0xF8; } | ||
78 | static inline int Square_reload_env_timer( struct Gb_Square* this ) | ||
79 | { | ||
80 | int raw = this->osc.regs [2] & 7; | ||
81 | this->env_delay = (raw ? raw : 8); | ||
82 | return raw; | ||
83 | } | ||
84 | |||
85 | // Sweep square | ||
86 | |||
87 | void clock_sweep( struct Gb_Square* this ) ICODE_ATTR; | ||
88 | void Sweep_write_register( struct Gb_Square* this, int frame_phase, int reg, int old_data, int data ) ICODE_ATTR; | ||
89 | |||
90 | static inline void Sweep_reset( struct Gb_Square* this ) | ||
91 | { | ||
92 | this->sweep_freq = 0; | ||
93 | this->sweep_delay = 0; | ||
94 | this->sweep_enabled = false; | ||
95 | this->sweep_neg = false; | ||
96 | |||
97 | this->env_delay = 0; | ||
98 | this->volume = 0; | ||
99 | Osc_reset( &this->osc ); | ||
100 | this->osc.delay = 0x40000000; // TODO: something less hacky (never clocked until first trigger) | ||
101 | } | ||
102 | |||
103 | void calc_sweep( struct Gb_Square* this, bool update ) ICODE_ATTR; | ||
104 | void reload_sweep_timer( struct Gb_Square* this ) ICODE_ATTR; | ||
105 | |||
106 | // Noise | ||
107 | |||
108 | enum { period2_mask = 0x1FFFF }; | ||
109 | |||
110 | struct Gb_Noise { | ||
111 | struct Gb_Osc osc; | ||
112 | |||
113 | int env_delay; | ||
114 | int volume; | ||
115 | bool env_enabled; | ||
116 | |||
117 | int divider; // noise has more complex frequency divider setup | ||
118 | }; | ||
119 | |||
120 | void Noise_run( struct Gb_Noise* this, blip_time_t, blip_time_t ) ICODE_ATTR; | ||
121 | void Noise_write_register( struct Gb_Noise* this, int frame_phase, int reg, int old_data, int data ) ICODE_ATTR; | ||
122 | |||
123 | static inline void Noise_reset( struct Gb_Noise* this ) | ||
124 | { | ||
125 | this->divider = 0; | ||
126 | |||
127 | this->env_delay = 0; | ||
128 | this->volume = 0; | ||
129 | Osc_reset( &this->osc ); | ||
130 | this->osc.delay = 4 * clk_mul; // TODO: remove? | ||
131 | } | ||
132 | |||
133 | void Noise_clock_envelope( struct Gb_Noise* this ) ICODE_ATTR; | ||
134 | |||
135 | // Non-zero if DAC is enabled | ||
136 | static inline int Noise_dac_enabled( struct Gb_Noise* this) { return this->osc.regs [2] & 0xF8; } | ||
137 | static inline int Noise_reload_env_timer( struct Gb_Noise* this ) | ||
138 | { | ||
139 | int raw = this->osc.regs [2] & 7; | ||
140 | this->env_delay = (raw ? raw : 8); | ||
141 | return raw; | ||
142 | } | ||
143 | |||
144 | static inline int period2_index( struct Gb_Noise* this ) { return this->osc.regs [3] >> 4; } | ||
145 | static inline int period2( struct Gb_Noise* this, int base ) { return base << period2_index( this ); } | ||
146 | static inline unsigned lfsr_mask( struct Gb_Noise* this ) { return (this->osc.regs [3] & 0x08) ? ~0x4040 : ~0x4000; } | ||
147 | |||
148 | // Wave | ||
149 | |||
150 | enum { bank40_mask = 0x40 }; | ||
151 | enum { wave_bank_size = 32 }; | ||
152 | |||
153 | struct Gb_Wave { | ||
154 | struct Gb_Osc osc; | ||
155 | |||
156 | int sample_buf; // last wave RAM byte read (hardware has this as well) | ||
157 | |||
158 | int agb_mask; // 0xFF if AGB features enabled, 0 otherwise | ||
159 | uint8_t* wave_ram; // 32 bytes (64 nybbles), stored in APU | ||
160 | }; | ||
161 | |||
162 | void Wave_write_register( struct Gb_Wave* this, int frame_phase, int reg, int old_data, int data ) ICODE_ATTR; | ||
163 | void Wave_run( struct Gb_Wave* this, blip_time_t, blip_time_t ) ICODE_ATTR; | ||
164 | |||
165 | static inline void Wave_reset( struct Gb_Wave* this ) | ||
166 | { | ||
167 | this->sample_buf = 0; | ||
168 | Osc_reset( &this->osc ); | ||
169 | } | ||
170 | |||
171 | // Frequency timer period | ||
172 | static inline int Wave_period( struct Gb_Wave* this ) { return (2048 - Osc_frequency( &this->osc )) * (2 * clk_mul); } | ||
173 | |||
174 | // Non-zero if DAC is enabled | ||
175 | static inline int Wave_dac_enabled( struct Gb_Wave* this ) { return this->osc.regs [0] & 0x80; } | ||
176 | |||
177 | void corrupt_wave( struct Gb_Wave* this ); | ||
178 | |||
179 | static inline uint8_t* wave_bank( struct Gb_Wave* this ) { return &this->wave_ram [(~this->osc.regs [0] & bank40_mask) >> 2 & this->agb_mask]; } | ||
180 | |||
181 | // Wave index that would be accessed, or -1 if no access would occur | ||
182 | int wave_access( struct Gb_Wave* this, int addr ) ICODE_ATTR; | ||
183 | |||
184 | // Reads/writes wave RAM | ||
185 | static inline int Wave_read( struct Gb_Wave* this, int addr ) | ||
186 | { | ||
187 | int index = wave_access( this, addr ); | ||
188 | return (index < 0 ? 0xFF : wave_bank( this ) [index]); | ||
189 | } | ||
190 | |||
191 | static inline void Wave_write( struct Gb_Wave* this, int addr, int data ) | ||
192 | { | ||
193 | int index = wave_access( this, addr ); | ||
194 | if ( index >= 0 ) | ||
195 | wave_bank( this ) [index] = data;; | ||
196 | } | ||
197 | |||
198 | #endif | ||