@libraz/libcantus 0.9.3 → 0.9.5
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 +29 -20
- package/README_ja.md +268 -0
- package/dist/analyze/index.cjs +39 -1947
- package/dist/analyze/index.cjs.map +1 -1
- package/dist/analyze/index.d.cts +161 -91
- package/dist/analyze/index.d.ts +161 -91
- package/dist/analyze/index.js +19 -8
- package/dist/chunk-2A2QMA74.cjs +261 -0
- package/dist/chunk-2A2QMA74.cjs.map +1 -0
- package/dist/chunk-2PTFGVD7.js +261 -0
- package/dist/chunk-2PTFGVD7.js.map +1 -0
- package/dist/chunk-357ZDPVU.cjs +162 -0
- package/dist/chunk-357ZDPVU.cjs.map +1 -0
- package/dist/chunk-3KX76RLG.js +1548 -0
- package/dist/chunk-3KX76RLG.js.map +1 -0
- package/dist/chunk-4VZ5MZAM.cjs +889 -0
- package/dist/chunk-4VZ5MZAM.cjs.map +1 -0
- package/dist/{chunk-C5XYKUVG.js → chunk-7EONYVI5.js} +471 -171
- package/dist/chunk-7EONYVI5.js.map +1 -0
- package/dist/{chunk-IT2O4XFE.js → chunk-7JEP3MFY.js} +42 -34
- package/dist/chunk-7JEP3MFY.js.map +1 -0
- package/dist/{chunk-4MHA432G.js → chunk-AID75RN3.js} +572 -250
- package/dist/chunk-AID75RN3.js.map +1 -0
- package/dist/chunk-BSLTLGM3.cjs +497 -0
- package/dist/chunk-BSLTLGM3.cjs.map +1 -0
- package/dist/chunk-CU6VG2YM.cjs +109 -0
- package/dist/chunk-CU6VG2YM.cjs.map +1 -0
- package/dist/{chunk-EH6EM37U.js → chunk-DZMHIGI4.js} +81 -59
- package/dist/chunk-DZMHIGI4.js.map +1 -0
- package/dist/{chunk-AKLYPWIN.js → chunk-EDOTEABK.js} +45 -19
- package/dist/chunk-EDOTEABK.js.map +1 -0
- package/dist/{chunk-2ZWMSJH6.js → chunk-HN2OEUN2.js} +7 -4
- package/dist/chunk-HN2OEUN2.js.map +1 -0
- package/dist/{chunk-MIWO425M.js → chunk-KBTTEX7Q.js} +128 -43
- package/dist/chunk-KBTTEX7Q.js.map +1 -0
- package/dist/chunk-KQN2ZYND.cjs +724 -0
- package/dist/chunk-KQN2ZYND.cjs.map +1 -0
- package/dist/chunk-MPTVJIVG.cjs +3176 -0
- package/dist/chunk-MPTVJIVG.cjs.map +1 -0
- package/dist/chunk-MTMZTMWM.cjs +53 -0
- package/dist/chunk-MTMZTMWM.cjs.map +1 -0
- package/dist/{chunk-CHMXELDS.js → chunk-NNB67XA2.js} +372 -197
- package/dist/chunk-NNB67XA2.js.map +1 -0
- package/dist/chunk-OL3IHHSJ.cjs +1204 -0
- package/dist/chunk-OL3IHHSJ.cjs.map +1 -0
- package/dist/chunk-PI3UXRWK.cjs +528 -0
- package/dist/chunk-PI3UXRWK.cjs.map +1 -0
- package/dist/chunk-R2VVFAIN.js +528 -0
- package/dist/chunk-R2VVFAIN.js.map +1 -0
- package/dist/chunk-T64C7ZD7.cjs +1 -0
- package/dist/chunk-T64C7ZD7.cjs.map +1 -0
- package/dist/chunk-WFDXOLUB.cjs +337 -0
- package/dist/chunk-WFDXOLUB.cjs.map +1 -0
- package/dist/chunk-WTAN4ACG.cjs +1548 -0
- package/dist/chunk-WTAN4ACG.cjs.map +1 -0
- package/dist/chunk-YFJXS3AU.cjs +33 -0
- package/dist/chunk-YFJXS3AU.cjs.map +1 -0
- package/dist/{chunk-GOAW4VYL.js → chunk-YUE6TJ4M.js} +315 -145
- package/dist/chunk-YUE6TJ4M.js.map +1 -0
- package/dist/{chunk-62QZKCJQ.js → chunk-ZGLJM4A4.js} +10 -6
- package/dist/chunk-ZGLJM4A4.js.map +1 -0
- package/dist/core/index.cjs +140 -647
- package/dist/core/index.cjs.map +1 -1
- package/dist/core/index.d.cts +313 -41
- package/dist/core/index.d.ts +313 -41
- package/dist/core/index.js +64 -16
- package/dist/{function-DVH4Eusr.d.ts → function-CxixTB02.d.cts} +122 -10
- package/dist/{function-DYt4iKsn.d.cts → function-DTCt675z.d.ts} +122 -10
- package/dist/generate/index.cjs +28 -4085
- package/dist/generate/index.cjs.map +1 -1
- package/dist/generate/index.d.cts +374 -66
- package/dist/generate/index.d.ts +374 -66
- package/dist/generate/index.js +23 -9
- package/dist/{index-Jc0Ryi79.d.ts → index-B2Ulxxpo.d.cts} +21 -5
- package/dist/{index-CpOsP1y9.d.cts → index-BkYJ0xMq.d.cts} +18 -17
- package/dist/{index-CxqBQtH1.d.cts → index-BuaB-ypt.d.ts} +21 -5
- package/dist/index-CAN7v-kw.d.ts +199 -0
- package/dist/{index-Bt4tOUD9.d.ts → index-COw1Ky9g.d.ts} +93 -8
- package/dist/{index-Dikst44v.d.cts → index-Cfx8xgH0.d.ts} +14 -11
- package/dist/{index-DxvARIP2.d.ts → index-DRtIhlJj.d.ts} +18 -17
- 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-alrRninU.d.cts +199 -0
- package/dist/{index-BNlGP86A.d.cts → index-oTQbYYIs.d.cts} +93 -8
- package/dist/index-tR9jTn26.d.cts +275 -0
- package/dist/index-tR9jTn26.d.ts +275 -0
- package/dist/{index-Bg5dYMmZ.d.ts → index-x2vcsduE.d.cts} +14 -11
- package/dist/index.cjs +429 -7383
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +15 -15
- package/dist/index.d.ts +15 -15
- package/dist/index.js +121 -27
- package/dist/model/index.cjs +8 -2562
- package/dist/model/index.cjs.map +1 -1
- package/dist/model/index.d.cts +471 -81
- package/dist/model/index.d.ts +471 -81
- package/dist/model/index.js +6 -7
- package/dist/styled-Bl0ZK28h.d.ts +543 -0
- package/dist/styled-Crv6SA4S.d.cts +543 -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 +34 -13
- 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 +0 -202
- 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 +0 -924
- 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,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
|
-
}
|
|
@@ -1,285 +0,0 @@
|
|
|
1
|
-
import type { DrumRole, DrumStyle, SectionType } from './internal.js';
|
|
2
|
-
import { GM } from './internal.js';
|
|
3
|
-
import type { DrumRng } from './rng.js';
|
|
4
|
-
|
|
5
|
-
/** Hi-hat subdivision level. */
|
|
6
|
-
export type HiHatLevel = 'quarter' | 'eighth' | 'sixteenth';
|
|
7
|
-
|
|
8
|
-
/** Hi-hat articulation type. */
|
|
9
|
-
export type HiHatType = 'closed' | 'pedal' | 'open' | 'halfOpen' | 'ride';
|
|
10
|
-
|
|
11
|
-
/** BPM at or above which 16th-note hi-hats become 8ths for playability. */
|
|
12
|
-
export const HH_16TH_BPM_THRESHOLD = 150;
|
|
13
|
-
|
|
14
|
-
const FHH_VEL_MIN = 45;
|
|
15
|
-
const FHH_VEL_MAX = 60;
|
|
16
|
-
/** Velocity boost applied to dynamic open hi-hat accents. */
|
|
17
|
-
export const OHH_VEL_BOOST = 7;
|
|
18
|
-
|
|
19
|
-
/** True unless the role suppresses timekeeping cymbals entirely. */
|
|
20
|
-
export function shouldPlayHiHat(role: DrumRole): boolean {
|
|
21
|
-
return role !== 'fxOnly';
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
/** Preferred timekeeping instrument for a role. */
|
|
25
|
-
export function roleHiHatInstrument(role: DrumRole, useRide: boolean): number {
|
|
26
|
-
if (role === 'ambient') {
|
|
27
|
-
return GM.RIDE;
|
|
28
|
-
}
|
|
29
|
-
return useRide ? GM.RIDE : GM.CHH;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
function sparser(level: HiHatLevel): HiHatLevel {
|
|
33
|
-
if (level === 'sixteenth') {
|
|
34
|
-
return 'eighth';
|
|
35
|
-
}
|
|
36
|
-
if (level === 'eighth') {
|
|
37
|
-
return 'quarter';
|
|
38
|
-
}
|
|
39
|
-
return 'quarter';
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
function denser(level: HiHatLevel): HiHatLevel {
|
|
43
|
-
if (level === 'quarter') {
|
|
44
|
-
return 'eighth';
|
|
45
|
-
}
|
|
46
|
-
if (level === 'eighth') {
|
|
47
|
-
return 'sixteenth';
|
|
48
|
-
}
|
|
49
|
-
return 'sixteenth';
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
/** Choose the hi-hat subdivision for a section/style/density/BPM. */
|
|
53
|
-
export function getHiHatLevel(
|
|
54
|
-
section: SectionType,
|
|
55
|
-
style: DrumStyle,
|
|
56
|
-
backingDensity: 'thin' | 'normal' | 'thick',
|
|
57
|
-
bpm: number,
|
|
58
|
-
rng: DrumRng,
|
|
59
|
-
): HiHatLevel {
|
|
60
|
-
const allow16th = bpm < HH_16TH_BPM_THRESHOLD;
|
|
61
|
-
let base: HiHatLevel = 'eighth';
|
|
62
|
-
|
|
63
|
-
if (style === 'sparse') {
|
|
64
|
-
base = section === 'chorus' ? 'eighth' : 'quarter';
|
|
65
|
-
} else if (style === 'fourOnFloor') {
|
|
66
|
-
if (allow16th && section === 'chorus' && rng.prob(0.25)) {
|
|
67
|
-
return 'sixteenth';
|
|
68
|
-
}
|
|
69
|
-
return 'eighth';
|
|
70
|
-
} else if (style === 'synth') {
|
|
71
|
-
if (!allow16th) {
|
|
72
|
-
return 'eighth';
|
|
73
|
-
}
|
|
74
|
-
if (section === 'a' && rng.prob(0.2)) {
|
|
75
|
-
return 'eighth';
|
|
76
|
-
}
|
|
77
|
-
return 'sixteenth';
|
|
78
|
-
} else if (style === 'trap') {
|
|
79
|
-
return allow16th ? 'sixteenth' : 'eighth';
|
|
80
|
-
} else if (style === 'latin') {
|
|
81
|
-
if (allow16th && section === 'chorus' && rng.prob(0.3)) {
|
|
82
|
-
return 'sixteenth';
|
|
83
|
-
}
|
|
84
|
-
return 'eighth';
|
|
85
|
-
} else {
|
|
86
|
-
switch (section) {
|
|
87
|
-
case 'intro':
|
|
88
|
-
base = 'quarter';
|
|
89
|
-
break;
|
|
90
|
-
case 'outro':
|
|
91
|
-
base = 'eighth';
|
|
92
|
-
break;
|
|
93
|
-
case 'a':
|
|
94
|
-
base = rng.prob(0.3) ? 'quarter' : 'eighth';
|
|
95
|
-
break;
|
|
96
|
-
case 'b':
|
|
97
|
-
base = allow16th && rng.prob(0.25) ? 'sixteenth' : 'eighth';
|
|
98
|
-
break;
|
|
99
|
-
case 'chorus':
|
|
100
|
-
base = allow16th && rng.prob(0.35) ? 'sixteenth' : 'eighth';
|
|
101
|
-
break;
|
|
102
|
-
case 'bridge':
|
|
103
|
-
base = 'eighth';
|
|
104
|
-
break;
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
if (backingDensity === 'thin') {
|
|
109
|
-
base = sparser(base);
|
|
110
|
-
} else if (backingDensity === 'thick') {
|
|
111
|
-
base = denser(base);
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
if (!allow16th && base === 'sixteenth') {
|
|
115
|
-
base = 'eighth';
|
|
116
|
-
}
|
|
117
|
-
return base;
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
/** Metric velocity multiplier for a 16th position within a beat. */
|
|
121
|
-
export function hiHatVelocityMultiplier(sixteenth: number, rng: DrumRng): number {
|
|
122
|
-
let baseValue: number;
|
|
123
|
-
switch (sixteenth) {
|
|
124
|
-
case 0:
|
|
125
|
-
baseValue = 0.95;
|
|
126
|
-
break;
|
|
127
|
-
case 2:
|
|
128
|
-
baseValue = 0.75;
|
|
129
|
-
break;
|
|
130
|
-
case 1:
|
|
131
|
-
baseValue = 0.55;
|
|
132
|
-
break;
|
|
133
|
-
default:
|
|
134
|
-
baseValue = 0.5;
|
|
135
|
-
break;
|
|
136
|
-
}
|
|
137
|
-
return baseValue * rng.float(0.95, 1.05);
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
/** Bars between dynamic open hi-hat accents (0 disables them). */
|
|
141
|
-
export function openHiHatBarInterval(section: SectionType, style: DrumStyle): number {
|
|
142
|
-
if (style === 'sparse') {
|
|
143
|
-
return section === 'chorus' ? 4 : 0;
|
|
144
|
-
}
|
|
145
|
-
switch (section) {
|
|
146
|
-
case 'intro':
|
|
147
|
-
return style === 'fourOnFloor' ? 4 : 0;
|
|
148
|
-
case 'a':
|
|
149
|
-
return style === 'fourOnFloor' || style === 'upbeat' ? 2 : 4;
|
|
150
|
-
case 'b':
|
|
151
|
-
return 2;
|
|
152
|
-
case 'chorus':
|
|
153
|
-
return style === 'rock' || style === 'fourOnFloor' ? 1 : 2;
|
|
154
|
-
case 'bridge':
|
|
155
|
-
return 0;
|
|
156
|
-
case 'outro':
|
|
157
|
-
return 4;
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
/** Beat that receives the dynamic open hi-hat within a bar. */
|
|
162
|
-
export function openHiHatBeat(section: SectionType, rng: DrumRng): number {
|
|
163
|
-
if (section === 'chorus') {
|
|
164
|
-
const choice = rng.range(0, 3);
|
|
165
|
-
if (choice < 2) {
|
|
166
|
-
return 3;
|
|
167
|
-
}
|
|
168
|
-
if (choice < 3) {
|
|
169
|
-
return 1;
|
|
170
|
-
}
|
|
171
|
-
return 2;
|
|
172
|
-
}
|
|
173
|
-
return 3;
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
/** Whether the section uses an independent foot hi-hat pulse. */
|
|
177
|
-
export function shouldUseFootHiHat(section: SectionType, role: DrumRole): boolean {
|
|
178
|
-
if (role === 'fxOnly') {
|
|
179
|
-
return false;
|
|
180
|
-
}
|
|
181
|
-
switch (section) {
|
|
182
|
-
case 'intro':
|
|
183
|
-
case 'bridge':
|
|
184
|
-
case 'outro':
|
|
185
|
-
return true;
|
|
186
|
-
default:
|
|
187
|
-
return role === 'ambient' || role === 'minimal';
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
/** Primary hi-hat articulation for a section. */
|
|
192
|
-
export function sectionHiHatType(section: SectionType, role: DrumRole): HiHatType {
|
|
193
|
-
if (role === 'ambient') {
|
|
194
|
-
return 'ride';
|
|
195
|
-
}
|
|
196
|
-
if (role === 'minimal') {
|
|
197
|
-
return 'pedal';
|
|
198
|
-
}
|
|
199
|
-
switch (section) {
|
|
200
|
-
case 'intro':
|
|
201
|
-
case 'a':
|
|
202
|
-
return 'pedal';
|
|
203
|
-
case 'b':
|
|
204
|
-
return 'closed';
|
|
205
|
-
case 'chorus':
|
|
206
|
-
return 'open';
|
|
207
|
-
case 'bridge':
|
|
208
|
-
return 'ride';
|
|
209
|
-
case 'outro':
|
|
210
|
-
return 'halfOpen';
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
/** GM note for a hi-hat articulation. */
|
|
215
|
-
export function hiHatNote(type: HiHatType): number {
|
|
216
|
-
switch (type) {
|
|
217
|
-
case 'pedal':
|
|
218
|
-
return GM.FHH;
|
|
219
|
-
case 'open':
|
|
220
|
-
return GM.OHH;
|
|
221
|
-
case 'ride':
|
|
222
|
-
return GM.RIDE;
|
|
223
|
-
default:
|
|
224
|
-
return GM.CHH;
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
/** Velocity multiplier for a hi-hat articulation. */
|
|
229
|
-
export function hiHatTypeVelocityMultiplier(type: HiHatType): number {
|
|
230
|
-
switch (type) {
|
|
231
|
-
case 'halfOpen':
|
|
232
|
-
return 0.75;
|
|
233
|
-
case 'pedal':
|
|
234
|
-
return 0.65;
|
|
235
|
-
case 'open':
|
|
236
|
-
return 1.0;
|
|
237
|
-
case 'ride':
|
|
238
|
-
return 0.9;
|
|
239
|
-
default:
|
|
240
|
-
return 0.85;
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
/** Whether to accent with an open hi-hat at a given beat. */
|
|
245
|
-
export function shouldAddOpenHHAccent(
|
|
246
|
-
section: SectionType,
|
|
247
|
-
beat: number,
|
|
248
|
-
bar: number,
|
|
249
|
-
rng: DrumRng,
|
|
250
|
-
): boolean {
|
|
251
|
-
if (section !== 'chorus' && section !== 'b') {
|
|
252
|
-
return false;
|
|
253
|
-
}
|
|
254
|
-
if (section === 'chorus') {
|
|
255
|
-
if (beat === 1 || beat === 3) {
|
|
256
|
-
return rng.prob(0.6);
|
|
257
|
-
}
|
|
258
|
-
return false;
|
|
259
|
-
}
|
|
260
|
-
if (beat === 3 && bar % 2 === 1) {
|
|
261
|
-
return rng.prob(0.4);
|
|
262
|
-
}
|
|
263
|
-
return false;
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
/** Foot hi-hat velocity with slight humanization. */
|
|
267
|
-
export function footHiHatVelocity(rng: DrumRng): number {
|
|
268
|
-
return rng.range(FHH_VEL_MIN, FHH_VEL_MAX);
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
/** Whether the section uses a ride cymbal instead of hi-hats. */
|
|
272
|
-
export function shouldUseRideForSection(section: SectionType, style: DrumStyle): boolean {
|
|
273
|
-
if (style === 'rock' && section === 'chorus') {
|
|
274
|
-
return true;
|
|
275
|
-
}
|
|
276
|
-
if (style === 'sparse') {
|
|
277
|
-
return false;
|
|
278
|
-
}
|
|
279
|
-
return section === 'bridge';
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
/** Whether a bridge beat is carried by a cross-stick instead of the hi-hat. */
|
|
283
|
-
export function shouldUseBridgeCrossStick(section: SectionType, beat: number): boolean {
|
|
284
|
-
return section === 'bridge' && (beat === 1 || beat === 3);
|
|
285
|
-
}
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import { clampVel, GM } from './internal.js';
|
|
2
|
-
|
|
3
|
-
/** A single percussion onset. */
|
|
4
|
-
export type DrumHit = {
|
|
5
|
-
pitch: number;
|
|
6
|
-
startBeat: number;
|
|
7
|
-
durationBeat: number;
|
|
8
|
-
velocity: number;
|
|
9
|
-
};
|
|
10
|
-
|
|
11
|
-
/** Accumulator for drum onsets with velocity clamping and simple lookups. */
|
|
12
|
-
export class HitList {
|
|
13
|
-
readonly hits: DrumHit[] = [];
|
|
14
|
-
|
|
15
|
-
/** Append a hit, clamping velocity and dropping non-positive positions. */
|
|
16
|
-
add(pitch: number, startBeat: number, durationBeat: number, velocity: number): void {
|
|
17
|
-
this.hits.push({
|
|
18
|
-
pitch,
|
|
19
|
-
startBeat: Math.max(0, startBeat),
|
|
20
|
-
durationBeat,
|
|
21
|
-
velocity: clampVel(velocity),
|
|
22
|
-
});
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
/** True when a crash already sits within a 16th of `startBeat`. */
|
|
26
|
-
hasCrashNear(startBeat: number): boolean {
|
|
27
|
-
return this.hits.some(
|
|
28
|
-
(h) => h.pitch === GM.CRASH && h.startBeat >= startBeat && h.startBeat < startBeat + 0.25,
|
|
29
|
-
);
|
|
30
|
-
}
|
|
31
|
-
}
|