summaryrefslogtreecommitdiff
path: root/apps/codecs/libgme/gb_oscs.h
diff options
context:
space:
mode:
Diffstat (limited to 'apps/codecs/libgme/gb_oscs.h')
-rw-r--r--apps/codecs/libgme/gb_oscs.h198
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
18enum { clk_mul = GB_APU_OVERCLOCK };
19enum { dac_bias = 7 };
20
21struct 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
38static inline int Osc_frequency( struct Gb_Osc* this ) { return (this->regs [4] & 7) * 0x100 + this->regs [3]; }
39
40void Osc_update_amp( struct Gb_Osc* this, blip_time_t, int new_amp ) ICODE_ATTR;
41int Osc_write_trig( struct Gb_Osc* this, int frame_phase, int max_len, int old_data ) ICODE_ATTR;
42void Osc_clock_length( struct Gb_Osc* this ) ICODE_ATTR;
43void Osc_reset( struct Gb_Osc* this );
44
45// Square
46
47enum { period_mask = 0x70 };
48enum { shift_mask = 0x07 };
49
50struct 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
64bool Square_write_register( struct Gb_Square* this, int frame_phase, int reg, int old_data, int data ) ICODE_ATTR;
65void Square_run( struct Gb_Square* this, blip_time_t, blip_time_t ) ICODE_ATTR;
66void Square_clock_envelope( struct Gb_Square* this ) ICODE_ATTR;
67
68static 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
76static inline int Square_period( struct Gb_Square* this ) { return (2048 - Osc_frequency( &this->osc )) * (4 * clk_mul); }
77static inline int Square_dac_enabled( struct Gb_Square* this) { return this->osc.regs [2] & 0xF8; }
78static 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
87void clock_sweep( struct Gb_Square* this ) ICODE_ATTR;
88void Sweep_write_register( struct Gb_Square* this, int frame_phase, int reg, int old_data, int data ) ICODE_ATTR;
89
90static 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
103void calc_sweep( struct Gb_Square* this, bool update ) ICODE_ATTR;
104void reload_sweep_timer( struct Gb_Square* this ) ICODE_ATTR;
105
106// Noise
107
108enum { period2_mask = 0x1FFFF };
109
110struct 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
120void Noise_run( struct Gb_Noise* this, blip_time_t, blip_time_t ) ICODE_ATTR;
121void Noise_write_register( struct Gb_Noise* this, int frame_phase, int reg, int old_data, int data ) ICODE_ATTR;
122
123static 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
133void Noise_clock_envelope( struct Gb_Noise* this ) ICODE_ATTR;
134
135// Non-zero if DAC is enabled
136static inline int Noise_dac_enabled( struct Gb_Noise* this) { return this->osc.regs [2] & 0xF8; }
137static 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
144static inline int period2_index( struct Gb_Noise* this ) { return this->osc.regs [3] >> 4; }
145static inline int period2( struct Gb_Noise* this, int base ) { return base << period2_index( this ); }
146static inline unsigned lfsr_mask( struct Gb_Noise* this ) { return (this->osc.regs [3] & 0x08) ? ~0x4040 : ~0x4000; }
147
148// Wave
149
150enum { bank40_mask = 0x40 };
151enum { wave_bank_size = 32 };
152
153struct 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
162void Wave_write_register( struct Gb_Wave* this, int frame_phase, int reg, int old_data, int data ) ICODE_ATTR;
163void Wave_run( struct Gb_Wave* this, blip_time_t, blip_time_t ) ICODE_ATTR;
164
165static 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
172static 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
175static inline int Wave_dac_enabled( struct Gb_Wave* this ) { return this->osc.regs [0] & 0x80; }
176
177void corrupt_wave( struct Gb_Wave* this );
178
179static 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
182int wave_access( struct Gb_Wave* this, int addr ) ICODE_ATTR;
183
184// Reads/writes wave RAM
185static 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
191static 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