Skip to content

Fallback built-in synthesizer - #274

Closed
psi29a wants to merge 5 commits into
masterfrom
fully_synth
Closed

Fallback built-in synthesizer#274
psi29a wants to merge 5 commits into
masterfrom
fully_synth

Conversation

@psi29a

@psi29a psi29a commented Jul 9, 2026

Copy link
Copy Markdown
Member

Fallback built-in synthesizer

There are 128 tonal (additive, 8 partials, 16 GM family profiles) + full GM percussion map with kick/snare/hat/cymbal/bell/click voice types;

Reversed engineered from OPL-3 sf2 to match the tone/pitch/timbre of the in C; can still be fine-tuned and expanded.

Extensions/future:

  • anti-aliasing ladder using freq_low/freq_high,
  • LFO vibrato/tremolo,
  • ensemble detune,
  • velocity-sensitive brightness,
  • richer cymbal/snare,
  • Karplus–Strong for plucked families,
  • per-program pan
  • iFFT possible (https://github.com/mborgerding/kissfft)

Closes #121

Summary by CodeRabbit

Summary by CodeRabbit

  • New Features

    • Added an opt-in “emergency” playback mode that synthesizes an in-memory soundbank when no .pat/.sf2 resources are available.
    • Introduced --emergency / -E to activate the fallback, including synthesized tonal and GM drum/percussion sounds.
  • Bug Fixes

    • Ensures missing emergency configuration is reported as an error (no silent fallback).
  • Tests

    • Added a smoke test that renders a MIDI file to WAV and verifies the output is non-empty.
  • Documentation

    • Added a specification document describing the emergency synthesis approach.

@psi29a
psi29a requested a review from sezero July 9, 2026 13:25
@coderabbitai

coderabbitai Bot commented Jul 9, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

This PR adds an emergency live-synthesis fallback for WildMIDI, with a new synth module, runtime integration for sample loading and initialization, CLI triggering, build wiring, platform config updates, and a design document.

Changes

Emergency Soundbank Synthesis

Layer / File(s) Summary
Design plan documentation
docs/synth_plan.md
Documents the emergency synthesis fallback design, triggers, licensing constraints, candidate approaches, and implementation task list.
Public synth API and build wiring
include/synth.h, src/CMakeLists.txt
Adds the synth.h header declaring WM_EMERGENCY_CONFIG, _WM_synth_patch, and _WM_emergency_init_patches, and registers synth.c and synth.h in the library build sources and headers.
Tonal and percussion synthesis engine
src/synth.c
Implements envelope utilities, additive tonal synthesis, percussion generators with dispatch, and the exported patch-generation and patch-initialization functions.
Sample loading fallback
src/sample.c
Adds synth.h and updates _WM_load_sample to synthesize a sample when the patch filename is NULL, otherwise using the existing GUS patch loader.
Library init emergency branch
src/wildmidi_lib.c
Adds synth.h and introduces a branch in _WM_Init that detects WM_EMERGENCY_CONFIG, calls _WM_emergency_init_patches, handles failure, and joins normal post-config initialization via a shared label.
CLI --emergency option
src/player/wildmidi.c
Adds a -E/--emergency option to long_options, help text, and getopt_long parsing, with a handler that sets config_file to @emergency.
Build and platform config updates
CMakeLists.txt, amiga/*, android/jni/*, djgpp/*, include/config.h.cmake, macosx/*, mingw/*, msvc/*, os2/*
Adds HAVE_SINF detection and defines and includes synth object files across the build scripts and platform configs.

Estimated code review effort: 4 (Complex) | ~50 minutes

Possibly related PRs

  • Mindwerks/wildmidi#270: Also changes src/wildmidi_lib.c initialization/output routing around soundbank selection, which is adjacent to the emergency config path added here.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 68.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed The PR delivers a fully synthetic emergency sound bank generator as requested in #121.
Out of Scope Changes check ✅ Passed The added build, config, and docs changes support the synthesizer fallback and appear in scope.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title is concise and clearly describes the main change: adding a built-in fallback synthesizer.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fully_synth

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@psi29a psi29a changed the title Fully synth Fallback built-in synthesizer Jul 9, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
docs/synth_plan.md (2)

90-91: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Stale filenames in the task list don't match the actual implementation.

The task list (lines 90, 109) references src/emerg_synth.c and include/emerg_synth.h, but the actual files added in this PR are src/synth.c and include/synth.h. Update the doc to match.

Also applies to: 109-109

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/synth_plan.md` around lines 90 - 91, The task list contains stale
implementation filenames and should be updated to match the actual added
symbols/files. In the plan entries that mention the emerg_synth implementation,
replace references to src/emerg_synth.c and include/emerg_synth.h with
src/synth.c and include/synth.h so the documentation aligns with the current
codebase.

24-25: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Clarify whether the fallback is automatic or opt-in.

Line 24 says "or automatic fallback when no cfg is found," but line 116–117 says "opt-in via option, not silent, so debugging stays honest." These are contradictory — one implies silent auto-enablement, the other explicit opt-in. Reconcile the wording to match the intended behavior.

Also applies to: 116-117

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/synth_plan.md` around lines 24 - 25, The plan currently contradicts
itself about fallback behavior: one section says `--emergency` can trigger an
automatic fallback when no cfg is found, while the later note for the fallback
flow says it must be opt-in and not silent. Update the wording in the relevant
plan sections so the behavior is described consistently, and make sure the
references to the trigger and fallback policy match the intended implementation
in the same terms throughout.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/synth.c`:
- Around line 467-485: Rollback the partial initialization in
_WM_emergency_init_patches: if alloc_patch fails after some entries of
_WM_patch[] have already been set, the function should clean up every patch
allocated so far before returning -1. Update the loop logic around alloc_patch,
_WM_patch[id], and the drum-chain append so any failure triggers teardown of
previously installed patches and leaves the global array in a consistent
uninitialized state.

---

Nitpick comments:
In `@docs/synth_plan.md`:
- Around line 90-91: The task list contains stale implementation filenames and
should be updated to match the actual added symbols/files. In the plan entries
that mention the emerg_synth implementation, replace references to
src/emerg_synth.c and include/emerg_synth.h with src/synth.c and include/synth.h
so the documentation aligns with the current codebase.
- Around line 24-25: The plan currently contradicts itself about fallback
behavior: one section says `--emergency` can trigger an automatic fallback when
no cfg is found, while the later note for the fallback flow says it must be
opt-in and not silent. Update the wording in the relevant plan sections so the
behavior is described consistently, and make sure the references to the trigger
and fallback policy match the intended implementation in the same terms
throughout.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: fa771ffd-1a3c-4d91-8a4d-c16d35f5ba9c

📥 Commits

Reviewing files that changed from the base of the PR and between 21dbbf8 and 18dde22.

📒 Files selected for processing (7)
  • docs/synth_plan.md
  • include/synth.h
  • src/CMakeLists.txt
  • src/player/wildmidi.c
  • src/sample.c
  • src/synth.c
  • src/wildmidi_lib.c

Comment thread src/synth.c
Comment thread src/synth.c Outdated
@sezero

sezero commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Pushed build fixes to this branch

@psi29a

psi29a commented Jul 9, 2026

Copy link
Copy Markdown
Member Author

Pushed build fixes to this branch

Cool, I had a fix for those ready but you beat me to it... you're very eager :P

Thank you though. You get a chance to play with it? I've had it baking for awhile...

It uses less CPU/Memory than with sf2 and patches which was surprising. Just sounds like a gameboy though 😆

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/synth_plan.md`:
- Around line 19-22: The fenced example in the markdown doc is missing a
language identifier, which triggers the MD040 lint rule. Update the fenced block
containing the _WM_load_gus_pat and _WM_synth_patch example so it uses the c
language tag on the opening fence, keeping the existing example content
unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 40a8dcbd-3fbe-4d40-b67b-3cceb8907bc6

📥 Commits

Reviewing files that changed from the base of the PR and between 60f02df and b15dd55.

📒 Files selected for processing (25)
  • CMakeLists.txt
  • amiga/Makefile
  • amiga/Makefile.vbcc
  • amiga/config.h
  • android/jni/Android.mk
  • android/jni/config.h
  • djgpp/Makefile
  • djgpp/config.h
  • docs/synth_plan.md
  • include/config.h.cmake
  • include/synth.h
  • macosx/Makefile
  • macosx/config.h
  • mingw/Makefile
  • mingw/config.h
  • msvc/common.mak
  • msvc/config.h
  • os2/config.h
  • os2/makefile
  • os2/makefile.emx
  • src/CMakeLists.txt
  • src/player/wildmidi.c
  • src/sample.c
  • src/synth.c
  • src/wildmidi_lib.c
✅ Files skipped from review due to trivial changes (10)
  • include/config.h.cmake
  • msvc/common.mak
  • djgpp/config.h
  • CMakeLists.txt
  • android/jni/config.h
  • mingw/config.h
  • macosx/config.h
  • amiga/config.h
  • src/CMakeLists.txt
  • mingw/Makefile
🚧 Files skipped from review as they are similar to previous changes (12)
  • os2/makefile.emx
  • os2/makefile
  • amiga/Makefile
  • android/jni/Android.mk
  • include/synth.h
  • djgpp/Makefile
  • amiga/Makefile.vbcc
  • src/wildmidi_lib.c
  • src/sample.c
  • os2/config.h
  • msvc/config.h
  • src/synth.c

Comment thread docs/synth_plan.md
Comment on lines +19 to +22
```
if (guspat = _WM_load_gus_pat(...)) { /* existing */ }
else if (emergency_bank_enabled) { guspat = _WM_synth_patch(patchid); }
```

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Add a language tag to this fenced example.

The docs lint already flags this block (MD040). Mark it as c so the markdown check passes.

Fix
-```
+```c
 if (guspat = _WM_load_gus_pat(...)) { /* existing */ }
 else if (emergency_bank_enabled)   { guspat = _WM_synth_patch(patchid); }
-```
+```
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
```
if (guspat = _WM_load_gus_pat(...)) { /* existing */ }
else if (emergency_bank_enabled) { guspat = _WM_synth_patch(patchid); }
```
🧰 Tools
🪛 markdownlint-cli2 (0.22.1)

[warning] 19-19: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/synth_plan.md` around lines 19 - 22, The fenced example in the markdown
doc is missing a language identifier, which triggers the MD040 lint rule. Update
the fenced block containing the _WM_load_gus_pat and _WM_synth_patch example so
it uses the c language tag on the opening fence, keeping the existing example
content unchanged.

Source: Linters/SAST tools

@sezero

sezero commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Rebased to current master.

You get a chance to play with it?

Abominable. So silent, I practically can't hear anything, even if I max-out my speakers' volume.

@psi29a

psi29a commented Jul 9, 2026

Copy link
Copy Markdown
Member Author

Rebased to current master.

You get a chance to play with it?

Abominable. So silent, I practically can't hear anything, even if I max-out my speakers' volume.

Really? I can hear it just fine here?
test.mp3

I mean, sure... it sounds like a gameboy, but it's not silent or do you mean something else?

If you feel like this is hot garbage, I can close and try something else.

@sezero

sezero commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Well, all I hear are "bop bop bop" sounds -- this is with the current rebased branch: out.mp3

(I did ./wildmidi -P wave -E -o out.wav canyon.mid and then ran lame on out.wav)

@psi29a

psi29a commented Jul 9, 2026

Copy link
Copy Markdown
Member Author

I'm going to try something else... going to put it in another branch/PR

@psi29a

psi29a commented Jul 9, 2026

Copy link
Copy Markdown
Member Author

@sezero I started another branch and PR here: #275
It makes use of Nuke OPL3 code, it's LGPL so that's good but we have handle the mixing and other knobs ourselves.

Does it sound any better than this branch?

@sezero

sezero commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Does it sound any better than this branch?

It sounds ... fair. At least I have proper sound with it.

@psi29a psi29a closed this Jul 10, 2026
@sezero
sezero deleted the fully_synth branch July 10, 2026 14:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

emergency sound bank generator

2 participants