@libraz/libcantus 0.9.3 → 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 +2 -2
- package/dist/analyze/index.cjs +39 -1947
- package/dist/analyze/index.cjs.map +1 -1
- package/dist/analyze/index.d.cts +197 -37
- package/dist/analyze/index.d.ts +197 -37
- 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-4MHA432G.js → chunk-7NKDPF74.js} +403 -180
- 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-MIWO425M.js → chunk-D2FAJBYL.js} +101 -34
- package/dist/chunk-D2FAJBYL.js.map +1 -0
- package/dist/{chunk-SGU7SPLK.js → chunk-EHVEBWM5.js} +1056 -531
- 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-IT2O4XFE.js → chunk-GQSGS2N4.js} +43 -24
- package/dist/chunk-GQSGS2N4.js.map +1 -0
- package/dist/{chunk-62QZKCJQ.js → chunk-HKGYCQ34.js} +10 -6
- package/dist/chunk-HKGYCQ34.js.map +1 -0
- package/dist/{chunk-AKLYPWIN.js → chunk-I24MV65U.js} +29 -6
- package/dist/chunk-I24MV65U.js.map +1 -0
- package/dist/{chunk-CHMXELDS.js → chunk-KMHOICIY.js} +311 -181
- 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-2ZWMSJH6.js → chunk-NKIBQ6PT.js} +2 -2
- 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-EH6EM37U.js → chunk-NYYWMV2C.js} +61 -49
- package/dist/chunk-NYYWMV2C.js.map +1 -0
- package/dist/{chunk-GOAW4VYL.js → chunk-Q2XUP227.js} +243 -117
- 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-C5XYKUVG.js → chunk-RK35RIN7.js} +370 -157
- 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-I5R7ZBJS.js → chunk-YLEMGEFH.js} +103 -59
- 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 -647
- package/dist/core/index.cjs.map +1 -1
- package/dist/core/index.d.cts +301 -39
- package/dist/core/index.d.ts +301 -39
- package/dist/core/index.js +54 -16
- package/dist/{function-DYt4iKsn.d.cts → function-BtiZb9i9.d.ts} +28 -7
- package/dist/{function-DVH4Eusr.d.ts → function-DNugAOrt.d.cts} +28 -7
- package/dist/generate/index.cjs +28 -4085
- package/dist/generate/index.cjs.map +1 -1
- package/dist/generate/index.d.cts +370 -62
- package/dist/generate/index.d.ts +370 -62
- package/dist/generate/index.js +23 -9
- package/dist/{index-CxqBQtH1.d.cts → index-6VR8-kit.d.ts} +19 -4
- package/dist/index-70p168VM.d.ts +192 -0
- package/dist/{index-CpOsP1y9.d.cts → index-Be74mcon.d.cts} +18 -17
- package/dist/index-BtXT6UQ0.d.cts +192 -0
- package/dist/{index-DxvARIP2.d.ts → index-C5UBbQ4G.d.ts} +18 -17
- package/dist/{index-Bt4tOUD9.d.ts → index-C83mZI1P.d.ts} +93 -8
- package/dist/{index-Bg5dYMmZ.d.ts → 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-Jc0Ryi79.d.ts → index-tJhkmQgE.d.cts} +19 -4
- package/dist/{index-Dikst44v.d.cts → index-tSQh-xwY.d.ts} +14 -11
- package/dist/{index-BNlGP86A.d.cts → index-y_ak9_Hi.d.cts} +93 -8
- package/dist/index.cjs +419 -7383
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +14 -14
- package/dist/index.d.ts +14 -14
- package/dist/index.js +111 -27
- package/dist/model/index.cjs +8 -2562
- package/dist/model/index.cjs.map +1 -1
- package/dist/model/index.d.cts +433 -75
- package/dist/model/index.d.ts +433 -75
- 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 -1822
- 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 +30 -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 +24 -6
- package/dist/chunk-2ZWMSJH6.js.map +0 -1
- package/dist/chunk-4MHA432G.js.map +0 -1
- package/dist/chunk-62QZKCJQ.js.map +0 -1
- package/dist/chunk-AKLYPWIN.js.map +0 -1
- package/dist/chunk-C5XYKUVG.js.map +0 -1
- package/dist/chunk-CHMXELDS.js.map +0 -1
- package/dist/chunk-DYWFNC4A.js +0 -152
- package/dist/chunk-DYWFNC4A.js.map +0 -1
- package/dist/chunk-EH6EM37U.js.map +0 -1
- package/dist/chunk-FBQK3ZQN.js +0 -131
- package/dist/chunk-FBQK3ZQN.js.map +0 -1
- package/dist/chunk-GOAW4VYL.js.map +0 -1
- package/dist/chunk-I5R7ZBJS.js.map +0 -1
- package/dist/chunk-IT2O4XFE.js.map +0 -1
- package/dist/chunk-MIWO425M.js.map +0 -1
- package/dist/chunk-SGU7SPLK.js.map +0 -1
- package/dist/index-CGMZNCx6.d.cts +0 -140
- package/dist/index-CGMZNCx6.d.ts +0 -140
- package/dist/index-CnZCo29u.d.cts +0 -108
- package/dist/index-JnF4v9bx.d.ts +0 -108
- package/dist/styled-DZ7GjShb.d.ts +0 -282
- package/dist/styled-ZTbdaVFM.d.cts +0 -282
- package/src/analyze/arrange/index.ts +0 -21
- package/src/analyze/arrange/internal.ts +0 -127
- package/src/analyze/arrange/tension.ts +0 -199
- package/src/analyze/arrange/tracks.ts +0 -312
- package/src/analyze/detect/index.ts +0 -272
- 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 -402
- package/src/analyze/index.ts +0 -49
- package/src/analyze/timeline/index.ts +0 -451
- package/src/analyze/voice/index.ts +0 -339
- package/src/core/event-index/index.ts +0 -104
- package/src/core/index.ts +0 -61
- package/src/core/interval/index.ts +0 -81
- package/src/core/meter/index.ts +0 -302
- package/src/core/pitch/index.ts +0 -311
- package/src/core/random/index.ts +0 -76
- package/src/core/tuning/index.ts +0 -186
- package/src/core/types.ts +0 -29
- package/src/core/validation/index.ts +0 -119
- package/src/generate/bass/index.ts +0 -373
- package/src/generate/countermelody/index.ts +0 -470
- package/src/generate/drums/beat.ts +0 -266
- package/src/generate/drums/euclid.ts +0 -65
- 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 -361
- 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 -351
- package/src/generate/harmonize/index.ts +0 -451
- package/src/generate/index.ts +0 -58
- package/src/generate/motif/index.ts +0 -422
- package/src/generate/progression/index.ts +0 -362
- package/src/generate/reharmony/index.ts +0 -323
- package/src/generate/rhythm/index.ts +0 -175
- package/src/index.ts +0 -13
- package/src/model/chord.ts +0 -442
- 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 -375
- package/src/theory/chordscale/index.ts +0 -374
- package/src/theory/counterpoint/index.ts +0 -230
- package/src/theory/harmony/index.ts +0 -77
- package/src/theory/index.ts +0 -112
- package/src/theory/safety/index.ts +0 -488
- 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 -249
- 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 -216
- package/src/theory/voicing/styled.ts +0 -199
- package/tsconfig.json +0 -23
|
@@ -1,266 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
getGhostDensity,
|
|
3
|
-
getGhostProbabilityAtPosition,
|
|
4
|
-
getGhostVelocity,
|
|
5
|
-
selectGhostPositions,
|
|
6
|
-
} from './ghost.js';
|
|
7
|
-
import {
|
|
8
|
-
footHiHatVelocity,
|
|
9
|
-
type HiHatLevel,
|
|
10
|
-
hiHatNote,
|
|
11
|
-
hiHatTypeVelocityMultiplier,
|
|
12
|
-
hiHatVelocityMultiplier,
|
|
13
|
-
OHH_VEL_BOOST,
|
|
14
|
-
roleHiHatInstrument,
|
|
15
|
-
sectionHiHatType,
|
|
16
|
-
shouldAddOpenHHAccent,
|
|
17
|
-
shouldPlayHiHat,
|
|
18
|
-
shouldUseBridgeCrossStick,
|
|
19
|
-
} from './hihat.js';
|
|
20
|
-
import type { HitList } from './hit.js';
|
|
21
|
-
import type { BackingDensity, DrumRole, DrumStyle, Feel, SectionType } from './internal.js';
|
|
22
|
-
import { EIGHTH, GM, type MoodCategory, SIXTEENTH } from './internal.js';
|
|
23
|
-
import type { KickPattern } from './kick.js';
|
|
24
|
-
import type { DrumRng } from './rng.js';
|
|
25
|
-
import { effectiveSwing, quantizeSwing } from './swing.js';
|
|
26
|
-
|
|
27
|
-
/** Per-section drum state shared across the bars of a section. */
|
|
28
|
-
export type SectionCtx = {
|
|
29
|
-
style: DrumStyle;
|
|
30
|
-
feel: Feel;
|
|
31
|
-
densityMult: number;
|
|
32
|
-
backingDensity: BackingDensity;
|
|
33
|
-
hhLevel: HiHatLevel;
|
|
34
|
-
useGhostNotes: boolean;
|
|
35
|
-
ghostBoost: boolean;
|
|
36
|
-
useRide: boolean;
|
|
37
|
-
useFootHh: boolean;
|
|
38
|
-
role: DrumRole;
|
|
39
|
-
ghostMood: MoodCategory;
|
|
40
|
-
snareBeat3: boolean;
|
|
41
|
-
};
|
|
42
|
-
|
|
43
|
-
/** Per-beat context passed to every beat processor. */
|
|
44
|
-
export type BeatCtx = {
|
|
45
|
-
track: HitList;
|
|
46
|
-
beatTick: number;
|
|
47
|
-
beat: number;
|
|
48
|
-
velocity: number;
|
|
49
|
-
section: SectionType;
|
|
50
|
-
bpm: number;
|
|
51
|
-
bar: number;
|
|
52
|
-
sectionBars: number;
|
|
53
|
-
inPrechorusLift: boolean;
|
|
54
|
-
swingAmount: number;
|
|
55
|
-
barHasOpenHh: boolean;
|
|
56
|
-
openHhBeat: number;
|
|
57
|
-
rng: DrumRng;
|
|
58
|
-
};
|
|
59
|
-
|
|
60
|
-
function swing16(tick: number, feel: Feel, swingAmount: number): number {
|
|
61
|
-
return quantizeSwing(tick, effectiveSwing(feel, swingAmount), 'sixteenth');
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
function hatSwingFactor(style: DrumStyle): number {
|
|
65
|
-
if (style === 'trap') {
|
|
66
|
-
return 0;
|
|
67
|
-
}
|
|
68
|
-
if (style === 'latin') {
|
|
69
|
-
return 0.35;
|
|
70
|
-
}
|
|
71
|
-
return 0.5;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
/** Emit the kick for one beat. */
|
|
75
|
-
export function generateKickForBeat(ctx: BeatCtx, sec: SectionCtx, kick: KickPattern): void {
|
|
76
|
-
if (ctx.inPrechorusLift) {
|
|
77
|
-
return;
|
|
78
|
-
}
|
|
79
|
-
const on = [kick.beat1, kick.beat2, kick.beat3, kick.beat4][ctx.beat] ?? false;
|
|
80
|
-
const and = [kick.beat1and, kick.beat2and, kick.beat3and, kick.beat4and][ctx.beat] ?? false;
|
|
81
|
-
|
|
82
|
-
if (on) {
|
|
83
|
-
ctx.track.add(GM.BD, ctx.beatTick, EIGHTH, ctx.velocity);
|
|
84
|
-
}
|
|
85
|
-
if (and) {
|
|
86
|
-
const andTick = swing16(ctx.beatTick + EIGHTH, sec.feel, ctx.swingAmount);
|
|
87
|
-
ctx.track.add(GM.BD, andTick, EIGHTH, ctx.velocity * 0.85);
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
/** Emit the backbeat snare (or side-stick) for one beat. */
|
|
92
|
-
export function generateSnareForBeat(ctx: BeatCtx, sec: SectionCtx, isIntroFirst: boolean): void {
|
|
93
|
-
if (ctx.inPrechorusLift) {
|
|
94
|
-
return;
|
|
95
|
-
}
|
|
96
|
-
const snareOn = sec.snareBeat3 ? ctx.beat === 2 : ctx.beat === 1 || ctx.beat === 3;
|
|
97
|
-
if (!snareOn || isIntroFirst) {
|
|
98
|
-
return;
|
|
99
|
-
}
|
|
100
|
-
if (sec.useRide && shouldUseBridgeCrossStick(ctx.section, ctx.beat)) {
|
|
101
|
-
return;
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
const backbeatVel = Math.min(127, ctx.velocity + 16);
|
|
105
|
-
const promoteSparseChorus =
|
|
106
|
-
sec.style === 'sparse' && ctx.section === 'chorus' && sec.role === 'full';
|
|
107
|
-
|
|
108
|
-
if (promoteSparseChorus) {
|
|
109
|
-
ctx.track.add(GM.SD, ctx.beatTick, EIGHTH, backbeatVel);
|
|
110
|
-
} else if (sec.style === 'sparse' || sec.role === 'ambient') {
|
|
111
|
-
if (sec.role !== 'fxOnly' && sec.role !== 'minimal') {
|
|
112
|
-
ctx.track.add(GM.SIDESTICK, ctx.beatTick, EIGHTH, ctx.velocity * 0.8);
|
|
113
|
-
}
|
|
114
|
-
} else {
|
|
115
|
-
ctx.track.add(GM.SD, ctx.beatTick, EIGHTH, backbeatVel);
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
/** Emit ghost snares at the "e"/"a" 16ths of beats 1 and 3. */
|
|
120
|
-
export function generateGhostNotesForBeat(ctx: BeatCtx, sec: SectionCtx): void {
|
|
121
|
-
if (ctx.beat !== 0 && ctx.beat !== 2) {
|
|
122
|
-
return;
|
|
123
|
-
}
|
|
124
|
-
const positions = selectGhostPositions(sec.ghostMood, ctx.rng);
|
|
125
|
-
let ghostProb = getGhostDensity(sec.ghostMood, ctx.section, sec.backingDensity, ctx.bpm);
|
|
126
|
-
if (sec.ghostBoost) {
|
|
127
|
-
ghostProb = Math.min(1, ghostProb * 1.4);
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
for (const pos of positions) {
|
|
131
|
-
const sixteenthInBeat = pos === 'e' ? 1 : 3;
|
|
132
|
-
const posProb = getGhostProbabilityAtPosition(ctx.beat, sixteenthInBeat);
|
|
133
|
-
if (!ctx.rng.prob(ghostProb * posProb)) {
|
|
134
|
-
continue;
|
|
135
|
-
}
|
|
136
|
-
const variation = ctx.rng.float(0.85, 1.15);
|
|
137
|
-
const ghostBase = getGhostVelocity(ctx.section, ctx.beat / 2, false);
|
|
138
|
-
let ghostVel = ctx.velocity * ghostBase * variation;
|
|
139
|
-
if (pos === 'a') {
|
|
140
|
-
ghostVel *= 0.9;
|
|
141
|
-
}
|
|
142
|
-
const offset = pos === 'e' ? SIXTEENTH : 3 * SIXTEENTH;
|
|
143
|
-
const tick = swing16(ctx.beatTick + offset, sec.feel, ctx.swingAmount);
|
|
144
|
-
ctx.track.add(GM.SD, tick, SIXTEENTH, ghostVel);
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
/** Emit the pre-chorus lift buildup for one beat. */
|
|
149
|
-
export function generatePreChorusBuildup(
|
|
150
|
-
ctx: BeatCtx,
|
|
151
|
-
sec: SectionCtx,
|
|
152
|
-
isSectionLastBar: boolean,
|
|
153
|
-
): void {
|
|
154
|
-
if (sec.style === 'sparse') {
|
|
155
|
-
if (isSectionLastBar && ctx.beat === 3) {
|
|
156
|
-
ctx.track.add(GM.SD, ctx.beatTick, EIGHTH, Math.max(45, ctx.velocity * 0.75));
|
|
157
|
-
ctx.track.add(GM.CRASH, ctx.beatTick + EIGHTH + SIXTEENTH, SIXTEENTH, ctx.velocity * 0.9);
|
|
158
|
-
}
|
|
159
|
-
return;
|
|
160
|
-
}
|
|
161
|
-
const barsInLift = 2;
|
|
162
|
-
const barInLift = ctx.bar - (ctx.sectionBars - barsInLift);
|
|
163
|
-
const progress = (barInLift * 4 + ctx.beat) / (barsInLift * 4);
|
|
164
|
-
const buildupVel = ctx.velocity * (0.5 + 0.5 * progress);
|
|
165
|
-
ctx.track.add(GM.SD, ctx.beatTick, EIGHTH, buildupVel);
|
|
166
|
-
ctx.track.add(GM.SD, ctx.beatTick + EIGHTH, EIGHTH, buildupVel * 0.85);
|
|
167
|
-
if (isSectionLastBar && ctx.beat === 3) {
|
|
168
|
-
ctx.track.add(GM.CRASH, ctx.beatTick + EIGHTH + SIXTEENTH, SIXTEENTH, ctx.velocity * 1.1);
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
/** Emit the timekeeping hi-hat (or ride/foot) for one beat. */
|
|
173
|
-
export function generateHiHatForBeat(ctx: BeatCtx, sec: SectionCtx): void {
|
|
174
|
-
if (!shouldPlayHiHat(sec.role)) {
|
|
175
|
-
if (sec.useFootHh && (ctx.beat === 0 || ctx.beat === 2)) {
|
|
176
|
-
ctx.track.add(GM.FHH, ctx.beatTick, EIGHTH, footHiHatVelocity(ctx.rng));
|
|
177
|
-
}
|
|
178
|
-
return;
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
const crossStick = sec.useRide && shouldUseBridgeCrossStick(ctx.section, ctx.beat);
|
|
182
|
-
const hhInstrument = crossStick ? GM.SIDESTICK : roleHiHatInstrument(sec.role, sec.useRide);
|
|
183
|
-
const hhType = sectionHiHatType(ctx.section, sec.role);
|
|
184
|
-
const typeMult = hiHatTypeVelocityMultiplier(hhType);
|
|
185
|
-
const isDynamicOpen = ctx.barHasOpenHh && ctx.beat === ctx.openHhBeat;
|
|
186
|
-
const dm = sec.densityMult;
|
|
187
|
-
|
|
188
|
-
if (sec.hhLevel === 'quarter') {
|
|
189
|
-
const introRest = ctx.section === 'intro' && ctx.beat !== 0;
|
|
190
|
-
if (!introRest) {
|
|
191
|
-
if (isDynamicOpen) {
|
|
192
|
-
ctx.track.add(
|
|
193
|
-
GM.OHH,
|
|
194
|
-
ctx.beatTick,
|
|
195
|
-
EIGHTH,
|
|
196
|
-
ctx.velocity * dm * 0.75 * typeMult + OHH_VEL_BOOST,
|
|
197
|
-
);
|
|
198
|
-
} else {
|
|
199
|
-
ctx.track.add(
|
|
200
|
-
hhInstrument,
|
|
201
|
-
ctx.beatTick,
|
|
202
|
-
EIGHTH,
|
|
203
|
-
Math.max(20, ctx.velocity * dm * 0.75 * typeMult),
|
|
204
|
-
);
|
|
205
|
-
}
|
|
206
|
-
} else if (sec.useFootHh) {
|
|
207
|
-
ctx.track.add(GM.FHH, ctx.beatTick, EIGHTH, footHiHatVelocity(ctx.rng));
|
|
208
|
-
}
|
|
209
|
-
return;
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
if (sec.hhLevel === 'eighth') {
|
|
213
|
-
for (let eighth = 0; eighth < 2; eighth += 1) {
|
|
214
|
-
let hhTick = ctx.beatTick + eighth * EIGHTH;
|
|
215
|
-
if (eighth === 1) {
|
|
216
|
-
hhTick = swing16(hhTick, sec.feel, ctx.swingAmount);
|
|
217
|
-
}
|
|
218
|
-
if (ctx.section === 'intro' && eighth === 1) {
|
|
219
|
-
if (sec.useFootHh && ctx.beat % 2 === 0) {
|
|
220
|
-
ctx.track.add(GM.FHH, hhTick, EIGHTH, footHiHatVelocity(ctx.rng));
|
|
221
|
-
}
|
|
222
|
-
continue;
|
|
223
|
-
}
|
|
224
|
-
const hhVel = Math.max(20, ctx.velocity * dm * typeMult * (eighth === 0 ? 0.9 : 0.65));
|
|
225
|
-
if (isDynamicOpen && eighth === 0) {
|
|
226
|
-
ctx.track.add(GM.OHH, hhTick, EIGHTH, hhVel + OHH_VEL_BOOST);
|
|
227
|
-
continue;
|
|
228
|
-
}
|
|
229
|
-
let useOpen = false;
|
|
230
|
-
if (sec.style === 'fourOnFloor' && eighth === 1) {
|
|
231
|
-
const openProb = Math.max(0.15, Math.min(0.8, 45 / ctx.bpm));
|
|
232
|
-
useOpen = (ctx.beat === 1 || ctx.beat === 3) && ctx.rng.prob(openProb);
|
|
233
|
-
} else if (eighth === 0) {
|
|
234
|
-
useOpen = shouldAddOpenHHAccent(ctx.section, ctx.beat, ctx.bar, ctx.rng);
|
|
235
|
-
}
|
|
236
|
-
if (useOpen) {
|
|
237
|
-
ctx.track.add(hiHatNote('open'), hhTick, EIGHTH, Math.max(20, hhVel * 1.1));
|
|
238
|
-
} else {
|
|
239
|
-
ctx.track.add(hhInstrument, hhTick, EIGHTH / 2, hhVel);
|
|
240
|
-
}
|
|
241
|
-
}
|
|
242
|
-
return;
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
for (let sixteenth = 0; sixteenth < 4; sixteenth += 1) {
|
|
246
|
-
let hhTick = ctx.beatTick + sixteenth * SIXTEENTH;
|
|
247
|
-
if (sixteenth === 1 || sixteenth === 3) {
|
|
248
|
-
const swung = effectiveSwing(sec.feel, ctx.swingAmount) * hatSwingFactor(sec.style);
|
|
249
|
-
hhTick = quantizeSwing(hhTick, swung, 'sixteenth');
|
|
250
|
-
}
|
|
251
|
-
const metricVel = hiHatVelocityMultiplier(sixteenth, ctx.rng);
|
|
252
|
-
const hhVel = Math.max(20, ctx.velocity * dm * typeMult * metricVel);
|
|
253
|
-
if (isDynamicOpen && sixteenth === 0) {
|
|
254
|
-
ctx.track.add(GM.OHH, hhTick, SIXTEENTH, hhVel + OHH_VEL_BOOST);
|
|
255
|
-
continue;
|
|
256
|
-
}
|
|
257
|
-
if (ctx.beat === 3 && sixteenth === 3) {
|
|
258
|
-
const openProb = Math.max(0.1, Math.min(0.4, 30 / ctx.bpm));
|
|
259
|
-
if (ctx.rng.prob(openProb)) {
|
|
260
|
-
ctx.track.add(GM.OHH, hhTick, SIXTEENTH, Math.max(20, hhVel * 1.2));
|
|
261
|
-
continue;
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
|
-
ctx.track.add(hhInstrument, hhTick, SIXTEENTH / 2, hhVel);
|
|
265
|
-
}
|
|
266
|
-
}
|
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Generate a euclidean onset pattern (Bjorklund's algorithm), distributing
|
|
3
|
-
* `pulses` as evenly as possible across `steps`, then rotating.
|
|
4
|
-
*
|
|
5
|
-
* @param pulses Number of onsets, clamped to [0, steps].
|
|
6
|
-
* @param steps Total steps (>= 1).
|
|
7
|
-
* @param rotation Steps to rotate onsets toward later positions.
|
|
8
|
-
* @returns One boolean per step; true marks an onset.
|
|
9
|
-
*/
|
|
10
|
-
import {
|
|
11
|
-
assertGenerationBudget,
|
|
12
|
-
assertInteger,
|
|
13
|
-
assertPositiveInt,
|
|
14
|
-
} from '../../core/validation/index.js';
|
|
15
|
-
|
|
16
|
-
export function euclideanRhythm(pulses: number, steps: number, rotation = 0): boolean[] {
|
|
17
|
-
assertPositiveInt(steps, 'euclidean steps');
|
|
18
|
-
assertInteger(pulses, 'euclidean pulses');
|
|
19
|
-
assertInteger(rotation, 'euclidean rotation');
|
|
20
|
-
assertGenerationBudget(steps, 'euclidean pattern steps');
|
|
21
|
-
const p = Math.max(0, Math.min(pulses, steps));
|
|
22
|
-
const base = bjorklund(p, steps);
|
|
23
|
-
const shift = ((rotation % steps) + steps) % steps;
|
|
24
|
-
if (shift === 0) {
|
|
25
|
-
return base;
|
|
26
|
-
}
|
|
27
|
-
return base.map((_, i) => base[(i - shift + steps) % steps] ?? false);
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
/** True when the 16-step bitmask has an onset at `step`. */
|
|
31
|
-
export function hasHit(mask: number, step: number): boolean {
|
|
32
|
-
return ((mask >> step) & 1) === 1;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
/** Convert a euclidean boolean pattern to a 16-step bitmask (LSB = step 0). */
|
|
36
|
-
export function patternToMask(pattern: boolean[]): number {
|
|
37
|
-
let mask = 0;
|
|
38
|
-
for (let i = 0; i < pattern.length; i += 1) {
|
|
39
|
-
if (pattern[i]) {
|
|
40
|
-
mask |= 1 << i;
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
return mask;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
function bjorklund(pulses: number, steps: number): boolean[] {
|
|
47
|
-
if (pulses === 0) {
|
|
48
|
-
return Array.from({ length: steps }, () => false);
|
|
49
|
-
}
|
|
50
|
-
if (pulses >= steps) {
|
|
51
|
-
return Array.from({ length: steps }, () => true);
|
|
52
|
-
}
|
|
53
|
-
let head: boolean[][] = Array.from({ length: pulses }, () => [true]);
|
|
54
|
-
let remainder: boolean[][] = Array.from({ length: steps - pulses }, () => [false]);
|
|
55
|
-
while (remainder.length > 1) {
|
|
56
|
-
const count = Math.min(head.length, remainder.length);
|
|
57
|
-
const next: boolean[][] = [];
|
|
58
|
-
for (let i = 0; i < count; i += 1) {
|
|
59
|
-
next.push([...(head[i] ?? []), ...(remainder[i] ?? [])]);
|
|
60
|
-
}
|
|
61
|
-
remainder = head.length > count ? head.slice(count) : remainder.slice(count);
|
|
62
|
-
head = next;
|
|
63
|
-
}
|
|
64
|
-
return [...head.flat(), ...remainder.flat()];
|
|
65
|
-
}
|
|
@@ -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
|
-
}
|