From 659e53766a8953b686f1fdf4b0494f31be94e7f0 Mon Sep 17 00:00:00 2001 From: Shawn Date: Sat, 13 Jun 2026 10:23:57 -0400 Subject: [PATCH] fix(bass-presets): move factory presets to channel subdirs + per-channel install MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Root cause: factory presets for bass (banks 17-20) sat in the root factory dir alongside guitar presets, and install_factory_presets() used rglob() which picked up ALL presets into the GUITAR channel. Changes: - Move bank_17-20 from presets/factory/ → presets/factory/bass/ (matching the existing keys/, vocals/, backing_tracks/ layout) - Fix install_factory_presets() to scan channel-specific subdirectory: GUITAR scans root bank_* dirs, all others scan /bank_* - Fix main.py to iterate over all 5 channels when installing factory presets (was only installing into GUITAR) - Import Channel enum in main.py Tests: 56/56 preset manager tests pass. Integration verified: - GUITAR: 68 presets (banks 0-16) - BASS: 16 presets (banks 17-20, SansAmp/Darkglass/Ampeg SVT) - KEYS: 12 presets (banks 21-23) - VOCALS: 12 presets (banks 24-26) - BACKING_TRACKS: 12 presets (banks 27-29) --- docs/bass-tone-research.md | 124 ++++++++++++++++++ docs/nam-ir-inventory.md | 5 + main.py | 14 +- presets/factory/{ => bass}/bank_17/bank.json | 0 .../factory/{ => bass}/bank_17/preset_0.json | 0 .../factory/{ => bass}/bank_17/preset_1.json | 0 .../factory/{ => bass}/bank_17/preset_2.json | 0 .../factory/{ => bass}/bank_17/preset_3.json | 0 presets/factory/{ => bass}/bank_18/bank.json | 0 .../factory/{ => bass}/bank_18/preset_0.json | 0 .../factory/{ => bass}/bank_18/preset_1.json | 0 .../factory/{ => bass}/bank_18/preset_2.json | 0 .../factory/{ => bass}/bank_18/preset_3.json | 0 presets/factory/{ => bass}/bank_19/bank.json | 0 .../factory/{ => bass}/bank_19/preset_0.json | 0 .../factory/{ => bass}/bank_19/preset_1.json | 0 .../factory/{ => bass}/bank_19/preset_2.json | 0 .../factory/{ => bass}/bank_19/preset_3.json | 0 presets/factory/{ => bass}/bank_20/bank.json | 0 .../factory/{ => bass}/bank_20/preset_0.json | 0 .../factory/{ => bass}/bank_20/preset_1.json | 0 .../factory/{ => bass}/bank_20/preset_2.json | 0 .../factory/{ => bass}/bank_20/preset_3.json | 0 src/presets/manager.py | 20 ++- src/presets/types.py | 9 +- 25 files changed, 162 insertions(+), 10 deletions(-) create mode 100644 docs/bass-tone-research.md rename presets/factory/{ => bass}/bank_17/bank.json (100%) rename presets/factory/{ => bass}/bank_17/preset_0.json (100%) rename presets/factory/{ => bass}/bank_17/preset_1.json (100%) rename presets/factory/{ => bass}/bank_17/preset_2.json (100%) rename presets/factory/{ => bass}/bank_17/preset_3.json (100%) rename presets/factory/{ => bass}/bank_18/bank.json (100%) rename presets/factory/{ => bass}/bank_18/preset_0.json (100%) rename presets/factory/{ => bass}/bank_18/preset_1.json (100%) rename presets/factory/{ => bass}/bank_18/preset_2.json (100%) rename presets/factory/{ => bass}/bank_18/preset_3.json (100%) rename presets/factory/{ => bass}/bank_19/bank.json (100%) rename presets/factory/{ => bass}/bank_19/preset_0.json (100%) rename presets/factory/{ => bass}/bank_19/preset_1.json (100%) rename presets/factory/{ => bass}/bank_19/preset_2.json (100%) rename presets/factory/{ => bass}/bank_19/preset_3.json (100%) rename presets/factory/{ => bass}/bank_20/bank.json (100%) rename presets/factory/{ => bass}/bank_20/preset_0.json (100%) rename presets/factory/{ => bass}/bank_20/preset_1.json (100%) rename presets/factory/{ => bass}/bank_20/preset_2.json (100%) rename presets/factory/{ => bass}/bank_20/preset_3.json (100%) diff --git a/docs/bass-tone-research.md b/docs/bass-tone-research.md new file mode 100644 index 0000000..672dce5 --- /dev/null +++ b/docs/bass-tone-research.md @@ -0,0 +1,124 @@ +# Bass Genre Tones — NAM Model Research & Artist Chain Configs + +_Researched: 2026-06-13_ +_Source: Tone3000 (tone3000.com) — the primary NAM capture repository_ + +## Overview + +We have **10 bass cabinet IRs** already installed but **5 bass NAM models already on disk** (Bank 7): + +| File | Type | +|------|------| +| `Ampeg_PF20T_A2.nam` | Small tube combo (Ampeg) | +| `Aguilar_Tone_Hammer_500_A2.nam` | Modern preamp | +| `GK_800RB_Line_A2.nam` | Classic solid-state | +| `Aguilar_DB751_Cab_A2.nam` | Bass amp DI | +| `Fender_Bassman_Dimed_A2.nam` | Bassman growl | + +**Gaps:** SansAmp BDDI, Darkglass B3K/B7K, Ampeg SVT-CL, Geddy Lee DI-2112. + +--- + +## Part 1: Available Bass NAM Models on Tone3000 + +### 1.1 Tech 21 SansAmp + +| Capture | Creator | Tone3000 URL | +|---------|---------|-------------| +| SansAmp BDDI v1 | jackspirited | `/tones/sansamp-bddi-v1-39232` | +| Tech21 SansAmp VT Bass DI | salamiexcerpt5j | `/tones/tech21-sansamp-vt-bass-di-30406` | +| Geddy Lee SansAmp DI-2112 | jakegideon | `/tones/geddy-lee-sansamp-di-2112-5989` | + +### 1.2 Darkglass Electronics + +| Capture | Creator | URL | +|---------|---------|-----| +| Darkglass B3K (A1+A2) | santo | `/tones/darkglass-microtubes-b3k-26546` | +| Darkglass B7K | tmrecprod | `/tones/darkglass-b7k-71080` | +| Darkglass B7K Ultra | darkglass | `/tones/darkglass-b7k-ultra-27698` | +| Darkglass Alpha-Omega | darkglass | `/tones/darkglass-alpha-omega-27697` | +| Darkglass Vintage Deluxe | darkglass | `/tones/darkglass-vintage-deluxe-27696` | +| Darkglass ADAM | fctwingov6 | `/tones/darkglass-adam-65168` | + +### 1.3 Ampeg + +| Capture | Creator | URL | +|---------|---------|-----| +| Ampeg SVT-CL Bass Head | deathblossomaudio | `/tones/ampeg-svt-cl-bass-head-45809` | +| Ampeg SVT-4 Pro | noamp | `/tones/ampeg-svt-4-pro-29376` | +| Ampeg B-15 Fliptop | tone3000 | `/tones/ampeg-b-15-fliptop-26828` | +| Ampeg SGT-DI | plingubus | `/tones/ampeg-sgt-di-34631` | + +### 1.4 Aguilar + +| Capture | Creator | URL | +|---------|---------|-----| +| Aguilar Tone Hammer (pedal) | wolffire99 | `/tones/aguilar-tone-hammer-45991` | +| Aguilar DB751 | dudubxt | `/tones/aguilar-db751-39531` | +| Aguiler Plugin Suite (Feather!) | jindrich | `/tones/aguilar-plugin-suite-feather-full-rig-collection-41096` | + +### 1.5 Gallien-Krueger + +| Capture | Creator | URL | +|---------|---------|-----| +| GK 800 | siddonfer | `/tones/gk-800--2608` | +| Gallien Krueger 800 RB | joeformat | `/tones/gallien-krueger-800-rb-56782` | + +### 1.6 Fender Bassman + +| Capture | Creator | URL | +|---------|---------|-----| +| Fender Bassman 5F6A Series | neampmod | `/tones/fender-bassman-5f6a-series-26082` | +| 1971 Fender Bassman | maestrodimusica | `/tones/1971-fender-bassman-13776` | + +### Full Captures Report +See `/home/oplabs/nam_bass_captures_report.md` for complete list (80+ captures). + +--- + +## Part 2: Artist Tone Matrix + +| Artist | Primary Model | Secondary Model | Best IR | +|--------|--------------|-----------------|---------| +| **Cliff Burton** (Metallica) | Ampeg SVT-CL | SansAmp BDDI v1 | bass-thick_classic | +| **Geddy Lee** (70s) | Ampeg SVT-CL (clean) | — | bass-classic | +| **Geddy Lee** (80s+) | Geddy Lee SansAmp DI-2112 | SansAmp BDDI v1 + SVT-CL | bass-balanced | +| **Justin Chancellor** (Tool) | Darkglass B3K | GK 800 | bass-more_mids | +| **John Paul Jones** (Led Zep) | Ampeg SVT-CL (clean) | Fender Bassman 5F6A | bass-classic | +| **Flea** (RHCP) | SansAmp BDDI v1 | Ampeg SVT-CL | bass-thick_classic | +| **Les Claypool** (Primus) | Darkglass Vintage Deluxe + B7K | SansAmp BDDI + SVT-CL | bass-more_mids | +| **Tim Commerford** (RATM) | SansAmp BDDI v1 | Ampeg SVT-CL | bass-classic | +| **Robert Trujillo** (Metallica) | Darkglass B7K | Ampeg SVT-CL | bass-clanky | + +--- + +## Part 3: Priority Download List + +1. **Ampeg SVT-CL** (deathblossomaudio) — foundation, used by almost every artist +2. **SansAmp BDDI v1** (jackspirited) — versatile preamp +3. **Darkglass B3K** (santo, A2) — modern growl +4. **Darkglass B7K** (tmrecprod) — versatile distortion +5. **Geddy Lee SansAmp DI-2112** (jakegideon) — direct Geddy rig capture +6. **Fender Bassman 5F6A** (neampmod) — vintage bass +7. **Aguilar Tone Hammer pedal** (wolffire99) — warm modern preamp +8. **GK 800** (siddonfer) — punchy solid-state + +**10 bass IRs already available** at `~/.pedal/irs/bass-*.wav`. + +--- + +## Part 4: Chain Architecture + +``` +Bass → NAM Model (preamp/amp) → Cab IR (bass-specific) → Output +``` + +- **Pedal captures** (SansAmp, Darkglass B3K, Tone Hammer) need a bass cab IR after them +- **Amp head captures** (SVT-CL, GK 800) also need a bass cab IR +- **Full rig captures** already include cab — skip IR +- **Compression** should be before the NAM model (not modeled by NAM) +- All captures are from Tone3000 — download URLs in full report + +### No BDDI v2 / No SVT-VR +- BDDI v2 NOT found; v1 is close (different headroom/EQ curve) +- SVT-VR NOT found; SVT-CL is equivalent (same circuit, different era) diff --git a/docs/nam-ir-inventory.md b/docs/nam-ir-inventory.md index 0236de5..596b75b 100644 --- a/docs/nam-ir-inventory.md +++ b/docs/nam-ir-inventory.md @@ -382,6 +382,11 @@ The following Archive.org sources returned 404 when last checked (2026-06-13): │ ├── Orange_Rocker30_Dirty_A2.nam # 295 KB — Rock crunch │ ├── Orange_Rocker30_Natural_A2.nam # 289 KB — Clean edge │ ├── Fender_Bassman_Dimed_A2.nam # 289 KB — Blues/rock breakup +│ │ +│ └── 🎸 Bass Genre Research: +│ └── Full artist tone chain configs → `docs/bass-tone-research.md` +│ Available on Tone3000 (needs download): SansAmp BDDI v1, Darkglass B3K/B7K, +│ Ampeg SVT-CL, Geddy Lee SansAmp DI-2112 │ ├── Hiwatt_DR103_Bright_A2.nam # 287 KB — Classic rock │ ├── Hiwatt_DR103_Cornish_A2.nam # 288 KB — Boosted classic rock │ ├── Supro_Black_Magick_M3_A2.nam # 288 KB — Garage/blues diff --git a/main.py b/main.py index 57387bd..9c66bcf 100644 --- a/main.py +++ b/main.py @@ -28,7 +28,7 @@ from src.dsp.pipeline import AudioPipeline from src.dsp.nam_host import NAMHost from src.dsp.ir_loader import IRLoader from src.presets.manager import PresetManager -from src.presets.types import MIDIMapping, Preset +from src.presets.types import Channel, MIDIMapping, Preset from src.midi.handler import MIDIHandler from src.ui.footswitch import FootswitchController, FootSwitch, SwitchAction from src.ui.leds import LEDController, LEDDriver, LEDConfig, LEDPattern @@ -170,11 +170,15 @@ class PedalApp: audio_pipeline=self.pipeline, ) - # Install factory presets (non-destructive by default) + # Install factory presets for all channels (non-destructive by default) if pcfg.get("install_factory", True): - installed = self.presets.install_factory_presets(overwrite=False) - if installed: - logger.info("Installed %d factory preset(s)", installed) + for ch in Channel: + installed = self.presets.install_factory_presets( + overwrite=False, channel=ch, + ) + if installed: + logger.info("Installed %d factory preset(s) for %s", + installed, ch.value) ir_installed = self.presets.install_factory_irs(overwrite=False) if ir_installed: logger.info("Installed %d factory cab IR(s)", ir_installed) diff --git a/presets/factory/bank_17/bank.json b/presets/factory/bass/bank_17/bank.json similarity index 100% rename from presets/factory/bank_17/bank.json rename to presets/factory/bass/bank_17/bank.json diff --git a/presets/factory/bank_17/preset_0.json b/presets/factory/bass/bank_17/preset_0.json similarity index 100% rename from presets/factory/bank_17/preset_0.json rename to presets/factory/bass/bank_17/preset_0.json diff --git a/presets/factory/bank_17/preset_1.json b/presets/factory/bass/bank_17/preset_1.json similarity index 100% rename from presets/factory/bank_17/preset_1.json rename to presets/factory/bass/bank_17/preset_1.json diff --git a/presets/factory/bank_17/preset_2.json b/presets/factory/bass/bank_17/preset_2.json similarity index 100% rename from presets/factory/bank_17/preset_2.json rename to presets/factory/bass/bank_17/preset_2.json diff --git a/presets/factory/bank_17/preset_3.json b/presets/factory/bass/bank_17/preset_3.json similarity index 100% rename from presets/factory/bank_17/preset_3.json rename to presets/factory/bass/bank_17/preset_3.json diff --git a/presets/factory/bank_18/bank.json b/presets/factory/bass/bank_18/bank.json similarity index 100% rename from presets/factory/bank_18/bank.json rename to presets/factory/bass/bank_18/bank.json diff --git a/presets/factory/bank_18/preset_0.json b/presets/factory/bass/bank_18/preset_0.json similarity index 100% rename from presets/factory/bank_18/preset_0.json rename to presets/factory/bass/bank_18/preset_0.json diff --git a/presets/factory/bank_18/preset_1.json b/presets/factory/bass/bank_18/preset_1.json similarity index 100% rename from presets/factory/bank_18/preset_1.json rename to presets/factory/bass/bank_18/preset_1.json diff --git a/presets/factory/bank_18/preset_2.json b/presets/factory/bass/bank_18/preset_2.json similarity index 100% rename from presets/factory/bank_18/preset_2.json rename to presets/factory/bass/bank_18/preset_2.json diff --git a/presets/factory/bank_18/preset_3.json b/presets/factory/bass/bank_18/preset_3.json similarity index 100% rename from presets/factory/bank_18/preset_3.json rename to presets/factory/bass/bank_18/preset_3.json diff --git a/presets/factory/bank_19/bank.json b/presets/factory/bass/bank_19/bank.json similarity index 100% rename from presets/factory/bank_19/bank.json rename to presets/factory/bass/bank_19/bank.json diff --git a/presets/factory/bank_19/preset_0.json b/presets/factory/bass/bank_19/preset_0.json similarity index 100% rename from presets/factory/bank_19/preset_0.json rename to presets/factory/bass/bank_19/preset_0.json diff --git a/presets/factory/bank_19/preset_1.json b/presets/factory/bass/bank_19/preset_1.json similarity index 100% rename from presets/factory/bank_19/preset_1.json rename to presets/factory/bass/bank_19/preset_1.json diff --git a/presets/factory/bank_19/preset_2.json b/presets/factory/bass/bank_19/preset_2.json similarity index 100% rename from presets/factory/bank_19/preset_2.json rename to presets/factory/bass/bank_19/preset_2.json diff --git a/presets/factory/bank_19/preset_3.json b/presets/factory/bass/bank_19/preset_3.json similarity index 100% rename from presets/factory/bank_19/preset_3.json rename to presets/factory/bass/bank_19/preset_3.json diff --git a/presets/factory/bank_20/bank.json b/presets/factory/bass/bank_20/bank.json similarity index 100% rename from presets/factory/bank_20/bank.json rename to presets/factory/bass/bank_20/bank.json diff --git a/presets/factory/bank_20/preset_0.json b/presets/factory/bass/bank_20/preset_0.json similarity index 100% rename from presets/factory/bank_20/preset_0.json rename to presets/factory/bass/bank_20/preset_0.json diff --git a/presets/factory/bank_20/preset_1.json b/presets/factory/bass/bank_20/preset_1.json similarity index 100% rename from presets/factory/bank_20/preset_1.json rename to presets/factory/bass/bank_20/preset_1.json diff --git a/presets/factory/bank_20/preset_2.json b/presets/factory/bass/bank_20/preset_2.json similarity index 100% rename from presets/factory/bank_20/preset_2.json rename to presets/factory/bass/bank_20/preset_2.json diff --git a/presets/factory/bank_20/preset_3.json b/presets/factory/bass/bank_20/preset_3.json similarity index 100% rename from presets/factory/bank_20/preset_3.json rename to presets/factory/bass/bank_20/preset_3.json diff --git a/src/presets/manager.py b/src/presets/manager.py index 09ed261..f8fe1fd 100644 --- a/src/presets/manager.py +++ b/src/presets/manager.py @@ -596,8 +596,11 @@ class PresetManager: channel: Channel = Channel.GUITAR) -> int: """Install bundled factory presets into the preset store. - Scans ``FACTORY_PRESET_DIR`` for ``bank_*/preset_*.json`` files - and copies them into the user preset store. + Scans the channel-specific subdirectory of ``FACTORY_PRESET_DIR`` + for ``bank_*/preset_*.json`` files and copies them into the user + preset store. For GUITAR the root of ``FACTORY_PRESET_DIR`` is + scanned (backward-compatible with legacy ``bank_0``–``bank_16``). + All other channels use ``FACTORY_PRESET_DIR / channel.value``. Args: overwrite: If True, overwrite existing presets at the same @@ -611,8 +614,17 @@ class PresetManager: logger.warning("Factory preset directory not found: %s", FACTORY_PRESET_DIR) return 0 + # Determine source directory — root for GUITAR, subdir for all others + source_dir = FACTORY_PRESET_DIR if channel == Channel.GUITAR \ + else FACTORY_PRESET_DIR / channel.value + + if not source_dir.is_dir(): + logger.warning("No factory presets for channel %s: %s", + channel.value, source_dir) + return 0 + count = 0 - for src in sorted(FACTORY_PRESET_DIR.rglob("preset_*.json")): + for src in sorted(source_dir.glob("bank_*/preset_*.json")): # Derive (bank, program) from file path bank_dir = src.parent try: @@ -635,7 +647,7 @@ class PresetManager: if count: self._dirty = True - logger.info("Installed %d factory presets", count) + logger.info("Installed %d factory presets for %s", count, channel.value) return count def install_factory_irs(self, overwrite: bool = False) -> int: diff --git a/src/presets/types.py b/src/presets/types.py index 274ddb0..5e4a4c2 100644 --- a/src/presets/types.py +++ b/src/presets/types.py @@ -8,9 +8,16 @@ from typing import Optional class Channel(enum.StrEnum): - """Guitar or Bass signal channel — each has its own independent preset bank.""" + """Instrument/voice signal channel — each has its own independent preset bank. + + Supports guitar, bass, keys, vocals, and backing tracks. Existing preset + files with "guitar" or "bass" channel values remain fully compatible. + """ GUITAR = "guitar" BASS = "bass" + KEYS = "keys" + VOCALS = "vocals" + BACKING_TRACKS = "backing_tracks" class FXType(enum.StrEnum):