@onjmin/dtm 2.1.9 → 2.1.11
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/dist/index.d.mts +433 -9
- package/dist/index.d.ts +433 -9
- package/dist/index.js +1859 -454
- package/dist/index.mjs +1845 -454
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -22,10 +22,13 @@ var index_exports = {};
|
|
|
22
22
|
__export(index_exports, {
|
|
23
23
|
A4_HZ: () => A4_HZ,
|
|
24
24
|
A4_UNITS: () => A4_UNITS,
|
|
25
|
+
BLUES_SCALE: () => BLUES_SCALE,
|
|
25
26
|
BREATH_MARK: () => BREATH_MARK,
|
|
26
27
|
CENTS_PER_UNIT: () => CENTS_PER_UNIT,
|
|
27
28
|
COMPOSE_KEYS: () => COMPOSE_KEYS,
|
|
28
29
|
COMPOSE_MOOD_GROUPS: () => COMPOSE_MOOD_GROUPS,
|
|
30
|
+
COMPOSE_SCALES: () => COMPOSE_SCALES,
|
|
31
|
+
COMPOSE_SCALE_IDS: () => COMPOSE_SCALE_IDS,
|
|
29
32
|
CORPUS_BANDS: () => CORPUS_BANDS,
|
|
30
33
|
CORPUS_SIZE: () => CORPUS_SIZE,
|
|
31
34
|
DAW_CSS: () => DAW_CSS,
|
|
@@ -45,7 +48,11 @@ __export(index_exports, {
|
|
|
45
48
|
FADE_IN_MARK: () => FADE_IN_MARK,
|
|
46
49
|
FADE_OUT_MARK: () => FADE_OUT_MARK,
|
|
47
50
|
GLOBAL_STORAGE_KEYS: () => GLOBAL_STORAGE_KEYS,
|
|
51
|
+
GM_BRIGHT_CEILING: () => GM_BRIGHT_CEILING,
|
|
48
52
|
GM_INSTRUMENT_NAMES: () => GM_INSTRUMENT_NAMES,
|
|
53
|
+
GM_INSTRUMENT_RANGE: () => GM_INSTRUMENT_RANGE,
|
|
54
|
+
HARMONIC_MINOR_SCALE: () => HARMONIC_MINOR_SCALE,
|
|
55
|
+
HUNGARIAN_SCALE: () => HUNGARIAN_SCALE,
|
|
49
56
|
INSTRUMENT_PRESETS: () => INSTRUMENT_PRESETS,
|
|
50
57
|
KEY_COUNT: () => KEY_COUNT,
|
|
51
58
|
KOE_BASE_URL: () => KOE_BASE_URL,
|
|
@@ -55,6 +62,7 @@ __export(index_exports, {
|
|
|
55
62
|
LinkedList: () => LinkedList,
|
|
56
63
|
MACRO_STORAGE_KEYS: () => MACRO_STORAGE_KEYS,
|
|
57
64
|
MAJOR_KEY_IDS: () => MAJOR_KEY_IDS,
|
|
65
|
+
MAJOR_SCALE: () => MAJOR_SCALE2,
|
|
58
66
|
MAX_VOCAL_VOLUME: () => MAX_VOCAL_VOLUME,
|
|
59
67
|
MICRO_STEP: () => MICRO_STEP,
|
|
60
68
|
MINOR_KEY_IDS: () => MINOR_KEY_IDS,
|
|
@@ -123,10 +131,12 @@ __export(index_exports, {
|
|
|
123
131
|
featureVector: () => featureVector,
|
|
124
132
|
fifthToStep: () => fifthToStep,
|
|
125
133
|
fifthToUnits: () => fifthToUnits,
|
|
134
|
+
fitInstrumentOctave: () => fitInstrumentOctave,
|
|
126
135
|
formatMmlMeta: () => formatMmlMeta,
|
|
127
136
|
freqFromPitch: () => freqFromPitch,
|
|
128
137
|
generateRandomPattern: () => generateRandomPattern,
|
|
129
138
|
getComposeKeyDescription: () => getComposeKeyDescription,
|
|
139
|
+
getComposeScaleDescription: () => getComposeScaleDescription,
|
|
130
140
|
getDrumPatternKeys: () => getDrumPatternKeys,
|
|
131
141
|
getMidiBPM: () => getMidiBPM,
|
|
132
142
|
icon: () => icon,
|
|
@@ -162,9 +172,13 @@ __export(index_exports, {
|
|
|
162
172
|
readGlobalSetting: () => readGlobalSetting,
|
|
163
173
|
readMacroSections: () => readMacroSections,
|
|
164
174
|
readMacroSetting: () => readMacroSetting,
|
|
175
|
+
resolveCenter: () => resolveCenter,
|
|
165
176
|
resolveComposeKey: () => resolveComposeKey,
|
|
177
|
+
resolveComposeScale: () => resolveComposeScale,
|
|
166
178
|
resolveDrumPattern: () => resolveDrumPattern,
|
|
167
179
|
resolveLoopPoint: () => resolveLoopPoint,
|
|
180
|
+
scaleDegrees: () => scaleDegrees,
|
|
181
|
+
scaleSize: () => scaleSize,
|
|
168
182
|
semitonesToUnits: () => semitonesToUnits,
|
|
169
183
|
shiftNotes: () => shiftNotes,
|
|
170
184
|
showLoadingOverlay: () => showLoadingOverlay,
|
|
@@ -1956,11 +1970,19 @@ var createChannelStrip = (ctx, destination, options = {}) => {
|
|
|
1956
1970
|
const duckGain = ctx.createGain();
|
|
1957
1971
|
duckGain.gain.value = 1;
|
|
1958
1972
|
const DUCK_ATTACK_SEC = 8e-3;
|
|
1973
|
+
let duckReleaseEndAt = 0;
|
|
1959
1974
|
const duck = (atTime, depth = 0.3, releaseSec = 0.18) => {
|
|
1960
1975
|
const t = Math.max(atTime, ctx.currentTime);
|
|
1961
1976
|
const floor = clamp(1 - depth, 0, 1);
|
|
1962
|
-
duckGain.gain
|
|
1963
|
-
|
|
1977
|
+
const param = duckGain.gain;
|
|
1978
|
+
if (t >= duckReleaseEndAt) {
|
|
1979
|
+
param.setValueAtTime(1, t);
|
|
1980
|
+
} else if (typeof param.cancelAndHoldAtTime === "function") {
|
|
1981
|
+
param.cancelAndHoldAtTime(t);
|
|
1982
|
+
}
|
|
1983
|
+
param.linearRampToValueAtTime(floor, t + DUCK_ATTACK_SEC);
|
|
1984
|
+
param.linearRampToValueAtTime(1, t + DUCK_ATTACK_SEC + releaseSec);
|
|
1985
|
+
duckReleaseEndAt = t + DUCK_ATTACK_SEC + releaseSec;
|
|
1964
1986
|
};
|
|
1965
1987
|
eqHigh.connect(compressor);
|
|
1966
1988
|
compressor.connect(duckGain);
|
|
@@ -2257,12 +2279,15 @@ var buildChordPlacements = (options) => {
|
|
|
2257
2279
|
}
|
|
2258
2280
|
}
|
|
2259
2281
|
} else if (patternType === "alternating") {
|
|
2282
|
+
const quarterSteps = Math.floor(stepsPerBar / 4);
|
|
2260
2283
|
notes.forEach((noteOffset, i2) => {
|
|
2261
|
-
const stepOffset = i2 *
|
|
2284
|
+
const stepOffset = i2 * quarterSteps;
|
|
2285
|
+
const isLast = i2 === notes.length - 1;
|
|
2286
|
+
const durationSteps = isLast ? Math.max(12, noteLength - stepOffset) : Math.max(12, quarterSteps);
|
|
2262
2287
|
placements.push({
|
|
2263
2288
|
startStep: chord.whenStep + stepOffset,
|
|
2264
2289
|
pitchUnits: toUnits(noteOffset),
|
|
2265
|
-
durationSteps
|
|
2290
|
+
durationSteps,
|
|
2266
2291
|
velocity: 100
|
|
2267
2292
|
});
|
|
2268
2293
|
});
|
|
@@ -4890,6 +4915,45 @@ var createReverbImpulse = (ctx, decaySec = DEFAULT_REVERB_DECAY_SEC) => {
|
|
|
4890
4915
|
};
|
|
4891
4916
|
var reverbAmountToGain = (amount) => Math.max(0, Math.min(100, amount)) / 100;
|
|
4892
4917
|
|
|
4918
|
+
// src/safety-limiter.ts
|
|
4919
|
+
var THRESHOLD_DB = -1;
|
|
4920
|
+
var KNEE_DB = 0;
|
|
4921
|
+
var RATIO = 20;
|
|
4922
|
+
var ATTACK_SEC = 1e-3;
|
|
4923
|
+
var RELEASE_SEC = 0.1;
|
|
4924
|
+
var CURVE_SAMPLES2 = 2048;
|
|
4925
|
+
var SOFT_KNEE = 0.85;
|
|
4926
|
+
var CEILING = 0.98;
|
|
4927
|
+
var SHAPER_RANGE = 4;
|
|
4928
|
+
var OVERSAMPLE2 = "none";
|
|
4929
|
+
var createSoftClipCurve = () => {
|
|
4930
|
+
const curve = new Float32Array(CURVE_SAMPLES2);
|
|
4931
|
+
const span = CEILING - SOFT_KNEE;
|
|
4932
|
+
for (let i2 = 0; i2 < CURVE_SAMPLES2; i2++) {
|
|
4933
|
+
const x2 = (i2 / (CURVE_SAMPLES2 - 1) * 2 - 1) * SHAPER_RANGE;
|
|
4934
|
+
const a = Math.abs(x2);
|
|
4935
|
+
curve[i2] = Math.sign(x2) * (a <= SOFT_KNEE ? a : SOFT_KNEE + span * Math.tanh((a - SOFT_KNEE) / span));
|
|
4936
|
+
}
|
|
4937
|
+
return curve;
|
|
4938
|
+
};
|
|
4939
|
+
var createSafetyLimiter = (ctx, destination) => {
|
|
4940
|
+
const limiter = ctx.createDynamicsCompressor();
|
|
4941
|
+
limiter.threshold.value = THRESHOLD_DB;
|
|
4942
|
+
limiter.knee.value = KNEE_DB;
|
|
4943
|
+
limiter.ratio.value = RATIO;
|
|
4944
|
+
limiter.attack.value = ATTACK_SEC;
|
|
4945
|
+
limiter.release.value = RELEASE_SEC;
|
|
4946
|
+
const preScale = ctx.createGain();
|
|
4947
|
+
preScale.gain.value = 1 / SHAPER_RANGE;
|
|
4948
|
+
const softClip = ctx.createWaveShaper();
|
|
4949
|
+
softClip.curve = createSoftClipCurve();
|
|
4950
|
+
softClip.oversample = OVERSAMPLE2;
|
|
4951
|
+
limiter.connect(preScale);
|
|
4952
|
+
preScale.connect(softClip);
|
|
4953
|
+
softClip.connect(destination);
|
|
4954
|
+
return limiter;
|
|
4955
|
+
};
|
|
4956
|
+
|
|
4893
4957
|
// src/sequencer.ts
|
|
4894
4958
|
var STEPS_PER_BEAT = 48;
|
|
4895
4959
|
var PLAN_TIME = 0.5;
|
|
@@ -7353,6 +7417,9 @@ var SONG_DRUM_PATTERNS = {
|
|
|
7353
7417
|
|
|
7354
7418
|
// src/synth.ts
|
|
7355
7419
|
var freqFromPitch = (pitchUnits) => unitsToHz(pitchUnits);
|
|
7420
|
+
var MIN_ATTACK_SEC = 15e-4;
|
|
7421
|
+
var MIN_RELEASE_SEC = 4e-3;
|
|
7422
|
+
var TAIL_RATIO = 1e-3;
|
|
7356
7423
|
var createSynth = (ctx, destination = ctx.destination, tone = {}) => {
|
|
7357
7424
|
const wave = tone.wave ?? "square";
|
|
7358
7425
|
const attack = tone.attack ?? 0;
|
|
@@ -7371,25 +7438,25 @@ var createSynth = (ctx, destination = ctx.destination, tone = {}) => {
|
|
|
7371
7438
|
osc.frequency.value = freqFromPitch(e.pitchUnits);
|
|
7372
7439
|
const t0 = ctx.currentTime + e.when;
|
|
7373
7440
|
const peak = Math.max(1e-4, 0.06 * e.volume * 1.5 * gainScale);
|
|
7441
|
+
const tail = peak * TAIL_RATIO;
|
|
7442
|
+
const stopAt = t0 + e.duration + MIN_RELEASE_SEC;
|
|
7374
7443
|
if (tone.decay) {
|
|
7375
7444
|
gain.gain.setValueAtTime(1e-4, t0);
|
|
7376
7445
|
gain.gain.linearRampToValueAtTime(peak, t0 + Math.max(3e-3, attack));
|
|
7377
|
-
gain.gain.exponentialRampToValueAtTime(
|
|
7446
|
+
gain.gain.exponentialRampToValueAtTime(tail, t0 + e.duration);
|
|
7378
7447
|
} else {
|
|
7379
7448
|
const releaseTime = Math.min(0.02, e.duration * 0.1);
|
|
7380
7449
|
const sustainDuration = e.duration - releaseTime;
|
|
7381
|
-
|
|
7382
|
-
|
|
7383
|
-
|
|
7384
|
-
|
|
7385
|
-
|
|
7386
|
-
|
|
7387
|
-
} else {
|
|
7388
|
-
gain.gain.setValueAtTime(peak, t0);
|
|
7389
|
-
}
|
|
7450
|
+
const attackTime = Math.min(
|
|
7451
|
+
Math.max(attack, MIN_ATTACK_SEC),
|
|
7452
|
+
sustainDuration
|
|
7453
|
+
);
|
|
7454
|
+
gain.gain.setValueAtTime(1e-4, t0);
|
|
7455
|
+
gain.gain.linearRampToValueAtTime(peak, t0 + attackTime);
|
|
7390
7456
|
gain.gain.setValueAtTime(peak, t0 + sustainDuration);
|
|
7391
|
-
gain.gain.exponentialRampToValueAtTime(
|
|
7457
|
+
gain.gain.exponentialRampToValueAtTime(tail, t0 + e.duration);
|
|
7392
7458
|
}
|
|
7459
|
+
gain.gain.linearRampToValueAtTime(0, stopAt);
|
|
7393
7460
|
osc.connect(gain);
|
|
7394
7461
|
let panner = null;
|
|
7395
7462
|
if (typeof ctx.createStereoPanner === "function" && e.pan) {
|
|
@@ -7401,7 +7468,7 @@ var createSynth = (ctx, destination = ctx.destination, tone = {}) => {
|
|
|
7401
7468
|
gain.connect(compressor);
|
|
7402
7469
|
}
|
|
7403
7470
|
osc.start(t0);
|
|
7404
|
-
osc.stop(
|
|
7471
|
+
osc.stop(stopAt);
|
|
7405
7472
|
osc.onended = () => {
|
|
7406
7473
|
osc.disconnect();
|
|
7407
7474
|
gain.disconnect();
|
|
@@ -7416,14 +7483,21 @@ var createSynth = (ctx, destination = ctx.destination, tone = {}) => {
|
|
|
7416
7483
|
if (isKick) {
|
|
7417
7484
|
const osc = ctx.createOscillator();
|
|
7418
7485
|
const g2 = ctx.createGain();
|
|
7486
|
+
const kickPeak = vol * 0.135;
|
|
7487
|
+
const kickDecayEnd = t0 + 0.18;
|
|
7488
|
+
const kickEnd = kickDecayEnd + MIN_RELEASE_SEC;
|
|
7419
7489
|
osc.frequency.setValueAtTime(150, t0);
|
|
7420
7490
|
osc.frequency.exponentialRampToValueAtTime(50, t0 + 0.12);
|
|
7421
|
-
g2.gain.setValueAtTime(
|
|
7422
|
-
g2.gain.exponentialRampToValueAtTime(
|
|
7491
|
+
g2.gain.setValueAtTime(kickPeak, t0);
|
|
7492
|
+
g2.gain.exponentialRampToValueAtTime(kickPeak * TAIL_RATIO, kickDecayEnd);
|
|
7493
|
+
g2.gain.linearRampToValueAtTime(0, kickEnd);
|
|
7423
7494
|
osc.connect(g2).connect(compressor);
|
|
7424
7495
|
osc.start(t0);
|
|
7425
|
-
osc.stop(
|
|
7426
|
-
osc.onended = () =>
|
|
7496
|
+
osc.stop(kickEnd);
|
|
7497
|
+
osc.onended = () => {
|
|
7498
|
+
osc.disconnect();
|
|
7499
|
+
g2.disconnect();
|
|
7500
|
+
};
|
|
7427
7501
|
return;
|
|
7428
7502
|
}
|
|
7429
7503
|
const dur = isSnareLike ? 0.18 : 0.05;
|
|
@@ -7437,8 +7511,13 @@ var createSynth = (ctx, destination = ctx.destination, tone = {}) => {
|
|
|
7437
7511
|
filter.type = isSnareLike ? "bandpass" : "highpass";
|
|
7438
7512
|
filter.frequency.value = isSnareLike ? 2e3 : 8e3;
|
|
7439
7513
|
const g = ctx.createGain();
|
|
7440
|
-
|
|
7441
|
-
g.gain.
|
|
7514
|
+
const noisePeak = vol * (isSnareLike ? 0.105 : 0.06);
|
|
7515
|
+
g.gain.setValueAtTime(noisePeak, t0);
|
|
7516
|
+
g.gain.exponentialRampToValueAtTime(
|
|
7517
|
+
noisePeak * TAIL_RATIO,
|
|
7518
|
+
t0 + dur - MIN_RELEASE_SEC
|
|
7519
|
+
);
|
|
7520
|
+
g.gain.linearRampToValueAtTime(0, t0 + dur);
|
|
7442
7521
|
src.connect(filter).connect(g).connect(compressor);
|
|
7443
7522
|
src.start(t0);
|
|
7444
7523
|
src.stop(t0 + dur);
|
|
@@ -7500,7 +7579,7 @@ var playPlacements = (placements, options) => {
|
|
|
7500
7579
|
reverbPreDelay.connect(reverbConvolver);
|
|
7501
7580
|
reverbConvolver.connect(reverbWetGain);
|
|
7502
7581
|
reverbWetGain.connect(finalMix);
|
|
7503
|
-
finalMix.connect(rawDestination);
|
|
7582
|
+
finalMix.connect(createSafetyLimiter(ctx, rawDestination));
|
|
7504
7583
|
const channelStrips = /* @__PURE__ */ new Map();
|
|
7505
7584
|
const getChannelStrip = (index) => {
|
|
7506
7585
|
let strip = channelStrips.get(index);
|
|
@@ -8314,6 +8393,22 @@ var DAW_CSS = `
|
|
|
8314
8393
|
opacity: 0.85;
|
|
8315
8394
|
}
|
|
8316
8395
|
.dtm-pill:not(.dtm-pill--active):active { transform: translate(1px,1px); box-shadow: none; }
|
|
8396
|
+
/* \u30DC\u30FC\u30AB\u30EB\u304C\u9078\u629E\u3055\u308C\u3066\u3044\u308B\u30C8\u30E9\u30C3\u30AF\u306E\u30BF\u30D6\u306B\u3001\u3046\u3063\u3059\u3089\u58F0\u306E\u30A2\u30A4\u30B3\u30F3\u3092\u91CD\u306D\u308B\uFF08\u80CC\u666F\u8272\u30FB\u30B5\u30A4\u30BA\u306F\u5909\u3048\u306A\u3044\uFF09 */
|
|
8397
|
+
.dtm-pill--vocal::after {
|
|
8398
|
+
content: '';
|
|
8399
|
+
position: absolute;
|
|
8400
|
+
inset: 0;
|
|
8401
|
+
background-image: var(--dtm-pill-icon);
|
|
8402
|
+
background-size: contain;
|
|
8403
|
+
background-repeat: no-repeat;
|
|
8404
|
+
background-position: right center;
|
|
8405
|
+
opacity: 0.4;
|
|
8406
|
+
pointer-events: none;
|
|
8407
|
+
}
|
|
8408
|
+
.dtm-pill__label {
|
|
8409
|
+
position: relative;
|
|
8410
|
+
z-index: 1;
|
|
8411
|
+
}
|
|
8317
8412
|
/* \u518D\u751F\u4E2D\u3001\u5B9F\u969B\u306B\u767A\u97F3\u3057\u305F\u77AC\u9593\u3060\u3051\u70B9\u706F\uFF08\u3069\u306E\u30BF\u30D6\u304C\u4ECA\u9CF4\u3063\u3066\u3044\u308B\u304B\u8996\u899A\u7684\u306B\u5206\u304B\u308B\u3088\u3046\u306B\uFF09 */
|
|
8318
8413
|
.dtm-pill--sounding {
|
|
8319
8414
|
filter: brightness(1.6);
|
|
@@ -9939,17 +10034,24 @@ var mountMmlPlayer = (target, mml, options = {}) => {
|
|
|
9939
10034
|
if (!audioCtx) audioCtx = new AudioContext();
|
|
9940
10035
|
return audioCtx;
|
|
9941
10036
|
};
|
|
10037
|
+
let limiterNode = null;
|
|
10038
|
+
const ensureOutput = () => {
|
|
10039
|
+
const ctx = ensureCtx();
|
|
10040
|
+
if (!limiterNode) limiterNode = createSafetyLimiter(ctx, ctx.destination);
|
|
10041
|
+
return limiterNode;
|
|
10042
|
+
};
|
|
9942
10043
|
let synthInstance = null;
|
|
9943
10044
|
const ensureSynth = () => {
|
|
9944
|
-
if (!synthInstance)
|
|
10045
|
+
if (!synthInstance) {
|
|
10046
|
+
synthInstance = createSynth(ensureCtx(), ensureOutput());
|
|
10047
|
+
}
|
|
9945
10048
|
return synthInstance;
|
|
9946
10049
|
};
|
|
9947
10050
|
let voices = null;
|
|
9948
10051
|
const ensureVoices = () => {
|
|
9949
10052
|
if (options.singingVoices) return options.singingVoices;
|
|
9950
10053
|
if (!voices) {
|
|
9951
|
-
|
|
9952
|
-
voices = createSingingVoices(ctx, ctx.destination);
|
|
10054
|
+
voices = createSingingVoices(ensureCtx(), ensureOutput());
|
|
9953
10055
|
voices.setVolume(trackVolume / 100 * (masterVolume / 100));
|
|
9954
10056
|
}
|
|
9955
10057
|
return voices;
|
|
@@ -11011,6 +11113,12 @@ var SoundFont = class _SoundFont {
|
|
|
11011
11113
|
// ファミリごとに変える。
|
|
11012
11114
|
/** アタック(無音からピークまで)秒。クリック防止の最小限。全楽器共通。 */
|
|
11013
11115
|
static attackSec = 5e-3;
|
|
11116
|
+
/**
|
|
11117
|
+
* 消え際に最低限確保する秒数。アタックと対になるクリック防止で、**サンプルが
|
|
11118
|
+
* 終わるまでに**必ずここまでに 0 へ落とし切る。振幅が残ったままバッファが尽きたり
|
|
11119
|
+
* `stop()` が来たりすると、その瞬間の値がそのまま段差になりプチノイズが出る。
|
|
11120
|
+
*/
|
|
11121
|
+
static minReleaseSec = 4e-3;
|
|
11014
11122
|
/**
|
|
11015
11123
|
* 減衰の型ごとのエンベロープ。
|
|
11016
11124
|
*
|
|
@@ -11197,14 +11305,23 @@ var SoundFont = class _SoundFont {
|
|
|
11197
11305
|
const startGainTime = Math.max(ctx.currentTime, _when);
|
|
11198
11306
|
g.gain.setValueAtTime(0, startGainTime);
|
|
11199
11307
|
const env = _SoundFont.envelopes[this.style.env] ?? _SoundFont.envelopes.sustain;
|
|
11200
|
-
const
|
|
11308
|
+
const playRate = _param.playbackRate * 2 ** ((humanizeCents + detuneCents) / 1200);
|
|
11309
|
+
const sampleEnd = _when + (buffer.duration - startOffsetSec) / playRate;
|
|
11310
|
+
const limit = src.loop ? Number.POSITIVE_INFINITY : sampleEnd;
|
|
11201
11311
|
const attackEnd = Math.min(startGainTime + _SoundFont.attackSec, limit);
|
|
11202
11312
|
const decayEnd = Math.min(
|
|
11203
11313
|
Math.max(attackEnd, attackEnd + env.decaySec),
|
|
11204
11314
|
limit
|
|
11205
11315
|
);
|
|
11206
|
-
const
|
|
11207
|
-
|
|
11316
|
+
const tailRoom = Math.min(
|
|
11317
|
+
_SoundFont.minReleaseSec,
|
|
11318
|
+
Math.max(0, limit - decayEnd)
|
|
11319
|
+
);
|
|
11320
|
+
const noteOff = Math.min(
|
|
11321
|
+
Math.max(decayEnd, _when + duration),
|
|
11322
|
+
limit - tailRoom
|
|
11323
|
+
);
|
|
11324
|
+
const end = isDrum ? sampleEnd : Math.max(Math.min(noteOff + env.releaseSec, limit), noteOff + tailRoom);
|
|
11208
11325
|
if (!isDrum) {
|
|
11209
11326
|
const sustainVolume = effectiveVolume * env.sustain;
|
|
11210
11327
|
g.gain.linearRampToValueAtTime(effectiveVolume, attackEnd);
|
|
@@ -11213,6 +11330,11 @@ var SoundFont = class _SoundFont {
|
|
|
11213
11330
|
g.gain.linearRampToValueAtTime(0, end);
|
|
11214
11331
|
} else {
|
|
11215
11332
|
g.gain.linearRampToValueAtTime(effectiveVolume, attackEnd);
|
|
11333
|
+
const releaseStart = Math.max(attackEnd, end - _SoundFont.minReleaseSec);
|
|
11334
|
+
if (releaseStart > attackEnd) {
|
|
11335
|
+
g.gain.setValueAtTime(effectiveVolume, releaseStart);
|
|
11336
|
+
}
|
|
11337
|
+
g.gain.linearRampToValueAtTime(0, end);
|
|
11216
11338
|
}
|
|
11217
11339
|
if (filter) src.connect(filter).connect(g);
|
|
11218
11340
|
else src.connect(g);
|
|
@@ -11422,12 +11544,10 @@ var addParam = (zone, pitch) => {
|
|
|
11422
11544
|
coarseTune,
|
|
11423
11545
|
fineTune,
|
|
11424
11546
|
sampleRate,
|
|
11425
|
-
delay
|
|
11426
|
-
buffer
|
|
11547
|
+
delay
|
|
11427
11548
|
} = zone;
|
|
11428
11549
|
const baseDetune = originalPitch - 100 * coarseTune - fineTune;
|
|
11429
11550
|
const playbackRate = 2 ** ((100 * pitch - baseDetune) / 1200);
|
|
11430
|
-
const max = (buffer?.duration ?? 0) / playbackRate;
|
|
11431
11551
|
const src = {
|
|
11432
11552
|
loop: loopStart >= 1 && loopStart < loopEnd
|
|
11433
11553
|
};
|
|
@@ -11435,7 +11555,7 @@ var addParam = (zone, pitch) => {
|
|
|
11435
11555
|
[src.loopStart, src.loopEnd] = [loopStart, loopEnd].map(
|
|
11436
11556
|
(v) => v / sampleRate + delay
|
|
11437
11557
|
);
|
|
11438
|
-
zone._param = { playbackRate,
|
|
11558
|
+
zone._param = { playbackRate, src };
|
|
11439
11559
|
};
|
|
11440
11560
|
|
|
11441
11561
|
// src/chord-player.ts
|
|
@@ -12733,29 +12853,30 @@ var CORPUS_BANDS = {
|
|
|
12733
12853
|
climaxPeaks: [1, 2, 13.5, 26],
|
|
12734
12854
|
complementarity: [0, 0.026, 0.179, 0.405]
|
|
12735
12855
|
};
|
|
12736
|
-
var
|
|
12737
|
-
entropy
|
|
12738
|
-
valueKinds
|
|
12739
|
-
restRatio
|
|
12740
|
-
leapRatio
|
|
12741
|
-
stepRatio
|
|
12742
|
-
chromaticRatio
|
|
12743
|
-
maxLeap
|
|
12744
|
-
melodyRange
|
|
12745
|
-
notesPerBar
|
|
12746
|
-
shortNoteRatio
|
|
12747
|
-
barDensityCv
|
|
12748
|
-
densityCliff
|
|
12749
|
-
sim1
|
|
12750
|
-
sim2
|
|
12751
|
-
sim4
|
|
12752
|
-
sim8
|
|
12753
|
-
phraseBreath
|
|
12754
|
-
turnRatio
|
|
12755
|
-
climaxPosition
|
|
12756
|
-
climaxPeaks
|
|
12757
|
-
complementarity
|
|
12758
|
-
|
|
12856
|
+
var CORPUS_PROFILE_KEYS = [
|
|
12857
|
+
"entropy",
|
|
12858
|
+
"valueKinds",
|
|
12859
|
+
"restRatio",
|
|
12860
|
+
"leapRatio",
|
|
12861
|
+
"stepRatio",
|
|
12862
|
+
"chromaticRatio",
|
|
12863
|
+
"maxLeap",
|
|
12864
|
+
"melodyRange",
|
|
12865
|
+
"notesPerBar",
|
|
12866
|
+
"shortNoteRatio",
|
|
12867
|
+
"barDensityCv",
|
|
12868
|
+
"densityCliff",
|
|
12869
|
+
"sim1",
|
|
12870
|
+
"sim2",
|
|
12871
|
+
"sim4",
|
|
12872
|
+
"sim8",
|
|
12873
|
+
"phraseBreath",
|
|
12874
|
+
"turnRatio",
|
|
12875
|
+
"climaxPosition",
|
|
12876
|
+
"climaxPeaks",
|
|
12877
|
+
"complementarity"
|
|
12878
|
+
];
|
|
12879
|
+
var CORPUS_DEVIATION_BUDGET = 4;
|
|
12759
12880
|
var CORPUS_CELL_WEIGHTS = {
|
|
12760
12881
|
"0,2,4,6,8,10,12,14": 584,
|
|
12761
12882
|
"0,2,4,6,8,12,14": 512,
|
|
@@ -13620,16 +13741,15 @@ var tensionFeatures = (barTension, opts) => {
|
|
|
13620
13741
|
return { rise, resolve };
|
|
13621
13742
|
};
|
|
13622
13743
|
var band = (v, lo, idealLo, idealHi, hi) => {
|
|
13623
|
-
if (v <= lo || v >= hi) return 0;
|
|
13624
13744
|
if (v >= idealLo && v <= idealHi) return 1;
|
|
13745
|
+
if (v <= lo || v >= hi) return 0;
|
|
13625
13746
|
if (v < idealLo) return idealLo === lo ? 0 : (v - lo) / (idealLo - lo);
|
|
13626
13747
|
return hi === idealHi ? 0 : (hi - v) / (hi - idealHi);
|
|
13627
13748
|
};
|
|
13628
|
-
var
|
|
13629
|
-
const
|
|
13630
|
-
|
|
13631
|
-
|
|
13632
|
-
return 1 - 0.15 * Math.min(1, Math.abs(v - median) / spread);
|
|
13749
|
+
var plausibleBand = (v, b) => {
|
|
13750
|
+
const span = b[3] - b[0];
|
|
13751
|
+
const margin = span > 0 ? span * 0.5 : 1;
|
|
13752
|
+
return band(v, b[0] - margin, b[0], b[3], b[3] + margin);
|
|
13633
13753
|
};
|
|
13634
13754
|
var featureVector = (f) => [
|
|
13635
13755
|
f.entropy / 3,
|
|
@@ -13653,6 +13773,650 @@ var featureDistance = (a, b) => {
|
|
|
13653
13773
|
return Math.sqrt(sum);
|
|
13654
13774
|
};
|
|
13655
13775
|
|
|
13776
|
+
// src/compose-scales.ts
|
|
13777
|
+
var MAJOR_SCALE2 = [
|
|
13778
|
+
{ semi: 0, fifth: 0 },
|
|
13779
|
+
// C
|
|
13780
|
+
{ semi: 2, fifth: 2 },
|
|
13781
|
+
// D
|
|
13782
|
+
{ semi: 4, fifth: 4 },
|
|
13783
|
+
// E
|
|
13784
|
+
{ semi: 5, fifth: -1 },
|
|
13785
|
+
// F
|
|
13786
|
+
{ semi: 7, fifth: 1 },
|
|
13787
|
+
// G
|
|
13788
|
+
{ semi: 9, fifth: 3 },
|
|
13789
|
+
// A
|
|
13790
|
+
{ semi: 11, fifth: 5 }
|
|
13791
|
+
// B
|
|
13792
|
+
];
|
|
13793
|
+
var HARMONIC_MINOR_SCALE = [
|
|
13794
|
+
{ semi: 0, fifth: 0 },
|
|
13795
|
+
// C
|
|
13796
|
+
{ semi: 2, fifth: 2 },
|
|
13797
|
+
// D
|
|
13798
|
+
{ semi: 4, fifth: 4 },
|
|
13799
|
+
// E
|
|
13800
|
+
{ semi: 5, fifth: -1 },
|
|
13801
|
+
// F
|
|
13802
|
+
{ semi: 8, fifth: 8 },
|
|
13803
|
+
// G#
|
|
13804
|
+
{ semi: 9, fifth: 3 },
|
|
13805
|
+
// A
|
|
13806
|
+
{ semi: 11, fifth: 5 }
|
|
13807
|
+
// B
|
|
13808
|
+
];
|
|
13809
|
+
var HUNGARIAN_SCALE = [
|
|
13810
|
+
{ semi: 0, fifth: 0 },
|
|
13811
|
+
// C
|
|
13812
|
+
{ semi: 3, fifth: 9 },
|
|
13813
|
+
// D#
|
|
13814
|
+
{ semi: 4, fifth: 4 },
|
|
13815
|
+
// E
|
|
13816
|
+
{ semi: 5, fifth: -1 },
|
|
13817
|
+
// F
|
|
13818
|
+
{ semi: 8, fifth: 8 },
|
|
13819
|
+
// G#
|
|
13820
|
+
{ semi: 9, fifth: 3 },
|
|
13821
|
+
// A
|
|
13822
|
+
{ semi: 11, fifth: 5 }
|
|
13823
|
+
// B
|
|
13824
|
+
];
|
|
13825
|
+
var BLUES_SCALE = [
|
|
13826
|
+
{ semi: 0, fifth: 0 },
|
|
13827
|
+
// C
|
|
13828
|
+
{ semi: 3, fifth: -3 },
|
|
13829
|
+
// Eb
|
|
13830
|
+
{ semi: 5, fifth: -1 },
|
|
13831
|
+
// F
|
|
13832
|
+
{ semi: 6, fifth: -6 },
|
|
13833
|
+
// Gb(ブルーノート)
|
|
13834
|
+
{ semi: 7, fifth: 1 },
|
|
13835
|
+
// G
|
|
13836
|
+
{ semi: 10, fifth: -2 }
|
|
13837
|
+
// Bb
|
|
13838
|
+
];
|
|
13839
|
+
var RYUKYU_CENTER = {
|
|
13840
|
+
tonic: "C",
|
|
13841
|
+
half: "G",
|
|
13842
|
+
deceptive: "Em",
|
|
13843
|
+
tonicPattern: /^C(?![#b]|m)/,
|
|
13844
|
+
a: [
|
|
13845
|
+
["C", "F", "G", "C"],
|
|
13846
|
+
["C", "C", "F", "G"],
|
|
13847
|
+
["F", "G", "C", "C"],
|
|
13848
|
+
["C", "G", "F", "G"],
|
|
13849
|
+
["CM7", "F", "G", "C"],
|
|
13850
|
+
["C", "F", "C", "G"],
|
|
13851
|
+
["C", "Em", "F", "G"],
|
|
13852
|
+
["F", "C", "G", "C"]
|
|
13853
|
+
],
|
|
13854
|
+
b: [
|
|
13855
|
+
["F", "G", "Em", "C"],
|
|
13856
|
+
["F", "G", "C", "G"],
|
|
13857
|
+
["G", "F", "C", "C"],
|
|
13858
|
+
["FM7", "G", "Em", "F"],
|
|
13859
|
+
["C", "G", "F", "C"],
|
|
13860
|
+
["F", "Em", "F", "G"]
|
|
13861
|
+
],
|
|
13862
|
+
c: [
|
|
13863
|
+
["Em", "F", "G", "C"],
|
|
13864
|
+
["F", "C", "G", "Em"],
|
|
13865
|
+
["C", "Em", "F", "G"]
|
|
13866
|
+
]
|
|
13867
|
+
};
|
|
13868
|
+
var MIYAKOBUSHI_CENTER = {
|
|
13869
|
+
tonic: "Em",
|
|
13870
|
+
half: "Am",
|
|
13871
|
+
deceptive: "F",
|
|
13872
|
+
tonicPattern: /^E(?:m|sus)/,
|
|
13873
|
+
a: [
|
|
13874
|
+
["Em", "F", "Em", "Em"],
|
|
13875
|
+
["Esus4", "F", "Esus4", "Em"],
|
|
13876
|
+
["Em", "Am", "F", "Em"],
|
|
13877
|
+
["Am", "Em", "F", "Em"],
|
|
13878
|
+
["Em", "F", "Am", "Em"],
|
|
13879
|
+
["Em", "Em", "F", "F"],
|
|
13880
|
+
["Am", "F", "Em", "Em"],
|
|
13881
|
+
["Em", "FM7", "Am", "Em"]
|
|
13882
|
+
],
|
|
13883
|
+
b: [
|
|
13884
|
+
["F", "Am", "Em", "Em"],
|
|
13885
|
+
["Am", "F", "Em", "Em"],
|
|
13886
|
+
["F", "Em", "Am", "Em"],
|
|
13887
|
+
["FM7", "Am", "F", "Em"],
|
|
13888
|
+
["Am", "Em", "F", "Am"],
|
|
13889
|
+
["F", "Am", "F", "Em"]
|
|
13890
|
+
],
|
|
13891
|
+
c: [
|
|
13892
|
+
["Am", "Em", "F", "Am"],
|
|
13893
|
+
["F", "Am", "Esus4", "Em"],
|
|
13894
|
+
["Am", "F", "Em", "Em"]
|
|
13895
|
+
]
|
|
13896
|
+
};
|
|
13897
|
+
var RITSU_CENTER = {
|
|
13898
|
+
tonic: "Dsus4",
|
|
13899
|
+
half: "G",
|
|
13900
|
+
deceptive: "Em",
|
|
13901
|
+
tonicPattern: /^Dsus/,
|
|
13902
|
+
a: [
|
|
13903
|
+
["Dsus4", "G", "Dsus4", "Dsus4"],
|
|
13904
|
+
["Dsus4", "Em", "G", "Dsus4"],
|
|
13905
|
+
["G", "Dsus4", "Em", "Dsus4"],
|
|
13906
|
+
["Dsus4", "G", "Em", "G"],
|
|
13907
|
+
["Em", "G", "Dsus4", "Dsus4"],
|
|
13908
|
+
["Dsus4", "Em7", "G", "Dsus4"],
|
|
13909
|
+
["G", "Em", "Dsus4", "G"],
|
|
13910
|
+
["Dsus4", "Am", "G", "Dsus4"]
|
|
13911
|
+
],
|
|
13912
|
+
b: [
|
|
13913
|
+
["G", "Em", "Dsus4", "Dsus4"],
|
|
13914
|
+
["Em", "G", "Em", "Dsus4"],
|
|
13915
|
+
["G", "Am", "Em", "Dsus4"],
|
|
13916
|
+
["Em7", "G", "Dsus4", "Dsus4"],
|
|
13917
|
+
["Am", "G", "Em", "Dsus4"],
|
|
13918
|
+
["Dsus4", "Em", "G", "Em"]
|
|
13919
|
+
],
|
|
13920
|
+
c: [
|
|
13921
|
+
["Em", "Dsus4", "G", "Em"],
|
|
13922
|
+
["G", "Em7", "Am", "G"],
|
|
13923
|
+
["Am", "G", "Em", "Dsus4"]
|
|
13924
|
+
]
|
|
13925
|
+
};
|
|
13926
|
+
var HARMONIC_MINOR_CENTER = {
|
|
13927
|
+
tonic: "Am",
|
|
13928
|
+
half: "E7",
|
|
13929
|
+
deceptive: "F",
|
|
13930
|
+
tonicPattern: /^Am/,
|
|
13931
|
+
a: [
|
|
13932
|
+
["Am", "Dm", "E7", "Am"],
|
|
13933
|
+
// i-iv-V7-i。和声的短音階の基本形
|
|
13934
|
+
["Am", "F", "E7", "Am"],
|
|
13935
|
+
["Am", "E7", "Am", "Am"],
|
|
13936
|
+
["Dm", "E7", "Am", "Am"],
|
|
13937
|
+
["Am", "AmM7", "Dm", "E7"],
|
|
13938
|
+
// 主和音に導音を重ねたクリシェ
|
|
13939
|
+
["Am", "F", "Dm", "E7"],
|
|
13940
|
+
["F", "E7", "Am", "Am"],
|
|
13941
|
+
["Am", "Bm7-5", "E7", "Am"]
|
|
13942
|
+
],
|
|
13943
|
+
b: [
|
|
13944
|
+
["Dm", "E7", "Am", "Am"],
|
|
13945
|
+
["F", "E7", "Am", "E7"],
|
|
13946
|
+
["Dm7", "G#dim", "Am", "E7"],
|
|
13947
|
+
["F", "Dm", "E7", "Am"],
|
|
13948
|
+
["Am", "Dm", "Bm7-5", "E7"],
|
|
13949
|
+
["FM7", "E7", "Am", "Am"]
|
|
13950
|
+
],
|
|
13951
|
+
c: [
|
|
13952
|
+
["Dm", "Am", "Bm7-5", "E7"],
|
|
13953
|
+
["F", "C+", "Dm", "E7"],
|
|
13954
|
+
["Am", "F", "Dm", "E7"]
|
|
13955
|
+
]
|
|
13956
|
+
};
|
|
13957
|
+
var HIJAZ_CENTER = {
|
|
13958
|
+
tonic: "E",
|
|
13959
|
+
half: "F",
|
|
13960
|
+
deceptive: "Am",
|
|
13961
|
+
tonicPattern: /^E(?![#b]|m)/,
|
|
13962
|
+
a: [
|
|
13963
|
+
["E", "F", "E", "E"],
|
|
13964
|
+
// I-♭II。ヒジャーズの顔
|
|
13965
|
+
["E7", "F", "E", "E"],
|
|
13966
|
+
["Am", "F", "E", "E"],
|
|
13967
|
+
["E", "F", "Dm", "E"],
|
|
13968
|
+
["F", "E", "F", "E"],
|
|
13969
|
+
["Dm", "E", "F", "E"],
|
|
13970
|
+
["E7", "Am", "F", "E"],
|
|
13971
|
+
["E", "Dm", "F", "E"]
|
|
13972
|
+
],
|
|
13973
|
+
b: [
|
|
13974
|
+
["F", "E", "Am", "E"],
|
|
13975
|
+
["Dm", "C+", "F", "E"],
|
|
13976
|
+
["Am", "Dm", "F", "E"],
|
|
13977
|
+
["F", "Dm", "E", "E"],
|
|
13978
|
+
["E7", "F", "Dm", "E"],
|
|
13979
|
+
["Bm7-5", "E7", "Am", "E"]
|
|
13980
|
+
],
|
|
13981
|
+
c: [
|
|
13982
|
+
["Am", "Dm", "F", "E"],
|
|
13983
|
+
["Dm", "Am", "F", "E7"],
|
|
13984
|
+
["F", "C+", "Dm", "E"]
|
|
13985
|
+
]
|
|
13986
|
+
};
|
|
13987
|
+
var HUNGARIAN_CENTER = {
|
|
13988
|
+
tonic: "Am",
|
|
13989
|
+
half: "E",
|
|
13990
|
+
deceptive: "F",
|
|
13991
|
+
tonicPattern: /^Am/,
|
|
13992
|
+
a: [
|
|
13993
|
+
["Am", "E", "Am", "Am"],
|
|
13994
|
+
["Am", "F", "E", "Am"],
|
|
13995
|
+
["Am", "AmM7", "F", "E"],
|
|
13996
|
+
["F", "E", "Am", "Am"],
|
|
13997
|
+
["Am", "Fm", "E", "Am"],
|
|
13998
|
+
// ♭VIm。増2度を和音の側でも鳴らす
|
|
13999
|
+
["Am", "E", "F", "E"],
|
|
14000
|
+
["FM7", "E", "Am", "Am"],
|
|
14001
|
+
["Am", "C+", "F", "E"]
|
|
14002
|
+
],
|
|
14003
|
+
b: [
|
|
14004
|
+
["F", "E", "Am", "E"],
|
|
14005
|
+
["Fm", "E", "Am", "Am"],
|
|
14006
|
+
["Am", "F", "C+", "E"],
|
|
14007
|
+
["FM7", "Am", "F", "E"],
|
|
14008
|
+
["E", "F", "E", "Am"],
|
|
14009
|
+
["Am", "AmM7", "Fm", "E"]
|
|
14010
|
+
],
|
|
14011
|
+
c: [
|
|
14012
|
+
["F", "Am", "Fm", "E"],
|
|
14013
|
+
["C+", "F", "Am", "E"],
|
|
14014
|
+
["Am", "Fm", "F", "E"]
|
|
14015
|
+
]
|
|
14016
|
+
};
|
|
14017
|
+
var BLUES_CENTER = {
|
|
14018
|
+
tonic: "C7",
|
|
14019
|
+
half: "G7",
|
|
14020
|
+
deceptive: "F7",
|
|
14021
|
+
tonicPattern: /^C7/,
|
|
14022
|
+
a: [
|
|
14023
|
+
["C7", "C7", "C7", "C7"],
|
|
14024
|
+
// 12小節ブルースの1〜4小節
|
|
14025
|
+
["C7", "F7", "C7", "C7"],
|
|
14026
|
+
["C7", "C7", "F7", "F7"],
|
|
14027
|
+
["F7", "F7", "C7", "C7"],
|
|
14028
|
+
// 5〜8小節
|
|
14029
|
+
["C7", "F7", "C7", "G7"],
|
|
14030
|
+
["C7", "C7", "G7", "F7"],
|
|
14031
|
+
["C7", "F7", "G7", "C7"],
|
|
14032
|
+
["F7", "C7", "G7", "C7"]
|
|
14033
|
+
],
|
|
14034
|
+
b: [
|
|
14035
|
+
["F7", "F7", "C7", "C7"],
|
|
14036
|
+
["G7", "F7", "C7", "C7"],
|
|
14037
|
+
// 9〜12小節(ターンアラウンド)
|
|
14038
|
+
["F7", "G7", "C7", "C7"],
|
|
14039
|
+
["C7", "F7", "G7", "C7"],
|
|
14040
|
+
["F7", "C7", "G7", "F7"],
|
|
14041
|
+
["G7", "G7", "F7", "C7"]
|
|
14042
|
+
],
|
|
14043
|
+
c: [
|
|
14044
|
+
["G7", "F7", "C7", "G7"],
|
|
14045
|
+
["F7", "F7", "G7", "G7"],
|
|
14046
|
+
["C7", "C7", "F7", "G7"]
|
|
14047
|
+
]
|
|
14048
|
+
};
|
|
14049
|
+
var COMPOSE_SCALES = {
|
|
14050
|
+
yo: {
|
|
14051
|
+
id: "yo",
|
|
14052
|
+
label: "\u967D\u97F3\u968E\uFF08\u9577\u8ABF\u30DA\u30F3\u30BF\u30C8\u30CB\u30C3\u30AF\uFF09",
|
|
14053
|
+
tonic: 0,
|
|
14054
|
+
core: [0, 1, 2, 4, 5],
|
|
14055
|
+
// ド レ ミ ソ ラ
|
|
14056
|
+
minorish: false,
|
|
14057
|
+
strict: false,
|
|
14058
|
+
description: "J-POP\u306E\u6A19\u6E96\u3002\u660E\u308B\u304F\u7D20\u76F4\u3067\u6B4C\u3044\u3084\u3059\u3044\u3002\u5F93\u6765\u306E\u9577\u8ABF\u3068\u540C\u3058"
|
|
14059
|
+
},
|
|
14060
|
+
minyo: {
|
|
14061
|
+
id: "minyo",
|
|
14062
|
+
label: "\u6C11\u8B21\u97F3\u968E\uFF08\u77ED\u8ABF\u30DA\u30F3\u30BF\u30C8\u30CB\u30C3\u30AF\uFF09",
|
|
14063
|
+
tonic: 5,
|
|
14064
|
+
core: [5, 0, 1, 2, 4],
|
|
14065
|
+
// ラ ド レ ミ ソ
|
|
14066
|
+
minorish: true,
|
|
14067
|
+
strict: false,
|
|
14068
|
+
description: "\u308F\u3089\u3079\u6B4C\u30FB\u6C11\u8B21\u306E\u97F3\u968E\u3002\u7FF3\u308A\u304C\u3042\u308B\u304C\u6697\u3059\u304E\u306A\u3044\u3002\u5F93\u6765\u306E\u77ED\u8ABF\u3068\u540C\u3058"
|
|
14069
|
+
},
|
|
14070
|
+
ritsu: {
|
|
14071
|
+
id: "ritsu",
|
|
14072
|
+
label: "\u5F8B\u97F3\u968E",
|
|
14073
|
+
tonic: 1,
|
|
14074
|
+
core: [1, 2, 4, 5, 6],
|
|
14075
|
+
// レ ミ ソ ラ シ
|
|
14076
|
+
minorish: true,
|
|
14077
|
+
strict: true,
|
|
14078
|
+
center: RITSU_CENTER,
|
|
14079
|
+
description: "\u96C5\u697D\u30FB\u58F0\u660E\u306E\u97F3\u968E\u3002\u534A\u97F3\u3092\u542B\u307E\u305A\u3001\u5E73\u3089\u3067\u8358\u91CD\u306B\u6D41\u308C\u308B"
|
|
14080
|
+
},
|
|
14081
|
+
miyakobushi: {
|
|
14082
|
+
id: "miyakobushi",
|
|
14083
|
+
label: "\u90FD\u7BC0\u97F3\u968E\uFF08\u9670\u97F3\u968E\uFF09",
|
|
14084
|
+
tonic: 2,
|
|
14085
|
+
core: [2, 3, 5, 6, 0],
|
|
14086
|
+
// ミ ファ ラ シ ド
|
|
14087
|
+
minorish: true,
|
|
14088
|
+
strict: true,
|
|
14089
|
+
center: MIYAKOBUSHI_CENTER,
|
|
14090
|
+
description: "\u300E\u3055\u304F\u3089\u3055\u304F\u3089\u300F\u306E\u97F3\u968E\u3002\u4E3B\u97F3\u306E\u3059\u3050\u4E0A\u304C\u534A\u97F3\u3067\u3001\u7FF3\u308A\u304C\u6FC3\u3044"
|
|
14091
|
+
},
|
|
14092
|
+
ryukyu: {
|
|
14093
|
+
id: "ryukyu",
|
|
14094
|
+
label: "\u7409\u7403\u97F3\u968E",
|
|
14095
|
+
tonic: 0,
|
|
14096
|
+
core: [0, 2, 3, 4, 6],
|
|
14097
|
+
// ド ミ ファ ソ シ
|
|
14098
|
+
minorish: false,
|
|
14099
|
+
strict: true,
|
|
14100
|
+
center: RYUKYU_CENTER,
|
|
14101
|
+
description: "\u6C96\u7E04\u97F3\u968E\u3002\u30EC\u3068\u30E9\u3092\u629C\u304D\u3001\u30D5\u30A1\u3068\u30B7\u3092\u67F1\u306B\u3059\u308B\u3002\u660E\u308B\u304F\u8DF3\u306D\u308B"
|
|
14102
|
+
},
|
|
14103
|
+
dorian: {
|
|
14104
|
+
id: "dorian",
|
|
14105
|
+
label: "\u30C9\u30EA\u30A2\u30F3",
|
|
14106
|
+
tonic: 1,
|
|
14107
|
+
core: [1, 3, 4, 5, 0],
|
|
14108
|
+
// レ ファ ソ ラ ド
|
|
14109
|
+
minorish: true,
|
|
14110
|
+
strict: false,
|
|
14111
|
+
description: "\u77ED\u8ABF\u3060\u304C6\u5EA6\u304C\u660E\u308B\u3044\u3002\u30B1\u30EB\u30C8\u30FB\u30ED\u30C3\u30AF\u30FB\u30B7\u30C6\u30A3\u30DD\u30C3\u30D7"
|
|
14112
|
+
},
|
|
14113
|
+
phrygian: {
|
|
14114
|
+
id: "phrygian",
|
|
14115
|
+
label: "\u30D5\u30EA\u30B8\u30A2\u30F3",
|
|
14116
|
+
tonic: 2,
|
|
14117
|
+
core: [2, 3, 5, 6, 1],
|
|
14118
|
+
// ミ ファ ラ シ レ
|
|
14119
|
+
minorish: true,
|
|
14120
|
+
strict: false,
|
|
14121
|
+
description: "\u4E3B\u97F3\u306E\u4E0A\u304C\u534A\u97F3\u3002\u30B9\u30D1\u30CB\u30C3\u30B7\u30E5\uFF0F\u30E1\u30BF\u30EB\u306E\u7DCA\u8FEB\u3057\u305F\u97FF\u304D"
|
|
14122
|
+
},
|
|
14123
|
+
lydian: {
|
|
14124
|
+
id: "lydian",
|
|
14125
|
+
label: "\u30EA\u30C7\u30A3\u30A2\u30F3",
|
|
14126
|
+
tonic: 3,
|
|
14127
|
+
core: [3, 4, 6, 0, 2],
|
|
14128
|
+
// ファ ソ シ ド ミ
|
|
14129
|
+
minorish: false,
|
|
14130
|
+
strict: false,
|
|
14131
|
+
description: "4\u5EA6\u304C\u9AD8\u304F\u3001\u6D6E\u904A\u3057\u3066\u5E83\u304C\u308B\u3002\u6620\u753B\u97F3\u697D\u30FB\u30B2\u30FC\u30E0\u306E\u7A7A\u306E\u8272"
|
|
14132
|
+
},
|
|
14133
|
+
mixolydian: {
|
|
14134
|
+
id: "mixolydian",
|
|
14135
|
+
label: "\u30DF\u30AF\u30BD\u30EA\u30C7\u30A3\u30A2\u30F3",
|
|
14136
|
+
tonic: 4,
|
|
14137
|
+
core: [4, 5, 0, 1, 3],
|
|
14138
|
+
// ソ ラ ド レ ファ
|
|
14139
|
+
minorish: false,
|
|
14140
|
+
strict: false,
|
|
14141
|
+
description: "\u9577\u8ABF\u3060\u304C7\u5EA6\u304C\u4F4E\u3044\u3002\u30D6\u30EB\u30FC\u30B9\u30ED\u30C3\u30AF\u30FB\u6C11\u65CF\u97F3\u697D\u306E\u571F\u304F\u3055\u3055"
|
|
14142
|
+
},
|
|
14143
|
+
harmonic_minor: {
|
|
14144
|
+
id: "harmonic_minor",
|
|
14145
|
+
label: "\u548C\u58F0\u7684\u77ED\u97F3\u968E",
|
|
14146
|
+
tonic: 5,
|
|
14147
|
+
parent: HARMONIC_MINOR_SCALE,
|
|
14148
|
+
core: [5, 0, 1, 2, 4],
|
|
14149
|
+
// ラ ド レ ミ ソ♯
|
|
14150
|
+
minorish: true,
|
|
14151
|
+
strict: false,
|
|
14152
|
+
center: HARMONIC_MINOR_CENTER,
|
|
14153
|
+
description: "\u5C0E\u97F3\u30BD\u266F\u3092\u6301\u3064\u77ED\u8ABF\u3002\u58972\u5EA6\u304C\u6CE3\u304D\u3092\u4F5C\u308B\u3002\u30AF\u30E9\u30B7\u30C3\u30AF\u30FBV\u7CFB\u30FB\u5287\u4F34"
|
|
14154
|
+
},
|
|
14155
|
+
hijaz: {
|
|
14156
|
+
id: "hijaz",
|
|
14157
|
+
label: "\u30D2\u30B8\u30E3\u30FC\u30BA\uFF08\u30D5\u30EA\u30B8\u30A2\u30F3\u30FB\u30C9\u30DF\u30CA\u30F3\u30C8\uFF09",
|
|
14158
|
+
tonic: 2,
|
|
14159
|
+
parent: HARMONIC_MINOR_SCALE,
|
|
14160
|
+
core: [2, 3, 4, 5, 6],
|
|
14161
|
+
// ミ ファ ソ♯ ラ シ
|
|
14162
|
+
minorish: false,
|
|
14163
|
+
strict: false,
|
|
14164
|
+
center: HIJAZ_CENTER,
|
|
14165
|
+
description: "\u4E3B\u97F3\u306E\u4E0A\u304C\u534A\u97F3\u3001\u4E3B\u548C\u97F3\u306F\u9577\u4E09\u548C\u97F3\u3002\u4E2D\u6771\u30FB\u30B9\u30D1\u30CB\u30C3\u30B7\u30E5\u30FB\u30E1\u30BF\u30EB"
|
|
14166
|
+
},
|
|
14167
|
+
hungarian: {
|
|
14168
|
+
id: "hungarian",
|
|
14169
|
+
label: "\u30CF\u30F3\u30AC\u30EA\u30A2\u30F3\u30FB\u30DE\u30A4\u30CA\u30FC\uFF08\u30B8\u30D7\u30B7\u30FC\uFF09",
|
|
14170
|
+
tonic: 5,
|
|
14171
|
+
parent: HUNGARIAN_SCALE,
|
|
14172
|
+
core: [5, 0, 1, 2, 4],
|
|
14173
|
+
// ラ ド レ♯ ミ ソ♯
|
|
14174
|
+
minorish: true,
|
|
14175
|
+
strict: false,
|
|
14176
|
+
center: HUNGARIAN_CENTER,
|
|
14177
|
+
description: "\u58972\u5EA6\u304C2\u304B\u6240\u3002\u97F3\u968E\u306E\u4E2D\u3067\u3044\u3061\u3070\u3093\u8DF3\u306D\u305F\u3001\u7570\u56FD\u3081\u3044\u305F\u97FF\u304D"
|
|
14178
|
+
},
|
|
14179
|
+
blues: {
|
|
14180
|
+
id: "blues",
|
|
14181
|
+
label: "\u30D6\u30EB\u30FC\u30B9\u97F3\u968E",
|
|
14182
|
+
tonic: 0,
|
|
14183
|
+
parent: BLUES_SCALE,
|
|
14184
|
+
core: [0, 1, 2, 4, 5],
|
|
14185
|
+
// ド ミ♭ ファ ソ シ♭
|
|
14186
|
+
minorish: true,
|
|
14187
|
+
strict: true,
|
|
14188
|
+
center: BLUES_CENTER,
|
|
14189
|
+
description: "\u30D6\u30EB\u30FC\u30CE\u30FC\u30C8\u5165\u308A\u306E6\u97F3\u97F3\u968E\u3002\u77ED3\u5EA6\u3067\u6B4C\u3044\u3001\u4F34\u594F\u306F\u95773\u5EA6\u3067\u9CF4\u308B"
|
|
14190
|
+
}
|
|
14191
|
+
};
|
|
14192
|
+
var COMPOSE_SCALE_IDS = Object.keys(
|
|
14193
|
+
COMPOSE_SCALES
|
|
14194
|
+
);
|
|
14195
|
+
var TONIC_CENTERS = {
|
|
14196
|
+
// --- レ(律・ドリアン) ---
|
|
14197
|
+
1: {
|
|
14198
|
+
tonic: "Dm",
|
|
14199
|
+
half: "G",
|
|
14200
|
+
deceptive: "F",
|
|
14201
|
+
tonicPattern: /^Dm/,
|
|
14202
|
+
a: [
|
|
14203
|
+
["Dm", "G", "Dm", "Dm"],
|
|
14204
|
+
// i-IV の往復。ドリアンの顔
|
|
14205
|
+
["Dm", "Am", "G", "Dm"],
|
|
14206
|
+
["Dm", "C", "G", "Dm"],
|
|
14207
|
+
["Dm7", "G", "Dm7", "C"],
|
|
14208
|
+
["Dm", "F", "C", "G"],
|
|
14209
|
+
["Dm", "Em", "F", "G"],
|
|
14210
|
+
["Dm", "G", "F", "C"],
|
|
14211
|
+
["Dm7", "Em7", "FM7", "G"]
|
|
14212
|
+
],
|
|
14213
|
+
b: [
|
|
14214
|
+
["F", "G", "Am", "Dm"],
|
|
14215
|
+
["C", "G", "Dm", "Dm"],
|
|
14216
|
+
["G", "F", "C", "Dm"],
|
|
14217
|
+
["Am", "G", "F", "Dm"],
|
|
14218
|
+
["FM7", "G", "Em7", "Dm7"],
|
|
14219
|
+
["Dm", "G", "C", "Am"]
|
|
14220
|
+
],
|
|
14221
|
+
c: [
|
|
14222
|
+
["Am", "Dm", "G", "C"],
|
|
14223
|
+
["F", "Em", "Dm", "G"],
|
|
14224
|
+
["Dm", "Am", "Em", "G"]
|
|
14225
|
+
]
|
|
14226
|
+
},
|
|
14227
|
+
// --- ミ(都節・フリジアン) ---
|
|
14228
|
+
2: {
|
|
14229
|
+
tonic: "Em",
|
|
14230
|
+
half: "Am",
|
|
14231
|
+
deceptive: "C",
|
|
14232
|
+
tonicPattern: /^Em/,
|
|
14233
|
+
a: [
|
|
14234
|
+
["Em", "F", "Em", "Em"],
|
|
14235
|
+
// i-♭II。フリジアン/都節の顔
|
|
14236
|
+
["Em", "Am", "F", "Em"],
|
|
14237
|
+
["Am", "Em", "F", "Em"],
|
|
14238
|
+
["Em", "F", "G", "Em"],
|
|
14239
|
+
["Em", "Em", "F", "F"],
|
|
14240
|
+
["Em", "C", "F", "Em"],
|
|
14241
|
+
["Am", "F", "Em", "Em"],
|
|
14242
|
+
["Em7", "FM7", "Em7", "Am7"]
|
|
14243
|
+
],
|
|
14244
|
+
b: [
|
|
14245
|
+
["F", "G", "Am", "Em"],
|
|
14246
|
+
["Am", "G", "F", "Em"],
|
|
14247
|
+
["F", "Em", "Am", "Em"],
|
|
14248
|
+
["C", "F", "Em", "Em"],
|
|
14249
|
+
["FM7", "G", "Em7", "Am"],
|
|
14250
|
+
["Am", "Em", "F", "G"]
|
|
14251
|
+
],
|
|
14252
|
+
c: [
|
|
14253
|
+
["Am", "Em", "F", "C"],
|
|
14254
|
+
["C", "G", "Am", "Em"],
|
|
14255
|
+
["F", "C", "Am", "Em"]
|
|
14256
|
+
]
|
|
14257
|
+
},
|
|
14258
|
+
// --- ファ(リディアン) ---
|
|
14259
|
+
3: {
|
|
14260
|
+
tonic: "FM7",
|
|
14261
|
+
half: "C",
|
|
14262
|
+
deceptive: "Dm",
|
|
14263
|
+
tonicPattern: /^F(?![#b]|m)/,
|
|
14264
|
+
a: [
|
|
14265
|
+
["FM7", "G", "FM7", "FM7"],
|
|
14266
|
+
// I-II。リディアンの顔(♯4 が G の3度に居る)
|
|
14267
|
+
["FM7", "G", "Em", "Am"],
|
|
14268
|
+
["F", "G", "C", "F"],
|
|
14269
|
+
["FM7", "G", "Am", "F"],
|
|
14270
|
+
["F", "C", "G", "F"],
|
|
14271
|
+
["FM7", "Em7", "Dm7", "G"],
|
|
14272
|
+
["F", "G", "F", "C"],
|
|
14273
|
+
["FM7", "G", "Dm7", "F"]
|
|
14274
|
+
],
|
|
14275
|
+
b: [
|
|
14276
|
+
["G", "F", "C", "F"],
|
|
14277
|
+
["Am", "G", "FM7", "FM7"],
|
|
14278
|
+
["C", "G", "Am", "F"],
|
|
14279
|
+
["G", "Em", "Am", "F"],
|
|
14280
|
+
["Dm7", "G", "FM7", "FM7"],
|
|
14281
|
+
["FM7", "G", "Em7", "F"]
|
|
14282
|
+
],
|
|
14283
|
+
c: [
|
|
14284
|
+
["Dm", "Am", "F", "G"],
|
|
14285
|
+
["Am", "Em", "F", "G"],
|
|
14286
|
+
["C", "Am", "Dm", "F"]
|
|
14287
|
+
]
|
|
14288
|
+
},
|
|
14289
|
+
// --- ソ(ミクソリディアン) ---
|
|
14290
|
+
4: {
|
|
14291
|
+
tonic: "G",
|
|
14292
|
+
half: "Dm",
|
|
14293
|
+
deceptive: "Em",
|
|
14294
|
+
tonicPattern: /^G(?![#b]|m)/,
|
|
14295
|
+
a: [
|
|
14296
|
+
["G", "F", "C", "G"],
|
|
14297
|
+
// I-♭VII-IV。ミクソリディアンの顔
|
|
14298
|
+
["G", "C", "F", "G"],
|
|
14299
|
+
["G", "F", "G", "G"],
|
|
14300
|
+
["C", "G", "F", "G"],
|
|
14301
|
+
["G", "Dm", "F", "G"],
|
|
14302
|
+
["G", "Am", "F", "G"],
|
|
14303
|
+
["G", "F", "Dm", "C"],
|
|
14304
|
+
["G", "C", "G", "F"]
|
|
14305
|
+
],
|
|
14306
|
+
b: [
|
|
14307
|
+
["F", "C", "G", "G"],
|
|
14308
|
+
["Am", "F", "C", "G"],
|
|
14309
|
+
["C", "Dm", "F", "G"],
|
|
14310
|
+
["Em", "F", "C", "G"],
|
|
14311
|
+
["F", "G", "Am", "G"],
|
|
14312
|
+
["Dm7", "F", "C", "G"]
|
|
14313
|
+
],
|
|
14314
|
+
c: [
|
|
14315
|
+
["Am", "Em", "F", "G"],
|
|
14316
|
+
["C", "Am", "Dm", "G"],
|
|
14317
|
+
["Em", "Am", "F", "C"]
|
|
14318
|
+
]
|
|
14319
|
+
}
|
|
14320
|
+
};
|
|
14321
|
+
var scaleDegrees = (scale) => scale.parent ?? MAJOR_SCALE2;
|
|
14322
|
+
var scaleSize = (scale) => scaleDegrees(scale).length;
|
|
14323
|
+
var degreeToPitch = (scale, degree) => {
|
|
14324
|
+
const list = scaleDegrees(scale);
|
|
14325
|
+
const size = list.length;
|
|
14326
|
+
const index = (degree % size + size) % size;
|
|
14327
|
+
const octave = Math.floor(degree / size);
|
|
14328
|
+
const d = list[index];
|
|
14329
|
+
return { semi: d.semi + octave * 12, fifth: d.fifth };
|
|
14330
|
+
};
|
|
14331
|
+
var semitoneToDegree = (scale, semi) => {
|
|
14332
|
+
const list = scaleDegrees(scale);
|
|
14333
|
+
const octave = Math.floor(semi / 12);
|
|
14334
|
+
const within = semi - octave * 12;
|
|
14335
|
+
let best = 0;
|
|
14336
|
+
let bestDist = Number.POSITIVE_INFINITY;
|
|
14337
|
+
for (let i2 = 0; i2 < list.length; i2++) {
|
|
14338
|
+
const dist = Math.abs(list[i2].semi - within);
|
|
14339
|
+
if (dist < bestDist) {
|
|
14340
|
+
bestDist = dist;
|
|
14341
|
+
best = i2;
|
|
14342
|
+
}
|
|
14343
|
+
}
|
|
14344
|
+
return octave * list.length + best;
|
|
14345
|
+
};
|
|
14346
|
+
var walk = (scale, semi, delta) => degreeToPitch(scale, semitoneToDegree(scale, semi) + delta).semi;
|
|
14347
|
+
var scaleFifth = (scale, semi) => degreeToPitch(scale, semitoneToDegree(scale, semi)).fifth;
|
|
14348
|
+
var SCALE_PCS = /* @__PURE__ */ new Map();
|
|
14349
|
+
var scalePcs = (scale) => {
|
|
14350
|
+
const hit = SCALE_PCS.get(scale.id);
|
|
14351
|
+
if (hit) return hit;
|
|
14352
|
+
const set = new Set(
|
|
14353
|
+
scaleDegrees(scale).map((d) => (d.semi % 12 + 12) % 12)
|
|
14354
|
+
);
|
|
14355
|
+
SCALE_PCS.set(scale.id, set);
|
|
14356
|
+
return set;
|
|
14357
|
+
};
|
|
14358
|
+
var CORE_SORTED = /* @__PURE__ */ new Map();
|
|
14359
|
+
var sortedCore = (scale) => {
|
|
14360
|
+
const hit = CORE_SORTED.get(scale.id);
|
|
14361
|
+
if (hit) return hit;
|
|
14362
|
+
const sorted = [...scale.core].sort((a, b) => a - b);
|
|
14363
|
+
CORE_SORTED.set(scale.id, sorted);
|
|
14364
|
+
return sorted;
|
|
14365
|
+
};
|
|
14366
|
+
var CORE_PCS = /* @__PURE__ */ new Map();
|
|
14367
|
+
var corePcs = (scale) => {
|
|
14368
|
+
const hit = CORE_PCS.get(scale.id);
|
|
14369
|
+
if (hit) return hit;
|
|
14370
|
+
const list = scaleDegrees(scale);
|
|
14371
|
+
const set = new Set(scale.core.map((d) => (list[d].semi % 12 + 12) % 12));
|
|
14372
|
+
CORE_PCS.set(scale.id, set);
|
|
14373
|
+
return set;
|
|
14374
|
+
};
|
|
14375
|
+
var isCoreDegree = (scale, degree) => {
|
|
14376
|
+
const size = scaleSize(scale);
|
|
14377
|
+
return sortedCore(scale).includes((degree % size + size) % size);
|
|
14378
|
+
};
|
|
14379
|
+
var coreToDegree = (scale, step) => {
|
|
14380
|
+
const sorted = sortedCore(scale);
|
|
14381
|
+
const n = sorted.length;
|
|
14382
|
+
const index = (step % n + n) % n;
|
|
14383
|
+
const octave = Math.floor(step / n);
|
|
14384
|
+
return sorted[index] + octave * scaleSize(scale);
|
|
14385
|
+
};
|
|
14386
|
+
var degreeToCore = (scale, degree) => {
|
|
14387
|
+
const sorted = sortedCore(scale);
|
|
14388
|
+
const size = scaleSize(scale);
|
|
14389
|
+
const index = (degree % size + size) % size;
|
|
14390
|
+
const octave = Math.floor(degree / size);
|
|
14391
|
+
let best = 0;
|
|
14392
|
+
let bestDist = Number.POSITIVE_INFINITY;
|
|
14393
|
+
for (let i2 = 0; i2 < sorted.length; i2++) {
|
|
14394
|
+
const dist = Math.abs(sorted[i2] - index);
|
|
14395
|
+
if (dist < bestDist) {
|
|
14396
|
+
bestDist = dist;
|
|
14397
|
+
best = i2;
|
|
14398
|
+
}
|
|
14399
|
+
}
|
|
14400
|
+
return octave * sorted.length + best;
|
|
14401
|
+
};
|
|
14402
|
+
var isOutsideCore = (scale, semi) => scale.strict ? !corePcs(scale).has((semi % 12 + 12) % 12) : !isCoreDegree(scale, semitoneToDegree(scale, semi));
|
|
14403
|
+
var resolveComposeScale = (choice, minorKey, rnd = Math.random) => {
|
|
14404
|
+
const c = (choice ?? "").trim() || "auto";
|
|
14405
|
+
const hit = COMPOSE_SCALES[c];
|
|
14406
|
+
if (hit) return hit;
|
|
14407
|
+
if (c === "any")
|
|
14408
|
+
return COMPOSE_SCALES[COMPOSE_SCALE_IDS[Math.floor(rnd() * COMPOSE_SCALE_IDS.length)] ?? "yo"];
|
|
14409
|
+
return COMPOSE_SCALES[minorKey ? "minyo" : "yo"];
|
|
14410
|
+
};
|
|
14411
|
+
var getComposeScaleDescription = (choice) => {
|
|
14412
|
+
const hit = COMPOSE_SCALES[choice];
|
|
14413
|
+
if (hit) return hit.description;
|
|
14414
|
+
if (choice === "any")
|
|
14415
|
+
return `${COMPOSE_SCALE_IDS.length}\u3064\u306E\u97F3\u968E\u304B\u3089\u30E9\u30F3\u30C0\u30E0\u306B\u62BD\u9078\u3057\u307E\u3059`;
|
|
14416
|
+
return "\u30D9\u30FC\u30B9\u8ABF\u306E\u9577\u77ED\u306B\u5408\u308F\u305B\u3066\u3001\u967D\u97F3\u968E\uFF08\u9577\u8ABF\uFF09\u304B\u6C11\u8B21\u97F3\u968E\uFF08\u77ED\u8ABF\uFF09\u3092\u4F7F\u3044\u307E\u3059";
|
|
14417
|
+
};
|
|
14418
|
+
var resolveCenter = (scale) => scale.center ?? TONIC_CENTERS[scale.tonic] ?? null;
|
|
14419
|
+
|
|
13656
14420
|
// src/compose-sections.ts
|
|
13657
14421
|
var SECTION_LABELS = {
|
|
13658
14422
|
intro: "\u30A4\u30F3\u30C8\u30ED",
|
|
@@ -13888,6 +14652,7 @@ var sectionAt = (plan, bar) => {
|
|
|
13888
14652
|
// src/compose.ts
|
|
13889
14653
|
var STEP_SEMITONES = 2;
|
|
13890
14654
|
var MAX_LEAP_SEMITONES = 10;
|
|
14655
|
+
var LEAP_CEILINGS = [7, 8, 9, 10, 10, 12, 14, 16];
|
|
13891
14656
|
var MAX_BAR_LEAP_SEMITONES = 10;
|
|
13892
14657
|
var HARD = {
|
|
13893
14658
|
/** メロディが1音も無い、音域が半音未満(同じ音を並べただけ)。 */
|
|
@@ -13946,13 +14711,16 @@ var WEIGHTS = {
|
|
|
13946
14711
|
// --- 直近に作った曲と違うか ---
|
|
13947
14712
|
novelty: 1.2
|
|
13948
14713
|
};
|
|
14714
|
+
var DEVIATION_BUDGET = CORPUS_DEVIATION_BUDGET;
|
|
14715
|
+
var BUDGETED_KEYS = new Set(CORPUS_PROFILE_KEYS);
|
|
13949
14716
|
var HAND_BANDS = {
|
|
13950
14717
|
/** サブメロの音数/小節。少なすぎると「置いただけ」、多すぎるとメロディを食う。 */
|
|
13951
14718
|
subDensity: [0.5, 1.8, 4.5, 8],
|
|
13952
14719
|
complementarity: [0.05, 0.25, 0.7, 0.95],
|
|
13953
14720
|
climaxPeaks: [0, 1, 2, 5]
|
|
13954
14721
|
};
|
|
13955
|
-
var DRAW_COUNT =
|
|
14722
|
+
var DRAW_COUNT = 12;
|
|
14723
|
+
var SELECT_TEMPERATURE = 0.05;
|
|
13956
14724
|
var BASE_STEPS_PER_BAR = 192;
|
|
13957
14725
|
var WHOLE = 192;
|
|
13958
14726
|
var DOT_HALF = 144;
|
|
@@ -14077,65 +14845,6 @@ var BPM_CHOICES = [
|
|
|
14077
14845
|
180,
|
|
14078
14846
|
185
|
|
14079
14847
|
];
|
|
14080
|
-
var MAJOR_SCALE2 = [
|
|
14081
|
-
{ semi: 0, fifth: 0 },
|
|
14082
|
-
// C
|
|
14083
|
-
{ semi: 2, fifth: 2 },
|
|
14084
|
-
// D
|
|
14085
|
-
{ semi: 4, fifth: 4 },
|
|
14086
|
-
// E
|
|
14087
|
-
{ semi: 5, fifth: -1 },
|
|
14088
|
-
// F
|
|
14089
|
-
{ semi: 7, fifth: 1 },
|
|
14090
|
-
// G
|
|
14091
|
-
{ semi: 9, fifth: 3 },
|
|
14092
|
-
// A
|
|
14093
|
-
{ semi: 11, fifth: 5 }
|
|
14094
|
-
// B
|
|
14095
|
-
];
|
|
14096
|
-
var degreeToPitch = (degree) => {
|
|
14097
|
-
const index = (degree % 7 + 7) % 7;
|
|
14098
|
-
const octave = Math.floor(degree / 7);
|
|
14099
|
-
const d = MAJOR_SCALE2[index];
|
|
14100
|
-
return { semi: d.semi + octave * 12, fifth: d.fifth };
|
|
14101
|
-
};
|
|
14102
|
-
var semitoneToDegree = (semi) => {
|
|
14103
|
-
const octave = Math.floor(semi / 12);
|
|
14104
|
-
const within = semi - octave * 12;
|
|
14105
|
-
let best = 0;
|
|
14106
|
-
let bestDist = Number.POSITIVE_INFINITY;
|
|
14107
|
-
for (let i2 = 0; i2 < MAJOR_SCALE2.length; i2++) {
|
|
14108
|
-
const dist = Math.abs(MAJOR_SCALE2[i2].semi - within);
|
|
14109
|
-
if (dist < bestDist) {
|
|
14110
|
-
bestDist = dist;
|
|
14111
|
-
best = i2;
|
|
14112
|
-
}
|
|
14113
|
-
}
|
|
14114
|
-
return octave * 7 + best;
|
|
14115
|
-
};
|
|
14116
|
-
var walk = (semi, delta) => degreeToPitch(semitoneToDegree(semi) + delta).semi;
|
|
14117
|
-
var NON_PENTATONIC_DEGREES = /* @__PURE__ */ new Set([3, 6]);
|
|
14118
|
-
var isNonPentatonic = (semi) => NON_PENTATONIC_DEGREES.has((semitoneToDegree(semi) % 7 + 7) % 7);
|
|
14119
|
-
var PENTATONIC_DEGREES = [0, 1, 2, 4, 5];
|
|
14120
|
-
var pentaToDegree = (penta) => {
|
|
14121
|
-
const index = (penta % 5 + 5) % 5;
|
|
14122
|
-
const octave = Math.floor(penta / 5);
|
|
14123
|
-
return PENTATONIC_DEGREES[index] + octave * 7;
|
|
14124
|
-
};
|
|
14125
|
-
var degreeToPenta = (degree) => {
|
|
14126
|
-
const index = (degree % 7 + 7) % 7;
|
|
14127
|
-
const octave = Math.floor(degree / 7);
|
|
14128
|
-
let best = 0;
|
|
14129
|
-
let bestDist = Number.POSITIVE_INFINITY;
|
|
14130
|
-
for (let i2 = 0; i2 < PENTATONIC_DEGREES.length; i2++) {
|
|
14131
|
-
const dist = Math.abs(PENTATONIC_DEGREES[i2] - index);
|
|
14132
|
-
if (dist < bestDist) {
|
|
14133
|
-
bestDist = dist;
|
|
14134
|
-
best = i2;
|
|
14135
|
-
}
|
|
14136
|
-
}
|
|
14137
|
-
return octave * 5 + best;
|
|
14138
|
-
};
|
|
14139
14848
|
var SECTION_A_PROGRESSIONS = [
|
|
14140
14849
|
["C", "G", "Am", "Em7"],
|
|
14141
14850
|
// カノン進行の前半
|
|
@@ -14254,6 +14963,22 @@ var SECTION_DECEPTIVE_DERIVATIONS = [
|
|
|
14254
14963
|
(a, t) => [a[0], "Dm7", "G7", t === "Am" ? "FM7" : "Am7"],
|
|
14255
14964
|
(a, t) => [a[0], "F", "G7", t === "Am" ? "F" : "Am7"]
|
|
14256
14965
|
];
|
|
14966
|
+
var MODAL_FULL_DERIVATIONS = [
|
|
14967
|
+
(a, c) => [a[0], a[1], c.half, c.tonic],
|
|
14968
|
+
(a, c) => [a[0], c.half, a[2], c.tonic],
|
|
14969
|
+
(a, c) => [a[0], a[1], a[2], c.tonic],
|
|
14970
|
+
(a, c) => [c.tonic, c.half, a[2], c.tonic]
|
|
14971
|
+
];
|
|
14972
|
+
var MODAL_HALF_DERIVATIONS = [
|
|
14973
|
+
(a, c) => [a[0], a[1], a[2], c.half],
|
|
14974
|
+
(a, c) => [a[0], a[1], c.tonic, c.half],
|
|
14975
|
+
(a, c) => [a[0], c.tonic, a[2], c.half]
|
|
14976
|
+
];
|
|
14977
|
+
var MODAL_DECEPTIVE_DERIVATIONS = [
|
|
14978
|
+
(a, c) => [a[0], a[1], c.half, c.deceptive],
|
|
14979
|
+
(a, c) => [a[0], c.half, a[2], c.deceptive],
|
|
14980
|
+
(a, c) => [a[0], a[1], a[2], c.deceptive]
|
|
14981
|
+
];
|
|
14257
14982
|
var MODAL_BORROW = {
|
|
14258
14983
|
F: "Fm",
|
|
14259
14984
|
// IV → IVm(サブドミナントマイナー。いちばん定番)
|
|
@@ -14711,6 +15436,14 @@ for (const c of [...MOTIF_CELLS, ...RHYTHM_CELLS]) {
|
|
|
14711
15436
|
const key = onsetKeyOf(c.value);
|
|
14712
15437
|
cellEntryCount.set(key, (cellEntryCount.get(key) ?? 0) + 1);
|
|
14713
15438
|
}
|
|
15439
|
+
var resolveMelodyForm = (choice, rnd) => {
|
|
15440
|
+
const c = (choice ?? "").trim() || "auto";
|
|
15441
|
+
if (c === "motif" || c === "ostinato" || c === "through") return c;
|
|
15442
|
+
const r = rnd();
|
|
15443
|
+
if (r < 0.25) return "ostinato";
|
|
15444
|
+
if (r < 0.4) return "through";
|
|
15445
|
+
return "motif";
|
|
15446
|
+
};
|
|
14714
15447
|
var groovyCells = (cells, groove, rnd) => {
|
|
14715
15448
|
const hasSixteenth = (c) => c.value.some((v) => Math.abs(v) <= SIXTEENTH);
|
|
14716
15449
|
if (groove === "eighth") {
|
|
@@ -14844,7 +15577,7 @@ var nearestChordTone = (targetSemi, tones, minWeight, preferColor = false) => {
|
|
|
14844
15577
|
var MELODY_LOW = 60;
|
|
14845
15578
|
var MELODY_HIGH = 81;
|
|
14846
15579
|
var MELODY_CENTER = (MELODY_LOW + MELODY_HIGH) / 2;
|
|
14847
|
-
var harmonyPitch = (melodySemi, tones, prevHarmony, offset, parallel, against) => {
|
|
15580
|
+
var harmonyPitch = (scale, melodySemi, tones, prevHarmony, offset, parallel, against) => {
|
|
14848
15581
|
const lo = Math.max(-12, Math.min(offset, 0) - 7);
|
|
14849
15582
|
const hi = Math.min(12, Math.max(offset, 0) + 7);
|
|
14850
15583
|
let best = null;
|
|
@@ -14862,7 +15595,8 @@ var harmonyPitch = (melodySemi, tones, prevHarmony, offset, parallel, against) =
|
|
|
14862
15595
|
const g = Math.abs(semi - against) % 12;
|
|
14863
15596
|
clash = g === 3 || g === 4 || g === 8 || g === 9 || g === 7 ? 0 : g === 0 ? 0.5 : 1.2;
|
|
14864
15597
|
}
|
|
14865
|
-
const
|
|
15598
|
+
const offCore = scale.strict && isOutsideCore(scale, semi) ? 1.5 : 0;
|
|
15599
|
+
const cost = stay + clash + offCore + Math.abs(delta - offset) * (parallel ? 1.4 : 0.7) + (3 - tone.weight) * 0.4;
|
|
14866
15600
|
if (cost < bestCost) {
|
|
14867
15601
|
bestCost = cost;
|
|
14868
15602
|
best = { semi, fifth: tone.fifth };
|
|
@@ -14885,7 +15619,7 @@ var clampSemi = (semi, low, high) => {
|
|
|
14885
15619
|
while (s > high) s -= 12;
|
|
14886
15620
|
return s;
|
|
14887
15621
|
};
|
|
14888
|
-
var leapTarget = (from, tones, rnd) => {
|
|
15622
|
+
var leapTarget = (from, tones, rnd, maxLeap = MAX_LEAP_SEMITONES) => {
|
|
14889
15623
|
const candidates = [];
|
|
14890
15624
|
for (const tone of tones) {
|
|
14891
15625
|
const base = pitchClass(tone.semi);
|
|
@@ -14893,7 +15627,7 @@ var leapTarget = (from, tones, rnd) => {
|
|
|
14893
15627
|
const semi = base + oct * 12;
|
|
14894
15628
|
if (semi < MELODY_LOW || semi > MELODY_HIGH) continue;
|
|
14895
15629
|
const gap = Math.abs(semi - from);
|
|
14896
|
-
if (gap >= 3 && gap <=
|
|
15630
|
+
if (gap >= 3 && gap <= maxLeap) candidates.push(semi);
|
|
14897
15631
|
}
|
|
14898
15632
|
}
|
|
14899
15633
|
if (candidates.length === 0) return null;
|
|
@@ -14907,40 +15641,43 @@ var leapTarget = (from, tones, rnd) => {
|
|
|
14907
15641
|
];
|
|
14908
15642
|
return pick(weighted.length > 0 ? weighted : candidates, rnd);
|
|
14909
15643
|
};
|
|
14910
|
-
var landOn = (degrees, scaleIndex) => {
|
|
15644
|
+
var landOn = (scale, degrees, scaleIndex) => {
|
|
14911
15645
|
if (degrees.length === 0) return;
|
|
15646
|
+
const size = scaleSize(scale);
|
|
14912
15647
|
const last = degrees[degrees.length - 1];
|
|
14913
|
-
const index = (last %
|
|
15648
|
+
const index = (last % size + size) % size;
|
|
14914
15649
|
let delta = scaleIndex - index;
|
|
14915
|
-
if (delta >
|
|
14916
|
-
if (delta < -
|
|
15650
|
+
if (delta > size / 2) delta -= size;
|
|
15651
|
+
if (delta < -size / 2) delta += size;
|
|
14917
15652
|
degrees[degrees.length - 1] = last + delta;
|
|
14918
15653
|
};
|
|
14919
|
-
var landPitch = (pitches, scaleIndex) => {
|
|
15654
|
+
var landPitch = (scale, pitches, scaleIndex) => {
|
|
14920
15655
|
if (pitches.length === 0) return;
|
|
15656
|
+
const size = scaleSize(scale);
|
|
14921
15657
|
const last = pitches[pitches.length - 1];
|
|
14922
|
-
const degree = semitoneToDegree(last);
|
|
14923
|
-
const index = (degree %
|
|
15658
|
+
const degree = semitoneToDegree(scale, last);
|
|
15659
|
+
const index = (degree % size + size) % size;
|
|
14924
15660
|
let delta = scaleIndex - index;
|
|
14925
|
-
if (delta >
|
|
14926
|
-
if (delta < -
|
|
15661
|
+
if (delta > size / 2) delta -= size;
|
|
15662
|
+
if (delta < -size / 2) delta += size;
|
|
14927
15663
|
pitches[pitches.length - 1] = clampSemi(
|
|
14928
|
-
degreeToPitch(degree + delta).semi,
|
|
15664
|
+
degreeToPitch(scale, degree + delta).semi,
|
|
14929
15665
|
MELODY_LOW,
|
|
14930
15666
|
MELODY_HIGH
|
|
14931
15667
|
);
|
|
14932
15668
|
};
|
|
14933
|
-
var barDegrees = (role, slots, tones, style, motifContour, startDegree, contourOffset, repeatShift, barHeadWeight, preferColor, quarterSteps, rnd) => {
|
|
15669
|
+
var barDegrees = (role, slots, tones, style, scale, motifContour, startDegree, contourOffset, repeatShift, barHeadWeight, preferColor, quarterSteps, rnd) => {
|
|
14934
15670
|
const noteCount = slots.length;
|
|
14935
15671
|
const out = [];
|
|
14936
15672
|
if (role === "motif" || role === "sequence" || role === "climax" || role === "answer") {
|
|
14937
15673
|
const shift = (role === "sequence" ? pick([-2, -1, 1, 2], rnd) : role === "climax" ? 5 : 0) + repeatShift;
|
|
14938
15674
|
if (style.pentatonicMotif) {
|
|
14939
|
-
const
|
|
15675
|
+
const startCore = degreeToCore(scale, startDegree);
|
|
14940
15676
|
for (let i2 = 0; i2 < noteCount; i2++)
|
|
14941
15677
|
out.push(
|
|
14942
|
-
|
|
14943
|
-
|
|
15678
|
+
coreToDegree(
|
|
15679
|
+
scale,
|
|
15680
|
+
startCore + shift + motifContour[(contourOffset + i2) % motifContour.length]
|
|
14944
15681
|
)
|
|
14945
15682
|
);
|
|
14946
15683
|
} else {
|
|
@@ -14960,9 +15697,9 @@ var barDegrees = (role, slots, tones, style, motifContour, startDegree, contourO
|
|
|
14960
15697
|
for (let i2 = 0; i2 < noteCount; i2++)
|
|
14961
15698
|
out.push(startDegree + dir2 * (i2 < peak ? i2 : peak * 2 - i2 - 1));
|
|
14962
15699
|
} else if (style.runShape === "broken") {
|
|
14963
|
-
const arp = tones.map((t) => semitoneToDegree(clampSemi(t.semi, 60, 71))).sort((a, b) => a - b);
|
|
15700
|
+
const arp = tones.map((t) => semitoneToDegree(scale, clampSemi(t.semi, 60, 71))).sort((a, b) => a - b);
|
|
14964
15701
|
for (let i2 = 0; i2 < noteCount; i2++) {
|
|
14965
|
-
const oct = Math.floor(i2 / arp.length) *
|
|
15702
|
+
const oct = Math.floor(i2 / arp.length) * scaleSize(scale);
|
|
14966
15703
|
const idx = dir2 > 0 ? i2 % arp.length : arp.length - 1 - i2 % arp.length;
|
|
14967
15704
|
out.push(arp[idx] + dir2 * oct);
|
|
14968
15705
|
}
|
|
@@ -14985,7 +15722,10 @@ var barDegrees = (role, slots, tones, style, motifContour, startDegree, contourO
|
|
|
14985
15722
|
return out;
|
|
14986
15723
|
}
|
|
14987
15724
|
if (role === "cadence") {
|
|
14988
|
-
const tonic = semitoneToDegree(
|
|
15725
|
+
const tonic = semitoneToDegree(
|
|
15726
|
+
scale,
|
|
15727
|
+
clampSemi(72, MELODY_LOW, MELODY_HIGH)
|
|
15728
|
+
);
|
|
14989
15729
|
for (let i2 = 0; i2 < noteCount; i2++) {
|
|
14990
15730
|
if (style.cadenceShape === "descend") {
|
|
14991
15731
|
out.push(tonic + noteCount - 1 - i2);
|
|
@@ -14993,7 +15733,9 @@ var barDegrees = (role, slots, tones, style, motifContour, startDegree, contourO
|
|
|
14993
15733
|
const shape = [4, 2, 0];
|
|
14994
15734
|
out.push(tonic + shape[Math.min(i2, shape.length - 1)]);
|
|
14995
15735
|
} else if (style.cadenceShape === "leap-up") {
|
|
14996
|
-
out.push(
|
|
15736
|
+
out.push(
|
|
15737
|
+
i2 === noteCount - 1 ? tonic : tonic - scaleSize(scale) + Math.min(i2, 4)
|
|
15738
|
+
);
|
|
14997
15739
|
} else {
|
|
14998
15740
|
out.push(i2 === 0 && noteCount > 1 ? tonic + 1 : tonic);
|
|
14999
15741
|
}
|
|
@@ -15028,8 +15770,9 @@ var barDegrees = (role, slots, tones, style, motifContour, startDegree, contourO
|
|
|
15028
15770
|
for (let i2 = 0; i2 < out.length; i2++) {
|
|
15029
15771
|
if (!slots[i2].isStrong) continue;
|
|
15030
15772
|
out[i2] = semitoneToDegree(
|
|
15773
|
+
scale,
|
|
15031
15774
|
nearestChordTone(
|
|
15032
|
-
degreeToPitch(out[i2]).semi,
|
|
15775
|
+
degreeToPitch(scale, out[i2]).semi,
|
|
15033
15776
|
tones,
|
|
15034
15777
|
barHeadWeight,
|
|
15035
15778
|
preferColor
|
|
@@ -15040,9 +15783,9 @@ var barDegrees = (role, slots, tones, style, motifContour, startDegree, contourO
|
|
|
15040
15783
|
if (slots[i2].isStrong) continue;
|
|
15041
15784
|
if (slots[i2].value >= quarterSteps) {
|
|
15042
15785
|
if (rnd() < style.leapAffinity) {
|
|
15043
|
-
const from = degreeToPitch(out[i2 - 1]).semi;
|
|
15044
|
-
const target = leapTarget(from, tones, rnd);
|
|
15045
|
-
if (target !== null) out[i2] = semitoneToDegree(target);
|
|
15786
|
+
const from = degreeToPitch(scale, out[i2 - 1]).semi;
|
|
15787
|
+
const target = leapTarget(from, tones, rnd, style.maxLeap);
|
|
15788
|
+
if (target !== null) out[i2] = semitoneToDegree(scale, target);
|
|
15046
15789
|
}
|
|
15047
15790
|
continue;
|
|
15048
15791
|
}
|
|
@@ -15052,20 +15795,20 @@ var barDegrees = (role, slots, tones, style, motifContour, startDegree, contourO
|
|
|
15052
15795
|
}
|
|
15053
15796
|
return out;
|
|
15054
15797
|
};
|
|
15055
|
-
var fitMotif = (degrees, slots, tones, prevSemi, quarterSteps, pentatonic, preferShift) => {
|
|
15798
|
+
var fitMotif = (degrees, slots, tones, prevSemi, quarterSteps, scale, pentatonic, preferShift, maxShift = 3) => {
|
|
15056
15799
|
let best = degrees;
|
|
15057
15800
|
let bestShift = 0;
|
|
15058
15801
|
let bestScore = Number.NEGATIVE_INFINITY;
|
|
15059
15802
|
let preferScore = Number.NEGATIVE_INFINITY;
|
|
15060
15803
|
let preferMoved = null;
|
|
15061
|
-
for (let shift = -
|
|
15804
|
+
for (let shift = -maxShift; shift <= maxShift; shift++) {
|
|
15062
15805
|
const moved = degrees.map(
|
|
15063
|
-
(d) => pentatonic ?
|
|
15806
|
+
(d) => pentatonic ? coreToDegree(scale, degreeToCore(scale, d) + shift) : d + shift
|
|
15064
15807
|
);
|
|
15065
15808
|
let score = 0;
|
|
15066
15809
|
for (let i2 = 0; i2 < moved.length; i2++) {
|
|
15067
15810
|
const semi = clampSemi(
|
|
15068
|
-
degreeToPitch(moved[i2]).semi,
|
|
15811
|
+
degreeToPitch(scale, moved[i2]).semi,
|
|
15069
15812
|
MELODY_LOW,
|
|
15070
15813
|
MELODY_HIGH
|
|
15071
15814
|
);
|
|
@@ -15074,7 +15817,7 @@ var fitMotif = (degrees, slots, tones, prevSemi, quarterSteps, pentatonic, prefe
|
|
|
15074
15817
|
score += important ? w * 3 : w;
|
|
15075
15818
|
}
|
|
15076
15819
|
const head = clampSemi(
|
|
15077
|
-
degreeToPitch(moved[0]).semi,
|
|
15820
|
+
degreeToPitch(scale, moved[0]).semi,
|
|
15078
15821
|
MELODY_LOW,
|
|
15079
15822
|
MELODY_HIGH
|
|
15080
15823
|
);
|
|
@@ -15097,7 +15840,7 @@ var shapeBar = (degrees, slots, tones, prevSemi, opts) => {
|
|
|
15097
15840
|
const out = [];
|
|
15098
15841
|
let prev = prevSemi;
|
|
15099
15842
|
if (opts.preserveContour) {
|
|
15100
|
-
const raw = degrees.map((d) => degreeToPitch(d).semi);
|
|
15843
|
+
const raw = degrees.map((d) => degreeToPitch(opts.scale, d).semi);
|
|
15101
15844
|
const lo = Math.min(...raw);
|
|
15102
15845
|
const hi = Math.max(...raw);
|
|
15103
15846
|
let shift = 0;
|
|
@@ -15111,30 +15854,42 @@ var shapeBar = (degrees, slots, tones, prevSemi, opts) => {
|
|
|
15111
15854
|
}
|
|
15112
15855
|
for (let i2 = 0; i2 < degrees.length; i2++) {
|
|
15113
15856
|
let semi = clampSemi(
|
|
15114
|
-
degreeToPitch(degrees[i2]).semi,
|
|
15857
|
+
degreeToPitch(opts.scale, degrees[i2]).semi,
|
|
15115
15858
|
MELODY_LOW,
|
|
15116
15859
|
MELODY_HIGH
|
|
15117
15860
|
);
|
|
15118
|
-
const limit = i2 === 0 ? MAX_BAR_LEAP_SEMITONES :
|
|
15861
|
+
const limit = i2 === 0 ? MAX_BAR_LEAP_SEMITONES : opts.maxLeap;
|
|
15119
15862
|
if (!opts.allowLeap && Math.abs(semi - prev) > limit) {
|
|
15120
15863
|
semi = clampSemi(
|
|
15121
|
-
walk(prev, Math.sign(semi - prev) * 3),
|
|
15864
|
+
walk(opts.scale, prev, Math.sign(semi - prev) * 3),
|
|
15122
15865
|
MELODY_LOW,
|
|
15123
15866
|
MELODY_HIGH
|
|
15124
15867
|
);
|
|
15125
15868
|
}
|
|
15126
15869
|
if (!opts.allowArpeggio && i2 >= 2 && Math.abs(out[i2 - 1] - out[i2 - 2]) > STEP_SEMITONES) {
|
|
15127
15870
|
const back = -Math.sign(out[i2 - 1] - out[i2 - 2]);
|
|
15128
|
-
semi = clampSemi(
|
|
15871
|
+
semi = clampSemi(
|
|
15872
|
+
walk(opts.scale, out[i2 - 1], back),
|
|
15873
|
+
MELODY_LOW,
|
|
15874
|
+
MELODY_HIGH
|
|
15875
|
+
);
|
|
15129
15876
|
}
|
|
15130
15877
|
if (toneWeight(semi, tones) === 0 && (slots[i2].isStrong || slots[i2].value >= opts.quarterSteps)) {
|
|
15131
15878
|
const resolved = semi + 1;
|
|
15132
|
-
const useResolved = resolved <= MELODY_HIGH && !
|
|
15879
|
+
const useResolved = resolved <= MELODY_HIGH && !scalePcs(opts.scale).has(pitchClass(resolved)) && toneWeight(resolved, tones) >= 2 && resolved !== prev && opts.rnd() < opts.chromaticAffinity;
|
|
15133
15880
|
if (useResolved) {
|
|
15134
15881
|
semi = resolved;
|
|
15135
15882
|
} else {
|
|
15136
|
-
const up = clampSemi(
|
|
15137
|
-
|
|
15883
|
+
const up = clampSemi(
|
|
15884
|
+
walk(opts.scale, semi, 1),
|
|
15885
|
+
MELODY_LOW,
|
|
15886
|
+
MELODY_HIGH
|
|
15887
|
+
);
|
|
15888
|
+
const down = clampSemi(
|
|
15889
|
+
walk(opts.scale, semi, -1),
|
|
15890
|
+
MELODY_LOW,
|
|
15891
|
+
MELODY_HIGH
|
|
15892
|
+
);
|
|
15138
15893
|
const score = (s) => toneWeight(s, tones) * 2 + (i2 > 0 && s === prev ? -3 : 0);
|
|
15139
15894
|
semi = score(down) >= score(up) ? down : up;
|
|
15140
15895
|
}
|
|
@@ -15142,7 +15897,14 @@ var shapeBar = (degrees, slots, tones, prevSemi, opts) => {
|
|
|
15142
15897
|
out.push(semi);
|
|
15143
15898
|
prev = semi;
|
|
15144
15899
|
}
|
|
15145
|
-
applyPentatonic(
|
|
15900
|
+
applyPentatonic(
|
|
15901
|
+
out,
|
|
15902
|
+
slots,
|
|
15903
|
+
tones,
|
|
15904
|
+
prevSemi,
|
|
15905
|
+
opts.quarterSteps / 2,
|
|
15906
|
+
opts.scale
|
|
15907
|
+
);
|
|
15146
15908
|
applyOctaveJumps(out, slots, opts.octaveAffinity, opts.rnd);
|
|
15147
15909
|
return out;
|
|
15148
15910
|
};
|
|
@@ -15159,27 +15921,27 @@ var applyOctaveJumps = (out, slots, affinity, rnd) => {
|
|
|
15159
15921
|
out[i2] = canUp && (!canDown || rnd() < 0.5) ? up : down;
|
|
15160
15922
|
}
|
|
15161
15923
|
};
|
|
15162
|
-
var applyPentatonic = (out, slots, tones, prevSemi, shortSteps) => {
|
|
15924
|
+
var applyPentatonic = (out, slots, tones, prevSemi, shortSteps, scale) => {
|
|
15163
15925
|
for (let i2 = 0; i2 < out.length; i2++) {
|
|
15164
15926
|
const semi = out[i2];
|
|
15165
|
-
if (!
|
|
15166
|
-
if (tones.some((t) => pitchClass(t.semi) === pitchClass(semi)))
|
|
15927
|
+
if (!isOutsideCore(scale, semi)) continue;
|
|
15928
|
+
if (!scale.strict && tones.some((t) => pitchClass(t.semi) === pitchClass(semi)))
|
|
15929
|
+
continue;
|
|
15167
15930
|
const before = i2 === 0 ? prevSemi : out[i2 - 1];
|
|
15168
15931
|
const after = i2 + 1 < out.length ? out[i2 + 1] : null;
|
|
15169
15932
|
const inByStep = Math.abs(semi - before) <= STEP_SEMITONES;
|
|
15170
15933
|
const outByStep = after !== null && Math.abs(after - semi) <= STEP_SEMITONES;
|
|
15171
|
-
if (inByStep || outByStep) continue;
|
|
15172
|
-
if (!slots[i2].isStrong && slots[i2].value <= shortSteps)
|
|
15173
|
-
|
|
15174
|
-
const
|
|
15175
|
-
const
|
|
15934
|
+
if (scale.strict ? inByStep && outByStep : inByStep || outByStep) continue;
|
|
15935
|
+
if (!scale.strict && !slots[i2].isStrong && slots[i2].value <= shortSteps)
|
|
15936
|
+
continue;
|
|
15937
|
+
const up = clampSemi(walk(scale, semi, 1), MELODY_LOW, MELODY_HIGH);
|
|
15938
|
+
const down = clampSemi(walk(scale, semi, -1), MELODY_LOW, MELODY_HIGH);
|
|
15939
|
+
const score = (s) => (isOutsideCore(scale, s) ? -4 : 0) + toneWeight(s, tones) + (s === before ? -3 : 0) + (after !== null ? -Math.abs(after - s) / 12 : 0);
|
|
15176
15940
|
out[i2] = score(down) >= score(up) ? down : up;
|
|
15177
15941
|
}
|
|
15178
15942
|
};
|
|
15179
|
-
var DIATONIC_PCS = new Set(MAJOR_SCALE2.map((d) => d.semi));
|
|
15180
15943
|
var SHARP_FIFTHS = [0, 7, 2, 9, 4, -1, 6, 1, 8, 3, 10, 5];
|
|
15181
15944
|
var FLAT_FIFTHS = [0, -5, 2, -3, 4, -1, -6, 1, -4, 3, -2, 5];
|
|
15182
|
-
var diatonicFifth = (semi) => degreeToPitch(semitoneToDegree(semi)).fifth;
|
|
15183
15945
|
var nearestOctaveOf = (near, semi) => {
|
|
15184
15946
|
const pc = pitchClass(semi);
|
|
15185
15947
|
let best = pc;
|
|
@@ -15194,7 +15956,7 @@ var nearestOctaveOf = (near, semi) => {
|
|
|
15194
15956
|
}
|
|
15195
15957
|
return best;
|
|
15196
15958
|
};
|
|
15197
|
-
var applyChromatic = (pitches, fifths, slots, tones, opts) => {
|
|
15959
|
+
var applyChromatic = (scale, pitches, fifths, slots, tones, opts) => {
|
|
15198
15960
|
const last = pitches.length - 1;
|
|
15199
15961
|
for (let i2 = 0; i2 < pitches.length; i2++) {
|
|
15200
15962
|
const tone = tones.find(
|
|
@@ -15202,7 +15964,8 @@ var applyChromatic = (pitches, fifths, slots, tones, opts) => {
|
|
|
15202
15964
|
);
|
|
15203
15965
|
if (tone) fifths[i2] = tone.fifth;
|
|
15204
15966
|
}
|
|
15205
|
-
const
|
|
15967
|
+
const pcs = scalePcs(scale);
|
|
15968
|
+
const altered = tones.filter((t) => !pcs.has(pitchClass(t.semi)));
|
|
15206
15969
|
for (let i2 = 0; i2 < pitches.length; i2++) {
|
|
15207
15970
|
if (opts.keepLast && i2 === last) continue;
|
|
15208
15971
|
if (!slots[i2].isStrong && slots[i2].value < opts.quarterSteps) continue;
|
|
@@ -15230,7 +15993,7 @@ var applyChromatic = (pitches, fifths, slots, tones, opts) => {
|
|
|
15230
15993
|
const span = Math.abs(after - before);
|
|
15231
15994
|
const target = span === 2 ? before + dir : span === 3 ? after - dir : null;
|
|
15232
15995
|
if (target === null) continue;
|
|
15233
|
-
if (
|
|
15996
|
+
if (pcs.has(pitchClass(target))) continue;
|
|
15234
15997
|
if (target === before || target === after) continue;
|
|
15235
15998
|
if (target < MELODY_LOW || target > MELODY_HIGH) continue;
|
|
15236
15999
|
pitches[i2] = target;
|
|
@@ -15238,7 +16001,8 @@ var applyChromatic = (pitches, fifths, slots, tones, opts) => {
|
|
|
15238
16001
|
lastAltered = i2;
|
|
15239
16002
|
}
|
|
15240
16003
|
};
|
|
15241
|
-
var draw = (options, resolvedKey, rnd) => {
|
|
16004
|
+
var draw = (options, resolvedKey, scale, rnd) => {
|
|
16005
|
+
const center = resolveCenter(scale);
|
|
15242
16006
|
const stepsPerBar = options.stepsPerBar;
|
|
15243
16007
|
const edo = options.edo === 31 ? 31 : 12;
|
|
15244
16008
|
const scaleStep = (v) => Math.max(1, Math.round(Math.abs(v) * stepsPerBar / BASE_STEPS_PER_BAR)) * Math.sign(v);
|
|
@@ -15266,7 +16030,7 @@ var draw = (options, resolvedKey, rnd) => {
|
|
|
15266
16030
|
const totalBars = sectionPlan.reduce((sum, s) => sum + s.bars, 0);
|
|
15267
16031
|
const relativeKinds = /* @__PURE__ */ new Set();
|
|
15268
16032
|
let relativeShift = 0;
|
|
15269
|
-
if (rnd() < 0.25) {
|
|
16033
|
+
if (rnd() < 0.25 && !center) {
|
|
15270
16034
|
for (const kind of pick(
|
|
15271
16035
|
[["prechorus"], ["bridge"], ["prechorus", "bridge"]],
|
|
15272
16036
|
rnd
|
|
@@ -15376,42 +16140,42 @@ var draw = (options, resolvedKey, rnd) => {
|
|
|
15376
16140
|
barKeyShift[b] = s.keyShift;
|
|
15377
16141
|
}
|
|
15378
16142
|
}
|
|
15379
|
-
const progAPool = resolvedKey.mode === "major" ? SECTION_A_PROGRESSIONS.filter((p) => !p[0].startsWith("Am")) : resolvedKey.mode === "minor" ? SECTION_A_PROGRESSIONS.filter((p) => p[0].startsWith("Am")) : SECTION_A_PROGRESSIONS;
|
|
16143
|
+
const progAPool = center ? center.a : resolvedKey.mode === "major" ? SECTION_A_PROGRESSIONS.filter((p) => !p[0].startsWith("Am")) : resolvedKey.mode === "minor" ? SECTION_A_PROGRESSIONS.filter((p) => p[0].startsWith("Am")) : SECTION_A_PROGRESSIONS;
|
|
15380
16144
|
const withoutTonic = (pool, root) => {
|
|
15381
|
-
const isTonic = (c) => root === "Am" ? /^Am/.test(c) : /^C(?![#b]|m)/.test(c);
|
|
16145
|
+
const isTonic = (c) => center ? center.tonicPattern.test(c) : root === "Am" ? /^Am/.test(c) : /^C(?![#b]|m)/.test(c);
|
|
15382
16146
|
const out = pool.filter((p) => !p.some(isTonic));
|
|
15383
16147
|
return out.length > 0 ? out : pool;
|
|
15384
16148
|
};
|
|
15385
|
-
const homeRoot = resolvedKey.mode === "minor" ? "Am" : "C";
|
|
16149
|
+
const homeRoot = center ? center.tonic : resolvedKey.mode === "minor" ? "Am" : "C";
|
|
15386
16150
|
const progA = pick(
|
|
15387
16151
|
floating ? withoutTonic(progAPool, homeRoot) : progAPool,
|
|
15388
16152
|
rnd
|
|
15389
16153
|
);
|
|
15390
|
-
const progBPool = SECTION_B_PROGRESSIONS.filter(
|
|
16154
|
+
const progBPool = (center ? center.b : SECTION_B_PROGRESSIONS).filter(
|
|
15391
16155
|
(p) => p.join("|") !== progA.join("|")
|
|
15392
16156
|
);
|
|
15393
16157
|
const progB = pick(
|
|
15394
16158
|
floating ? withoutTonic(progBPool, homeRoot) : progBPool,
|
|
15395
16159
|
rnd
|
|
15396
16160
|
);
|
|
15397
|
-
const progRelativePool = SECTION_A_PROGRESSIONS.filter(
|
|
16161
|
+
const progRelativePool = center ? center.a : SECTION_A_PROGRESSIONS.filter(
|
|
15398
16162
|
(p) => resolvedKey.mode === "minor" ? !p[0].startsWith("Am") : p[0].startsWith("Am")
|
|
15399
16163
|
);
|
|
15400
16164
|
const progRelative = pick(
|
|
15401
16165
|
floating ? withoutTonic(progRelativePool, homeRoot) : progRelativePool,
|
|
15402
16166
|
rnd
|
|
15403
16167
|
);
|
|
15404
|
-
const progCPool = SECTION_C_PROGRESSIONS.filter(
|
|
16168
|
+
const progCPool = (center ? center.c : SECTION_C_PROGRESSIONS).filter(
|
|
15405
16169
|
(p) => p.join("|") !== progA.join("|") && p.join("|") !== progB.join("|")
|
|
15406
16170
|
);
|
|
15407
16171
|
const progC = pick(
|
|
15408
16172
|
floating ? withoutTonic(progCPool, homeRoot) : progCPool,
|
|
15409
16173
|
rnd
|
|
15410
16174
|
);
|
|
15411
|
-
const tonic = progA[0].startsWith("Am") ? "Am" : "C";
|
|
15412
|
-
const progHalf = pick(SECTION_A2_DERIVATIONS, rnd)(progA);
|
|
15413
|
-
const progFull = pick(SECTION_A3_DERIVATIONS, rnd)(progA, tonic);
|
|
15414
|
-
const progDeceptive = pick(SECTION_DECEPTIVE_DERIVATIONS, rnd)(progA, tonic);
|
|
16175
|
+
const tonic = center ? center.tonic : progA[0].startsWith("Am") ? "Am" : "C";
|
|
16176
|
+
const progHalf = center ? pick(MODAL_HALF_DERIVATIONS, rnd)(progA, center) : pick(SECTION_A2_DERIVATIONS, rnd)(progA);
|
|
16177
|
+
const progFull = center ? pick(MODAL_FULL_DERIVATIONS, rnd)(progA, center) : pick(SECTION_A3_DERIVATIONS, rnd)(progA, tonic);
|
|
16178
|
+
const progDeceptive = center ? pick(MODAL_DECEPTIVE_DERIVATIONS, rnd)(progA, center) : pick(SECTION_DECEPTIVE_DERIVATIONS, rnd)(progA, tonic);
|
|
15415
16179
|
let lastChorusBar = -1;
|
|
15416
16180
|
for (const section of sectionPlan)
|
|
15417
16181
|
if (section.kind === "chorus" || section.kind === "outro")
|
|
@@ -15458,7 +16222,7 @@ var draw = (options, resolvedKey, rnd) => {
|
|
|
15458
16222
|
progression[bar - 1] = transposeChordName("G7", shift - prev);
|
|
15459
16223
|
}
|
|
15460
16224
|
}
|
|
15461
|
-
if (rnd() < 0.3) {
|
|
16225
|
+
if (rnd() < 0.3 && !center) {
|
|
15462
16226
|
const tonicNames = tonic === "Am" ? ["Am", "Am7"] : ["C", "CM7"];
|
|
15463
16227
|
const spots = [];
|
|
15464
16228
|
for (let bar = 0; bar + 1 < totalBars; bar++) {
|
|
@@ -15479,21 +16243,27 @@ var draw = (options, resolvedKey, rnd) => {
|
|
|
15479
16243
|
const sourceOf = (kind) => kind === "chorus" || kind === "interlude" || kind === "drop_chorus" ? "b" : kind === "prechorus" ? "a2" : kind === "bridge" ? "c" : "a";
|
|
15480
16244
|
const landingOf = (section) => {
|
|
15481
16245
|
if (section.spec.landing === null) return null;
|
|
15482
|
-
const
|
|
15483
|
-
|
|
15484
|
-
|
|
15485
|
-
|
|
16246
|
+
const relativeHere = relativeKinds.has(section.kind);
|
|
16247
|
+
const tonicDegree = relativeHere ? scale.tonic === 5 ? 0 : 5 : scale.tonic;
|
|
16248
|
+
const size = scaleSize(scale);
|
|
16249
|
+
let landing = (section.spec.landing + tonicDegree) % size;
|
|
16250
|
+
if (floating && landing === tonicDegree)
|
|
16251
|
+
landing = (landing + pick([2, 4], rnd)) % size;
|
|
15486
16252
|
return landing;
|
|
15487
16253
|
};
|
|
16254
|
+
const form = resolveMelodyForm(options.form, rnd);
|
|
15488
16255
|
const units2 = [];
|
|
15489
16256
|
for (const section of sectionPlan) {
|
|
15490
16257
|
const unitCount = Math.max(1, Math.round(section.bars / 2));
|
|
15491
16258
|
const src = sourceOf(section.kind);
|
|
15492
16259
|
for (let u = 0; u < unitCount; u++) {
|
|
15493
16260
|
if (!section.spec.melody) {
|
|
16261
|
+
const solo2 = section.kind === "interlude";
|
|
15494
16262
|
units2.push({
|
|
15495
|
-
|
|
15496
|
-
|
|
16263
|
+
// 見せ場なので走句と山を交互に置く。`hold` のままだと
|
|
16264
|
+
// リズム型が最も薄いものになり、ソロにならない。
|
|
16265
|
+
role: solo2 ? u % 2 === 0 ? "run" : "climax" : "hold",
|
|
16266
|
+
source: solo2 ? "solo" : "silent",
|
|
15497
16267
|
landing: null,
|
|
15498
16268
|
section
|
|
15499
16269
|
});
|
|
@@ -15502,16 +16272,31 @@ var draw = (options, resolvedKey, rnd) => {
|
|
|
15502
16272
|
const isLast = u === unitCount - 1;
|
|
15503
16273
|
if (u % 2 === 0) {
|
|
15504
16274
|
units2.push({
|
|
15505
|
-
|
|
15506
|
-
|
|
16275
|
+
// リフ主体の曲は**変形しない**。セクエンツもオクターブ上げも入れず、
|
|
16276
|
+
// 同じ型を回し続ける。セクションの対比は編曲側(ドラム・楽器・レイヤ)
|
|
16277
|
+
// が担う——ヤツメ穴型の曲がまさにその作りで、120小節を通して
|
|
16278
|
+
// 5半音のセルが変わらない。
|
|
16279
|
+
role: form === "ostinato" ? "motif" : form === "through" ? (
|
|
16280
|
+
// 通し作曲は素材を戻さない。`step` の書法(アーチ・谷・波)で
|
|
16281
|
+
// 独立した線を書き、たまに走句と山を挟んで単調さを避ける。
|
|
16282
|
+
u % 3 === 2 ? "run" : u % 3 === 1 ? "climax" : "step"
|
|
16283
|
+
) : section.kind === "bridge" ? "step" : section.kind === "chorus" ? "climax" : src === "a2" || u > 0 ? "sequence" : "motif",
|
|
16284
|
+
// リフ型は素材も1つに揃える(`sourceOf` でセクションごとに
|
|
16285
|
+
// 変えると、そこだけ別の型が始まってオスティナートにならない)。
|
|
16286
|
+
source: form === "ostinato" ? "a" : src,
|
|
15507
16287
|
landing: null,
|
|
15508
16288
|
section
|
|
15509
16289
|
});
|
|
15510
16290
|
} else {
|
|
15511
16291
|
const landing = landingOf(section);
|
|
16292
|
+
const riff = form === "ostinato" && !(isLast && landing === 0);
|
|
15512
16293
|
units2.push({
|
|
15513
|
-
role: isLast && landing === 0 ? "cadence" : "
|
|
15514
|
-
|
|
16294
|
+
role: isLast && landing === 0 ? "cadence" : riff ? "motif" : (
|
|
16295
|
+
// 通し作曲は「問いと答え」で閉じない。answer は問いのリズムを
|
|
16296
|
+
// 受けて着地音だけ変える形なので、そのままだと反復が戻る。
|
|
16297
|
+
form === "through" ? "step" : "answer"
|
|
16298
|
+
),
|
|
16299
|
+
source: riff ? "a" : "answer",
|
|
15515
16300
|
landing: isLast ? landing : null,
|
|
15516
16301
|
section
|
|
15517
16302
|
});
|
|
@@ -15529,6 +16314,7 @@ var draw = (options, resolvedKey, rnd) => {
|
|
|
15529
16314
|
const restatementOf = (bar) => {
|
|
15530
16315
|
const curSec = sectionAt(sectionPlan, bar);
|
|
15531
16316
|
if (!curSec.spec.melody) return null;
|
|
16317
|
+
if (form === "through") return null;
|
|
15532
16318
|
if (curSec.restatement) {
|
|
15533
16319
|
const firstSec = sectionPlan.find(
|
|
15534
16320
|
(s) => s.kind === curSec.kind && !s.restatement
|
|
@@ -15550,14 +16336,19 @@ var draw = (options, resolvedKey, rnd) => {
|
|
|
15550
16336
|
}
|
|
15551
16337
|
return null;
|
|
15552
16338
|
};
|
|
16339
|
+
const registerSpread = form === "ostinato" ? rnd() ** 2 * 0.5 : 0.25 + rnd() * 0.75;
|
|
15553
16340
|
const style = {
|
|
15554
16341
|
groove: pick(["eighth", "sixteenth"], rnd),
|
|
15555
16342
|
arcPeriod: pick([4, 8, 8, 16], rnd),
|
|
15556
16343
|
arcPhase: pick([0, 1, 2], rnd),
|
|
15557
|
-
arcAmp:
|
|
16344
|
+
arcAmp: 5 * registerSpread,
|
|
15558
16345
|
// オクターブ跳躍は参考曲では音程の1.0%しかない。上げすぎると音域が広がる。
|
|
15559
|
-
octaveAffinity: 0.
|
|
15560
|
-
|
|
16346
|
+
octaveAffinity: 0.18 * registerSpread,
|
|
16347
|
+
maxLeap: pick(LEAP_CEILINGS, rnd),
|
|
16348
|
+
// **音階を厳しく締める曲は必ず中核音の歩数で組む。** ダイアトニックの度数で輪郭を
|
|
16349
|
+
// 作ると、琉球音階なのにレやラが輪郭の中に入り込む。ファ・シを自由に使う
|
|
16350
|
+
// 陽・民謡だけが、曲ごとに掛けたり掛けなかったりする({@link ComposeScale.strict})。
|
|
16351
|
+
pentatonicMotif: rnd() < 0.55 || scale.strict,
|
|
15561
16352
|
runShape: pick(["scale", "turn", "broken", "zigzag"], rnd),
|
|
15562
16353
|
stepShape: pick(
|
|
15563
16354
|
["arch", "valley", "ascend", "descend", "wave", "pivot"],
|
|
@@ -15575,7 +16366,11 @@ var draw = (options, resolvedKey, rnd) => {
|
|
|
15575
16366
|
// 界隈曲らしさ:調の外の音(クロマチック)や微小な逸脱を積極的に許容する。
|
|
15576
16367
|
// 刻みを細かくすると経過音の置き場所が増えるので、同じ係数でも変化音は増える。
|
|
15577
16368
|
// 参考曲の1.75倍まで伸びていたぶんを引く。
|
|
15578
|
-
|
|
16369
|
+
// **音階を厳しく締める曲は変化音を控える。** 半音の経過音は長調・短調の泣きメロの
|
|
16370
|
+
// 芯だが、琉球・都節・律ではその半音が音階の外にしか無く、入れたぶんだけ
|
|
16371
|
+
// 音階の色が薄まる(実測で嬰ヘが3%出て、音階内のラ2%より多いという逆転が
|
|
16372
|
+
// 起きていた)。0 にはしない——民族音階の実際の曲にも装飾の半音は出る。
|
|
16373
|
+
chromaticAffinity: (rnd() < 0.2 ? 0 : 0.12 + rnd() * 0.33) * (scale.strict ? 0.4 : 1),
|
|
15579
16374
|
barHeadWeight: rnd() < 0.5 ? 3 : 2,
|
|
15580
16375
|
bassStyle: pick(
|
|
15581
16376
|
[
|
|
@@ -15602,8 +16397,11 @@ var draw = (options, resolvedKey, rnd) => {
|
|
|
15602
16397
|
subInterval: pick([3, 4, 8, 9], rnd)
|
|
15603
16398
|
};
|
|
15604
16399
|
const motifPool = groovyCells(MOTIF_CELLS, style.groove, rnd);
|
|
15605
|
-
const
|
|
15606
|
-
const
|
|
16400
|
+
const targetRestRatio = 0.02 + rnd() ** 2 * 0.42;
|
|
16401
|
+
const targetNotesPerBar = Math.max(
|
|
16402
|
+
2.8,
|
|
16403
|
+
Math.min(9.5, 7.4 - 6 * targetRestRatio + (rnd() * 4 - 2))
|
|
16404
|
+
);
|
|
15607
16405
|
const cellNotes = (c) => c.value.filter((v) => v > 0).length;
|
|
15608
16406
|
const cellRest = (c) => {
|
|
15609
16407
|
let rest = 0;
|
|
@@ -15626,9 +16424,13 @@ var draw = (options, resolvedKey, rnd) => {
|
|
|
15626
16424
|
return pool[pool.length - 1];
|
|
15627
16425
|
};
|
|
15628
16426
|
const pickCell = (pool, densityMul = 1) => {
|
|
15629
|
-
|
|
16427
|
+
const want = targetRestRatio / Math.max(0.5, densityMul);
|
|
16428
|
+
const tol = Math.max(0.08, want * 0.6);
|
|
16429
|
+
const near = pool.filter((c) => Math.abs(cellRest(c) - want) <= tol);
|
|
16430
|
+
const from = near.length > 0 ? near : pool;
|
|
16431
|
+
let best = weightedPick(from);
|
|
15630
16432
|
for (let i2 = 0; i2 < 2; i2++) {
|
|
15631
|
-
const c = weightedPick(
|
|
16433
|
+
const c = weightedPick(from);
|
|
15632
16434
|
if (cellDistance(c, densityMul) < cellDistance(best, densityMul))
|
|
15633
16435
|
best = c;
|
|
15634
16436
|
}
|
|
@@ -15730,7 +16532,7 @@ var draw = (options, resolvedKey, rnd) => {
|
|
|
15730
16532
|
if (breathBars.has(source)) breathBars.add(bar);
|
|
15731
16533
|
continue;
|
|
15732
16534
|
}
|
|
15733
|
-
const isB = units2[u].source === "b";
|
|
16535
|
+
const isB = units2[u].source === "b" || units2[u].source === "solo";
|
|
15734
16536
|
const isA2 = units2[u].source === "a2";
|
|
15735
16537
|
const isC = units2[u].source === "c";
|
|
15736
16538
|
const isPrechorusEnd = units2[u].section.kind === "prechorus" && bar === units2[u].section.startBar + units2[u].section.bars - 1;
|
|
@@ -15780,6 +16582,7 @@ var draw = (options, resolvedKey, rnd) => {
|
|
|
15780
16582
|
const harmony = [];
|
|
15781
16583
|
const harmony2 = [];
|
|
15782
16584
|
const pad = [];
|
|
16585
|
+
const solo = [];
|
|
15783
16586
|
const melodyDurations = [];
|
|
15784
16587
|
const barTension = new Array(totalBars).fill(0);
|
|
15785
16588
|
let restSteps = 0;
|
|
@@ -15790,9 +16593,9 @@ var draw = (options, resolvedKey, rnd) => {
|
|
|
15790
16593
|
let chromaticNotes = 0;
|
|
15791
16594
|
let sungBars = 0;
|
|
15792
16595
|
let prevSemi = pick([60, 64, 65, 67, 69, 72, 74, 76], rnd);
|
|
15793
|
-
const pickFigure = (gapSteps,
|
|
16596
|
+
const pickFigure = (gapSteps, scale2) => {
|
|
15794
16597
|
const fits = ANSWER_FIGURES.filter(
|
|
15795
|
-
(f) => f.reduce((sum, v) => sum +
|
|
16598
|
+
(f) => f.reduce((sum, v) => sum + scale2(Math.abs(v)), 0) <= gapSteps
|
|
15796
16599
|
);
|
|
15797
16600
|
return fits.length === 0 ? null : pick(fits, rnd);
|
|
15798
16601
|
};
|
|
@@ -15850,8 +16653,9 @@ var draw = (options, resolvedKey, rnd) => {
|
|
|
15850
16653
|
slots,
|
|
15851
16654
|
tones,
|
|
15852
16655
|
style,
|
|
16656
|
+
scale,
|
|
15853
16657
|
motifContour,
|
|
15854
|
-
semitoneToDegree(headSemi),
|
|
16658
|
+
semitoneToDegree(scale, headSemi),
|
|
15855
16659
|
contourOffset,
|
|
15856
16660
|
repeatShift,
|
|
15857
16661
|
headWeight,
|
|
@@ -15867,7 +16671,8 @@ var draw = (options, resolvedKey, rnd) => {
|
|
|
15867
16671
|
...plannedDegrees[source]
|
|
15868
16672
|
);
|
|
15869
16673
|
const landing = units2[unitOf(bar)].landing;
|
|
15870
|
-
if (landing !== null && barInUnit(bar) === 1)
|
|
16674
|
+
if (landing !== null && barInUnit(bar) === 1)
|
|
16675
|
+
landOn(scale, degrees, landing);
|
|
15871
16676
|
plannedDegrees[bar] = [...degrees];
|
|
15872
16677
|
const isMotifBar = source !== null || role === "motif" || role === "sequence" || role === "climax" || role === "answer";
|
|
15873
16678
|
let fitted = degrees;
|
|
@@ -15879,13 +16684,18 @@ var draw = (options, resolvedKey, rnd) => {
|
|
|
15879
16684
|
tones,
|
|
15880
16685
|
prevSemi,
|
|
15881
16686
|
quarterSteps,
|
|
16687
|
+
scale,
|
|
15882
16688
|
style.pentatonicMotif,
|
|
15883
|
-
motifShiftMemo.get(shiftKey) ?? null
|
|
16689
|
+
motifShiftMemo.get(shiftKey) ?? null,
|
|
16690
|
+
// リフ型は和音へ寄せない。同じセルを回し続けるのが役目。
|
|
16691
|
+
form === "ostinato" ? 0 : 3
|
|
15884
16692
|
);
|
|
15885
16693
|
fitted = r.degrees;
|
|
15886
16694
|
motifShiftMemo.set(shiftKey, r.shift);
|
|
15887
16695
|
}
|
|
15888
16696
|
const pitches = shapeBar(fitted, slots, tones, prevSemi, {
|
|
16697
|
+
scale,
|
|
16698
|
+
maxLeap: style.maxLeap,
|
|
15889
16699
|
allowLeap: role === "climax",
|
|
15890
16700
|
allowArpeggio: role === "climax" || role === "run" && style.runShape === "broken" || role === "cadence" && style.cadenceShape !== "descend",
|
|
15891
16701
|
quarterSteps,
|
|
@@ -15900,16 +16710,19 @@ var draw = (options, resolvedKey, rnd) => {
|
|
|
15900
16710
|
rnd,
|
|
15901
16711
|
preserveContour: isMotifBar
|
|
15902
16712
|
});
|
|
15903
|
-
if (landing !== null && barInUnit(bar) === 1)
|
|
15904
|
-
|
|
15905
|
-
|
|
16713
|
+
if (landing !== null && barInUnit(bar) === 1)
|
|
16714
|
+
landPitch(scale, pitches, landing);
|
|
16715
|
+
const fifths = pitches.map((semi) => scaleFifth(scale, semi));
|
|
16716
|
+
applyChromatic(scale, pitches, fifths, slots, tones, {
|
|
15906
16717
|
affinity: style.chromaticAffinity,
|
|
15907
16718
|
quarterSteps,
|
|
15908
16719
|
shortSteps: scaleStep(EIGHTH),
|
|
15909
16720
|
keepLast: landing !== null && barInUnit(bar) === 1,
|
|
15910
16721
|
rnd
|
|
15911
16722
|
});
|
|
15912
|
-
const
|
|
16723
|
+
const unitSource = units2[unitOf(bar)].source;
|
|
16724
|
+
const isSolo = unitSource === "solo";
|
|
16725
|
+
const silent = unitSource === "silent" || isSolo;
|
|
15913
16726
|
const barHead = pitches[0];
|
|
15914
16727
|
let tensionSum = 0;
|
|
15915
16728
|
let tensionSteps = 0;
|
|
@@ -15917,7 +16730,7 @@ var draw = (options, resolvedKey, rnd) => {
|
|
|
15917
16730
|
const semi = pitches[i2];
|
|
15918
16731
|
tensionSum += (3 - toneWeight(semi, tones)) / 3 * slots[i2].value;
|
|
15919
16732
|
tensionSteps += slots[i2].value;
|
|
15920
|
-
if (role !== "climax") {
|
|
16733
|
+
if (!silent && role !== "climax") {
|
|
15921
16734
|
const gap = Math.abs(semi - prevSemi);
|
|
15922
16735
|
maxLeap = Math.max(maxLeap, gap);
|
|
15923
16736
|
intervals++;
|
|
@@ -15926,10 +16739,25 @@ var draw = (options, resolvedKey, rnd) => {
|
|
|
15926
16739
|
}
|
|
15927
16740
|
const slot = slots[i2];
|
|
15928
16741
|
if (silent) {
|
|
16742
|
+
if (isSolo) {
|
|
16743
|
+
const ks = barKeyShift[bar];
|
|
16744
|
+
const fifthShiftSolo = ks === 0 ? 0 : SEMITONE_TO_FIFTH_SHIFT[(ks % 12 + 12) % 12];
|
|
16745
|
+
solo.push({
|
|
16746
|
+
startStep: barStart + slot.at,
|
|
16747
|
+
pitchUnits: spelledToUnits(
|
|
16748
|
+
semi + ks,
|
|
16749
|
+
fifths[i2] + fifthShiftSolo,
|
|
16750
|
+
edo
|
|
16751
|
+
),
|
|
16752
|
+
durationSteps: slot.value,
|
|
16753
|
+
// ソロは前に出る声部なので、歌メロより気持ち強く弾く。
|
|
16754
|
+
velocity: slot.at === 0 ? 116 : slot.value <= scaleStep(SIXTEENTH) ? 96 : 106
|
|
16755
|
+
});
|
|
16756
|
+
}
|
|
15929
16757
|
prevSemi = semi;
|
|
15930
16758
|
continue;
|
|
15931
16759
|
}
|
|
15932
|
-
if (!
|
|
16760
|
+
if (!scalePcs(scale).has(pitchClass(semi))) chromaticNotes++;
|
|
15933
16761
|
const k = barKeyShift[bar];
|
|
15934
16762
|
const fifthShift = k === 0 ? 0 : SEMITONE_TO_FIFTH_SHIFT[(k % 12 + 12) % 12];
|
|
15935
16763
|
melody.push({
|
|
@@ -15983,7 +16811,7 @@ var draw = (options, resolvedKey, rnd) => {
|
|
|
15983
16811
|
subSemi = pushSub(
|
|
15984
16812
|
cursor,
|
|
15985
16813
|
step,
|
|
15986
|
-
i2 === 0 ? subSemi : walk(subSemi, subDir)
|
|
16814
|
+
i2 === 0 ? subSemi : walk(scale, subSemi, subDir)
|
|
15987
16815
|
);
|
|
15988
16816
|
placed++;
|
|
15989
16817
|
}
|
|
@@ -16007,7 +16835,7 @@ var draw = (options, resolvedKey, rnd) => {
|
|
|
16007
16835
|
subSemi = pushSub(
|
|
16008
16836
|
cursor,
|
|
16009
16837
|
step,
|
|
16010
|
-
index === 0 ? subSemi : walk(subSemi, subDir * (index % 2 === 0 ? 1 : -1))
|
|
16838
|
+
index === 0 ? subSemi : walk(scale, subSemi, subDir * (index % 2 === 0 ? 1 : -1))
|
|
16011
16839
|
);
|
|
16012
16840
|
index++;
|
|
16013
16841
|
}
|
|
@@ -16017,7 +16845,11 @@ var draw = (options, resolvedKey, rnd) => {
|
|
|
16017
16845
|
pushSub(0, stepsPerBar, subSemi);
|
|
16018
16846
|
} else if (subStyle === "long-short") {
|
|
16019
16847
|
subSemi = pushSub(0, scaleStep(DOT_HALF), subSemi);
|
|
16020
|
-
pushSub(
|
|
16848
|
+
pushSub(
|
|
16849
|
+
scaleStep(DOT_HALF),
|
|
16850
|
+
scaleStep(QUARTER),
|
|
16851
|
+
walk(scale, subSemi, subDir)
|
|
16852
|
+
);
|
|
16021
16853
|
} else if (role === "cadence") {
|
|
16022
16854
|
pushSub(0, stepsPerBar, subSemi);
|
|
16023
16855
|
} else {
|
|
@@ -16032,6 +16864,7 @@ var draw = (options, resolvedKey, rnd) => {
|
|
|
16032
16864
|
const written = [];
|
|
16033
16865
|
for (let i2 = 0; i2 < slots.length; i2++) {
|
|
16034
16866
|
const hTone = harmonyPitch(
|
|
16867
|
+
scale,
|
|
16035
16868
|
pitches[i2],
|
|
16036
16869
|
tones,
|
|
16037
16870
|
last,
|
|
@@ -16102,6 +16935,7 @@ var draw = (options, resolvedKey, rnd) => {
|
|
|
16102
16935
|
const nextTones = chordTones(progression[(bar + 1) % totalBars]);
|
|
16103
16936
|
const A = clampSemi(
|
|
16104
16937
|
walk(
|
|
16938
|
+
scale,
|
|
16105
16939
|
nextTones[0] ? clampSemi(nextTones[0].semi, BASS_LOW, BASS_HIGH) : R,
|
|
16106
16940
|
-1
|
|
16107
16941
|
),
|
|
@@ -16158,7 +16992,7 @@ var draw = (options, resolvedKey, rnd) => {
|
|
|
16158
16992
|
let bassCursor = 0;
|
|
16159
16993
|
for (const [semi, value] of bassCell) {
|
|
16160
16994
|
const len = scaleStep(value);
|
|
16161
|
-
const fifth = semi === R || semi === O ? rootTone.fifth : semi === F ? fifthTone?.fifth ?? rootTone.fifth : semi === T ? thirdTone?.fifth ?? rootTone.fifth :
|
|
16995
|
+
const fifth = semi === R || semi === O ? rootTone.fifth : semi === F ? fifthTone?.fifth ?? rootTone.fifth : semi === T ? thirdTone?.fifth ?? rootTone.fifth : scaleFifth(scale, semi);
|
|
16162
16996
|
const k = barKeyShift[bar];
|
|
16163
16997
|
const fifthShift = k === 0 ? 0 : SEMITONE_TO_FIFTH_SHIFT[(k % 12 + 12) % 12];
|
|
16164
16998
|
barBass.push({
|
|
@@ -16220,7 +17054,7 @@ var draw = (options, resolvedKey, rnd) => {
|
|
|
16220
17054
|
const after = melody[i2 + 2];
|
|
16221
17055
|
if (after && Math.floor(after.startStep / stepsPerBar) === barIdx) {
|
|
16222
17056
|
const afterSemi = Math.round(after.pitchUnits / UNITS_PER_SEMITONE) - (barKeyShift[barIdx] ?? 0);
|
|
16223
|
-
if (!
|
|
17057
|
+
if (!scalePcs(scale).has(pitchClass(afterSemi))) continue;
|
|
16224
17058
|
}
|
|
16225
17059
|
const nextRole = barRoles[barIdx];
|
|
16226
17060
|
let tieProb = 0.3;
|
|
@@ -16241,11 +17075,13 @@ var draw = (options, resolvedKey, rnd) => {
|
|
|
16241
17075
|
melodyDurations[i2] += melodyDurations[i2 + 1];
|
|
16242
17076
|
melodyDurations.splice(i2 + 1, 1);
|
|
16243
17077
|
}
|
|
16244
|
-
const
|
|
16245
|
-
|
|
16246
|
-
|
|
16247
|
-
|
|
16248
|
-
|
|
17078
|
+
for (const voice of [harmony, harmony2]) {
|
|
17079
|
+
const nxtIdx = voice.findIndex((h) => h.startStep === nxt.startStep);
|
|
17080
|
+
if (nxtIdx < 0) continue;
|
|
17081
|
+
const curIdx = voice.findIndex((h) => h.startStep === cur.startStep);
|
|
17082
|
+
if (curIdx >= 0)
|
|
17083
|
+
voice[curIdx].durationSteps += voice[nxtIdx].durationSteps;
|
|
17084
|
+
voice.splice(nxtIdx, 1);
|
|
16249
17085
|
}
|
|
16250
17086
|
i2--;
|
|
16251
17087
|
}
|
|
@@ -16299,17 +17135,20 @@ var draw = (options, resolvedKey, rnd) => {
|
|
|
16299
17135
|
};
|
|
16300
17136
|
const shiftUnits = semitonesToUnits(rootShift, edo);
|
|
16301
17137
|
if (shiftUnits !== 0)
|
|
16302
|
-
for (const list of [melody, submelody, bass, harmony, harmony2, pad])
|
|
17138
|
+
for (const list of [melody, submelody, bass, harmony, harmony2, pad, solo])
|
|
16303
17139
|
for (const n of list) n.pitchUnits = n.pitchUnits + shiftUnits;
|
|
16304
17140
|
const octave = useOctaveLayer ? melody.filter(
|
|
16305
17141
|
(n) => n.durationSteps >= quarterSteps || rnd() < octaveCoverage
|
|
16306
17142
|
).map((n) => ({ ...n, velocity: Math.max(40, n.velocity - 26) })) : [];
|
|
16307
17143
|
return {
|
|
17144
|
+
form,
|
|
16308
17145
|
chordProgression,
|
|
16309
17146
|
chordPattern,
|
|
16310
17147
|
rootShift,
|
|
16311
17148
|
keyName: resolvedKey.keyName,
|
|
16312
17149
|
keyLabel: resolvedKey.keyLabel,
|
|
17150
|
+
scaleId: scale.id,
|
|
17151
|
+
scaleLabel: scale.label,
|
|
16313
17152
|
moodLabel: resolvedKey.moodLabel,
|
|
16314
17153
|
bpm,
|
|
16315
17154
|
sections: sectionPlan,
|
|
@@ -16329,6 +17168,7 @@ var draw = (options, resolvedKey, rnd) => {
|
|
|
16329
17168
|
harmony2,
|
|
16330
17169
|
octave,
|
|
16331
17170
|
pad,
|
|
17171
|
+
solo,
|
|
16332
17172
|
melodyDurations,
|
|
16333
17173
|
restSteps,
|
|
16334
17174
|
totalSteps: Math.max(1, sungBars) * stepsPerBar,
|
|
@@ -16388,7 +17228,7 @@ var evaluate = (d, recent) => {
|
|
|
16388
17228
|
Math.min(...recent.map((r) => featureDistance(fingerprint, r))) / 1
|
|
16389
17229
|
);
|
|
16390
17230
|
const at = (b, v) => band(v, b[0], b[1], b[2], b[3]);
|
|
16391
|
-
const atc = (key, v) =>
|
|
17231
|
+
const atc = (key, v) => plausibleBand(v, CORPUS_BANDS[key]);
|
|
16392
17232
|
const peakBand = d.bars > 24 ? [0, 1, Math.round(d.bars / 16), Math.round(d.bars / 8) + 2] : HAND_BANDS.climaxPeaks;
|
|
16393
17233
|
const scoreBreakdown = {
|
|
16394
17234
|
entropy: atc("entropy", entropy),
|
|
@@ -16424,9 +17264,16 @@ var evaluate = (d, recent) => {
|
|
|
16424
17264
|
tensionResolve: d.tonal.floating ? 1 : tension.resolve,
|
|
16425
17265
|
novelty
|
|
16426
17266
|
};
|
|
17267
|
+
const forgiven = new Set(
|
|
17268
|
+
Object.entries(WEIGHTS).filter(([key]) => BUDGETED_KEYS.has(key)).map(([key, weight]) => ({
|
|
17269
|
+
key,
|
|
17270
|
+
deficit: weight * (1 - (scoreBreakdown[key] ?? 0))
|
|
17271
|
+
})).sort((a, b) => b.deficit - a.deficit).slice(0, DEVIATION_BUDGET).filter((e) => e.deficit > 0).map((e) => e.key)
|
|
17272
|
+
);
|
|
16427
17273
|
let weighted = 0;
|
|
16428
17274
|
let weightSum = 0;
|
|
16429
17275
|
for (const [key, weight] of Object.entries(WEIGHTS)) {
|
|
17276
|
+
if (forgiven.has(key)) continue;
|
|
16430
17277
|
weighted += (scoreBreakdown[key] ?? 0) * weight;
|
|
16431
17278
|
weightSum += weight;
|
|
16432
17279
|
}
|
|
@@ -16458,49 +17305,74 @@ var composeSong = (options) => {
|
|
|
16458
17305
|
const recent = options.recent ?? [];
|
|
16459
17306
|
const count = Math.max(1, options.drawCount ?? DRAW_COUNT);
|
|
16460
17307
|
const resolvedKey = resolveComposeKey(options.baseKey, rnd);
|
|
16461
|
-
|
|
16462
|
-
|
|
16463
|
-
|
|
17308
|
+
const scale = resolveComposeScale(
|
|
17309
|
+
options.scale,
|
|
17310
|
+
resolvedKey.mode === "minor",
|
|
17311
|
+
rnd
|
|
17312
|
+
);
|
|
17313
|
+
const valid = [];
|
|
17314
|
+
const invalid = [];
|
|
16464
17315
|
let rejected = 0;
|
|
16465
17316
|
for (let attempt = 1; attempt <= count; attempt++) {
|
|
16466
|
-
const
|
|
16467
|
-
const { stats, ok } = evaluate(
|
|
16468
|
-
if (
|
|
16469
|
-
|
|
16470
|
-
|
|
16471
|
-
|
|
16472
|
-
|
|
16473
|
-
|
|
16474
|
-
|
|
16475
|
-
|
|
16476
|
-
|
|
16477
|
-
|
|
16478
|
-
|
|
16479
|
-
|
|
16480
|
-
|
|
16481
|
-
|
|
16482
|
-
|
|
16483
|
-
|
|
16484
|
-
|
|
16485
|
-
|
|
16486
|
-
|
|
16487
|
-
|
|
16488
|
-
tonal: d.tonal,
|
|
16489
|
-
melody: d.melody,
|
|
16490
|
-
submelody: d.submelody,
|
|
16491
|
-
bass: d.bass,
|
|
16492
|
-
harmony: d.harmony,
|
|
16493
|
-
harmony2: d.harmony2,
|
|
16494
|
-
octave: d.octave,
|
|
16495
|
-
pad: d.pad,
|
|
16496
|
-
stats: { ...stats, attempts: attempt, rejected }
|
|
16497
|
-
};
|
|
17317
|
+
const d2 = draw(options, resolvedKey, scale, rnd);
|
|
17318
|
+
const { stats, ok } = evaluate(d2, recent);
|
|
17319
|
+
if (ok) valid.push({ d: d2, stats });
|
|
17320
|
+
else {
|
|
17321
|
+
rejected++;
|
|
17322
|
+
invalid.push({ d: d2, stats });
|
|
17323
|
+
}
|
|
17324
|
+
}
|
|
17325
|
+
const pool = valid.length > 0 ? valid : invalid;
|
|
17326
|
+
const top = Math.max(...pool.map((c) => c.stats.score));
|
|
17327
|
+
const weights = pool.map(
|
|
17328
|
+
(c) => Math.exp((c.stats.score - top) / SELECT_TEMPERATURE)
|
|
17329
|
+
);
|
|
17330
|
+
const total = weights.reduce((a, b) => a + b, 0);
|
|
17331
|
+
let ticket = rnd() * total;
|
|
17332
|
+
let chosen = pool[pool.length - 1];
|
|
17333
|
+
for (let i2 = 0; i2 < pool.length; i2++) {
|
|
17334
|
+
ticket -= weights[i2];
|
|
17335
|
+
if (ticket <= 0) {
|
|
17336
|
+
chosen = pool[i2];
|
|
17337
|
+
break;
|
|
17338
|
+
}
|
|
16498
17339
|
}
|
|
16499
|
-
const
|
|
17340
|
+
const d = chosen.d;
|
|
17341
|
+
const result = {
|
|
17342
|
+
// ドラム・楽器・編曲プランは勝った候補にだけ後から付ける(メロディに
|
|
17343
|
+
// 依存しないので候補ごとに引いても採点は動かず、候補数ぶん無駄になる)。
|
|
17344
|
+
drum: "",
|
|
17345
|
+
instrument: "",
|
|
17346
|
+
arrange: EMPTY_ARRANGE,
|
|
17347
|
+
chordProgression: d.chordProgression,
|
|
17348
|
+
chordPattern: d.chordPattern,
|
|
17349
|
+
rootShift: d.rootShift,
|
|
17350
|
+
keyName: d.keyName,
|
|
17351
|
+
keyLabel: d.keyLabel,
|
|
17352
|
+
scaleId: scale.id,
|
|
17353
|
+
scaleLabel: scale.label,
|
|
17354
|
+
form: d.form,
|
|
17355
|
+
moodLabel: d.moodLabel,
|
|
17356
|
+
bpm: d.bpm,
|
|
17357
|
+
sections: d.sections,
|
|
17358
|
+
bars: d.bars,
|
|
17359
|
+
vocal: d.vocal,
|
|
17360
|
+
tonal: d.tonal,
|
|
17361
|
+
melody: d.melody,
|
|
17362
|
+
submelody: d.submelody,
|
|
17363
|
+
bass: d.bass,
|
|
17364
|
+
harmony: d.harmony,
|
|
17365
|
+
harmony2: d.harmony2,
|
|
17366
|
+
octave: d.octave,
|
|
17367
|
+
pad: d.pad,
|
|
17368
|
+
solo: d.solo,
|
|
17369
|
+
stats: { ...chosen.stats, attempts: count, rejected }
|
|
17370
|
+
};
|
|
16500
17371
|
result.stats.attempts = count;
|
|
16501
17372
|
result.stats.rejected = rejected;
|
|
16502
17373
|
result.drum = pickBuiltinDrum(result, rnd);
|
|
16503
17374
|
result.instrument = pickBuiltinInstrument(result, rnd);
|
|
17375
|
+
result.arrange = buildArrangePlan(result, rnd);
|
|
16504
17376
|
return result;
|
|
16505
17377
|
};
|
|
16506
17378
|
var pickBuiltinDrum = (song, rnd) => {
|
|
@@ -16512,6 +17384,80 @@ var pickBuiltinDrum = (song, rnd) => {
|
|
|
16512
17384
|
const pool = dotted >= 0.08 ? ["shuffle", "8beat", "16beat"] : song.bpm >= 150 ? ["4beat", "dance", "16beat", "disco"] : short >= 0.85 ? ["16beat", "dance", "disco"] : song.bpm <= 115 ? ["bossa", "8beat", "shuffle", "4beat"] : ["8beat", "4beat", "16beat", "dance"];
|
|
16513
17385
|
return pick(pool, rnd);
|
|
16514
17386
|
};
|
|
17387
|
+
var EMPTY_ARRANGE = {
|
|
17388
|
+
backing: [],
|
|
17389
|
+
sparkle: null,
|
|
17390
|
+
padSections: [],
|
|
17391
|
+
lead: null,
|
|
17392
|
+
bassLayer: null
|
|
17393
|
+
};
|
|
17394
|
+
var LOUD_KINDS = ["prechorus", "chorus", "bridge"];
|
|
17395
|
+
var QUIET_KINDS = [
|
|
17396
|
+
"intro",
|
|
17397
|
+
"verse",
|
|
17398
|
+
"interlude",
|
|
17399
|
+
"drop_chorus",
|
|
17400
|
+
"outro"
|
|
17401
|
+
];
|
|
17402
|
+
var CHORUS_KINDS = ["chorus", "drop_chorus"];
|
|
17403
|
+
var buildArrangePlan = (song, rnd) => {
|
|
17404
|
+
const present = new Set(song.sections.map((s) => s.kind));
|
|
17405
|
+
const narrow = (kinds) => {
|
|
17406
|
+
const hit = kinds.filter((k) => present.has(k));
|
|
17407
|
+
return hit.length === 0 ? null : hit;
|
|
17408
|
+
};
|
|
17409
|
+
const base = {
|
|
17410
|
+
pattern: song.chordPattern,
|
|
17411
|
+
sections: null,
|
|
17412
|
+
octave: 0
|
|
17413
|
+
};
|
|
17414
|
+
const others = chordPatternPool(song.bpm).filter((p) => p !== base.pattern);
|
|
17415
|
+
const backing = [base];
|
|
17416
|
+
const addKinds = pick(
|
|
17417
|
+
[LOUD_KINDS, CHORUS_KINDS, LOUD_KINDS, QUIET_KINDS],
|
|
17418
|
+
rnd
|
|
17419
|
+
);
|
|
17420
|
+
const second = pick(others, rnd);
|
|
17421
|
+
backing.push({
|
|
17422
|
+
pattern: second,
|
|
17423
|
+
sections: narrow(addKinds),
|
|
17424
|
+
octave: 0
|
|
17425
|
+
});
|
|
17426
|
+
if (rnd() < 0.55) {
|
|
17427
|
+
const rest = others.filter((p) => p !== second);
|
|
17428
|
+
backing.push({
|
|
17429
|
+
pattern: pick(rest.length > 0 ? rest : others, rnd),
|
|
17430
|
+
// 2本目と逆側へ置く(両方サビに寄せると、サビだけ団子になる)。
|
|
17431
|
+
sections: narrow(addKinds === QUIET_KINDS ? LOUD_KINDS : QUIET_KINDS),
|
|
17432
|
+
octave: 0
|
|
17433
|
+
});
|
|
17434
|
+
}
|
|
17435
|
+
const sparklePool = chordPatternPool(song.bpm).filter(
|
|
17436
|
+
(p) => p !== "block" && !backing.some((b) => b.pattern === p)
|
|
17437
|
+
);
|
|
17438
|
+
const sparkle = sparklePool.length > 0 && rnd() < 0.7 ? {
|
|
17439
|
+
pattern: pick(sparklePool, rnd),
|
|
17440
|
+
sections: narrow(pick([LOUD_KINDS, CHORUS_KINDS], rnd)) ?? CHORUS_KINDS,
|
|
17441
|
+
octave: 1
|
|
17442
|
+
} : null;
|
|
17443
|
+
const padSections = narrow(
|
|
17444
|
+
pick(
|
|
17445
|
+
[
|
|
17446
|
+
["prechorus", "chorus", "bridge", "drop_chorus"],
|
|
17447
|
+
["chorus", "drop_chorus"],
|
|
17448
|
+
["prechorus", "chorus", "bridge", "drop_chorus"],
|
|
17449
|
+
["bridge", "chorus"]
|
|
17450
|
+
],
|
|
17451
|
+
rnd
|
|
17452
|
+
)
|
|
17453
|
+
) ?? [];
|
|
17454
|
+
const lead = rnd() < 0.75 ? {
|
|
17455
|
+
sections: narrow(pick([CHORUS_KINDS, LOUD_KINDS], rnd)) ?? CHORUS_KINDS,
|
|
17456
|
+
octave: rnd() < 0.5 ? 0 : 1
|
|
17457
|
+
} : null;
|
|
17458
|
+
const bassLayer = rnd() < 0.25 ? { sections: narrow(CHORUS_KINDS) ?? CHORUS_KINDS, octave: 1 } : null;
|
|
17459
|
+
return { backing, sparkle, padSections, lead, bassLayer };
|
|
17460
|
+
};
|
|
16515
17461
|
var pickBuiltinInstrument = (song, rnd) => {
|
|
16516
17462
|
const eighth = BASE_STEPS_PER_BAR / 8;
|
|
16517
17463
|
const short = song.melody.filter((n) => n.durationSteps <= eighth).length / Math.max(1, song.melody.length);
|
|
@@ -16622,6 +17568,492 @@ var composeLyrics = (melody, options) => {
|
|
|
16622
17568
|
return out.join("");
|
|
16623
17569
|
};
|
|
16624
17570
|
|
|
17571
|
+
// src/instrument-presets.ts
|
|
17572
|
+
var INSTRUMENT_PRESETS = {
|
|
17573
|
+
// --- STANDARD: 汎用性と完成度重視 ---
|
|
17574
|
+
piano: {
|
|
17575
|
+
displayName: "\u30B0\u30E9\u30F3\u30C9\u30D4\u30A2\u30CE",
|
|
17576
|
+
description: "\u6700\u3082\u7834\u7DBB\u3057\u306B\u304F\u3044\u69CB\u6210\u3002\u697D\u66F2\u5236\u4F5C\u306E\u30B9\u30B1\u30C3\u30C1\u306B\u3082\u6700\u9069\u3002",
|
|
17577
|
+
melody: "Acoustic Grand Piano",
|
|
17578
|
+
submelody: "Vibraphone",
|
|
17579
|
+
bass: "Electric Bass (finger)",
|
|
17580
|
+
chord: "Pad 2 (warm)",
|
|
17581
|
+
solo: "Electric Guitar (clean)",
|
|
17582
|
+
// **Glockenspiel は使わない。音源側のサンプルが音程を外している**(実聴で確認)。
|
|
17583
|
+
// 音域の問題(G5〜の高音楽器)なら {@link GM_BRIGHT_CEILING} で下げれば済むが、
|
|
17584
|
+
// ピッチそのものがずれているものは置き場所を変えても直らない。同じ役割
|
|
17585
|
+
// (サビの上に乗る明るい音板)で、素直に鳴る Celesta へ差し替えてある。
|
|
17586
|
+
// ※ {@link GM_INSTRUMENT_RANGE} / {@link GM_BRIGHT_CEILING} の Glockenspiel の
|
|
17587
|
+
// 項は残す。手で選んだときの置き場所の判断はそのまま要るため。
|
|
17588
|
+
chorusLead: "Celesta",
|
|
17589
|
+
chordAlt: "Electric Piano 1",
|
|
17590
|
+
sparkle: "Music Box",
|
|
17591
|
+
bassAlt: "Acoustic Bass",
|
|
17592
|
+
harmonyAlt: "Choir Aahs"
|
|
17593
|
+
},
|
|
17594
|
+
acoustic: {
|
|
17595
|
+
displayName: "\u30A2\u30B3\u30FC\u30B9\u30C6\u30A3\u30C3\u30AF",
|
|
17596
|
+
description: "\u751F\u697D\u5668\u306E\u6E29\u304B\u307F\u3092\u91CD\u8996\u3002\u30D5\u30A9\u30FC\u30AF\u3084\u30DD\u30C3\u30D7\u30B9\u306B\u3002",
|
|
17597
|
+
melody: "Acoustic Guitar (steel)",
|
|
17598
|
+
submelody: "Harmonica",
|
|
17599
|
+
bass: "Acoustic Bass",
|
|
17600
|
+
chord: "Acoustic Guitar (nylon)",
|
|
17601
|
+
solo: "Overdriven Guitar",
|
|
17602
|
+
chorusLead: "String Ensemble 1",
|
|
17603
|
+
chordAlt: "Acoustic Grand Piano",
|
|
17604
|
+
sparkle: "Celesta",
|
|
17605
|
+
bassAlt: "Electric Bass (finger)",
|
|
17606
|
+
harmonyAlt: "Choir Aahs"
|
|
17607
|
+
},
|
|
17608
|
+
jazz_night: {
|
|
17609
|
+
displayName: "\u30B8\u30E3\u30BA\u30FB\u30CA\u30A4\u30C8",
|
|
17610
|
+
description: "Rhodes\u98A8\u306EEP\u3068\u30A6\u30C3\u30C9\u30D9\u30FC\u30B9\u306B\u3088\u308B\u3001\u5927\u4EBA\u3073\u305F\u30A2\u30F3\u30B5\u30F3\u30D6\u30EB\u3002",
|
|
17611
|
+
melody: "Electric Piano 1",
|
|
17612
|
+
submelody: "Flute",
|
|
17613
|
+
bass: "Acoustic Bass",
|
|
17614
|
+
chord: "Electric Guitar (jazz)",
|
|
17615
|
+
solo: "Tenor Sax",
|
|
17616
|
+
chorusLead: "Muted Trumpet",
|
|
17617
|
+
chordAlt: "Vibraphone",
|
|
17618
|
+
sparkle: "Celesta",
|
|
17619
|
+
bassAlt: "Electric Bass (finger)",
|
|
17620
|
+
harmonyAlt: "Choir Aahs"
|
|
17621
|
+
},
|
|
17622
|
+
// --- MODERN & VIBE: エッジの効いた現代的な響き ---
|
|
17623
|
+
synth_pop: {
|
|
17624
|
+
displayName: "\u30B7\u30F3\u30BB\u30DD\u30C3\u30D7",
|
|
17625
|
+
description: "80s\u301C\u73FE\u4EE3\u307E\u3067\u3002\u629C\u3051\u308B\u30EA\u30FC\u30C9\u3068\u592A\u3044\u30D9\u30FC\u30B9\u306E\u738B\u9053\u3002",
|
|
17626
|
+
melody: "Lead 2 (sawtooth)",
|
|
17627
|
+
submelody: "Lead 4 (chiff)",
|
|
17628
|
+
bass: "Synth Bass 2",
|
|
17629
|
+
chord: "Pad 3 (polysynth)",
|
|
17630
|
+
solo: "Distortion Guitar",
|
|
17631
|
+
chorusLead: "Synth Brass 1",
|
|
17632
|
+
chordAlt: "Electric Piano 2",
|
|
17633
|
+
sparkle: "FX 3 (crystal)",
|
|
17634
|
+
bassAlt: "Synth Bass 1",
|
|
17635
|
+
harmonyAlt: "Synth Choir"
|
|
17636
|
+
},
|
|
17637
|
+
cyber_punk: {
|
|
17638
|
+
displayName: "\u30B5\u30A4\u30D0\u30FC\u30D1\u30F3\u30AF",
|
|
17639
|
+
description: "\u30C7\u30B8\u30BF\u30EB\u306A\u51B7\u305F\u3055\u3068\u6B6A\u307F\u304C\u6DF7\u3056\u308A\u5408\u3046\u3001\u672A\u6765\u7684\u306A\u97FF\u304D\u3002",
|
|
17640
|
+
melody: "Lead 8 (bass + lead)",
|
|
17641
|
+
submelody: "Lead 5 (charang)",
|
|
17642
|
+
bass: "Synth Bass 2",
|
|
17643
|
+
chord: "Pad 8 (sweep)",
|
|
17644
|
+
solo: "Distortion Guitar",
|
|
17645
|
+
chorusLead: "Lead 7 (fifths)",
|
|
17646
|
+
chordAlt: "Pad 4 (choir)",
|
|
17647
|
+
sparkle: "FX 3 (crystal)",
|
|
17648
|
+
bassAlt: "Synth Bass 1",
|
|
17649
|
+
harmonyAlt: "Synth Choir"
|
|
17650
|
+
},
|
|
17651
|
+
rock: {
|
|
17652
|
+
displayName: "\u30CF\u30FC\u30C9\u30ED\u30C3\u30AF",
|
|
17653
|
+
description: "\u6B6A\u307F\u30AE\u30BF\u30FC\u3068\u91CD\u539A\u306A\u30D9\u30FC\u30B9\u3067\u3001\u30D1\u30EF\u30FC\u3092\u524D\u9762\u306B\u3002",
|
|
17654
|
+
melody: "Distortion Guitar",
|
|
17655
|
+
submelody: "Rock Organ",
|
|
17656
|
+
bass: "Electric Bass (pick)",
|
|
17657
|
+
chord: "Overdriven Guitar",
|
|
17658
|
+
solo: "Distortion Guitar",
|
|
17659
|
+
chorusLead: "Brass Section",
|
|
17660
|
+
chordAlt: "Electric Guitar (clean)",
|
|
17661
|
+
sparkle: "Electric Guitar (muted)",
|
|
17662
|
+
bassAlt: "Electric Bass (finger)",
|
|
17663
|
+
harmonyAlt: "Choir Aahs"
|
|
17664
|
+
},
|
|
17665
|
+
// --- WORLD & CLASSIC: 特定のジャンル・地域 ---
|
|
17666
|
+
orchestra: {
|
|
17667
|
+
displayName: "\u30AA\u30FC\u30B1\u30B9\u30C8\u30E9",
|
|
17668
|
+
description: "\u58EE\u5927\u306A\u7269\u8A9E\u3092\u4E88\u611F\u3055\u305B\u308B\u3001\u7BA1\u5F26\u697D\u5668\u306E\u91CD\u539A\u306A\u97FF\u304D\u3002",
|
|
17669
|
+
melody: "French Horn",
|
|
17670
|
+
submelody: "Pizzicato Strings",
|
|
17671
|
+
bass: "Cello",
|
|
17672
|
+
chord: "Tremolo Strings",
|
|
17673
|
+
solo: "Violin",
|
|
17674
|
+
chorusLead: "Trumpet",
|
|
17675
|
+
chordAlt: "String Ensemble 1",
|
|
17676
|
+
sparkle: "Orchestral Harp",
|
|
17677
|
+
bassAlt: "Contrabass",
|
|
17678
|
+
harmonyAlt: "Choir Aahs"
|
|
17679
|
+
},
|
|
17680
|
+
japanese_wa: {
|
|
17681
|
+
displayName: "\u548C\u98A8\u30FB\u96C5",
|
|
17682
|
+
description: "\u7434\u3068\u4E09\u5473\u7DDA\u306E\u7E4A\u7D30\u306A\u8ABF\u3079\u306B\u3001\u5C3A\u516B\u306E\u60C5\u7DD2\u3092\u6DFB\u3048\u3066\u3002",
|
|
17683
|
+
melody: "Koto",
|
|
17684
|
+
submelody: "Shamisen",
|
|
17685
|
+
bass: "Taiko Drum",
|
|
17686
|
+
chord: "Shakuhachi",
|
|
17687
|
+
solo: "Shakuhachi",
|
|
17688
|
+
// piano プリセットと同じ理由で Glockenspiel を避ける(音源のピッチずれ)。
|
|
17689
|
+
chorusLead: "Celesta",
|
|
17690
|
+
chordAlt: "Kalimba",
|
|
17691
|
+
sparkle: "Music Box",
|
|
17692
|
+
bassAlt: "Acoustic Bass",
|
|
17693
|
+
harmonyAlt: "Choir Aahs"
|
|
17694
|
+
},
|
|
17695
|
+
arabic_exotic: {
|
|
17696
|
+
displayName: "\u30A8\u30AD\u30BE\u30C1\u30C3\u30AF",
|
|
17697
|
+
description: "\u30B7\u30BF\u30FC\u30EB\u3084\u30D0\u30B0\u30D1\u30A4\u30D7\u306B\u3088\u308B\u3001\u7570\u56FD\u60C5\u7DD2\u6EA2\u308C\u308B\u30B5\u30A6\u30F3\u30C9\u3002",
|
|
17698
|
+
melody: "Sitar",
|
|
17699
|
+
submelody: "Bagpipe",
|
|
17700
|
+
bass: "Fretless Bass",
|
|
17701
|
+
chord: "Kalimba",
|
|
17702
|
+
solo: "Shanai",
|
|
17703
|
+
chorusLead: "Steel Drums",
|
|
17704
|
+
chordAlt: "Orchestral Harp",
|
|
17705
|
+
sparkle: "Tinkle Bell",
|
|
17706
|
+
bassAlt: "Acoustic Bass",
|
|
17707
|
+
harmonyAlt: "Choir Aahs"
|
|
17708
|
+
},
|
|
17709
|
+
// --- FANTASY & ATMOSPHERE: 雰囲気と余韻 ---
|
|
17710
|
+
fantasy_rpg: {
|
|
17711
|
+
displayName: "\u30D5\u30A1\u30F3\u30BF\u30B8\u30FCRPG",
|
|
17712
|
+
description: "\u30AA\u30AB\u30EA\u30CA\u3068\u30CF\u30FC\u30D7\u304C\u7D21\u3050\u3001\u5192\u967A\u3068\u9B54\u6CD5\u306E\u4E16\u754C\u89B3\u3002",
|
|
17713
|
+
melody: "Ocarina",
|
|
17714
|
+
submelody: "Celesta",
|
|
17715
|
+
bass: "Timpani",
|
|
17716
|
+
chord: "Orchestral Harp",
|
|
17717
|
+
solo: "Pan Flute",
|
|
17718
|
+
chorusLead: "Choir Aahs",
|
|
17719
|
+
chordAlt: "String Ensemble 2",
|
|
17720
|
+
sparkle: "Tinkle Bell",
|
|
17721
|
+
bassAlt: "Contrabass",
|
|
17722
|
+
harmonyAlt: "Choir Aahs"
|
|
17723
|
+
},
|
|
17724
|
+
ambient_cloud: {
|
|
17725
|
+
displayName: "\u30A2\u30F3\u30D3\u30A8\u30F3\u30C8",
|
|
17726
|
+
description: "\u8F2A\u90ED\u3092\u307C\u304B\u3057\u305F\u97F3\u8272\u3067\u3001\u6DF1\u3044\u6CA1\u5165\u611F\u3068\u4F59\u97FB\u3092\u6F14\u51FA\u3002",
|
|
17727
|
+
melody: "Lead 6 (voice)",
|
|
17728
|
+
submelody: "Music Box",
|
|
17729
|
+
bass: "Synth Bass 1",
|
|
17730
|
+
chord: "Pad 7 (halo)",
|
|
17731
|
+
solo: "Lead 3 (calliope)",
|
|
17732
|
+
chorusLead: "Synth Choir",
|
|
17733
|
+
chordAlt: "Pad 5 (bowed)",
|
|
17734
|
+
sparkle: "FX 3 (crystal)",
|
|
17735
|
+
bassAlt: "Synth Bass 2",
|
|
17736
|
+
harmonyAlt: "Synth Choir"
|
|
17737
|
+
},
|
|
17738
|
+
retro_game: {
|
|
17739
|
+
displayName: "8-bit \u30EC\u30C8\u30ED",
|
|
17740
|
+
description: "\u77E9\u5F62\u6CE2\u3092\u60F3\u8D77\u3055\u305B\u308B\u3001\u521D\u671F\u30B2\u30FC\u30E0\u6A5F\u306E\u3088\u3046\u306A\u61D0\u304B\u3057\u3044\u97FF\u304D\u3002",
|
|
17741
|
+
melody: "Lead 1 (square)",
|
|
17742
|
+
submelody: "Lead 2 (sawtooth)",
|
|
17743
|
+
bass: "Synth Bass 1",
|
|
17744
|
+
chord: "Clavinet",
|
|
17745
|
+
solo: "Lead 8 (bass + lead)",
|
|
17746
|
+
chorusLead: "Lead 4 (chiff)",
|
|
17747
|
+
chordAlt: "Lead 5 (charang)",
|
|
17748
|
+
sparkle: "Xylophone",
|
|
17749
|
+
bassAlt: "Synth Bass 2",
|
|
17750
|
+
harmonyAlt: "Lead 6 (voice)"
|
|
17751
|
+
}
|
|
17752
|
+
};
|
|
17753
|
+
var GM_INSTRUMENT_RANGE = {
|
|
17754
|
+
// 鍵盤・音板
|
|
17755
|
+
"Acoustic Grand Piano": [21, 108],
|
|
17756
|
+
"Electric Piano 1": [28, 103],
|
|
17757
|
+
Clavinet: [36, 96],
|
|
17758
|
+
Celesta: [60, 108],
|
|
17759
|
+
Glockenspiel: [79, 108],
|
|
17760
|
+
"Music Box": [72, 108],
|
|
17761
|
+
Vibraphone: [53, 89],
|
|
17762
|
+
Kalimba: [60, 84],
|
|
17763
|
+
"Orchestral Harp": [23, 104],
|
|
17764
|
+
// 弦・撥弦
|
|
17765
|
+
"Acoustic Guitar (steel)": [40, 83],
|
|
17766
|
+
"Acoustic Guitar (nylon)": [40, 83],
|
|
17767
|
+
"Electric Guitar (clean)": [40, 86],
|
|
17768
|
+
"Electric Guitar (jazz)": [40, 86],
|
|
17769
|
+
"Overdriven Guitar": [40, 88],
|
|
17770
|
+
"Distortion Guitar": [40, 88],
|
|
17771
|
+
Violin: [55, 103],
|
|
17772
|
+
Cello: [36, 76],
|
|
17773
|
+
"String Ensemble 1": [28, 100],
|
|
17774
|
+
"Tremolo Strings": [28, 100],
|
|
17775
|
+
"Pizzicato Strings": [28, 96],
|
|
17776
|
+
Sitar: [48, 79],
|
|
17777
|
+
Shamisen: [48, 84],
|
|
17778
|
+
Koto: [41, 77],
|
|
17779
|
+
// ベース
|
|
17780
|
+
"Acoustic Bass": [28, 60],
|
|
17781
|
+
"Electric Bass (finger)": [28, 67],
|
|
17782
|
+
"Electric Bass (pick)": [28, 67],
|
|
17783
|
+
"Fretless Bass": [28, 67],
|
|
17784
|
+
"Synth Bass 1": [24, 72],
|
|
17785
|
+
"Synth Bass 2": [24, 72],
|
|
17786
|
+
// 管
|
|
17787
|
+
Flute: [60, 96],
|
|
17788
|
+
"Pan Flute": [60, 91],
|
|
17789
|
+
Shakuhachi: [62, 86],
|
|
17790
|
+
Ocarina: [60, 84],
|
|
17791
|
+
Harmonica: [60, 96],
|
|
17792
|
+
Bagpipe: [62, 86],
|
|
17793
|
+
Shanai: [60, 86],
|
|
17794
|
+
"Tenor Sax": [44, 75],
|
|
17795
|
+
Trumpet: [55, 82],
|
|
17796
|
+
"Muted Trumpet": [55, 82],
|
|
17797
|
+
"French Horn": [41, 77],
|
|
17798
|
+
"Brass Section": [41, 84],
|
|
17799
|
+
// 声・打・オルガン
|
|
17800
|
+
"Choir Aahs": [43, 84],
|
|
17801
|
+
"Synth Choir": [43, 84],
|
|
17802
|
+
"Steel Drums": [55, 86],
|
|
17803
|
+
"Taiko Drum": [30, 60],
|
|
17804
|
+
Timpani: [36, 57],
|
|
17805
|
+
"Rock Organ": [36, 96],
|
|
17806
|
+
// シンセ(実物が無いので一般的な使用域)
|
|
17807
|
+
"Synth Brass 1": [36, 96],
|
|
17808
|
+
"Lead 1 (square)": [36, 96],
|
|
17809
|
+
"Lead 2 (sawtooth)": [36, 96],
|
|
17810
|
+
"Lead 3 (calliope)": [48, 96],
|
|
17811
|
+
"Lead 4 (chiff)": [48, 96],
|
|
17812
|
+
"Lead 5 (charang)": [40, 96],
|
|
17813
|
+
"Lead 6 (voice)": [43, 91],
|
|
17814
|
+
"Lead 7 (fifths)": [36, 84],
|
|
17815
|
+
"Lead 8 (bass + lead)": [28, 91],
|
|
17816
|
+
"Pad 2 (warm)": [24, 96],
|
|
17817
|
+
"Pad 3 (polysynth)": [24, 96],
|
|
17818
|
+
"Pad 7 (halo)": [24, 96],
|
|
17819
|
+
"Pad 8 (sweep)": [24, 96]
|
|
17820
|
+
};
|
|
17821
|
+
var GM_BRIGHT_CEILING = {
|
|
17822
|
+
Glockenspiel: 72,
|
|
17823
|
+
"Tinkle Bell": 72,
|
|
17824
|
+
"Music Box": 79,
|
|
17825
|
+
Celesta: 84,
|
|
17826
|
+
Kalimba: 79,
|
|
17827
|
+
"Steel Drums": 84,
|
|
17828
|
+
"FX 3 (crystal)": 79
|
|
17829
|
+
};
|
|
17830
|
+
var OCTAVE_FIT_TOLERANCE = 3;
|
|
17831
|
+
var fitInstrumentOctave = (semitoneRange, instrument, wanted) => {
|
|
17832
|
+
const range = GM_INSTRUMENT_RANGE[instrument];
|
|
17833
|
+
if (!range || !semitoneRange) return wanted;
|
|
17834
|
+
const hi = Math.min(range[1], GM_BRIGHT_CEILING[instrument] ?? range[1]);
|
|
17835
|
+
let octave = wanted;
|
|
17836
|
+
while (octave > wanted - 2) {
|
|
17837
|
+
if (semitoneRange[1] + octave * 12 <= hi + OCTAVE_FIT_TOLERANCE) break;
|
|
17838
|
+
octave--;
|
|
17839
|
+
}
|
|
17840
|
+
return octave;
|
|
17841
|
+
};
|
|
17842
|
+
|
|
17843
|
+
// src/advanced-layers.ts
|
|
17844
|
+
var buildAdvancedLayers = (song, config) => {
|
|
17845
|
+
const { edo, stepsPerBar, preset } = config;
|
|
17846
|
+
const semitoneRange = (notes) => {
|
|
17847
|
+
if (notes.length === 0) return null;
|
|
17848
|
+
let lo = Number.POSITIVE_INFINITY;
|
|
17849
|
+
let hi = Number.NEGATIVE_INFINITY;
|
|
17850
|
+
for (const n of notes) {
|
|
17851
|
+
const semi = n.pitchUnits / UNITS_PER_SEMITONE;
|
|
17852
|
+
if (semi < lo) lo = semi;
|
|
17853
|
+
if (semi > hi) hi = semi;
|
|
17854
|
+
}
|
|
17855
|
+
return [Math.round(lo), Math.round(hi)];
|
|
17856
|
+
};
|
|
17857
|
+
const fit = (notes, slot, wanted) => fitInstrumentOctave(semitoneRange(notes), preset[slot], wanted);
|
|
17858
|
+
const kindAtBar = (bar) => song.sections.find(
|
|
17859
|
+
(sec) => bar >= sec.startBar && bar < sec.startBar + sec.bars
|
|
17860
|
+
)?.kind ?? null;
|
|
17861
|
+
const onlyIn = (notes, kinds) => {
|
|
17862
|
+
if (!kinds) return notes;
|
|
17863
|
+
const want = new Set(kinds);
|
|
17864
|
+
return notes.filter((n) => {
|
|
17865
|
+
const kind = kindAtBar(Math.floor(n.startStep / stepsPerBar));
|
|
17866
|
+
return kind !== null && want.has(kind);
|
|
17867
|
+
});
|
|
17868
|
+
};
|
|
17869
|
+
const chordNotes = (pattern, velocityShift = 0) => buildChordPlacements({
|
|
17870
|
+
edo,
|
|
17871
|
+
chordStr: song.chordProgression,
|
|
17872
|
+
patternType: pattern,
|
|
17873
|
+
rootShift: song.rootShift,
|
|
17874
|
+
bpm: song.bpm,
|
|
17875
|
+
stepsPerBar
|
|
17876
|
+
}).map((p) => ({
|
|
17877
|
+
startStep: p.startStep,
|
|
17878
|
+
pitchUnits: p.pitchUnits,
|
|
17879
|
+
durationSteps: p.durationSteps,
|
|
17880
|
+
velocity: Math.max(30, p.velocity + velocityShift)
|
|
17881
|
+
}));
|
|
17882
|
+
const plan = song.arrange;
|
|
17883
|
+
const kindsPresent = [...new Set(song.sections.map((sec) => sec.kind))];
|
|
17884
|
+
const LOUD = ["chorus", "drop_chorus"];
|
|
17885
|
+
const loudKinds = kindsPresent.filter((k) => LOUD.includes(k));
|
|
17886
|
+
const quietKinds = kindsPresent.filter((k) => !LOUD.includes(k));
|
|
17887
|
+
const splittable = loudKinds.length > 0 && quietKinds.length > 0;
|
|
17888
|
+
const leadNotes = plan.lead ? onlyIn(song.melody, plan.lead.sections) : [];
|
|
17889
|
+
const leadOctave = fit(leadNotes, "chorusLead", plan.lead?.octave ?? 0);
|
|
17890
|
+
const leadLayer = {
|
|
17891
|
+
index: 1,
|
|
17892
|
+
notes: leadNotes,
|
|
17893
|
+
octave: leadOctave,
|
|
17894
|
+
// ユニゾンで重ねるときは、オクターブ上より前に出やすいので少し引く。
|
|
17895
|
+
volume: leadOctave === 0 ? 54 : 62,
|
|
17896
|
+
slot: "chorusLead"
|
|
17897
|
+
};
|
|
17898
|
+
const bassNotes = plan.bassLayer ? onlyIn(song.bass, plan.bassLayer.sections) : [];
|
|
17899
|
+
const bassOctave = fit(bassNotes, "bass", plan.bassLayer?.octave ?? 0);
|
|
17900
|
+
const wantBassLayer = plan.bassLayer !== null && bassOctave !== 0;
|
|
17901
|
+
const bassLayer = wantBassLayer ? {
|
|
17902
|
+
index: 5,
|
|
17903
|
+
notes: bassNotes,
|
|
17904
|
+
octave: bassOctave,
|
|
17905
|
+
volume: 58,
|
|
17906
|
+
slot: "bass"
|
|
17907
|
+
} : {
|
|
17908
|
+
index: 5,
|
|
17909
|
+
notes: splittable ? onlyIn(song.bass, loudKinds) : [],
|
|
17910
|
+
octave: 0,
|
|
17911
|
+
volume: 92,
|
|
17912
|
+
slot: "bassAlt"
|
|
17913
|
+
};
|
|
17914
|
+
const padNotes = onlyIn(song.pad, plan.padSections);
|
|
17915
|
+
const layers = [
|
|
17916
|
+
{ index: 0, notes: song.melody, octave: 0, volume: 104, slot: "melody" },
|
|
17917
|
+
leadLayer,
|
|
17918
|
+
// t2 ハモリ。**セクションで分割しない。**
|
|
17919
|
+
// 一度 t12 と loud/quiet で分けてみたが、ハモリは音の87%が盛り上がる側にあり、
|
|
17920
|
+
// 71%の曲は静かな側に1音も無い——分割すると t2 が空になって中身が t12 へ移る。
|
|
17921
|
+
// 「トラック番号と役割の対応は固定」(ピアノロールのどこに何があるかが曲ごとに
|
|
17922
|
+
// 動くとユーザーが編集できない)という原則にも反するので、ここは丸ごと持つ。
|
|
17923
|
+
{ index: 2, notes: song.harmony, octave: 0, volume: 82 },
|
|
17924
|
+
// t3 サブメロ。t14 が間奏ソロを持たないとき、そちらへ盛り上がる側を渡して
|
|
17925
|
+
// こちらは静かな側だけ持つ。対旋律・合いの手がセクションで音色替えする。
|
|
17926
|
+
{
|
|
17927
|
+
index: 3,
|
|
17928
|
+
notes: song.solo.length === 0 && splittable ? onlyIn(song.submelody, quietKinds) : song.submelody,
|
|
17929
|
+
octave: 0,
|
|
17930
|
+
volume: 86,
|
|
17931
|
+
slot: "submelody"
|
|
17932
|
+
},
|
|
17933
|
+
// t4。t5 が `bassAlt` で盛り上がる側を持つときは、こちらは静かな側だけ持つ
|
|
17934
|
+
// (分割であって間引きではない——2本合わせて元のベースが漏れなく鳴る)。
|
|
17935
|
+
{
|
|
17936
|
+
index: 4,
|
|
17937
|
+
notes: !wantBassLayer && splittable ? onlyIn(song.bass, quietKinds) : song.bass,
|
|
17938
|
+
octave: 0,
|
|
17939
|
+
volume: 92,
|
|
17940
|
+
slot: "bass"
|
|
17941
|
+
},
|
|
17942
|
+
bassLayer,
|
|
17943
|
+
// **パッドは伴奏用の楽器で、伴奏より1.5オクターブ高いところを鳴らす。**
|
|
17944
|
+
// そのまま置くとナイロンギターで10半音、カリンバで9半音、尺八で7半音ぶん
|
|
17945
|
+
// 音域を突き抜ける。楽器に合わせて下げる。
|
|
17946
|
+
{
|
|
17947
|
+
index: 6,
|
|
17948
|
+
notes: padNotes,
|
|
17949
|
+
octave: fit(padNotes, "chord", 0),
|
|
17950
|
+
volume: 64,
|
|
17951
|
+
slot: "chord"
|
|
17952
|
+
}
|
|
17953
|
+
];
|
|
17954
|
+
const backingVolumes = [62, 54, 50];
|
|
17955
|
+
for (let i2 = 0; i2 < 3; i2++) {
|
|
17956
|
+
const layer = plan.backing[i2];
|
|
17957
|
+
layers.push({
|
|
17958
|
+
index: 7 + i2,
|
|
17959
|
+
notes: layer ? onlyIn(chordNotes(layer.pattern), layer.sections) : [],
|
|
17960
|
+
octave: layer?.octave ?? 0,
|
|
17961
|
+
volume: backingVolumes[i2],
|
|
17962
|
+
slot: i2 % 2 === 0 ? "chordAlt" : "chord"
|
|
17963
|
+
});
|
|
17964
|
+
}
|
|
17965
|
+
const sparkleNotes = plan.sparkle ? onlyIn(chordNotes(plan.sparkle.pattern, -14), plan.sparkle.sections) : [];
|
|
17966
|
+
layers.push(
|
|
17967
|
+
{
|
|
17968
|
+
index: 10,
|
|
17969
|
+
notes: sparkleNotes,
|
|
17970
|
+
// 装飾は伴奏と別の音色にする(以前はここも `chord` の使い回しだった)。
|
|
17971
|
+
octave: fit(sparkleNotes, "sparkle", plan.sparkle?.octave ?? 0),
|
|
17972
|
+
volume: 56,
|
|
17973
|
+
slot: "sparkle"
|
|
17974
|
+
},
|
|
17975
|
+
// 掛け合い(デュエット)の相手。**歌入り作曲のときだけ**中身が入る。
|
|
17976
|
+
{ index: 11, notes: [], octave: 0, volume: 104, slot: "melody" },
|
|
17977
|
+
// 2声目のハモリ(主旋律を上下から挟む3声)と、主旋律のオクターブ下の重ね。
|
|
17978
|
+
// どちらも曲ごとに出るかどうかが決まる(`song.vocal`)。
|
|
17979
|
+
// t12。3声目のハモリは曲ごとに出るかが決まり、実測28%。
|
|
17980
|
+
//
|
|
17981
|
+
// 出ない曲では**パッド(t6)が鳴っていないセクション**を、別の音色
|
|
17982
|
+
// (`harmonyAlt` =声もの・柔らかい持続音)で受け持つ。パッドはセクション種別の
|
|
17983
|
+
// 39%しか覆っておらず補集合は常に存在するので、ここは**いま何も鳴っていない
|
|
17984
|
+
// 場所に持続音を足す**ことになる——重ねでも写しでもなく、純粋な追加。
|
|
17985
|
+
song.harmony2.length > 0 ? { index: 12, notes: song.harmony2, octave: 0, volume: 74 } : (() => {
|
|
17986
|
+
const rest = plan.padSections ? kindsPresent.filter((k) => !plan.padSections?.includes(k)) : [];
|
|
17987
|
+
const notes = rest.length > 0 ? onlyIn(song.pad, rest) : [];
|
|
17988
|
+
return {
|
|
17989
|
+
index: 12,
|
|
17990
|
+
notes,
|
|
17991
|
+
octave: fit(notes, "harmonyAlt", 0),
|
|
17992
|
+
volume: 60,
|
|
17993
|
+
slot: "harmonyAlt"
|
|
17994
|
+
};
|
|
17995
|
+
})(),
|
|
17996
|
+
// t13。既定は**主旋律のオクターブ下の重ね**で、歌入り作曲ではここに歌詞が付く
|
|
17997
|
+
// (オクターブ下でハモる歌手。単なる写しではない)。
|
|
17998
|
+
//
|
|
17999
|
+
// ただしこの層は曲ごとに出るかどうかが決まり、実測で**18%しか鳴らない**。
|
|
18000
|
+
// 残り82%はトラックが1本まるごと遊ぶ。オクターブ等価の写しに常設の価値は
|
|
18001
|
+
// 無いが、**空けておく価値はもっと無い**ので、層が無い曲では
|
|
18002
|
+
// 「t1(サビ重ね)が担当しないセクションの主旋律を、別の楽器でなぞる」層に回す。
|
|
18003
|
+
// t1 は CHORUS/LOUD 側を持つので、こちらは静かな側を持つ——結果として
|
|
18004
|
+
// **セクションの境目で主旋律に付く音色が入れ替わる**。1トラック1楽器の制約下で
|
|
18005
|
+
// 「パートごとに楽器が変わる」を作れるのは、この書き分けだけ。
|
|
18006
|
+
song.octave.length > 0 ? {
|
|
18007
|
+
index: 13,
|
|
18008
|
+
notes: song.octave,
|
|
18009
|
+
octave: -1,
|
|
18010
|
+
volume: 56,
|
|
18011
|
+
slot: "melody"
|
|
18012
|
+
} : (() => {
|
|
18013
|
+
const leadKinds = new Set(plan.lead?.sections ?? []);
|
|
18014
|
+
const quiet = song.sections.filter((sec) => sec.spec.melody && !leadKinds.has(sec.kind)).map((sec) => sec.kind);
|
|
18015
|
+
const notes = quiet.length > 0 ? onlyIn(song.melody, quiet) : [];
|
|
18016
|
+
const slot = ["solo", "chorusLead", "submelody", "chordAlt"].find(
|
|
18017
|
+
(k) => preset[k] !== preset.melody && preset[k] !== preset.chord
|
|
18018
|
+
) ?? "submelody";
|
|
18019
|
+
return {
|
|
18020
|
+
index: 13,
|
|
18021
|
+
notes,
|
|
18022
|
+
// ユニゾンで置く。**音色だけを変えるのが狙い**なので、
|
|
18023
|
+
// オクターブを動かすと「オクターブ写し」に戻ってしまう。
|
|
18024
|
+
octave: fit(notes, slot, 0),
|
|
18025
|
+
volume: 58,
|
|
18026
|
+
slot
|
|
18027
|
+
};
|
|
18028
|
+
})(),
|
|
18029
|
+
// **間奏のソロ。** 音が入るのは間奏の小節だけなので、この1本だけを
|
|
18030
|
+
// 別の楽器にしても他のセクションの鳴りは変わらない。歌の音域をそのまま
|
|
18031
|
+
// 渡すと管楽器が上へ抜ける(テナーサックスで10半音)ので、ここも合わせる。
|
|
18032
|
+
// t14。**間奏のソロ。** ただし間奏は既定の構成(`DEFAULT_SECTIONS`)に無く、
|
|
18033
|
+
// テンプレートも `jpop_standard` しか含まないので、実測で**0%**——設計上の
|
|
18034
|
+
// 出番が既定では一度も来ないトラックだった。
|
|
18035
|
+
// 間奏が無い曲では、サブメロの盛り上がる側を `solo` の音色で受け持つ
|
|
18036
|
+
// (t3 は静かな側。分割なので音数は増えない)。
|
|
18037
|
+
song.solo.length > 0 ? {
|
|
18038
|
+
index: 14,
|
|
18039
|
+
notes: song.solo,
|
|
18040
|
+
octave: fit(song.solo, "solo", 0),
|
|
18041
|
+
volume: 100,
|
|
18042
|
+
slot: "solo"
|
|
18043
|
+
} : (() => {
|
|
18044
|
+
const notes = splittable ? onlyIn(song.submelody, loudKinds) : [];
|
|
18045
|
+
return {
|
|
18046
|
+
index: 14,
|
|
18047
|
+
notes,
|
|
18048
|
+
octave: fit(notes, "solo", 0),
|
|
18049
|
+
volume: 86,
|
|
18050
|
+
slot: "solo"
|
|
18051
|
+
};
|
|
18052
|
+
})()
|
|
18053
|
+
);
|
|
18054
|
+
return layers;
|
|
18055
|
+
};
|
|
18056
|
+
|
|
16625
18057
|
// src/delay.ts
|
|
16626
18058
|
var DELAY_DIVISIONS = [
|
|
16627
18059
|
{ value: "4", label: "4\u5206", beats: 1 },
|
|
@@ -17042,6 +18474,34 @@ var buildUI = (target, options) => {
|
|
|
17042
18474
|
<span class="dtm-grow"></span>
|
|
17043
18475
|
<span class="dtm-hint" data-dtm="compose-key-hint"></span>
|
|
17044
18476
|
</div>
|
|
18477
|
+
<div class="dtm-row" data-dtm="compose-scale-row">
|
|
18478
|
+
<span class="dtm-label">\u97F3\u968E</span>
|
|
18479
|
+
<select class="dtm-select" data-dtm="compose-scale" title="\u65CB\u5F8B\u304C\u4F7F\u3046\u97F3\u968E\u3092\u9078\u3073\u307E\u3059\u3002\u30D9\u30FC\u30B9\u8ABF\uFF08\u4E3B\u97F3\u306E\u9AD8\u3055\uFF09\u3068\u306F\u72EC\u7ACB\u3057\u305F\u8A2D\u5B9A\u3067\u3059">
|
|
18480
|
+
<option value="auto" title="\u30D9\u30FC\u30B9\u8ABF\u306E\u9577\u77ED\u306B\u5408\u308F\u305B\u3066\u3001\u967D\u97F3\u968E\uFF08\u9577\u8ABF\uFF09\u304B\u6C11\u8B21\u97F3\u968E\uFF08\u77ED\u8ABF\uFF09\u3092\u4F7F\u3044\u307E\u3059">\u304A\u307E\u304B\u305B\uFF08\u5F93\u6765\u3069\u304A\u308A\uFF09</option>
|
|
18481
|
+
<option value="any" title="9\u3064\u306E\u97F3\u968E\u304B\u3089\u30E9\u30F3\u30C0\u30E0\u306B\u62BD\u9078\u3057\u307E\u3059">\u5E0C\u671B\u306A\u3057\uFF08\u5168\u97F3\u968E\u304B\u3089\u62BD\u9078\uFF09</option>
|
|
18482
|
+
<optgroup label="\u30DA\u30F3\u30BF\u30C8\u30CB\u30C3\u30AF\uFF085\u97F3\u97F3\u968E\uFF09">
|
|
18483
|
+
<option value="yo" title="J-POP\u306E\u6A19\u6E96\u3002\u660E\u308B\u304F\u7D20\u76F4\u3067\u6B4C\u3044\u3084\u3059\u3044\u3002\u5F93\u6765\u306E\u9577\u8ABF\u3068\u540C\u3058">\u967D\u97F3\u968E\uFF08\u9577\u8ABF\u30DA\u30F3\u30BF\uFF09</option>
|
|
18484
|
+
<option value="minyo" title="\u308F\u3089\u3079\u6B4C\u30FB\u6C11\u8B21\u306E\u97F3\u968E\u3002\u7FF3\u308A\u304C\u3042\u308B\u304C\u6697\u3059\u304E\u306A\u3044\u3002\u5F93\u6765\u306E\u77ED\u8ABF\u3068\u540C\u3058">\u6C11\u8B21\u97F3\u968E\uFF08\u77ED\u8ABF\u30DA\u30F3\u30BF\uFF09</option>
|
|
18485
|
+
<option value="ryukyu" title="\u6C96\u7E04\u97F3\u968E\u3002\u30EC\u3068\u30E9\u3092\u629C\u304D\u3001\u30D5\u30A1\u3068\u30B7\u3092\u67F1\u306B\u3059\u308B\u3002\u660E\u308B\u304F\u8DF3\u306D\u308B">\u7409\u7403\u97F3\u968E\uFF08\u6C96\u7E04\uFF09</option>
|
|
18486
|
+
<option value="miyakobushi" title="\u300E\u3055\u304F\u3089\u3055\u304F\u3089\u300F\u306E\u97F3\u968E\u3002\u4E3B\u97F3\u306E\u3059\u3050\u4E0A\u304C\u534A\u97F3\u3067\u3001\u7FF3\u308A\u304C\u6FC3\u3044">\u90FD\u7BC0\u97F3\u968E\uFF08\u9670\u97F3\u968E\uFF09</option>
|
|
18487
|
+
<option value="ritsu" title="\u96C5\u697D\u30FB\u58F0\u660E\u306E\u97F3\u968E\u3002\u534A\u97F3\u3092\u542B\u307E\u305A\u3001\u5E73\u3089\u3067\u8358\u91CD\u306B\u6D41\u308C\u308B">\u5F8B\u97F3\u968E\uFF08\u96C5\u697D\uFF09</option>
|
|
18488
|
+
</optgroup>
|
|
18489
|
+
<optgroup label="\u30C1\u30E3\u30FC\u30C1\u30E2\u30FC\u30C9\uFF087\u97F3\u97F3\u968E\uFF09">
|
|
18490
|
+
<option value="dorian" title="\u77ED\u8ABF\u3060\u304C6\u5EA6\u304C\u660E\u308B\u3044\u3002\u30B1\u30EB\u30C8\u30FB\u30ED\u30C3\u30AF\u30FB\u30B7\u30C6\u30A3\u30DD\u30C3\u30D7">\u30C9\u30EA\u30A2\u30F3</option>
|
|
18491
|
+
<option value="phrygian" title="\u4E3B\u97F3\u306E\u4E0A\u304C\u534A\u97F3\u3002\u30B9\u30D1\u30CB\u30C3\u30B7\u30E5\uFF0F\u30E1\u30BF\u30EB\u306E\u7DCA\u8FEB\u3057\u305F\u97FF\u304D">\u30D5\u30EA\u30B8\u30A2\u30F3</option>
|
|
18492
|
+
<option value="lydian" title="4\u5EA6\u304C\u9AD8\u304F\u3001\u6D6E\u904A\u3057\u3066\u5E83\u304C\u308B\u3002\u6620\u753B\u97F3\u697D\u30FB\u30B2\u30FC\u30E0\u306E\u7A7A\u306E\u8272">\u30EA\u30C7\u30A3\u30A2\u30F3</option>
|
|
18493
|
+
<option value="mixolydian" title="\u9577\u8ABF\u3060\u304C7\u5EA6\u304C\u4F4E\u3044\u3002\u30D6\u30EB\u30FC\u30B9\u30ED\u30C3\u30AF\u30FB\u6C11\u65CF\u97F3\u697D\u306E\u571F\u304F\u3055\u3055">\u30DF\u30AF\u30BD\u30EA\u30C7\u30A3\u30A2\u30F3</option>
|
|
18494
|
+
</optgroup>
|
|
18495
|
+
<optgroup label="\u7279\u6B8A\u97F3\u968E\uFF08\u97F3\u7A0B\u96C6\u5408\u3054\u3068\u5165\u308C\u66FF\u308F\u308B\uFF09">
|
|
18496
|
+
<option value="harmonic_minor" title="\u5C0E\u97F3\u30BD\u266F\u3092\u6301\u3064\u77ED\u8ABF\u3002\u58972\u5EA6\u304C\u6CE3\u304D\u3092\u4F5C\u308B\u3002\u30AF\u30E9\u30B7\u30C3\u30AF\u30FBV\u7CFB\u30FB\u5287\u4F34">\u548C\u58F0\u7684\u77ED\u97F3\u968E</option>
|
|
18497
|
+
<option value="hijaz" title="\u4E3B\u97F3\u306E\u4E0A\u304C\u534A\u97F3\u3001\u4E3B\u548C\u97F3\u306F\u9577\u4E09\u548C\u97F3\u3002\u4E2D\u6771\u30FB\u30B9\u30D1\u30CB\u30C3\u30B7\u30E5\u30FB\u30E1\u30BF\u30EB">\u30D2\u30B8\u30E3\u30FC\u30BA\uFF08\u30D5\u30EA\u30B8\u30A2\u30F3\u30FB\u30C9\u30DF\u30CA\u30F3\u30C8\uFF09</option>
|
|
18498
|
+
<option value="hungarian" title="\u58972\u5EA6\u304C2\u304B\u6240\u3002\u97F3\u968E\u306E\u4E2D\u3067\u3044\u3061\u3070\u3093\u8DF3\u306D\u305F\u3001\u7570\u56FD\u3081\u3044\u305F\u97FF\u304D">\u30CF\u30F3\u30AC\u30EA\u30A2\u30F3\u30FB\u30DE\u30A4\u30CA\u30FC\uFF08\u30B8\u30D7\u30B7\u30FC\uFF09</option>
|
|
18499
|
+
<option value="blues" title="\u30D6\u30EB\u30FC\u30CE\u30FC\u30C8\u5165\u308A\u306E6\u97F3\u97F3\u968E\u3002\u77ED3\u5EA6\u3067\u6B4C\u3044\u3001\u4F34\u594F\u306F\u95773\u5EA6\u3067\u9CF4\u308B">\u30D6\u30EB\u30FC\u30B9\u97F3\u968E</option>
|
|
18500
|
+
</optgroup>
|
|
18501
|
+
</select>
|
|
18502
|
+
<span class="dtm-grow"></span>
|
|
18503
|
+
<span class="dtm-hint" data-dtm="compose-scale-hint"></span>
|
|
18504
|
+
</div>
|
|
17045
18505
|
</div>
|
|
17046
18506
|
<div class="dtm-row">
|
|
17047
18507
|
<span class="dtm-label">\u5168\u4F53\u30B7\u30D5\u30C8</span>
|
|
@@ -17244,6 +18704,8 @@ var buildUI = (target, options) => {
|
|
|
17244
18704
|
composeSectionsLen: sel("compose-sections-len"),
|
|
17245
18705
|
composeKey: sel("compose-key"),
|
|
17246
18706
|
composeKeyHint: sel("compose-key-hint"),
|
|
18707
|
+
composeScale: sel("compose-scale"),
|
|
18708
|
+
composeScaleHint: sel("compose-scale-hint"),
|
|
17247
18709
|
macroComposeVocal: sel("macro-compose-vocal"),
|
|
17248
18710
|
macroComposeInfo: sel("macro-compose-info"),
|
|
17249
18711
|
macroClear: sel("macro-clear"),
|
|
@@ -17278,115 +18740,12 @@ var buildUI = (target, options) => {
|
|
|
17278
18740
|
};
|
|
17279
18741
|
};
|
|
17280
18742
|
|
|
17281
|
-
// src/instrument-presets.ts
|
|
17282
|
-
var INSTRUMENT_PRESETS = {
|
|
17283
|
-
// --- STANDARD: 汎用性と完成度重視 ---
|
|
17284
|
-
piano: {
|
|
17285
|
-
displayName: "\u30B0\u30E9\u30F3\u30C9\u30D4\u30A2\u30CE",
|
|
17286
|
-
description: "\u6700\u3082\u7834\u7DBB\u3057\u306B\u304F\u3044\u69CB\u6210\u3002\u697D\u66F2\u5236\u4F5C\u306E\u30B9\u30B1\u30C3\u30C1\u306B\u3082\u6700\u9069\u3002",
|
|
17287
|
-
melody: "Acoustic Grand Piano",
|
|
17288
|
-
submelody: "Vibraphone",
|
|
17289
|
-
bass: "Electric Bass (finger)",
|
|
17290
|
-
chord: "Pad 2 (warm)"
|
|
17291
|
-
},
|
|
17292
|
-
acoustic: {
|
|
17293
|
-
displayName: "\u30A2\u30B3\u30FC\u30B9\u30C6\u30A3\u30C3\u30AF",
|
|
17294
|
-
description: "\u751F\u697D\u5668\u306E\u6E29\u304B\u307F\u3092\u91CD\u8996\u3002\u30D5\u30A9\u30FC\u30AF\u3084\u30DD\u30C3\u30D7\u30B9\u306B\u3002",
|
|
17295
|
-
melody: "Acoustic Guitar (steel)",
|
|
17296
|
-
submelody: "Harmonica",
|
|
17297
|
-
bass: "Acoustic Bass",
|
|
17298
|
-
chord: "Acoustic Guitar (nylon)"
|
|
17299
|
-
},
|
|
17300
|
-
jazz_night: {
|
|
17301
|
-
displayName: "\u30B8\u30E3\u30BA\u30FB\u30CA\u30A4\u30C8",
|
|
17302
|
-
description: "Rhodes\u98A8\u306EEP\u3068\u30A6\u30C3\u30C9\u30D9\u30FC\u30B9\u306B\u3088\u308B\u3001\u5927\u4EBA\u3073\u305F\u30A2\u30F3\u30B5\u30F3\u30D6\u30EB\u3002",
|
|
17303
|
-
melody: "Electric Piano 1",
|
|
17304
|
-
submelody: "Flute",
|
|
17305
|
-
bass: "Acoustic Bass",
|
|
17306
|
-
chord: "Electric Guitar (jazz)"
|
|
17307
|
-
},
|
|
17308
|
-
// --- MODERN & VIBE: エッジの効いた現代的な響き ---
|
|
17309
|
-
synth_pop: {
|
|
17310
|
-
displayName: "\u30B7\u30F3\u30BB\u30DD\u30C3\u30D7",
|
|
17311
|
-
description: "80s\u301C\u73FE\u4EE3\u307E\u3067\u3002\u629C\u3051\u308B\u30EA\u30FC\u30C9\u3068\u592A\u3044\u30D9\u30FC\u30B9\u306E\u738B\u9053\u3002",
|
|
17312
|
-
melody: "Lead 2 (sawtooth)",
|
|
17313
|
-
submelody: "Lead 4 (chiff)",
|
|
17314
|
-
bass: "Synth Bass 2",
|
|
17315
|
-
chord: "Pad 3 (polysynth)"
|
|
17316
|
-
},
|
|
17317
|
-
cyber_punk: {
|
|
17318
|
-
displayName: "\u30B5\u30A4\u30D0\u30FC\u30D1\u30F3\u30AF",
|
|
17319
|
-
description: "\u30C7\u30B8\u30BF\u30EB\u306A\u51B7\u305F\u3055\u3068\u6B6A\u307F\u304C\u6DF7\u3056\u308A\u5408\u3046\u3001\u672A\u6765\u7684\u306A\u97FF\u304D\u3002",
|
|
17320
|
-
melody: "Lead 8 (bass + lead)",
|
|
17321
|
-
submelody: "Lead 5 (charang)",
|
|
17322
|
-
bass: "Synth Bass 2",
|
|
17323
|
-
chord: "Pad 8 (sweep)"
|
|
17324
|
-
},
|
|
17325
|
-
rock: {
|
|
17326
|
-
displayName: "\u30CF\u30FC\u30C9\u30ED\u30C3\u30AF",
|
|
17327
|
-
description: "\u6B6A\u307F\u30AE\u30BF\u30FC\u3068\u91CD\u539A\u306A\u30D9\u30FC\u30B9\u3067\u3001\u30D1\u30EF\u30FC\u3092\u524D\u9762\u306B\u3002",
|
|
17328
|
-
melody: "Distortion Guitar",
|
|
17329
|
-
submelody: "Rock Organ",
|
|
17330
|
-
bass: "Electric Bass (pick)",
|
|
17331
|
-
chord: "Overdriven Guitar"
|
|
17332
|
-
},
|
|
17333
|
-
// --- WORLD & CLASSIC: 特定のジャンル・地域 ---
|
|
17334
|
-
orchestra: {
|
|
17335
|
-
displayName: "\u30AA\u30FC\u30B1\u30B9\u30C8\u30E9",
|
|
17336
|
-
description: "\u58EE\u5927\u306A\u7269\u8A9E\u3092\u4E88\u611F\u3055\u305B\u308B\u3001\u7BA1\u5F26\u697D\u5668\u306E\u91CD\u539A\u306A\u97FF\u304D\u3002",
|
|
17337
|
-
melody: "French Horn",
|
|
17338
|
-
submelody: "Pizzicato Strings",
|
|
17339
|
-
bass: "Cello",
|
|
17340
|
-
chord: "Tremolo Strings"
|
|
17341
|
-
},
|
|
17342
|
-
japanese_wa: {
|
|
17343
|
-
displayName: "\u548C\u98A8\u30FB\u96C5",
|
|
17344
|
-
description: "\u7434\u3068\u4E09\u5473\u7DDA\u306E\u7E4A\u7D30\u306A\u8ABF\u3079\u306B\u3001\u5C3A\u516B\u306E\u60C5\u7DD2\u3092\u6DFB\u3048\u3066\u3002",
|
|
17345
|
-
melody: "Koto",
|
|
17346
|
-
submelody: "Shamisen",
|
|
17347
|
-
bass: "Taiko Drum",
|
|
17348
|
-
chord: "Shakuhachi"
|
|
17349
|
-
},
|
|
17350
|
-
arabic_exotic: {
|
|
17351
|
-
displayName: "\u30A8\u30AD\u30BE\u30C1\u30C3\u30AF",
|
|
17352
|
-
description: "\u30B7\u30BF\u30FC\u30EB\u3084\u30D0\u30B0\u30D1\u30A4\u30D7\u306B\u3088\u308B\u3001\u7570\u56FD\u60C5\u7DD2\u6EA2\u308C\u308B\u30B5\u30A6\u30F3\u30C9\u3002",
|
|
17353
|
-
melody: "Sitar",
|
|
17354
|
-
submelody: "Bagpipe",
|
|
17355
|
-
bass: "Fretless Bass",
|
|
17356
|
-
chord: "Kalimba"
|
|
17357
|
-
},
|
|
17358
|
-
// --- FANTASY & ATMOSPHERE: 雰囲気と余韻 ---
|
|
17359
|
-
fantasy_rpg: {
|
|
17360
|
-
displayName: "\u30D5\u30A1\u30F3\u30BF\u30B8\u30FCRPG",
|
|
17361
|
-
description: "\u30AA\u30AB\u30EA\u30CA\u3068\u30CF\u30FC\u30D7\u304C\u7D21\u3050\u3001\u5192\u967A\u3068\u9B54\u6CD5\u306E\u4E16\u754C\u89B3\u3002",
|
|
17362
|
-
melody: "Ocarina",
|
|
17363
|
-
submelody: "Celesta",
|
|
17364
|
-
bass: "Timpani",
|
|
17365
|
-
chord: "Orchestral Harp"
|
|
17366
|
-
},
|
|
17367
|
-
ambient_cloud: {
|
|
17368
|
-
displayName: "\u30A2\u30F3\u30D3\u30A8\u30F3\u30C8",
|
|
17369
|
-
description: "\u8F2A\u90ED\u3092\u307C\u304B\u3057\u305F\u97F3\u8272\u3067\u3001\u6DF1\u3044\u6CA1\u5165\u611F\u3068\u4F59\u97FB\u3092\u6F14\u51FA\u3002",
|
|
17370
|
-
melody: "Lead 6 (voice)",
|
|
17371
|
-
submelody: "Music Box",
|
|
17372
|
-
bass: "Synth Bass 1",
|
|
17373
|
-
chord: "Pad 7 (halo)"
|
|
17374
|
-
},
|
|
17375
|
-
retro_game: {
|
|
17376
|
-
displayName: "8-bit \u30EC\u30C8\u30ED",
|
|
17377
|
-
description: "\u77E9\u5F62\u6CE2\u3092\u60F3\u8D77\u3055\u305B\u308B\u3001\u521D\u671F\u30B2\u30FC\u30E0\u6A5F\u306E\u3088\u3046\u306A\u61D0\u304B\u3057\u3044\u97FF\u304D\u3002",
|
|
17378
|
-
melody: "Lead 1 (square)",
|
|
17379
|
-
submelody: "Lead 2 (sawtooth)",
|
|
17380
|
-
bass: "Synth Bass 1",
|
|
17381
|
-
chord: "Clavinet"
|
|
17382
|
-
}
|
|
17383
|
-
};
|
|
17384
|
-
|
|
17385
18743
|
// src/macro-state.ts
|
|
17386
18744
|
var MACRO_STORAGE_KEYS = {
|
|
17387
18745
|
template: "dtm-macro:template",
|
|
17388
18746
|
sections: "dtm-macro:sections",
|
|
17389
18747
|
key: "dtm-macro:key",
|
|
18748
|
+
scale: "dtm-macro:scale",
|
|
17390
18749
|
shift: "dtm-macro:shift",
|
|
17391
18750
|
transpose: "dtm-macro:transpose"
|
|
17392
18751
|
};
|
|
@@ -19546,6 +20905,7 @@ var COMPOSE_INFO_HTML = `
|
|
|
19546
20905
|
<li><strong>\u30E1\u30ED\u30C7\u30A3\u306E\u66F8\u6CD5</strong>\u2014\u2014\u8D70\u53E5\u306E\u5F62\uFF08\u97F3\u968E\uFF0F\u6298\u308A\u8FD4\u3057\uFF0F\u5206\u6563\u548C\u97F3\uFF0F\u30B8\u30B0\u30B6\u30B0\uFF09\u3001\u3064\u306A\u304E\u306E\u5F62\uFF08\u5C71\u306A\u308A\uFF0F\u8C37\uFF0F\u4E0A\u884C\uFF0F\u4E0B\u884C\uFF0F\u3046\u306D\u308A\uFF0F\u8EF8\u97F3\u307E\u308F\u308A\uFF09\u3001\u7D42\u6B62\u306E\u5F62\uFF08\u9806\u6B21\u4E0B\u964D\uFF0F\u30BD\u30DF\u30C9\uFF0F\u8DF3\u306D\u4E0A\u304C\u308A\uFF0F\u30ED\u30F3\u30B0\u30C8\u30FC\u30F3\uFF09\u3001\u30E2\u30C1\u30FC\u30D5\u306E\u539F\u578B\u3001\u8DF3\u8E8D\u306E\u6DF7\u305C\u5177\u5408\u3001\u958B\u59CB\u97F3\u3001\u57FA\u6E96\u306E\u523B\u307F\uFF088\u5206\uFF0F16\u5206\uFF0F\u4E09\u9023\uFF09\u3001\u30B9\u30A6\u30A3\u30F3\u30B0\u91CF</li>
|
|
19547
20906
|
<li><strong>\u30D9\u30FC\u30B9\u306E\u594F\u6CD5</strong>\uFF084\u5206\u6253\u3061\uFF0F\u30AA\u30EB\u30BF\u30CD\u30A4\u30C8\uFF0F2\u5206\uFF0F8\u5206\u30C9\u30E9\u30A4\u30D6\uFF0F\u30B7\u30F3\u30B3\u30DA\uFF0F\u30A6\u30A9\u30FC\u30AD\u30F3\u30B0\uFF0F\u30AA\u30AF\u30BF\u30FC\u30D6\uFF09</li>
|
|
19548
20907
|
<li><strong>\u30B5\u30D6\u30E1\u30ED\u306E\u66F8\u304D\u65B9</strong>\u2014\u2014\u5408\u3044\u306E\u624B\uFF08\u30E1\u30ED\u30C7\u30A3\u304C\u4F11\u3093\u3060\u9699\u9593\u306B\u3060\u3051\u5165\u308B\uFF09\u3001\u30CF\u30E2\u30EA\uFF08\u30E1\u30ED\u30C7\u30A3\u306E\u30EA\u30BA\u30E0\u3092\u306A\u305E\u3063\u30663\u5EA6\u30FB6\u5EA6\u4E0B\u3092\u6B4C\u3046\uFF09\u3001\u5BFE\u65CB\u5F8B\uFF088\u5206\u3067\u30E1\u30ED\u30C7\u30A3\u3068\u53CD\u884C\u3059\u308B\uFF09\u3001\u4FDD\u7D9A\u97F3\uFF08\u540C\u3058\u97F3\u3092\u4F38\u3070\u3057\u7D9A\u3051\u308B\uFF09\u3001\u30D1\u30C3\u30C9\u3002\u5C0F\u7BC0\u3054\u3068\u306B\u3001\u30E1\u30ED\u30C7\u30A3\u304C\u606F\u7D99\u304E\u3057\u3066\u3044\u308B\u5834\u6240\u3067\u306F\u81EA\u52D5\u3067\u5408\u3044\u306E\u624B\u306B\u5207\u308A\u66FF\u308F\u308A\u307E\u3059\u3002</li>
|
|
20908
|
+
<li><strong>\u7DE8\u66F2\u30D7\u30E9\u30F3</strong>\uFF08\u4E0A\u7D1A\u8005\u30E2\u30FC\u30C9\u306E\u307F\uFF09\u2014\u2014\u4F34\u594F\u3092\u4F55\u5C64\u306B\u3059\u308B\u304B\u3001\u305D\u308C\u305E\u308C\u3069\u306E\u594F\u6CD5\u3067\u3069\u306E\u30BB\u30AF\u30B7\u30E7\u30F3\u3092\u9CF4\u3089\u3059\u304B\u3001\u30B5\u30D3\u306E\u91CD\u306D\u3092\u51FA\u3059\u304B\u30FB\u30E6\u30CB\u30BE\u30F3\u304B\u30AA\u30AF\u30BF\u30FC\u30D6\u4E0A\u304B\u3001\u88C5\u98FE\u3092\u3069\u3053\u306B\u7F6E\u304F\u304B\u3002400\u66F2\u5F15\u304F\u3068392\u901A\u308A\u306E\u578B\u304C\u51FA\u307E\u3059\u3002</li>
|
|
19549
20909
|
</ul>
|
|
19550
20910
|
<p>\u3055\u3089\u306B\u3001\u76F4\u524D\u306B\u4F5C\u3063\u305F5\u66F2\u3068\u7279\u5FB4\u304C\u4F3C\u3066\u3044\u308B\u5019\u88DC\u306B\u306F\u6E1B\u70B9\u3057\u3066\u3044\u307E\u3059\u3002\u7D9A\u3051\u3066\u62BC\u3057\u305F\u3068\u304D\u306B\u4F3C\u305F\u66F2\u304C\u4E26\u3070\u306A\u3044\u3088\u3046\u306B\u3059\u308B\u305F\u3081\u3067\u3059\u3002</p>
|
|
19551
20911
|
<h4>\u3067\u304D\u3042\u304C\u308A\u306E\u9078\u3073\u65B9</h4>
|
|
@@ -19564,6 +20924,18 @@ var COMPOSE_INFO_HTML = `
|
|
|
19564
20924
|
<li><strong>\u639B\u3051\u5408\u3044\uFF08\u30C7\u30E5\u30A8\u30C3\u30C8\uFF09</strong> \u2014 4\u5272\u307B\u3069\u306E\u66F2\u304C2\u4EBA\u6B4C\u3044\u306B\u306A\u308A\u307E\u3059\u3002\u30BB\u30AF\u30B7\u30E7\u30F3\u3054\u3068\uFF0FA\u30E1\u30ED\u30672\u5C0F\u7BC0\u3054\u3068\uFF0F\u639B\u3051\u5408\u3044\u30B5\u30D3\uFF0FA\u30E1\u30ED\u3060\u3051\u3001\u306E4\u901A\u308A\u3002<strong>\u53D7\u3051\u6E21\u3057\u306F\u5C0F\u7BC0\u7DDA\u3074\u3063\u305F\u308A\u3067\u306F\u306A\u304F\u3001\u6B21\u306E\u4EBA\u304C\u624B\u524D\u304B\u3089\u98DF\u3044\u6C17\u5473\u306B\u5165\u308A\u307E\u3059\u3002</strong>\u4E00\u7DD2\u306B\u6B4C\u3046\u30B5\u30D3\u3067\u306F\u76F8\u65B9\u304C\u30CF\u30E2\u30EA\u3078\u56DE\u308A\u307E\u3059\uFF08\u540C\u3058\u97F3\u3092\u306A\u305E\u308B\u30E6\u30CB\u30BE\u30F3\u306B\u306F\u3057\u307E\u305B\u3093\uFF09\u3002</li>
|
|
19565
20925
|
</ul>
|
|
19566
20926
|
<p>\u30B7\u30F3\u30D7\u30EB\u30E2\u30FC\u30C9\uFF084\u30C8\u30E9\u30C3\u30AF\uFF09\u306F\u72EC\u5531\u3067\u3059\u30024\u672C\u304C\u57CB\u307E\u3063\u3066\u3044\u3066\u30CF\u30E2\u30EA\u306E\u7F6E\u304D\u5834\u6240\u304C\u7121\u3044\u305F\u3081\u3067\u3059\u3002</p>
|
|
20927
|
+
<h4>\u30BB\u30AF\u30B7\u30E7\u30F3\u3067\u697D\u5668\u30FB\u4F34\u594F\u304C\u5909\u308F\u308B\uFF08\u4E0A\u7D1A\u8005\u30E2\u30FC\u30C9\u306E\u307F\uFF09</h4>
|
|
20928
|
+
<p>1\u672C\u306E\u30C8\u30E9\u30C3\u30AF\u306F\u3001\u66F2\u306E\u6700\u521D\u304B\u3089\u6700\u5F8C\u307E\u30671\u3064\u306E\u697D\u5668\u3067\u9CF4\u308A\u307E\u3059\u3002\u3064\u307E\u308A<strong>\u300C\u30B5\u30D3\u3060\u3051\u5225\u306E\u697D\u5668\u306B\u3059\u308B\u300D\u306F\u30011\u672C\u306E\u30C8\u30E9\u30C3\u30AF\u306E\u4E2D\u3067\u306F\u4F5C\u308C\u307E\u305B\u3093</strong>\u3002\u4F5C\u308C\u308B\u306E\u306F\u3001\u9CF4\u3089\u3057\u305F\u3044\u533A\u9593\u3092\u5225\u306E\u30C8\u30E9\u30C3\u30AF\u3078\u66F8\u304D\u5206\u3051\u305F\u3068\u304D\u3060\u3051\u3067\u3059\u3002\u4E0A\u7D1A\u8005\u30E2\u30FC\u30C9\uFF0815\u30C8\u30E9\u30C3\u30AF\uFF09\u304C15\u672C\u3042\u308B\u306E\u306F\u305D\u306E\u305F\u3081\u3067\u3001\u300C\u4F5C\u66F2\u300D\u306F\u5834\u6240\u3054\u3068\u306B\u30C8\u30E9\u30C3\u30AF\u3092\u5206\u3051\u307E\u3059\u3002</p>
|
|
20929
|
+
<ul>
|
|
20930
|
+
<li><strong>\u4F34\u594F\u306E\u624B\u89E6\u308A\u304C\u30BB\u30AF\u30B7\u30E7\u30F3\u3067\u5909\u308F\u308B</strong> \u2014 \u540C\u3058\u30B3\u30FC\u30C9\u9032\u884C\u3092\u3001\u30D6\u30ED\u30C3\u30AF\u30FB\u30A2\u30EB\u30DA\u30B8\u30AA\u30FB\u88CF\u62CD\u30FB\u516B\u5206\u98DF\u3044\u30FB\u5206\u6563\u306E\u4E2D\u304B\u3089<strong>\u5225\u3005\u306E\u594F\u6CD5</strong>\u30671\u301C3\u5C64\u306B\u91CD\u306D\u307E\u3059\u3002\u3069\u306E\u594F\u6CD5\u3092\u3069\u306E\u30BB\u30AF\u30B7\u30E7\u30F3\u3067\u9CF4\u3089\u3059\u304B\u306F\u66F2\u3054\u3068\u306B\u5F15\u304F\u306E\u3067\u3001A\u30E1\u30ED\u3068\u30B5\u30D3\u3067\u4F34\u594F\u306E\u523B\u307F\u65B9\u305D\u306E\u3082\u306E\u304C\u5909\u308F\u308A\u307E\u3059\u3002\u66F2\u5168\u4F53\u3092\u901A\u308B\u300C\u5730\u300D\u306E\u5C64\u304C1\u3064\u3042\u308A\u3001\u6B8B\u308A\u306F\u8DB3\u3059\u5834\u6240\u3092\u7D5E\u308A\u307E\u3059\u3002</li>
|
|
20931
|
+
<li><strong>\u30B5\u30D3\u306E\u91CD\u306D</strong> \u2014 \u4E3B\u65CB\u5F8B\u3092\u3082\u30461\u672C\u306E\u5225\u697D\u5668\uFF08\u30D7\u30EA\u30BB\u30C3\u30C8\u306B\u3088\u3063\u3066\u30D6\u30E9\u30B9\u30FB\u30B9\u30C8\u30EA\u30F3\u30B0\u30B9\u30FB\u30B0\u30ED\u30C3\u30B1\u30F3\u306A\u3069\uFF09\u3067\u91CD\u306D\u307E\u3059\u3002<strong>\u30AA\u30AF\u30BF\u30FC\u30D6\u4E0A\u3068\u30E6\u30CB\u30BE\u30F3\u306E\u4E21\u65B9\u3092\u5F15\u304D\u307E\u3059</strong>\u2014\u2014\u540C\u3058\u9AD8\u3055\u3092\u5225\u306E\u697D\u5668\u3067\u91CD\u306D\u308B\u30682\u3064\u306E\u97F3\u8272\u304C\u6EB6\u3051\u3066\u5225\u306E\u97F3\u8272\u306B\u306A\u308B\u306E\u3067\u3001\u30AA\u30AF\u30BF\u30FC\u30D6\u4E0A\u3052\u308B\u3088\u308A\u60C5\u5831\u91CF\u304C\u591A\u3044\u3053\u3068\u304C\u3042\u308A\u307E\u3059\u3002\u91CD\u306D\u306A\u3044\u66F2\u3082\u3042\u308A\u307E\u3059\u3002</li>
|
|
20932
|
+
<li><strong>\u9593\u594F\u306E\u30BD\u30ED</strong> \u2014 \u9593\u594F\u306F\u6B4C\u304C\u4F11\u3080\u5834\u6240\u3067\u3042\u3063\u3066\u3001\u97F3\u697D\u304C\u4F11\u3080\u5834\u6240\u3067\u306F\u3042\u308A\u307E\u305B\u3093\u3002\u6B4C\u30E1\u30ED\u306E\u4EE3\u308F\u308A\u306B\u5668\u697D\u306E\u30BD\u30ED\u3092\u66F8\u304D\u3001\u5C02\u7528\u306E\u30C8\u30E9\u30C3\u30AF\u3067\u9CF4\u3089\u3057\u307E\u3059\u3002\u30D7\u30EA\u30BB\u30C3\u30C8\u306B\u3088\u3063\u3066\u6B6A\u307F\u30AE\u30BF\u30FC\u30FB\u30B5\u30C3\u30AF\u30B9\u30FB\u5C3A\u516B\u306A\u3069\u306B\u5909\u308F\u308A\u307E\u3059\u3002\u7D20\u6750\u306F\u30B5\u30D3\u3068\u540C\u3058\u306A\u306E\u3067\u3001\u9593\u594F\u304C\u30B5\u30D3\u306E\u4E3B\u984C\u3092\u5F3E\u304F\u5F62\u306B\u306A\u308A\u307E\u3059\u3002</li>
|
|
20933
|
+
<li><strong>\u30A6\u30EF\u30E2\u30CE</strong> \u2014 \u304D\u3089\u3073\u3084\u304B\u306A\u88C5\u98FE\u3092\u3001\u76DB\u308A\u4E0A\u304C\u308B\u30BB\u30AF\u30B7\u30E7\u30F3\u306B\u3060\u3051\u30AA\u30AF\u30BF\u30FC\u30D6\u4E0A\u3067\u8DB3\u3057\u307E\u3059\u3002<strong>\u5730\u306E\u4F34\u594F\u3068\u540C\u3058\u594F\u6CD5\u306F\u4F7F\u3044\u307E\u305B\u3093</strong>\u2014\u2014\u540C\u3058\u3082\u306E\u3092\u30AA\u30AF\u30BF\u30FC\u30D6\u4E0A\u3052\u305F\u3060\u3051\u306E\u5C64\u306F\u88C5\u98FE\u3067\u306F\u306A\u304F\u5199\u3057\u3060\u304B\u3089\u3067\u3059\u3002\u30D6\u30ED\u30C3\u30AF\u3082\u5916\u3057\u307E\u3059\uFF08\u548C\u97F3\u3092\u4E38\u3054\u3068\u30AA\u30AF\u30BF\u30FC\u30D6\u4E0A\u3067\u9CF4\u3089\u3059\u306E\u306F\u88C5\u98FE\u3067\u306F\u306A\u304F\u58C1\u306B\u306A\u308A\u307E\u3059\uFF09\u3002</li>
|
|
20934
|
+
</ul>
|
|
20935
|
+
<p><strong>\u697D\u5668\u306E\u97F3\u57DF\u306B\u5408\u308F\u305B\u3066\u30AA\u30AF\u30BF\u30FC\u30D6\u3092\u4E0B\u3052\u307E\u3059\u3002</strong>1\u30C8\u30E9\u30C3\u30AF1\u697D\u5668\u3067\u3001\u3057\u304B\u3082\u5C64\u3054\u3068\u306B\u30AA\u30AF\u30BF\u30FC\u30D6\u3092\u5909\u3048\u308B\u306E\u3067\u3001\u6C7A\u3081\u305F\u30AA\u30AF\u30BF\u30FC\u30D6\u304C\u305D\u306E\u697D\u5668\u306E\u51FA\u305B\u306A\u3044\u9AD8\u3055\u306B\u306A\u308B\u3053\u3068\u304C\u3042\u308A\u307E\u3059\u3002\u5B9F\u6E2C\u3059\u308B\u3068\u3001\u30B5\u30D3\u306E\u91CD\u306D\u30921\u30AA\u30AF\u30BF\u30FC\u30D6\u4E0A\u3052\u308B\u6307\u5B9A\u306F\u30DF\u30E5\u30FC\u30C8\u30C8\u30E9\u30F3\u30DA\u30C3\u30C8\u3084\u30C8\u30E9\u30F3\u30DA\u30C3\u30C8\u306714\u534A\u97F3\u3076\u3093\u3001\u30B3\u30FC\u30C9\u30D1\u30C3\u30C9\uFF08\u5B9F\u97F377\u301C93\uFF09\u306F\u30CA\u30A4\u30ED\u30F3\u30AE\u30BF\u30FC\u306710\u534A\u97F3\u30FB\u30AB\u30EA\u30F3\u30D0\u30679\u534A\u97F3\u3076\u3093\u97F3\u57DF\u3092\u7A81\u304D\u629C\u3051\u3066\u3044\u307E\u3057\u305F\u3002\u30B5\u30F3\u30D7\u30EB\u304C\u5F15\u304D\u4F38\u3070\u3055\u308C\u3066<strong>\u91D1\u5207\u308A\u97F3</strong>\u306B\u306A\u308A\u3001\u8074\u304D\u624B\u306B\u306F\u300C\u8033\u304C\u75DB\u3044\u300D\u3068\u3057\u304B\u611F\u3058\u3089\u308C\u307E\u305B\u3093\u3002\u305D\u3053\u3067\u3001\u9CF4\u3089\u3059\u97F3\u57DF\u304C\u305D\u306E\u697D\u5668\u306E\u5B9F\u7528\u4E0A\u9650\u306B\u53CE\u307E\u308B\u3068\u3053\u308D\u307E\u3067<strong>\u30AA\u30AF\u30BF\u30FC\u30D6\u3092\u4E0B\u3052\u3066\u304B\u3089</strong>\u7F6E\u304D\u307E\u3059\uFF08\u30C8\u30E9\u30C3\u30AF\u306E\u30AA\u30AF\u30BF\u30FC\u30D6\u8A2D\u5B9A\u306F\u3001\u307E\u3055\u306B\u3053\u3046\u3044\u3046\u300C\u5F97\u610F\u306A\u97F3\u57DF\u304C\u504F\u3063\u305F\u97F3\u6E90\u300D\u3092\u4F7F\u3048\u308B\u3088\u3046\u306B\u3059\u308B\u305F\u3081\u306B\u5728\u308B\u3082\u306E\u3067\u3059\uFF09\u3002<strong>\u4E0B\u3052\u308B\u65B9\u5411\u306B\u3057\u304B\u52D5\u304B\u3057\u307E\u305B\u3093</strong>\u2014\u2014\u4E0A\u3052\u308B\u5074\u304C\u75DB\u307F\u3092\u4F5C\u308B\u5074\u306A\u306E\u3067\u3002</p>
|
|
20936
|
+
<p>\u5B9F\u7269\u306E\u97F3\u57DF\u306B\u53CE\u307E\u3063\u3066\u3044\u3066\u3082\u75DB\u304F\u306A\u308B\u97F3\u8272\u304C\u3042\u308A\u307E\u3059\u3002\u30B0\u30ED\u30C3\u30B1\u30F3\u306F\u5B9F\u7269\u306E\u97F3\u57DF\u304CG5\u301CC8\u306A\u306E\u3067\u3001\u65CB\u5F8B\u306E\u97F3\u57DF\uFF08\u301CC6\uFF09\u306F\u300C\u4F59\u88D5\u3067\u7BC4\u56F2\u5185\u300D\u3067\u3059\u304C\u3001\u91D1\u5C5E\u4F53\u306E\u500D\u97F3\u306F\u4EBA\u306E\u8033\u304C\u3044\u3061\u3070\u3093\u654F\u611F\u306A2\u301C4kHz\u306B\u96C6\u307E\u308B\u305F\u3081\u3001\u305D\u306E\u9AD8\u3055\u3067\u9CF4\u3089\u3057\u7D9A\u3051\u308B\u3068\u523A\u3055\u308A\u307E\u3059\u3002\u3053\u3046\u3044\u3046\u97F3\u8272\u306B\u306F\u97F3\u57DF\u3068\u306F\u5225\u306B<strong>\u660E\u308B\u3055\u306E\u4E0A\u9650</strong>\u3092\u6301\u305F\u305B\u3066\u3042\u308A\u3001\u30B0\u30ED\u30C3\u30B1\u30F3\u306A\u3089C5\u3088\u308A\u4E0A\u3067\u9CF4\u3089\u306A\u3044\u3068\u3053\u308D\u307E\u3067\u4E0B\u3052\u307E\u3059\u3002<strong>\u5019\u88DC\u304B\u3089\u5916\u3059\u306E\u3067\u306F\u306A\u304F\u7F6E\u304D\u5834\u6240\u3092\u5909\u3048\u307E\u3059</strong>\u2014\u2014\u5916\u3059\u3068\u97F3\u8272\u306E\u5E45\u304C\u305D\u306E\u3076\u3093\u6E1B\u308B\u3060\u3051\u3067\u3001\u4F4E\u304F\u9CF4\u3089\u3057\u305F\u30B0\u30ED\u30C3\u30B1\u30F3\u306F\u30DD\u30C3\u30D7\u30B9\u3067\u666E\u901A\u306B\u4F7F\u308F\u308C\u308B\u67D4\u3089\u304B\u3044\u97F3\u3067\u3059\u3002</p>
|
|
20937
|
+
<p><strong>\u30AA\u30AF\u30BF\u30FC\u30D6\u306E\u91CD\u306D\u3092\u4E3B\u5F79\u306B\u3057\u3066\u3044\u307E\u305B\u3093\u3002</strong>\u300C\u65E2\u306B\u3042\u308B\u30C8\u30E9\u30C3\u30AF\u30921\u30AA\u30AF\u30BF\u30FC\u30D6\u52D5\u304B\u3057\u3066\u5225\u30C8\u30E9\u30C3\u30AF\u3078\u5199\u3059\u300D\u5C64\u306F\u3001\u97F3\u697D\u7684\u306A\u4FA1\u5024\u304C\u9AD8\u304F\u3042\u308A\u307E\u305B\u3093\u3002\u4EBA\u306E\u8033\u306F\u30AA\u30AF\u30BF\u30FC\u30D6\u9055\u3044\u3092<strong>\u540C\u3058\u97F3</strong>\u3068\u3057\u3066\u805E\u304F\u306E\u3067\uFF08\u30AA\u30AF\u30BF\u30FC\u30D6\u7B49\u4FA1\uFF09\u3001\u5199\u3057\u305F\u5C64\u306F\u65B0\u3057\u3044\u58F0\u90E8\u306B\u306A\u3089\u305A\u3001\u97F3\u91CF\u3068\u97F3\u8272\u304C\u308F\u305A\u304B\u306B\u5909\u308F\u308B\u3060\u3051\u3067\u3059\u3002\u5F37\u8ABF\u3068\u3057\u3066\u306E\u610F\u5473\u306F\u3042\u308B\u306E\u3067\u4F7F\u3044\u306F\u3057\u307E\u3059\u304C\u3001\u5E38\u8A2D\u306B\u306F\u3057\u307E\u305B\u3093\u3002\u30D9\u30FC\u30B9\u306E\u30AA\u30AF\u30BF\u30FC\u30D6\u4E0B\u306E\u91CD\u306D\u306F\u7279\u306B\u300130Hz\u524D\u5F8C\u307E\u3067\u843D\u3061\u3066\u8F2A\u90ED\u304C\u6FC1\u308B\u306E\u3067\u65E2\u5B9A\u3067\u306F\u51FA\u3057\u307E\u305B\u3093\uFF08\u51FA\u3059\u3068\u304D\u3082\u4E0A\u306E\u30AA\u30AF\u30BF\u30FC\u30D6\u3078\u3001\u76DB\u308A\u4E0A\u304C\u308B\u5834\u6240\u3060\u3051\u306B\u7F6E\u304D\u307E\u3059\uFF09\u3002</p>
|
|
20938
|
+
<p>\u300C\u4F5C\u66F2\u300D\u304C\u6C7A\u3081\u305F\u3053\u308C\u3089\u306E\u697D\u5668\u306F\u3001\u304A\u307E\u304B\u305B\u30DE\u30B9\u30BF\u30EA\u30F3\u30B0\u306E\u5F79\u5272\u63A8\u5B9A\u3088\u308A\u512A\u5148\u3055\u308C\u307E\u3059\uFF08\u6F14\u594F\u5185\u5BB9\u3060\u3051\u3092\u898B\u308B\u3068\u3001\u9593\u594F\u306E\u30BD\u30ED\u3082\u30B5\u30D3\u306E\u91CD\u306D\u3082\u300C\u97F3\u306E\u5C11\u306A\u3044\u5358\u65CB\u5F8B\u300D\u3067\u3001\u4E3B\u65CB\u5F8B\u3068\u533A\u5225\u304C\u4ED8\u304B\u306A\u3044\u305F\u3081\u3067\u3059\uFF09\u3002\u697D\u5668\u3092\u624B\u3067\u9078\u3073\u76F4\u3057\u305F\u30C8\u30E9\u30C3\u30AF\u306F\u3001\u4EE5\u5F8C\u3069\u3061\u3089\u306B\u3082\u4E0A\u66F8\u304D\u3055\u308C\u307E\u305B\u3093\u3002</p>
|
|
19567
20939
|
<h4>\u305D\u306E\u307B\u304B</h4>
|
|
19568
20940
|
<ul>
|
|
19569
20941
|
<li><strong>\u66F2\u306E\u9014\u4E2D\u3067\u8EE2\u8ABF\u3057\u307E\u3059</strong>\uFF08\u304A\u3088\u305D\u534A\u5206\u306E\u66F2\uFF09\u3002\u4E94\u5EA6\u570F\u3067\u8FD1\u3044\u5C5E\u8ABF\u30FB\u4E0B\u5C5E\u8ABF\u3078\u306F\u5171\u901A\u3059\u308B\u548C\u97F3\uFF08\u30D4\u30DC\u30C3\u30C8\u30B3\u30FC\u30C9\uFF09\u304B\u65B0\u3057\u3044\u8ABF\u306E\u30C9\u30DF\u30CA\u30F3\u30C8\u3067\u6A4B\u6E21\u3057\u3057\u3001\u30E9\u30B9\u30B5\u30D3\u306E\u534A\u97F3\u4E0A\u3052\u306F\u6E96\u5099\u306A\u3057\u306E\u76F4\u63A5\u8EE2\u8ABF\u306B\u3057\u307E\u3059\u3002\u8ABF\u53F7\u3092\u5909\u3048\u305A\u306B\u660E\u6697\u3060\u3051\u5165\u308C\u66FF\u3048\u308B<strong>\u5E73\u884C\u8ABF</strong>\uFF08\u30CF\u9577\u8ABF\u2194\u30A4\u77ED\u8ABF\uFF09\u3068\u3001\u4E3B\u97F3\u3092\u4FDD\u3063\u305F\u307E\u307E\u6697\u304F\u3059\u308B<strong>\u540C\u4E3B\u8ABF</strong>\uFF08\u30CF\u9577\u8ABF\u2192\u30CF\u77ED\u8ABF\uFF09\u3082\u5F15\u304D\u307E\u3059\u30021\u5272\u5F37\u306E\u66F2\u306F\u4E3B\u548C\u97F3\u3092\u907F\u3051\u3066\u300C\u660E\u308B\u3044\u306E\u304B\u6697\u3044\u306E\u304B\u5206\u304B\u3089\u306A\u3044\u300D\u6D6E\u904A\u611F\u3067\u901A\u3057\u307E\u3059\u3002</li>
|
|
@@ -19830,26 +21202,6 @@ var pickComposeVocal = (exclude) => {
|
|
|
19830
21202
|
const list = pool.length > 0 ? pool : COMPOSE_VOCAL_POOL;
|
|
19831
21203
|
return list[Math.floor(Math.random() * list.length)] ?? "klatt";
|
|
19832
21204
|
};
|
|
19833
|
-
var ADVANCED_COMPOSE_LAYOUT = [
|
|
19834
|
-
{ index: 0, part: "melody", octave: 0, volume: 104 },
|
|
19835
|
-
{ index: 1, part: "melody", octave: 1, volume: 62 },
|
|
19836
|
-
{ index: 2, part: "harmony", octave: 0, volume: 82 },
|
|
19837
|
-
{ index: 3, part: "submelody", octave: 0, volume: 86 },
|
|
19838
|
-
{ index: 4, part: "bass", octave: 0, volume: 92 },
|
|
19839
|
-
{ index: 5, part: "bass", octave: -1, volume: 58 },
|
|
19840
|
-
{ index: 6, part: "pad", octave: 0, volume: 64 },
|
|
19841
|
-
{ index: 7, part: "block", octave: 0, volume: 62 },
|
|
19842
|
-
{ index: 8, part: "arpeggio", octave: 0, volume: 54 },
|
|
19843
|
-
{ index: 9, part: "offbeat", octave: 0, volume: 50 },
|
|
19844
|
-
{ index: 10, part: "uwamono", octave: 1, volume: 56 },
|
|
19845
|
-
// 掛け合い(デュエット)の相手。**歌入り作曲のときだけ**中身が入る。
|
|
19846
|
-
// 作曲だけならメロディは t0 が全部持つので、ここは空のまま。
|
|
19847
|
-
{ index: 11, part: "duet", octave: 0, volume: 104 },
|
|
19848
|
-
// 2声目のハモリ(主旋律を上下から挟む3声)と、主旋律のオクターブ下の重ね。
|
|
19849
|
-
// どちらも曲ごとに出るかどうかが決まる(`song.vocal`)。
|
|
19850
|
-
{ index: 12, part: "harmony2", octave: 0, volume: 74 },
|
|
19851
|
-
{ index: 13, part: "melody", octave: -1, volume: 56 }
|
|
19852
|
-
];
|
|
19853
21205
|
var LYRIC_MODEL_CATEGORIES = [
|
|
19854
21206
|
{
|
|
19855
21207
|
label: "kusa\u30D7\u30EA\u30BB\u30C3\u30C8",
|
|
@@ -20005,7 +21357,7 @@ var mountDAW = (target, options = {}) => {
|
|
|
20005
21357
|
showChord,
|
|
20006
21358
|
showMidiSearch,
|
|
20007
21359
|
// 「作曲」は simple では役割固定の4トラックへ、advanced では15トラックへ
|
|
20008
|
-
// 編曲を展開する({@link
|
|
21360
|
+
// 編曲を展開する({@link buildAdvancedLayers})。どちらでも出す。
|
|
20009
21361
|
showCompose: true
|
|
20010
21362
|
});
|
|
20011
21363
|
refs.masterVolume.value = String(options.masterVolume ?? 50);
|
|
@@ -20199,6 +21551,14 @@ var mountDAW = (target, options = {}) => {
|
|
|
20199
21551
|
while (customVocalsMap.has(`custom${n}`)) n++;
|
|
20200
21552
|
return `custom${n}`;
|
|
20201
21553
|
};
|
|
21554
|
+
const getVocalIconSrc = (lyricModel) => {
|
|
21555
|
+
if (!lyricModel) return void 0;
|
|
21556
|
+
const customDef = customVocalsMap.get(lyricModel);
|
|
21557
|
+
if (customDef !== void 0)
|
|
21558
|
+
return customDef.iconUrl || FALLBACK_VOCAL_ICON;
|
|
21559
|
+
const imgKey = VOICE_IMAGE_KEY[lyricModel.toLowerCase()];
|
|
21560
|
+
return imgKey ? VOICE_IMAGES[imgKey] : void 0;
|
|
21561
|
+
};
|
|
20202
21562
|
let selectedNotes = [];
|
|
20203
21563
|
let selectionRect = null;
|
|
20204
21564
|
let copiedNotes = [];
|
|
@@ -20332,6 +21692,7 @@ var mountDAW = (target, options = {}) => {
|
|
|
20332
21692
|
vocalTension: t1?.vocalTension ?? 50,
|
|
20333
21693
|
vocalOctaveUnison: t1?.vocalOctaveUnison ?? "none",
|
|
20334
21694
|
trackInstrument: t1?.trackInstrument ?? "",
|
|
21695
|
+
composeSlot: null,
|
|
20335
21696
|
trackCompression: t1?.trackCompression ?? 0,
|
|
20336
21697
|
trackWidth: t1?.trackWidth ?? 100,
|
|
20337
21698
|
trackReverbSend: t1?.trackReverbSend ?? 0,
|
|
@@ -21383,25 +22744,38 @@ var mountDAW = (target, options = {}) => {
|
|
|
21383
22744
|
refs.undoBtn.disabled = !core.canUndo();
|
|
21384
22745
|
refs.redoBtn.disabled = !core.canRedo();
|
|
21385
22746
|
};
|
|
21386
|
-
const
|
|
22747
|
+
const updateTrackTabs = () => {
|
|
21387
22748
|
refs.trackTabs.innerHTML = "";
|
|
21388
22749
|
trackPillEls.clear();
|
|
21389
22750
|
for (const [i2, t] of trackStates.entries()) {
|
|
21390
22751
|
const [r, g, b] = t.config.color;
|
|
21391
22752
|
const isActive = t.config.id === activeTrackId;
|
|
21392
22753
|
const btn = document.createElement("button");
|
|
21393
|
-
|
|
22754
|
+
const vocalIconSrc = getVocalIconSrc(t.lyricModel);
|
|
22755
|
+
btn.className = `dtm-pill ${isActive ? "dtm-pill--active" : ""} ${vocalIconSrc ? "dtm-pill--vocal" : ""}`;
|
|
21394
22756
|
btn.style.setProperty("--dtm-pill-color", `rgb(${r},${g},${b})`);
|
|
22757
|
+
if (vocalIconSrc) {
|
|
22758
|
+
btn.style.setProperty(
|
|
22759
|
+
"--dtm-pill-icon",
|
|
22760
|
+
`url(${JSON.stringify(vocalIconSrc)})`
|
|
22761
|
+
);
|
|
22762
|
+
}
|
|
21395
22763
|
btn.title = `Track ${i2 + 1}: ${t.config.name}`;
|
|
21396
22764
|
btn.setAttribute(
|
|
21397
22765
|
"aria-label",
|
|
21398
|
-
`Track ${i2 + 1}: ${t.config.name}${isActive ? " (\u9078\u629E\u4E2D)" : ""}`
|
|
22766
|
+
`Track ${i2 + 1}: ${t.config.name}${isActive ? " (\u9078\u629E\u4E2D)" : ""}${vocalIconSrc ? "\uFF08\u30DC\u30FC\u30AB\u30EB\u9078\u629E\u4E2D\uFF09" : ""}`
|
|
21399
22767
|
);
|
|
21400
|
-
|
|
22768
|
+
const labelEl = document.createElement("span");
|
|
22769
|
+
labelEl.className = "dtm-pill__label";
|
|
22770
|
+
labelEl.textContent = String(i2 + 1);
|
|
22771
|
+
btn.appendChild(labelEl);
|
|
21401
22772
|
btn.addEventListener("click", () => switchTrack(t.config.id));
|
|
21402
22773
|
refs.trackTabs.appendChild(btn);
|
|
21403
22774
|
trackPillEls.set(t.config.id, btn);
|
|
21404
22775
|
}
|
|
22776
|
+
};
|
|
22777
|
+
const updateTrackPanel = () => {
|
|
22778
|
+
updateTrackTabs();
|
|
21405
22779
|
const active = getActive();
|
|
21406
22780
|
const activeIndex = trackStates.findIndex(
|
|
21407
22781
|
(t) => t.config.id === activeTrackId
|
|
@@ -21718,6 +23092,7 @@ var mountDAW = (target, options = {}) => {
|
|
|
21718
23092
|
syncInstDisabled();
|
|
21719
23093
|
instSel.addEventListener("change", () => {
|
|
21720
23094
|
active.trackInstrument = instSel.value;
|
|
23095
|
+
active.composeSlot = null;
|
|
21721
23096
|
const trackIndex = trackStates.indexOf(active);
|
|
21722
23097
|
options.onTrackInstrumentChange?.(trackIndex, active.trackInstrument);
|
|
21723
23098
|
persistTrack1(active);
|
|
@@ -22121,6 +23496,7 @@ var mountDAW = (target, options = {}) => {
|
|
|
22121
23496
|
redrawAll();
|
|
22122
23497
|
fireLyricsChange(active);
|
|
22123
23498
|
reloadVoicesForModel(active.lyricModel);
|
|
23499
|
+
updateTrackTabs();
|
|
22124
23500
|
});
|
|
22125
23501
|
lyricCustomGuide.addEventListener("click", () => {
|
|
22126
23502
|
showModal("\u30AB\u30B9\u30BF\u30E0\u97F3\u58F0(.koe)\u306E\u4F7F\u3044\u65B9", KOE_INFO_HTML);
|
|
@@ -22654,6 +24030,7 @@ var mountDAW = (target, options = {}) => {
|
|
|
22654
24030
|
}
|
|
22655
24031
|
trackStates.forEach((t, i2) => {
|
|
22656
24032
|
if (applyActiveOnly && i2 !== activeTrackIndex) return;
|
|
24033
|
+
t.composeSlot = null;
|
|
22657
24034
|
const name = normalizeInstrumentName(meta.trackInstruments?.[i2] ?? "");
|
|
22658
24035
|
if (t.trackInstrument !== name) {
|
|
22659
24036
|
t.trackInstrument = name;
|
|
@@ -22905,7 +24282,7 @@ var mountDAW = (target, options = {}) => {
|
|
|
22905
24282
|
const p = programOfInstrumentName(t.trackInstrument);
|
|
22906
24283
|
if (p !== null) program = p;
|
|
22907
24284
|
} else if (!t.lyricModel) {
|
|
22908
|
-
const role = DECLARED_ROLE[t.config.id] ?? "melody";
|
|
24285
|
+
const role = t.composeSlot ?? DECLARED_ROLE[t.config.id] ?? "melody";
|
|
22909
24286
|
const instName = autoPreset[role] ?? autoPreset.melody;
|
|
22910
24287
|
const p = programOfInstrumentName(instName);
|
|
22911
24288
|
if (p !== null) program = p;
|
|
@@ -23274,7 +24651,7 @@ var mountDAW = (target, options = {}) => {
|
|
|
23274
24651
|
if (!stats) continue;
|
|
23275
24652
|
const role = DECLARED_ROLE[t.config.id] ?? classifyTrackRole(stats, t.config.id === topSingleVoiceId);
|
|
23276
24653
|
roleByTrackId.set(t.config.id, role);
|
|
23277
|
-
const instName = autoPreset[role];
|
|
24654
|
+
const instName = autoPreset[t.composeSlot ?? role] ?? autoPreset[role];
|
|
23278
24655
|
t.trackInstrument = instName;
|
|
23279
24656
|
const trackIndex = trackStates.indexOf(t);
|
|
23280
24657
|
options.onTrackInstrumentChange?.(trackIndex, instName);
|
|
@@ -23425,6 +24802,15 @@ var mountDAW = (target, options = {}) => {
|
|
|
23425
24802
|
refs.composeKey.value = savedKey;
|
|
23426
24803
|
}
|
|
23427
24804
|
}
|
|
24805
|
+
const savedScale = readMacroSetting("scale");
|
|
24806
|
+
if (savedScale && refs.composeScale) {
|
|
24807
|
+
const hasOption = Array.from(refs.composeScale.options).some(
|
|
24808
|
+
(opt) => opt.value === savedScale
|
|
24809
|
+
);
|
|
24810
|
+
if (hasOption) {
|
|
24811
|
+
refs.composeScale.value = savedScale;
|
|
24812
|
+
}
|
|
24813
|
+
}
|
|
23428
24814
|
const savedShift = readMacroSetting("shift");
|
|
23429
24815
|
if (savedShift && refs.shiftSelect) {
|
|
23430
24816
|
const hasOption = Array.from(refs.shiftSelect.options).some(
|
|
@@ -23487,6 +24873,20 @@ var mountDAW = (target, options = {}) => {
|
|
|
23487
24873
|
});
|
|
23488
24874
|
updateComposeKeyHint();
|
|
23489
24875
|
}
|
|
24876
|
+
const updateComposeScaleHint = () => {
|
|
24877
|
+
if (!refs.composeScale || !refs.composeScaleHint) return;
|
|
24878
|
+
const desc = getComposeScaleDescription(refs.composeScale.value);
|
|
24879
|
+
refs.composeScaleHint.textContent = desc;
|
|
24880
|
+
refs.composeScaleHint.title = desc;
|
|
24881
|
+
};
|
|
24882
|
+
const composeScale = refs.composeScale;
|
|
24883
|
+
if (composeScale) {
|
|
24884
|
+
composeScale.addEventListener("change", () => {
|
|
24885
|
+
writeMacroSetting("scale", composeScale.value);
|
|
24886
|
+
updateComposeScaleHint();
|
|
24887
|
+
});
|
|
24888
|
+
updateComposeScaleHint();
|
|
24889
|
+
}
|
|
23490
24890
|
if (refs.shiftSelect) {
|
|
23491
24891
|
refs.shiftSelect.addEventListener("change", () => {
|
|
23492
24892
|
writeMacroSetting("shift", refs.shiftSelect.value);
|
|
@@ -23507,6 +24907,7 @@ var mountDAW = (target, options = {}) => {
|
|
|
23507
24907
|
sections: selectedComposeSections(),
|
|
23508
24908
|
template: tmpl,
|
|
23509
24909
|
baseKey: refs.composeKey?.value ?? "any",
|
|
24910
|
+
scale: refs.composeScale?.value ?? "auto",
|
|
23510
24911
|
// 直近に作った曲の特徴を渡すと、それらから離れた候補に加点される。
|
|
23511
24912
|
// 「作曲」を続けて押したときに似た曲が並ぶのを防ぐ。
|
|
23512
24913
|
recent: recentComposeFingerprints
|
|
@@ -23540,45 +24941,39 @@ var mountDAW = (target, options = {}) => {
|
|
|
23540
24941
|
}
|
|
23541
24942
|
track.core.endBatch();
|
|
23542
24943
|
};
|
|
24944
|
+
const shouldAutoInstrument = !currentInstrument || currentInstrument === "auto" || currentInstrument === autoComposeInstrument;
|
|
24945
|
+
if (shouldAutoInstrument && song.instrument) {
|
|
24946
|
+
currentInstrument = song.instrument;
|
|
24947
|
+
autoComposeInstrument = song.instrument;
|
|
24948
|
+
options.onInstrumentChange?.(song.instrument);
|
|
24949
|
+
}
|
|
23543
24950
|
if (isAdvanced) {
|
|
23544
|
-
|
|
24951
|
+
const layers = buildAdvancedLayers(song, {
|
|
24952
|
+
edo: renderConfig.edo,
|
|
24953
|
+
stepsPerBar: renderConfig.stepsPerBar,
|
|
24954
|
+
preset: INSTRUMENT_PRESETS[currentInstrument] ?? INSTRUMENT_PRESETS.piano
|
|
24955
|
+
});
|
|
24956
|
+
for (const layer of layers) {
|
|
23545
24957
|
const track = trackStates[layer.index];
|
|
23546
24958
|
if (!track) continue;
|
|
23547
|
-
|
|
23548
|
-
edo: renderConfig.edo,
|
|
23549
|
-
chordStr: song.chordProgression,
|
|
23550
|
-
patternType: "arpeggio",
|
|
23551
|
-
rootShift: song.rootShift,
|
|
23552
|
-
bpm: song.bpm,
|
|
23553
|
-
stepsPerBar: renderConfig.stepsPerBar
|
|
23554
|
-
}).map((p) => ({
|
|
23555
|
-
startStep: p.startStep,
|
|
23556
|
-
pitchUnits: p.pitchUnits,
|
|
23557
|
-
durationSteps: p.durationSteps,
|
|
23558
|
-
velocity: Math.max(30, p.velocity - 14)
|
|
23559
|
-
})) : buildChordPlacements({
|
|
23560
|
-
edo: renderConfig.edo,
|
|
23561
|
-
chordStr: song.chordProgression,
|
|
23562
|
-
patternType: layer.part,
|
|
23563
|
-
rootShift: song.rootShift,
|
|
23564
|
-
bpm: song.bpm,
|
|
23565
|
-
stepsPerBar: renderConfig.stepsPerBar
|
|
23566
|
-
}).map((p) => ({
|
|
23567
|
-
startStep: p.startStep,
|
|
23568
|
-
pitchUnits: p.pitchUnits,
|
|
23569
|
-
durationSteps: p.durationSteps,
|
|
23570
|
-
velocity: p.velocity
|
|
23571
|
-
}));
|
|
23572
|
-
writeTrackAt(layer.index, notes);
|
|
24959
|
+
writeTrackAt(layer.index, layer.notes);
|
|
23573
24960
|
track.trackOctave = layer.octave;
|
|
23574
24961
|
track.volume = layer.volume;
|
|
23575
24962
|
track.core.setVolume(layer.volume);
|
|
24963
|
+
track.composeSlot = layer.notes.length > 0 ? layer.slot ?? null : null;
|
|
24964
|
+
if (layer.notes.length === 0 && track.trackInstrument) {
|
|
24965
|
+
track.trackInstrument = "";
|
|
24966
|
+
options.onTrackInstrumentChange?.(layer.index, "");
|
|
24967
|
+
}
|
|
23576
24968
|
}
|
|
23577
24969
|
for (let i2 = 0; i2 < trackStates.length; i2++) {
|
|
23578
|
-
if (
|
|
24970
|
+
if (layers.some((l) => l.index === i2)) continue;
|
|
23579
24971
|
writeTrackAt(i2, []);
|
|
24972
|
+
const t = trackStates[i2];
|
|
24973
|
+
if (t) t.composeSlot = null;
|
|
23580
24974
|
}
|
|
23581
24975
|
} else {
|
|
24976
|
+
for (const t of trackStates) t.composeSlot = null;
|
|
23582
24977
|
writeTrack("melody", song.melody);
|
|
23583
24978
|
writeTrack("submelody", song.submelody);
|
|
23584
24979
|
writeTrack("bass", song.bass);
|
|
@@ -23595,12 +24990,6 @@ var mountDAW = (target, options = {}) => {
|
|
|
23595
24990
|
refs.drumSelect.value = song.drum;
|
|
23596
24991
|
options.onDrumChange?.(song.drum);
|
|
23597
24992
|
applyDrumPatternFont(song.drum);
|
|
23598
|
-
const shouldAutoInstrument = !currentInstrument || currentInstrument === "auto" || currentInstrument === autoComposeInstrument;
|
|
23599
|
-
if (shouldAutoInstrument && song.instrument) {
|
|
23600
|
-
currentInstrument = song.instrument;
|
|
23601
|
-
autoComposeInstrument = song.instrument;
|
|
23602
|
-
options.onInstrumentChange?.(song.instrument);
|
|
23603
|
-
}
|
|
23604
24993
|
if (withVocal) {
|
|
23605
24994
|
autoComposeVocalTracks.clear();
|
|
23606
24995
|
const melodyTrack = isAdvanced ? trackStates[0] : trackStates.find((t) => t.config.id === "melody");
|
|
@@ -24837,6 +26226,7 @@ var mountDAW = (target, options = {}) => {
|
|
|
24837
26226
|
if (!t) return;
|
|
24838
26227
|
const name = normalizeInstrumentName(instrumentName);
|
|
24839
26228
|
t.trackInstrument = name;
|
|
26229
|
+
t.composeSlot = null;
|
|
24840
26230
|
if (t.config.id === activeTrackId) updateTrackPanel();
|
|
24841
26231
|
},
|
|
24842
26232
|
noteToCanvas: (step, pitch) => {
|
|
@@ -24960,8 +26350,9 @@ var playSingingMML = async (mml, options = {}) => {
|
|
|
24960
26350
|
});
|
|
24961
26351
|
const ownsCtx = !options.audioContext;
|
|
24962
26352
|
const ctx = options.audioContext ?? new AudioContext();
|
|
24963
|
-
const
|
|
26353
|
+
const rawDestination = options.destination ?? ctx.destination;
|
|
24964
26354
|
const useSynth = options.synth ?? !options.onPlayNote;
|
|
26355
|
+
const destination = createSafetyLimiter(ctx, rawDestination);
|
|
24965
26356
|
const synth = useSynth ? createSynth(ctx, destination) : null;
|
|
24966
26357
|
const pauseWhenHidden = options.pauseWhenHidden ?? ownsCtx;
|
|
24967
26358
|
let playing = false;
|
|
@@ -25967,21 +27358,29 @@ var createDtmStudio = async (options = {}) => {
|
|
|
25967
27358
|
};
|
|
25968
27359
|
applyGlueCompression(options.masterCompression ?? 0);
|
|
25969
27360
|
const setMasterCompression = (amount) => applyGlueCompression(amount);
|
|
25970
|
-
const safetyLimiter = audioCtx.createDynamicsCompressor();
|
|
25971
|
-
safetyLimiter.threshold.value = -1;
|
|
25972
|
-
safetyLimiter.knee.value = 0;
|
|
25973
|
-
safetyLimiter.ratio.value = 20;
|
|
25974
|
-
safetyLimiter.attack.value = 1e-3;
|
|
25975
|
-
safetyLimiter.release.value = 0.1;
|
|
25976
|
-
glueMakeup.connect(safetyLimiter);
|
|
25977
27361
|
const fadeGain = audioCtx.createGain();
|
|
25978
27362
|
fadeGain.gain.value = 1;
|
|
25979
|
-
safetyLimiter.connect(fadeGain);
|
|
25980
27363
|
fadeGain.connect(options.destination ?? audioCtx.destination);
|
|
27364
|
+
const safetyLimiter = createSafetyLimiter(audioCtx, fadeGain);
|
|
27365
|
+
glueMakeup.connect(safetyLimiter);
|
|
27366
|
+
const FADE_RESTORE_SEC = 0.02;
|
|
27367
|
+
const rampFadeGainToUnity = (from, at) => {
|
|
27368
|
+
fadeGain.gain.setValueAtTime(from, at);
|
|
27369
|
+
fadeGain.gain.linearRampToValueAtTime(1, at + FADE_RESTORE_SEC);
|
|
27370
|
+
};
|
|
27371
|
+
const restoreFadeGainIfMuted = () => {
|
|
27372
|
+
const current = fadeGain.gain.value;
|
|
27373
|
+
if (current >= 1) return;
|
|
27374
|
+
const now = audioCtx.currentTime;
|
|
27375
|
+
fadeGain.gain.cancelScheduledValues(now);
|
|
27376
|
+
rampFadeGainToUnity(current, now);
|
|
27377
|
+
};
|
|
25981
27378
|
const scheduleFade = (params) => {
|
|
25982
|
-
|
|
27379
|
+
const now = audioCtx.currentTime;
|
|
27380
|
+
const current = fadeGain.gain.value;
|
|
27381
|
+
fadeGain.gain.cancelScheduledValues(now);
|
|
25983
27382
|
if (!params) {
|
|
25984
|
-
|
|
27383
|
+
rampFadeGainToUnity(current, now);
|
|
25985
27384
|
return;
|
|
25986
27385
|
}
|
|
25987
27386
|
const { fadeInStartAt, fadeInEndAt, fadeOutStartAt, fadeOutEndAt } = params;
|
|
@@ -25989,13 +27388,12 @@ var createDtmStudio = async (options = {}) => {
|
|
|
25989
27388
|
fadeGain.gain.setValueAtTime(0, fadeInStartAt);
|
|
25990
27389
|
fadeGain.gain.linearRampToValueAtTime(1, fadeInEndAt);
|
|
25991
27390
|
} else {
|
|
25992
|
-
|
|
27391
|
+
rampFadeGainToUnity(current, now);
|
|
25993
27392
|
}
|
|
25994
27393
|
if (fadeOutStartAt !== void 0 && fadeOutEndAt !== void 0) {
|
|
25995
27394
|
fadeGain.gain.setValueAtTime(1, fadeOutStartAt);
|
|
25996
27395
|
fadeGain.gain.linearRampToValueAtTime(0, fadeOutEndAt);
|
|
25997
|
-
|
|
25998
|
-
fadeGain.gain.setValueAtTime(1, fadeOutEndAt + 2);
|
|
27396
|
+
rampFadeGainToUnity(0, fadeOutEndAt + 2);
|
|
25999
27397
|
}
|
|
26000
27398
|
};
|
|
26001
27399
|
const clipMeter = createClipMeter(audioCtx, glueMakeup);
|
|
@@ -26055,8 +27453,7 @@ var createDtmStudio = async (options = {}) => {
|
|
|
26055
27453
|
};
|
|
26056
27454
|
};
|
|
26057
27455
|
const resumeAudio = () => {
|
|
26058
|
-
|
|
26059
|
-
fadeGain.gain.setValueAtTime(1, audioCtx.currentTime);
|
|
27456
|
+
restoreFadeGainIfMuted();
|
|
26060
27457
|
if (audioCtx.state === "closed") return Promise.resolve();
|
|
26061
27458
|
return audioCtx.resume();
|
|
26062
27459
|
};
|
|
@@ -26267,12 +27664,6 @@ var createDtmStudio = async (options = {}) => {
|
|
|
26267
27664
|
await listReady;
|
|
26268
27665
|
nameToKey = await buildNameToKeyMapping();
|
|
26269
27666
|
await Promise.all([drumReady, loadPreset(defaultPreset)]);
|
|
26270
|
-
const restoreFadeGainIfMuted = () => {
|
|
26271
|
-
if (fadeGain.gain.value < 1) {
|
|
26272
|
-
fadeGain.gain.cancelScheduledValues(audioCtx.currentTime);
|
|
26273
|
-
fadeGain.gain.setValueAtTime(1, audioCtx.currentTime);
|
|
26274
|
-
}
|
|
26275
|
-
};
|
|
26276
27667
|
const playDrum = (e) => {
|
|
26277
27668
|
if (!sfDrum.font) return;
|
|
26278
27669
|
if (e.when === 0) restoreFadeGainIfMuted();
|
|
@@ -27023,7 +28414,7 @@ var createDtmStudio = async (options = {}) => {
|
|
|
27023
28414
|
};
|
|
27024
28415
|
const setMasterVolume = (volume) => {
|
|
27025
28416
|
const g = Math.max(0, Math.min(100, volume)) / 100;
|
|
27026
|
-
masterGain.gain.
|
|
28417
|
+
masterGain.gain.setTargetAtTime(g, audioCtx.currentTime, 0.02);
|
|
27027
28418
|
};
|
|
27028
28419
|
let recordDestNode = null;
|
|
27029
28420
|
const createMediaStreamDestination = () => {
|
|
@@ -27106,10 +28497,13 @@ var createDtmStudio = async (options = {}) => {
|
|
|
27106
28497
|
0 && (module.exports = {
|
|
27107
28498
|
A4_HZ,
|
|
27108
28499
|
A4_UNITS,
|
|
28500
|
+
BLUES_SCALE,
|
|
27109
28501
|
BREATH_MARK,
|
|
27110
28502
|
CENTS_PER_UNIT,
|
|
27111
28503
|
COMPOSE_KEYS,
|
|
27112
28504
|
COMPOSE_MOOD_GROUPS,
|
|
28505
|
+
COMPOSE_SCALES,
|
|
28506
|
+
COMPOSE_SCALE_IDS,
|
|
27113
28507
|
CORPUS_BANDS,
|
|
27114
28508
|
CORPUS_SIZE,
|
|
27115
28509
|
DAW_CSS,
|
|
@@ -27129,7 +28523,11 @@ var createDtmStudio = async (options = {}) => {
|
|
|
27129
28523
|
FADE_IN_MARK,
|
|
27130
28524
|
FADE_OUT_MARK,
|
|
27131
28525
|
GLOBAL_STORAGE_KEYS,
|
|
28526
|
+
GM_BRIGHT_CEILING,
|
|
27132
28527
|
GM_INSTRUMENT_NAMES,
|
|
28528
|
+
GM_INSTRUMENT_RANGE,
|
|
28529
|
+
HARMONIC_MINOR_SCALE,
|
|
28530
|
+
HUNGARIAN_SCALE,
|
|
27133
28531
|
INSTRUMENT_PRESETS,
|
|
27134
28532
|
KEY_COUNT,
|
|
27135
28533
|
KOE_BASE_URL,
|
|
@@ -27139,6 +28537,7 @@ var createDtmStudio = async (options = {}) => {
|
|
|
27139
28537
|
LinkedList,
|
|
27140
28538
|
MACRO_STORAGE_KEYS,
|
|
27141
28539
|
MAJOR_KEY_IDS,
|
|
28540
|
+
MAJOR_SCALE,
|
|
27142
28541
|
MAX_VOCAL_VOLUME,
|
|
27143
28542
|
MICRO_STEP,
|
|
27144
28543
|
MINOR_KEY_IDS,
|
|
@@ -27207,10 +28606,12 @@ var createDtmStudio = async (options = {}) => {
|
|
|
27207
28606
|
featureVector,
|
|
27208
28607
|
fifthToStep,
|
|
27209
28608
|
fifthToUnits,
|
|
28609
|
+
fitInstrumentOctave,
|
|
27210
28610
|
formatMmlMeta,
|
|
27211
28611
|
freqFromPitch,
|
|
27212
28612
|
generateRandomPattern,
|
|
27213
28613
|
getComposeKeyDescription,
|
|
28614
|
+
getComposeScaleDescription,
|
|
27214
28615
|
getDrumPatternKeys,
|
|
27215
28616
|
getMidiBPM,
|
|
27216
28617
|
icon,
|
|
@@ -27246,9 +28647,13 @@ var createDtmStudio = async (options = {}) => {
|
|
|
27246
28647
|
readGlobalSetting,
|
|
27247
28648
|
readMacroSections,
|
|
27248
28649
|
readMacroSetting,
|
|
28650
|
+
resolveCenter,
|
|
27249
28651
|
resolveComposeKey,
|
|
28652
|
+
resolveComposeScale,
|
|
27250
28653
|
resolveDrumPattern,
|
|
27251
28654
|
resolveLoopPoint,
|
|
28655
|
+
scaleDegrees,
|
|
28656
|
+
scaleSize,
|
|
27252
28657
|
semitonesToUnits,
|
|
27253
28658
|
shiftNotes,
|
|
27254
28659
|
showLoadingOverlay,
|