git.y1.nz

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.