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,123 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>TuneFrames — Cinematic Score</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":72,"duration":"15s"}</div>
9
+ <script>
10
+ async function main() {
11
+ await Tone.start();
12
+ Tone.Transport.bpm.value = 72;
13
+
14
+ const bar = Tone.Time('1n').toSeconds(); // ~3.33s per bar at 72 BPM
15
+ const q = Tone.Time('4n').toSeconds(); // ~0.83s per beat
16
+
17
+ // ── Reverb halls ─────────────────────────────────────────────────────
18
+ const hall = new Tone.Reverb({ decay: 7, preDelay: 0.06, wet: 0.65 });
19
+ const room = new Tone.Reverb({ decay: 3, preDelay: 0.01, wet: 0.35 });
20
+ // Await IR generation before offline rendering begins — required in Tone.Offline
21
+ await Promise.all([hall.ready, room.ready]);
22
+ hall.toDestination();
23
+ room.toDestination();
24
+
25
+ // ── Choir pad (enters immediately, very soft) ─────────────────────────
26
+ const choir = new Tone.PolySynth(Tone.Synth, {
27
+ oscillator: { type: 'sine' },
28
+ envelope: { attack: 2.8, decay: 0.4, sustain: 0.85, release: 6.0 }
29
+ }).connect(hall);
30
+ choir.volume.value = -22;
31
+
32
+ // Dm open fifth — ethereal, thin, creates space
33
+ choir.triggerAttackRelease(['D3','A3'], '2n', 0);
34
+
35
+ // ── Strings — slow attack swell ──────────────────────────────────────
36
+ const strings = new Tone.PolySynth(Tone.Synth, {
37
+ oscillator: { type: 'sawtooth' },
38
+ envelope: { attack: 2.0, decay: 0.5, sustain: 0.85, release: 5.0 }
39
+ }).connect(hall);
40
+ strings.volume.value = -16;
41
+
42
+ // Dm – Bb – F – C (the cinematic minor-to-relative-major arc)
43
+ const prog = [
44
+ ['D3','F3','A3','D4'], // Dm (bar 1)
45
+ ['Bb2','D3','F3','Bb3'], // Bb (bar 2)
46
+ ['F2','C3','F3','A3'], // F (bar 3)
47
+ ['C3','G3','C4','E4'], // C (bar 4)
48
+ ];
49
+ prog.forEach((ch, i) => strings.triggerAttackRelease(ch, '1n', i * bar));
50
+
51
+ // ── Cello ostinato (enters bar 2 — adds forward motion) ──────────────
52
+ const cello = new Tone.Synth({
53
+ oscillator: { type: 'sawtooth' },
54
+ envelope: { attack: 0.12, decay: 0.2, sustain: 0.7, release: 0.8 }
55
+ }).connect(hall);
56
+ cello.volume.value = -18;
57
+
58
+ // D–A–D pattern driving through bars 2–4
59
+ const ostinato = ['D3','A3','D3','A3','D3','A3','D3','F3'];
60
+ ostinato.forEach((n, i) => cello.triggerAttackRelease(n, '8n', bar + i * (q * 0.5)));
61
+
62
+ const ostinato2 = ['Bb2','F3','Bb2','F3','Bb2','F3','C3','G3'];
63
+ ostinato2.forEach((n, i) => cello.triggerAttackRelease(n, '8n', bar * 2 + i * (q * 0.5)));
64
+
65
+ const ostinato3 = ['F2','C3','F3','C3','F2','C3','G2','C3'];
66
+ ostinato3.forEach((n, i) => cello.triggerAttackRelease(n, '8n', bar * 3 + i * (q * 0.5)));
67
+
68
+ // ── Low piano (enters bar 1, punctuates downbeats) ───────────────────
69
+ const piano = new Tone.Synth({
70
+ oscillator: { type: 'sine' },
71
+ envelope: { attack: 0.01, decay: 1.2, sustain: 0.1, release: 2.0 }
72
+ }).connect(room);
73
+ piano.volume.value = -14;
74
+
75
+ piano.triggerAttackRelease('D2', '2n', 0);
76
+ piano.triggerAttackRelease('Bb1', '2n', bar);
77
+ piano.triggerAttackRelease('F1', '2n', bar * 2);
78
+ piano.triggerAttackRelease('C2', '2n', bar * 3);
79
+
80
+ // ── Yearning solo melody (enters bar 2, high register) ───────────────
81
+ const solo = new Tone.Synth({
82
+ oscillator: { type: 'sine' },
83
+ envelope: { attack: 0.35, decay: 0.3, sustain: 0.85, release: 2.5 }
84
+ }).connect(hall);
85
+ solo.volume.value = -14;
86
+
87
+ // Morricone-style descending phrase: D5–C5–Bb4–A4–F4–A4
88
+ const soloPhrase = [
89
+ { note: 'D5', time: bar * 1.5, dur: '4n' },
90
+ { note: 'C5', time: bar * 1.5 + q, dur: '4n' },
91
+ { note: 'Bb4', time: bar * 1.5 + q*2, dur: '2n' },
92
+ { note: 'A4', time: bar * 2.5, dur: '4n' },
93
+ { note: 'F4', time: bar * 2.5 + q, dur: '4n' },
94
+ { note: 'A4', time: bar * 2.5 + q*2, dur: '4n' },
95
+ { note: 'D5', time: bar * 3, dur: '2n.' },
96
+ { note: 'C5', time: bar * 3.75, dur: '4n' },
97
+ ];
98
+ soloPhrase.forEach(({ note, time, dur }) => solo.triggerAttackRelease(note, dur, time));
99
+
100
+ // ── Brass swell (enters bar 3 — the climax) ──────────────────────────
101
+ const brass = new Tone.PolySynth(Tone.Synth, {
102
+ oscillator: { type: 'sawtooth' },
103
+ envelope: { attack: 0.5, decay: 0.3, sustain: 0.85, release: 3.0 }
104
+ }).connect(hall);
105
+ brass.volume.value = -20;
106
+
107
+ brass.triggerAttackRelease(['F3','A3','C4','F4'], '2n', bar * 2);
108
+ brass.triggerAttackRelease(['C3','G3','C4','E4'], '1n', bar * 3);
109
+
110
+ // ── Timpani — dramatic hits on bars 3 and 4 ──────────────────────────
111
+ const timp = new Tone.MembraneSynth({
112
+ pitchDecay: 0.1, octaves: 6,
113
+ envelope: { attack: 0.001, decay: 1.5, sustain: 0, release: 2.5 }
114
+ }).connect(hall);
115
+ timp.volume.value = -8;
116
+
117
+ timp.triggerAttackRelease('F1', '4n', bar * 2);
118
+ timp.triggerAttackRelease('D1', '4n', bar * 3);
119
+ timp.triggerAttackRelease('C1', '4n', bar * 3 + q * 2);
120
+ }
121
+ </script>
122
+ </body>
123
+ </html>
@@ -0,0 +1,138 @@
1
+ ---
2
+ name: audio-classical
3
+ description: Classical solo piano — left hand Alberti bass or broken chords, right hand melody with ornaments, no effects beyond room reverb
4
+ ---
5
+
6
+ # TuneFrames — Classical Piano
7
+
8
+ ## Genre Profile
9
+ - BPM range: 80-140 (Allegro for Mozart, Andante for slow movements)
10
+ - Key characteristics: Alberti bass in left hand (bass-chord-chord pattern), melodic right hand in single notes or octaves, voice leading between the two hands, harmonic rhythm changes every half or full bar
11
+ - Typical instruments: Tone.Synth with triangle oscillator (cleanest piano approximation), slight room reverb only
12
+ - Mood: elegant, structured, emotionally direct, intellectually clear
13
+
14
+ ## Core Pattern
15
+
16
+ ```js
17
+ // Classical piano: right hand melody over left hand Alberti bass
18
+ // Key = C major, BPM = 104 (Allegro moderato)
19
+ // Alberti bass = bass note → inner chord → upper chord, repeating 8th notes
20
+ Tone.Transport.bpm.value = 104;
21
+
22
+ // Piano synth — triangle wave with tight envelope
23
+ const piano = new Tone.Synth({
24
+ oscillator: { type: 'triangle' },
25
+ envelope: { attack: 0.008, decay: 0.3, sustain: 0.2, release: 1.2 },
26
+ volume: -6,
27
+ });
28
+
29
+ // Gentle room reverb only
30
+ const reverb = new Tone.Reverb({ decay: 1.2, preDelay: 0.01, wet: 0.25 });
31
+ await reverb.generate();
32
+ reverb.toDestination();
33
+ piano.connect(reverb);
34
+
35
+ // A second instance for left hand (allows simultaneous notes)
36
+ const pianoL = new Tone.Synth({
37
+ oscillator: { type: 'triangle' },
38
+ envelope: { attack: 0.008, decay: 0.4, sustain: 0.15, release: 1.0 },
39
+ volume: -10, // left hand slightly quieter
40
+ });
41
+ pianoL.connect(reverb);
42
+
43
+ // RIGHT HAND: C major scale as 8th-note melody (C D E F G F E D)
44
+ const rhNotes = ['C5','D5','E5','F5','G5','F5','E5','D5'];
45
+ const rhTimes = [0, 0.29, 0.57, 0.86, 1.15, 1.44, 1.73, 2.02]; // 8th notes at 104 BPM
46
+ rhNotes.forEach((note, i) => {
47
+ Tone.Transport.scheduleOnce(time => {
48
+ piano.triggerAttackRelease(note, '8n', time);
49
+ }, rhTimes[i]);
50
+ });
51
+
52
+ // LEFT HAND: Alberti bass on C major chord (C3 → E3 → G3 repeating)
53
+ // Pattern: C3, G3, E3, G3 (bass → upper → inner → upper)
54
+ const lhPattern = ['C3','G3','E3','G3', 'F2','A2','F2','A2'];
55
+ lhPattern.forEach((note, i) => {
56
+ Tone.Transport.scheduleOnce(time => {
57
+ pianoL.triggerAttackRelease(note, '8n', time);
58
+ }, i * 0.29); // 8th note spacing at 104 BPM
59
+ });
60
+ ```
61
+
62
+ ## Instrument Configuration
63
+
64
+ ```js
65
+ // Piano approximation — triangle + tight decay, slight room
66
+ // Two instances: right hand (melody) and left hand (accompaniment)
67
+
68
+ // Room reverb — small, not a concert hall
69
+ const reverb = new Tone.Reverb({ decay: 1.1, preDelay: 0.008, wet: 0.22 });
70
+ await reverb.generate();
71
+ reverb.toDestination();
72
+
73
+ // Right hand — melody voice, slightly brighter
74
+ const rh = new Tone.Synth({
75
+ oscillator: { type: 'triangle' },
76
+ envelope: { attack: 0.006, decay: 0.25, sustain: 0.15, release: 1.4 },
77
+ volume: -4,
78
+ }).connect(reverb);
79
+
80
+ // Left hand — accompaniment, slightly softer and darker
81
+ const lh = new Tone.Synth({
82
+ oscillator: { type: 'triangle' },
83
+ envelope: { attack: 0.01, decay: 0.4, sustain: 0.1, release: 1.0 },
84
+ volume: -9,
85
+ }).connect(reverb);
86
+
87
+ // For chords in the left hand, use PolySynth
88
+ const lhChord = new Tone.PolySynth(Tone.Synth, {
89
+ oscillator: { type: 'triangle' },
90
+ envelope: { attack: 0.01, decay: 0.35, sustain: 0.15, release: 1.2 },
91
+ volume: -11,
92
+ }).connect(reverb);
93
+ ```
94
+
95
+ ## Composition Structure
96
+
97
+ **Classical follows phrase structure — typically 4-bar or 8-bar phrases:**
98
+
99
+ 1. **Antecedent phrase (0-4s):** Opening melody in right hand. Left hand Alberti bass on I chord (tonic). Ends on V (half cadence — tension).
100
+ 2. **Consequent phrase (4-8s):** Melody continues or develops. Left hand harmonic progression I→IV→V→I. Ends on I (full cadence — resolution).
101
+ 3. **Middle section / contrast (8-12s):** Move to relative minor or vi. Melody gets more chromatic or ornamental. Left hand may switch from Alberti to block chords.
102
+ 4. **Return (12s+):** Return to opening material. Final cadence: IV→V→I.
103
+
104
+ **Alberti bass pattern at any BPM:**
105
+ - Bass note (lowest note of chord) → Upper note → Middle note → Upper note
106
+ - Repeat for each 8th note subdivision
107
+ - C major: C3 → G3 → E3 → G3
108
+ - F major: F2 → C3 → A2 → C3
109
+ - G major: G2 → D3 → B2 → D3
110
+
111
+ ## Example Variations
112
+
113
+ ### Variation 1: Slow movement (Andante cantabile)
114
+ ```js
115
+ Tone.Transport.bpm.value = 72;
116
+ // Right hand: long notes (quarter and half notes) — singable melody
117
+ // Left hand: broken octaves instead of Alberti — just bass + high octave alternating
118
+ // Reverb slightly wetter: 0.35 — feels more intimate
119
+ // Envelope release: 2.0 — notes ring longer
120
+ ```
121
+
122
+ ### Variation 2: Fast passage work (Allegro vivace)
123
+ ```js
124
+ Tone.Transport.bpm.value = 132;
125
+ // Right hand: 16th-note scalar run (C major scale, 2 octaves up and down)
126
+ // Left hand: block chords on beats 1 and 3 only (not Alberti — too busy)
127
+ // Use PolySynth for left hand chords: ['C3','E3','G3'], ['G2','B2','D3'], etc.
128
+ // Shorter release: 0.6 — crisp, not muddy at fast tempo
129
+ ```
130
+
131
+ ### Variation 3: Ornamental turn
132
+ ```js
133
+ // Right hand melody includes a trill approximation
134
+ // Instead of one quarter note on E5, play: E5, F5, E5, D5, E5 as 32nd notes
135
+ // Schedule these rapid notes as very short triggerAttackRelease calls
136
+ // const trillNotes = ['E5','F5','E5','D5','E5'];
137
+ // trillNotes.forEach((n, i) => rh.triggerAttackRelease(n, '32n', time + i * 0.045));
138
+ ```
@@ -0,0 +1,145 @@
1
+ <div id="tuneframes" style="display:none">{"bpm":104,"duration":"12s"}</div>
2
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/tone/14.8.49/Tone.js"></script>
3
+ <script>
4
+ // TuneFrames — Classical Piano
5
+ // C major, Allegro moderato (104 BPM)
6
+ // Right hand: melodic line with ornamental turn
7
+ // Left hand: Alberti bass (bass-upper-inner-upper pattern)
8
+ // Harmony: I → V → vi → IV → V → I (complete progression)
9
+
10
+ async function main() {
11
+ await Tone.start();
12
+
13
+ Tone.Transport.bpm.value = 104;
14
+
15
+ const beat = 60 / 104; // 0.577s per quarter note
16
+ const eighth = beat / 2; // 0.288s per eighth note
17
+ const sixteenth = beat / 4; // 0.144s per sixteenth note
18
+
19
+ // ── Small room reverb — a piano in a parlour, not a concert hall ──────────
20
+ const reverb = new Tone.Reverb({ decay: 1.1, preDelay: 0.008, wet: 0.22 });
21
+ await reverb.generate();
22
+ reverb.toDestination();
23
+
24
+ // ── Right hand — melody voice, triangle wave ──────────────────────────────
25
+ const rh = new Tone.Synth({
26
+ oscillator: { type: 'triangle' },
27
+ envelope: { attack: 0.006, decay: 0.22, sustain: 0.18, release: 1.4 },
28
+ volume: -4,
29
+ });
30
+ rh.connect(reverb);
31
+
32
+ // ── Left hand single notes (bass) — slightly softer, same timbre ─────────
33
+ const lhBass = new Tone.Synth({
34
+ oscillator: { type: 'triangle' },
35
+ envelope: { attack: 0.008, decay: 0.35, sustain: 0.12, release: 1.0 },
36
+ volume: -10,
37
+ });
38
+ lhBass.connect(reverb);
39
+
40
+ // ── Left hand chord notes (inner voices of Alberti) ───────────────────────
41
+ const lhChord = new Tone.PolySynth(Tone.Synth, {
42
+ oscillator: { type: 'triangle' },
43
+ envelope: { attack: 0.008, decay: 0.3, sustain: 0.1, release: 0.9 },
44
+ volume: -13,
45
+ });
46
+ lhChord.connect(reverb);
47
+
48
+ // ─────────────────────────────────────────────────────────────────────────
49
+ // Helper: schedule an Alberti bass pattern for one bar using direct time
50
+ // root = bass note (e.g. 'C3'), inner = e.g. 'E3', upper = e.g. 'G3'
51
+ // Pattern of 8 eighth notes: root upper inner upper root upper inner upper
52
+ // ─────────────────────────────────────────────────────────────────────────
53
+ function alberti(root, inner, upper, startTime) {
54
+ const pattern = [root, upper, inner, upper, root, upper, inner, upper];
55
+ pattern.forEach((note, i) => {
56
+ const t = startTime + i * eighth;
57
+ if (i % 2 === 0) {
58
+ lhBass.triggerAttackRelease(note, '8n', t);
59
+ } else {
60
+ lhChord.triggerAttackRelease(note, '8n', t);
61
+ }
62
+ });
63
+ }
64
+
65
+ // ─────────────────────────────────────────────────────────────────────────
66
+ // Harmony plan (one bar each, 4 beats = beat*4 per bar):
67
+ // Bar 1: I — C major (C3 E3 G3)
68
+ // Bar 2: V — G major (G2 B2 D3)
69
+ // Bar 3: vi — A minor (A2 C3 E3)
70
+ // Bar 4: IV — F major (F2 A2 C3)
71
+ // Bar 5: V — G major (G2 B2 D3)
72
+ // Bar 6: I — C major (C3 E3 G3) — final resolution
73
+ // ─────────────────────────────────────────────────────────────────────────
74
+ const barLen = beat * 4;
75
+
76
+ alberti('C3', 'E3', 'G3', 0); // I
77
+ alberti('G2', 'B2', 'D3', barLen); // V
78
+ alberti('A2', 'C3', 'E3', barLen * 2); // vi
79
+ alberti('F2', 'A2', 'C3', barLen * 3); // IV
80
+ alberti('G2', 'B2', 'D3', barLen * 4); // V
81
+ alberti('C3', 'E3', 'G3', barLen * 5); // I (final)
82
+
83
+ // ─────────────────────────────────────────────────────────────────────────
84
+ // Right hand melody — stepwise, fits the chord above
85
+ // Phrase 1 (bars 1-2): C major scale ascending, quarter + eighth mix
86
+ // Phrase 2 (bars 3-4): descent with ornamental turn on E5
87
+ // Phrase 3 (bars 5-6): cadential figure, landing on C5
88
+ // ─────────────────────────────────────────────────────────────────────────
89
+
90
+ // Phrase 1: ascending C major scale with rhythmic variety
91
+ const phrase1 = [
92
+ { note: 'C5', dur: '4n', t: 0 },
93
+ { note: 'D5', dur: '8n', t: beat },
94
+ { note: 'E5', dur: '8n', t: beat + eighth },
95
+ { note: 'F5', dur: '4n', t: beat * 2 },
96
+ { note: 'G5', dur: '4n', t: beat * 3 },
97
+ // Bar 2: hold G5, then step up to A5
98
+ { note: 'G5', dur: '8n', t: barLen },
99
+ { note: 'A5', dur: '8n', t: barLen + eighth },
100
+ { note: 'G5', dur: '4n', t: barLen + beat },
101
+ { note: 'F5', dur: '4n', t: barLen + beat * 2 },
102
+ { note: 'E5', dur: '4n', t: barLen + beat * 3 },
103
+ ];
104
+
105
+ // Phrase 2: ornamental turn on E5 (F E D E), then descent
106
+ const turnStart = barLen * 2;
107
+ const turn = [
108
+ { note: 'F5', dur: '16n', t: turnStart },
109
+ { note: 'E5', dur: '16n', t: turnStart + sixteenth },
110
+ { note: 'D5', dur: '16n', t: turnStart + sixteenth * 2 },
111
+ { note: 'E5', dur: '8n', t: turnStart + sixteenth * 3 },
112
+ ];
113
+ const phrase2 = [
114
+ ...turn,
115
+ { note: 'D5', dur: '4n', t: turnStart + beat },
116
+ { note: 'C5', dur: '4n', t: turnStart + beat * 2 },
117
+ { note: 'B4', dur: '4n', t: turnStart + beat * 3 },
118
+ // Bar 4:
119
+ { note: 'A4', dur: '4n', t: barLen * 3 },
120
+ { note: 'G4', dur: '8n', t: barLen * 3 + beat },
121
+ { note: 'A4', dur: '8n', t: barLen * 3 + beat + eighth },
122
+ { note: 'C5', dur: '2n', t: barLen * 3 + beat * 2 },
123
+ ];
124
+
125
+ // Phrase 3: cadential figure V → I landing
126
+ const p3start = barLen * 4;
127
+ const phrase3 = [
128
+ { note: 'B4', dur: '4n', t: p3start },
129
+ { note: 'D5', dur: '4n', t: p3start + beat },
130
+ { note: 'G5', dur: '4n', t: p3start + beat * 2 },
131
+ { note: 'F5', dur: '4n', t: p3start + beat * 3 },
132
+ // Bar 6: resolution to I — long final note
133
+ { note: 'E5', dur: '8n', t: barLen * 5 },
134
+ { note: 'D5', dur: '8n', t: barLen * 5 + eighth },
135
+ { note: 'C5', dur: '2n', t: barLen * 5 + beat },
136
+ ];
137
+
138
+ // Schedule all right hand notes using direct time offsets (seconds)
139
+ [...phrase1, ...phrase2, ...phrase3].forEach(({ note, dur, t }) => {
140
+ if (t < 12) {
141
+ rh.triggerAttackRelease(note, dur, t);
142
+ }
143
+ });
144
+ }
145
+ </script>
@@ -0,0 +1,142 @@
1
+ ---
2
+ name: audio-dnb
3
+ description: Drum and Bass — syncopated Amen-style breakbeat, reese bass with chorus and filter, atmospheric pad, heavy sub frequencies. Hard hitting and kinetic.
4
+ ---
5
+
6
+ # TuneFrames — Drum and Bass
7
+
8
+ ## Genre Profile
9
+ - BPM range: 165–180
10
+ - Key characteristics: Complex syncopated breakbeat (kick not on the beat — that's the point), heavy Reese bass (sawtooth + chorus + filter), atmospheric pad underneath, powerful sub frequencies, kinetic forward momentum
11
+ - Typical instruments: MembraneSynth (kick), NoiseSynth (snare), MetalSynth (hi-hat), FMSynth or MonoSynth (Reese bass), PolySynth (pad)
12
+ - Mood: Intense, kinetic, dark, cerebral, euphoric at the peak
13
+
14
+ ## Core Pattern
15
+
16
+ ```js
17
+ // Drum and Bass — 174 BPM
18
+ // Breakbeat: kick/snare NOT on beats 1,2,3,4 — syncopated Amen-style
19
+ // Reese bass: sawtooth + heavy chorus = that "wobble" character
20
+ // Pad: slow attack, atmospheric underneath
21
+
22
+ // Classic DnB breakbeat (Amen-style, 16-step)
23
+ // K=kick, S=snare, .=rest
24
+ // K . . S . K K S . . K . S . K S (feel, not strict)
25
+ const breakPattern = [
26
+ "kick", null, null, "snare", null, "kick", "kick", "snare",
27
+ null, null, "kick", null, "snare", null, "kick", "snare"
28
+ ];
29
+
30
+ new Tone.Sequence((time, hit) => {
31
+ if (hit === "kick") kick.triggerAttackRelease("C1", "8n", time);
32
+ if (hit === "snare") snare.triggerAttackRelease("16n", time);
33
+ }, breakPattern, "16n").start(0);
34
+
35
+ // Reese bass — sawtooth through chorus
36
+ const chorus = new Tone.Chorus({ frequency: 1.8, delayTime: 3.5, depth: 0.7, wet: 0.7 });
37
+ const filter = new Tone.Filter({ frequency: 800, type: "lowpass", Q: 2 });
38
+ const reese = new Tone.MonoSynth({
39
+ oscillator: { type: "sawtooth" },
40
+ envelope: { attack: 0.01, decay: 0.5, sustain: 0.8, release: 0.3 },
41
+ volume: -4
42
+ }).chain(chorus, filter, Tone.Destination);
43
+ chorus.start();
44
+
45
+ Tone.Transport.bpm.value = 174;
46
+ Tone.Transport.start();
47
+ ```
48
+
49
+ ## Instrument Configuration
50
+
51
+ ```js
52
+ // Kick — short, punchy, low
53
+ const kick = new Tone.MembraneSynth({
54
+ pitchDecay: 0.04,
55
+ octaves: 5,
56
+ envelope: { attack: 0.001, decay: 0.2, sustain: 0, release: 0.08 },
57
+ volume: 2
58
+ }).toDestination();
59
+
60
+ // Snare — crisp, with slight room
61
+ const snareVerb = new Tone.Reverb({ decay: 0.5, wet: 0.15 }).toDestination();
62
+ const snare = new Tone.NoiseSynth({
63
+ noise: { type: "white" },
64
+ envelope: { attack: 0.001, decay: 0.12, sustain: 0, release: 0.04 },
65
+ volume: -2
66
+ }).connect(snareVerb);
67
+
68
+ // Hi-hat — very fast, adds texture between beats
69
+ const hat = new Tone.MetalSynth({
70
+ frequency: 500, harmonicity: 5.1, modulationIndex: 32,
71
+ resonance: 4500, octaves: 1.5,
72
+ envelope: { attack: 0.001, decay: 0.035, release: 0.01 },
73
+ volume: -12
74
+ }).toDestination();
75
+
76
+ // Reese bass — the DnB defining sound
77
+ // Two detuned sawtooths + heavy chorus + filter
78
+ const reeseLimiter = new Tone.Limiter(-4).toDestination();
79
+ const reeseFilter = new Tone.Filter({ frequency: 700, type: "lowpass", Q: 3 }).connect(reeseLimiter);
80
+ const reeseChorus = new Tone.Chorus({
81
+ frequency: 1.8, // slow chorus = the "reese" movement
82
+ delayTime: 3.5,
83
+ depth: 0.75,
84
+ wet: 0.75
85
+ }).connect(reeseFilter);
86
+ reeseChorus.start();
87
+ const reese = new Tone.MonoSynth({
88
+ oscillator: { type: "sawtooth" },
89
+ filter: { Q: 1, type: "lowpass", frequency: 2000 },
90
+ filterEnvelope: { attack: 0.02, decay: 0.5, sustain: 0.5, release: 0.5,
91
+ baseFrequency: 200, octaves: 2 },
92
+ envelope: { attack: 0.01, decay: 0.3, sustain: 0.8, release: 0.3 },
93
+ volume: -2
94
+ }).connect(reeseChorus);
95
+
96
+ // Atmospheric pad — slow attack, long release
97
+ const padVerb = new Tone.Reverb({ decay: 5.0, wet: 0.7 }).toDestination();
98
+ const pad = new Tone.PolySynth(Tone.Synth, {
99
+ oscillator: { type: "sawtooth4" },
100
+ envelope: { attack: 0.6, decay: 1.0, sustain: 0.6, release: 2.5 },
101
+ volume: -14
102
+ }).connect(padVerb);
103
+ ```
104
+
105
+ ## Composition Structure
106
+
107
+ - **Bar 1-2:** Breakbeat only — establish the syncopated groove immediately
108
+ - **Bar 3-4:** Add hi-hat fills between kick/snare — density builds
109
+ - **Bar 5-8:** Add Reese bass — low sustained notes, filter opens slowly
110
+ - **Bar 9-16:** Full arrangement — breakbeat + Reese + atmospheric pad
111
+ - **Variation bar:** Every 4 bars, drop a kick or add a snare roll for surprise
112
+ - **Reese movement:** Filter automation — close at bar 5, sweep open over bar 6-8, close and re-open
113
+ - **Outro:** Break strip — just pad remains, then breakbeat returns for exit
114
+
115
+ The breakbeat is the identity. The kick landing OFF the downbeat is what separates DnB from techno — resist putting the kick on beat 1. The snare DOES land around beats 2 and 4 but offset slightly.
116
+
117
+ ## Example Variations
118
+
119
+ ### 1 — Half-time feel bridge
120
+ ```js
121
+ // Every 8 bars, drop to a 2-step pattern (kick-snare only) for 1 bar
122
+ // Builds tension before the full break returns
123
+ const halfTimeBar = ["kick", null, null, null, null, null, null, null,
124
+ null, null, null, null, "snare", null, null, null];
125
+ ```
126
+
127
+ ### 2 — Reese filter wobble (1/4 note LFO)
128
+ ```js
129
+ // LFO modulating the Reese filter — creates rhythmic wobble
130
+ const lfo = new Tone.LFO({ frequency: "4n", min: 200, max: 2000, type: "sine" });
131
+ lfo.connect(reeseFilter.frequency);
132
+ lfo.start();
133
+ ```
134
+
135
+ ### 3 — Snare roll into drop
136
+ ```js
137
+ // 16th-note snare roll over the last bar before a new section
138
+ // Schedule 8 snare hits in last bar
139
+ for (let i = 0; i < 8; i++) {
140
+ snare.triggerAttackRelease("32n", `${barStart} + ${i * 0.107}`, 0.3 + i * 0.087);
141
+ }
142
+ ```
@@ -0,0 +1,124 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <title>TuneFrames — Drum and 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":174,"duration":"12s"}</div>
11
+
12
+ <script>
13
+ async function main() {
14
+ await Tone.start();
15
+ Tone.Transport.bpm.value = 174;
16
+
17
+ // --- MASTER BUS ---
18
+ const masterLimiter = new Tone.Limiter(-1).toDestination();
19
+ const masterGain = new Tone.Gain(0.87).connect(masterLimiter);
20
+
21
+ // --- KICK — short, punchy, sub-heavy ---
22
+ const kickGain = new Tone.Gain(0.9).connect(masterGain);
23
+ const kick = new Tone.MembraneSynth({
24
+ pitchDecay: 0.038,
25
+ octaves: 5,
26
+ envelope: { attack: 0.001, decay: 0.18, sustain: 0, release: 0.07 }
27
+ }).connect(kickGain);
28
+
29
+ // --- SNARE — crisp white noise ---
30
+ const snareVerb = new Tone.Reverb({ decay: 0.45, wet: 0.14 }).connect(masterGain);
31
+ const snareGain = new Tone.Gain(0.65).connect(snareVerb);
32
+ const snare = new Tone.NoiseSynth({
33
+ noise: { type: "white" },
34
+ envelope: { attack: 0.001, decay: 0.11, sustain: 0, release: 0.035 }
35
+ }).connect(snareGain);
36
+
37
+ // --- HI-HAT — fast texture between beats ---
38
+ const hatGain = new Tone.Gain(0.28).connect(masterGain);
39
+ const hat = new Tone.MetalSynth({
40
+ frequency: 520,
41
+ envelope: { attack: 0.001, decay: 0.032, release: 0.01 },
42
+ harmonicity: 5.1,
43
+ modulationIndex: 32,
44
+ resonance: 4600,
45
+ octaves: 1.5
46
+ }).connect(hatGain);
47
+
48
+ // --- REESE BASS — MonoSynth sawtooth + Chorus + Filter ---
49
+ // The Reese is the defining DnB sound: two slightly detuned saws = chorus
50
+ const reeseLimiter = new Tone.Limiter(-4).connect(masterGain);
51
+ const reeseFilter = new Tone.Filter({ frequency: 500, type: "lowpass", Q: 2.5 }).connect(reeseLimiter);
52
+ const reeseChorus = new Tone.Chorus({
53
+ frequency: 1.7,
54
+ delayTime: 3.5,
55
+ depth: 0.78,
56
+ wet: 0.72
57
+ }).connect(reeseFilter);
58
+ reeseChorus.start();
59
+ const reese = new Tone.MonoSynth({
60
+ oscillator: { type: "sawtooth" },
61
+ filter: { Q: 1.5, type: "lowpass", frequency: 3000 },
62
+ filterEnvelope: {
63
+ attack: 0.02, decay: 0.6, sustain: 0.5, release: 0.4,
64
+ baseFrequency: 180, octaves: 2.5
65
+ },
66
+ envelope: { attack: 0.008, decay: 0.4, sustain: 0.8, release: 0.35 },
67
+ volume: 0
68
+ }).connect(reeseChorus);
69
+
70
+ // --- ATMOSPHERIC PAD — slow attack, very wet reverb ---
71
+ const padVerb = new Tone.Reverb({ decay: 5.5, wet: 0.72 }).connect(masterGain);
72
+ const padGain = new Tone.Gain(0.45).connect(padVerb);
73
+ const pad = new Tone.PolySynth(Tone.Synth, {
74
+ oscillator: { type: "sawtooth4" },
75
+ envelope: { attack: 0.7, decay: 1.2, sustain: 0.6, release: 3.0 },
76
+ volume: -2
77
+ }).connect(padGain);
78
+
79
+ // --- BREAKBEAT PATTERN — syncopated Amen-style ---
80
+ // K=kick, S=snare, h=hat, .=rest
81
+ // Pattern: . . S . K K S . . K . S K . S h
82
+ const breakSeq = new Tone.Sequence((time, hit) => {
83
+ if (hit === "K") kick.triggerAttackRelease("C1", "8n", time);
84
+ if (hit === "S") snare.triggerAttackRelease("16n", time, 0.85);
85
+ if (hit === "s") snare.triggerAttackRelease("16n", time, 0.45); // ghost snare
86
+ if (hit === "h") hat.triggerAttackRelease("32n", time, 0.5);
87
+ }, [
88
+ null, "h", "S", null, "K", "K", "S", null,
89
+ "h", "K", null, "S", "K", "h", "S", "h"
90
+ ], "16n");
91
+ breakSeq.start(0);
92
+
93
+ // --- REESE BASS LINE — D minor, sustained long notes ---
94
+ // Reese bass plays whole-bar notes — the filter movement IS the melody
95
+ const reeseLine = [
96
+ { note: "D1", dur: "1m", time: "2m" },
97
+ { note: "C1", dur: "1m", time: "3m" },
98
+ { note: "Bb0", dur: "1m", time: "4m" },
99
+ { note: "A0", dur: "1m", time: "5m" },
100
+ { note: "D1", dur: "1m", time: "6m" },
101
+ { note: "F1", dur: "1m", time: "7m" },
102
+ ];
103
+ reeseLine.forEach(({ note, dur, time }) => {
104
+ reese.triggerAttackRelease(note, dur, time);
105
+ });
106
+
107
+ // Filter sweep on Reese — opens over bars 3-5, closes back bar 6-7
108
+ const sweepStart = Tone.Time("2m").toSeconds();
109
+ reeseFilter.frequency.setValueAtTime(300, sweepStart);
110
+ reeseFilter.frequency.exponentialRampToValueAtTime(2200, sweepStart + 4);
111
+ reeseFilter.frequency.exponentialRampToValueAtTime(250, sweepStart + 5.5);
112
+ reeseFilter.frequency.exponentialRampToValueAtTime(1800, sweepStart + 9);
113
+
114
+ // --- PAD — atmospheric Dm chord, enters at bar 4 ---
115
+ const padNotes = ["D3", "F3", "A3", "C4"]; // Dm7
116
+ pad.triggerAttackRelease(padNotes, "4m", "3m");
117
+ pad.triggerAttackRelease(["C3", "Eb3", "G3", "Bb3"], "4m", "7m"); // Cm7
118
+
119
+ }
120
+
121
+ main();
122
+ </script>
123
+ </body>
124
+ </html>