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