forked from libretro/libretro-fceumm
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- start using structs for each channel - revised duty cycle / step counter in square duty logic - use lookup table for square duty cycle and triangle wave - use more accurate frame counter timing (pass some tests, improves accuracy but causes moderate loss of performance) - cleanups and others
- Loading branch information
1 parent
32d8fd3
commit 3a17e2a
Showing
3 changed files
with
1,014 additions
and
810 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,141 @@ | ||
#ifndef _FCEU_APU_H | ||
#define _FCEU_APU_H | ||
|
||
enum FrameSeqMode { | ||
FrameFourStepMode = 0, | ||
FrameFiveStepMode = 1 | ||
}; | ||
|
||
enum FrameType { | ||
FrameNone = 0, | ||
FrameHalf = 1, | ||
FrameQuarter = 2 | ||
}; | ||
|
||
enum WavePositionShift { | ||
SQ_SHIFT = 24, | ||
TRINPCM_SHIFT = 16 | ||
}; | ||
|
||
typedef struct Timer { | ||
uint16 period; /* Frequency period for square wave (controls pitch) */ | ||
|
||
/* Internal */ | ||
int32 counter; /* Counter tracking the square wave period (timing of cycles) */ | ||
int32 count2; /* Shifted period timer for low-quality mode */ | ||
} Timer; | ||
|
||
typedef struct LengthCount { | ||
/* Registers */ | ||
uint8 enabled; /* set by channel enable flag in 4015 write */ | ||
uint8 halt; /* Halt flag: if set, disables further counting */ | ||
|
||
uint8 counter; /* Current count value for length counter (counts down) */ | ||
|
||
uint8 delayHalt; | ||
uint8 delayCounter; | ||
uint8 nextHalt; | ||
uint8 nextCounter; | ||
} LengthCount; | ||
|
||
typedef struct Envelope { | ||
/* Register */ | ||
uint8 loop; /* Loop mode flag: if set, envelope restarts after reaching a certain state */ | ||
uint8 constant; /* Constant mode flag: if set, volume remains constant */ | ||
uint8 speed; /* Speed of volume decay, affecting the rate of decrease */ | ||
|
||
/* internal */ | ||
uint8 decay_volume; /* Current volume level during the decay phase */ | ||
uint8 counter; /* Counter tracking the current state of decay process */ | ||
uint8 reload; /* Flag to reload decay counter (restarts volume decrease) */ | ||
} Envelope; | ||
|
||
typedef struct Sweep { | ||
/* Register */ | ||
uint8 enabled; /* Enable flag for sweep operation (if set, sweep occurs) */ | ||
uint8 period; /* Sweep period: determines the rate at which frequency is adjusted */ | ||
uint8 negate; /* Negate flag: if set, subtracts from the frequency during sweep */ | ||
uint8 shift; /* Number of bits to shift for frequency adjustment in the sweep */ | ||
|
||
uint16 pulsePeriod; /* Period of the pulse being swept (frequency of waveform) */ | ||
|
||
/* Internal */ | ||
uint8 id; | ||
uint8 counter; /* Counter for sweep timing (decrements until reload) */ | ||
uint8 reload; /* Reload flag: when set, resets sweep counter to initial value */ | ||
} Sweep; | ||
|
||
typedef struct SquareUnit { | ||
/* Registers*/ | ||
uint8 duty; /* Duty cycle defines the waveform's high-to-low ratio */ | ||
|
||
/* Internal */ | ||
uint8 step; /* Counter for tracking the current phase of the duty cycle */ | ||
|
||
LengthCount length; /* Length counter to manage note duration for square wave */ | ||
Envelope envelope; /* Envelope to control volume for square wave */ | ||
Sweep sweep; /* Sweep to modify frequency of square wave */ | ||
Timer timer; /* Cycle counter and period to reload */ | ||
} SquareUnit; | ||
|
||
typedef struct TriangleUnit { | ||
uint8 linearPeriod; /* Linear length control value for the triangle wave */ | ||
|
||
/* Internal */ | ||
uint8 linearCounter; /* Counter to track linear length during envelope decay */ | ||
uint8 linearReload; /* Flag to reload the linear length counter */ | ||
uint8 stepCounter; /* Counter for tracking the steps in the triangle wave's length */ | ||
|
||
LengthCount length; /* Length counter for triangle wave channel (note duration) */ | ||
Timer timer; /* Cycle counter and period to reload */ | ||
} TriangleUnit; | ||
|
||
typedef struct NoiseUnit { | ||
/* Register */ | ||
uint8 shortMode; /* Short mode flag for noise wave: alters frequency generation behavior */ | ||
uint8 periodIndex; /* The period determines how many CPU cycles happen between shift register clocks. */ | ||
|
||
/* Internal */ | ||
uint16 shiftRegister; /* Shift register used to generate noise waveform */ | ||
|
||
LengthCount length; /* Length counter for noise wave channel (note duration) */ | ||
Envelope envelope; /* Envelope to control volume for noise wave */ | ||
Timer timer; /* Cycle counter and period to reload */ | ||
} NoiseUnit; | ||
|
||
typedef struct DMCUnit { | ||
uint8 bitCounter; /* Bit counter for reading sample data bits (tracks position in current sample) */ | ||
|
||
uint8 addressLatch; /* Address latch for DMC sample address (mapped to $4012) */ | ||
uint8 lengthLatch; /* Length latch for DMC sample length (mapped to $4013) */ | ||
uint8 periodIndex; /* The rate determines for how many CPU cycles happen between changes in the output level during automatic delta-encoded sample playback */ | ||
uint8 loop; /* Loop flag for DMC sample (1 = loop, 0 = no loop) */ | ||
uint8 irqEnabled; /* IRQ enabled flag: if set, triggers IRQ when sample finishes loading */ | ||
uint8 irqPending; /* Flag indicating if an IRQ is pending */ | ||
|
||
uint16 readAddress; /* Address to read data from in memory for DMC sample */ | ||
uint16 lengthCounter; /* Counter for the length of the sample data to play */ | ||
uint8 sampleShiftReg; /* Holds the current sample data during DMA shift processing */ | ||
|
||
uint8 dmaBufferValid; /* Flag indicating whether the DMA buffer contains valid data */ | ||
uint8 dmaBuffer; /* DMA buffer for transferring sample data to audio output */ | ||
uint8 sampleValid; /* Sample validity flag: indicates if sample data is properly loaded */ | ||
uint8 rawDataLatch; /* Raw data latch for DMC control (mapped to $4011 0xxxxxxx) */ | ||
|
||
Timer timer; | ||
} DMCUnit; | ||
|
||
typedef struct FrameCounter { | ||
uint8 mode; /* Mode of the frame counter operation, 1=5-step, 0=4-step */ | ||
uint8 irqInhibit; /* Flag to inhibit IRQ generation */ | ||
uint8 irqPending; /* Flag indicating if an IRQ is pending */ | ||
uint8 step; /* Current step in frame counter operation */ | ||
|
||
/* Timers */ | ||
int32 counter; /* frame cycle counter */ | ||
|
||
uint8 delay; /* Delay after 4017 write */ | ||
uint8 newMode; | ||
} FrameCounter; | ||
|
||
#endif /* _FCEU_APU_H */ |
Oops, something went wrong.