Skip to content

ApuCore

Class

Source: ApuCore.h

Description

Shared NES-style APU core used by every AudioScheduler.

Owns an eight-voice pool (MAX_VOICES = 8), the SPSC command queue and the music sequencer. Voice slots 0–3 are reserved for sequencer tracks (trackIdx maps 1:1 to slot); slots 4–7 are reserved for PLAY_EVENT / SFX and sequencer percussion hits (shared subpool, steal policy confined to 4–7). Platform-specific schedulers (DefaultAudioScheduler, ESP32AudioScheduler, NativeAudioScheduler) are thin orchestrators that decide when generateSamples() runs; all synthesis, mixing and sequencing lives here to eliminate the three-way duplication that existed before.

Mixing curve: per channel: s_c = wave_c(phase) * volume_c * MIXER_SCALE sum: S = Σ s_c (bounded to [-1.6, 1.6]) compressor: y = S / (1 + |S| * MIXER_K) output: y * masterVolume * 32767, passed through a single-pole DC-blocker to remove offset + transient clicks.

On cores without an FPU (ESP32-C3) the integer-optimised path uses audio_mixer_lut which is pre-fitted to the same curve.

Properties

NameTypeDescription
audioTimeSamplesuint64_tGlobal sample counter at capture.
peakfloatPeak sample magnitude [0.0 - 1.0].
clippedboolWhether any sample exceeded ±32767.

Methods

void init(int sampleRate)

Description:

Configures the output sample rate.

Parameters:

  • sampleRate: Sample rate in Hz (e.g., 22050, 44100).

Safe to call before start(). Pre-calculates internal timing values.

bool submitCommand(const AudioCommand& cmd)

Description:

Enqueues a command for processing.

Parameters:

  • cmd: The audio command to enqueue.

Returns: true if the command was enqueued, false if the queue was full.

void generateSamples(int16_t* stream, int length)

Description:

Generates audio samples.

Parameters:

  • stream: Output buffer (mono, int16 samples).
  • length: Number of samples to generate.

Processes all pending commands, updates music sequencer, and synthesizes voices into the output buffer. Applies master volume, bitcrush, and DC blocking.

uint32_t getDroppedCommands() const

Description:

Returns the total number of commands dropped since construction. @return Monotonic count.

Returns: Monotonic count.

void setSequencerNoteLimit(size_t limit)

Description:

Sets the maximum notes processed per audio frame.

Parameters:

  • limit: Max notes [1-1000], clamped to safe bounds internally.

Bounded processing prevents audio starvation when many notes queue up.

size_t getSequencerNoteLimit() const

Description:

Gets current max notes per frame setting. @return Current limit.

Returns: Current limit.

size_t getDeferredNotes() const

Description:

Returns notes deferred to next frame due to note limit. @return Deferred count.

Returns: Deferred count.

bool isMusicPlaying() const

Description:

Reports if music is currently playing. @return true if playing.

Returns: true if playing.

bool isMusicPaused() const

Description:

Reports if music is paused. @return true if paused.

Returns: true if paused.

int getSampleRate() const

Description:

Gets the configured sample rate. @return Sample rate in Hz.

Returns: Sample rate in Hz.

void reset()

Description:

Resets all state to initial values.

void setPostMixMono(void (*fn)(int16_t* mono, int length, void* user), void* user)

Description:

Sets an optional post-mix callback.

Parameters:

  • fn: Function pointer: void(int16_t* mono, int length, void* user).
  • user: User data passed to the callback.

Called after bitcrush on the final mono buffer. Runs in audio thread context.

void getAndResetProfileStats(ProfileEntry* out, uint8_t& count)

Description:

Reads and clears all profile entries.

Parameters:

  • out: Array of ProfileEntry to fill.
  • count: On input: max entries. On output: actual count written.

size_t countEnabledVoicesForTesting() const

Description:

Test-only: counts voices with enabled==true.

Returns: Active voice count in [0, MAX_VOICES].

TIP

Available only when UNIT_TEST is defined (native_test). Not for game code.

size_t getSequencerMainNoteIndexForTesting() const

Description:

Test-only: main music track note index after the last sequencer run.

Returns: Index into track 0's note array.

TIP

Available only when UNIT_TEST is defined (native_test). Not for game code.

bool isVoiceEnabledForTesting(int slot) const

Description:

Test-only: reports whether a voice slot is currently synthesizing.

Parameters:

  • slot: Voice index [0, MAX_VOICES); out-of-range returns false.

Returns: true if voices[slot].enabled.

TIP

Available only when UNIT_TEST is defined (native_test). Not for game code.

bool isMusicTrackVoiceActiveForTesting(size_t track_index) const

Description:

Test-only: reports whether a music track has an active melodic gate.

Parameters:

  • track_index: Sequencer track [0, MAX_MUSIC_TRACKS); out-of-range returns false.

Returns: true after a melodic note until Rest note-off or lifecycle reset.

TIP

Available only when UNIT_TEST is defined (native_test). Not for game code.

uint32_t getVoiceNoisePeriodForTesting(int slot) const

Description:

Test-only: NOISE LFSR period in samples for a voice slot.

Parameters:

  • slot: Voice index [0, MAX_VOICES); out-of-range returns 0.

Returns: NOISE LFSR period in samples if slot is valid, 0 otherwise.

uint64_t getVoiceRemainingSamplesForTesting(int slot) const

Description:

Test-only: remaining sample gate for a voice slot.

Parameters:

  • slot: Voice index [0, MAX_VOICES); out-of-range returns 0.

Returns: remaining samples if slot is valid, 0 otherwise.

bool isVoiceLoopForTesting(int slot) const

Description:

Test-only: whether a voice slot is in continuous loop mode.

Parameters:

  • slot: Voice index [0, MAX_VOICES); out-of-range returns false.

Returns: true if voice is in loop mode.

float getVoiceFrequencyForTesting(int slot) const

Description:

Test-only: current voice frequency in Hz (melodic / noise clock).

Parameters:

  • slot: Voice index [0, MAX_VOICES); out-of-range returns 0.

Returns: Frequency in Hz if slot is valid, 0 otherwise.

float getVoiceDutyCycleForTesting(int slot) const

Description:

Test-only: current PULSE duty cycle [0,1].

Parameters:

  • slot: Voice index [0, MAX_VOICES); out-of-range returns 0.

float getVoiceDutySweepPerSampleForTesting(int slot) const

Description:

Test-only: continuous dutySweep delta per sample (0 when duty stepped).

Parameters:

  • slot: Voice index [0, MAX_VOICES); out-of-range returns 0.

Released under the MIT License.