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.
- package/LICENSE +166 -166
- package/README.md +158 -55
- 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 +47 -47
- package/examples/example-lofi.html +45 -45
- package/examples/example-lofi.mp3 +0 -0
- package/examples/example-minimal.html +20 -20
- package/examples/example-orchestral.html +67 -67
- package/examples/example-orchestral.mp3 +0 -0
- package/examples/example-piano.html +52 -52
- 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 -37
- 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 +260 -151
- package/src/render.js +134 -7
- package/examples/example-bass.mp3 +0 -0
- package/examples/example-demo-beat.wav +0 -0
- package/examples/example-orchestral.wav +0 -0
|
@@ -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
|
+
```
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<title>TuneFrames — Boom Bap Hip Hop</title>
|
|
6
|
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/tone/14.8.49/Tone.js"></script>
|
|
7
|
+
</head>
|
|
8
|
+
<body>
|
|
9
|
+
<!-- TuneFrames Metadata — must be JSON textContent, not data attributes -->
|
|
10
|
+
<div id="tuneframes" style="display:none">{"bpm":88,"duration":"12s"}</div>
|
|
11
|
+
|
|
12
|
+
<script>
|
|
13
|
+
async function main() {
|
|
14
|
+
await Tone.start();
|
|
15
|
+
|
|
16
|
+
// Set BPM so Tone.Time string values resolve correctly
|
|
17
|
+
Tone.Transport.bpm.value = 88;
|
|
18
|
+
|
|
19
|
+
const beat = Tone.Time("4n").toSeconds(); // ~0.682s at 88 BPM
|
|
20
|
+
const s16 = beat / 4; // 16th note ~0.170s
|
|
21
|
+
const bar = beat * 4; // 1 bar ~2.727s
|
|
22
|
+
const numBars = 4; // 4 bars ~10.9s (fits in 12s)
|
|
23
|
+
|
|
24
|
+
// --- MASTER BUS ---
|
|
25
|
+
const masterLimiter = new Tone.Limiter(-1).toDestination();
|
|
26
|
+
const masterGain = new Tone.Gain(0.82).connect(masterLimiter);
|
|
27
|
+
|
|
28
|
+
// --- KICK — punchy MembraneSynth ---
|
|
29
|
+
const kickDist = new Tone.Distortion({ distortion: 0.2, wet: 0.4 }).connect(masterGain);
|
|
30
|
+
const kickGain = new Tone.Gain(0.88).connect(kickDist);
|
|
31
|
+
const kick = new Tone.MembraneSynth({
|
|
32
|
+
pitchDecay: 0.07,
|
|
33
|
+
octaves: 6,
|
|
34
|
+
envelope: { attack: 0.001, decay: 0.32, sustain: 0, release: 0.1 }
|
|
35
|
+
}).connect(kickGain);
|
|
36
|
+
|
|
37
|
+
// --- SNARE — white noise with reverb tail ---
|
|
38
|
+
const snareVerb = new Tone.Reverb({ decay: 1.8, wet: 0.5 }).connect(masterGain);
|
|
39
|
+
const snareGain = new Tone.Gain(0.52).connect(snareVerb);
|
|
40
|
+
const snare = new Tone.NoiseSynth({
|
|
41
|
+
noise: { type: "white" },
|
|
42
|
+
envelope: { attack: 0.001, decay: 0.2, sustain: 0, release: 0.06 }
|
|
43
|
+
}).connect(snareGain);
|
|
44
|
+
|
|
45
|
+
// --- HI-HAT — MetalSynth, short and crisp ---
|
|
46
|
+
const hatGain = new Tone.Gain(0.28).connect(masterGain);
|
|
47
|
+
const hat = new Tone.MetalSynth({
|
|
48
|
+
frequency: 500,
|
|
49
|
+
envelope: { attack: 0.001, decay: 0.04, release: 0.01 },
|
|
50
|
+
harmonicity: 5.1,
|
|
51
|
+
modulationIndex: 24,
|
|
52
|
+
resonance: 4000,
|
|
53
|
+
octaves: 1.2
|
|
54
|
+
}).connect(hatGain);
|
|
55
|
+
|
|
56
|
+
// --- BASS — MonoSynth with filter envelope ---
|
|
57
|
+
const bassGain = new Tone.Gain(0.7).connect(masterGain);
|
|
58
|
+
const bass = new Tone.MonoSynth({
|
|
59
|
+
oscillator: { type: "sawtooth" },
|
|
60
|
+
filter: { Q: 2, type: "lowpass", rolloff: -12 },
|
|
61
|
+
filterEnvelope: {
|
|
62
|
+
attack: 0.01, decay: 0.2, sustain: 0.4, release: 0.3,
|
|
63
|
+
baseFrequency: 120, octaves: 1.5
|
|
64
|
+
},
|
|
65
|
+
envelope: { attack: 0.01, decay: 0.15, sustain: 0.7, release: 0.3 }
|
|
66
|
+
}).connect(bassGain);
|
|
67
|
+
|
|
68
|
+
// --- SOUL PAD — warm PolySynth, slow attack ---
|
|
69
|
+
const padVerb = new Tone.Reverb({ decay: 3.5, wet: 0.5 }).connect(masterGain);
|
|
70
|
+
const padGain = new Tone.Gain(0.35).connect(padVerb);
|
|
71
|
+
const pad = new Tone.PolySynth(Tone.Synth, {
|
|
72
|
+
oscillator: { type: "triangle" },
|
|
73
|
+
envelope: { attack: 0.6, decay: 0.5, sustain: 0.7, release: 2.0 }
|
|
74
|
+
}).connect(padGain);
|
|
75
|
+
|
|
76
|
+
// --- KICK PATTERN — beat 1, "and" of 2, beat 3 (classic boom bap) ---
|
|
77
|
+
// 16-step grid: positions 0, 6, 8
|
|
78
|
+
for (let b = 0; b < numBars; b++) {
|
|
79
|
+
[0, 6, 8].forEach(step => {
|
|
80
|
+
kick.triggerAttackRelease("C1", beat * 0.5, b * bar + step * s16);
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// --- SNARE — strictly beats 2 and 4 (steps 4 and 12) ---
|
|
85
|
+
for (let b = 0; b < numBars; b++) {
|
|
86
|
+
[4, 12].forEach(step => {
|
|
87
|
+
snare.triggerAttackRelease(beat * 0.5, b * bar + step * s16);
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// --- HI-HAT — all 16 steps per bar, velocity variation adds humanity ---
|
|
92
|
+
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];
|
|
93
|
+
for (let b = 0; b < numBars; b++) {
|
|
94
|
+
for (let s = 0; s < 16; s++) {
|
|
95
|
+
hat.triggerAttackRelease(s16 * 0.8, b * bar + s * s16, hatVels[s]);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// --- BASS LINE — Fm vamp: 2-bar phrase played twice ---
|
|
100
|
+
// phrase repeats at bars 0-1 and bars 2-3
|
|
101
|
+
const bassPhrase = [
|
|
102
|
+
{ step: 0, note: "F1", dur: beat },
|
|
103
|
+
{ step: 4, note: "F1", dur: beat * 0.5 },
|
|
104
|
+
{ step: 6, note: "C2", dur: beat * 0.5 },
|
|
105
|
+
{ step: 8, note: "Eb2", dur: beat * 0.5 },
|
|
106
|
+
{ step: 10, note: "D2", dur: beat * 0.5 },
|
|
107
|
+
{ step: 12, note: "C2", dur: beat },
|
|
108
|
+
{ step: 16, note: "Bb1", dur: beat },
|
|
109
|
+
{ step: 20, note: "Bb1", dur: beat * 0.5 },
|
|
110
|
+
{ step: 22, note: "F1", dur: beat * 0.5 },
|
|
111
|
+
{ step: 24, note: "Ab1", dur: beat * 0.5 },
|
|
112
|
+
{ step: 26, note: "G1", dur: beat * 0.5 },
|
|
113
|
+
{ step: 28, note: "F1", dur: beat },
|
|
114
|
+
];
|
|
115
|
+
for (let phrase = 0; phrase < 2; phrase++) {
|
|
116
|
+
bassPhrase.forEach(({ step, note, dur }) => {
|
|
117
|
+
bass.triggerAttackRelease(note, dur, phrase * 2 * bar + step * s16);
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// --- SOUL PAD — Fm7 bars 0-1, Bbm7 bars 2-3 ---
|
|
122
|
+
pad.triggerAttackRelease(["F3","Ab3","C4","Eb4"], bar * 2, 0);
|
|
123
|
+
pad.triggerAttackRelease(["Bb2","Db3","F3","Ab3"], bar * 2, bar * 2);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
main();
|
|
127
|
+
</script>
|
|
128
|
+
</body>
|
|
129
|
+
</html>
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: audio-house
|
|
3
|
+
description: Chicago/deep house — 4-on-the-floor kick, clap on 2 and 4, off-beat hi-hat, warm piano chord stabs, bass following the kick. Groovy and soulful.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# TuneFrames — House
|
|
7
|
+
|
|
8
|
+
## Genre Profile
|
|
9
|
+
- BPM range: 120–128
|
|
10
|
+
- Key characteristics: 4-on-the-floor kick, clap strictly on beats 2 and 4, off-beat open hi-hat on the "and" of every beat, warm chord stabs (7ths and 9ths), bass line locked to kick
|
|
11
|
+
- Typical instruments: MembraneSynth (kick), NoiseSynth (clap), MetalSynth (hi-hat), PolySynth (piano stabs), MonoSynth (bass)
|
|
12
|
+
- Mood: Warm, groovy, hypnotic, soulful, uplifting
|
|
13
|
+
|
|
14
|
+
## Core Pattern
|
|
15
|
+
|
|
16
|
+
```js
|
|
17
|
+
// Chicago House — 4/4 at 124 BPM
|
|
18
|
+
// Kick: every beat (1, 2, 3, 4)
|
|
19
|
+
// Clap: beats 2 and 4
|
|
20
|
+
// Hi-hat: off-beat 8th notes ("and" of each beat)
|
|
21
|
+
// Piano stab: 2-bar chord loop with 7th chords
|
|
22
|
+
// Bass: short punchy notes on kick hits + off-beat fills
|
|
23
|
+
|
|
24
|
+
const kick = new Tone.MembraneSynth({
|
|
25
|
+
pitchDecay: 0.05,
|
|
26
|
+
octaves: 6,
|
|
27
|
+
envelope: { attack: 0.001, decay: 0.3, sustain: 0, release: 0.1 }
|
|
28
|
+
}).toDestination();
|
|
29
|
+
|
|
30
|
+
const clap = new Tone.NoiseSynth({
|
|
31
|
+
noise: { type: "white" },
|
|
32
|
+
envelope: { attack: 0.001, decay: 0.12, sustain: 0, release: 0.05 }
|
|
33
|
+
}).toDestination();
|
|
34
|
+
|
|
35
|
+
// Reverb on clap — classic house sound
|
|
36
|
+
const clapReverb = new Tone.Reverb({ decay: 2.5, wet: 0.55 }).toDestination();
|
|
37
|
+
clap.connect(clapReverb);
|
|
38
|
+
|
|
39
|
+
// 16-step kick: 4 on the floor
|
|
40
|
+
new Tone.Sequence((time, val) => {
|
|
41
|
+
if (val) kick.triggerAttackRelease("C1", "8n", time);
|
|
42
|
+
}, ["C1", null, null, null, "C1", null, null, null,
|
|
43
|
+
"C1", null, null, null, "C1", null, null, null], "16n").start(0);
|
|
44
|
+
|
|
45
|
+
// Clap on 2 and 4 (steps 4 and 12 in 16-step)
|
|
46
|
+
new Tone.Sequence((time, val) => {
|
|
47
|
+
if (val) clap.triggerAttackRelease("16n", time);
|
|
48
|
+
}, [null, null, null, null, 1, null, null, null,
|
|
49
|
+
null, null, null, null, 1, null, null, null], "16n").start(0);
|
|
50
|
+
|
|
51
|
+
// Off-beat hi-hat (every other 8th note)
|
|
52
|
+
new Tone.Sequence((time, val) => {
|
|
53
|
+
if (val) hat.triggerAttackRelease("16n", time, 0.6);
|
|
54
|
+
}, [null, null, 1, null, null, null, 1, null,
|
|
55
|
+
null, null, 1, null, null, null, 1, null], "16n").start(0);
|
|
56
|
+
|
|
57
|
+
Tone.Transport.bpm.value = 124;
|
|
58
|
+
Tone.Transport.start();
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Instrument Configuration
|
|
62
|
+
|
|
63
|
+
```js
|
|
64
|
+
// Kick — warm, slightly softer than techno
|
|
65
|
+
const kick = new Tone.MembraneSynth({
|
|
66
|
+
pitchDecay: 0.05,
|
|
67
|
+
octaves: 6,
|
|
68
|
+
volume: 0,
|
|
69
|
+
envelope: { attack: 0.001, decay: 0.28, sustain: 0, release: 0.1 }
|
|
70
|
+
}).toDestination();
|
|
71
|
+
|
|
72
|
+
// Clap — snappy noise with heavy reverb tail
|
|
73
|
+
const clapVerb = new Tone.Reverb({ decay: 2.2, wet: 0.5 }).toDestination();
|
|
74
|
+
const clap = new Tone.NoiseSynth({
|
|
75
|
+
noise: { type: "white" },
|
|
76
|
+
envelope: { attack: 0.001, decay: 0.1, sustain: 0, release: 0.04 },
|
|
77
|
+
volume: -4
|
|
78
|
+
}).connect(clapVerb);
|
|
79
|
+
|
|
80
|
+
// Hi-hat — open, airy metallic
|
|
81
|
+
const hat = new Tone.MetalSynth({
|
|
82
|
+
frequency: 300, harmonicity: 3.1, modulationIndex: 16,
|
|
83
|
+
resonance: 3500, octaves: 1.2,
|
|
84
|
+
envelope: { attack: 0.001, decay: 0.08, release: 0.02 },
|
|
85
|
+
volume: -10
|
|
86
|
+
}).toDestination();
|
|
87
|
+
|
|
88
|
+
// Piano stab — warm PolySynth, major 7ths
|
|
89
|
+
const stabChorus = new Tone.Chorus({ frequency: 3, depth: 0.4, wet: 0.3 }).toDestination();
|
|
90
|
+
const stabVerb = new Tone.Reverb({ decay: 1.8, wet: 0.25 }).connect(stabChorus);
|
|
91
|
+
const piano = new Tone.PolySynth(Tone.Synth, {
|
|
92
|
+
oscillator: { type: "triangle" },
|
|
93
|
+
envelope: { attack: 0.01, decay: 0.4, sustain: 0.1, release: 0.6 },
|
|
94
|
+
volume: -8
|
|
95
|
+
}).connect(stabVerb);
|
|
96
|
+
|
|
97
|
+
// Bass — punchy MonoSynth, follows kick
|
|
98
|
+
const bass = new Tone.MonoSynth({
|
|
99
|
+
oscillator: { type: "sawtooth" },
|
|
100
|
+
filter: { Q: 2, type: "lowpass", frequency: 600 },
|
|
101
|
+
filterEnvelope: { attack: 0.001, decay: 0.15, sustain: 0.1, release: 0.2,
|
|
102
|
+
baseFrequency: 100, octaves: 2 },
|
|
103
|
+
envelope: { attack: 0.001, decay: 0.2, sustain: 0.1, release: 0.15 },
|
|
104
|
+
volume: -4
|
|
105
|
+
}).toDestination();
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## Composition Structure
|
|
109
|
+
|
|
110
|
+
- **Bar 1-2:** Kick + hi-hat only — establish 4-on-floor groove
|
|
111
|
+
- **Bar 3-4:** Add clap on 2 and 4 — full drum feel
|
|
112
|
+
- **Bar 5-8:** Add bass — follows kick with short punchy notes
|
|
113
|
+
- **Bar 9-16:** Add piano stabs — 2-bar chord loop, minor 7ths or major 9ths
|
|
114
|
+
- **Bar 17-24:** Full groove — all elements, maybe add a secondary hi-hat accent
|
|
115
|
+
- **Breakdown (bar 25-32):** Drop kick and bass, keep hats + piano — build tension
|
|
116
|
+
- **Drop:** Kick returns hard — full energy re-entry
|
|
117
|
+
- **Outro:** Hi-hat fades, bass drops out, kick last
|
|
118
|
+
|
|
119
|
+
Chord vocabulary (deep house): Fm7 (F-Ab-C-Eb), Bbm9, Ebmaj7, Dbmaj7. Use minor 7ths for darkness, major 7ths for warmth.
|
|
120
|
+
|
|
121
|
+
## Example Variations
|
|
122
|
+
|
|
123
|
+
### 1 — Swung 16ths (shuffle feel)
|
|
124
|
+
```js
|
|
125
|
+
// Apply shuffle to the Transport for a more "human" groove
|
|
126
|
+
Tone.Transport.swing = 0.15;
|
|
127
|
+
Tone.Transport.swingSubdivision = "16n";
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### 2 — Rolling Bass (octave fills between kicks)
|
|
131
|
+
```js
|
|
132
|
+
// Bass hits on kick + fills in the gaps with octave jumps
|
|
133
|
+
const bassPattern = [
|
|
134
|
+
{ note: "A1", dur: "8n" }, { note: null },
|
|
135
|
+
{ note: "A2", dur: "16n" }, { note: null }, // octave fill
|
|
136
|
+
{ note: "A1", dur: "8n" }, { note: null },
|
|
137
|
+
{ note: "A1", dur: "16n" }, { note: "G1", dur: "16n" } // chromatic approach
|
|
138
|
+
];
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### 3 — Piano Chord Stab Rhythm Variation
|
|
142
|
+
```js
|
|
143
|
+
// Syncopated stab — off the beat for groove
|
|
144
|
+
// Hit on the "and" of beat 2 and beat 4
|
|
145
|
+
const stabSteps = [null, null, null, null, null, 1, null, null,
|
|
146
|
+
null, null, null, null, null, 1, null, null];
|
|
147
|
+
```
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<title>TuneFrames — House</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":124,"duration":"12s"}</div>
|
|
11
|
+
|
|
12
|
+
<script>
|
|
13
|
+
async function main() {
|
|
14
|
+
await Tone.start();
|
|
15
|
+
Tone.Transport.bpm.value = 124;
|
|
16
|
+
|
|
17
|
+
// --- MASTER BUS ---
|
|
18
|
+
const masterLimiter = new Tone.Limiter(-1).toDestination();
|
|
19
|
+
const masterGain = new Tone.Gain(0.88).connect(masterLimiter);
|
|
20
|
+
|
|
21
|
+
// --- KICK — warm 4-on-the-floor ---
|
|
22
|
+
const kickGain = new Tone.Gain(0.85).connect(masterGain);
|
|
23
|
+
const kick = new Tone.MembraneSynth({
|
|
24
|
+
pitchDecay: 0.055,
|
|
25
|
+
octaves: 6,
|
|
26
|
+
envelope: { attack: 0.001, decay: 0.28, sustain: 0, release: 0.1 }
|
|
27
|
+
}).connect(kickGain);
|
|
28
|
+
|
|
29
|
+
// --- CLAP — white noise with long reverb tail ---
|
|
30
|
+
const clapVerb = new Tone.Reverb({ decay: 2.4, wet: 0.52 }).connect(masterGain);
|
|
31
|
+
const clapGain = new Tone.Gain(0.55).connect(clapVerb);
|
|
32
|
+
const clap = new Tone.NoiseSynth({
|
|
33
|
+
noise: { type: "white" },
|
|
34
|
+
envelope: { attack: 0.001, decay: 0.11, sustain: 0, release: 0.04 }
|
|
35
|
+
}).connect(clapGain);
|
|
36
|
+
|
|
37
|
+
// --- HI-HAT — open off-beat, airy ---
|
|
38
|
+
const hatGain = new Tone.Gain(0.38).connect(masterGain);
|
|
39
|
+
const hat = new Tone.MetalSynth({
|
|
40
|
+
frequency: 300,
|
|
41
|
+
envelope: { attack: 0.001, decay: 0.09, release: 0.025 },
|
|
42
|
+
harmonicity: 3.1,
|
|
43
|
+
modulationIndex: 16,
|
|
44
|
+
resonance: 3600,
|
|
45
|
+
octaves: 1.2
|
|
46
|
+
}).connect(hatGain);
|
|
47
|
+
|
|
48
|
+
// --- PIANO STAB — PolySynth triangle, warm chord stabs ---
|
|
49
|
+
const stabVerb = new Tone.Reverb({ decay: 1.6, wet: 0.28 }).connect(masterGain);
|
|
50
|
+
const stabChorus = new Tone.Chorus({ frequency: 2.5, depth: 0.35, wet: 0.25 }).connect(stabVerb);
|
|
51
|
+
stabChorus.start();
|
|
52
|
+
const stabGain = new Tone.Gain(0.55).connect(stabChorus);
|
|
53
|
+
const piano = new Tone.PolySynth(Tone.Synth, {
|
|
54
|
+
oscillator: { type: "triangle" },
|
|
55
|
+
envelope: { attack: 0.008, decay: 0.35, sustain: 0.08, release: 0.7 },
|
|
56
|
+
volume: 0
|
|
57
|
+
}).connect(stabGain);
|
|
58
|
+
|
|
59
|
+
// --- BASS — punchy, follows kick ---
|
|
60
|
+
const bassGain = new Tone.Gain(0.75).connect(masterGain);
|
|
61
|
+
const bass = new Tone.MonoSynth({
|
|
62
|
+
oscillator: { type: "sawtooth" },
|
|
63
|
+
filter: { Q: 3, type: "lowpass", rolloff: -24 },
|
|
64
|
+
filterEnvelope: {
|
|
65
|
+
attack: 0.001, decay: 0.18, sustain: 0.1, release: 0.2,
|
|
66
|
+
baseFrequency: 90, octaves: 2.2
|
|
67
|
+
},
|
|
68
|
+
envelope: { attack: 0.001, decay: 0.22, sustain: 0.1, release: 0.15 },
|
|
69
|
+
volume: -2
|
|
70
|
+
}).connect(bassGain);
|
|
71
|
+
|
|
72
|
+
// --- SEQUENCES ---
|
|
73
|
+
|
|
74
|
+
// Kick: strict 4-on-the-floor
|
|
75
|
+
const kickSeq = new Tone.Sequence((time) => {
|
|
76
|
+
kick.triggerAttackRelease("C1", "8n", time);
|
|
77
|
+
}, [1, null, null, null, 1, null, null, null,
|
|
78
|
+
1, null, null, null, 1, null, null, null], "16n");
|
|
79
|
+
kickSeq.start(0);
|
|
80
|
+
|
|
81
|
+
// Clap: beats 2 and 4 only
|
|
82
|
+
const clapSeq = new Tone.Sequence((time, val) => {
|
|
83
|
+
if (val) clap.triggerAttackRelease("16n", time);
|
|
84
|
+
}, [null, null, null, null, 1, null, null, null,
|
|
85
|
+
null, null, null, null, 1, null, null, null], "16n");
|
|
86
|
+
clapSeq.start(0);
|
|
87
|
+
|
|
88
|
+
// Hi-hat: off-beat 8th notes
|
|
89
|
+
const hatSeq = new Tone.Sequence((time, val) => {
|
|
90
|
+
if (val) hat.triggerAttackRelease("16n", time, 0.6);
|
|
91
|
+
}, [null, null, 1, null, null, null, 1, null,
|
|
92
|
+
null, null, 1, null, null, null, 1, null], "16n");
|
|
93
|
+
hatSeq.start(0);
|
|
94
|
+
|
|
95
|
+
// Bass: follows kick + syncopated fills
|
|
96
|
+
// F1 root following the groove
|
|
97
|
+
const bassPattern = [
|
|
98
|
+
"F1", null, null, null, "F1", null, null, "F1",
|
|
99
|
+
"F1", null, "Ab1", null, "F1", null, "Eb1", null
|
|
100
|
+
];
|
|
101
|
+
const bassSeq = new Tone.Sequence((time, note) => {
|
|
102
|
+
if (note) bass.triggerAttackRelease(note, "16n", time);
|
|
103
|
+
}, bassPattern, "16n");
|
|
104
|
+
bassSeq.start("2m"); // bass enters bar 3
|
|
105
|
+
|
|
106
|
+
// Piano stabs: Fm7 → Bbm7 → Ebmaj7 → Dbmaj7 (2-bar cycle)
|
|
107
|
+
// Deep house chord vocabulary
|
|
108
|
+
const chords = [
|
|
109
|
+
{ notes: ["F3", "Ab3", "C4", "Eb4"], time: "4m" }, // Fm7
|
|
110
|
+
{ notes: ["Bb2", "Db3", "F3", "Ab3"], time: "4m:2" }, // Bbm7
|
|
111
|
+
{ notes: ["Eb3", "G3", "Bb3", "D4"], time: "5m" }, // Ebmaj7
|
|
112
|
+
{ notes: ["Db3", "F3", "Ab3", "C4"], time: "5m:2" }, // Dbmaj7
|
|
113
|
+
// repeat
|
|
114
|
+
{ notes: ["F3", "Ab3", "C4", "Eb4"], time: "6m" },
|
|
115
|
+
{ notes: ["Bb2", "Db3", "F3", "Ab3"], time: "6m:2" },
|
|
116
|
+
{ notes: ["Eb3", "G3", "Bb3", "D4"], time: "7m" },
|
|
117
|
+
{ notes: ["Db3", "F3", "Ab3", "C4"], time: "7m:2" },
|
|
118
|
+
];
|
|
119
|
+
chords.forEach(({ notes, time }) => {
|
|
120
|
+
piano.triggerAttackRelease(notes, "4n", time);
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
main();
|
|
126
|
+
</script>
|
|
127
|
+
</body>
|
|
128
|
+
</html>
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: audio-indie-pop
|
|
3
|
+
description: Indie Pop — jangly pluck arpeggios through chorus/reverb, warm bass, steady kick-snare-hat groove. Vampire Weekend / Tame Impala feel. Major key or Dorian, bright and infectious.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# TuneFrames — Indie Pop
|
|
7
|
+
|
|
8
|
+
## Genre Profile
|
|
9
|
+
- BPM range: 115–140
|
|
10
|
+
- Key characteristics: Guitar-like arpeggio lines with short pluck envelope (triangle osc, fast decay, low sustain), warm bass on root and 5th, kick on beats 1+3, snare on 2+4, steady 8th-note hi-hat, lush chorus + reverb on guitar synth
|
|
11
|
+
- Typical instruments: PolySynth/Synth (guitar pluck), Synth/MonoSynth (bass), MembraneSynth (kick), NoiseSynth (snare, hat)
|
|
12
|
+
- Mood: Bright, infectious, slightly nostalgic, melodic, danceable
|
|
13
|
+
|
|
14
|
+
## Core Pattern
|
|
15
|
+
|
|
16
|
+
```js
|
|
17
|
+
// Indie Pop — 128 BPM, G major
|
|
18
|
+
// Chord progression: G - C - Em - D (4-bar loop)
|
|
19
|
+
// Guitar: 8th note arpeggios with pluck envelope
|
|
20
|
+
// Kick: beats 1 and 3 | Snare: beats 2 and 4 | Hat: 8th notes
|
|
21
|
+
|
|
22
|
+
Tone.Transport.bpm.value = 128;
|
|
23
|
+
|
|
24
|
+
// Effects
|
|
25
|
+
const reverb = new Tone.Reverb({ decay: 2.5, wet: 0.3 }).toDestination();
|
|
26
|
+
const chorus = new Tone.Chorus(3.5, 2.0, 0.6).connect(reverb);
|
|
27
|
+
chorus.start(); // REQUIRED — Chorus LFO must be started manually
|
|
28
|
+
|
|
29
|
+
// Guitar pluck: triangle oscillator, fast attack, short decay, minimal sustain
|
|
30
|
+
const guitar = new Tone.PolySynth(Tone.Synth, {
|
|
31
|
+
oscillator: { type: "triangle" },
|
|
32
|
+
envelope: { attack: 0.005, decay: 0.28, sustain: 0.06, release: 0.7 },
|
|
33
|
+
}).connect(chorus);
|
|
34
|
+
|
|
35
|
+
// 32-note arpeggio grid (8 notes × 4 bars = G, C, Em, D)
|
|
36
|
+
const arpGrid = [
|
|
37
|
+
"G3","B3","D4","G4","D4","B3","G3","B3", // G major
|
|
38
|
+
"C4","E4","G4","C5","G4","E4","C4","E4", // C major
|
|
39
|
+
"E3","G3","B3","E4","B3","G3","E3","G3", // E minor
|
|
40
|
+
"D3","F#3","A3","D4","A3","F#3","D3","F#3", // D major
|
|
41
|
+
];
|
|
42
|
+
let arpStep = 0;
|
|
43
|
+
const arpSeq = new Tone.Sequence((time) => {
|
|
44
|
+
guitar.triggerAttackRelease(arpGrid[arpStep++ % arpGrid.length], "8n", time);
|
|
45
|
+
}, new Array(8).fill(1), "8n").start(0);
|
|
46
|
+
|
|
47
|
+
// Kick: beats 1 and 3
|
|
48
|
+
new Tone.Sequence((time, val) => {
|
|
49
|
+
if (val) kick.triggerAttackRelease("C1", "8n", time);
|
|
50
|
+
}, ["C1",null,null,null,null,null,null,null,"C1",null,null,null,null,null,null,null], "16n").start(0);
|
|
51
|
+
|
|
52
|
+
// Snare: beats 2 and 4
|
|
53
|
+
new Tone.Sequence((time, val) => {
|
|
54
|
+
if (val) snare.triggerAttackRelease("8n", time);
|
|
55
|
+
}, [null,null,null,null,1,null,null,null,null,null,null,null,1,null,null,null], "16n").start(0);
|
|
56
|
+
|
|
57
|
+
// Hat: 8th notes, quiet
|
|
58
|
+
new Tone.Sequence((time, val) => {
|
|
59
|
+
if (val) hat.triggerAttackRelease("16n", time, 0.5);
|
|
60
|
+
}, [1,null,1,null,1,null,1,null,1,null,1,null,1,null,1,null], "16n").start(0);
|
|
61
|
+
|
|
62
|
+
Tone.Transport.start();
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## Instrument Configuration
|
|
66
|
+
|
|
67
|
+
```js
|
|
68
|
+
// Guitar pluck — triangle oscillator is key (warmer than sawtooth, brighter than sine)
|
|
69
|
+
const guitarVerb = new Tone.Reverb({ decay: 2.5, wet: 0.3 }).toDestination();
|
|
70
|
+
const guitarChorus = new Tone.Chorus({ frequency: 3.5, delayTime: 2, depth: 0.6, wet: 0.5 }).connect(guitarVerb);
|
|
71
|
+
guitarChorus.start();
|
|
72
|
+
const guitar = new Tone.PolySynth(Tone.Synth, {
|
|
73
|
+
oscillator: { type: "triangle" },
|
|
74
|
+
envelope: { attack: 0.005, decay: 0.28, sustain: 0.06, release: 0.7 },
|
|
75
|
+
volume: -8
|
|
76
|
+
}).connect(guitarChorus);
|
|
77
|
+
|
|
78
|
+
// Bass — sine oscillator for warmth, gentle attack
|
|
79
|
+
const bassVerb = new Tone.Reverb({ decay: 0.6, wet: 0.1 }).toDestination();
|
|
80
|
+
const bass = new Tone.Synth({
|
|
81
|
+
oscillator: { type: "sine" },
|
|
82
|
+
envelope: { attack: 0.05, decay: 0.2, sustain: 0.7, release: 0.4 },
|
|
83
|
+
volume: -4
|
|
84
|
+
}).connect(bassVerb);
|
|
85
|
+
|
|
86
|
+
// Kick — less aggressive than techno, shorter pitch decay
|
|
87
|
+
const kickDist = new Tone.Distortion({ distortion: 0.1, wet: 0.3 }).toDestination();
|
|
88
|
+
const kick = new Tone.MembraneSynth({
|
|
89
|
+
pitchDecay: 0.06, octaves: 5,
|
|
90
|
+
envelope: { attack: 0.001, decay: 0.3, sustain: 0, release: 0.1 },
|
|
91
|
+
volume: -2
|
|
92
|
+
}).connect(kickDist);
|
|
93
|
+
|
|
94
|
+
// Snare — white noise, moderate reverb tail (less than house, more presence)
|
|
95
|
+
const snareVerb = new Tone.Reverb({ decay: 0.8, wet: 0.35 }).toDestination();
|
|
96
|
+
const snare = new Tone.NoiseSynth({
|
|
97
|
+
noise: { type: "white" },
|
|
98
|
+
envelope: { attack: 0.001, decay: 0.15, sustain: 0, release: 0.05 },
|
|
99
|
+
volume: -8
|
|
100
|
+
}).connect(snareVerb);
|
|
101
|
+
|
|
102
|
+
// Hi-hat — highpass filtered noise, quiet
|
|
103
|
+
const hatFilter = new Tone.Filter(7000, "highpass").toDestination();
|
|
104
|
+
const hat = new Tone.NoiseSynth({
|
|
105
|
+
noise: { type: "white" },
|
|
106
|
+
envelope: { attack: 0.001, decay: 0.05, sustain: 0, release: 0.01 },
|
|
107
|
+
volume: -16
|
|
108
|
+
}).connect(hatFilter);
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
## Composition Structure
|
|
112
|
+
|
|
113
|
+
- **Bars 1–2:** Guitar arpeggio + hi-hat only — establish the melodic hook
|
|
114
|
+
- **Bars 3–4:** Add kick and snare — drums lock in the groove
|
|
115
|
+
- **Bars 5–8:** Add bass — root + 5th pattern follows chord changes
|
|
116
|
+
- **Bars 9–16:** Full band, all elements — the main verse/chorus loop
|
|
117
|
+
- **Variation:** Add feedback delay on guitar (8th note, 25% wet) for extra spaciousness
|
|
118
|
+
- **Outro:** Drop drums, let guitar arpeggio ring out with reverb tail
|
|
119
|
+
|
|
120
|
+
Chord vocabulary: I–V–vi–IV in any major key (G–D–Em–C is the "axis of awesome"). Dorian mode (e.g., Am–G) adds darkness while keeping the bright groove.
|
|
121
|
+
|
|
122
|
+
## Example Variations
|
|
123
|
+
|
|
124
|
+
### 1 — Dorian Mode (darker, Am sound)
|
|
125
|
+
```js
|
|
126
|
+
// A Dorian: A B C D E F# G — common in Vampire Weekend
|
|
127
|
+
const arpGrid = [
|
|
128
|
+
"A3","C4","E4","A4","E4","C4","A3","C4", // Am
|
|
129
|
+
"G3","B3","D4","G4","D4","B3","G3","B3", // G major
|
|
130
|
+
"D3","F#3","A3","D4","A3","F#3","D3","F#3", // D major
|
|
131
|
+
"E3","G3","B3","E4","B3","G3","E3","G3", // Em
|
|
132
|
+
];
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
### 2 — 16th-note arpeggio (Math rock / faster feel)
|
|
136
|
+
```js
|
|
137
|
+
// Double the arpeggio speed — 16 notes per bar instead of 8
|
|
138
|
+
const arpGrid = ["G3","B3","D4","G4","D4","B3","G3","B3","D4","G4","B3","D4","G4","B3","D4","G4"]; // G bar
|
|
139
|
+
let arpStep = 0;
|
|
140
|
+
new Tone.Sequence((time) => {
|
|
141
|
+
guitar.triggerAttackRelease(arpGrid[arpStep++ % arpGrid.length], "16n", time);
|
|
142
|
+
}, new Array(16).fill(1), "16n").start(0);
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
### 3 — Add feedback delay for shimmer
|
|
146
|
+
```js
|
|
147
|
+
// Guitar → delay → chorus → reverb
|
|
148
|
+
const delay = new Tone.FeedbackDelay({ delayTime: "8n", feedback: 0.28, wet: 0.22 });
|
|
149
|
+
// Insert: guitar.connect(delay); delay.connect(guitarChorus);
|
|
150
|
+
```
|