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,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
|
+
```
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<title>TuneFrames — Indie Pop</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":128,"duration":"12s"}</div>
|
|
11
|
+
|
|
12
|
+
<script>
|
|
13
|
+
async function main() {
|
|
14
|
+
await Tone.start();
|
|
15
|
+
Tone.Transport.bpm.value = 128;
|
|
16
|
+
|
|
17
|
+
// --- MASTER BUS ---
|
|
18
|
+
const masterLimiter = new Tone.Limiter(-1).toDestination();
|
|
19
|
+
const masterGain = new Tone.Gain(0.85).connect(masterLimiter);
|
|
20
|
+
|
|
21
|
+
// --- GUITAR — jangly pluck through chorus + reverb ---
|
|
22
|
+
const guitarVerb = new Tone.Reverb({ decay: 2.5, wet: 0.35 }).connect(masterGain);
|
|
23
|
+
const guitarChorus = new Tone.Chorus({ frequency: 3.5, delayTime: 2, depth: 0.6, wet: 0.5 }).connect(guitarVerb);
|
|
24
|
+
guitarChorus.start();
|
|
25
|
+
const guitarGain = new Tone.Gain(0.55).connect(guitarChorus);
|
|
26
|
+
const guitar = new Tone.PolySynth(Tone.Synth, {
|
|
27
|
+
oscillator: { type: "triangle" },
|
|
28
|
+
envelope: { attack: 0.005, decay: 0.28, sustain: 0.06, release: 0.7 },
|
|
29
|
+
volume: 0
|
|
30
|
+
}).connect(guitarGain);
|
|
31
|
+
|
|
32
|
+
// --- BASS — warm sine, root movement ---
|
|
33
|
+
const bassVerb = new Tone.Reverb({ decay: 0.6, wet: 0.1 }).connect(masterGain);
|
|
34
|
+
const bassGain = new Tone.Gain(0.65).connect(bassVerb);
|
|
35
|
+
const bass = new Tone.Synth({
|
|
36
|
+
oscillator: { type: "sine" },
|
|
37
|
+
envelope: { attack: 0.05, decay: 0.2, sustain: 0.7, release: 0.4 },
|
|
38
|
+
volume: 0
|
|
39
|
+
}).connect(bassGain);
|
|
40
|
+
|
|
41
|
+
// --- KICK — punchy but not hard ---
|
|
42
|
+
const kickDist = new Tone.Distortion({ distortion: 0.1, wet: 0.3 }).connect(masterGain);
|
|
43
|
+
const kickGain = new Tone.Gain(0.75).connect(kickDist);
|
|
44
|
+
const kick = new Tone.MembraneSynth({
|
|
45
|
+
pitchDecay: 0.06,
|
|
46
|
+
octaves: 5,
|
|
47
|
+
envelope: { attack: 0.001, decay: 0.3, sustain: 0, release: 0.1 }
|
|
48
|
+
}).connect(kickGain);
|
|
49
|
+
|
|
50
|
+
// --- SNARE — white noise with moderate reverb ---
|
|
51
|
+
const snareVerb = new Tone.Reverb({ decay: 0.9, wet: 0.38 }).connect(masterGain);
|
|
52
|
+
const snareGain = new Tone.Gain(0.45).connect(snareVerb);
|
|
53
|
+
const snare = new Tone.NoiseSynth({
|
|
54
|
+
noise: { type: "white" },
|
|
55
|
+
envelope: { attack: 0.001, decay: 0.15, sustain: 0, release: 0.05 }
|
|
56
|
+
}).connect(snareGain);
|
|
57
|
+
|
|
58
|
+
// --- HI-HAT — highpass filtered, airy ---
|
|
59
|
+
const hatFilter = new Tone.Filter(7000, "highpass").connect(masterGain);
|
|
60
|
+
const hatGain = new Tone.Gain(0.22).connect(hatFilter);
|
|
61
|
+
const hat = new Tone.NoiseSynth({
|
|
62
|
+
noise: { type: "white" },
|
|
63
|
+
envelope: { attack: 0.001, decay: 0.05, sustain: 0, release: 0.01 }
|
|
64
|
+
}).connect(hatGain);
|
|
65
|
+
|
|
66
|
+
// --- ARPEGGIO — 4-bar G–C–Em–D chord cycle, 8th note grid ---
|
|
67
|
+
// 8 notes per bar × 4 bars = 32-note grid, loops seamlessly
|
|
68
|
+
const arpGrid = [
|
|
69
|
+
// Bar 0: G major
|
|
70
|
+
"G3","B3","D4","G4","D4","B3","G3","B3",
|
|
71
|
+
// Bar 1: C major
|
|
72
|
+
"C4","E4","G4","C5","G4","E4","C4","E4",
|
|
73
|
+
// Bar 2: E minor
|
|
74
|
+
"E3","G3","B3","E4","B3","G3","E3","G3",
|
|
75
|
+
// Bar 3: D major
|
|
76
|
+
"D3","F#3","A3","D4","A3","F#3","D3","F#3",
|
|
77
|
+
];
|
|
78
|
+
let arpStep = 0;
|
|
79
|
+
const arpSeq = new Tone.Sequence((time) => {
|
|
80
|
+
guitar.triggerAttackRelease(arpGrid[arpStep % arpGrid.length], "8n", time);
|
|
81
|
+
arpStep++;
|
|
82
|
+
}, new Array(8).fill(1), "8n");
|
|
83
|
+
arpSeq.start(0);
|
|
84
|
+
|
|
85
|
+
// --- BASS — root + 5th pattern per chord, enters bar 3 ---
|
|
86
|
+
const bassPart = new Tone.Part((time, note) => {
|
|
87
|
+
bass.triggerAttackRelease(note, "4n", time);
|
|
88
|
+
}, [
|
|
89
|
+
["0:0:0","G2"], ["0:2:0","D2"],
|
|
90
|
+
["1:0:0","C2"], ["1:2:0","G2"],
|
|
91
|
+
["2:0:0","E2"], ["2:2:0","B2"],
|
|
92
|
+
["3:0:0","D2"], ["3:2:0","A2"],
|
|
93
|
+
]);
|
|
94
|
+
bassPart.loopEnd = "4m";
|
|
95
|
+
bassPart.loop = true;
|
|
96
|
+
bassPart.start("2m");
|
|
97
|
+
|
|
98
|
+
// --- KICK — beats 1 and 3, enters bar 3 ---
|
|
99
|
+
const kickSeq = new Tone.Sequence((time, val) => {
|
|
100
|
+
if (val) kick.triggerAttackRelease("C1", "8n", time);
|
|
101
|
+
}, ["C1",null,null,null,null,null,null,null,"C1",null,null,null,null,null,null,null], "16n");
|
|
102
|
+
kickSeq.start("2m");
|
|
103
|
+
|
|
104
|
+
// --- SNARE — beats 2 and 4, enters bar 3 ---
|
|
105
|
+
const snareSeq = new Tone.Sequence((time, val) => {
|
|
106
|
+
if (val) snare.triggerAttackRelease("8n", time);
|
|
107
|
+
}, [null,null,null,null,1,null,null,null,null,null,null,null,1,null,null,null], "16n");
|
|
108
|
+
snareSeq.start("2m");
|
|
109
|
+
|
|
110
|
+
// --- HI-HAT — 8th notes throughout ---
|
|
111
|
+
const hatSeq = new Tone.Sequence((time, val) => {
|
|
112
|
+
if (val) hat.triggerAttackRelease("16n", time, 0.5);
|
|
113
|
+
}, [1,null,1,null,1,null,1,null,1,null,1,null,1,null,1,null], "16n");
|
|
114
|
+
hatSeq.start(0);
|
|
115
|
+
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
main();
|
|
119
|
+
</script>
|
|
120
|
+
</body>
|
|
121
|
+
</html>
|