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.
- package/LICENSE +167 -199
- package/README.md +150 -97
- package/examples/example-ai-dj-chill.html +167 -0
- package/examples/example-ai-dj-dark.html +167 -0
- package/examples/example-ai-dj-energetic.html +167 -0
- package/examples/example-ai-dj-happy.html +167 -0
- package/examples/example-ai-dj.html +167 -0
- package/examples/example-ambient.html +63 -63
- package/examples/example-ambient.mp3 +0 -0
- package/examples/example-bass.html +48 -0
- package/examples/example-lofi.html +45 -45
- package/examples/example-lofi.mp3 +0 -0
- package/examples/example-minimal.html +21 -19
- package/examples/example-minimal.mp3 +0 -0
- package/examples/example-orchestral.html +67 -67
- package/examples/example-orchestral.mp3 +0 -0
- package/examples/example-piano.html +53 -0
- package/examples/example-piano.mp3 +0 -0
- package/examples/example-techno.html +69 -69
- package/examples/example-techno.mp3 +0 -0
- package/package.json +42 -24
- package/registry/presets/bass-electric.html +67 -0
- package/registry/presets/bass-saw.html +22 -0
- package/registry/presets/chord-progression.html +22 -0
- package/registry/presets/drums-808.html +85 -0
- package/registry/presets/drums-lofi.html +35 -0
- package/registry/presets/lead-piano.html +26 -0
- package/registry/presets/piano-salamander.html +69 -0
- package/registry/presets/reverb-warm.html +11 -0
- package/registry/samples.json +226 -0
- package/skills/audio-ambient/SKILL.md +141 -0
- package/skills/audio-ambient/example.html +113 -0
- package/skills/audio-boss-battle/SKILL.md +157 -0
- package/skills/audio-boss-battle/example.html +185 -0
- package/skills/audio-boss-battle/example.mp3 +0 -0
- package/skills/audio-chillwave/SKILL.md +142 -0
- package/skills/audio-chillwave/example.html +144 -0
- package/skills/audio-cinematic/SKILL.md +147 -0
- package/skills/audio-cinematic/example.html +123 -0
- package/skills/audio-classical/SKILL.md +138 -0
- package/skills/audio-classical/example.html +145 -0
- package/skills/audio-dnb/SKILL.md +142 -0
- package/skills/audio-dnb/example.html +124 -0
- package/skills/audio-downtempo/SKILL.md +152 -0
- package/skills/audio-downtempo/example.html +164 -0
- package/skills/audio-folk/SKILL.md +139 -0
- package/skills/audio-folk/example.html +132 -0
- package/skills/audio-funk/SKILL.md +149 -0
- package/skills/audio-funk/example.html +144 -0
- package/skills/audio-future-bass/SKILL.md +163 -0
- package/skills/audio-future-bass/example.html +164 -0
- package/skills/audio-hip-hop/SKILL.md +133 -0
- package/skills/audio-hip-hop/example.html +129 -0
- package/skills/audio-house/SKILL.md +147 -0
- package/skills/audio-house/example.html +128 -0
- package/skills/audio-indie-pop/SKILL.md +150 -0
- package/skills/audio-indie-pop/example.html +121 -0
- package/skills/audio-jazz/SKILL.md +141 -0
- package/skills/audio-jazz/example.html +146 -0
- package/skills/audio-lofi/SKILL.md +140 -0
- package/skills/audio-lofi/example.html +135 -0
- package/skills/audio-minimal/SKILL.md +155 -0
- package/skills/audio-minimal/example.html +118 -0
- package/skills/audio-orchestral/SKILL.md +156 -0
- package/skills/audio-orchestral/example.html +140 -0
- package/skills/audio-r-and-b/SKILL.md +134 -0
- package/skills/audio-r-and-b/example.html +154 -0
- package/skills/audio-r-and-b/example.mp3 +0 -0
- package/skills/audio-techno/SKILL.md +140 -0
- package/skills/audio-techno/example.html +125 -0
- package/skills/audio-trap/SKILL.md +123 -0
- package/skills/audio-trap/example.html +119 -0
- package/skills/render-retest/example.html +115 -0
- package/skills/tuneframes/SKILL.md +221 -0
- package/skills/tuneframes-cli/SKILL.md +46 -0
- package/skills/verify/example.html +104 -0
- package/src/cli.js +261 -89
- package/src/render.js +134 -7
|
@@ -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&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
|
+
```
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<title>TuneFrames — Techno</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":136,"duration":"12s"}</div>
|
|
11
|
+
|
|
12
|
+
<script>
|
|
13
|
+
async function main() {
|
|
14
|
+
await Tone.start();
|
|
15
|
+
Tone.Transport.bpm.value = 136;
|
|
16
|
+
|
|
17
|
+
// --- MASTER BUS ---
|
|
18
|
+
const masterLimiter = new Tone.Limiter(-1).toDestination();
|
|
19
|
+
const masterGain = new Tone.Gain(0.85).connect(masterLimiter);
|
|
20
|
+
|
|
21
|
+
// --- KICK — hard MembraneSynth ---
|
|
22
|
+
const kickGain = new Tone.Gain(0.9).connect(masterGain);
|
|
23
|
+
const kick = new Tone.MembraneSynth({
|
|
24
|
+
pitchDecay: 0.07,
|
|
25
|
+
octaves: 10,
|
|
26
|
+
envelope: { attack: 0.001, decay: 0.38, sustain: 0, release: 0.1 }
|
|
27
|
+
}).connect(kickGain);
|
|
28
|
+
|
|
29
|
+
// --- ACID BASS — MonoSynth sawtooth through distortion ---
|
|
30
|
+
const bassLimiter = new Tone.Limiter(-4).connect(masterGain);
|
|
31
|
+
const bassDist = new Tone.Distortion({ distortion: 0.55, wet: 0.7 }).connect(bassLimiter);
|
|
32
|
+
const bassFilter = new Tone.Filter({ frequency: 400, type: "lowpass", rolloff: -24, Q: 3 }).connect(bassDist);
|
|
33
|
+
const bass = new Tone.MonoSynth({
|
|
34
|
+
oscillator: { type: "sawtooth" },
|
|
35
|
+
filter: { Q: 7, type: "lowpass", rolloff: -24 },
|
|
36
|
+
filterEnvelope: {
|
|
37
|
+
attack: 0.002, decay: 0.25, sustain: 0.2, release: 0.5,
|
|
38
|
+
baseFrequency: 70, octaves: 3.5
|
|
39
|
+
},
|
|
40
|
+
envelope: { attack: 0.001, decay: 0.25, sustain: 0.5, release: 0.3 },
|
|
41
|
+
volume: -2
|
|
42
|
+
}).connect(bassFilter);
|
|
43
|
+
|
|
44
|
+
// --- HI-HAT — tight MetalSynth ---
|
|
45
|
+
const hatGain = new Tone.Gain(0.45).connect(masterGain);
|
|
46
|
+
const hat = new Tone.MetalSynth({
|
|
47
|
+
frequency: 400,
|
|
48
|
+
envelope: { attack: 0.001, decay: 0.045, release: 0.01 },
|
|
49
|
+
harmonicity: 5.1,
|
|
50
|
+
modulationIndex: 32,
|
|
51
|
+
resonance: 4200,
|
|
52
|
+
octaves: 1.5
|
|
53
|
+
}).connect(hatGain);
|
|
54
|
+
|
|
55
|
+
// --- STAB — sparse cold PolySynth ---
|
|
56
|
+
const stabReverb = new Tone.Reverb({ decay: 1.8, wet: 0.35 }).connect(masterGain);
|
|
57
|
+
const stab = new Tone.PolySynth(Tone.Synth, {
|
|
58
|
+
oscillator: { type: "square4" },
|
|
59
|
+
envelope: { attack: 0.001, decay: 0.12, sustain: 0, release: 0.08 },
|
|
60
|
+
volume: -14
|
|
61
|
+
}).connect(stabReverb);
|
|
62
|
+
|
|
63
|
+
// Stab chords — dissonant, industrial
|
|
64
|
+
const stabNotes = [["A2", "Eb3"], ["A2", "D3"], null, ["G2", "C#3"]];
|
|
65
|
+
|
|
66
|
+
// --- SEQUENCES ---
|
|
67
|
+
|
|
68
|
+
// Kick: 4-on-the-floor with ghost on bar 2 last 16th
|
|
69
|
+
const kickPattern = new Tone.Sequence((time, val) => {
|
|
70
|
+
if (val) kick.triggerAttackRelease("C1", "8n", time);
|
|
71
|
+
}, ["C1", null, null, null, "C1", null, null, null,
|
|
72
|
+
"C1", null, null, null, "C1", null, "C1", null], "16n");
|
|
73
|
+
kickPattern.start(0);
|
|
74
|
+
|
|
75
|
+
// Hi-hat: 16th notes, velocity variation
|
|
76
|
+
let hatStep = 0;
|
|
77
|
+
const hatVels = [0.75, 0.35, 0.75, 0.35, 0.75, 0.35, 0.95, 0.35,
|
|
78
|
+
0.75, 0.35, 0.75, 0.35, 0.75, 0.45, 0.95, 0.55];
|
|
79
|
+
const hatSeq = new Tone.Sequence((time) => {
|
|
80
|
+
hat.triggerAttackRelease("32n", time, hatVels[hatStep % 16]);
|
|
81
|
+
hatStep++;
|
|
82
|
+
}, new Array(16).fill(1), "16n");
|
|
83
|
+
hatSeq.start(0);
|
|
84
|
+
|
|
85
|
+
// Bass: acid pattern — A1 root with chromatic movement
|
|
86
|
+
const bassLine = [
|
|
87
|
+
{ note: "A1", dur: "8n" }, { note: null },
|
|
88
|
+
{ note: "A1", dur: "16n" }, { note: "A1", dur: "16n" },
|
|
89
|
+
{ note: null }, { note: "C2", dur: "8n" },
|
|
90
|
+
{ note: null }, { note: "A1", dur: "16n" },
|
|
91
|
+
{ note: "A1", dur: "8n" }, { note: null },
|
|
92
|
+
{ note: "Bb1", dur: "16n" }, { note: "A1", dur: "16n" },
|
|
93
|
+
{ note: null }, { note: "G1", dur: "16n" },
|
|
94
|
+
{ note: null }, { note: "A1", dur: "8n" }
|
|
95
|
+
];
|
|
96
|
+
let bassStep = 0;
|
|
97
|
+
const bassSeq = new Tone.Sequence((time) => {
|
|
98
|
+
const step = bassLine[bassStep % bassLine.length];
|
|
99
|
+
if (step.note) bass.triggerAttackRelease(step.note, step.dur, time);
|
|
100
|
+
bassStep++;
|
|
101
|
+
}, new Array(16).fill(1), "16n");
|
|
102
|
+
bassSeq.start("2m"); // bass enters at bar 3
|
|
103
|
+
|
|
104
|
+
// Stabs: every 2 bars on beat 3
|
|
105
|
+
let stabStep = 0;
|
|
106
|
+
const stabSeq = new Tone.Sequence((time) => {
|
|
107
|
+
const chord = stabNotes[stabStep % stabNotes.length];
|
|
108
|
+
if (chord) stab.triggerAttackRelease(chord, "32n", time);
|
|
109
|
+
stabStep++;
|
|
110
|
+
}, [1, null, null, null, null, null, null, null], "2n");
|
|
111
|
+
stabSeq.start("4m"); // stabs enter at bar 5
|
|
112
|
+
|
|
113
|
+
// --- BASS FILTER SWEEP — signature acid movement ---
|
|
114
|
+
const sweepStart = Tone.Time("2m").toSeconds();
|
|
115
|
+
bassFilter.frequency.setValueAtTime(200, sweepStart);
|
|
116
|
+
bassFilter.frequency.linearRampToValueAtTime(2800, sweepStart + 4);
|
|
117
|
+
bassFilter.frequency.linearRampToValueAtTime(150, sweepStart + 4.5);
|
|
118
|
+
bassFilter.frequency.linearRampToValueAtTime(1800, sweepStart + 8);
|
|
119
|
+
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
main();
|
|
123
|
+
</script>
|
|
124
|
+
</body>
|
|
125
|
+
</html>
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: audio-trap
|
|
3
|
+
description: Trap — 808 sub bass with pitch bend, snare on 2 and 4, rapid hi-hat rolls with velocity variation, sparse orchestral strings for drama.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# TuneFrames — Trap
|
|
7
|
+
|
|
8
|
+
## Genre Profile
|
|
9
|
+
- BPM range: 130–160 (half-time feel makes it sit like 65–80)
|
|
10
|
+
- Key characteristics: 808 sub bass with long decay and downward pitch bend, snare on beats 2 and 4, hi-hat rolls in 16th/32nd triplets with strong velocity variation, heavy low end, atmospheric elements
|
|
11
|
+
- Typical instruments: MembraneSynth (808 sub), NoiseSynth (snare), MetalSynth (hi-hats), PolySynth (strings/pads)
|
|
12
|
+
- Mood: Menacing, cinematic, heavy, dramatic
|
|
13
|
+
|
|
14
|
+
## Core Pattern
|
|
15
|
+
|
|
16
|
+
```js
|
|
17
|
+
// Trap — 140 BPM, half-time feel
|
|
18
|
+
// 808: long decay sub with downward pitch glide
|
|
19
|
+
// Snare: beat 2 and 4 (half-time = bars 1 and 3)
|
|
20
|
+
// Hi-hats: rapid rolls, velocity builds and drops — the signature
|
|
21
|
+
// Strings: sparse atmospheric chords
|
|
22
|
+
|
|
23
|
+
// 808 sub — MembraneSynth with pitch envelope = signature glide
|
|
24
|
+
const sub = new Tone.MembraneSynth({
|
|
25
|
+
pitchDecay: 0.5, // long pitch glide (the "808 fall")
|
|
26
|
+
octaves: 3, // moderate pitch drop
|
|
27
|
+
envelope: { attack: 0.001, decay: 1.2, sustain: 0, release: 0.5 }
|
|
28
|
+
}).toDestination();
|
|
29
|
+
|
|
30
|
+
// Trigger 808 on beat 1 — pitch starts at C2 then falls
|
|
31
|
+
sub.triggerAttackRelease("C2", "2n", time);
|
|
32
|
+
|
|
33
|
+
// Hi-hat roll — 32nd notes, velocity variation = the trap signature
|
|
34
|
+
const hatVelocities = [
|
|
35
|
+
0.9, 0.3, 0.5, 0.2, 0.7, 0.2, 0.4, 0.2, // 8-step build
|
|
36
|
+
0.6, 0.3, 0.8, 0.2, 0.5, 0.3, 1.0, 0.2 // accent on last
|
|
37
|
+
];
|
|
38
|
+
new Tone.Sequence((time, vel) => {
|
|
39
|
+
hat.triggerAttackRelease("32n", time, vel);
|
|
40
|
+
}, hatVelocities, "32n").start(0);
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Instrument Configuration
|
|
44
|
+
|
|
45
|
+
```js
|
|
46
|
+
// 808 Sub — long pitchDecay is the defining characteristic
|
|
47
|
+
const dist808 = new Tone.Distortion({ distortion: 0.15, wet: 0.3 }).toDestination();
|
|
48
|
+
const sub = new Tone.MembraneSynth({
|
|
49
|
+
pitchDecay: 0.45, // how long the pitch "falls" — the 808 glide
|
|
50
|
+
octaves: 3, // semitones of pitch drop
|
|
51
|
+
volume: 2,
|
|
52
|
+
envelope: { attack: 0.001, decay: 1.0, sustain: 0, release: 0.6 }
|
|
53
|
+
}).connect(dist808); // light saturation adds warmth to the sub
|
|
54
|
+
|
|
55
|
+
// Snare — tight white noise, minimal reverb
|
|
56
|
+
const snareVerb = new Tone.Reverb({ decay: 0.8, wet: 0.2 }).toDestination();
|
|
57
|
+
const snare = new Tone.NoiseSynth({
|
|
58
|
+
noise: { type: "white" },
|
|
59
|
+
envelope: { attack: 0.001, decay: 0.18, sustain: 0, release: 0.06 },
|
|
60
|
+
volume: -2
|
|
61
|
+
}).connect(snareVerb);
|
|
62
|
+
|
|
63
|
+
// Hi-hat — very short decay, high frequency
|
|
64
|
+
const hat = new Tone.MetalSynth({
|
|
65
|
+
frequency: 800,
|
|
66
|
+
envelope: { attack: 0.001, decay: 0.03, release: 0.008 },
|
|
67
|
+
harmonicity: 5.1,
|
|
68
|
+
modulationIndex: 32,
|
|
69
|
+
resonance: 5000,
|
|
70
|
+
octaves: 2,
|
|
71
|
+
volume: -8
|
|
72
|
+
}).toDestination();
|
|
73
|
+
|
|
74
|
+
// Orchestral strings — sparse, atmospheric
|
|
75
|
+
const stringsVerb = new Tone.Reverb({ decay: 4.0, wet: 0.6 }).toDestination();
|
|
76
|
+
const strings = new Tone.PolySynth(Tone.Synth, {
|
|
77
|
+
oscillator: { type: "sawtooth4" },
|
|
78
|
+
envelope: { attack: 0.4, decay: 1.0, sustain: 0.7, release: 1.5 },
|
|
79
|
+
volume: -12
|
|
80
|
+
}).connect(stringsVerb);
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## Composition Structure
|
|
84
|
+
|
|
85
|
+
- **Bar 1:** 808 hit on beat 1, snare on beat 3 (half-time), hi-hat roll building
|
|
86
|
+
- **Bar 2:** 808 on beat 1 again (the sub is still decaying from bar 1), hi-hat variation
|
|
87
|
+
- **Bars 1-4:** Drum loop establishes half-time feel with rolls escalating
|
|
88
|
+
- **Bar 5-8:** Add strings — sparse pad chord, lots of reverb
|
|
89
|
+
- **Bar 9-16:** Full arrangement — 808 pattern + hi-hat rolls + strings harmony
|
|
90
|
+
- **Build:** Hi-hat velocity increases toward drop, 32nd note flurry
|
|
91
|
+
- **Drop:** 808 hits hard, hi-hats sparse, strings cut — maximum impact
|
|
92
|
+
|
|
93
|
+
Hi-hat roll anatomy: Start sparse (quarter notes), build to 8ths, then 16ths, then 32nds on the approach to the drop. This escalation is the genre's primary tension tool.
|
|
94
|
+
|
|
95
|
+
## Example Variations
|
|
96
|
+
|
|
97
|
+
### 1 — Classic 808 Double Hit
|
|
98
|
+
```js
|
|
99
|
+
// 808 hits twice in a bar — beat 1 and the "and" of beat 3
|
|
100
|
+
const subPattern = ["C2", null, null, null, null, null, "C1", null];
|
|
101
|
+
// Second hit is higher (C1 vs C2) — common trap technique
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### 2 — Hi-Hat Triplet Roll
|
|
105
|
+
```js
|
|
106
|
+
// Triplet 16ths (12 per bar instead of 16) — more organic feel
|
|
107
|
+
new Tone.Sequence((time, vel) => {
|
|
108
|
+
if (vel) hat.triggerAttackRelease("32n", time, vel);
|
|
109
|
+
}, [0.9, 0.3, 0.6, 0.9, 0.3, 0.6, 0.9, 0.3, 0.6, 0.9, 0.3, 0.9], "8t").start(0);
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### 3 — Sliding 808 Pitch (Tone.js portamento)
|
|
113
|
+
```js
|
|
114
|
+
// Use portamento on MonoSynth for more dramatic pitch slide
|
|
115
|
+
const slideSub = new Tone.MonoSynth({
|
|
116
|
+
oscillator: { type: "sine" },
|
|
117
|
+
portamento: 0.4, // glide time in seconds
|
|
118
|
+
envelope: { attack: 0.001, decay: 1.2, sustain: 0, release: 0.5 },
|
|
119
|
+
filter: { type: "lowpass", frequency: 200 }
|
|
120
|
+
});
|
|
121
|
+
slideSub.triggerAttackRelease("C3", "2n", time);
|
|
122
|
+
// Then after portamento, note has already slid down
|
|
123
|
+
```
|