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,11 @@
|
|
|
1
|
+
<!-- TuneFrames preset: reverb-warm
|
|
2
|
+
Long reverb chain. Paste before your instruments. -->
|
|
3
|
+
<script>
|
|
4
|
+
// Reverb: long decay, high wet — lush, ambient
|
|
5
|
+
const verb = new Tone.Reverb({
|
|
6
|
+
decay: 4,
|
|
7
|
+
wet: 0.75
|
|
8
|
+
}).toDestination();
|
|
9
|
+
// Call .generate() to build the impulse response (runs at composition start)
|
|
10
|
+
verb.generate();
|
|
11
|
+
</script>
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": "1.0.0",
|
|
3
|
+
"cdn": {
|
|
4
|
+
"gleitz_fluidr3_gm": {
|
|
5
|
+
"name": "gleitz FluidR3_GM",
|
|
6
|
+
"baseUrlTemplate": "https://gleitz.github.io/midi-js-soundfonts/FluidR3_GM/{instrument}-mp3/",
|
|
7
|
+
"format": "mp3",
|
|
8
|
+
"noteNameFormat": "Sharps written with 's' suffix (e.g. F#4 = Fs4, C#3 = Cs3)",
|
|
9
|
+
"license": "Public domain (FluidR3_GM SoundFont)",
|
|
10
|
+
"repo": "https://github.com/gleitz/midi-js-soundfonts"
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
"instruments": {
|
|
14
|
+
"acoustic_grand_piano": {
|
|
15
|
+
"cdn": "gleitz_fluidr3_gm",
|
|
16
|
+
"baseUrl": "https://gleitz.github.io/midi-js-soundfonts/FluidR3_GM/acoustic_grand_piano-mp3/",
|
|
17
|
+
"category": "piano",
|
|
18
|
+
"range": { "low": "A0", "high": "C8" },
|
|
19
|
+
"urls": {
|
|
20
|
+
"A0": "A0.mp3",
|
|
21
|
+
"C1": "C1.mp3",
|
|
22
|
+
"Ds1": "Ds1.mp3",
|
|
23
|
+
"Fs1": "Fs1.mp3",
|
|
24
|
+
"A1": "A1.mp3",
|
|
25
|
+
"C2": "C2.mp3",
|
|
26
|
+
"Ds2": "Ds2.mp3",
|
|
27
|
+
"Fs2": "Fs2.mp3",
|
|
28
|
+
"A2": "A2.mp3",
|
|
29
|
+
"C3": "C3.mp3",
|
|
30
|
+
"Ds3": "Ds3.mp3",
|
|
31
|
+
"Fs3": "Fs3.mp3",
|
|
32
|
+
"A3": "A3.mp3",
|
|
33
|
+
"C4": "C4.mp3",
|
|
34
|
+
"Ds4": "Ds4.mp3",
|
|
35
|
+
"Fs4": "Fs4.mp3",
|
|
36
|
+
"A4": "A4.mp3",
|
|
37
|
+
"C5": "C5.mp3",
|
|
38
|
+
"Ds5": "Ds5.mp3",
|
|
39
|
+
"Fs5": "Fs5.mp3",
|
|
40
|
+
"A5": "A5.mp3",
|
|
41
|
+
"C6": "C6.mp3",
|
|
42
|
+
"Ds6": "Ds6.mp3",
|
|
43
|
+
"Fs6": "Fs6.mp3",
|
|
44
|
+
"A6": "A6.mp3",
|
|
45
|
+
"C7": "C7.mp3",
|
|
46
|
+
"Ds7": "Ds7.mp3",
|
|
47
|
+
"Fs7": "Fs7.mp3",
|
|
48
|
+
"A7": "A7.mp3",
|
|
49
|
+
"C8": "C8.mp3"
|
|
50
|
+
},
|
|
51
|
+
"notes": "Full 88-key range. Tone.Sampler pitch-shifts from nearest sample automatically."
|
|
52
|
+
},
|
|
53
|
+
"acoustic_bass": {
|
|
54
|
+
"cdn": "gleitz_fluidr3_gm",
|
|
55
|
+
"baseUrl": "https://gleitz.github.io/midi-js-soundfonts/FluidR3_GM/acoustic_bass-mp3/",
|
|
56
|
+
"category": "bass",
|
|
57
|
+
"range": { "low": "C1", "high": "G4" },
|
|
58
|
+
"urls": {
|
|
59
|
+
"C1": "C1.mp3",
|
|
60
|
+
"Ds1": "Ds1.mp3",
|
|
61
|
+
"Fs1": "Fs1.mp3",
|
|
62
|
+
"A1": "A1.mp3",
|
|
63
|
+
"C2": "C2.mp3",
|
|
64
|
+
"Ds2": "Ds2.mp3",
|
|
65
|
+
"Fs2": "Fs2.mp3",
|
|
66
|
+
"A2": "A2.mp3",
|
|
67
|
+
"C3": "C3.mp3",
|
|
68
|
+
"Ds3": "Ds3.mp3",
|
|
69
|
+
"Fs3": "Fs3.mp3",
|
|
70
|
+
"A3": "A3.mp3",
|
|
71
|
+
"C4": "C4.mp3",
|
|
72
|
+
"Fs4": "Fs4.mp3"
|
|
73
|
+
},
|
|
74
|
+
"notes": "Upright/double bass. Best in C1–C3 range for natural timbre."
|
|
75
|
+
},
|
|
76
|
+
"string_ensemble_1": {
|
|
77
|
+
"cdn": "gleitz_fluidr3_gm",
|
|
78
|
+
"baseUrl": "https://gleitz.github.io/midi-js-soundfonts/FluidR3_GM/string_ensemble_1-mp3/",
|
|
79
|
+
"category": "strings",
|
|
80
|
+
"range": { "low": "C2", "high": "C7" },
|
|
81
|
+
"urls": {
|
|
82
|
+
"C2": "C2.mp3",
|
|
83
|
+
"Ds2": "Ds2.mp3",
|
|
84
|
+
"Fs2": "Fs2.mp3",
|
|
85
|
+
"A2": "A2.mp3",
|
|
86
|
+
"C3": "C3.mp3",
|
|
87
|
+
"Ds3": "Ds3.mp3",
|
|
88
|
+
"Fs3": "Fs3.mp3",
|
|
89
|
+
"A3": "A3.mp3",
|
|
90
|
+
"C4": "C4.mp3",
|
|
91
|
+
"Ds4": "Ds4.mp3",
|
|
92
|
+
"Fs4": "Fs4.mp3",
|
|
93
|
+
"A4": "A4.mp3",
|
|
94
|
+
"C5": "C5.mp3",
|
|
95
|
+
"Ds5": "Ds5.mp3",
|
|
96
|
+
"Fs5": "Fs5.mp3",
|
|
97
|
+
"A5": "A5.mp3",
|
|
98
|
+
"C6": "C6.mp3",
|
|
99
|
+
"Ds6": "Ds6.mp3",
|
|
100
|
+
"Fs6": "Fs6.mp3",
|
|
101
|
+
"A6": "A6.mp3",
|
|
102
|
+
"C7": "C7.mp3"
|
|
103
|
+
},
|
|
104
|
+
"notes": "Lush string section. Long note durations ('1n', '2n') sound most natural."
|
|
105
|
+
},
|
|
106
|
+
"brass_section": {
|
|
107
|
+
"cdn": "gleitz_fluidr3_gm",
|
|
108
|
+
"baseUrl": "https://gleitz.github.io/midi-js-soundfonts/FluidR3_GM/brass_section-mp3/",
|
|
109
|
+
"category": "brass",
|
|
110
|
+
"range": { "low": "C2", "high": "C6" },
|
|
111
|
+
"urls": {
|
|
112
|
+
"C2": "C2.mp3",
|
|
113
|
+
"Ds2": "Ds2.mp3",
|
|
114
|
+
"Fs2": "Fs2.mp3",
|
|
115
|
+
"A2": "A2.mp3",
|
|
116
|
+
"C3": "C3.mp3",
|
|
117
|
+
"Ds3": "Ds3.mp3",
|
|
118
|
+
"Fs3": "Fs3.mp3",
|
|
119
|
+
"A3": "A3.mp3",
|
|
120
|
+
"C4": "C4.mp3",
|
|
121
|
+
"Ds4": "Ds4.mp3",
|
|
122
|
+
"Fs4": "Fs4.mp3",
|
|
123
|
+
"A4": "A4.mp3",
|
|
124
|
+
"C5": "C5.mp3",
|
|
125
|
+
"Ds5": "Ds5.mp3",
|
|
126
|
+
"Fs5": "Fs5.mp3",
|
|
127
|
+
"A5": "A5.mp3",
|
|
128
|
+
"C6": "C6.mp3"
|
|
129
|
+
},
|
|
130
|
+
"notes": "Big brass stabs and fanfares. Works best for short, punchy note durations ('8n', '4n')."
|
|
131
|
+
},
|
|
132
|
+
"acoustic_guitar_nylon": {
|
|
133
|
+
"cdn": "gleitz_fluidr3_gm",
|
|
134
|
+
"baseUrl": "https://gleitz.github.io/midi-js-soundfonts/FluidR3_GM/acoustic_guitar_nylon-mp3/",
|
|
135
|
+
"category": "guitar",
|
|
136
|
+
"range": { "low": "E2", "high": "D6" },
|
|
137
|
+
"urls": {
|
|
138
|
+
"Fs2": "Fs2.mp3",
|
|
139
|
+
"A2": "A2.mp3",
|
|
140
|
+
"C3": "C3.mp3",
|
|
141
|
+
"Ds3": "Ds3.mp3",
|
|
142
|
+
"Fs3": "Fs3.mp3",
|
|
143
|
+
"A3": "A3.mp3",
|
|
144
|
+
"C4": "C4.mp3",
|
|
145
|
+
"Ds4": "Ds4.mp3",
|
|
146
|
+
"Fs4": "Fs4.mp3",
|
|
147
|
+
"A4": "A4.mp3",
|
|
148
|
+
"C5": "C5.mp3",
|
|
149
|
+
"Ds5": "Ds5.mp3",
|
|
150
|
+
"Fs5": "Fs5.mp3",
|
|
151
|
+
"A5": "A5.mp3",
|
|
152
|
+
"C6": "C6.mp3"
|
|
153
|
+
},
|
|
154
|
+
"notes": "Classical nylon-string guitar. Natural decay — use release or short durations."
|
|
155
|
+
},
|
|
156
|
+
"vibraphone": {
|
|
157
|
+
"cdn": "gleitz_fluidr3_gm",
|
|
158
|
+
"baseUrl": "https://gleitz.github.io/midi-js-soundfonts/FluidR3_GM/vibraphone-mp3/",
|
|
159
|
+
"category": "mallet",
|
|
160
|
+
"range": { "low": "C3", "high": "C7" },
|
|
161
|
+
"urls": {
|
|
162
|
+
"C3": "C3.mp3",
|
|
163
|
+
"Ds3": "Ds3.mp3",
|
|
164
|
+
"Fs3": "Fs3.mp3",
|
|
165
|
+
"A3": "A3.mp3",
|
|
166
|
+
"C4": "C4.mp3",
|
|
167
|
+
"Ds4": "Ds4.mp3",
|
|
168
|
+
"Fs4": "Fs4.mp3",
|
|
169
|
+
"A4": "A4.mp3",
|
|
170
|
+
"C5": "C5.mp3",
|
|
171
|
+
"Ds5": "Ds5.mp3",
|
|
172
|
+
"Fs5": "Fs5.mp3",
|
|
173
|
+
"A5": "A5.mp3",
|
|
174
|
+
"C6": "C6.mp3",
|
|
175
|
+
"Ds6": "Ds6.mp3",
|
|
176
|
+
"Fs6": "Fs6.mp3",
|
|
177
|
+
"A6": "A6.mp3",
|
|
178
|
+
"C7": "C7.mp3"
|
|
179
|
+
},
|
|
180
|
+
"notes": "Warm bell-like timbre. Pairs well with reverb for jazz/ambient contexts."
|
|
181
|
+
},
|
|
182
|
+
"flute": {
|
|
183
|
+
"cdn": "gleitz_fluidr3_gm",
|
|
184
|
+
"baseUrl": "https://gleitz.github.io/midi-js-soundfonts/FluidR3_GM/flute-mp3/",
|
|
185
|
+
"category": "woodwind",
|
|
186
|
+
"range": { "low": "C4", "high": "A7" },
|
|
187
|
+
"urls": {
|
|
188
|
+
"C4": "C4.mp3",
|
|
189
|
+
"Ds4": "Ds4.mp3",
|
|
190
|
+
"Fs4": "Fs4.mp3",
|
|
191
|
+
"A4": "A4.mp3",
|
|
192
|
+
"C5": "C5.mp3",
|
|
193
|
+
"Ds5": "Ds5.mp3",
|
|
194
|
+
"Fs5": "Fs5.mp3",
|
|
195
|
+
"A5": "A5.mp3",
|
|
196
|
+
"C6": "C6.mp3",
|
|
197
|
+
"Ds6": "Ds6.mp3",
|
|
198
|
+
"Fs6": "Fs6.mp3",
|
|
199
|
+
"A6": "A6.mp3",
|
|
200
|
+
"C7": "C7.mp3"
|
|
201
|
+
},
|
|
202
|
+
"notes": "Breathy and lyrical. Best for melodic lines, not chords."
|
|
203
|
+
},
|
|
204
|
+
"choir_aahs": {
|
|
205
|
+
"cdn": "gleitz_fluidr3_gm",
|
|
206
|
+
"baseUrl": "https://gleitz.github.io/midi-js-soundfonts/FluidR3_GM/choir_aahs-mp3/",
|
|
207
|
+
"category": "choir",
|
|
208
|
+
"range": { "low": "C3", "high": "G5" },
|
|
209
|
+
"urls": {
|
|
210
|
+
"C3": "C3.mp3",
|
|
211
|
+
"Ds3": "Ds3.mp3",
|
|
212
|
+
"Fs3": "Fs3.mp3",
|
|
213
|
+
"A3": "A3.mp3",
|
|
214
|
+
"C4": "C4.mp3",
|
|
215
|
+
"Ds4": "Ds4.mp3",
|
|
216
|
+
"Fs4": "Fs4.mp3",
|
|
217
|
+
"A4": "A4.mp3",
|
|
218
|
+
"C5": "C5.mp3",
|
|
219
|
+
"Ds5": "Ds5.mp3",
|
|
220
|
+
"Fs5": "Fs5.mp3",
|
|
221
|
+
"A5": "A5.mp3"
|
|
222
|
+
},
|
|
223
|
+
"notes": "Sustained 'aah' choir vowel. Long durations ('1n', '2n') and reverb are essential for realism."
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: audio-ambient
|
|
3
|
+
description: Brian Eno-style ambient — long evolving drone pads, massive reverb (8-12s decay), no percussion, slow pitch movement
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# TuneFrames — Ambient
|
|
7
|
+
|
|
8
|
+
## Genre Profile
|
|
9
|
+
- BPM range: 50-70 (or unmeasured — BPM matters only for note scheduling)
|
|
10
|
+
- Key characteristics: slow fade-ins/outs (attack 3-6s, release 5-8s), pitch movement by semitones over 4-8 seconds, overlapping sustain layers, no rhythm
|
|
11
|
+
- Typical instruments: PolySynth (sine/triangle), soft AM pads, FMSynth with gentle modulation
|
|
12
|
+
- Mood: deep, meditative, timeless, oceanic
|
|
13
|
+
|
|
14
|
+
## Core Pattern
|
|
15
|
+
|
|
16
|
+
```js
|
|
17
|
+
// Ambient: overlapping long pads that evolve slowly
|
|
18
|
+
// Key = D minor — dark and peaceful
|
|
19
|
+
// Chord tones: D2, F2, A2, C3, E3, G3
|
|
20
|
+
|
|
21
|
+
const reverb = new Tone.Reverb({ decay: 10, wet: 0.9 });
|
|
22
|
+
await reverb.generate(); // must await before using
|
|
23
|
+
reverb.toDestination();
|
|
24
|
+
|
|
25
|
+
const delay = new Tone.FeedbackDelay({ delayTime: '4n', feedback: 0.4, wet: 0.3 });
|
|
26
|
+
delay.connect(reverb);
|
|
27
|
+
|
|
28
|
+
// Primary drone pad — slow attack, very long sustain
|
|
29
|
+
const drone = new Tone.PolySynth(Tone.Synth, {
|
|
30
|
+
oscillator: { type: 'sine' },
|
|
31
|
+
envelope: { attack: 4.0, decay: 2.0, sustain: 0.9, release: 6.0 },
|
|
32
|
+
volume: -10,
|
|
33
|
+
});
|
|
34
|
+
drone.connect(delay);
|
|
35
|
+
|
|
36
|
+
// Shimmer layer — high harmonics, triangle wave
|
|
37
|
+
const shimmer = new Tone.PolySynth(Tone.Synth, {
|
|
38
|
+
oscillator: { type: 'triangle' },
|
|
39
|
+
envelope: { attack: 5.0, decay: 1.5, sustain: 0.7, release: 7.0 },
|
|
40
|
+
volume: -18,
|
|
41
|
+
});
|
|
42
|
+
shimmer.connect(reverb);
|
|
43
|
+
|
|
44
|
+
// Schedule evolving chord tones — no rhythm, just slow fades in/out
|
|
45
|
+
const notes = ['D2', 'A2', 'F3', 'C3', 'E3', 'D3', 'G2'];
|
|
46
|
+
notes.forEach((note, i) => {
|
|
47
|
+
const offset = i * 2.5; // stagger each note by 2.5 seconds
|
|
48
|
+
Tone.Transport.scheduleOnce((time) => {
|
|
49
|
+
drone.triggerAttackRelease(note, '8n', time); // long hold
|
|
50
|
+
}, offset);
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
// Shimmer tones — offset so they breathe between drone attacks
|
|
54
|
+
['F4', 'A4', 'C5', 'E5'].forEach((note, i) => {
|
|
55
|
+
Tone.Transport.scheduleOnce((time) => {
|
|
56
|
+
shimmer.triggerAttackRelease(note, '8n', time);
|
|
57
|
+
}, i * 3.2 + 1.5);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
Tone.Transport.bpm.value = 60;
|
|
61
|
+
Tone.Transport.start();
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## Instrument Configuration
|
|
65
|
+
|
|
66
|
+
```js
|
|
67
|
+
// Massive reverb — the defining character of ambient
|
|
68
|
+
const reverb = new Tone.Reverb({ decay: 10, preDelay: 0.05, wet: 0.88 });
|
|
69
|
+
await reverb.generate(); // always await!
|
|
70
|
+
|
|
71
|
+
// Sidechain delay for shimmer depth
|
|
72
|
+
const delay = new Tone.FeedbackDelay({ delayTime: 0.375, feedback: 0.45, wet: 0.35 });
|
|
73
|
+
|
|
74
|
+
// Primary drone — sine waves, extremely slow envelope
|
|
75
|
+
const drone = new Tone.PolySynth(Tone.Synth, {
|
|
76
|
+
oscillator: { type: 'sine' },
|
|
77
|
+
envelope: { attack: 4.5, decay: 2.0, sustain: 0.85, release: 7.0 },
|
|
78
|
+
volume: -8,
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
// Overtone layer — triangle adds warmth without brightness
|
|
82
|
+
const overtone = new Tone.PolySynth(Tone.Synth, {
|
|
83
|
+
oscillator: { type: 'triangle' },
|
|
84
|
+
envelope: { attack: 3.0, decay: 1.5, sustain: 0.7, release: 5.0 },
|
|
85
|
+
volume: -16,
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
// Sub drone — sine one octave below, anchors the space
|
|
89
|
+
const sub = new Tone.Synth({
|
|
90
|
+
oscillator: { type: 'sine' },
|
|
91
|
+
envelope: { attack: 6.0, decay: 3.0, sustain: 0.9, release: 8.0 },
|
|
92
|
+
volume: -14,
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
// Signal chain: instruments → delay → reverb → destination
|
|
96
|
+
drone.connect(delay);
|
|
97
|
+
overtone.connect(reverb);
|
|
98
|
+
sub.connect(reverb);
|
|
99
|
+
delay.connect(reverb);
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
## Composition Structure
|
|
103
|
+
|
|
104
|
+
**Ambient has no traditional structure — it breathes.**
|
|
105
|
+
|
|
106
|
+
1. **Entry (0-4s):** First note fades in almost imperceptibly — attack is 4+ seconds
|
|
107
|
+
2. **Accumulation (4-10s):** Second and third pitches enter, staggered 2-4s apart, building a slow chord cloud
|
|
108
|
+
3. **Shimmer (8-14s):** Upper register tones enter — overtones of the root
|
|
109
|
+
4. **Sustained body (10-20s+):** All layers overlap. Nothing resolves — everything just exists together
|
|
110
|
+
5. **No outro needed** — ambient fades naturally because of long release envelopes
|
|
111
|
+
|
|
112
|
+
**Pitch movement rules:**
|
|
113
|
+
- Move by semitones or whole steps only — no jumps larger than a 4th
|
|
114
|
+
- Let dissonance exist — it resolves by itself over time
|
|
115
|
+
- Never use more than 4-5 notes simultaneously
|
|
116
|
+
|
|
117
|
+
## Example Variations
|
|
118
|
+
|
|
119
|
+
### Variation 1: Major / peaceful
|
|
120
|
+
```js
|
|
121
|
+
// C major drone — open and spacious
|
|
122
|
+
const chordNotes = ['C3', 'G3', 'E4', 'B3', 'D4'];
|
|
123
|
+
// Brighter attack on shimmer: attack: 2.5
|
|
124
|
+
// Higher reverb wet: 0.92
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### Variation 2: Cluster / tension
|
|
128
|
+
```js
|
|
129
|
+
// Half-step cluster — creates gentle tension that never resolves
|
|
130
|
+
const tones = ['E3', 'F3', 'G3', 'Ab3']; // chromatic compression
|
|
131
|
+
// Slower attack: 6.0 — the dissonance appears gradually so it never feels harsh
|
|
132
|
+
// Delay feedback higher: 0.55 — creates wash of overtones
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
### Variation 3: Single-note breath
|
|
136
|
+
```js
|
|
137
|
+
// Pure minimalism — one pitch at a time, long silences between
|
|
138
|
+
const seq = ['D3', null, null, null, 'F3', null, null, null, 'A3'];
|
|
139
|
+
// This is the most meditative form — inspired by Feldman/Satie
|
|
140
|
+
// Set reverb decay to 12s so notes bleed into silence
|
|
141
|
+
```
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
<div id="tuneframes" style="display:none">{"bpm":60,"duration":"14s"}</div>
|
|
2
|
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/tone/14.8.49/Tone.js"></script>
|
|
3
|
+
<script>
|
|
4
|
+
// TuneFrames — Ambient (Brian Eno style)
|
|
5
|
+
// D minor drone pads, massive reverb, slow evolving pitch movement
|
|
6
|
+
// No percussion. Everything breathes.
|
|
7
|
+
|
|
8
|
+
async function main() {
|
|
9
|
+
await Tone.start();
|
|
10
|
+
|
|
11
|
+
Tone.Transport.bpm.value = 60;
|
|
12
|
+
|
|
13
|
+
// ── Effects chain ──────────────────────────────────────────────────────────
|
|
14
|
+
const reverb = new Tone.Reverb({ decay: 10, preDelay: 0.05, wet: 0.88 });
|
|
15
|
+
await reverb.generate();
|
|
16
|
+
reverb.toDestination();
|
|
17
|
+
|
|
18
|
+
const delay = new Tone.FeedbackDelay({ delayTime: 0.5, feedback: 0.42, wet: 0.32 });
|
|
19
|
+
delay.connect(reverb);
|
|
20
|
+
|
|
21
|
+
// ── Primary drone — sine wave, very slow attack ────────────────────────────
|
|
22
|
+
const drone = new Tone.PolySynth(Tone.Synth, {
|
|
23
|
+
oscillator: { type: 'sine' },
|
|
24
|
+
envelope: { attack: 4.5, decay: 2.0, sustain: 0.9, release: 7.0 },
|
|
25
|
+
volume: -8,
|
|
26
|
+
});
|
|
27
|
+
drone.connect(delay);
|
|
28
|
+
|
|
29
|
+
// ── Shimmer layer — triangle, even slower, upper register ─────────────────
|
|
30
|
+
const shimmer = new Tone.PolySynth(Tone.Synth, {
|
|
31
|
+
oscillator: { type: 'triangle' },
|
|
32
|
+
envelope: { attack: 5.0, decay: 1.5, sustain: 0.75, release: 6.0 },
|
|
33
|
+
volume: -17,
|
|
34
|
+
});
|
|
35
|
+
shimmer.connect(reverb);
|
|
36
|
+
|
|
37
|
+
// ── Sub drone — anchors the bass register ─────────────────────────────────
|
|
38
|
+
const sub = new Tone.Synth({
|
|
39
|
+
oscillator: { type: 'sine' },
|
|
40
|
+
envelope: { attack: 6.0, decay: 3.0, sustain: 0.9, release: 8.0 },
|
|
41
|
+
volume: -13,
|
|
42
|
+
});
|
|
43
|
+
sub.connect(reverb);
|
|
44
|
+
|
|
45
|
+
// ── Schedule drone tones — D minor: D F A C ───────────────────────────────
|
|
46
|
+
// Staggered so they don't all attack at once — the overlapping sustains
|
|
47
|
+
// create the "chord cloud" that defines ambient music.
|
|
48
|
+
// Note durations use seconds (6, 5, etc.) so the 4.5–6s attacks can fully
|
|
49
|
+
// develop before release. '8n' (0.5s at 60 BPM) is far too short.
|
|
50
|
+
|
|
51
|
+
// Root drone: enters immediately, fades in over 4.5 seconds
|
|
52
|
+
Tone.Transport.scheduleOnce((t) => {
|
|
53
|
+
drone.triggerAttackRelease(['D3', 'A3'], 6, t);
|
|
54
|
+
}, 0);
|
|
55
|
+
|
|
56
|
+
// Fifth enters at 1.5s — builds on the drone
|
|
57
|
+
Tone.Transport.scheduleOnce((t) => {
|
|
58
|
+
drone.triggerAttackRelease(['F3', 'C4'], 6, t);
|
|
59
|
+
}, 1.5);
|
|
60
|
+
|
|
61
|
+
// Color tone — minor 7th adds bittersweet quality
|
|
62
|
+
Tone.Transport.scheduleOnce((t) => {
|
|
63
|
+
drone.triggerAttackRelease(['E3', 'G3'], 5, t);
|
|
64
|
+
}, 3.5);
|
|
65
|
+
|
|
66
|
+
// Second wave — new chord cloud begins overlapping the first
|
|
67
|
+
Tone.Transport.scheduleOnce((t) => {
|
|
68
|
+
drone.triggerAttackRelease(['D3', 'F3'], 5, t);
|
|
69
|
+
}, 6.0);
|
|
70
|
+
|
|
71
|
+
Tone.Transport.scheduleOnce((t) => {
|
|
72
|
+
drone.triggerAttackRelease(['A3', 'C4'], 4, t);
|
|
73
|
+
}, 8.0);
|
|
74
|
+
|
|
75
|
+
// ── Shimmer tones — upper harmonics ───────────────────────────────────────
|
|
76
|
+
Tone.Transport.scheduleOnce((t) => {
|
|
77
|
+
shimmer.triggerAttackRelease(['F5', 'A5'], 5, t);
|
|
78
|
+
}, 2.0);
|
|
79
|
+
|
|
80
|
+
Tone.Transport.scheduleOnce((t) => {
|
|
81
|
+
shimmer.triggerAttackRelease(['D5', 'C5'], 5, t);
|
|
82
|
+
}, 5.5);
|
|
83
|
+
|
|
84
|
+
Tone.Transport.scheduleOnce((t) => {
|
|
85
|
+
shimmer.triggerAttackRelease(['E5', 'G5'], 4, t);
|
|
86
|
+
}, 9.0);
|
|
87
|
+
|
|
88
|
+
// ── Sub bass — single low D, fades in and holds ───────────────────────────
|
|
89
|
+
Tone.Transport.scheduleOnce((t) => {
|
|
90
|
+
sub.triggerAttackRelease('D2', 7, t);
|
|
91
|
+
}, 0.5);
|
|
92
|
+
|
|
93
|
+
// NOTE: do NOT call Tone.Transport.start() here — Tone.Offline manages
|
|
94
|
+
// transport internally. Calling it manually breaks offline rendering.
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
window.renderComposition = async function(wavPath) {
|
|
98
|
+
let attempts = 0;
|
|
99
|
+
while (typeof Tone === 'undefined' && attempts < 50) {
|
|
100
|
+
await new Promise(r => setTimeout(r, 100));
|
|
101
|
+
attempts++;
|
|
102
|
+
}
|
|
103
|
+
if (typeof Tone === 'undefined') throw new Error('Tone not loaded');
|
|
104
|
+
|
|
105
|
+
const meta = JSON.parse(document.getElementById('tuneframes').textContent);
|
|
106
|
+
const durationSec = parseFloat(meta.duration) + 1.0;
|
|
107
|
+
|
|
108
|
+
const buffer = await Tone.Offline(async () => { await main(); }, durationSec, 1, 44100);
|
|
109
|
+
const wav = audioBufferToWav(buffer);
|
|
110
|
+
window.writeFile(wavPath, Array.from(new Uint8Array(wav)));
|
|
111
|
+
return wav.byteLength;
|
|
112
|
+
};
|
|
113
|
+
</script>
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: audio-boss-battle
|
|
3
|
+
description: Video Game Boss Battle — driving 16th-note bass ostinato, power chord stabs on offbeats, heroic AMSynth brass melody, tuned timpani hits, fast counter-arpeggio. Final Fantasy / Nobuo Uematsu epic orchestral-hybrid energy.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# TuneFrames — Video Game Boss Battle
|
|
7
|
+
|
|
8
|
+
## Genre Profile
|
|
9
|
+
- BPM range: 150–185 (intense, relentless forward drive)
|
|
10
|
+
- Key characteristics: Bass ostinato hammering the root in 16th notes (MonoSynth sawtooth), power chord stabs on offbeats (PolySynth square/sawtooth, short decay), heroic lead melody (AMSynth with sawtooth + sine modulation for brass-like tone), tuned timpani accents (MembraneSynth pitched to D1/A1), fast ascending counter-arpeggio for tension, driving kick pattern
|
|
11
|
+
- Typical instruments: MonoSynth (bass ostinato), PolySynth (power chords), AMSynth (brass melody), MembraneSynth × 2 (kick + timpani), PolySynth (counter arpeggio)
|
|
12
|
+
- Mood: Intense, epic, driving, heroic, desperate, high-stakes
|
|
13
|
+
|
|
14
|
+
## Core Pattern
|
|
15
|
+
|
|
16
|
+
```js
|
|
17
|
+
// Boss Battle — 165 BPM, D minor
|
|
18
|
+
// Bars 1–2: bass ostinato alone (ominous)
|
|
19
|
+
// Bars 3–4: power chord stabs on offbeats
|
|
20
|
+
// Bars 5–8: full: melody + counter arpeggio + drums
|
|
21
|
+
|
|
22
|
+
Tone.Transport.bpm.value = 165;
|
|
23
|
+
|
|
24
|
+
// Bass ostinato — driving 16th note figure around D root
|
|
25
|
+
const bass = new Tone.MonoSynth({
|
|
26
|
+
oscillator: { type: "sawtooth" },
|
|
27
|
+
filter: { Q: 3, type: "lowpass", rolloff: -24 },
|
|
28
|
+
filterEnvelope: { attack: 0.001, decay: 0.1, sustain: 0.5, release: 0.2,
|
|
29
|
+
baseFrequency: 80, octaves: 2 },
|
|
30
|
+
envelope: { attack: 0.001, decay: 0.1, sustain: 0.7, release: 0.1 },
|
|
31
|
+
volume: -4
|
|
32
|
+
}).toDestination();
|
|
33
|
+
|
|
34
|
+
// 16th-note ostinato: D root hammered with neighbor-note movement
|
|
35
|
+
const bassLine = [
|
|
36
|
+
"D2","D2","F2","D2", "G2","D2","F2","E2",
|
|
37
|
+
"D2","D2","F2","D2", "G2","F2","Eb2","D2"
|
|
38
|
+
];
|
|
39
|
+
let bassStep = 0;
|
|
40
|
+
new Tone.Sequence((time) => {
|
|
41
|
+
bass.triggerAttackRelease(bassLine[bassStep++ % bassLine.length], "16n", time);
|
|
42
|
+
}, new Array(16).fill(1), "16n").start(0);
|
|
43
|
+
|
|
44
|
+
// Power chord stabs — PolySynth on the "and" of beats 1 and 3
|
|
45
|
+
const stabChords = [["D3","A3"],["F3","C4"],["G3","D4"],["Bb3","F4"]];
|
|
46
|
+
let stabStep = 0;
|
|
47
|
+
new Tone.Sequence((time, val) => {
|
|
48
|
+
if (val) stabs.triggerAttackRelease(stabChords[stabStep++ % stabChords.length], "16n", time);
|
|
49
|
+
}, [null,null,1,null,null,null,null,null,null,null,1,null,null,null,null,null], "16n").start("2m");
|
|
50
|
+
|
|
51
|
+
// Heroic AMSynth melody — D minor ascending/descending
|
|
52
|
+
const melody = [
|
|
53
|
+
{ time: "4m", note: "D4", dur: "4n" }, { time: "4m:1", note: "F4", dur: "4n" },
|
|
54
|
+
{ time: "4m:2", note: "A4", dur: "4n" }, { time: "4m:3", note: "C5", dur: "4n" },
|
|
55
|
+
{ time: "5m", note: "Bb4", dur: "4n" }, { time: "5m:1", note: "A4", dur: "4n" },
|
|
56
|
+
{ time: "5m:2", note: "G4", dur: "2n" },
|
|
57
|
+
];
|
|
58
|
+
melody.forEach(({ time, note, dur }) => brass.triggerAttackRelease(note, dur, time));
|
|
59
|
+
|
|
60
|
+
Tone.Transport.start();
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Instrument Configuration
|
|
64
|
+
|
|
65
|
+
```js
|
|
66
|
+
// Bass ostinato — sawtooth through lowpass filter for growl
|
|
67
|
+
const bassVerb = new Tone.Reverb({ decay: 0.4, wet: 0.1 }).toDestination();
|
|
68
|
+
const bass = new Tone.MonoSynth({
|
|
69
|
+
oscillator: { type: "sawtooth" },
|
|
70
|
+
filter: { Q: 3, type: "lowpass", rolloff: -24 },
|
|
71
|
+
filterEnvelope: { attack: 0.001, decay: 0.1, sustain: 0.5, release: 0.2,
|
|
72
|
+
baseFrequency: 80, octaves: 2 },
|
|
73
|
+
envelope: { attack: 0.001, decay: 0.1, sustain: 0.7, release: 0.1 },
|
|
74
|
+
volume: -4
|
|
75
|
+
}).connect(bassVerb);
|
|
76
|
+
|
|
77
|
+
// Power chord stabs — square wave, very short decay, punchy
|
|
78
|
+
const stabReverb = new Tone.Reverb({ decay: 0.6, wet: 0.2 }).toDestination();
|
|
79
|
+
const stabs = new Tone.PolySynth(Tone.Synth, {
|
|
80
|
+
oscillator: { type: "square" },
|
|
81
|
+
envelope: { attack: 0.001, decay: 0.12, sustain: 0.0, release: 0.08 },
|
|
82
|
+
volume: -8
|
|
83
|
+
}).connect(stabReverb);
|
|
84
|
+
|
|
85
|
+
// AMSynth brass melody — sawtooth carrier + sine AM creates "blat" of brass
|
|
86
|
+
const brassVerb = new Tone.Reverb({ decay: 1.5, wet: 0.3 }).toDestination();
|
|
87
|
+
const brass = new Tone.AMSynth({
|
|
88
|
+
oscillator: { type: "sawtooth" },
|
|
89
|
+
envelope: { attack: 0.04, decay: 0.1, sustain: 0.85, release: 0.4 },
|
|
90
|
+
modulation: { type: "sine" },
|
|
91
|
+
modulationEnvelope: { attack: 0.5, decay: 0, sustain: 1, release: 0.5 },
|
|
92
|
+
harmonicity: 1,
|
|
93
|
+
volume: -8
|
|
94
|
+
}).connect(brassVerb);
|
|
95
|
+
|
|
96
|
+
// Timpani — MembraneSynth pitched low, longer decay than kick
|
|
97
|
+
const timpsVerb = new Tone.Reverb({ decay: 1.2, wet: 0.35 }).toDestination();
|
|
98
|
+
const timps = new Tone.MembraneSynth({
|
|
99
|
+
pitchDecay: 0.2,
|
|
100
|
+
octaves: 4,
|
|
101
|
+
envelope: { attack: 0.001, decay: 0.6, sustain: 0, release: 0.3 },
|
|
102
|
+
volume: -4
|
|
103
|
+
}).connect(timpsVerb);
|
|
104
|
+
|
|
105
|
+
// Kick — driving, 8th or 16th note pattern
|
|
106
|
+
const kick = new Tone.MembraneSynth({
|
|
107
|
+
pitchDecay: 0.06, octaves: 8,
|
|
108
|
+
envelope: { attack: 0.001, decay: 0.28, sustain: 0, release: 0.08 },
|
|
109
|
+
volume: 0
|
|
110
|
+
}).toDestination();
|
|
111
|
+
|
|
112
|
+
// Counter arpeggio — fast 16th note ascent, adds tension
|
|
113
|
+
const arpVerb = new Tone.Reverb({ decay: 0.8, wet: 0.25 }).toDestination();
|
|
114
|
+
const arpSynth = new Tone.PolySynth(Tone.Synth, {
|
|
115
|
+
oscillator: { type: "sawtooth4" },
|
|
116
|
+
envelope: { attack: 0.001, decay: 0.08, sustain: 0, release: 0.1 },
|
|
117
|
+
volume: -14
|
|
118
|
+
}).connect(arpVerb);
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
## Composition Structure
|
|
122
|
+
|
|
123
|
+
- **Bars 1–2:** Bass ostinato only — ominous, low, relentless (the enemy approaches)
|
|
124
|
+
- **Bars 3–4:** Timpani accents on bar downbeats, power chord stabs on offbeats (tension escalates)
|
|
125
|
+
- **Bars 5–6:** Kick + snare enter, driving rhythm locked in, counter arpeggio begins
|
|
126
|
+
- **Bars 7–10:** Full arrangement — AMSynth brass melody soars over the groove
|
|
127
|
+
- **Bar 11–12:** Climax: all elements together, melody at highest pitch, bass most active
|
|
128
|
+
- **Buildup trick:** Use `Tone.Transport.bpm.linearRampTo(180, "+4m")` to gradually accelerate into the final bars
|
|
129
|
+
|
|
130
|
+
Harmonic vocabulary: D natural minor (D E F G A Bb C). Tritone sub on beat 3 (Ab) adds danger. Perfect 5th power chords [root, 5th] — no thirds — are the "8-bit" signature.
|
|
131
|
+
|
|
132
|
+
## Example Variations
|
|
133
|
+
|
|
134
|
+
### 1 — Faster bass (triplet feel, more chaotic)
|
|
135
|
+
```js
|
|
136
|
+
// 8th note triplets instead of 16ths — more chaotic, less locked-in
|
|
137
|
+
const tripletBass = ["D2","F2","A2","G2","F2","D2"];
|
|
138
|
+
let step = 0;
|
|
139
|
+
new Tone.Sequence((time) => {
|
|
140
|
+
bass.triggerAttackRelease(tripletBass[step++ % tripletBass.length], "8t", time);
|
|
141
|
+
}, new Array(6).fill(1), "8t").start(0);
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### 2 — Tempo acceleration (building to a climax)
|
|
145
|
+
```js
|
|
146
|
+
// Slowly push the BPM from 160 to 185 over 8 bars
|
|
147
|
+
const startTime = Tone.Time("4m").toSeconds();
|
|
148
|
+
Tone.Transport.bpm.setValueAtTime(160, startTime);
|
|
149
|
+
Tone.Transport.bpm.linearRampToValueAtTime(185, startTime + Tone.Time("4m").toSeconds());
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
### 3 — Minor key shift mid-battle (F minor for boss phase 2)
|
|
153
|
+
```js
|
|
154
|
+
// After 8 bars, shift to F minor: F G Ab Bb C Db Eb
|
|
155
|
+
// Retrigger stab chords and melody with new root
|
|
156
|
+
const phase2Chords = [["F3","C4"],["Ab3","Eb4"],["Bb3","F4"],["Db4","Ab4"]];
|
|
157
|
+
```
|