SameBoy | Accurate GB/GBC emulator |
| download: https://git.y1.nz/archives/sameboy.tar.gz | |
| README | Files | Log | Refs | LICENSE |
Core/apu.h
1 #pragma once
2 #include <stdbool.h>
3 #include <stdint.h>
4 #include <stddef.h>
5 #include <stdio.h>
6 #include "defs.h"
7
8 #define GB_BAND_LIMITED_WIDTH 64
9 #define GB_BAND_LIMITED_PHASES 256
10
11 #define GB_QUICK_MULTIPLY_COUNT 64
12
13 #ifdef GB_INTERNAL
14 #define GB_BAND_LIMITED_ONE 0x10000 // fixed point value equal to 1
15
16 /* Speed = 1 / Length (in seconds) */
17 #define DAC_DECAY_SPEED 20000
18 #define DAC_ATTACK_SPEED 20000
19
20
21 /* Divides nicely and never overflows with 4 channels and 8 (1-8) volume levels */
22 #define MAX_CH_AMP 0xFF0
23 #define CH_STEP (MAX_CH_AMP/0xF/8)
24 #endif
25
26
27
28 /* APU ticks are 2MHz, triggered by an internal APU clock. */
29
30 #ifdef GB_INTERNAL
31 typedef union
32 {
33 struct {
34 int16_t left;
35 int16_t right;
36 };
37 uint32_t packed;
38 } GB_sample_t;
39 #else
40 typedef struct
41 {
42 int16_t left;
43 int16_t right;
44 } GB_sample_t;
45 #endif
46
47 typedef struct
48 {
49 double left;
50 double right;
51 } GB_double_sample_t;
52
53 typedef enum {
54 GB_SQUARE_1,
55 GB_SQUARE_2,
56 GB_WAVE,
57 GB_NOISE,
58 GB_N_CHANNELS
59 } GB_channel_t;
60
61 typedef struct
62 {
63 bool locked:1; // Represents FYNO's output on channel 4
64 bool clock:1; // Represents FOSY on channel 4
65 bool should_lock:1; // Represents FYNO's input on channel 4
66 uint8_t padding:5;
67 } GB_envelope_clock_t;
68
69 typedef void (*GB_sample_callback_t)(GB_gameboy_t *gb, GB_sample_t *sample);
70
71 typedef struct
72 {
73 bool global_enable;
74 uint16_t apu_cycles;
75
76 uint8_t samples[GB_N_CHANNELS];
77 bool is_active[GB_N_CHANNELS];
78
79 uint8_t div_divider; // The DIV register ticks the APU at 512Hz, but is then divided
80 // once more to generate 128Hz and 64Hz clocks
81
82 uint8_t lf_div; // The APU runs in 2MHz, but channels 1, 2 and 4 run in 1MHZ so we divide
83 // need to divide the signal.
84
85 uint8_t square_sweep_countdown; // In 128Hz
86 uint8_t square_sweep_calculate_countdown; // In 1 MHz
87 uint8_t square_sweep_calculate_countdown_reload_timer; // In 1 Mhz, for glitches related to reloading square_sweep_calculate_countdown
88 uint16_t sweep_length_addend;
89 uint16_t shadow_sweep_sample_length;
90 bool unshifted_sweep;
91 bool square_sweep_instant_calculation_done;
92
93 uint8_t channel_1_restart_hold;
94 uint16_t channel1_completed_addend;
95 struct {
96 uint16_t pulse_length; // Reloaded from NRX1 (xorred), in 256Hz DIV ticks
97 uint8_t current_volume; // Reloaded from NRX2
98 uint8_t volume_countdown; // Reloaded from NRX2
99 uint8_t current_sample_index;
100 bool sample_surpressed;
101
102 uint16_t sample_countdown; // in APU ticks (Reloaded from sample_length, xorred $7FF)
103 uint16_t sample_length; // From NRX3, NRX4, in APU ticks
104 bool length_enabled; // NRX4
105 GB_envelope_clock_t envelope_clock;
106 uint8_t delay; // Hack for CGB D/E phantom step due to how sample_countdown is implemented in SameBoy
107 bool did_tick:1;
108 bool just_reloaded:1;
109 uint8_t padding:6;
110 } square_channels[2];
111
112 struct {
113 bool enable; // NR30
114 uint16_t pulse_length; // Reloaded from NR31 (xorred), in 256Hz DIV ticks
115 uint8_t shift; // NR32
116 uint16_t sample_length; // NR33, NR34, in APU ticks
117 bool length_enabled; // NR34
118
119 uint16_t sample_countdown; // in APU ticks (Reloaded from sample_length, xorred $7FF)
120 uint8_t current_sample_index;
121 uint8_t current_sample_byte; // Current sample byte.
122 bool wave_form_just_read;
123 bool pulsed;
124 uint8_t bugged_read_countdown;
125 } wave_channel;
126
127 struct {
128 uint16_t pulse_length; // Reloaded from NR41 (xorred), in 256Hz DIV ticks
129 uint8_t current_volume; // Reloaded from NR42
130 uint8_t volume_countdown; // Reloaded from NR42
131 uint16_t lfsr;
132 bool narrow;
133
134 uint8_t counter_countdown; // Counts from 0-7 to 0 to tick counter (Scaled from 512KHz to 2MHz)
135 uint16_t counter; // A bit from this 14-bit register ticks LFSR
136 bool length_enabled; // NR44
137
138 uint8_t alignment; // If (NR43 & 7) != 0, samples are aligned to 512KHz clock instead of
139 // 1MHz. This variable keeps track of the alignment.
140 bool current_lfsr_sample;
141 bool did_step_counter;
142 bool countdown_reloaded;
143 uint8_t dmg_delayed_start;
144 GB_envelope_clock_t envelope_clock;
145 } noise_channel;
146
147 GB_ENUM(uint8_t, {
148 GB_SKIP_DIV_EVENT_INACTIVE,
149 GB_SKIP_DIV_EVENT_SKIPPED,
150 GB_SKIP_DIV_EVENT_SKIP,
151 }) skip_div_event;
152 uint8_t pcm_mask[2]; // For CGB-0 to CGB-C PCM read glitch
153
154 bool apu_cycles_in_2mhz; // For compatibility with 0.16.x save states
155 bool pending_envelope_tick;
156
157 // Move to noise struct when breaking compat
158 bool noise_counter_active;
159 bool noise_background_counter_active;
160 bool lfsr_stepped_in_narrow;
161 bool lfsr_bit_7_before_step; // Used by some corruptions?
162 bool noise_started_with_dac_disabled; // TODO: Background counting behaves slightly different this way?
163 } GB_apu_t;
164
165 typedef enum {
166 GB_HIGHPASS_OFF, // Do not apply any filter, keep DC offset
167 GB_HIGHPASS_ACCURATE, // Apply a highpass filter similar to the one used on hardware
168 GB_HIGHPASS_REMOVE_DC_OFFSET, // Remove DC Offset without affecting the waveform
169 GB_HIGHPASS_MAX
170 } GB_highpass_mode_t;
171
172 typedef enum {
173 GB_AUDIO_FORMAT_RAW, // Native endian
174 GB_AUDIO_FORMAT_AIFF, // Native endian
175 GB_AUDIO_FORMAT_WAV,
176 } GB_audio_format_t;
177
178 typedef struct {
179 struct {
180 int32_t left, right;
181 } buffer[GB_BAND_LIMITED_WIDTH * 2], output;
182 uint8_t pos;
183 GB_sample_t input;
184 GB_sample_t last_output;
185 unsigned silence_detection;
186 } GB_band_limited_t;
187
188 typedef struct {
189 unsigned sample_rate;
190
191 unsigned sample_cycles; // Counts by sample_rate until it reaches the clock frequency
192 unsigned max_cycles_per_sample;
193
194 uint32_t cycles_since_render;
195 uint32_t sample_fraction; // Counter in 1 / sample_rate, in 4.28 fixed format
196 uint32_t quick_fraction_multiply_cache[GB_QUICK_MULTIPLY_COUNT];
197
198 GB_band_limited_t band_limited[GB_N_CHANNELS];
199 double dac_discharge[GB_N_CHANNELS];
200 bool channel_muted[GB_N_CHANNELS];
201 bool edge_triggered[GB_N_CHANNELS];
202
203 GB_highpass_mode_t highpass_mode;
204 double highpass_rate;
205 GB_double_sample_t highpass_diff;
206
207 GB_sample_callback_t sample_callback;
208
209 double interference_volume;
210 double interference_highpass;
211
212 FILE *output_file;
213 GB_audio_format_t output_format;
214 int output_error;
215
216 /* Not output related, but it's temp state so I'll put it here */
217 bool square_sweep_disable_stepping;
218 } GB_apu_output_t;
219
220 void GB_set_channel_muted(GB_gameboy_t *gb, GB_channel_t channel, bool muted);
221 bool GB_is_channel_muted(GB_gameboy_t *gb, GB_channel_t channel);
222 void GB_set_sample_rate(GB_gameboy_t *gb, unsigned sample_rate);
223 unsigned GB_get_sample_rate(GB_gameboy_t *gb);
224 void GB_set_sample_rate_by_clocks(GB_gameboy_t *gb, double cycles_per_sample); /* Cycles are in 8MHz units */
225 void GB_set_highpass_filter_mode(GB_gameboy_t *gb, GB_highpass_mode_t mode);
226 void GB_set_interference_volume(GB_gameboy_t *gb, double volume);
227 void GB_apu_set_sample_callback(GB_gameboy_t *gb, GB_sample_callback_t callback);
228 int GB_start_audio_recording(GB_gameboy_t *gb, const char *path, GB_audio_format_t format);
229 int GB_stop_audio_recording(GB_gameboy_t *gb);
230 uint8_t GB_get_channel_volume(GB_gameboy_t *gb, GB_channel_t channel);
231 uint8_t GB_get_channel_amplitude(GB_gameboy_t *gb, GB_channel_t channel);
232 uint16_t GB_get_channel_period(GB_gameboy_t *gb, GB_channel_t channel);
233 void GB_get_apu_wave_table(GB_gameboy_t *gb, uint8_t *wave_table);
234 bool GB_get_channel_edge_triggered(GB_gameboy_t *gb, GB_channel_t channel);
235 #ifdef GB_INTERNAL
236 internal bool GB_apu_is_DAC_enabled(GB_gameboy_t *gb, GB_channel_t index);
237 internal void GB_apu_write(GB_gameboy_t *gb, uint8_t reg, uint8_t value);
238 internal uint8_t GB_apu_read(GB_gameboy_t *gb, uint8_t reg);
239 internal void GB_apu_div_event(GB_gameboy_t *gb);
240 internal void GB_apu_div_secondary_event(GB_gameboy_t *gb);
241 internal void GB_apu_delayed_envelope_tick(GB_gameboy_t *gb);
242 internal void GB_apu_init(GB_gameboy_t *gb);
243 internal void GB_apu_run(GB_gameboy_t *gb, bool force);
244 #endif
This webpage is intended to be an accessible preview of this repository. To get a fuller picture, clone it and use the git CLI.