Skip to content

Releases

Release 2.3.0

Choose a tag to compare

@Gperez88 Gperez88 released this 06 Nov 06:29

🚀 What's New in 2.3.0

Gives drums and bass their body back under the NES-derived profiles. Profile value 2 becomes Famicom: the Nes character with the Famicom's output stage, which keeps the low end that the NES 440 Hz high-pass removes. Kick and snare keep the noise period they were authored with, and a new triangle kick brings the classic NES "thump". Legacy and Nes output stays byte-identical.

🎛️ Famicom Profile

  • SoundProfile::Famicom: Replaces Hybrid at value 2. It has the same character as Nes: linear default envelope, ideal saw, the four NES duty patterns, unipolar noise and the NES-weighted mix.
  • Famicom Output Stage: A single 37 Hz high-pass into the same Butterworth low-pass (min(14 kHz, 0.45 fs)), instead of the NES chain's 90 Hz → 440 Hz → LPF.
    • At 65 Hz, Nes attenuates −21.1 dB and Famicom only −1.2 dB.
    • The 440 Hz section is bypassed with a unity pole, so Nes pays nothing extra per sample.
  • Level Trim: Recalibrated with the crest-weighted heuristic: 31765 (−0.27 dB). W lands within 0.001 dB of Legacy, and the RMS is now only 0.31 dB below it, instead of 2.4 dB.

🥁 Drums and Bass

  • Kick and Snare Keep Their Body: INSTR_KICK and INSTR_SNARE use NoisePeriodMode::Note, so under Nes/Famicom they keep periods 60 and 15 instead of collapsing to the one-sample hiss of NES LUT index 0.
  • Authentic NES Hi-Hat: INSTR_HIHAT keeps the profile default and takes NES LUT index 0, the bright hat NES games use.
  • INSTR_KICK_TRI: A new triangle kick. On a TRIANGLE track it sweeps from 196 Hz (G3, the default octave) to 50 Hz in 45 ms, with a short decay. Double it with a NOISE hit on the same beat for the attack.

🔧 Changed

  • Linear Default Envelope Everywhere: No profile defaults to the exponential curve any more. A note can still ask for EnvelopeCurve::Exponential.
  • Band-Limited Saw Is Dormant: No profile selects the mipmapped saw now. AudioOscMipLUT.h and its read path are kept until a decision is made: remove it, or expose it as a per-voice option.
  • Fixtures: apu_famicom_canonical and apu_famicom_wavetable replace the apu_hybrid_* pair.

🧪 Testing & Tools

  • New Coverage:
    • The Famicom output-stage response at 8 kHz, 22.05 kHz, 44.1 kHz and 48 kHz.
    • Low-end attenuation for Nes and Famicom.
    • Character parity between Nes and Famicom.
    • Drum periods under every profile.
    • The triangle-kick sweep.
    • test_apu_hybrid_wavetable becomes test_apu_famicom_saw.
    • 616 cases across 16 targets.
  • Tools: golden_gen and profiles_ab accept famicom, with hybrid kept as an alias.
  • Hardware Listening: The engine's apu_profiles example was built for esp32dev against this release and compared by ear on the board.

📌 Compatibility Notes

  • Hybrid Is Deprecated, Not Removed: SoundProfile::Hybrid is an alias of Famicom (same value 2). Existing code compiles with a deprecation warning.

  • Profile 2 Sounds Different: Content authored for Hybrid now gets:

    • a linear envelope;
    • the ideal saw;
    • the 37 Hz output stage;
    • a lower trim: +1.90 dB → −0.27 dB.

    Use Nes for the old NES output stage, or set EnvelopeCurve::Exponential on a note for the exponential curve.

  • Default Output Unchanged for Legacy and Nes: Their fixtures were not regenerated and reproduce byte for byte.

  • Not Measured on Boards: Famicom's CPU cost was not measured on hardware. It is expected to match Nes, because the per-sample work is identical.

  • Consumer Pin:

    • The engine's ^2.0.0 range already resolves 2.3.0.
    • Code that names SoundProfile::Famicom or INSTR_KICK_TRI needs >= 2.3.0.

Release 2.2.0

Choose a tag to compare

@Gperez88 Gperez88 released this 29 Oct 02:58

🚀 What’s New in 2.2.0

Lets a note keep the noise period and the continuous pulse duty it authored, even when the Nes or Hybrid sound profile would otherwise overwrite them. Curated percussion and custom duty values stay expressible under any profile, and the default output remains byte-identical.

🔊 Note-Pinned Character

  • Noise Period Under NES Profiles: Adds InstrumentPreset::noisePeriodMode with NoisePeriodMode::Note. Nes and Hybrid arm the NES period LUT, which used to retune a noise voice to a one-sample clock; a note can now keep its own noisePeriod, so a kick authored with a 60-sample body stays a kick instead of becoming white hiss.
  • Continuous Pulse Duty: Adds InstrumentPreset::pulseDutyMode with PulseDutyMode::Continuous. A static duty is no longer snapped to one of the four NES patterns, so values a caller can already express, such as 30 % or 20 %, survive the profile.
  • Per Note, Not Per Slot: Both requests resolve on note-on and leave the slot clean, so the next note on that voice gets the profile character again. Neither writes a per-voice override.

🔧 Changed

  • Preset Layout: sizeof(InstrumentPreset) grows from 72 to 76 bytes, entirely from trailing padding. sizeof(AudioChannel), sizeof(AudioCommand), sizeof(AudioEvent) and both sizeof(ApuCore) figures (13,344 host and 13,368 test build) are unchanged, because the two requests reach the character hook as parameters instead of being stored per voice.

🧪 Testing & Tools

  • Character Regression Tests: Adds 13 cases covering the pinned period, the frequency-derived path, no leakage into the next note, a voice pin outranking the note, PULSE-only duty scope and Legacy inertness. test_apu_core moves from 210 to 223 cases.
  • Default-Path Matrix: A 15-scenario comparison against 2.1.0, covering three profiles, both duty and noise paths, nesAccurate and two-note sequences, reproduces identical PCM hashes and identical slot state.
  • Independent Verification: A separate review of the change reported no blockers; the two defects it found are fixed before this release.

📌 Compatibility Notes

  • Default Output Unchanged: With the new fields at their defaults, Legacy, Nes and Hybrid render byte-identical PCM. None of the reference fixtures was regenerated.
  • Source Compatible, Rebuild Required: The fields are appended after envelopeCurve, so existing 17-value positional InstrumentPreset literals keep their meaning. Consumers must rebuild against 2.2.0.
  • Voice Pins Still Win: setVoiceNesNoiseLutMode() and setVoicePulseDutyMode() outrank the note-level request, exactly as they already outrank an animated duty.
  • Consumer Pin: The engine's ^2.0.0 range already resolves 2.2.0 with no manifest change. The Tool Suite needs >= 2.2.0 to use the new fields.

Release 2.1.0

Choose a tag to compare

@Gperez88 Gperez88 released this 28 Oct 20:40

🚀 What’s New in 2.1.0

Introduces NES-inspired and Hybrid sound profiles, improving audio character with NES-style mixing, envelopes, pulse duty patterns and output filtering. This release also fixes two integer-rendering issues on no-FPU builds, reduces command queue memory usage and preserves the default Legacy output on FPU builds.

🔊 Sound Profiles

  • New Sound Profiles: Adds Legacy (default), Nes and Hybrid, selectable at runtime through ApuCore::setSoundProfile(). Nes introduces NES-style mixing and stepped pulse duty, while Hybrid adds exponential envelopes and band-limited SAW synthesis.
  • NES-Style Output: Adds profile-specific filtering and level compensation for a more consistent listening experience, while preserving the original Legacy rendering behavior.
  • Consistent Integer Rendering: Nes and Hybrid use the same integer core across platforms, producing identical PCM output for equivalent inputs.

🔧 Changed

  • Reduced Memory Usage: Lowers the default audio command queue capacity from 128 to 64, reducing sizeof(ApuCore) on the host ABI from 22,416 to 13,344 bytes.
  • Configurable Legacy Float Core: Adds PR32_APU_ENABLE_LEGACY_FLOAT to optionally exclude the legacy floating-point renderer on FPU targets, reducing flash usage.
  • Engine Audio Integration: Updates the recommended render block sizes to 512 samples on FPU builds and 1024 on no-FPU builds, reducing processing wake-ups at the cost of increased command latency.

🐛 Fixed

  • Integer DC Blocking: Fixes a persistent negative DC offset after voices are silenced on no-FPU builds.
  • 100% Pulse Duty: Fixes pulse waves rendering as silence at duty = 1.0 on the integer rendering path.

🧪 Testing & Tools

  • Audio Regression Tests: Adds immutable PCM reference fixtures for the Nes, Hybrid and integer rendering paths.
  • Audio Profiling Tools: Adds profile comparison, canonical audio rendering and host/firmware benchmarking tools.

📌 Compatibility Notes

  • Legacy remains the default profile and preserves its existing output on FPU builds.
  • On ESP32-C3, Nes and Hybrid are limited to 22,050 Hz with eight voices due to processing constraints.
  • The reduced command queue capacity may affect applications that depend on more than 63 pending commands.
  • Applications using the integer path should revalidate audio levels and regenerate PCM references affected by the DC blocker fix or the new sound profiles.