tuneframes 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (78) hide show
  1. package/LICENSE +167 -199
  2. package/README.md +150 -97
  3. package/examples/example-ai-dj-chill.html +167 -0
  4. package/examples/example-ai-dj-dark.html +167 -0
  5. package/examples/example-ai-dj-energetic.html +167 -0
  6. package/examples/example-ai-dj-happy.html +167 -0
  7. package/examples/example-ai-dj.html +167 -0
  8. package/examples/example-ambient.html +63 -63
  9. package/examples/example-ambient.mp3 +0 -0
  10. package/examples/example-bass.html +48 -0
  11. package/examples/example-lofi.html +45 -45
  12. package/examples/example-lofi.mp3 +0 -0
  13. package/examples/example-minimal.html +21 -19
  14. package/examples/example-minimal.mp3 +0 -0
  15. package/examples/example-orchestral.html +67 -67
  16. package/examples/example-orchestral.mp3 +0 -0
  17. package/examples/example-piano.html +53 -0
  18. package/examples/example-piano.mp3 +0 -0
  19. package/examples/example-techno.html +69 -69
  20. package/examples/example-techno.mp3 +0 -0
  21. package/package.json +42 -24
  22. package/registry/presets/bass-electric.html +67 -0
  23. package/registry/presets/bass-saw.html +22 -0
  24. package/registry/presets/chord-progression.html +22 -0
  25. package/registry/presets/drums-808.html +85 -0
  26. package/registry/presets/drums-lofi.html +35 -0
  27. package/registry/presets/lead-piano.html +26 -0
  28. package/registry/presets/piano-salamander.html +69 -0
  29. package/registry/presets/reverb-warm.html +11 -0
  30. package/registry/samples.json +226 -0
  31. package/skills/audio-ambient/SKILL.md +141 -0
  32. package/skills/audio-ambient/example.html +113 -0
  33. package/skills/audio-boss-battle/SKILL.md +157 -0
  34. package/skills/audio-boss-battle/example.html +185 -0
  35. package/skills/audio-boss-battle/example.mp3 +0 -0
  36. package/skills/audio-chillwave/SKILL.md +142 -0
  37. package/skills/audio-chillwave/example.html +144 -0
  38. package/skills/audio-cinematic/SKILL.md +147 -0
  39. package/skills/audio-cinematic/example.html +123 -0
  40. package/skills/audio-classical/SKILL.md +138 -0
  41. package/skills/audio-classical/example.html +145 -0
  42. package/skills/audio-dnb/SKILL.md +142 -0
  43. package/skills/audio-dnb/example.html +124 -0
  44. package/skills/audio-downtempo/SKILL.md +152 -0
  45. package/skills/audio-downtempo/example.html +164 -0
  46. package/skills/audio-folk/SKILL.md +139 -0
  47. package/skills/audio-folk/example.html +132 -0
  48. package/skills/audio-funk/SKILL.md +149 -0
  49. package/skills/audio-funk/example.html +144 -0
  50. package/skills/audio-future-bass/SKILL.md +163 -0
  51. package/skills/audio-future-bass/example.html +164 -0
  52. package/skills/audio-hip-hop/SKILL.md +133 -0
  53. package/skills/audio-hip-hop/example.html +129 -0
  54. package/skills/audio-house/SKILL.md +147 -0
  55. package/skills/audio-house/example.html +128 -0
  56. package/skills/audio-indie-pop/SKILL.md +150 -0
  57. package/skills/audio-indie-pop/example.html +121 -0
  58. package/skills/audio-jazz/SKILL.md +141 -0
  59. package/skills/audio-jazz/example.html +146 -0
  60. package/skills/audio-lofi/SKILL.md +140 -0
  61. package/skills/audio-lofi/example.html +135 -0
  62. package/skills/audio-minimal/SKILL.md +155 -0
  63. package/skills/audio-minimal/example.html +118 -0
  64. package/skills/audio-orchestral/SKILL.md +156 -0
  65. package/skills/audio-orchestral/example.html +140 -0
  66. package/skills/audio-r-and-b/SKILL.md +134 -0
  67. package/skills/audio-r-and-b/example.html +154 -0
  68. package/skills/audio-r-and-b/example.mp3 +0 -0
  69. package/skills/audio-techno/SKILL.md +140 -0
  70. package/skills/audio-techno/example.html +125 -0
  71. package/skills/audio-trap/SKILL.md +123 -0
  72. package/skills/audio-trap/example.html +119 -0
  73. package/skills/render-retest/example.html +115 -0
  74. package/skills/tuneframes/SKILL.md +221 -0
  75. package/skills/tuneframes-cli/SKILL.md +46 -0
  76. package/skills/verify/example.html +104 -0
  77. package/src/cli.js +261 -89
  78. package/src/render.js +134 -7
@@ -0,0 +1,144 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>TuneFrames — Funk</title>
5
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/tone/14.8.49/Tone.js"></script>
6
+ </head>
7
+ <body>
8
+ <div id="tuneframes" style="display:none">{"bpm":104,"duration":"12s"}</div>
9
+ <script>
10
+ async function main() {
11
+ await Tone.start();
12
+ Tone.Transport.bpm.value = 104;
13
+
14
+ const s16 = Tone.Time('16n').toSeconds(); // ~0.144s
15
+ const q = Tone.Time('4n').toSeconds(); // ~0.577s
16
+ const bar = Tone.Time('1n').toSeconds(); // ~2.308s
17
+
18
+ // ── Bus compressor (the funk glue) ──────────────────────────────────
19
+ const comp = new Tone.Compressor({ threshold: -16, ratio: 4, attack: 0.003, release: 0.12 }).toDestination();
20
+ const room = new Tone.Reverb({ decay: 0.6, wet: 0.12 }).connect(comp);
21
+
22
+ // ── Slap bass ───────────────────────────────────────────────────────
23
+ const bassFilter = new Tone.Filter(800, 'lowpass').connect(comp);
24
+ const bass = new Tone.Synth({
25
+ oscillator: { type: 'square' },
26
+ envelope: { attack: 0.001, decay: 0.09, sustain: 0.0, release: 0.04 }
27
+ }).connect(bassFilter);
28
+ bass.volume.value = -4;
29
+
30
+ // One-bar groove in E — repeated 5 times
31
+ const bassPattern = [
32
+ { note: 'E2', t: 0 },
33
+ { note: 'E2', t: s16*2 },
34
+ { note: 'G2', t: s16*3 },
35
+ { note: 'E2', t: s16*4 },
36
+ { note: 'A2', t: s16*6 },
37
+ { note: 'E2', t: s16*8 },
38
+ { note: 'D2', t: s16*10 },
39
+ { note: 'E2', t: s16*12 },
40
+ { note: 'Gb2', t: s16*14 },
41
+ ];
42
+ for (let rep = 0; rep < 5; rep++) {
43
+ bassPattern.forEach(({ note, t }) => bass.triggerAttackRelease(note, '16n', rep * bar + t));
44
+ }
45
+
46
+ // ── Rhythm guitar chank (bandpass, hits on upbeats) ─────────────────
47
+ const guitFilter = new Tone.Filter(2200, 'bandpass').connect(room);
48
+ const guitar = new Tone.PolySynth(Tone.Synth, {
49
+ oscillator: { type: 'triangle' },
50
+ envelope: { attack: 0.003, decay: 0.1, sustain: 0.0, release: 0.06 }
51
+ }).connect(guitFilter);
52
+ guitar.volume.value = -14;
53
+
54
+ // Chank on "and" of 2 (s16*9) and "and" of 4 (s16*13) — classic funk chop
55
+ const chankTimes = [s16 * 9, s16 * 13];
56
+ for (let rep = 0; rep < 5; rep++) {
57
+ chankTimes.forEach(t => {
58
+ guitar.triggerAttackRelease(['E4','G4','B4'], '16n', rep * bar + t);
59
+ });
60
+ }
61
+
62
+ // ── Brass stabs (upbeat, punchy) ────────────────────────────────────
63
+ const brassFilter = new Tone.Filter(4000, 'lowpass').connect(room);
64
+ const brass = new Tone.PolySynth(Tone.Synth, {
65
+ oscillator: { type: 'sawtooth' },
66
+ envelope: { attack: 0.006, decay: 0.13, sustain: 0.0, release: 0.07 }
67
+ }).connect(brassFilter);
68
+ brass.volume.value = -10;
69
+
70
+ // Stabs enter on bar 2 — same upbeat timing as guitar chank
71
+ for (let rep = 1; rep < 5; rep++) {
72
+ [s16 * 9, s16 * 13].forEach(t => {
73
+ brass.triggerAttackRelease(['E4','G4','B4'], '16n', rep * bar + t);
74
+ // Second stab chord a beat later for call-and-response
75
+ brass.triggerAttackRelease(['D4','F4','A4'], '16n', rep * bar + t + s16 * 2);
76
+ });
77
+ }
78
+
79
+ // ── Kick drum ───────────────────────────────────────────────────────
80
+ const kick = new Tone.MembraneSynth({
81
+ pitchDecay: 0.04, octaves: 6,
82
+ envelope: { attack: 0.001, decay: 0.22, sustain: 0, release: 0.08 }
83
+ }).connect(comp);
84
+ kick.volume.value = -8;
85
+
86
+ // Kick pattern: beat 1, then syncopated 16th before beat 3 and on the "a" of 3
87
+ for (let rep = 0; rep < 5; rep++) {
88
+ kick.triggerAttackRelease('C1', '8n', rep * bar); // beat 1
89
+ kick.triggerAttackRelease('C1', '8n', rep * bar + s16 * 7); // "and-a" of 2
90
+ kick.triggerAttackRelease('C1', '8n', rep * bar + s16 * 10); // "and" of 3
91
+ }
92
+
93
+ // ── Snare on 2 and 4 (with ghost notes) ────────────────────────────
94
+ const snareBp = new Tone.Filter(3200, 'bandpass').connect(room);
95
+ const snare = new Tone.NoiseSynth({
96
+ noise: { type: 'white' },
97
+ envelope: { attack: 0.001, decay: 0.11, sustain: 0, release: 0.04 }
98
+ }).connect(snareBp);
99
+ snare.volume.value = -12;
100
+
101
+ const ghostSnare = new Tone.NoiseSynth({
102
+ noise: { type: 'white' },
103
+ envelope: { attack: 0.001, decay: 0.05, sustain: 0, release: 0.02 }
104
+ }).connect(snareBp);
105
+ ghostSnare.volume.value = -26; // quiet ghosts
106
+
107
+ for (let rep = 0; rep < 5; rep++) {
108
+ snare.triggerAttackRelease('8n', rep * bar + q); // beat 2
109
+ snare.triggerAttackRelease('8n', rep * bar + q * 3); // beat 4
110
+ // Ghost notes around beat 3
111
+ ghostSnare.triggerAttackRelease('16n', rep * bar + s16 * 9);
112
+ ghostSnare.triggerAttackRelease('16n', rep * bar + s16 * 11);
113
+ }
114
+
115
+ // ── 16th hi-hats ───────────────────────────────────────────────────
116
+ const hat = new Tone.MetalSynth({
117
+ frequency: 600, harmonicity: 5.1, modulationIndex: 32,
118
+ resonance: 4000, octaves: 1.5,
119
+ envelope: { attack: 0.001, decay: 0.028, release: 0.008 }
120
+ }).connect(comp);
121
+ hat.volume.value = -19;
122
+
123
+ // Full 16th grid, slight accent on quarter notes
124
+ for (let rep = 0; rep < 5; rep++) {
125
+ for (let i = 0; i < 16; i++) {
126
+ hat.triggerAttackRelease('32n', rep * bar + i * s16);
127
+ }
128
+ }
129
+
130
+ // ── Open hi-hat accent on beat 4 of every other bar ────────────────
131
+ const openHat = new Tone.MetalSynth({
132
+ frequency: 400, harmonicity: 3.1, modulationIndex: 12,
133
+ resonance: 2000, octaves: 1.0,
134
+ envelope: { attack: 0.001, decay: 0.22, release: 0.08 }
135
+ }).connect(room);
136
+ openHat.volume.value = -18;
137
+
138
+ for (let rep = 1; rep < 5; rep += 2) {
139
+ openHat.triggerAttackRelease('8n', rep * bar + q * 3);
140
+ }
141
+ }
142
+ </script>
143
+ </body>
144
+ </html>
@@ -0,0 +1,163 @@
1
+ ---
2
+ name: audio-future-bass
3
+ description: Future Bass — wide supersaw chords (fatsawtooth PolySynth), emotional melodic lead, pitched 808 sub, trap-influenced drums, massive chorus/reverb. Flume / San Holo energy. Big, emotional, wide stereo field.
4
+ ---
5
+
6
+ # TuneFrames — Future Bass
7
+
8
+ ## Genre Profile
9
+ - BPM range: 140–160 (half-time groove feel, effective "heard" tempo closer to 70–80)
10
+ - Key characteristics: Supersaw chords (fatsawtooth oscillator, 5–7 unison voices, 30–50 spread), emotional minor-key melody, 808 sub bass (MembraneSynth with long pitchDecay), trap-influenced sparse kick, massive clap with reverb, hi-hat rolls with velocity variation, heavy chorus and reverb on chords
11
+ - Typical instruments: PolySynth/Synth fatsawtooth (supersaw chords), Synth/AMSynth (lead), MembraneSynth (808 + kick), NoiseSynth (clap), MetalSynth (hi-hats)
12
+ - Mood: Euphoric, emotional, uplifting, wide, festival-ready
13
+
14
+ ## Core Pattern
15
+
16
+ ```js
17
+ // Future Bass — 150 BPM, A minor
18
+ // Structure: intro (bars 1–2) → drop (bar 3 onward)
19
+ // Chords: Am – F – C – G (1 bar each, looping)
20
+ // 808 sub follows chord roots with pitch glide
21
+ // Half-time drums: sparse kick, big clap on beat 3
22
+
23
+ Tone.Transport.bpm.value = 150;
24
+
25
+ // Supersaw chord synth — fatsawtooth is the key ingredient
26
+ const chordVerb = new Tone.Reverb({ decay: 4, wet: 0.55 }).toDestination();
27
+ const chordChorus = new Tone.Chorus({ frequency: 0.8, delayTime: 3.5, depth: 0.8, wet: 0.7 }).connect(chordVerb);
28
+ chordChorus.start();
29
+ const chords = new Tone.PolySynth(Tone.Synth, {
30
+ oscillator: { type: "fatsawtooth", count: 5, spread: 40 },
31
+ envelope: { attack: 0.08, decay: 0.2, sustain: 0.75, release: 2.0 },
32
+ volume: -10
33
+ }).connect(chordChorus);
34
+
35
+ // 808 sub — MembraneSynth with long pitch glide
36
+ const sub808Dist = new Tone.Distortion({ distortion: 0.1, wet: 0.25 }).toDestination();
37
+ const sub808 = new Tone.MembraneSynth({
38
+ pitchDecay: 0.45, // the "808 fall" — pitch glides from note down
39
+ octaves: 3,
40
+ envelope: { attack: 0.001, decay: 0.85, sustain: 0, release: 0.4 }
41
+ }).connect(sub808Dist);
42
+
43
+ // Schedule supersaw chords at the drop (bar 3+)
44
+ // One-bar chord stabs with full sustain
45
+ const dropChords = [
46
+ { time: "2m", notes: ["A2","E3","A3","C4","E4"] }, // Am
47
+ { time: "3m", notes: ["F2","C3","F3","A3","C4"] }, // F
48
+ { time: "4m", notes: ["C3","G3","C4","E4","G4"] }, // C
49
+ { time: "5m", notes: ["G2","D3","G3","B3","D4"] }, // G
50
+ ];
51
+ dropChords.forEach(({ time, notes }) => {
52
+ chords.triggerAttackRelease(notes, "1m", time);
53
+ });
54
+
55
+ // 808 bass hits on chord roots — enters with drop
56
+ const subHits = [
57
+ { time: "2m", note: "A2" }, { time: "3m", note: "F2" },
58
+ { time: "4m", note: "C2" }, { time: "5m", note: "G2" },
59
+ ];
60
+ subHits.forEach(({ time, note }) => {
61
+ sub808.triggerAttackRelease(note, "2n", time);
62
+ });
63
+
64
+ Tone.Transport.start();
65
+ ```
66
+
67
+ ## Instrument Configuration
68
+
69
+ ```js
70
+ // Supersaw chords — fatsawtooth + wide chorus is the defining sound
71
+ const chordVerb = new Tone.Reverb({ decay: 4.0, wet: 0.55 }).toDestination();
72
+ const chordChorus = new Tone.Chorus({ frequency: 0.8, delayTime: 3.5, depth: 0.8, wet: 0.7 });
73
+ chordChorus.connect(chordVerb);
74
+ chordChorus.start();
75
+ const chords = new Tone.PolySynth(Tone.Synth, {
76
+ oscillator: { type: "fatsawtooth", count: 5, spread: 40 },
77
+ envelope: { attack: 0.08, decay: 0.2, sustain: 0.75, release: 2.0 },
78
+ volume: -10
79
+ }).connect(chordChorus);
80
+
81
+ // Lead melody — bright, emotional
82
+ const leadVerb = new Tone.Reverb({ decay: 2.5, wet: 0.4 }).toDestination();
83
+ const leadDelay = new Tone.FeedbackDelay({ delayTime: "8n", feedback: 0.3, wet: 0.25 }).connect(leadVerb);
84
+ const lead = new Tone.Synth({
85
+ oscillator: { type: "triangle" },
86
+ envelope: { attack: 0.02, decay: 0.3, sustain: 0.6, release: 1.0 },
87
+ volume: -6
88
+ }).connect(leadDelay);
89
+
90
+ // 808 sub — long pitch decay = the glide
91
+ const sub808Dist = new Tone.Distortion({ distortion: 0.1, wet: 0.25 }).toDestination();
92
+ const sub808 = new Tone.MembraneSynth({
93
+ pitchDecay: 0.45,
94
+ octaves: 3,
95
+ envelope: { attack: 0.001, decay: 0.85, sustain: 0, release: 0.4 },
96
+ volume: 2
97
+ }).connect(sub808Dist);
98
+
99
+ // Trap kick — on beat 1 (half-time feel)
100
+ const kick = new Tone.MembraneSynth({
101
+ pitchDecay: 0.08, octaves: 8,
102
+ envelope: { attack: 0.001, decay: 0.35, sustain: 0, release: 0.1 },
103
+ volume: 0
104
+ }).toDestination();
105
+
106
+ // Clap — big noise transient with long reverb
107
+ const clapVerb = new Tone.Reverb({ decay: 2.8, wet: 0.55 }).toDestination();
108
+ const clap = new Tone.NoiseSynth({
109
+ noise: { type: "white" },
110
+ envelope: { attack: 0.001, decay: 0.18, sustain: 0, release: 0.08 },
111
+ volume: -4
112
+ }).connect(clapVerb);
113
+
114
+ // Hi-hat — trap roll with velocity variation
115
+ const hat = new Tone.MetalSynth({
116
+ frequency: 600, harmonicity: 5.1, modulationIndex: 32,
117
+ resonance: 4500, octaves: 1.5,
118
+ envelope: { attack: 0.001, decay: 0.03, release: 0.01 },
119
+ volume: -12
120
+ }).toDestination();
121
+ ```
122
+
123
+ ## Composition Structure
124
+
125
+ - **Intro (bars 1–2):** Lead melody only with light hi-hats — emotional hook, no chords yet
126
+ - **Build (end of bar 2):** Riser noise (NoiseSynth with rising filter) creates anticipation
127
+ - **Drop (bar 3):** Supersaw chords crash in simultaneously with kick, clap, and 808 sub
128
+ - **Drop loop:** Am–F–C–G chord cycle (1 bar each), 808 follows roots, hats roll
129
+ - **Variation:** Add pitch bend on lead (modulate `lead.detune.value` ±50 cents over 1 bar)
130
+ - **Breakdown:** Mute drums, let chords ring with reverb tail — rebuild tension
131
+ - **Second drop:** Higher register chord voicing, lead octave up
132
+
133
+ Emotional tension technique: during the bar before the drop, cut all sound (or just leave a white noise riser), then everything hits at once — maximum impact.
134
+
135
+ ## Example Variations
136
+
137
+ ### 1 — Wider supersaw (more voices)
138
+ ```js
139
+ // More unison voices = fatter, more expensive but more enormous
140
+ const chords = new Tone.PolySynth(Tone.Synth, {
141
+ oscillator: { type: "fatsawtooth", count: 7, spread: 55 },
142
+ // ...
143
+ });
144
+ ```
145
+
146
+ ### 2 — Filter sweep on drop entry
147
+ ```js
148
+ // Chords start filtered and open up over the first bar of the drop
149
+ const chordFilter = new Tone.Filter({ frequency: 300, type: "lowpass", Q: 2 });
150
+ // chain: chords → chordFilter → chordChorus → chordVerb
151
+ const sweepStart = Tone.Time("2m").toSeconds();
152
+ chordFilter.frequency.setValueAtTime(300, sweepStart);
153
+ chordFilter.frequency.exponentialRampToValueAtTime(12000, sweepStart + Tone.Time("1m").toSeconds());
154
+ ```
155
+
156
+ ### 3 — Pitched chord stab (one-hit per bar)
157
+ ```js
158
+ // Instead of sustained chords, use a sharp pluck attack then let the reverb carry
159
+ const chords = new Tone.PolySynth(Tone.Synth, {
160
+ oscillator: { type: "fatsawtooth", count: 5, spread: 40 },
161
+ envelope: { attack: 0.005, decay: 0.15, sustain: 0, release: 2.5 }, // no sustain = pluck
162
+ });
163
+ ```
@@ -0,0 +1,164 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <title>TuneFrames — Future Bass</title>
6
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/tone/14.8.49/Tone.js"></script>
7
+ </head>
8
+ <body>
9
+ <!-- TuneFrames Metadata -->
10
+ <div id="tuneframes" style="display:none">{"bpm":150,"duration":"12s"}</div>
11
+
12
+ <script>
13
+ async function main() {
14
+ await Tone.start();
15
+ Tone.Transport.bpm.value = 150;
16
+
17
+ // --- MASTER BUS ---
18
+ const masterLimiter = new Tone.Limiter(-1).toDestination();
19
+ const masterGain = new Tone.Gain(0.82).connect(masterLimiter);
20
+
21
+ // --- SUPERSAW CHORDS — fatsawtooth + wide chorus + huge reverb ---
22
+ const chordVerb = new Tone.Reverb({ decay: 4.0, wet: 0.55 }).connect(masterGain);
23
+ const chordChorus = new Tone.Chorus({ frequency: 0.8, delayTime: 3.5, depth: 0.8, wet: 0.7 }).connect(chordVerb);
24
+ chordChorus.start();
25
+ const chordGain = new Tone.Gain(0.45).connect(chordChorus);
26
+ const chords = new Tone.PolySynth(Tone.Synth, {
27
+ oscillator: { type: "fatsawtooth", count: 5, spread: 40 },
28
+ envelope: { attack: 0.08, decay: 0.2, sustain: 0.75, release: 2.0 },
29
+ volume: 0
30
+ }).connect(chordGain);
31
+
32
+ // --- LEAD — emotional melodic line, triangle + delay ---
33
+ const leadVerb = new Tone.Reverb({ decay: 2.5, wet: 0.4 }).connect(masterGain);
34
+ const leadDelay = new Tone.FeedbackDelay({ delayTime: "8n", feedback: 0.28, wet: 0.25 }).connect(leadVerb);
35
+ const leadGain = new Tone.Gain(0.6).connect(leadDelay);
36
+ const lead = new Tone.Synth({
37
+ oscillator: { type: "triangle" },
38
+ envelope: { attack: 0.02, decay: 0.3, sustain: 0.6, release: 1.0 },
39
+ volume: 0
40
+ }).connect(leadGain);
41
+
42
+ // --- 808 SUB — long pitch glide, saturated ---
43
+ const sub808Dist = new Tone.Distortion({ distortion: 0.12, wet: 0.3 }).connect(masterGain);
44
+ const sub808Gain = new Tone.Gain(0.85).connect(sub808Dist);
45
+ const sub808 = new Tone.MembraneSynth({
46
+ pitchDecay: 0.45,
47
+ octaves: 3,
48
+ envelope: { attack: 0.001, decay: 0.9, sustain: 0, release: 0.4 }
49
+ }).connect(sub808Gain);
50
+
51
+ // --- KICK — trap: sparse, heavy ---
52
+ const kickGain = new Tone.Gain(0.9).connect(masterGain);
53
+ const kick = new Tone.MembraneSynth({
54
+ pitchDecay: 0.08,
55
+ octaves: 8,
56
+ envelope: { attack: 0.001, decay: 0.38, sustain: 0, release: 0.1 }
57
+ }).connect(kickGain);
58
+
59
+ // --- CLAP — big noise with long reverb ---
60
+ const clapVerb = new Tone.Reverb({ decay: 2.8, wet: 0.55 }).connect(masterGain);
61
+ const clapGain = new Tone.Gain(0.55).connect(clapVerb);
62
+ const clap = new Tone.NoiseSynth({
63
+ noise: { type: "white" },
64
+ envelope: { attack: 0.001, decay: 0.18, sustain: 0, release: 0.08 }
65
+ }).connect(clapGain);
66
+
67
+ // --- HI-HAT — trap roll, heavy velocity variation ---
68
+ const hatGain = new Tone.Gain(0.35).connect(masterGain);
69
+ const hat = new Tone.MetalSynth({
70
+ frequency: 600,
71
+ envelope: { attack: 0.001, decay: 0.03, release: 0.01 },
72
+ harmonicity: 5.1,
73
+ modulationIndex: 32,
74
+ resonance: 4500,
75
+ octaves: 1.5
76
+ }).connect(hatGain);
77
+
78
+ // --- PATTERNS ---
79
+
80
+ // Intro lead melody (bars 1–2): emotional minor pentatonic line
81
+ const introLead = [
82
+ { time: "0:0:0", note: "A4", dur: "4n" },
83
+ { time: "0:1:0", note: "G4", dur: "8n" },
84
+ { time: "0:1:2", note: "E4", dur: "8n" },
85
+ { time: "0:2:0", note: "C5", dur: "4n" },
86
+ { time: "0:3:0", note: "A4", dur: "4n" },
87
+ { time: "1:0:0", note: "E4", dur: "2n" },
88
+ { time: "1:2:0", note: "G4", dur: "4n" },
89
+ { time: "1:3:0", note: "A4", dur: "4n" },
90
+ ];
91
+ introLead.forEach(({ time, note, dur }) => {
92
+ lead.triggerAttackRelease(note, dur, time);
93
+ });
94
+
95
+ // Drop lead melody (bars 3–6): brighter, higher register
96
+ const dropLead = [
97
+ { time: "2:0:0", note: "A5", dur: "4n" },
98
+ { time: "2:1:0", note: "G5", dur: "8n" },
99
+ { time: "2:1:2", note: "E5", dur: "8n" },
100
+ { time: "2:2:0", note: "C5", dur: "4n" },
101
+ { time: "2:3:0", note: "A4", dur: "4n" },
102
+ { time: "3:0:0", note: "F5", dur: "2n" },
103
+ { time: "3:2:0", note: "E5", dur: "4n" },
104
+ { time: "3:3:0", note: "D5", dur: "4n" },
105
+ { time: "4:0:0", note: "C5", dur: "2n" },
106
+ { time: "4:2:0", note: "E5", dur: "4n" },
107
+ { time: "4:3:0", note: "G5", dur: "4n" },
108
+ { time: "5:0:0", note: "G5", dur: "2n" },
109
+ { time: "5:2:0", note: "A5", dur: "4n" },
110
+ { time: "5:3:0", note: "G5", dur: "4n" },
111
+ ];
112
+ dropLead.forEach(({ time, note, dur }) => {
113
+ lead.triggerAttackRelease(note, dur, time);
114
+ });
115
+
116
+ // Drop supersaw chords — Am, F, C, G (1 bar each, wide voicings)
117
+ const dropChords = [
118
+ { time: "2m", notes: ["A2","E3","A3","C4","E4"] },
119
+ { time: "3m", notes: ["F2","C3","F3","A3","C4"] },
120
+ { time: "4m", notes: ["C3","G3","C4","E4","G4"] },
121
+ { time: "5m", notes: ["G2","D3","G3","B3","D4"] },
122
+ ];
123
+ dropChords.forEach(({ time, notes }) => {
124
+ chords.triggerAttackRelease(notes, "1m", time);
125
+ });
126
+
127
+ // 808 sub bass — follows chord roots, enters with the drop
128
+ const subHits = [
129
+ { time: "2m", note: "A2" },
130
+ { time: "3m", note: "F2" },
131
+ { time: "4m", note: "C2" },
132
+ { time: "5m", note: "G2" },
133
+ ];
134
+ subHits.forEach(({ time, note }) => {
135
+ sub808.triggerAttackRelease(note, "2n", time);
136
+ });
137
+
138
+ // Kick: half-time feel — beat 1 every bar, plus extra on bar 2 beat 3
139
+ const kickSeq = new Tone.Sequence((time, val) => {
140
+ if (val) kick.triggerAttackRelease("C1", "8n", time);
141
+ }, ["C1",null,null,null,null,null,null,null,"C1",null,null,null,null,null,"C1",null], "16n");
142
+ kickSeq.start("2m");
143
+
144
+ // Clap: half-time snare on beat 3 (step 8 in 16-step)
145
+ const clapSeq = new Tone.Sequence((time, val) => {
146
+ if (val) clap.triggerAttackRelease("8n", time);
147
+ }, [null,null,null,null,null,null,null,null,1,null,null,null,null,null,null,null], "16n");
148
+ clapSeq.start("2m");
149
+
150
+ // Hi-hat: trap roll with velocity variation throughout
151
+ const hatVels = [0.8,0.3,0.7,0.2,0.6,0.3,0.8,0.2,0.7,0.3,0.6,0.2,0.9,0.3,1.0,0.2];
152
+ let hatStep = 0;
153
+ const hatSeq = new Tone.Sequence((time) => {
154
+ hat.triggerAttackRelease("32n", time, hatVels[hatStep % 16]);
155
+ hatStep++;
156
+ }, new Array(16).fill(1), "16n");
157
+ hatSeq.start(0);
158
+
159
+ }
160
+
161
+ main();
162
+ </script>
163
+ </body>
164
+ </html>
@@ -0,0 +1,133 @@
1
+ ---
2
+ name: audio-hip-hop
3
+ description: Boom Bap Hip Hop — punchy kick, snare on 2 and 4 with reverb tail, shuffled 16th hi-hats with swing, smooth bass line, warm soul-pad. Pete Rock / J Dilla / Madlib head-nod groove.
4
+ ---
5
+
6
+ # TuneFrames — Boom Bap Hip Hop
7
+
8
+ ## Genre Profile
9
+ - BPM range: 80–95 (slow enough to feel heavy)
10
+ - Key characteristics: Heavy kick with short distortion (MembraneSynth), snare strictly on beats 2 and 4 with long reverb tail, 16th-note hi-hats with Tone.Transport swing (0.4–0.6) for the shuffle, smooth chromatic bass line, warm pad chord with slow attack for "sampled soul" texture
11
+ - Typical instruments: MembraneSynth (kick), NoiseSynth (snare), MetalSynth or NoiseSynth (hat), MonoSynth or Synth (bass), PolySynth (pad)
12
+ - Mood: Head-nodding, soulful, heavy, hypnotic, dusty
13
+
14
+ ## Core Pattern
15
+
16
+ ```js
17
+ // Boom Bap — 88 BPM, F minor, 2-bar loop
18
+ // Swing makes this: 16th hat offbeats push back into shuffle territory
19
+ // Kick: beat 1 + syncopated ghost hit | Snare: beats 2 and 4 | Hat: 16ths shuffled
20
+
21
+ Tone.Transport.bpm.value = 88;
22
+ Tone.Transport.swing = 0.5; // full swing — offbeat 16ths pushed back
23
+ Tone.Transport.swingSubdivision = "16n";
24
+
25
+ // Kick: beat 1, "and" of beat 2, beat 3 (classic boom bap syncopation)
26
+ new Tone.Sequence((time, val) => {
27
+ if (val) kick.triggerAttackRelease("C1", "8n", time);
28
+ }, ["C1",null,null,null,null,null,"C1",null,"C1",null,null,null,null,null,null,null], "16n").start(0);
29
+ // beat1 and-of-2 beat3
30
+
31
+ // Snare: strictly 2 and 4
32
+ new Tone.Sequence((time, val) => {
33
+ if (val) snare.triggerAttackRelease("8n", time);
34
+ }, [null,null,null,null,1,null,null,null,null,null,null,null,1,null,null,null], "16n").start(0);
35
+
36
+ // Hi-hat: all 16ths with alternating velocity — swing does the shuffle work
37
+ const hatVels = [0.9,0.45,0.85,0.4,0.9,0.45,0.85,0.4,0.9,0.45,0.9,0.4,0.85,0.45,0.9,0.45];
38
+ let hatStep = 0;
39
+ new Tone.Sequence((time) => {
40
+ hat.triggerAttackRelease("16n", time, hatVels[hatStep++ % 16]);
41
+ }, new Array(16).fill(1), "16n").start(0);
42
+
43
+ Tone.Transport.start();
44
+ ```
45
+
46
+ ## Instrument Configuration
47
+
48
+ ```js
49
+ // Kick — MembraneSynth with slight saturation (the "punchy" sound)
50
+ const kickDist = new Tone.Distortion({ distortion: 0.2, wet: 0.4 }).toDestination();
51
+ const kick = new Tone.MembraneSynth({
52
+ pitchDecay: 0.07,
53
+ octaves: 6,
54
+ envelope: { attack: 0.001, decay: 0.32, sustain: 0, release: 0.1 },
55
+ volume: 0
56
+ }).connect(kickDist);
57
+
58
+ // Snare — white noise with a long reverb tail (the "room" sound)
59
+ const snareVerb = new Tone.Reverb({ decay: 1.8, wet: 0.5 }).toDestination();
60
+ const snare = new Tone.NoiseSynth({
61
+ noise: { type: "white" },
62
+ envelope: { attack: 0.001, decay: 0.2, sustain: 0, release: 0.06 },
63
+ volume: -4
64
+ }).connect(snareVerb);
65
+
66
+ // Hi-hat — crisp, short, metallic
67
+ const hat = new Tone.MetalSynth({
68
+ frequency: 500,
69
+ envelope: { attack: 0.001, decay: 0.04, release: 0.01 },
70
+ harmonicity: 5.1,
71
+ modulationIndex: 24,
72
+ resonance: 4000,
73
+ octaves: 1.2,
74
+ volume: -12
75
+ }).toDestination();
76
+
77
+ // Bass — MonoSynth, smooth but defined
78
+ const bass = new Tone.MonoSynth({
79
+ oscillator: { type: "sawtooth" },
80
+ filter: { Q: 2, type: "lowpass", rolloff: -12 },
81
+ filterEnvelope: { attack: 0.01, decay: 0.2, sustain: 0.4, release: 0.3,
82
+ baseFrequency: 120, octaves: 1.5 },
83
+ envelope: { attack: 0.01, decay: 0.15, sustain: 0.7, release: 0.3 },
84
+ volume: -4
85
+ }).toDestination();
86
+
87
+ // Soul pad — warm PolySynth, slow attack = "reverse sample" texture
88
+ const padVerb = new Tone.Reverb({ decay: 3.5, wet: 0.5 }).toDestination();
89
+ const pad = new Tone.PolySynth(Tone.Synth, {
90
+ oscillator: { type: "triangle" },
91
+ envelope: { attack: 0.6, decay: 0.5, sustain: 0.7, release: 2.0 },
92
+ volume: -14
93
+ }).connect(padVerb);
94
+ ```
95
+
96
+ ## Composition Structure
97
+
98
+ - **Bar 1:** Kick + snare + hat only — establish the swung groove, feel the shuffle
99
+ - **Bars 2–4:** Add bass — smooth line following Fm → Cm → Bb → Eb
100
+ - **Bars 5–8:** Add soul pad — Fm7 chord with slow attack, warm
101
+ - **Bars 9–16:** Full groove — all elements, occasionally double the kick for variation
102
+ - **Half-time bar:** Every 4–8 bars, simplify to kick on beat 1 only — creates space then snaps back
103
+
104
+ Dilla technique: vary the kick pattern slightly each 2 bars instead of looping the exact same hit positions. Use a step counter to swap between two kick pattern arrays.
105
+
106
+ ## Example Variations
107
+
108
+ ### 1 — "Dilla" floating kick (pattern alternates every 2 bars)
109
+ ```js
110
+ const kickPatterns = [
111
+ ["C1",null,null,null,null,null,"C1",null,"C1",null,null,null,null,null,null,null],
112
+ ["C1",null,null,null,null,null,null,null,"C1",null,"C1",null,null,null,null,null],
113
+ ];
114
+ let bar = 0;
115
+ new Tone.Sequence((time, val) => {
116
+ if (val) kick.triggerAttackRelease("C1", "8n", time);
117
+ }, kickPatterns[Math.floor(bar++ / 16) % 2], "16n").start(0);
118
+ ```
119
+
120
+ ### 2 — Swing amount variation (lighter shuffle)
121
+ ```js
122
+ // 0.3 = light shuffle (more "straight"), 0.5 = full triplet swing, 0.15 = barely swung
123
+ Tone.Transport.swing = 0.35; // Pete Rock feel — noticeable but not extreme
124
+ ```
125
+
126
+ ### 3 — Open hi-hat accent on beat 4
127
+ ```js
128
+ // Add an open hi-hat (longer decay) on step 12 for groove
129
+ const openHat = new Tone.MetalSynth({ ...hat options..., envelope: { decay: 0.18 } }).toDestination();
130
+ const openHatSeq = new Tone.Sequence((time, val) => {
131
+ if (val) openHat.triggerAttackRelease("8n", time, 0.7);
132
+ }, [null,null,null,null,null,null,null,null,null,null,null,null,1,null,null,null], "16n").start(0);
133
+ ```