tuneframes 0.1.1 → 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 (80) hide show
  1. package/LICENSE +166 -166
  2. package/README.md +158 -55
  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 +47 -47
  11. package/examples/example-lofi.html +45 -45
  12. package/examples/example-lofi.mp3 +0 -0
  13. package/examples/example-minimal.html +20 -20
  14. package/examples/example-orchestral.html +67 -67
  15. package/examples/example-orchestral.mp3 +0 -0
  16. package/examples/example-piano.html +52 -52
  17. package/examples/example-piano.mp3 +0 -0
  18. package/examples/example-techno.html +69 -69
  19. package/examples/example-techno.mp3 +0 -0
  20. package/package.json +42 -37
  21. package/registry/presets/bass-electric.html +67 -0
  22. package/registry/presets/bass-saw.html +22 -0
  23. package/registry/presets/chord-progression.html +22 -0
  24. package/registry/presets/drums-808.html +85 -0
  25. package/registry/presets/drums-lofi.html +35 -0
  26. package/registry/presets/lead-piano.html +26 -0
  27. package/registry/presets/piano-salamander.html +69 -0
  28. package/registry/presets/reverb-warm.html +11 -0
  29. package/registry/samples.json +226 -0
  30. package/skills/audio-ambient/SKILL.md +141 -0
  31. package/skills/audio-ambient/example.html +113 -0
  32. package/skills/audio-boss-battle/SKILL.md +157 -0
  33. package/skills/audio-boss-battle/example.html +185 -0
  34. package/skills/audio-boss-battle/example.mp3 +0 -0
  35. package/skills/audio-chillwave/SKILL.md +142 -0
  36. package/skills/audio-chillwave/example.html +144 -0
  37. package/skills/audio-cinematic/SKILL.md +147 -0
  38. package/skills/audio-cinematic/example.html +123 -0
  39. package/skills/audio-classical/SKILL.md +138 -0
  40. package/skills/audio-classical/example.html +145 -0
  41. package/skills/audio-dnb/SKILL.md +142 -0
  42. package/skills/audio-dnb/example.html +124 -0
  43. package/skills/audio-downtempo/SKILL.md +152 -0
  44. package/skills/audio-downtempo/example.html +164 -0
  45. package/skills/audio-folk/SKILL.md +139 -0
  46. package/skills/audio-folk/example.html +132 -0
  47. package/skills/audio-funk/SKILL.md +149 -0
  48. package/skills/audio-funk/example.html +144 -0
  49. package/skills/audio-future-bass/SKILL.md +163 -0
  50. package/skills/audio-future-bass/example.html +164 -0
  51. package/skills/audio-hip-hop/SKILL.md +133 -0
  52. package/skills/audio-hip-hop/example.html +129 -0
  53. package/skills/audio-house/SKILL.md +147 -0
  54. package/skills/audio-house/example.html +128 -0
  55. package/skills/audio-indie-pop/SKILL.md +150 -0
  56. package/skills/audio-indie-pop/example.html +121 -0
  57. package/skills/audio-jazz/SKILL.md +141 -0
  58. package/skills/audio-jazz/example.html +146 -0
  59. package/skills/audio-lofi/SKILL.md +140 -0
  60. package/skills/audio-lofi/example.html +135 -0
  61. package/skills/audio-minimal/SKILL.md +155 -0
  62. package/skills/audio-minimal/example.html +118 -0
  63. package/skills/audio-orchestral/SKILL.md +156 -0
  64. package/skills/audio-orchestral/example.html +140 -0
  65. package/skills/audio-r-and-b/SKILL.md +134 -0
  66. package/skills/audio-r-and-b/example.html +154 -0
  67. package/skills/audio-r-and-b/example.mp3 +0 -0
  68. package/skills/audio-techno/SKILL.md +140 -0
  69. package/skills/audio-techno/example.html +125 -0
  70. package/skills/audio-trap/SKILL.md +123 -0
  71. package/skills/audio-trap/example.html +119 -0
  72. package/skills/render-retest/example.html +115 -0
  73. package/skills/tuneframes/SKILL.md +221 -0
  74. package/skills/tuneframes-cli/SKILL.md +46 -0
  75. package/skills/verify/example.html +104 -0
  76. package/src/cli.js +260 -151
  77. package/src/render.js +134 -7
  78. package/examples/example-bass.mp3 +0 -0
  79. package/examples/example-demo-beat.wav +0 -0
  80. package/examples/example-orchestral.wav +0 -0
@@ -0,0 +1,140 @@
1
+ <div id="tuneframes" style="display:none">{"bpm":80,"duration":"14s"}</div>
2
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/tone/14.8.49/Tone.js"></script>
3
+ <script>
4
+ // TuneFrames — Orchestral
5
+ // D minor: strings carry melody, brass confirm harmony,
6
+ // woodwinds add color, timpani on downbeats
7
+ // Proper voice leading — each section has a role
8
+
9
+ async function main() {
10
+ await Tone.start();
11
+
12
+ const beat = 60 / 80; // 0.75s per quarter note
13
+ const half = beat * 2; // 1.5s per half note
14
+
15
+ // ── Hall reverb — all orchestral sound happens in a hall ──────────────────
16
+ const reverb = new Tone.Reverb({ decay: 3.5, preDelay: 0.05, wet: 0.7 });
17
+ await reverb.generate();
18
+ reverb.toDestination();
19
+
20
+ // ── STRINGS — PolySynth triangle, slow bow-attack ─────────────────────────
21
+ const strings = new Tone.PolySynth(Tone.Synth, {
22
+ oscillator: { type: 'triangle' },
23
+ envelope: { attack: 0.75, decay: 0.2, sustain: 0.95, release: 1.5 },
24
+ volume: -5,
25
+ });
26
+ strings.connect(reverb);
27
+
28
+ // ── BRASS — PolySynth sawtooth, medium breath-attack ─────────────────────
29
+ const brass = new Tone.PolySynth(Tone.Synth, {
30
+ oscillator: { type: 'sawtooth' },
31
+ envelope: { attack: 0.32, decay: 0.35, sustain: 0.72, release: 1.0 },
32
+ volume: -10,
33
+ });
34
+ brass.connect(reverb);
35
+
36
+ // ── WOODWINDS — AMSynth for reedy, breathy character ─────────────────────
37
+ const woodwinds = new Tone.AMSynth({
38
+ harmonicity: 1.0,
39
+ oscillator: { type: 'triangle' },
40
+ envelope: { attack: 0.14, decay: 0.1, sustain: 0.88, release: 0.6 },
41
+ modulation: { type: 'square' },
42
+ modulationEnvelope: { attack: 0.5, decay: 0.0, sustain: 0.3, release: 0.5 },
43
+ volume: -16,
44
+ });
45
+ woodwinds.connect(reverb);
46
+
47
+ // ── TIMPANI — MembraneSynth, long resonating pitch ───────────────────────
48
+ const timpani = new Tone.MembraneSynth({
49
+ pitchDecay: 0.38, octaves: 5,
50
+ envelope: { attack: 0.001, decay: 1.6, sustain: 0, release: 1.0 },
51
+ volume: -7,
52
+ });
53
+ timpani.connect(reverb);
54
+
55
+ // ─────────────────────────────────────────────────────────────────────────
56
+ // PHRASE 1 (0-6s): Statement — strings introduce D minor melody
57
+ // D minor scale ascending: D E F G A Bb A G
58
+ // ─────────────────────────────────────────────────────────────────────────
59
+
60
+ const phrase1 = [
61
+ { note: 'D4', t: 0 },
62
+ { note: 'E4', t: beat * 0.5 },
63
+ { note: 'F4', t: beat * 1 },
64
+ { note: 'G4', t: beat * 1.5 },
65
+ { note: 'A4', t: beat * 2 },
66
+ { note: 'Bb4', t: beat * 2.5 },
67
+ { note: 'A4', t: beat * 3 },
68
+ { note: 'G4', t: beat * 3.5 },
69
+ ];
70
+ phrase1.forEach(({ note, t }) => strings.triggerAttackRelease(note, '4n', t));
71
+
72
+ // Brass: tonic Dm for 3 beats, then IV (Gm)
73
+ brass.triggerAttackRelease(['D3', 'F3', 'A3'], half, 0);
74
+ brass.triggerAttackRelease(['G2', 'Bb2', 'D3'], half, beat * 3);
75
+
76
+ // Timpani: downbeat on D2
77
+ timpani.triggerAttackRelease('D2', '8n', 0);
78
+
79
+ // ─────────────────────────────────────────────────────────────────────────
80
+ // PHRASE 2 (6-10s): Response — melody rises, woodwinds fill
81
+ // Half-cadence: ends on A major (V chord)
82
+ // ─────────────────────────────────────────────────────────────────────────
83
+
84
+ const p2start = beat * 8; // 6s
85
+
86
+ const phrase2 = [
87
+ { note: 'F4', t: p2start },
88
+ { note: 'A4', t: p2start + beat * 0.5 },
89
+ { note: 'C5', t: p2start + beat * 1 },
90
+ { note: 'D5', t: p2start + beat * 1.5 },
91
+ { note: 'E5', t: p2start + beat * 2 },
92
+ { note: 'F5', t: p2start + beat * 2.5 },
93
+ ];
94
+ phrase2.forEach(({ note, t }) => strings.triggerAttackRelease(note, '4n', t));
95
+
96
+ // Woodwinds: fill inner voices between string notes
97
+ const woodwindNotes = [
98
+ { note: 'A4', t: p2start + beat * 0.25 },
99
+ { note: 'C5', t: p2start + beat * 1.25 },
100
+ { note: 'F4', t: p2start + beat * 2.25 },
101
+ ];
102
+ woodwindNotes.forEach(({ note, t }) => woodwinds.triggerAttackRelease(note, '4n', t));
103
+
104
+ // Brass: IV (Bb) → V (A major) — half cadence
105
+ brass.triggerAttackRelease(['Bb2', 'D3', 'F3'], half, p2start);
106
+ brass.triggerAttackRelease(['A2', 'C#3', 'E3'], half, p2start + beat * 3);
107
+
108
+ timpani.triggerAttackRelease('G2', '8n', p2start);
109
+ timpani.triggerAttackRelease('A2', '8n', p2start + beat * 3);
110
+
111
+ // ─────────────────────────────────────────────────────────────────────────
112
+ // PHRASE 3 (10-14s): Resolution — full cadence I (Dm), all voices converge
113
+ // ─────────────────────────────────────────────────────────────────────────
114
+
115
+ const p3start = p2start + beat * 6; // ~10.5s
116
+
117
+ const phrase3 = [
118
+ { note: 'F5', t: p3start },
119
+ { note: 'E5', t: p3start + beat * 0.5 },
120
+ { note: 'D5', t: p3start + beat * 1 },
121
+ { note: 'C5', t: p3start + beat * 1.5 },
122
+ { note: 'A4', t: p3start + beat * 2 },
123
+ { note: 'F4', t: p3start + beat * 2.5 },
124
+ { note: 'D4', t: p3start + beat * 3 },
125
+ ];
126
+ phrase3.forEach(({ note, t }) => {
127
+ if (t < 14) strings.triggerAttackRelease(note, '4n', t);
128
+ });
129
+
130
+ // Brass: full Dm resolution chord
131
+ brass.triggerAttackRelease(['D3', 'F3', 'A3', 'D4'], beat * 4, p3start);
132
+
133
+ // Woodwinds: hold the 5th above brass
134
+ woodwinds.triggerAttackRelease('F5', beat * 3, p3start);
135
+
136
+ // Timpani: final downbeats on D2
137
+ timpani.triggerAttackRelease('D2', '4n', p3start);
138
+ timpani.triggerAttackRelease('D2', '4n', p3start + beat * 3);
139
+ }
140
+ </script>
@@ -0,0 +1,134 @@
1
+ ---
2
+ name: audio-r-and-b
3
+ description: R&B / Neo-Soul — lush extended chords, smooth Rhodes, laid-back syncopated groove
4
+ ---
5
+
6
+ # TuneFrames — R&B / Neo-Soul
7
+
8
+ ## Genre Profile
9
+ - BPM range: 70–95 (the groove breathes; never rushed)
10
+ - Key characteristics: Extended chord voicings (min9, maj9, add9, 11ths), Rhodes/electric piano feel, laid-back beat placement (drums sit just behind the grid), syncopated bass that locks with the kick, gentle compression on everything
11
+ - Typical instruments: Rhodes (PolySynth triangle), warm bass (Synth sine), soft kick (MembraneSynth), brush snare (NoiseSynth), 8th hi-hats with occasional 16th fills, optional synth pad underneath
12
+ - Mood: Warm, sensual, introspective, polished — D'Angelo, H.E.R., Frank Ocean, Erykah Badu, Sade
13
+
14
+ ## Core Pattern
15
+
16
+ ```js
17
+ // Neo-Soul core: 85 BPM, Fm9–Dbmaj9–Ab–Eb progression
18
+ async function main() {
19
+ await Tone.start();
20
+ Tone.Transport.bpm.value = 85;
21
+
22
+ const bar = Tone.Time('1n').toSeconds();
23
+ const q = Tone.Time('4n').toSeconds();
24
+ const s8 = Tone.Time('8n').toSeconds();
25
+
26
+ // ── Warm compression + reverb ─────────────────────────────────────────
27
+ const comp = new Tone.Compressor({ threshold: -20, ratio: 3, attack: 0.01, release: 0.2 }).toDestination();
28
+ const reverb = new Tone.Reverb({ decay: 2.5, preDelay: 0.01, wet: 0.35 }).connect(comp);
29
+
30
+ // ── Rhodes — extended voicings ────────────────────────────────────────
31
+ const rhodes = new Tone.PolySynth(Tone.Synth, {
32
+ oscillator: { type: 'triangle' },
33
+ envelope: { attack: 0.03, decay: 0.5, sustain: 0.6, release: 2.0 }
34
+ }).connect(reverb);
35
+ rhodes.volume.value = -10;
36
+
37
+ // Fm9 – Dbmaj9 – Ab – Eb (rich neo-soul changes)
38
+ const chords = [
39
+ ['F3','Ab3','C4','Eb4','G4'], // Fm9
40
+ ['Db3','F3','Ab3','C4','Eb4'], // Dbmaj9
41
+ ['Ab2','C3','Eb3','G3'], // Ab maj7
42
+ ['Eb3','G3','Bb3','D4'], // Ebmaj7
43
+ ];
44
+ chords.forEach((ch, i) => rhodes.triggerAttackRelease(ch, '1n', i * bar));
45
+
46
+ // ── Syncopated bass ───────────────────────────────────────────────────
47
+ const bass = new Tone.Synth({
48
+ oscillator: { type: 'sine' },
49
+ envelope: { attack: 0.015, decay: 0.15, sustain: 0.5, release: 0.3 }
50
+ }).connect(comp);
51
+ bass.volume.value = -7;
52
+
53
+ // Root on 1, then syncopated hits — lands a 16th early on beat 3
54
+ const bassLine = [
55
+ { note: 'F2', time: 0 },
56
+ { note: 'F2', time: q * 1.75 }, // 16th before beat 3
57
+ { note: 'Eb2', time: q * 3 },
58
+ ];
59
+ bassLine.forEach(({ note, time }) => bass.triggerAttackRelease(note, '8n', time));
60
+ }
61
+ ```
62
+
63
+ ## Instrument Configuration
64
+
65
+ ```js
66
+ // Rhodes feel — triangle wave, moderate attack, long release
67
+ const rhodes = new Tone.PolySynth(Tone.Synth, {
68
+ oscillator: { type: 'triangle' },
69
+ envelope: { attack: 0.03, decay: 0.5, sustain: 0.6, release: 2.0 }
70
+ });
71
+
72
+ // Warm bass — sine, slightly longer attack than funk (more laid-back)
73
+ const bass = new Tone.Synth({
74
+ oscillator: { type: 'sine' },
75
+ envelope: { attack: 0.015, decay: 0.15, sustain: 0.5, release: 0.3 }
76
+ });
77
+
78
+ // Pad underneath — very slow attack, barely audible, adds warmth
79
+ const pad = new Tone.PolySynth(Tone.Synth, {
80
+ oscillator: { type: 'sine' },
81
+ envelope: { attack: 2.0, decay: 0.5, sustain: 0.8, release: 4.0 }
82
+ });
83
+ pad.volume.value = -22; // subtle, under everything
84
+
85
+ // Chorus on the Rhodes for that electric piano shimmer
86
+ const chorus = new Tone.Chorus({ frequency: 1.5, delayTime: 3.5, depth: 0.4, wet: 0.5 });
87
+ chorus.start();
88
+
89
+ // Gentle compression — glues without pumping
90
+ const comp = new Tone.Compressor({ threshold: -20, ratio: 3, attack: 0.01, release: 0.2 });
91
+
92
+ // Chain: rhodes → chorus → reverb → comp → destination
93
+ const reverb = new Tone.Reverb({ decay: 2.5, wet: 0.35 });
94
+ rhodes.connect(chorus);
95
+ chorus.connect(reverb);
96
+ reverb.connect(comp);
97
+ comp.toDestination();
98
+ ```
99
+
100
+ ## Composition Structure
101
+
102
+ 1. **Intro (0–3s):** Rhodes alone with pad underneath — establish the lush harmonic world
103
+ 2. **Bass enters (3–6s):** Syncopated bass locks with the root, still no drums
104
+ 3. **Drums drop (6–9s):** Soft kick on 1 and 3, snare on 2 and 4, 8th hats — laid-back, never aggressive
105
+ 4. **Melody/hook (9–12s):** High Rhodes or separate synth carries a smooth melodic phrase
106
+ 5. **Outro:** Strip back to Rhodes + pad, let the chord voicings breathe and decay
107
+
108
+ ## Example Variations
109
+
110
+ ### 1 — D'Angelo "Voodoo" feel (heavy laid-back drums)
111
+ ```js
112
+ // Drums sit 20ms behind the grid — schedule everything slightly late
113
+ const LAG = 0.02; // seconds
114
+ kick.triggerAttackRelease('C1', '8n', 0 + LAG);
115
+ snare.triggerAttackRelease('8n', q + LAG);
116
+ ```
117
+
118
+ ### 2 — Sade-style sparse ballad (60 BPM, less is more)
119
+ ```js
120
+ Tone.Transport.bpm.value = 60;
121
+ // Just Rhodes + bass, no drums, add a gentle delay on the melody
122
+ const delay = new Tone.FeedbackDelay({ delayTime: '4n', feedback: 0.2, wet: 0.25 }).connect(reverb);
123
+ ```
124
+
125
+ ### 3 — Neo-soul key change (drop a half-step on bar 3)
126
+ ```js
127
+ // Modulate from Fm to Em for bar 3 — creates emotional lift/tension
128
+ const chordsWithMod = [
129
+ ['F3','Ab3','C4','Eb4','G4'], // Fm9
130
+ ['Db3','F3','Ab3','C4','Eb4'], // Dbmaj9
131
+ ['E3','G3','B3','D4','F#4'], // Em9 (half-step down = brighter surprise)
132
+ ['C3','E3','G3','B3'], // Cmaj7
133
+ ];
134
+ ```
@@ -0,0 +1,154 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>TuneFrames — R&amp;B / Neo-Soul</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":86,"duration":"12s"}</div>
9
+ <script>
10
+ async function main() {
11
+ await Tone.start();
12
+ Tone.Transport.bpm.value = 86;
13
+
14
+ const bar = Tone.Time('1n').toSeconds(); // ~2.79s
15
+ const q = Tone.Time('4n').toSeconds(); // ~0.698s
16
+ const s8 = Tone.Time('8n').toSeconds(); // ~0.349s
17
+ const s16 = Tone.Time('16n').toSeconds();
18
+
19
+ // ── Signal chain: everything → comp → destination ────────────────────
20
+ const comp = new Tone.Compressor({ threshold: -20, ratio: 3, attack: 0.008, release: 0.18 }).toDestination();
21
+ const reverb = new Tone.Freeverb({ roomSize: 0.72, dampening: 3500, wet: 0.38 }).connect(comp);
22
+
23
+ // ── Pad underneath (barely audible warmth) ───────────────────────────
24
+ const pad = new Tone.PolySynth(Tone.Synth, {
25
+ oscillator: { type: 'sine' },
26
+ envelope: { attack: 2.2, decay: 0.5, sustain: 0.85, release: 5.0 }
27
+ }).connect(reverb);
28
+ pad.volume.value = -24;
29
+
30
+ // Hold the tonic throughout
31
+ pad.triggerAttackRelease(['F2','C3','Eb3'], '2n', 0);
32
+ pad.triggerAttackRelease(['Db2','Ab2','C3'], '2n', bar);
33
+ pad.triggerAttackRelease(['Ab2','Eb3','G3'], '2n', bar * 2);
34
+ pad.triggerAttackRelease(['Eb2','Bb2','D3'], '2n', bar * 3);
35
+
36
+ // ── Rhodes — chorus shimmer + reverb ────────────────────────────────
37
+ const chorus = new Tone.Chorus({ frequency: 1.5, delayTime: 3.5, depth: 0.4, wet: 0.45 }).connect(reverb);
38
+ chorus.start();
39
+ const rhodes = new Tone.PolySynth(Tone.Synth, {
40
+ oscillator: { type: 'triangle' },
41
+ envelope: { attack: 0.025, decay: 0.5, sustain: 0.62, release: 2.2 }
42
+ }).connect(chorus);
43
+ rhodes.volume.value = -9;
44
+
45
+ // Fm9 – Dbmaj9 – Abmaj7 – Ebmaj7 (4-bar loop × 2 passes + variation)
46
+ const changes = [
47
+ { chord: ['F3','Ab3','C4','Eb4','G4'], time: 0 }, // Fm9
48
+ { chord: ['Db3','F3','Ab3','C4','Eb4'], time: bar }, // Dbmaj9
49
+ { chord: ['Ab2','Eb3','G3','C4'], time: bar * 2 }, // Abmaj7
50
+ { chord: ['Eb3','G3','Bb3','D4'], time: bar * 3 }, // Ebmaj7
51
+ // Second pass with richer upper voicing
52
+ { chord: ['F3','Ab3','C4','G4'], time: bar * 4 }, // Fm add9
53
+ { chord: ['Db3','Ab3','C4','F4'], time: bar * 4 + bar }, // Dbmaj9/Ab
54
+ ];
55
+ changes.forEach(({ chord, time }) => rhodes.triggerAttackRelease(chord, '1n', time));
56
+
57
+ // ── Warm syncopated bass ─────────────────────────────────────────────
58
+ const bass = new Tone.Synth({
59
+ oscillator: { type: 'sine' },
60
+ envelope: { attack: 0.014, decay: 0.18, sustain: 0.48, release: 0.28 }
61
+ }).connect(comp);
62
+ bass.volume.value = -5;
63
+
64
+ // Neo-soul bass: root on 1, anticipation (16th early) into beat 3, fill at end
65
+ const bassPattern = (root, fifth, t) => [
66
+ { note: root, time: t }, // beat 1
67
+ { note: root, time: t + q + s16 }, // "and-a" of beat 2 (anticipates 3)
68
+ { note: fifth, time: t + q * 2 }, // beat 3
69
+ { note: root, time: t + q * 3 + s16 * 2 }, // syncopated fill before bar end
70
+ ];
71
+
72
+ [
73
+ ['F2', 'C3', 0 ],
74
+ ['Db2', 'Ab2', bar ],
75
+ ['Ab1', 'Eb2', bar * 2 ],
76
+ ['Eb2', 'Bb2', bar * 3 ],
77
+ ['F2', 'C3', bar * 4 ],
78
+ ['Db2', 'Ab2', bar * 4 + bar],
79
+ ].forEach(([root, fifth, t]) => {
80
+ bassPattern(root, fifth, t).forEach(({ note, time }) =>
81
+ bass.triggerAttackRelease(note, '8n', time));
82
+ });
83
+
84
+ // ── Kick (soft, beat 1 and 3) ────────────────────────────────────────
85
+ const kick = new Tone.MembraneSynth({
86
+ pitchDecay: 0.055, octaves: 5,
87
+ envelope: { attack: 0.001, decay: 0.35, sustain: 0, release: 0.3 }
88
+ }).connect(comp);
89
+ kick.volume.value = -14;
90
+
91
+ // Kicks enter on bar 2 (let Rhodes establish first)
92
+ for (let rep = 1; rep < 5; rep++) {
93
+ kick.triggerAttackRelease('C1', '8n', rep * bar); // beat 1
94
+ kick.triggerAttackRelease('C1', '8n', rep * bar + q * 2); // beat 3
95
+ // Syncopated ghost kick on the "and" of 4 every other bar
96
+ if (rep % 2 === 0) kick.triggerAttackRelease('C1', '8n', rep * bar + q * 3.5);
97
+ }
98
+
99
+ // ── Brush snare on 2 and 4 ──────────────────────────────────────────
100
+ const snareBp = new Tone.Filter(2600, 'bandpass').connect(reverb);
101
+ const snare = new Tone.NoiseSynth({
102
+ noise: { type: 'white' },
103
+ envelope: { attack: 0.003, decay: 0.13, sustain: 0, release: 0.06 }
104
+ }).connect(snareBp);
105
+ snare.volume.value = -20;
106
+
107
+ for (let rep = 1; rep < 5; rep++) {
108
+ snare.triggerAttackRelease('8n', rep * bar + q); // beat 2
109
+ snare.triggerAttackRelease('8n', rep * bar + q * 3); // beat 4
110
+ }
111
+
112
+ // ── Hi-hats: 8ths with 16th fill before beat 3 ──────────────────────
113
+ const hat = new Tone.MetalSynth({
114
+ frequency: 500, harmonicity: 5.1, modulationIndex: 24,
115
+ resonance: 4000, octaves: 1.5,
116
+ envelope: { attack: 0.001, decay: 0.05, release: 0.01 }
117
+ }).connect(reverb);
118
+ hat.volume.value = -24;
119
+
120
+ for (let rep = 1; rep < 5; rep++) {
121
+ // Regular 8th notes
122
+ for (let i = 0; i < 8; i++) hat.triggerAttackRelease('16n', rep * bar + i * s8);
123
+ // 16th-note fill going into beat 3 (soul fill)
124
+ hat.triggerAttackRelease('16n', rep * bar + q * 2 - s16 * 2);
125
+ hat.triggerAttackRelease('16n', rep * bar + q * 2 - s16);
126
+ }
127
+
128
+ // ── Melody (enters bar 3) — smooth Rhodes phrase ─────────────────────
129
+ const melDelay = new Tone.FeedbackDelay({ delayTime: '8n', feedback: 0.18, wet: 0.22 }).connect(reverb);
130
+ const melody = new Tone.Synth({
131
+ oscillator: { type: 'triangle' },
132
+ envelope: { attack: 0.04, decay: 0.35, sustain: 0.5, release: 1.5 }
133
+ }).connect(melDelay);
134
+ melody.volume.value = -13;
135
+
136
+ // Silky descending/ascending phrase — Fm pentatonic flavour
137
+ const phrase = [
138
+ { note: 'C5', time: bar * 2, dur: '8n' },
139
+ { note: 'Ab4', time: bar * 2 + s8, dur: '8n' },
140
+ { note: 'G4', time: bar * 2 + s8*2, dur: '4n' },
141
+ { note: 'Eb4', time: bar * 2 + s8*4, dur: '8n' },
142
+ { note: 'F4', time: bar * 2 + s8*5, dur: '4n.' },
143
+ { note: 'G4', time: bar * 3 + q, dur: '8n' },
144
+ { note: 'Ab4', time: bar * 3 + q + s8, dur: '8n' },
145
+ { note: 'C5', time: bar * 3 + q*2, dur: '2n' },
146
+ { note: 'Bb4', time: bar * 4 + s8, dur: '4n' },
147
+ { note: 'Ab4', time: bar * 4 + s8*3, dur: '4n' },
148
+ { note: 'G4', time: bar * 4 + s8*5, dur: '2n' },
149
+ ];
150
+ phrase.forEach(({ note, time, dur }) => melody.triggerAttackRelease(note, dur, time));
151
+ }
152
+ </script>
153
+ </body>
154
+ </html>
Binary file
@@ -0,0 +1,140 @@
1
+ ---
2
+ name: audio-techno
3
+ description: Berlin-style techno — hard MembraneSynth kick, acid MonoSynth bass, industrial hi-hats, sparse stabs. Dark and mechanical.
4
+ ---
5
+
6
+ # TuneFrames — Techno
7
+
8
+ ## Genre Profile
9
+ - BPM range: 130–145
10
+ - Key characteristics: Hard kick on every beat, relentless forward momentum, hypnotic repetition, industrial textures, minimal melody
11
+ - Typical instruments: MembraneSynth (kick), MonoSynth (acid bass), MetalSynth or NoiseSynth (hi-hats), PolySynth (sparse stabs)
12
+ - Mood: Dark, mechanical, hypnotic, relentless
13
+
14
+ ## Core Pattern
15
+
16
+ ```js
17
+ // Berlin Techno — 4/4 at 136 BPM
18
+ // Kick on every beat (4-on-the-floor)
19
+ // Acid bass follows kick with filter sweep
20
+ // Hi-hats: closed on 8ths, open on off-beats
21
+ // Stabs: sparse, dissonant, 2-bar cycle
22
+
23
+ const kick = new Tone.MembraneSynth({
24
+ pitchDecay: 0.08,
25
+ octaves: 10,
26
+ envelope: { attack: 0.001, decay: 0.4, sustain: 0, release: 0.1 }
27
+ }).toDestination();
28
+
29
+ // Acid bass through distortion
30
+ const dist = new Tone.Distortion(0.6).toDestination();
31
+ const bass = new Tone.MonoSynth({
32
+ oscillator: { type: "sawtooth" },
33
+ filter: { Q: 6, type: "lowpass", rolloff: -24 },
34
+ filterEnvelope: {
35
+ attack: 0.001, decay: 0.2, sustain: 0.3, release: 0.5,
36
+ baseFrequency: 80, octaves: 4
37
+ },
38
+ envelope: { attack: 0.001, decay: 0.3, sustain: 0.4, release: 0.2 }
39
+ }).connect(dist);
40
+
41
+ // Industrial closed hi-hat
42
+ const hat = new Tone.MetalSynth({
43
+ frequency: 400, envelope: { attack: 0.001, decay: 0.04, release: 0.01 },
44
+ harmonicity: 5.1, modulationIndex: 32, resonance: 4000, octaves: 1.5
45
+ }).toDestination();
46
+
47
+ // Scheduling — 1-bar loop
48
+ new Tone.Sequence((time, note) => {
49
+ kick.triggerAttackRelease("C1", "8n", time);
50
+ }, ["C1", null, null, null, "C1", null, null, null,
51
+ "C1", null, null, null, "C1", null, null, null], "16n").start(0);
52
+
53
+ new Tone.Sequence((time, note) => {
54
+ if (note) hat.triggerAttackRelease("16n", time, note);
55
+ }, [0.7, 0.4, 0.7, 0.4, 0.7, 0.4, 0.9, 0.4,
56
+ 0.7, 0.4, 0.7, 0.4, 0.7, 0.5, 0.9, 0.6], "16n").start(0);
57
+
58
+ Tone.Transport.bpm.value = 136;
59
+ Tone.Transport.start();
60
+ ```
61
+
62
+ ## Instrument Configuration
63
+
64
+ ```js
65
+ // Kick — punchy, sub-heavy membrane
66
+ const kick = new Tone.MembraneSynth({
67
+ pitchDecay: 0.06,
68
+ octaves: 10,
69
+ volume: 2,
70
+ envelope: { attack: 0.001, decay: 0.35, sustain: 0, release: 0.1 }
71
+ }).toDestination();
72
+
73
+ // Acid bass — sawtooth through distortion + filter
74
+ const limiter = new Tone.Limiter(-3).toDestination();
75
+ const dist = new Tone.Distortion({ distortion: 0.5, wet: 0.8 }).connect(limiter);
76
+ const bass = new Tone.MonoSynth({
77
+ oscillator: { type: "sawtooth" },
78
+ filter: { Q: 8, type: "lowpass", rolloff: -24 },
79
+ filterEnvelope: {
80
+ attack: 0.002, decay: 0.3, sustain: 0.2, release: 0.6,
81
+ baseFrequency: 60, octaves: 3.5
82
+ },
83
+ envelope: { attack: 0.001, decay: 0.2, sustain: 0.5, release: 0.3 },
84
+ volume: -4
85
+ }).connect(dist);
86
+
87
+ // Hi-hat — metallic, tight
88
+ const hat = new Tone.MetalSynth({
89
+ frequency: 380, harmonicity: 5.1, modulationIndex: 32,
90
+ resonance: 4000, octaves: 1.5,
91
+ envelope: { attack: 0.001, decay: 0.05, release: 0.01 },
92
+ volume: -8
93
+ }).toDestination();
94
+
95
+ // Stab — cold PolySynth, short decay
96
+ const reverb = new Tone.Reverb({ decay: 1.5, wet: 0.3 }).toDestination();
97
+ const stab = new Tone.PolySynth(Tone.Synth, {
98
+ oscillator: { type: "square" },
99
+ envelope: { attack: 0.001, decay: 0.15, sustain: 0, release: 0.1 },
100
+ volume: -10
101
+ }).connect(reverb);
102
+ ```
103
+
104
+ ## Composition Structure
105
+
106
+ - **Bar 1-2:** Kick only — establish the pulse
107
+ - **Bar 3-4:** Add hi-hats — density builds
108
+ - **Bar 5-8:** Add acid bass — filter opens over 4 bars (automation)
109
+ - **Bar 9-16:** Full loop — kick + hats + bass + sparse stabs every 2 bars
110
+ - **Bar 17+:** Variation — mute elements in/out for tension/release
111
+ - **Breakdown:** Drop kick, keep hats, let bass filter sweep down — then kick re-enters hard
112
+ - **Outro:** Strip back to kick only, fade hats
113
+
114
+ Key technique: filter automation on the bass is the main expressive tool. Sweep `bass.filter.frequency` from 80Hz up to 2kHz over 8 bars, then drop back.
115
+
116
+ ## Example Variations
117
+
118
+ ### 1 — Stutter Kick (double kick on last 16th)
119
+ ```js
120
+ // Standard 4-on-floor with double hit before the beat
121
+ const kickPattern = ["C1", null, null, null, "C1", null, null, null,
122
+ "C1", null, null, null, "C1", null, "C1", null];
123
+ ```
124
+
125
+ ### 2 — Acid Filter Sweep (automation)
126
+ ```js
127
+ // Automate bass filter opening over 2 bars
128
+ const now = Tone.now();
129
+ bass.filter.frequency.setValueAtTime(80, now);
130
+ bass.filter.frequency.linearRampToValueAtTime(3000, now + 4);
131
+ bass.filter.frequency.linearRampToValueAtTime(120, now + 4.5);
132
+ ```
133
+
134
+ ### 3 — Ride + Open Hat Pattern
135
+ ```js
136
+ // More complex hat pattern: closed-closed-open on the off
137
+ const hatVelocities = [0.8, 0.3, 0.8, 0.3, 0.8, 0.3, 1.0, 0.2,
138
+ 0.8, 0.3, 0.8, 0.3, 0.8, 0.4, 1.0, 0.5];
139
+ // Longer decay on accented hits for "open hat" feel
140
+ ```