Skip to content

Commit efd130d

Browse files
authored
feat: Add 5 new instruments + fix silent failure bugs (#40)
This PR adds 5 new instruments, fixes critical bugs, and adds comprehensive validation infrastructure: **New Instruments (CC0 licensed)** - acoustic-crash, brushes-snare, kalimba, slap-bass, steel-drums **Bug Fixes** - Fixed silent failure bug where 12 drums had playableRange excluding MIDI 60 - Fixed velocity layer inversion across all multi-velocity instruments **Validation Infrastructure** - Added instrument-validation CI job - Auto-generated SAMPLED_INSTRUMENT_NOTES from manifests - Added velocity layer and manifest validators **Code Quality** - Removed dead code (baseNote, oneShot) from all 27 manifests - Added playableRange to 6 instruments missing it - Added pitch range restrictions to UI - Added comprehensive copy/paste and property-based tests - Created playable-range-demo session All 4032 unit tests and 247 integration tests pass.
1 parent daff507 commit efd130d

File tree

143 files changed

+7322
-135
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

143 files changed

+7322
-135
lines changed

.github/workflows/ci.yml

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,29 @@ jobs:
106106
- name: Build application
107107
run: npm run build
108108

109+
instrument-validation:
110+
name: Instrument Validation
111+
runs-on: ubuntu-latest
112+
defaults:
113+
run:
114+
working-directory: ./app
115+
steps:
116+
- name: Checkout repository
117+
uses: actions/checkout@v4
118+
119+
- name: Setup Node.js
120+
uses: actions/setup-node@v4
121+
with:
122+
node-version: '20'
123+
cache: 'npm'
124+
cache-dependency-path: app/package-lock.json
125+
126+
- name: Install dependencies
127+
run: npm ci
128+
129+
- name: Run all validators
130+
run: npm run validate:all
131+
109132
e2e-tests:
110133
name: E2E Tests
111134
runs-on: ubuntu-latest

app/.husky/pre-push

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,27 @@ echo " PRE-PUSH: Test Suite"
1919
echo "========================================"
2020
echo ""
2121

22+
# Phase 0: Manifest Validation (instant, catches silent failure bugs)
23+
echo "----------------------------------------"
24+
echo "Phase 0: Manifest Validation"
25+
echo "----------------------------------------"
26+
echo ""
27+
28+
if npx tsx scripts/validate-manifests.ts; then
29+
echo ""
30+
echo "✅ All manifests valid!"
31+
echo ""
32+
else
33+
echo ""
34+
echo "❌ Manifest validation FAILED"
35+
echo ""
36+
echo "Fix the issues above before pushing."
37+
echo "Instruments with invalid manifests will be SILENT."
38+
echo "To skip: git push --no-verify"
39+
echo ""
40+
exit 1
41+
fi
42+
2243
# Phase 1: Unit Tests (runs first, no backend required)
2344
echo "----------------------------------------"
2445
echo "Phase 1: Unit Tests (~11s)"
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
{
2+
"name": "808 Drums - Correct Pitch Demo",
3+
"description": "Demonstrates the 808 drum kit playing at correct pitch. The drums now have playableRange limits to prevent extreme pitch-shifting artifacts.",
4+
"bpm": 140,
5+
"tracks": [
6+
{
7+
"name": "808 Kick - Bass Foundation",
8+
"sampleId": "sampled:808-kick",
9+
"steps": [true, false, false, false, true, false, false, false, true, false, false, true, false, false, true, false],
10+
"pitches": [0, 0, 0, 0, -5, 0, 0, 0, 0, 0, 0, -3, 0, 0, 0, 0],
11+
"volume": 95,
12+
"_comment": "808 kick at natural pitch with subtle pitch drops for variation"
13+
},
14+
{
15+
"name": "808 Snare - Snap",
16+
"sampleId": "sampled:808-snare",
17+
"steps": [false, false, false, false, true, false, false, false, false, false, false, false, true, false, false, false],
18+
"pitches": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0],
19+
"volume": 85,
20+
"_comment": "Classic 808 snare placement with slight pitch up on second hit"
21+
},
22+
{
23+
"name": "808 Hi-Hat - Closed",
24+
"sampleId": "sampled:808-hihat-closed",
25+
"steps": [true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false],
26+
"pitches": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
27+
"volume": 70,
28+
"_comment": "Steady hi-hat pattern at natural pitch"
29+
},
30+
{
31+
"name": "808 Hi-Hat - Open",
32+
"sampleId": "sampled:808-hihat-open",
33+
"steps": [false, false, false, false, false, false, false, true, false, false, false, false, false, false, false, true],
34+
"pitches": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
35+
"volume": 68,
36+
"_comment": "Open hat accents"
37+
},
38+
{
39+
"name": "808 Clap - Layer",
40+
"sampleId": "sampled:808-clap",
41+
"steps": [false, false, false, false, true, false, false, false, false, false, false, false, true, false, false, false],
42+
"pitches": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
43+
"volume": 75,
44+
"_comment": "Clap layered with snare for thickness"
45+
},
46+
{
47+
"name": "808 Kick - Pitched Melodic",
48+
"sampleId": "sampled:808-kick",
49+
"steps": [false, false, true, false, false, false, true, false, false, false, true, false, false, false, false, false],
50+
"pitches": [-12, 0, -7, 0, 0, 0, -5, 0, 0, 0, -3, 0, 0, 0, 0, 0],
51+
"volume": 80,
52+
"_comment": "Second 808 kick as a pitched bass element - stays within playable range"
53+
}
54+
],
55+
"listenFor": [
56+
"808 Kick: Deep, punchy bass without chipmunk artifacts even when pitched",
57+
"808 Snare: Crisp snap at correct pitch",
58+
"808 Hi-Hats: Clean, electronic character preserved",
59+
"808 Clap: Full clap sound without distortion",
60+
"Melodic Kick: Pitched kicks stay musical within the playable range"
61+
],
62+
"whyItMatters": "The 808 drum machine is iconic in hip-hop and electronic music. Correct pitch reproduction ensures that classic sound is preserved. The playableRange limits prevent extreme pitch-shifting that would destroy the character of these sounds."
63+
}
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
{
2+
"name": "Hammond Organ Showcase",
3+
"description": "Demonstrates the new Hammond Organ sampled instrument with 10 multi-sample zones. The dense sample coverage (every major 3rd) provides smooth pitch-shifting across the full range.",
4+
"bpm": 110,
5+
"tracks": [
6+
{
7+
"name": "Hammond - Gospel Chords",
8+
"sampleId": "sampled:hammond-organ",
9+
"steps": [true, false, false, false, true, false, false, false, true, false, false, false, true, false, false, false],
10+
"pitches": [0, 0, 0, 0, 4, 0, 0, 0, 7, 0, 0, 0, 12, 0, 0, 0],
11+
"volume": 75,
12+
"_comment": "Hammond root notes building a chord progression"
13+
},
14+
{
15+
"name": "Hammond - Thirds",
16+
"sampleId": "sampled:hammond-organ",
17+
"steps": [true, false, false, false, true, false, false, false, true, false, false, false, true, false, false, false],
18+
"pitches": [4, 0, 0, 0, 7, 0, 0, 0, 11, 0, 0, 0, 16, 0, 0, 0],
19+
"volume": 70,
20+
"_comment": "Third intervals layered with roots"
21+
},
22+
{
23+
"name": "Hammond - Upper Melody",
24+
"sampleId": "sampled:hammond-organ",
25+
"steps": [false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true],
26+
"pitches": [12, 0, 14, 0, 16, 0, 19, 0, 16, 0, 14, 0, 12, 0, 11, 0],
27+
"volume": 65,
28+
"_comment": "Melodic line in upper register showing smooth pitch transitions"
29+
},
30+
{
31+
"name": "Hammond - Bass Pedals",
32+
"sampleId": "sampled:hammond-organ",
33+
"steps": [true, false, false, false, false, false, false, false, true, false, false, false, false, false, false, false],
34+
"pitches": [-12, 0, 0, 0, 0, 0, 0, 0, -8, 0, 0, 0, 0, 0, 0, 0],
35+
"volume": 80,
36+
"_comment": "Low organ bass pedals"
37+
},
38+
{
39+
"name": "Acoustic Kick",
40+
"sampleId": "sampled:acoustic-kick",
41+
"steps": [true, false, false, false, true, false, false, false, true, false, false, false, true, false, false, false],
42+
"pitches": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
43+
"volume": 85,
44+
"_comment": "Kick drum foundation"
45+
},
46+
{
47+
"name": "Acoustic Snare",
48+
"sampleId": "sampled:acoustic-snare",
49+
"steps": [false, false, false, false, true, false, false, false, false, false, false, false, true, false, false, false],
50+
"pitches": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
51+
"volume": 80,
52+
"_comment": "Snare backbeat"
53+
}
54+
],
55+
"listenFor": [
56+
"Hammond: Rich, warm organ tone with drawbar character",
57+
"Smooth transitions: Notes shift smoothly between samples (max 2 semitone shift)",
58+
"Full range: Bass pedals to upper melody all sound consistent",
59+
"Sustain: Organ tones hold naturally with 0.3s release"
60+
],
61+
"whyItMatters": "The Hammond B3 organ is essential for gospel, jazz, and rock. With 10 samples covering every major 3rd from C2 to C5, this instrument provides excellent pitch-shift quality across its entire playable range (C2-C6)."
62+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
{
2+
"name": "Pitch-Shift Artifact Demo",
3+
"description": "Demonstrates pitch-shifting artifacts at extreme ranges. Listen for formant shift (chipmunk effect), unnatural attacks, and quality inconsistency.",
4+
"bpm": 100,
5+
"tracks": [
6+
{
7+
"name": "French Horn - Chromatic (Problem: 17st gap)",
8+
"sampleId": "synth:french-horn",
9+
"steps": [true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false],
10+
"pitches": [-12, 0, -10, 0, -8, 0, -6, 0, -4, 0, -2, 0, 0, 0, 2, 0],
11+
"volume": 80,
12+
"_comment": "Notes at -12 to -6 require 8+ semitone shift from C1 sample - listen for chipmunk effect"
13+
},
14+
{
15+
"name": "808 Kick - Pitched Up (Problem: single sample)",
16+
"sampleId": "synth:808-kick",
17+
"steps": [true, false, false, false, true, false, false, false, true, false, false, false, true, false, false, false],
18+
"pitches": [0, 0, 0, 0, 6, 0, 0, 0, 12, 0, 0, 0, 18, 0, 0, 0],
19+
"volume": 90,
20+
"_comment": "Base note is 36. +18 semitones sounds unnatural - outside playable range"
21+
},
22+
{
23+
"name": "Marimba - Wide Melody (Problem: 17st gap)",
24+
"sampleId": "synth:marimba",
25+
"steps": [true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false],
26+
"pitches": [-12, 0, -6, 0, 0, 0, 6, 0, 12, 0, 6, 0, 0, 0, -6, 0],
27+
"volume": 75,
28+
"_comment": "Large gaps between samples cause quality inconsistency across range"
29+
},
30+
{
31+
"name": "Piano - Reference (Octave spacing OK)",
32+
"sampleId": "synth:piano",
33+
"steps": [true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false],
34+
"pitches": [-12, 0, -6, 0, 0, 0, 6, 0, 12, 0, 6, 0, 0, 0, -6, 0],
35+
"volume": 70,
36+
"_comment": "Same melody on piano for comparison - octave spacing is acceptable"
37+
}
38+
],
39+
"listenFor": [
40+
"French Horn: Formant shift (chipmunk effect) on low notes",
41+
"808 Kick: Unnatural attack and timbre when pitched up high",
42+
"Marimba: Quality inconsistency between notes near vs far from samples",
43+
"Piano: Reference - should sound more consistent despite same octave spacing"
44+
]
45+
}
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
{
2+
"name": "Release Time Calibration Demo",
3+
"description": "Demonstrates the importance of proper release time calibration. Some instruments cut off too abruptly (short release), others sustain too long and blur together.",
4+
"bpm": 120,
5+
"tracks": [
6+
{
7+
"name": "Vibraphone - Natural Resonance",
8+
"sampleId": "synth:vibraphone",
9+
"steps": [true, false, false, false, true, false, false, false, true, false, false, false, true, false, false, false],
10+
"pitches": [0, 0, 0, 0, 4, 0, 0, 0, 7, 0, 0, 0, 12, 0, 0, 0],
11+
"volume": 75,
12+
"_comment": "Release time: 1.0s. Real vibraphones ring for 2-4 seconds. Listen for natural decay."
13+
},
14+
{
15+
"name": "Piano - Damper Pedal Effect",
16+
"sampleId": "synth:piano",
17+
"steps": [true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false],
18+
"pitches": [0, 0, 2, 0, 4, 0, 5, 0, 7, 0, 9, 0, 11, 0, 12, 0],
19+
"volume": 70,
20+
"_comment": "Release time: 0.5s. Fast passages should have clear note separation."
21+
},
22+
{
23+
"name": "Rhodes EP - Tine Decay",
24+
"sampleId": "synth:rhodes-ep",
25+
"steps": [true, false, false, true, false, false, true, false, true, false, false, true, false, false, true, false],
26+
"pitches": [0, 0, 0, 4, 0, 0, 7, 0, 12, 0, 0, 7, 0, 0, 4, 0],
27+
"volume": 72,
28+
"_comment": "Release time: 0.8s. Rhodes tines have distinctive bell-like decay character."
29+
},
30+
{
31+
"name": "808 Kick - Tight Decay",
32+
"sampleId": "synth:808-kick",
33+
"steps": [true, false, false, false, true, false, false, false, true, false, false, false, true, false, false, false],
34+
"pitches": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
35+
"volume": 90,
36+
"_comment": "Release time: 0.1s. 808 kicks need tight control to prevent muddy low end."
37+
},
38+
{
39+
"name": "Hi-Hat Closed - Crisp Cutoff",
40+
"sampleId": "synth:808-hihat-closed",
41+
"steps": [true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true],
42+
"pitches": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
43+
"volume": 65,
44+
"_comment": "Release time: 0.05s. Closed hi-hats should cut off very quickly for tight rhythm."
45+
},
46+
{
47+
"name": "Strings - Long Sustain",
48+
"sampleId": "synth:strings",
49+
"steps": [true, false, false, false, false, false, false, false, true, false, false, false, false, false, false, false],
50+
"pitches": [0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0],
51+
"volume": 68,
52+
"_comment": "Release time: 1.5s. Strings naturally sustain long with bow. Listen for smooth transitions."
53+
}
54+
],
55+
"listenFor": [
56+
"Vibraphone: Does the decay feel natural like metal bars ringing?",
57+
"Piano: Are fast passages clear or do notes blur together?",
58+
"Rhodes EP: Does the bell-like quality sustain appropriately?",
59+
"808 Kick: Is the low end tight or does it get muddy?",
60+
"Hi-Hat: Does it cut off crisply between hits?",
61+
"Strings: Do sustained notes transition smoothly?"
62+
],
63+
"calibratedValues": {
64+
"vibraphone": "1.0s (was 1.5s - reduced for step sequencer context)",
65+
"piano": "0.5s (unchanged - good for melodic use)",
66+
"rhodes-ep": "0.8s (was 1.0s - tightened for clarity)",
67+
"808-kick": "0.1s (unchanged - tight and punchy)",
68+
"808-hihat-closed": "0.05s (unchanged - crisp)",
69+
"strings": "1.5s (was 2.0s - reduced for better transitions)"
70+
}
71+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
{
2+
"name": "Velocity Limitation Demo",
3+
"description": "Demonstrates the lack of velocity layers. All notes play at same dynamic level regardless of intended intensity. Compare soft vs loud passages - they sound identical except for volume.",
4+
"bpm": 80,
5+
"tracks": [
6+
{
7+
"name": "Piano - Should be expressive",
8+
"sampleId": "synth:piano",
9+
"steps": [true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true],
10+
"pitches": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
11+
"volume": 80,
12+
"_comment": "Real piano: soft notes have rounder tone, loud notes have brighter attack. Here: all identical timbre."
13+
},
14+
{
15+
"name": "Vibraphone - Mallet intensity missing",
16+
"sampleId": "synth:vibraphone",
17+
"steps": [true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false],
18+
"pitches": [0, 0, 2, 0, 4, 0, 5, 0, 7, 0, 9, 0, 11, 0, 12, 0],
19+
"volume": 75,
20+
"_comment": "Real vibraphone: soft mallets produce warm tone, hard strikes produce bright shimmer. Here: uniform."
21+
},
22+
{
23+
"name": "Strings - No bow pressure variation",
24+
"sampleId": "synth:strings",
25+
"steps": [true, false, false, false, true, false, false, false, true, false, false, false, true, false, false, false],
26+
"pitches": [0, 0, 0, 0, 7, 0, 0, 0, 12, 0, 0, 0, 7, 0, 0, 0],
27+
"volume": 70,
28+
"_comment": "Real strings: light bow = airy, heavy bow = rich harmonics. Here: same sample always."
29+
},
30+
{
31+
"name": "808 Kick - Impact variation missing",
32+
"sampleId": "synth:808-kick",
33+
"steps": [true, false, false, false, true, false, true, false, true, false, false, false, true, false, true, false],
34+
"pitches": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
35+
"volume": 90,
36+
"_comment": "Pattern alternates between accented and ghost notes - but all sound identical in character."
37+
}
38+
],
39+
"listenFor": [
40+
"Piano: Every note has identical attack character regardless of musical context",
41+
"Vibraphone: No timbral difference between gentle and struck notes",
42+
"Strings: Uniform texture without expressive bow pressure variation",
43+
"808 Kick: Ghost notes and accents have same impact character (only volume differs)"
44+
],
45+
"whyItMatters": "Velocity layers are essential for musical expression. Without them, performances sound mechanical and lifeless. Real instruments change their timbral character based on playing intensity - soft piano notes are rounder, loud notes are brighter with more harmonics. This demo shows how current samples lack this dynamic expression."
46+
}

0 commit comments

Comments
 (0)