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