fix(bass-presets): move factory presets to channel subdirs + per-channel install

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 <channel>/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)
This commit is contained in:
2026-06-13 10:23:57 -04:00
parent 575535762c
commit 659e53766a
25 changed files with 162 additions and 10 deletions
+124
View File
@@ -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)
+5
View File
@@ -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
+9 -5
View File
@@ -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)
+16 -4
View File
@@ -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:
+8 -1
View File
@@ -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):