@libraz/libcantus 0.9.2 → 0.9.4
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/README.md +6 -5
- package/dist/analyze/index.cjs +41 -1676
- package/dist/analyze/index.cjs.map +1 -1
- package/dist/analyze/index.d.cts +194 -122
- package/dist/analyze/index.d.ts +194 -122
- package/dist/analyze/index.js +19 -8
- package/dist/chunk-36N73KZ3.cjs +246 -0
- package/dist/chunk-36N73KZ3.cjs.map +1 -0
- package/dist/chunk-4HLLZPXT.cjs +3077 -0
- package/dist/chunk-4HLLZPXT.cjs.map +1 -0
- package/dist/chunk-7MGZ7D62.cjs +498 -0
- package/dist/chunk-7MGZ7D62.cjs.map +1 -0
- package/dist/{chunk-R3S2LUBH.js → chunk-7NKDPF74.js} +660 -305
- package/dist/chunk-7NKDPF74.js.map +1 -0
- package/dist/chunk-CAN76NCU.cjs +679 -0
- package/dist/chunk-CAN76NCU.cjs.map +1 -0
- package/dist/{chunk-7Y7WF64D.js → chunk-D2FAJBYL.js} +104 -35
- package/dist/chunk-D2FAJBYL.js.map +1 -0
- package/dist/{chunk-COKTX2G5.js → chunk-EHVEBWM5.js} +1052 -510
- package/dist/chunk-EHVEBWM5.js.map +1 -0
- package/dist/chunk-FCANXBAT.cjs +30 -0
- package/dist/chunk-FCANXBAT.cjs.map +1 -0
- package/dist/chunk-FNDWXRRI.cjs +479 -0
- package/dist/chunk-FNDWXRRI.cjs.map +1 -0
- package/dist/{chunk-GQKN5KDT.js → chunk-GQSGS2N4.js} +43 -29
- package/dist/chunk-GQSGS2N4.js.map +1 -0
- package/dist/chunk-HKGYCQ34.js +53 -0
- package/dist/chunk-HKGYCQ34.js.map +1 -0
- package/dist/chunk-I24MV65U.js +106 -0
- package/dist/chunk-I24MV65U.js.map +1 -0
- package/dist/{chunk-LN7ZZMD2.js → chunk-KMHOICIY.js} +322 -173
- package/dist/chunk-KMHOICIY.js.map +1 -0
- package/dist/chunk-LW53AHQU.cjs +1117 -0
- package/dist/chunk-LW53AHQU.cjs.map +1 -0
- package/dist/chunk-N6IHQUOX.js +1 -0
- package/dist/chunk-N6IHQUOX.js.map +1 -0
- package/dist/chunk-NKIBQ6PT.js +30 -0
- package/dist/chunk-NKIBQ6PT.js.map +1 -0
- package/dist/chunk-NP4NA2FB.cjs +106 -0
- package/dist/chunk-NP4NA2FB.cjs.map +1 -0
- package/dist/chunk-NVE34YGZ.cjs +1449 -0
- package/dist/chunk-NVE34YGZ.cjs.map +1 -0
- package/dist/{chunk-A4532ZFR.js → chunk-NYYWMV2C.js} +115 -47
- package/dist/chunk-NYYWMV2C.js.map +1 -0
- package/dist/{chunk-5HTNMQW4.js → chunk-Q2XUP227.js} +310 -118
- package/dist/chunk-Q2XUP227.js.map +1 -0
- package/dist/chunk-Q6OP4U43.cjs +327 -0
- package/dist/chunk-Q6OP4U43.cjs.map +1 -0
- package/dist/chunk-RC6GBMCD.cjs +845 -0
- package/dist/chunk-RC6GBMCD.cjs.map +1 -0
- package/dist/{chunk-XTC3X6MS.js → chunk-RK35RIN7.js} +453 -152
- package/dist/chunk-RK35RIN7.js.map +1 -0
- package/dist/chunk-RUMU3UA6.cjs +53 -0
- package/dist/chunk-RUMU3UA6.cjs.map +1 -0
- package/dist/chunk-T64C7ZD7.cjs +1 -0
- package/dist/chunk-T64C7ZD7.cjs.map +1 -0
- package/dist/chunk-XEBG3G53.js +498 -0
- package/dist/chunk-XEBG3G53.js.map +1 -0
- package/dist/chunk-YLEMGEFH.js +246 -0
- package/dist/chunk-YLEMGEFH.js.map +1 -0
- package/dist/chunk-ZEJR4TKL.cjs +173 -0
- package/dist/chunk-ZEJR4TKL.cjs.map +1 -0
- package/dist/core/index.cjs +130 -431
- package/dist/core/index.cjs.map +1 -1
- package/dist/core/index.d.cts +331 -17
- package/dist/core/index.d.ts +331 -17
- package/dist/core/index.js +71 -13
- package/dist/{function-2bJW1Zp_.d.ts → function-BtiZb9i9.d.ts} +28 -7
- package/dist/{function-r2sh-jOO.d.cts → function-DNugAOrt.d.cts} +28 -7
- package/dist/generate/index.cjs +30 -3751
- package/dist/generate/index.cjs.map +1 -1
- package/dist/generate/index.d.cts +373 -59
- package/dist/generate/index.d.ts +373 -59
- package/dist/generate/index.js +23 -9
- package/dist/{index-DZ1M21do.d.cts → index-6VR8-kit.d.ts} +20 -4
- package/dist/index-70p168VM.d.ts +192 -0
- package/dist/{index-D_ZTUNKp.d.cts → index-Be74mcon.d.cts} +18 -17
- package/dist/index-BtXT6UQ0.d.cts +192 -0
- package/dist/{index-BMPxwjwV.d.ts → index-C5UBbQ4G.d.ts} +18 -17
- package/dist/{index-BOBXBNwP.d.cts → index-C83mZI1P.d.ts} +93 -8
- package/dist/{index-BdeQ1r_p.d.cts → index-D6b6na69.d.cts} +14 -11
- package/dist/{index-Cl7mhOFM.d.cts → index-DXd9JikN.d.cts} +92 -10
- package/dist/{index-Cl7mhOFM.d.ts → index-DXd9JikN.d.ts} +92 -10
- package/dist/index-OG65ocOr.d.cts +272 -0
- package/dist/index-OG65ocOr.d.ts +272 -0
- package/dist/{index-BreoJRw0.d.ts → index-tJhkmQgE.d.cts} +20 -4
- package/dist/{index-CP3wAfEH.d.ts → index-tSQh-xwY.d.ts} +14 -11
- package/dist/{index-CM5W4rcm.d.ts → index-y_ak9_Hi.d.cts} +93 -8
- package/dist/index.cjs +419 -6848
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +14 -13
- package/dist/index.d.ts +14 -13
- package/dist/index.js +132 -27
- package/dist/model/index.cjs +8 -2423
- package/dist/model/index.cjs.map +1 -1
- package/dist/model/index.d.cts +433 -74
- package/dist/model/index.d.ts +433 -74
- package/dist/model/index.js +6 -7
- package/dist/styled-DIRkk9Uz.d.ts +506 -0
- package/dist/styled-DJbkJQfj.d.cts +506 -0
- package/dist/theory/index.cjs +172 -1676
- package/dist/theory/index.cjs.map +1 -1
- package/dist/theory/index.d.cts +151 -233
- package/dist/theory/index.d.ts +151 -233
- package/dist/theory/index.js +31 -7
- package/dist/{types-MGP29r3t.d.cts → types-BN6_Q9Kl.d.cts} +11 -2
- package/dist/{types-MGP29r3t.d.ts → types-BN6_Q9Kl.d.ts} +11 -2
- package/package.json +73 -24
- package/dist/chunk-5HTNMQW4.js.map +0 -1
- package/dist/chunk-7Y7WF64D.js.map +0 -1
- package/dist/chunk-A4532ZFR.js.map +0 -1
- package/dist/chunk-BHUT2S5G.js +0 -22
- package/dist/chunk-BHUT2S5G.js.map +0 -1
- package/dist/chunk-CCBLVAPK.js +0 -42
- package/dist/chunk-CCBLVAPK.js.map +0 -1
- package/dist/chunk-COKTX2G5.js.map +0 -1
- package/dist/chunk-DYWFNC4A.js +0 -152
- package/dist/chunk-DYWFNC4A.js.map +0 -1
- package/dist/chunk-GQKN5KDT.js.map +0 -1
- package/dist/chunk-LN7ZZMD2.js.map +0 -1
- package/dist/chunk-MSWFZF7J.js +0 -118
- package/dist/chunk-MSWFZF7J.js.map +0 -1
- package/dist/chunk-R3S2LUBH.js.map +0 -1
- package/dist/chunk-SDM3VJJ5.js +0 -41
- package/dist/chunk-SDM3VJJ5.js.map +0 -1
- package/dist/chunk-XTC3X6MS.js.map +0 -1
- package/dist/chunk-ZXW5YIWK.js +0 -55
- package/dist/chunk-ZXW5YIWK.js.map +0 -1
- package/dist/index-CGMZNCx6.d.cts +0 -140
- package/dist/index-CGMZNCx6.d.ts +0 -140
- package/dist/styled-BjXtOFNk.d.cts +0 -282
- package/dist/styled-D7BAx3S3.d.ts +0 -282
- package/src/analyze/arrange/index.ts +0 -21
- package/src/analyze/arrange/internal.ts +0 -125
- package/src/analyze/arrange/tension.ts +0 -187
- package/src/analyze/arrange/tracks.ts +0 -279
- package/src/analyze/detect/index.ts +0 -235
- package/src/analyze/functional/borrowed.ts +0 -84
- package/src/analyze/functional/cadence.ts +0 -66
- package/src/analyze/functional/function.ts +0 -184
- package/src/analyze/functional/index.ts +0 -23
- package/src/analyze/functional/internal.ts +0 -29
- package/src/analyze/functional/roman.ts +0 -393
- package/src/analyze/index.ts +0 -49
- package/src/analyze/timeline/index.ts +0 -415
- package/src/analyze/voice/index.ts +0 -330
- package/src/core/index.ts +0 -47
- package/src/core/interval/index.ts +0 -81
- package/src/core/meter/index.ts +0 -282
- package/src/core/pitch/index.ts +0 -311
- package/src/core/random/index.ts +0 -53
- package/src/core/tuning/index.ts +0 -156
- package/src/core/types.ts +0 -29
- package/src/generate/bass/index.ts +0 -350
- package/src/generate/countermelody/index.ts +0 -379
- package/src/generate/drums/beat.ts +0 -266
- package/src/generate/drums/euclid.ts +0 -58
- package/src/generate/drums/fills.ts +0 -356
- package/src/generate/drums/ghost.ts +0 -119
- package/src/generate/drums/hihat.ts +0 -285
- package/src/generate/drums/hit.ts +0 -31
- package/src/generate/drums/index.ts +0 -329
- package/src/generate/drums/internal.ts +0 -257
- package/src/generate/drums/kick.ts +0 -160
- package/src/generate/drums/percussion.ts +0 -121
- package/src/generate/drums/rng.ts +0 -7
- package/src/generate/drums/swing.ts +0 -71
- package/src/generate/groove/index.ts +0 -326
- package/src/generate/harmonize/index.ts +0 -440
- package/src/generate/index.ts +0 -59
- package/src/generate/motif/index.ts +0 -398
- package/src/generate/progression/index.ts +0 -370
- package/src/generate/reharmony/index.ts +0 -330
- package/src/generate/rhythm/index.ts +0 -165
- package/src/index.ts +0 -247
- package/src/model/chord.ts +0 -423
- package/src/model/index.ts +0 -15
- package/src/model/interval.ts +0 -82
- package/src/model/key.ts +0 -266
- package/src/model/note.ts +0 -176
- package/src/model/progression.ts +0 -161
- package/src/model/shared.ts +0 -12
- package/src/theory/chord/index.ts +0 -373
- package/src/theory/chordscale/index.ts +0 -374
- package/src/theory/counterpoint/index.ts +0 -230
- package/src/theory/harmony/index.ts +0 -92
- package/src/theory/index.ts +0 -107
- package/src/theory/safety/index.ts +0 -419
- package/src/theory/scale/degrees.ts +0 -123
- package/src/theory/scale/index.ts +0 -28
- package/src/theory/scale/key.ts +0 -56
- package/src/theory/scale/masks.ts +0 -153
- package/src/theory/spelling/index.ts +0 -182
- package/src/theory/symbol/index.ts +0 -268
- package/src/theory/voicing/index.ts +0 -5
- package/src/theory/voicing/internal.ts +0 -168
- package/src/theory/voicing/leading.ts +0 -112
- package/src/theory/voicing/satb.ts +0 -195
- package/src/theory/voicing/styled.ts +0 -176
- package/tsconfig.json +0 -23
|
@@ -1,356 +0,0 @@
|
|
|
1
|
-
import type { HitList } from './hit.js';
|
|
2
|
-
import type { DrumStyle, SectionEnergy, SectionType } from './internal.js';
|
|
3
|
-
import { EIGHTH, GM, SIXTEENTH } from './internal.js';
|
|
4
|
-
import type { DrumRng } from './rng.js';
|
|
5
|
-
|
|
6
|
-
/** The thirteen fill archetypes for section transitions. */
|
|
7
|
-
export type FillType =
|
|
8
|
-
| 'snareRoll'
|
|
9
|
-
| 'tomDescend'
|
|
10
|
-
| 'tomAscend'
|
|
11
|
-
| 'snareTomCombo'
|
|
12
|
-
| 'simpleCrash'
|
|
13
|
-
| 'linearFill'
|
|
14
|
-
| 'ghostToAccent'
|
|
15
|
-
| 'bdSnareAlternate'
|
|
16
|
-
| 'hiHatChoke'
|
|
17
|
-
| 'tomShuffle'
|
|
18
|
-
| 'breakdownFill'
|
|
19
|
-
| 'flamsAndDrags'
|
|
20
|
-
| 'halfTimeFill';
|
|
21
|
-
|
|
22
|
-
/** Beat at which a fill begins, widening with section energy. */
|
|
23
|
-
export function getFillStartBeat(energy: SectionEnergy): number {
|
|
24
|
-
switch (energy) {
|
|
25
|
-
case 'low':
|
|
26
|
-
return 3;
|
|
27
|
-
case 'medium':
|
|
28
|
-
return 2;
|
|
29
|
-
case 'high':
|
|
30
|
-
case 'peak':
|
|
31
|
-
return 0;
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* Pick a fill archetype for a section transition.
|
|
37
|
-
*
|
|
38
|
-
* The transition-specific archetypes (into a chorus, out of an intro) are
|
|
39
|
-
* checked before the generic energy fills so every variation stays reachable;
|
|
40
|
-
* with `from === to` the caller effectively asks for a within-section fill.
|
|
41
|
-
*
|
|
42
|
-
* @param from Section the fill leaves.
|
|
43
|
-
* @param to Section the fill leads into.
|
|
44
|
-
* @param style Internal drum style.
|
|
45
|
-
* @param nextEnergy Energy of the section the fill leads into.
|
|
46
|
-
* @param rng Deterministic PRNG.
|
|
47
|
-
*/
|
|
48
|
-
export function selectFillType(
|
|
49
|
-
from: SectionType,
|
|
50
|
-
to: SectionType,
|
|
51
|
-
style: DrumStyle,
|
|
52
|
-
nextEnergy: SectionEnergy,
|
|
53
|
-
rng: DrumRng,
|
|
54
|
-
): FillType {
|
|
55
|
-
if (style === 'sparse') {
|
|
56
|
-
return rng.range(0, 1) === 0 ? 'simpleCrash' : 'breakdownFill';
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
const toChorus = to === 'chorus';
|
|
60
|
-
const fromIntro = from === 'intro';
|
|
61
|
-
const highEnergy = style === 'rock' || style === 'fourOnFloor';
|
|
62
|
-
|
|
63
|
-
// Dropping into a low-energy section: keep the phrase end gentle.
|
|
64
|
-
if (nextEnergy === 'low') {
|
|
65
|
-
switch (rng.range(0, 2)) {
|
|
66
|
-
case 0:
|
|
67
|
-
return 'simpleCrash';
|
|
68
|
-
case 1:
|
|
69
|
-
return 'breakdownFill';
|
|
70
|
-
default:
|
|
71
|
-
return 'halfTimeFill';
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
// Big lead-ins to a chorus take precedence over the generic energy fills.
|
|
76
|
-
if (toChorus) {
|
|
77
|
-
const choice = rng.range(0, 7);
|
|
78
|
-
if (highEnergy) {
|
|
79
|
-
switch (choice) {
|
|
80
|
-
case 0:
|
|
81
|
-
case 1:
|
|
82
|
-
return 'tomDescend';
|
|
83
|
-
case 2:
|
|
84
|
-
return 'snareRoll';
|
|
85
|
-
case 3:
|
|
86
|
-
return 'linearFill';
|
|
87
|
-
case 4:
|
|
88
|
-
return 'bdSnareAlternate';
|
|
89
|
-
case 5:
|
|
90
|
-
return 'flamsAndDrags';
|
|
91
|
-
case 6:
|
|
92
|
-
return 'tomShuffle';
|
|
93
|
-
default:
|
|
94
|
-
return 'ghostToAccent';
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
switch (choice) {
|
|
98
|
-
case 0:
|
|
99
|
-
case 1:
|
|
100
|
-
return 'snareTomCombo';
|
|
101
|
-
case 2:
|
|
102
|
-
return 'tomDescend';
|
|
103
|
-
case 3:
|
|
104
|
-
return 'ghostToAccent';
|
|
105
|
-
case 4:
|
|
106
|
-
return 'hiHatChoke';
|
|
107
|
-
case 5:
|
|
108
|
-
return 'linearFill';
|
|
109
|
-
default:
|
|
110
|
-
return 'snareRoll';
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
// Leaving the intro: lighter, building character.
|
|
115
|
-
if (fromIntro) {
|
|
116
|
-
switch (rng.range(0, 5)) {
|
|
117
|
-
case 0:
|
|
118
|
-
case 1:
|
|
119
|
-
return 'snareRoll';
|
|
120
|
-
case 2:
|
|
121
|
-
return 'simpleCrash';
|
|
122
|
-
case 3:
|
|
123
|
-
return 'ghostToAccent';
|
|
124
|
-
case 4:
|
|
125
|
-
return 'breakdownFill';
|
|
126
|
-
default:
|
|
127
|
-
return 'halfTimeFill';
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
// Generic medium/high/peak fills, split by style energy.
|
|
132
|
-
const choice = rng.range(0, 7);
|
|
133
|
-
if (highEnergy) {
|
|
134
|
-
switch (choice) {
|
|
135
|
-
case 0:
|
|
136
|
-
return 'tomDescend';
|
|
137
|
-
case 1:
|
|
138
|
-
return 'snareRoll';
|
|
139
|
-
case 2:
|
|
140
|
-
return 'tomAscend';
|
|
141
|
-
case 3:
|
|
142
|
-
return 'snareTomCombo';
|
|
143
|
-
case 4:
|
|
144
|
-
return 'linearFill';
|
|
145
|
-
case 5:
|
|
146
|
-
return 'bdSnareAlternate';
|
|
147
|
-
case 6:
|
|
148
|
-
return 'flamsAndDrags';
|
|
149
|
-
default:
|
|
150
|
-
return 'tomShuffle';
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
switch (choice) {
|
|
155
|
-
case 0:
|
|
156
|
-
case 1:
|
|
157
|
-
return 'snareRoll';
|
|
158
|
-
case 2:
|
|
159
|
-
return 'snareTomCombo';
|
|
160
|
-
case 3:
|
|
161
|
-
return 'ghostToAccent';
|
|
162
|
-
case 4:
|
|
163
|
-
return 'hiHatChoke';
|
|
164
|
-
case 5:
|
|
165
|
-
return 'halfTimeFill';
|
|
166
|
-
default:
|
|
167
|
-
return 'breakdownFill';
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
/**
|
|
172
|
-
* Emit a fill for a single beat of the fill bar.
|
|
173
|
-
*
|
|
174
|
-
* @param track Hit accumulator.
|
|
175
|
-
* @param beatTick Absolute beat position of this beat.
|
|
176
|
-
* @param beat Beat index within the bar (0-3).
|
|
177
|
-
* @param fillType Selected fill archetype.
|
|
178
|
-
* @param velocity Base velocity for the beat.
|
|
179
|
-
*/
|
|
180
|
-
export function generateFill(
|
|
181
|
-
track: HitList,
|
|
182
|
-
beatTick: number,
|
|
183
|
-
beat: number,
|
|
184
|
-
fillType: FillType,
|
|
185
|
-
velocity: number,
|
|
186
|
-
): void {
|
|
187
|
-
const fillVel = velocity * 0.9;
|
|
188
|
-
const accentVel = velocity * 0.95;
|
|
189
|
-
const S = SIXTEENTH;
|
|
190
|
-
const E = EIGHTH;
|
|
191
|
-
|
|
192
|
-
if (beat === 0) {
|
|
193
|
-
track.add(GM.BD, beatTick, E, fillVel);
|
|
194
|
-
track.add(GM.SD, beatTick + E, E, fillVel - 5);
|
|
195
|
-
return;
|
|
196
|
-
}
|
|
197
|
-
if (beat === 1) {
|
|
198
|
-
track.add(GM.SD, beatTick, E, fillVel);
|
|
199
|
-
track.add(GM.TOM_H, beatTick + E, E, fillVel - 3);
|
|
200
|
-
return;
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
switch (fillType) {
|
|
204
|
-
case 'snareRoll':
|
|
205
|
-
if (beat === 2) {
|
|
206
|
-
for (let i = 0; i < 4; i += 1) {
|
|
207
|
-
track.add(GM.SD, beatTick + i * S, S, fillVel * (0.6 + 0.1 * i));
|
|
208
|
-
}
|
|
209
|
-
} else {
|
|
210
|
-
for (let i = 0; i < 3; i += 1) {
|
|
211
|
-
track.add(GM.SD, beatTick + i * S, S, fillVel * (0.7 + 0.1 * i));
|
|
212
|
-
}
|
|
213
|
-
track.add(GM.SD, beatTick + 3 * S, S, accentVel);
|
|
214
|
-
}
|
|
215
|
-
break;
|
|
216
|
-
|
|
217
|
-
case 'tomDescend':
|
|
218
|
-
if (beat === 2) {
|
|
219
|
-
track.add(GM.SD, beatTick, E, fillVel);
|
|
220
|
-
track.add(GM.TOM_H, beatTick + E, E, fillVel - 5);
|
|
221
|
-
} else {
|
|
222
|
-
track.add(GM.TOM_H, beatTick, S, fillVel);
|
|
223
|
-
track.add(GM.TOM_M, beatTick + S, S, fillVel - 3);
|
|
224
|
-
track.add(GM.TOM_M, beatTick + E, S, fillVel - 5);
|
|
225
|
-
track.add(GM.TOM_L, beatTick + E + S, S, accentVel);
|
|
226
|
-
}
|
|
227
|
-
break;
|
|
228
|
-
|
|
229
|
-
case 'tomAscend':
|
|
230
|
-
if (beat === 2) {
|
|
231
|
-
track.add(GM.SD, beatTick, E, fillVel);
|
|
232
|
-
track.add(GM.TOM_L, beatTick + E, E, fillVel - 5);
|
|
233
|
-
} else {
|
|
234
|
-
track.add(GM.TOM_L, beatTick, S, fillVel);
|
|
235
|
-
track.add(GM.TOM_M, beatTick + S, S, fillVel + 3);
|
|
236
|
-
track.add(GM.TOM_M, beatTick + E, S, fillVel + 5);
|
|
237
|
-
track.add(GM.TOM_H, beatTick + E + S, S, accentVel);
|
|
238
|
-
}
|
|
239
|
-
break;
|
|
240
|
-
|
|
241
|
-
case 'snareTomCombo':
|
|
242
|
-
if (beat === 2) {
|
|
243
|
-
track.add(GM.SD, beatTick, E, fillVel);
|
|
244
|
-
track.add(GM.SD, beatTick + E, S, fillVel - 5);
|
|
245
|
-
track.add(GM.TOM_H, beatTick + E + S, S, fillVel);
|
|
246
|
-
} else {
|
|
247
|
-
track.add(GM.TOM_M, beatTick, S, fillVel);
|
|
248
|
-
track.add(GM.SD, beatTick + S, S, fillVel - 3);
|
|
249
|
-
track.add(GM.TOM_L, beatTick + E, S, fillVel + 2);
|
|
250
|
-
track.add(GM.BD, beatTick + E + S, S, accentVel);
|
|
251
|
-
}
|
|
252
|
-
break;
|
|
253
|
-
|
|
254
|
-
case 'simpleCrash':
|
|
255
|
-
if (beat === 3) {
|
|
256
|
-
track.add(GM.BD, beatTick + E + S, S, accentVel);
|
|
257
|
-
track.add(GM.CRASH, beatTick + E + S, E, accentVel);
|
|
258
|
-
}
|
|
259
|
-
break;
|
|
260
|
-
|
|
261
|
-
case 'linearFill':
|
|
262
|
-
if (beat === 2) {
|
|
263
|
-
track.add(GM.BD, beatTick, S, fillVel);
|
|
264
|
-
track.add(GM.SD, beatTick + S, S, fillVel);
|
|
265
|
-
track.add(GM.TOM_H, beatTick + 2 * S, S, fillVel);
|
|
266
|
-
track.add(GM.TOM_M, beatTick + 3 * S, S, fillVel);
|
|
267
|
-
} else {
|
|
268
|
-
track.add(GM.TOM_L, beatTick, S, fillVel + 3);
|
|
269
|
-
track.add(GM.SD, beatTick + S, S, fillVel + 5);
|
|
270
|
-
track.add(GM.BD, beatTick + 2 * S, S, fillVel + 7);
|
|
271
|
-
track.add(GM.SD, beatTick + 3 * S, S, accentVel);
|
|
272
|
-
}
|
|
273
|
-
break;
|
|
274
|
-
|
|
275
|
-
case 'ghostToAccent':
|
|
276
|
-
if (beat === 2) {
|
|
277
|
-
const ghost = fillVel * 0.4;
|
|
278
|
-
track.add(GM.SD, beatTick, S, ghost);
|
|
279
|
-
track.add(GM.SD, beatTick + S, S, ghost + 10);
|
|
280
|
-
track.add(GM.SD, beatTick + 2 * S, S, ghost + 20);
|
|
281
|
-
track.add(GM.SD, beatTick + 3 * S, S, ghost + 30);
|
|
282
|
-
} else {
|
|
283
|
-
track.add(GM.SD, beatTick, E, fillVel);
|
|
284
|
-
track.add(GM.SD, beatTick + E, E, accentVel);
|
|
285
|
-
}
|
|
286
|
-
break;
|
|
287
|
-
|
|
288
|
-
case 'bdSnareAlternate':
|
|
289
|
-
if (beat === 2) {
|
|
290
|
-
track.add(GM.BD, beatTick, S, fillVel);
|
|
291
|
-
track.add(GM.SD, beatTick + S, S, fillVel);
|
|
292
|
-
track.add(GM.BD, beatTick + 2 * S, S, fillVel + 3);
|
|
293
|
-
track.add(GM.SD, beatTick + 3 * S, S, fillVel + 3);
|
|
294
|
-
} else {
|
|
295
|
-
track.add(GM.BD, beatTick, S, fillVel + 5);
|
|
296
|
-
track.add(GM.SD, beatTick + S, S, fillVel + 5);
|
|
297
|
-
track.add(GM.BD, beatTick + 2 * S, S, accentVel);
|
|
298
|
-
track.add(GM.SD, beatTick + 3 * S, S, accentVel);
|
|
299
|
-
}
|
|
300
|
-
break;
|
|
301
|
-
|
|
302
|
-
case 'hiHatChoke':
|
|
303
|
-
if (beat === 2) {
|
|
304
|
-
track.add(GM.OHH, beatTick, E, fillVel);
|
|
305
|
-
track.add(GM.OHH, beatTick + E, E, fillVel + 5);
|
|
306
|
-
} else {
|
|
307
|
-
track.add(GM.OHH, beatTick, S, fillVel + 8);
|
|
308
|
-
track.add(GM.CHH, beatTick + S, S, accentVel);
|
|
309
|
-
track.add(GM.SD, beatTick + E, E, accentVel);
|
|
310
|
-
}
|
|
311
|
-
break;
|
|
312
|
-
|
|
313
|
-
case 'tomShuffle':
|
|
314
|
-
if (beat === 2) {
|
|
315
|
-
track.add(GM.TOM_H, beatTick, E, fillVel);
|
|
316
|
-
track.add(GM.TOM_M, beatTick + E + S / 2, S, fillVel - 5);
|
|
317
|
-
} else {
|
|
318
|
-
track.add(GM.TOM_M, beatTick, E, fillVel);
|
|
319
|
-
track.add(GM.TOM_L, beatTick + E + S / 2, S, fillVel + 5);
|
|
320
|
-
}
|
|
321
|
-
break;
|
|
322
|
-
|
|
323
|
-
case 'breakdownFill':
|
|
324
|
-
if (beat === 3) {
|
|
325
|
-
track.add(GM.SD, beatTick + E, S, accentVel);
|
|
326
|
-
}
|
|
327
|
-
break;
|
|
328
|
-
|
|
329
|
-
case 'flamsAndDrags':
|
|
330
|
-
if (beat === 2) {
|
|
331
|
-
track.add(GM.SD, beatTick - S / 4, S / 4, fillVel * 0.5);
|
|
332
|
-
track.add(GM.SD, beatTick, E, fillVel);
|
|
333
|
-
track.add(GM.SD, beatTick + E, S / 2, fillVel * 0.6);
|
|
334
|
-
track.add(GM.SD, beatTick + E + S / 2, S / 2, fillVel * 0.6);
|
|
335
|
-
track.add(GM.SD, beatTick + E + S, E, fillVel);
|
|
336
|
-
} else {
|
|
337
|
-
track.add(GM.SD, beatTick - S / 4, S / 4, fillVel * 0.5);
|
|
338
|
-
track.add(GM.SD, beatTick, 1, accentVel);
|
|
339
|
-
}
|
|
340
|
-
break;
|
|
341
|
-
|
|
342
|
-
case 'halfTimeFill':
|
|
343
|
-
if (beat === 2) {
|
|
344
|
-
track.add(GM.SD, beatTick, 1, accentVel);
|
|
345
|
-
track.add(GM.BD, beatTick, 1, fillVel);
|
|
346
|
-
} else if (beat === 3) {
|
|
347
|
-
// At low energy the fill spans only beat 3, so this branch keeps the
|
|
348
|
-
// phrase end from going silent: a broad half-time backbeat snare with a
|
|
349
|
-
// light pickup into the next section.
|
|
350
|
-
track.add(GM.SD, beatTick, EIGHTH, accentVel);
|
|
351
|
-
track.add(GM.SD, beatTick + E, S, fillVel * 0.6);
|
|
352
|
-
track.add(GM.SD, beatTick + E + S, S, accentVel);
|
|
353
|
-
}
|
|
354
|
-
break;
|
|
355
|
-
}
|
|
356
|
-
}
|
|
@@ -1,119 +0,0 @@
|
|
|
1
|
-
import type { BackingDensity, SectionType } from './internal.js';
|
|
2
|
-
import { MoodCategory, sectionIndex } from './internal.js';
|
|
3
|
-
import type { DrumRng } from './rng.js';
|
|
4
|
-
|
|
5
|
-
/** Ghost-note position within a beat: the "e" (1st 16th) or "a" (3rd 16th). */
|
|
6
|
-
export type GhostPosition = 'e' | 'a';
|
|
7
|
-
|
|
8
|
-
/** Ghost density level ordinal (0 = none, 3 = heavy). */
|
|
9
|
-
type GhostDensityLevel = 0 | 1 | 2 | 3;
|
|
10
|
-
|
|
11
|
-
// Ghost density level per [section index][mood category].
|
|
12
|
-
const GHOST_DENSITY_TABLE: GhostDensityLevel[][] = [
|
|
13
|
-
/* intro */ [0, 1, 1],
|
|
14
|
-
/* a */ [0, 1, 2],
|
|
15
|
-
/* b */ [1, 2, 2],
|
|
16
|
-
/* chorus */ [1, 2, 3],
|
|
17
|
-
/* bridge */ [1, 1, 2],
|
|
18
|
-
/* interlude */ [0, 1, 1],
|
|
19
|
-
/* outro */ [0, 1, 1],
|
|
20
|
-
];
|
|
21
|
-
|
|
22
|
-
function levelToProbability(level: GhostDensityLevel): number {
|
|
23
|
-
switch (level) {
|
|
24
|
-
case 0:
|
|
25
|
-
return 0;
|
|
26
|
-
case 1:
|
|
27
|
-
return 0.15;
|
|
28
|
-
case 2:
|
|
29
|
-
return 0.3;
|
|
30
|
-
case 3:
|
|
31
|
-
return 0.45;
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
function clampLevel(level: number): GhostDensityLevel {
|
|
36
|
-
return Math.max(0, Math.min(3, level)) as GhostDensityLevel;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
function adjustForBpm(level: GhostDensityLevel, bpm: number): GhostDensityLevel {
|
|
40
|
-
if (bpm >= 160 && level !== 0) {
|
|
41
|
-
return clampLevel(level - 1);
|
|
42
|
-
}
|
|
43
|
-
if (bpm <= 90 && level !== 3) {
|
|
44
|
-
return clampLevel(level + 1);
|
|
45
|
-
}
|
|
46
|
-
return level;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
/** Ghost-note trigger probability for a section, mood, density, and tempo. */
|
|
50
|
-
export function getGhostDensity(
|
|
51
|
-
mood: MoodCategory,
|
|
52
|
-
section: SectionType,
|
|
53
|
-
backingDensity: BackingDensity,
|
|
54
|
-
bpm: number,
|
|
55
|
-
): number {
|
|
56
|
-
const row = GHOST_DENSITY_TABLE[sectionIndex(section)] ?? GHOST_DENSITY_TABLE[1];
|
|
57
|
-
const level = adjustForBpm((row?.[mood] ?? 0) as GhostDensityLevel, bpm);
|
|
58
|
-
|
|
59
|
-
if (backingDensity === 'thin' && level !== 0) {
|
|
60
|
-
return levelToProbability(clampLevel(level - 1));
|
|
61
|
-
}
|
|
62
|
-
if (backingDensity === 'thick' && level !== 3) {
|
|
63
|
-
return levelToProbability(clampLevel(level + 1));
|
|
64
|
-
}
|
|
65
|
-
return levelToProbability(level);
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
/** Ghost-note velocity multiplier for a section and metric position. */
|
|
69
|
-
export function getGhostVelocity(
|
|
70
|
-
section: SectionType,
|
|
71
|
-
beatPosition: number,
|
|
72
|
-
isAfterSnare: boolean,
|
|
73
|
-
): number {
|
|
74
|
-
let base = 0.4;
|
|
75
|
-
const even = beatPosition % 2 === 0 ? 0.05 : 0;
|
|
76
|
-
switch (section) {
|
|
77
|
-
case 'a':
|
|
78
|
-
base = 0.35 + even;
|
|
79
|
-
break;
|
|
80
|
-
case 'chorus':
|
|
81
|
-
base = 0.5 + even;
|
|
82
|
-
break;
|
|
83
|
-
case 'bridge':
|
|
84
|
-
base = 0.25 + even;
|
|
85
|
-
break;
|
|
86
|
-
case 'b':
|
|
87
|
-
base = 0.4 + even;
|
|
88
|
-
break;
|
|
89
|
-
case 'intro':
|
|
90
|
-
case 'outro':
|
|
91
|
-
base = 0.38;
|
|
92
|
-
break;
|
|
93
|
-
}
|
|
94
|
-
if (isAfterSnare) {
|
|
95
|
-
base += 0.1;
|
|
96
|
-
}
|
|
97
|
-
return Math.max(0.25, Math.min(0.65, base));
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
/** Probability of a ghost at a specific 16th position (higher near the snare). */
|
|
101
|
-
export function getGhostProbabilityAtPosition(beat: number, sixteenthInBeat: number): number {
|
|
102
|
-
const nearSnare =
|
|
103
|
-
(beat === 0 && sixteenthInBeat === 3) ||
|
|
104
|
-
(beat === 1 && sixteenthInBeat === 1) ||
|
|
105
|
-
(beat === 2 && sixteenthInBeat === 3) ||
|
|
106
|
-
(beat === 3 && sixteenthInBeat === 1);
|
|
107
|
-
return nearSnare ? 0.6 : 0.25;
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
/** Choose which ghost positions a groove favours. */
|
|
111
|
-
export function selectGhostPositions(mood: MoodCategory, rng: DrumRng): GhostPosition[] {
|
|
112
|
-
if (mood === MoodCategory.Energetic) {
|
|
113
|
-
return ['e', 'a'];
|
|
114
|
-
}
|
|
115
|
-
if (mood === MoodCategory.Calm) {
|
|
116
|
-
return rng.prob(0.5) ? ['e'] : [];
|
|
117
|
-
}
|
|
118
|
-
return ['e'];
|
|
119
|
-
}
|