@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.mjs
CHANGED
|
@@ -1763,11 +1763,19 @@ var createChannelStrip = (ctx, destination, options = {}) => {
|
|
|
1763
1763
|
const duckGain = ctx.createGain();
|
|
1764
1764
|
duckGain.gain.value = 1;
|
|
1765
1765
|
const DUCK_ATTACK_SEC = 8e-3;
|
|
1766
|
+
let duckReleaseEndAt = 0;
|
|
1766
1767
|
const duck = (atTime, depth = 0.3, releaseSec = 0.18) => {
|
|
1767
1768
|
const t = Math.max(atTime, ctx.currentTime);
|
|
1768
1769
|
const floor = clamp(1 - depth, 0, 1);
|
|
1769
|
-
duckGain.gain
|
|
1770
|
-
|
|
1770
|
+
const param = duckGain.gain;
|
|
1771
|
+
if (t >= duckReleaseEndAt) {
|
|
1772
|
+
param.setValueAtTime(1, t);
|
|
1773
|
+
} else if (typeof param.cancelAndHoldAtTime === "function") {
|
|
1774
|
+
param.cancelAndHoldAtTime(t);
|
|
1775
|
+
}
|
|
1776
|
+
param.linearRampToValueAtTime(floor, t + DUCK_ATTACK_SEC);
|
|
1777
|
+
param.linearRampToValueAtTime(1, t + DUCK_ATTACK_SEC + releaseSec);
|
|
1778
|
+
duckReleaseEndAt = t + DUCK_ATTACK_SEC + releaseSec;
|
|
1771
1779
|
};
|
|
1772
1780
|
eqHigh.connect(compressor);
|
|
1773
1781
|
compressor.connect(duckGain);
|
|
@@ -2064,12 +2072,15 @@ var buildChordPlacements = (options) => {
|
|
|
2064
2072
|
}
|
|
2065
2073
|
}
|
|
2066
2074
|
} else if (patternType === "alternating") {
|
|
2075
|
+
const quarterSteps = Math.floor(stepsPerBar / 4);
|
|
2067
2076
|
notes.forEach((noteOffset, i2) => {
|
|
2068
|
-
const stepOffset = i2 *
|
|
2077
|
+
const stepOffset = i2 * quarterSteps;
|
|
2078
|
+
const isLast = i2 === notes.length - 1;
|
|
2079
|
+
const durationSteps = isLast ? Math.max(12, noteLength - stepOffset) : Math.max(12, quarterSteps);
|
|
2069
2080
|
placements.push({
|
|
2070
2081
|
startStep: chord.whenStep + stepOffset,
|
|
2071
2082
|
pitchUnits: toUnits(noteOffset),
|
|
2072
|
-
durationSteps
|
|
2083
|
+
durationSteps,
|
|
2073
2084
|
velocity: 100
|
|
2074
2085
|
});
|
|
2075
2086
|
});
|
|
@@ -4697,6 +4708,45 @@ var createReverbImpulse = (ctx, decaySec = DEFAULT_REVERB_DECAY_SEC) => {
|
|
|
4697
4708
|
};
|
|
4698
4709
|
var reverbAmountToGain = (amount) => Math.max(0, Math.min(100, amount)) / 100;
|
|
4699
4710
|
|
|
4711
|
+
// src/safety-limiter.ts
|
|
4712
|
+
var THRESHOLD_DB = -1;
|
|
4713
|
+
var KNEE_DB = 0;
|
|
4714
|
+
var RATIO = 20;
|
|
4715
|
+
var ATTACK_SEC = 1e-3;
|
|
4716
|
+
var RELEASE_SEC = 0.1;
|
|
4717
|
+
var CURVE_SAMPLES2 = 2048;
|
|
4718
|
+
var SOFT_KNEE = 0.85;
|
|
4719
|
+
var CEILING = 0.98;
|
|
4720
|
+
var SHAPER_RANGE = 4;
|
|
4721
|
+
var OVERSAMPLE2 = "none";
|
|
4722
|
+
var createSoftClipCurve = () => {
|
|
4723
|
+
const curve = new Float32Array(CURVE_SAMPLES2);
|
|
4724
|
+
const span = CEILING - SOFT_KNEE;
|
|
4725
|
+
for (let i2 = 0; i2 < CURVE_SAMPLES2; i2++) {
|
|
4726
|
+
const x2 = (i2 / (CURVE_SAMPLES2 - 1) * 2 - 1) * SHAPER_RANGE;
|
|
4727
|
+
const a = Math.abs(x2);
|
|
4728
|
+
curve[i2] = Math.sign(x2) * (a <= SOFT_KNEE ? a : SOFT_KNEE + span * Math.tanh((a - SOFT_KNEE) / span));
|
|
4729
|
+
}
|
|
4730
|
+
return curve;
|
|
4731
|
+
};
|
|
4732
|
+
var createSafetyLimiter = (ctx, destination) => {
|
|
4733
|
+
const limiter = ctx.createDynamicsCompressor();
|
|
4734
|
+
limiter.threshold.value = THRESHOLD_DB;
|
|
4735
|
+
limiter.knee.value = KNEE_DB;
|
|
4736
|
+
limiter.ratio.value = RATIO;
|
|
4737
|
+
limiter.attack.value = ATTACK_SEC;
|
|
4738
|
+
limiter.release.value = RELEASE_SEC;
|
|
4739
|
+
const preScale = ctx.createGain();
|
|
4740
|
+
preScale.gain.value = 1 / SHAPER_RANGE;
|
|
4741
|
+
const softClip = ctx.createWaveShaper();
|
|
4742
|
+
softClip.curve = createSoftClipCurve();
|
|
4743
|
+
softClip.oversample = OVERSAMPLE2;
|
|
4744
|
+
limiter.connect(preScale);
|
|
4745
|
+
preScale.connect(softClip);
|
|
4746
|
+
softClip.connect(destination);
|
|
4747
|
+
return limiter;
|
|
4748
|
+
};
|
|
4749
|
+
|
|
4700
4750
|
// src/sequencer.ts
|
|
4701
4751
|
var STEPS_PER_BEAT = 48;
|
|
4702
4752
|
var PLAN_TIME = 0.5;
|
|
@@ -7160,6 +7210,9 @@ var SONG_DRUM_PATTERNS = {
|
|
|
7160
7210
|
|
|
7161
7211
|
// src/synth.ts
|
|
7162
7212
|
var freqFromPitch = (pitchUnits) => unitsToHz(pitchUnits);
|
|
7213
|
+
var MIN_ATTACK_SEC = 15e-4;
|
|
7214
|
+
var MIN_RELEASE_SEC = 4e-3;
|
|
7215
|
+
var TAIL_RATIO = 1e-3;
|
|
7163
7216
|
var createSynth = (ctx, destination = ctx.destination, tone = {}) => {
|
|
7164
7217
|
const wave = tone.wave ?? "square";
|
|
7165
7218
|
const attack = tone.attack ?? 0;
|
|
@@ -7178,25 +7231,25 @@ var createSynth = (ctx, destination = ctx.destination, tone = {}) => {
|
|
|
7178
7231
|
osc.frequency.value = freqFromPitch(e.pitchUnits);
|
|
7179
7232
|
const t0 = ctx.currentTime + e.when;
|
|
7180
7233
|
const peak = Math.max(1e-4, 0.06 * e.volume * 1.5 * gainScale);
|
|
7234
|
+
const tail = peak * TAIL_RATIO;
|
|
7235
|
+
const stopAt = t0 + e.duration + MIN_RELEASE_SEC;
|
|
7181
7236
|
if (tone.decay) {
|
|
7182
7237
|
gain.gain.setValueAtTime(1e-4, t0);
|
|
7183
7238
|
gain.gain.linearRampToValueAtTime(peak, t0 + Math.max(3e-3, attack));
|
|
7184
|
-
gain.gain.exponentialRampToValueAtTime(
|
|
7239
|
+
gain.gain.exponentialRampToValueAtTime(tail, t0 + e.duration);
|
|
7185
7240
|
} else {
|
|
7186
7241
|
const releaseTime = Math.min(0.02, e.duration * 0.1);
|
|
7187
7242
|
const sustainDuration = e.duration - releaseTime;
|
|
7188
|
-
|
|
7189
|
-
|
|
7190
|
-
|
|
7191
|
-
|
|
7192
|
-
|
|
7193
|
-
|
|
7194
|
-
} else {
|
|
7195
|
-
gain.gain.setValueAtTime(peak, t0);
|
|
7196
|
-
}
|
|
7243
|
+
const attackTime = Math.min(
|
|
7244
|
+
Math.max(attack, MIN_ATTACK_SEC),
|
|
7245
|
+
sustainDuration
|
|
7246
|
+
);
|
|
7247
|
+
gain.gain.setValueAtTime(1e-4, t0);
|
|
7248
|
+
gain.gain.linearRampToValueAtTime(peak, t0 + attackTime);
|
|
7197
7249
|
gain.gain.setValueAtTime(peak, t0 + sustainDuration);
|
|
7198
|
-
gain.gain.exponentialRampToValueAtTime(
|
|
7250
|
+
gain.gain.exponentialRampToValueAtTime(tail, t0 + e.duration);
|
|
7199
7251
|
}
|
|
7252
|
+
gain.gain.linearRampToValueAtTime(0, stopAt);
|
|
7200
7253
|
osc.connect(gain);
|
|
7201
7254
|
let panner = null;
|
|
7202
7255
|
if (typeof ctx.createStereoPanner === "function" && e.pan) {
|
|
@@ -7208,7 +7261,7 @@ var createSynth = (ctx, destination = ctx.destination, tone = {}) => {
|
|
|
7208
7261
|
gain.connect(compressor);
|
|
7209
7262
|
}
|
|
7210
7263
|
osc.start(t0);
|
|
7211
|
-
osc.stop(
|
|
7264
|
+
osc.stop(stopAt);
|
|
7212
7265
|
osc.onended = () => {
|
|
7213
7266
|
osc.disconnect();
|
|
7214
7267
|
gain.disconnect();
|
|
@@ -7223,14 +7276,21 @@ var createSynth = (ctx, destination = ctx.destination, tone = {}) => {
|
|
|
7223
7276
|
if (isKick) {
|
|
7224
7277
|
const osc = ctx.createOscillator();
|
|
7225
7278
|
const g2 = ctx.createGain();
|
|
7279
|
+
const kickPeak = vol * 0.135;
|
|
7280
|
+
const kickDecayEnd = t0 + 0.18;
|
|
7281
|
+
const kickEnd = kickDecayEnd + MIN_RELEASE_SEC;
|
|
7226
7282
|
osc.frequency.setValueAtTime(150, t0);
|
|
7227
7283
|
osc.frequency.exponentialRampToValueAtTime(50, t0 + 0.12);
|
|
7228
|
-
g2.gain.setValueAtTime(
|
|
7229
|
-
g2.gain.exponentialRampToValueAtTime(
|
|
7284
|
+
g2.gain.setValueAtTime(kickPeak, t0);
|
|
7285
|
+
g2.gain.exponentialRampToValueAtTime(kickPeak * TAIL_RATIO, kickDecayEnd);
|
|
7286
|
+
g2.gain.linearRampToValueAtTime(0, kickEnd);
|
|
7230
7287
|
osc.connect(g2).connect(compressor);
|
|
7231
7288
|
osc.start(t0);
|
|
7232
|
-
osc.stop(
|
|
7233
|
-
osc.onended = () =>
|
|
7289
|
+
osc.stop(kickEnd);
|
|
7290
|
+
osc.onended = () => {
|
|
7291
|
+
osc.disconnect();
|
|
7292
|
+
g2.disconnect();
|
|
7293
|
+
};
|
|
7234
7294
|
return;
|
|
7235
7295
|
}
|
|
7236
7296
|
const dur = isSnareLike ? 0.18 : 0.05;
|
|
@@ -7244,8 +7304,13 @@ var createSynth = (ctx, destination = ctx.destination, tone = {}) => {
|
|
|
7244
7304
|
filter.type = isSnareLike ? "bandpass" : "highpass";
|
|
7245
7305
|
filter.frequency.value = isSnareLike ? 2e3 : 8e3;
|
|
7246
7306
|
const g = ctx.createGain();
|
|
7247
|
-
|
|
7248
|
-
g.gain.
|
|
7307
|
+
const noisePeak = vol * (isSnareLike ? 0.105 : 0.06);
|
|
7308
|
+
g.gain.setValueAtTime(noisePeak, t0);
|
|
7309
|
+
g.gain.exponentialRampToValueAtTime(
|
|
7310
|
+
noisePeak * TAIL_RATIO,
|
|
7311
|
+
t0 + dur - MIN_RELEASE_SEC
|
|
7312
|
+
);
|
|
7313
|
+
g.gain.linearRampToValueAtTime(0, t0 + dur);
|
|
7249
7314
|
src.connect(filter).connect(g).connect(compressor);
|
|
7250
7315
|
src.start(t0);
|
|
7251
7316
|
src.stop(t0 + dur);
|
|
@@ -7307,7 +7372,7 @@ var playPlacements = (placements, options) => {
|
|
|
7307
7372
|
reverbPreDelay.connect(reverbConvolver);
|
|
7308
7373
|
reverbConvolver.connect(reverbWetGain);
|
|
7309
7374
|
reverbWetGain.connect(finalMix);
|
|
7310
|
-
finalMix.connect(rawDestination);
|
|
7375
|
+
finalMix.connect(createSafetyLimiter(ctx, rawDestination));
|
|
7311
7376
|
const channelStrips = /* @__PURE__ */ new Map();
|
|
7312
7377
|
const getChannelStrip = (index) => {
|
|
7313
7378
|
let strip = channelStrips.get(index);
|
|
@@ -8121,6 +8186,22 @@ var DAW_CSS = `
|
|
|
8121
8186
|
opacity: 0.85;
|
|
8122
8187
|
}
|
|
8123
8188
|
.dtm-pill:not(.dtm-pill--active):active { transform: translate(1px,1px); box-shadow: none; }
|
|
8189
|
+
/* \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 */
|
|
8190
|
+
.dtm-pill--vocal::after {
|
|
8191
|
+
content: '';
|
|
8192
|
+
position: absolute;
|
|
8193
|
+
inset: 0;
|
|
8194
|
+
background-image: var(--dtm-pill-icon);
|
|
8195
|
+
background-size: contain;
|
|
8196
|
+
background-repeat: no-repeat;
|
|
8197
|
+
background-position: right center;
|
|
8198
|
+
opacity: 0.4;
|
|
8199
|
+
pointer-events: none;
|
|
8200
|
+
}
|
|
8201
|
+
.dtm-pill__label {
|
|
8202
|
+
position: relative;
|
|
8203
|
+
z-index: 1;
|
|
8204
|
+
}
|
|
8124
8205
|
/* \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 */
|
|
8125
8206
|
.dtm-pill--sounding {
|
|
8126
8207
|
filter: brightness(1.6);
|
|
@@ -9746,17 +9827,24 @@ var mountMmlPlayer = (target, mml, options = {}) => {
|
|
|
9746
9827
|
if (!audioCtx) audioCtx = new AudioContext();
|
|
9747
9828
|
return audioCtx;
|
|
9748
9829
|
};
|
|
9830
|
+
let limiterNode = null;
|
|
9831
|
+
const ensureOutput = () => {
|
|
9832
|
+
const ctx = ensureCtx();
|
|
9833
|
+
if (!limiterNode) limiterNode = createSafetyLimiter(ctx, ctx.destination);
|
|
9834
|
+
return limiterNode;
|
|
9835
|
+
};
|
|
9749
9836
|
let synthInstance = null;
|
|
9750
9837
|
const ensureSynth = () => {
|
|
9751
|
-
if (!synthInstance)
|
|
9838
|
+
if (!synthInstance) {
|
|
9839
|
+
synthInstance = createSynth(ensureCtx(), ensureOutput());
|
|
9840
|
+
}
|
|
9752
9841
|
return synthInstance;
|
|
9753
9842
|
};
|
|
9754
9843
|
let voices = null;
|
|
9755
9844
|
const ensureVoices = () => {
|
|
9756
9845
|
if (options.singingVoices) return options.singingVoices;
|
|
9757
9846
|
if (!voices) {
|
|
9758
|
-
|
|
9759
|
-
voices = createSingingVoices(ctx, ctx.destination);
|
|
9847
|
+
voices = createSingingVoices(ensureCtx(), ensureOutput());
|
|
9760
9848
|
voices.setVolume(trackVolume / 100 * (masterVolume / 100));
|
|
9761
9849
|
}
|
|
9762
9850
|
return voices;
|
|
@@ -10818,6 +10906,12 @@ var SoundFont = class _SoundFont {
|
|
|
10818
10906
|
// ファミリごとに変える。
|
|
10819
10907
|
/** アタック(無音からピークまで)秒。クリック防止の最小限。全楽器共通。 */
|
|
10820
10908
|
static attackSec = 5e-3;
|
|
10909
|
+
/**
|
|
10910
|
+
* 消え際に最低限確保する秒数。アタックと対になるクリック防止で、**サンプルが
|
|
10911
|
+
* 終わるまでに**必ずここまでに 0 へ落とし切る。振幅が残ったままバッファが尽きたり
|
|
10912
|
+
* `stop()` が来たりすると、その瞬間の値がそのまま段差になりプチノイズが出る。
|
|
10913
|
+
*/
|
|
10914
|
+
static minReleaseSec = 4e-3;
|
|
10821
10915
|
/**
|
|
10822
10916
|
* 減衰の型ごとのエンベロープ。
|
|
10823
10917
|
*
|
|
@@ -11004,14 +11098,23 @@ var SoundFont = class _SoundFont {
|
|
|
11004
11098
|
const startGainTime = Math.max(ctx.currentTime, _when);
|
|
11005
11099
|
g.gain.setValueAtTime(0, startGainTime);
|
|
11006
11100
|
const env = _SoundFont.envelopes[this.style.env] ?? _SoundFont.envelopes.sustain;
|
|
11007
|
-
const
|
|
11101
|
+
const playRate = _param.playbackRate * 2 ** ((humanizeCents + detuneCents) / 1200);
|
|
11102
|
+
const sampleEnd = _when + (buffer.duration - startOffsetSec) / playRate;
|
|
11103
|
+
const limit = src.loop ? Number.POSITIVE_INFINITY : sampleEnd;
|
|
11008
11104
|
const attackEnd = Math.min(startGainTime + _SoundFont.attackSec, limit);
|
|
11009
11105
|
const decayEnd = Math.min(
|
|
11010
11106
|
Math.max(attackEnd, attackEnd + env.decaySec),
|
|
11011
11107
|
limit
|
|
11012
11108
|
);
|
|
11013
|
-
const
|
|
11014
|
-
|
|
11109
|
+
const tailRoom = Math.min(
|
|
11110
|
+
_SoundFont.minReleaseSec,
|
|
11111
|
+
Math.max(0, limit - decayEnd)
|
|
11112
|
+
);
|
|
11113
|
+
const noteOff = Math.min(
|
|
11114
|
+
Math.max(decayEnd, _when + duration),
|
|
11115
|
+
limit - tailRoom
|
|
11116
|
+
);
|
|
11117
|
+
const end = isDrum ? sampleEnd : Math.max(Math.min(noteOff + env.releaseSec, limit), noteOff + tailRoom);
|
|
11015
11118
|
if (!isDrum) {
|
|
11016
11119
|
const sustainVolume = effectiveVolume * env.sustain;
|
|
11017
11120
|
g.gain.linearRampToValueAtTime(effectiveVolume, attackEnd);
|
|
@@ -11020,6 +11123,11 @@ var SoundFont = class _SoundFont {
|
|
|
11020
11123
|
g.gain.linearRampToValueAtTime(0, end);
|
|
11021
11124
|
} else {
|
|
11022
11125
|
g.gain.linearRampToValueAtTime(effectiveVolume, attackEnd);
|
|
11126
|
+
const releaseStart = Math.max(attackEnd, end - _SoundFont.minReleaseSec);
|
|
11127
|
+
if (releaseStart > attackEnd) {
|
|
11128
|
+
g.gain.setValueAtTime(effectiveVolume, releaseStart);
|
|
11129
|
+
}
|
|
11130
|
+
g.gain.linearRampToValueAtTime(0, end);
|
|
11023
11131
|
}
|
|
11024
11132
|
if (filter) src.connect(filter).connect(g);
|
|
11025
11133
|
else src.connect(g);
|
|
@@ -11229,12 +11337,10 @@ var addParam = (zone, pitch) => {
|
|
|
11229
11337
|
coarseTune,
|
|
11230
11338
|
fineTune,
|
|
11231
11339
|
sampleRate,
|
|
11232
|
-
delay
|
|
11233
|
-
buffer
|
|
11340
|
+
delay
|
|
11234
11341
|
} = zone;
|
|
11235
11342
|
const baseDetune = originalPitch - 100 * coarseTune - fineTune;
|
|
11236
11343
|
const playbackRate = 2 ** ((100 * pitch - baseDetune) / 1200);
|
|
11237
|
-
const max = (buffer?.duration ?? 0) / playbackRate;
|
|
11238
11344
|
const src = {
|
|
11239
11345
|
loop: loopStart >= 1 && loopStart < loopEnd
|
|
11240
11346
|
};
|
|
@@ -11242,7 +11348,7 @@ var addParam = (zone, pitch) => {
|
|
|
11242
11348
|
[src.loopStart, src.loopEnd] = [loopStart, loopEnd].map(
|
|
11243
11349
|
(v) => v / sampleRate + delay
|
|
11244
11350
|
);
|
|
11245
|
-
zone._param = { playbackRate,
|
|
11351
|
+
zone._param = { playbackRate, src };
|
|
11246
11352
|
};
|
|
11247
11353
|
|
|
11248
11354
|
// src/chord-player.ts
|
|
@@ -12540,29 +12646,30 @@ var CORPUS_BANDS = {
|
|
|
12540
12646
|
climaxPeaks: [1, 2, 13.5, 26],
|
|
12541
12647
|
complementarity: [0, 0.026, 0.179, 0.405]
|
|
12542
12648
|
};
|
|
12543
|
-
var
|
|
12544
|
-
entropy
|
|
12545
|
-
valueKinds
|
|
12546
|
-
restRatio
|
|
12547
|
-
leapRatio
|
|
12548
|
-
stepRatio
|
|
12549
|
-
chromaticRatio
|
|
12550
|
-
maxLeap
|
|
12551
|
-
melodyRange
|
|
12552
|
-
notesPerBar
|
|
12553
|
-
shortNoteRatio
|
|
12554
|
-
barDensityCv
|
|
12555
|
-
densityCliff
|
|
12556
|
-
sim1
|
|
12557
|
-
sim2
|
|
12558
|
-
sim4
|
|
12559
|
-
sim8
|
|
12560
|
-
phraseBreath
|
|
12561
|
-
turnRatio
|
|
12562
|
-
climaxPosition
|
|
12563
|
-
climaxPeaks
|
|
12564
|
-
complementarity
|
|
12565
|
-
|
|
12649
|
+
var CORPUS_PROFILE_KEYS = [
|
|
12650
|
+
"entropy",
|
|
12651
|
+
"valueKinds",
|
|
12652
|
+
"restRatio",
|
|
12653
|
+
"leapRatio",
|
|
12654
|
+
"stepRatio",
|
|
12655
|
+
"chromaticRatio",
|
|
12656
|
+
"maxLeap",
|
|
12657
|
+
"melodyRange",
|
|
12658
|
+
"notesPerBar",
|
|
12659
|
+
"shortNoteRatio",
|
|
12660
|
+
"barDensityCv",
|
|
12661
|
+
"densityCliff",
|
|
12662
|
+
"sim1",
|
|
12663
|
+
"sim2",
|
|
12664
|
+
"sim4",
|
|
12665
|
+
"sim8",
|
|
12666
|
+
"phraseBreath",
|
|
12667
|
+
"turnRatio",
|
|
12668
|
+
"climaxPosition",
|
|
12669
|
+
"climaxPeaks",
|
|
12670
|
+
"complementarity"
|
|
12671
|
+
];
|
|
12672
|
+
var CORPUS_DEVIATION_BUDGET = 4;
|
|
12566
12673
|
var CORPUS_CELL_WEIGHTS = {
|
|
12567
12674
|
"0,2,4,6,8,10,12,14": 584,
|
|
12568
12675
|
"0,2,4,6,8,12,14": 512,
|
|
@@ -13427,16 +13534,15 @@ var tensionFeatures = (barTension, opts) => {
|
|
|
13427
13534
|
return { rise, resolve };
|
|
13428
13535
|
};
|
|
13429
13536
|
var band = (v, lo, idealLo, idealHi, hi) => {
|
|
13430
|
-
if (v <= lo || v >= hi) return 0;
|
|
13431
13537
|
if (v >= idealLo && v <= idealHi) return 1;
|
|
13538
|
+
if (v <= lo || v >= hi) return 0;
|
|
13432
13539
|
if (v < idealLo) return idealLo === lo ? 0 : (v - lo) / (idealLo - lo);
|
|
13433
13540
|
return hi === idealHi ? 0 : (hi - v) / (hi - idealHi);
|
|
13434
13541
|
};
|
|
13435
|
-
var
|
|
13436
|
-
const
|
|
13437
|
-
|
|
13438
|
-
|
|
13439
|
-
return 1 - 0.15 * Math.min(1, Math.abs(v - median) / spread);
|
|
13542
|
+
var plausibleBand = (v, b) => {
|
|
13543
|
+
const span = b[3] - b[0];
|
|
13544
|
+
const margin = span > 0 ? span * 0.5 : 1;
|
|
13545
|
+
return band(v, b[0] - margin, b[0], b[3], b[3] + margin);
|
|
13440
13546
|
};
|
|
13441
13547
|
var featureVector = (f) => [
|
|
13442
13548
|
f.entropy / 3,
|
|
@@ -13460,6 +13566,650 @@ var featureDistance = (a, b) => {
|
|
|
13460
13566
|
return Math.sqrt(sum);
|
|
13461
13567
|
};
|
|
13462
13568
|
|
|
13569
|
+
// src/compose-scales.ts
|
|
13570
|
+
var MAJOR_SCALE2 = [
|
|
13571
|
+
{ semi: 0, fifth: 0 },
|
|
13572
|
+
// C
|
|
13573
|
+
{ semi: 2, fifth: 2 },
|
|
13574
|
+
// D
|
|
13575
|
+
{ semi: 4, fifth: 4 },
|
|
13576
|
+
// E
|
|
13577
|
+
{ semi: 5, fifth: -1 },
|
|
13578
|
+
// F
|
|
13579
|
+
{ semi: 7, fifth: 1 },
|
|
13580
|
+
// G
|
|
13581
|
+
{ semi: 9, fifth: 3 },
|
|
13582
|
+
// A
|
|
13583
|
+
{ semi: 11, fifth: 5 }
|
|
13584
|
+
// B
|
|
13585
|
+
];
|
|
13586
|
+
var HARMONIC_MINOR_SCALE = [
|
|
13587
|
+
{ semi: 0, fifth: 0 },
|
|
13588
|
+
// C
|
|
13589
|
+
{ semi: 2, fifth: 2 },
|
|
13590
|
+
// D
|
|
13591
|
+
{ semi: 4, fifth: 4 },
|
|
13592
|
+
// E
|
|
13593
|
+
{ semi: 5, fifth: -1 },
|
|
13594
|
+
// F
|
|
13595
|
+
{ semi: 8, fifth: 8 },
|
|
13596
|
+
// G#
|
|
13597
|
+
{ semi: 9, fifth: 3 },
|
|
13598
|
+
// A
|
|
13599
|
+
{ semi: 11, fifth: 5 }
|
|
13600
|
+
// B
|
|
13601
|
+
];
|
|
13602
|
+
var HUNGARIAN_SCALE = [
|
|
13603
|
+
{ semi: 0, fifth: 0 },
|
|
13604
|
+
// C
|
|
13605
|
+
{ semi: 3, fifth: 9 },
|
|
13606
|
+
// D#
|
|
13607
|
+
{ semi: 4, fifth: 4 },
|
|
13608
|
+
// E
|
|
13609
|
+
{ semi: 5, fifth: -1 },
|
|
13610
|
+
// F
|
|
13611
|
+
{ semi: 8, fifth: 8 },
|
|
13612
|
+
// G#
|
|
13613
|
+
{ semi: 9, fifth: 3 },
|
|
13614
|
+
// A
|
|
13615
|
+
{ semi: 11, fifth: 5 }
|
|
13616
|
+
// B
|
|
13617
|
+
];
|
|
13618
|
+
var BLUES_SCALE = [
|
|
13619
|
+
{ semi: 0, fifth: 0 },
|
|
13620
|
+
// C
|
|
13621
|
+
{ semi: 3, fifth: -3 },
|
|
13622
|
+
// Eb
|
|
13623
|
+
{ semi: 5, fifth: -1 },
|
|
13624
|
+
// F
|
|
13625
|
+
{ semi: 6, fifth: -6 },
|
|
13626
|
+
// Gb(ブルーノート)
|
|
13627
|
+
{ semi: 7, fifth: 1 },
|
|
13628
|
+
// G
|
|
13629
|
+
{ semi: 10, fifth: -2 }
|
|
13630
|
+
// Bb
|
|
13631
|
+
];
|
|
13632
|
+
var RYUKYU_CENTER = {
|
|
13633
|
+
tonic: "C",
|
|
13634
|
+
half: "G",
|
|
13635
|
+
deceptive: "Em",
|
|
13636
|
+
tonicPattern: /^C(?![#b]|m)/,
|
|
13637
|
+
a: [
|
|
13638
|
+
["C", "F", "G", "C"],
|
|
13639
|
+
["C", "C", "F", "G"],
|
|
13640
|
+
["F", "G", "C", "C"],
|
|
13641
|
+
["C", "G", "F", "G"],
|
|
13642
|
+
["CM7", "F", "G", "C"],
|
|
13643
|
+
["C", "F", "C", "G"],
|
|
13644
|
+
["C", "Em", "F", "G"],
|
|
13645
|
+
["F", "C", "G", "C"]
|
|
13646
|
+
],
|
|
13647
|
+
b: [
|
|
13648
|
+
["F", "G", "Em", "C"],
|
|
13649
|
+
["F", "G", "C", "G"],
|
|
13650
|
+
["G", "F", "C", "C"],
|
|
13651
|
+
["FM7", "G", "Em", "F"],
|
|
13652
|
+
["C", "G", "F", "C"],
|
|
13653
|
+
["F", "Em", "F", "G"]
|
|
13654
|
+
],
|
|
13655
|
+
c: [
|
|
13656
|
+
["Em", "F", "G", "C"],
|
|
13657
|
+
["F", "C", "G", "Em"],
|
|
13658
|
+
["C", "Em", "F", "G"]
|
|
13659
|
+
]
|
|
13660
|
+
};
|
|
13661
|
+
var MIYAKOBUSHI_CENTER = {
|
|
13662
|
+
tonic: "Em",
|
|
13663
|
+
half: "Am",
|
|
13664
|
+
deceptive: "F",
|
|
13665
|
+
tonicPattern: /^E(?:m|sus)/,
|
|
13666
|
+
a: [
|
|
13667
|
+
["Em", "F", "Em", "Em"],
|
|
13668
|
+
["Esus4", "F", "Esus4", "Em"],
|
|
13669
|
+
["Em", "Am", "F", "Em"],
|
|
13670
|
+
["Am", "Em", "F", "Em"],
|
|
13671
|
+
["Em", "F", "Am", "Em"],
|
|
13672
|
+
["Em", "Em", "F", "F"],
|
|
13673
|
+
["Am", "F", "Em", "Em"],
|
|
13674
|
+
["Em", "FM7", "Am", "Em"]
|
|
13675
|
+
],
|
|
13676
|
+
b: [
|
|
13677
|
+
["F", "Am", "Em", "Em"],
|
|
13678
|
+
["Am", "F", "Em", "Em"],
|
|
13679
|
+
["F", "Em", "Am", "Em"],
|
|
13680
|
+
["FM7", "Am", "F", "Em"],
|
|
13681
|
+
["Am", "Em", "F", "Am"],
|
|
13682
|
+
["F", "Am", "F", "Em"]
|
|
13683
|
+
],
|
|
13684
|
+
c: [
|
|
13685
|
+
["Am", "Em", "F", "Am"],
|
|
13686
|
+
["F", "Am", "Esus4", "Em"],
|
|
13687
|
+
["Am", "F", "Em", "Em"]
|
|
13688
|
+
]
|
|
13689
|
+
};
|
|
13690
|
+
var RITSU_CENTER = {
|
|
13691
|
+
tonic: "Dsus4",
|
|
13692
|
+
half: "G",
|
|
13693
|
+
deceptive: "Em",
|
|
13694
|
+
tonicPattern: /^Dsus/,
|
|
13695
|
+
a: [
|
|
13696
|
+
["Dsus4", "G", "Dsus4", "Dsus4"],
|
|
13697
|
+
["Dsus4", "Em", "G", "Dsus4"],
|
|
13698
|
+
["G", "Dsus4", "Em", "Dsus4"],
|
|
13699
|
+
["Dsus4", "G", "Em", "G"],
|
|
13700
|
+
["Em", "G", "Dsus4", "Dsus4"],
|
|
13701
|
+
["Dsus4", "Em7", "G", "Dsus4"],
|
|
13702
|
+
["G", "Em", "Dsus4", "G"],
|
|
13703
|
+
["Dsus4", "Am", "G", "Dsus4"]
|
|
13704
|
+
],
|
|
13705
|
+
b: [
|
|
13706
|
+
["G", "Em", "Dsus4", "Dsus4"],
|
|
13707
|
+
["Em", "G", "Em", "Dsus4"],
|
|
13708
|
+
["G", "Am", "Em", "Dsus4"],
|
|
13709
|
+
["Em7", "G", "Dsus4", "Dsus4"],
|
|
13710
|
+
["Am", "G", "Em", "Dsus4"],
|
|
13711
|
+
["Dsus4", "Em", "G", "Em"]
|
|
13712
|
+
],
|
|
13713
|
+
c: [
|
|
13714
|
+
["Em", "Dsus4", "G", "Em"],
|
|
13715
|
+
["G", "Em7", "Am", "G"],
|
|
13716
|
+
["Am", "G", "Em", "Dsus4"]
|
|
13717
|
+
]
|
|
13718
|
+
};
|
|
13719
|
+
var HARMONIC_MINOR_CENTER = {
|
|
13720
|
+
tonic: "Am",
|
|
13721
|
+
half: "E7",
|
|
13722
|
+
deceptive: "F",
|
|
13723
|
+
tonicPattern: /^Am/,
|
|
13724
|
+
a: [
|
|
13725
|
+
["Am", "Dm", "E7", "Am"],
|
|
13726
|
+
// i-iv-V7-i。和声的短音階の基本形
|
|
13727
|
+
["Am", "F", "E7", "Am"],
|
|
13728
|
+
["Am", "E7", "Am", "Am"],
|
|
13729
|
+
["Dm", "E7", "Am", "Am"],
|
|
13730
|
+
["Am", "AmM7", "Dm", "E7"],
|
|
13731
|
+
// 主和音に導音を重ねたクリシェ
|
|
13732
|
+
["Am", "F", "Dm", "E7"],
|
|
13733
|
+
["F", "E7", "Am", "Am"],
|
|
13734
|
+
["Am", "Bm7-5", "E7", "Am"]
|
|
13735
|
+
],
|
|
13736
|
+
b: [
|
|
13737
|
+
["Dm", "E7", "Am", "Am"],
|
|
13738
|
+
["F", "E7", "Am", "E7"],
|
|
13739
|
+
["Dm7", "G#dim", "Am", "E7"],
|
|
13740
|
+
["F", "Dm", "E7", "Am"],
|
|
13741
|
+
["Am", "Dm", "Bm7-5", "E7"],
|
|
13742
|
+
["FM7", "E7", "Am", "Am"]
|
|
13743
|
+
],
|
|
13744
|
+
c: [
|
|
13745
|
+
["Dm", "Am", "Bm7-5", "E7"],
|
|
13746
|
+
["F", "C+", "Dm", "E7"],
|
|
13747
|
+
["Am", "F", "Dm", "E7"]
|
|
13748
|
+
]
|
|
13749
|
+
};
|
|
13750
|
+
var HIJAZ_CENTER = {
|
|
13751
|
+
tonic: "E",
|
|
13752
|
+
half: "F",
|
|
13753
|
+
deceptive: "Am",
|
|
13754
|
+
tonicPattern: /^E(?![#b]|m)/,
|
|
13755
|
+
a: [
|
|
13756
|
+
["E", "F", "E", "E"],
|
|
13757
|
+
// I-♭II。ヒジャーズの顔
|
|
13758
|
+
["E7", "F", "E", "E"],
|
|
13759
|
+
["Am", "F", "E", "E"],
|
|
13760
|
+
["E", "F", "Dm", "E"],
|
|
13761
|
+
["F", "E", "F", "E"],
|
|
13762
|
+
["Dm", "E", "F", "E"],
|
|
13763
|
+
["E7", "Am", "F", "E"],
|
|
13764
|
+
["E", "Dm", "F", "E"]
|
|
13765
|
+
],
|
|
13766
|
+
b: [
|
|
13767
|
+
["F", "E", "Am", "E"],
|
|
13768
|
+
["Dm", "C+", "F", "E"],
|
|
13769
|
+
["Am", "Dm", "F", "E"],
|
|
13770
|
+
["F", "Dm", "E", "E"],
|
|
13771
|
+
["E7", "F", "Dm", "E"],
|
|
13772
|
+
["Bm7-5", "E7", "Am", "E"]
|
|
13773
|
+
],
|
|
13774
|
+
c: [
|
|
13775
|
+
["Am", "Dm", "F", "E"],
|
|
13776
|
+
["Dm", "Am", "F", "E7"],
|
|
13777
|
+
["F", "C+", "Dm", "E"]
|
|
13778
|
+
]
|
|
13779
|
+
};
|
|
13780
|
+
var HUNGARIAN_CENTER = {
|
|
13781
|
+
tonic: "Am",
|
|
13782
|
+
half: "E",
|
|
13783
|
+
deceptive: "F",
|
|
13784
|
+
tonicPattern: /^Am/,
|
|
13785
|
+
a: [
|
|
13786
|
+
["Am", "E", "Am", "Am"],
|
|
13787
|
+
["Am", "F", "E", "Am"],
|
|
13788
|
+
["Am", "AmM7", "F", "E"],
|
|
13789
|
+
["F", "E", "Am", "Am"],
|
|
13790
|
+
["Am", "Fm", "E", "Am"],
|
|
13791
|
+
// ♭VIm。増2度を和音の側でも鳴らす
|
|
13792
|
+
["Am", "E", "F", "E"],
|
|
13793
|
+
["FM7", "E", "Am", "Am"],
|
|
13794
|
+
["Am", "C+", "F", "E"]
|
|
13795
|
+
],
|
|
13796
|
+
b: [
|
|
13797
|
+
["F", "E", "Am", "E"],
|
|
13798
|
+
["Fm", "E", "Am", "Am"],
|
|
13799
|
+
["Am", "F", "C+", "E"],
|
|
13800
|
+
["FM7", "Am", "F", "E"],
|
|
13801
|
+
["E", "F", "E", "Am"],
|
|
13802
|
+
["Am", "AmM7", "Fm", "E"]
|
|
13803
|
+
],
|
|
13804
|
+
c: [
|
|
13805
|
+
["F", "Am", "Fm", "E"],
|
|
13806
|
+
["C+", "F", "Am", "E"],
|
|
13807
|
+
["Am", "Fm", "F", "E"]
|
|
13808
|
+
]
|
|
13809
|
+
};
|
|
13810
|
+
var BLUES_CENTER = {
|
|
13811
|
+
tonic: "C7",
|
|
13812
|
+
half: "G7",
|
|
13813
|
+
deceptive: "F7",
|
|
13814
|
+
tonicPattern: /^C7/,
|
|
13815
|
+
a: [
|
|
13816
|
+
["C7", "C7", "C7", "C7"],
|
|
13817
|
+
// 12小節ブルースの1〜4小節
|
|
13818
|
+
["C7", "F7", "C7", "C7"],
|
|
13819
|
+
["C7", "C7", "F7", "F7"],
|
|
13820
|
+
["F7", "F7", "C7", "C7"],
|
|
13821
|
+
// 5〜8小節
|
|
13822
|
+
["C7", "F7", "C7", "G7"],
|
|
13823
|
+
["C7", "C7", "G7", "F7"],
|
|
13824
|
+
["C7", "F7", "G7", "C7"],
|
|
13825
|
+
["F7", "C7", "G7", "C7"]
|
|
13826
|
+
],
|
|
13827
|
+
b: [
|
|
13828
|
+
["F7", "F7", "C7", "C7"],
|
|
13829
|
+
["G7", "F7", "C7", "C7"],
|
|
13830
|
+
// 9〜12小節(ターンアラウンド)
|
|
13831
|
+
["F7", "G7", "C7", "C7"],
|
|
13832
|
+
["C7", "F7", "G7", "C7"],
|
|
13833
|
+
["F7", "C7", "G7", "F7"],
|
|
13834
|
+
["G7", "G7", "F7", "C7"]
|
|
13835
|
+
],
|
|
13836
|
+
c: [
|
|
13837
|
+
["G7", "F7", "C7", "G7"],
|
|
13838
|
+
["F7", "F7", "G7", "G7"],
|
|
13839
|
+
["C7", "C7", "F7", "G7"]
|
|
13840
|
+
]
|
|
13841
|
+
};
|
|
13842
|
+
var COMPOSE_SCALES = {
|
|
13843
|
+
yo: {
|
|
13844
|
+
id: "yo",
|
|
13845
|
+
label: "\u967D\u97F3\u968E\uFF08\u9577\u8ABF\u30DA\u30F3\u30BF\u30C8\u30CB\u30C3\u30AF\uFF09",
|
|
13846
|
+
tonic: 0,
|
|
13847
|
+
core: [0, 1, 2, 4, 5],
|
|
13848
|
+
// ド レ ミ ソ ラ
|
|
13849
|
+
minorish: false,
|
|
13850
|
+
strict: false,
|
|
13851
|
+
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"
|
|
13852
|
+
},
|
|
13853
|
+
minyo: {
|
|
13854
|
+
id: "minyo",
|
|
13855
|
+
label: "\u6C11\u8B21\u97F3\u968E\uFF08\u77ED\u8ABF\u30DA\u30F3\u30BF\u30C8\u30CB\u30C3\u30AF\uFF09",
|
|
13856
|
+
tonic: 5,
|
|
13857
|
+
core: [5, 0, 1, 2, 4],
|
|
13858
|
+
// ラ ド レ ミ ソ
|
|
13859
|
+
minorish: true,
|
|
13860
|
+
strict: false,
|
|
13861
|
+
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"
|
|
13862
|
+
},
|
|
13863
|
+
ritsu: {
|
|
13864
|
+
id: "ritsu",
|
|
13865
|
+
label: "\u5F8B\u97F3\u968E",
|
|
13866
|
+
tonic: 1,
|
|
13867
|
+
core: [1, 2, 4, 5, 6],
|
|
13868
|
+
// レ ミ ソ ラ シ
|
|
13869
|
+
minorish: true,
|
|
13870
|
+
strict: true,
|
|
13871
|
+
center: RITSU_CENTER,
|
|
13872
|
+
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"
|
|
13873
|
+
},
|
|
13874
|
+
miyakobushi: {
|
|
13875
|
+
id: "miyakobushi",
|
|
13876
|
+
label: "\u90FD\u7BC0\u97F3\u968E\uFF08\u9670\u97F3\u968E\uFF09",
|
|
13877
|
+
tonic: 2,
|
|
13878
|
+
core: [2, 3, 5, 6, 0],
|
|
13879
|
+
// ミ ファ ラ シ ド
|
|
13880
|
+
minorish: true,
|
|
13881
|
+
strict: true,
|
|
13882
|
+
center: MIYAKOBUSHI_CENTER,
|
|
13883
|
+
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"
|
|
13884
|
+
},
|
|
13885
|
+
ryukyu: {
|
|
13886
|
+
id: "ryukyu",
|
|
13887
|
+
label: "\u7409\u7403\u97F3\u968E",
|
|
13888
|
+
tonic: 0,
|
|
13889
|
+
core: [0, 2, 3, 4, 6],
|
|
13890
|
+
// ド ミ ファ ソ シ
|
|
13891
|
+
minorish: false,
|
|
13892
|
+
strict: true,
|
|
13893
|
+
center: RYUKYU_CENTER,
|
|
13894
|
+
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"
|
|
13895
|
+
},
|
|
13896
|
+
dorian: {
|
|
13897
|
+
id: "dorian",
|
|
13898
|
+
label: "\u30C9\u30EA\u30A2\u30F3",
|
|
13899
|
+
tonic: 1,
|
|
13900
|
+
core: [1, 3, 4, 5, 0],
|
|
13901
|
+
// レ ファ ソ ラ ド
|
|
13902
|
+
minorish: true,
|
|
13903
|
+
strict: false,
|
|
13904
|
+
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"
|
|
13905
|
+
},
|
|
13906
|
+
phrygian: {
|
|
13907
|
+
id: "phrygian",
|
|
13908
|
+
label: "\u30D5\u30EA\u30B8\u30A2\u30F3",
|
|
13909
|
+
tonic: 2,
|
|
13910
|
+
core: [2, 3, 5, 6, 1],
|
|
13911
|
+
// ミ ファ ラ シ レ
|
|
13912
|
+
minorish: true,
|
|
13913
|
+
strict: false,
|
|
13914
|
+
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"
|
|
13915
|
+
},
|
|
13916
|
+
lydian: {
|
|
13917
|
+
id: "lydian",
|
|
13918
|
+
label: "\u30EA\u30C7\u30A3\u30A2\u30F3",
|
|
13919
|
+
tonic: 3,
|
|
13920
|
+
core: [3, 4, 6, 0, 2],
|
|
13921
|
+
// ファ ソ シ ド ミ
|
|
13922
|
+
minorish: false,
|
|
13923
|
+
strict: false,
|
|
13924
|
+
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"
|
|
13925
|
+
},
|
|
13926
|
+
mixolydian: {
|
|
13927
|
+
id: "mixolydian",
|
|
13928
|
+
label: "\u30DF\u30AF\u30BD\u30EA\u30C7\u30A3\u30A2\u30F3",
|
|
13929
|
+
tonic: 4,
|
|
13930
|
+
core: [4, 5, 0, 1, 3],
|
|
13931
|
+
// ソ ラ ド レ ファ
|
|
13932
|
+
minorish: false,
|
|
13933
|
+
strict: false,
|
|
13934
|
+
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"
|
|
13935
|
+
},
|
|
13936
|
+
harmonic_minor: {
|
|
13937
|
+
id: "harmonic_minor",
|
|
13938
|
+
label: "\u548C\u58F0\u7684\u77ED\u97F3\u968E",
|
|
13939
|
+
tonic: 5,
|
|
13940
|
+
parent: HARMONIC_MINOR_SCALE,
|
|
13941
|
+
core: [5, 0, 1, 2, 4],
|
|
13942
|
+
// ラ ド レ ミ ソ♯
|
|
13943
|
+
minorish: true,
|
|
13944
|
+
strict: false,
|
|
13945
|
+
center: HARMONIC_MINOR_CENTER,
|
|
13946
|
+
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"
|
|
13947
|
+
},
|
|
13948
|
+
hijaz: {
|
|
13949
|
+
id: "hijaz",
|
|
13950
|
+
label: "\u30D2\u30B8\u30E3\u30FC\u30BA\uFF08\u30D5\u30EA\u30B8\u30A2\u30F3\u30FB\u30C9\u30DF\u30CA\u30F3\u30C8\uFF09",
|
|
13951
|
+
tonic: 2,
|
|
13952
|
+
parent: HARMONIC_MINOR_SCALE,
|
|
13953
|
+
core: [2, 3, 4, 5, 6],
|
|
13954
|
+
// ミ ファ ソ♯ ラ シ
|
|
13955
|
+
minorish: false,
|
|
13956
|
+
strict: false,
|
|
13957
|
+
center: HIJAZ_CENTER,
|
|
13958
|
+
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"
|
|
13959
|
+
},
|
|
13960
|
+
hungarian: {
|
|
13961
|
+
id: "hungarian",
|
|
13962
|
+
label: "\u30CF\u30F3\u30AC\u30EA\u30A2\u30F3\u30FB\u30DE\u30A4\u30CA\u30FC\uFF08\u30B8\u30D7\u30B7\u30FC\uFF09",
|
|
13963
|
+
tonic: 5,
|
|
13964
|
+
parent: HUNGARIAN_SCALE,
|
|
13965
|
+
core: [5, 0, 1, 2, 4],
|
|
13966
|
+
// ラ ド レ♯ ミ ソ♯
|
|
13967
|
+
minorish: true,
|
|
13968
|
+
strict: false,
|
|
13969
|
+
center: HUNGARIAN_CENTER,
|
|
13970
|
+
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"
|
|
13971
|
+
},
|
|
13972
|
+
blues: {
|
|
13973
|
+
id: "blues",
|
|
13974
|
+
label: "\u30D6\u30EB\u30FC\u30B9\u97F3\u968E",
|
|
13975
|
+
tonic: 0,
|
|
13976
|
+
parent: BLUES_SCALE,
|
|
13977
|
+
core: [0, 1, 2, 4, 5],
|
|
13978
|
+
// ド ミ♭ ファ ソ シ♭
|
|
13979
|
+
minorish: true,
|
|
13980
|
+
strict: true,
|
|
13981
|
+
center: BLUES_CENTER,
|
|
13982
|
+
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"
|
|
13983
|
+
}
|
|
13984
|
+
};
|
|
13985
|
+
var COMPOSE_SCALE_IDS = Object.keys(
|
|
13986
|
+
COMPOSE_SCALES
|
|
13987
|
+
);
|
|
13988
|
+
var TONIC_CENTERS = {
|
|
13989
|
+
// --- レ(律・ドリアン) ---
|
|
13990
|
+
1: {
|
|
13991
|
+
tonic: "Dm",
|
|
13992
|
+
half: "G",
|
|
13993
|
+
deceptive: "F",
|
|
13994
|
+
tonicPattern: /^Dm/,
|
|
13995
|
+
a: [
|
|
13996
|
+
["Dm", "G", "Dm", "Dm"],
|
|
13997
|
+
// i-IV の往復。ドリアンの顔
|
|
13998
|
+
["Dm", "Am", "G", "Dm"],
|
|
13999
|
+
["Dm", "C", "G", "Dm"],
|
|
14000
|
+
["Dm7", "G", "Dm7", "C"],
|
|
14001
|
+
["Dm", "F", "C", "G"],
|
|
14002
|
+
["Dm", "Em", "F", "G"],
|
|
14003
|
+
["Dm", "G", "F", "C"],
|
|
14004
|
+
["Dm7", "Em7", "FM7", "G"]
|
|
14005
|
+
],
|
|
14006
|
+
b: [
|
|
14007
|
+
["F", "G", "Am", "Dm"],
|
|
14008
|
+
["C", "G", "Dm", "Dm"],
|
|
14009
|
+
["G", "F", "C", "Dm"],
|
|
14010
|
+
["Am", "G", "F", "Dm"],
|
|
14011
|
+
["FM7", "G", "Em7", "Dm7"],
|
|
14012
|
+
["Dm", "G", "C", "Am"]
|
|
14013
|
+
],
|
|
14014
|
+
c: [
|
|
14015
|
+
["Am", "Dm", "G", "C"],
|
|
14016
|
+
["F", "Em", "Dm", "G"],
|
|
14017
|
+
["Dm", "Am", "Em", "G"]
|
|
14018
|
+
]
|
|
14019
|
+
},
|
|
14020
|
+
// --- ミ(都節・フリジアン) ---
|
|
14021
|
+
2: {
|
|
14022
|
+
tonic: "Em",
|
|
14023
|
+
half: "Am",
|
|
14024
|
+
deceptive: "C",
|
|
14025
|
+
tonicPattern: /^Em/,
|
|
14026
|
+
a: [
|
|
14027
|
+
["Em", "F", "Em", "Em"],
|
|
14028
|
+
// i-♭II。フリジアン/都節の顔
|
|
14029
|
+
["Em", "Am", "F", "Em"],
|
|
14030
|
+
["Am", "Em", "F", "Em"],
|
|
14031
|
+
["Em", "F", "G", "Em"],
|
|
14032
|
+
["Em", "Em", "F", "F"],
|
|
14033
|
+
["Em", "C", "F", "Em"],
|
|
14034
|
+
["Am", "F", "Em", "Em"],
|
|
14035
|
+
["Em7", "FM7", "Em7", "Am7"]
|
|
14036
|
+
],
|
|
14037
|
+
b: [
|
|
14038
|
+
["F", "G", "Am", "Em"],
|
|
14039
|
+
["Am", "G", "F", "Em"],
|
|
14040
|
+
["F", "Em", "Am", "Em"],
|
|
14041
|
+
["C", "F", "Em", "Em"],
|
|
14042
|
+
["FM7", "G", "Em7", "Am"],
|
|
14043
|
+
["Am", "Em", "F", "G"]
|
|
14044
|
+
],
|
|
14045
|
+
c: [
|
|
14046
|
+
["Am", "Em", "F", "C"],
|
|
14047
|
+
["C", "G", "Am", "Em"],
|
|
14048
|
+
["F", "C", "Am", "Em"]
|
|
14049
|
+
]
|
|
14050
|
+
},
|
|
14051
|
+
// --- ファ(リディアン) ---
|
|
14052
|
+
3: {
|
|
14053
|
+
tonic: "FM7",
|
|
14054
|
+
half: "C",
|
|
14055
|
+
deceptive: "Dm",
|
|
14056
|
+
tonicPattern: /^F(?![#b]|m)/,
|
|
14057
|
+
a: [
|
|
14058
|
+
["FM7", "G", "FM7", "FM7"],
|
|
14059
|
+
// I-II。リディアンの顔(♯4 が G の3度に居る)
|
|
14060
|
+
["FM7", "G", "Em", "Am"],
|
|
14061
|
+
["F", "G", "C", "F"],
|
|
14062
|
+
["FM7", "G", "Am", "F"],
|
|
14063
|
+
["F", "C", "G", "F"],
|
|
14064
|
+
["FM7", "Em7", "Dm7", "G"],
|
|
14065
|
+
["F", "G", "F", "C"],
|
|
14066
|
+
["FM7", "G", "Dm7", "F"]
|
|
14067
|
+
],
|
|
14068
|
+
b: [
|
|
14069
|
+
["G", "F", "C", "F"],
|
|
14070
|
+
["Am", "G", "FM7", "FM7"],
|
|
14071
|
+
["C", "G", "Am", "F"],
|
|
14072
|
+
["G", "Em", "Am", "F"],
|
|
14073
|
+
["Dm7", "G", "FM7", "FM7"],
|
|
14074
|
+
["FM7", "G", "Em7", "F"]
|
|
14075
|
+
],
|
|
14076
|
+
c: [
|
|
14077
|
+
["Dm", "Am", "F", "G"],
|
|
14078
|
+
["Am", "Em", "F", "G"],
|
|
14079
|
+
["C", "Am", "Dm", "F"]
|
|
14080
|
+
]
|
|
14081
|
+
},
|
|
14082
|
+
// --- ソ(ミクソリディアン) ---
|
|
14083
|
+
4: {
|
|
14084
|
+
tonic: "G",
|
|
14085
|
+
half: "Dm",
|
|
14086
|
+
deceptive: "Em",
|
|
14087
|
+
tonicPattern: /^G(?![#b]|m)/,
|
|
14088
|
+
a: [
|
|
14089
|
+
["G", "F", "C", "G"],
|
|
14090
|
+
// I-♭VII-IV。ミクソリディアンの顔
|
|
14091
|
+
["G", "C", "F", "G"],
|
|
14092
|
+
["G", "F", "G", "G"],
|
|
14093
|
+
["C", "G", "F", "G"],
|
|
14094
|
+
["G", "Dm", "F", "G"],
|
|
14095
|
+
["G", "Am", "F", "G"],
|
|
14096
|
+
["G", "F", "Dm", "C"],
|
|
14097
|
+
["G", "C", "G", "F"]
|
|
14098
|
+
],
|
|
14099
|
+
b: [
|
|
14100
|
+
["F", "C", "G", "G"],
|
|
14101
|
+
["Am", "F", "C", "G"],
|
|
14102
|
+
["C", "Dm", "F", "G"],
|
|
14103
|
+
["Em", "F", "C", "G"],
|
|
14104
|
+
["F", "G", "Am", "G"],
|
|
14105
|
+
["Dm7", "F", "C", "G"]
|
|
14106
|
+
],
|
|
14107
|
+
c: [
|
|
14108
|
+
["Am", "Em", "F", "G"],
|
|
14109
|
+
["C", "Am", "Dm", "G"],
|
|
14110
|
+
["Em", "Am", "F", "C"]
|
|
14111
|
+
]
|
|
14112
|
+
}
|
|
14113
|
+
};
|
|
14114
|
+
var scaleDegrees = (scale) => scale.parent ?? MAJOR_SCALE2;
|
|
14115
|
+
var scaleSize = (scale) => scaleDegrees(scale).length;
|
|
14116
|
+
var degreeToPitch = (scale, degree) => {
|
|
14117
|
+
const list = scaleDegrees(scale);
|
|
14118
|
+
const size = list.length;
|
|
14119
|
+
const index = (degree % size + size) % size;
|
|
14120
|
+
const octave = Math.floor(degree / size);
|
|
14121
|
+
const d = list[index];
|
|
14122
|
+
return { semi: d.semi + octave * 12, fifth: d.fifth };
|
|
14123
|
+
};
|
|
14124
|
+
var semitoneToDegree = (scale, semi) => {
|
|
14125
|
+
const list = scaleDegrees(scale);
|
|
14126
|
+
const octave = Math.floor(semi / 12);
|
|
14127
|
+
const within = semi - octave * 12;
|
|
14128
|
+
let best = 0;
|
|
14129
|
+
let bestDist = Number.POSITIVE_INFINITY;
|
|
14130
|
+
for (let i2 = 0; i2 < list.length; i2++) {
|
|
14131
|
+
const dist = Math.abs(list[i2].semi - within);
|
|
14132
|
+
if (dist < bestDist) {
|
|
14133
|
+
bestDist = dist;
|
|
14134
|
+
best = i2;
|
|
14135
|
+
}
|
|
14136
|
+
}
|
|
14137
|
+
return octave * list.length + best;
|
|
14138
|
+
};
|
|
14139
|
+
var walk = (scale, semi, delta) => degreeToPitch(scale, semitoneToDegree(scale, semi) + delta).semi;
|
|
14140
|
+
var scaleFifth = (scale, semi) => degreeToPitch(scale, semitoneToDegree(scale, semi)).fifth;
|
|
14141
|
+
var SCALE_PCS = /* @__PURE__ */ new Map();
|
|
14142
|
+
var scalePcs = (scale) => {
|
|
14143
|
+
const hit = SCALE_PCS.get(scale.id);
|
|
14144
|
+
if (hit) return hit;
|
|
14145
|
+
const set = new Set(
|
|
14146
|
+
scaleDegrees(scale).map((d) => (d.semi % 12 + 12) % 12)
|
|
14147
|
+
);
|
|
14148
|
+
SCALE_PCS.set(scale.id, set);
|
|
14149
|
+
return set;
|
|
14150
|
+
};
|
|
14151
|
+
var CORE_SORTED = /* @__PURE__ */ new Map();
|
|
14152
|
+
var sortedCore = (scale) => {
|
|
14153
|
+
const hit = CORE_SORTED.get(scale.id);
|
|
14154
|
+
if (hit) return hit;
|
|
14155
|
+
const sorted = [...scale.core].sort((a, b) => a - b);
|
|
14156
|
+
CORE_SORTED.set(scale.id, sorted);
|
|
14157
|
+
return sorted;
|
|
14158
|
+
};
|
|
14159
|
+
var CORE_PCS = /* @__PURE__ */ new Map();
|
|
14160
|
+
var corePcs = (scale) => {
|
|
14161
|
+
const hit = CORE_PCS.get(scale.id);
|
|
14162
|
+
if (hit) return hit;
|
|
14163
|
+
const list = scaleDegrees(scale);
|
|
14164
|
+
const set = new Set(scale.core.map((d) => (list[d].semi % 12 + 12) % 12));
|
|
14165
|
+
CORE_PCS.set(scale.id, set);
|
|
14166
|
+
return set;
|
|
14167
|
+
};
|
|
14168
|
+
var isCoreDegree = (scale, degree) => {
|
|
14169
|
+
const size = scaleSize(scale);
|
|
14170
|
+
return sortedCore(scale).includes((degree % size + size) % size);
|
|
14171
|
+
};
|
|
14172
|
+
var coreToDegree = (scale, step) => {
|
|
14173
|
+
const sorted = sortedCore(scale);
|
|
14174
|
+
const n = sorted.length;
|
|
14175
|
+
const index = (step % n + n) % n;
|
|
14176
|
+
const octave = Math.floor(step / n);
|
|
14177
|
+
return sorted[index] + octave * scaleSize(scale);
|
|
14178
|
+
};
|
|
14179
|
+
var degreeToCore = (scale, degree) => {
|
|
14180
|
+
const sorted = sortedCore(scale);
|
|
14181
|
+
const size = scaleSize(scale);
|
|
14182
|
+
const index = (degree % size + size) % size;
|
|
14183
|
+
const octave = Math.floor(degree / size);
|
|
14184
|
+
let best = 0;
|
|
14185
|
+
let bestDist = Number.POSITIVE_INFINITY;
|
|
14186
|
+
for (let i2 = 0; i2 < sorted.length; i2++) {
|
|
14187
|
+
const dist = Math.abs(sorted[i2] - index);
|
|
14188
|
+
if (dist < bestDist) {
|
|
14189
|
+
bestDist = dist;
|
|
14190
|
+
best = i2;
|
|
14191
|
+
}
|
|
14192
|
+
}
|
|
14193
|
+
return octave * sorted.length + best;
|
|
14194
|
+
};
|
|
14195
|
+
var isOutsideCore = (scale, semi) => scale.strict ? !corePcs(scale).has((semi % 12 + 12) % 12) : !isCoreDegree(scale, semitoneToDegree(scale, semi));
|
|
14196
|
+
var resolveComposeScale = (choice, minorKey, rnd = Math.random) => {
|
|
14197
|
+
const c = (choice ?? "").trim() || "auto";
|
|
14198
|
+
const hit = COMPOSE_SCALES[c];
|
|
14199
|
+
if (hit) return hit;
|
|
14200
|
+
if (c === "any")
|
|
14201
|
+
return COMPOSE_SCALES[COMPOSE_SCALE_IDS[Math.floor(rnd() * COMPOSE_SCALE_IDS.length)] ?? "yo"];
|
|
14202
|
+
return COMPOSE_SCALES[minorKey ? "minyo" : "yo"];
|
|
14203
|
+
};
|
|
14204
|
+
var getComposeScaleDescription = (choice) => {
|
|
14205
|
+
const hit = COMPOSE_SCALES[choice];
|
|
14206
|
+
if (hit) return hit.description;
|
|
14207
|
+
if (choice === "any")
|
|
14208
|
+
return `${COMPOSE_SCALE_IDS.length}\u3064\u306E\u97F3\u968E\u304B\u3089\u30E9\u30F3\u30C0\u30E0\u306B\u62BD\u9078\u3057\u307E\u3059`;
|
|
14209
|
+
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";
|
|
14210
|
+
};
|
|
14211
|
+
var resolveCenter = (scale) => scale.center ?? TONIC_CENTERS[scale.tonic] ?? null;
|
|
14212
|
+
|
|
13463
14213
|
// src/compose-sections.ts
|
|
13464
14214
|
var SECTION_LABELS = {
|
|
13465
14215
|
intro: "\u30A4\u30F3\u30C8\u30ED",
|
|
@@ -13695,6 +14445,7 @@ var sectionAt = (plan, bar) => {
|
|
|
13695
14445
|
// src/compose.ts
|
|
13696
14446
|
var STEP_SEMITONES = 2;
|
|
13697
14447
|
var MAX_LEAP_SEMITONES = 10;
|
|
14448
|
+
var LEAP_CEILINGS = [7, 8, 9, 10, 10, 12, 14, 16];
|
|
13698
14449
|
var MAX_BAR_LEAP_SEMITONES = 10;
|
|
13699
14450
|
var HARD = {
|
|
13700
14451
|
/** メロディが1音も無い、音域が半音未満(同じ音を並べただけ)。 */
|
|
@@ -13753,13 +14504,16 @@ var WEIGHTS = {
|
|
|
13753
14504
|
// --- 直近に作った曲と違うか ---
|
|
13754
14505
|
novelty: 1.2
|
|
13755
14506
|
};
|
|
14507
|
+
var DEVIATION_BUDGET = CORPUS_DEVIATION_BUDGET;
|
|
14508
|
+
var BUDGETED_KEYS = new Set(CORPUS_PROFILE_KEYS);
|
|
13756
14509
|
var HAND_BANDS = {
|
|
13757
14510
|
/** サブメロの音数/小節。少なすぎると「置いただけ」、多すぎるとメロディを食う。 */
|
|
13758
14511
|
subDensity: [0.5, 1.8, 4.5, 8],
|
|
13759
14512
|
complementarity: [0.05, 0.25, 0.7, 0.95],
|
|
13760
14513
|
climaxPeaks: [0, 1, 2, 5]
|
|
13761
14514
|
};
|
|
13762
|
-
var DRAW_COUNT =
|
|
14515
|
+
var DRAW_COUNT = 12;
|
|
14516
|
+
var SELECT_TEMPERATURE = 0.05;
|
|
13763
14517
|
var BASE_STEPS_PER_BAR = 192;
|
|
13764
14518
|
var WHOLE = 192;
|
|
13765
14519
|
var DOT_HALF = 144;
|
|
@@ -13884,65 +14638,6 @@ var BPM_CHOICES = [
|
|
|
13884
14638
|
180,
|
|
13885
14639
|
185
|
|
13886
14640
|
];
|
|
13887
|
-
var MAJOR_SCALE2 = [
|
|
13888
|
-
{ semi: 0, fifth: 0 },
|
|
13889
|
-
// C
|
|
13890
|
-
{ semi: 2, fifth: 2 },
|
|
13891
|
-
// D
|
|
13892
|
-
{ semi: 4, fifth: 4 },
|
|
13893
|
-
// E
|
|
13894
|
-
{ semi: 5, fifth: -1 },
|
|
13895
|
-
// F
|
|
13896
|
-
{ semi: 7, fifth: 1 },
|
|
13897
|
-
// G
|
|
13898
|
-
{ semi: 9, fifth: 3 },
|
|
13899
|
-
// A
|
|
13900
|
-
{ semi: 11, fifth: 5 }
|
|
13901
|
-
// B
|
|
13902
|
-
];
|
|
13903
|
-
var degreeToPitch = (degree) => {
|
|
13904
|
-
const index = (degree % 7 + 7) % 7;
|
|
13905
|
-
const octave = Math.floor(degree / 7);
|
|
13906
|
-
const d = MAJOR_SCALE2[index];
|
|
13907
|
-
return { semi: d.semi + octave * 12, fifth: d.fifth };
|
|
13908
|
-
};
|
|
13909
|
-
var semitoneToDegree = (semi) => {
|
|
13910
|
-
const octave = Math.floor(semi / 12);
|
|
13911
|
-
const within = semi - octave * 12;
|
|
13912
|
-
let best = 0;
|
|
13913
|
-
let bestDist = Number.POSITIVE_INFINITY;
|
|
13914
|
-
for (let i2 = 0; i2 < MAJOR_SCALE2.length; i2++) {
|
|
13915
|
-
const dist = Math.abs(MAJOR_SCALE2[i2].semi - within);
|
|
13916
|
-
if (dist < bestDist) {
|
|
13917
|
-
bestDist = dist;
|
|
13918
|
-
best = i2;
|
|
13919
|
-
}
|
|
13920
|
-
}
|
|
13921
|
-
return octave * 7 + best;
|
|
13922
|
-
};
|
|
13923
|
-
var walk = (semi, delta) => degreeToPitch(semitoneToDegree(semi) + delta).semi;
|
|
13924
|
-
var NON_PENTATONIC_DEGREES = /* @__PURE__ */ new Set([3, 6]);
|
|
13925
|
-
var isNonPentatonic = (semi) => NON_PENTATONIC_DEGREES.has((semitoneToDegree(semi) % 7 + 7) % 7);
|
|
13926
|
-
var PENTATONIC_DEGREES = [0, 1, 2, 4, 5];
|
|
13927
|
-
var pentaToDegree = (penta) => {
|
|
13928
|
-
const index = (penta % 5 + 5) % 5;
|
|
13929
|
-
const octave = Math.floor(penta / 5);
|
|
13930
|
-
return PENTATONIC_DEGREES[index] + octave * 7;
|
|
13931
|
-
};
|
|
13932
|
-
var degreeToPenta = (degree) => {
|
|
13933
|
-
const index = (degree % 7 + 7) % 7;
|
|
13934
|
-
const octave = Math.floor(degree / 7);
|
|
13935
|
-
let best = 0;
|
|
13936
|
-
let bestDist = Number.POSITIVE_INFINITY;
|
|
13937
|
-
for (let i2 = 0; i2 < PENTATONIC_DEGREES.length; i2++) {
|
|
13938
|
-
const dist = Math.abs(PENTATONIC_DEGREES[i2] - index);
|
|
13939
|
-
if (dist < bestDist) {
|
|
13940
|
-
bestDist = dist;
|
|
13941
|
-
best = i2;
|
|
13942
|
-
}
|
|
13943
|
-
}
|
|
13944
|
-
return octave * 5 + best;
|
|
13945
|
-
};
|
|
13946
14641
|
var SECTION_A_PROGRESSIONS = [
|
|
13947
14642
|
["C", "G", "Am", "Em7"],
|
|
13948
14643
|
// カノン進行の前半
|
|
@@ -14061,6 +14756,22 @@ var SECTION_DECEPTIVE_DERIVATIONS = [
|
|
|
14061
14756
|
(a, t) => [a[0], "Dm7", "G7", t === "Am" ? "FM7" : "Am7"],
|
|
14062
14757
|
(a, t) => [a[0], "F", "G7", t === "Am" ? "F" : "Am7"]
|
|
14063
14758
|
];
|
|
14759
|
+
var MODAL_FULL_DERIVATIONS = [
|
|
14760
|
+
(a, c) => [a[0], a[1], c.half, c.tonic],
|
|
14761
|
+
(a, c) => [a[0], c.half, a[2], c.tonic],
|
|
14762
|
+
(a, c) => [a[0], a[1], a[2], c.tonic],
|
|
14763
|
+
(a, c) => [c.tonic, c.half, a[2], c.tonic]
|
|
14764
|
+
];
|
|
14765
|
+
var MODAL_HALF_DERIVATIONS = [
|
|
14766
|
+
(a, c) => [a[0], a[1], a[2], c.half],
|
|
14767
|
+
(a, c) => [a[0], a[1], c.tonic, c.half],
|
|
14768
|
+
(a, c) => [a[0], c.tonic, a[2], c.half]
|
|
14769
|
+
];
|
|
14770
|
+
var MODAL_DECEPTIVE_DERIVATIONS = [
|
|
14771
|
+
(a, c) => [a[0], a[1], c.half, c.deceptive],
|
|
14772
|
+
(a, c) => [a[0], c.half, a[2], c.deceptive],
|
|
14773
|
+
(a, c) => [a[0], a[1], a[2], c.deceptive]
|
|
14774
|
+
];
|
|
14064
14775
|
var MODAL_BORROW = {
|
|
14065
14776
|
F: "Fm",
|
|
14066
14777
|
// IV → IVm(サブドミナントマイナー。いちばん定番)
|
|
@@ -14518,6 +15229,14 @@ for (const c of [...MOTIF_CELLS, ...RHYTHM_CELLS]) {
|
|
|
14518
15229
|
const key = onsetKeyOf(c.value);
|
|
14519
15230
|
cellEntryCount.set(key, (cellEntryCount.get(key) ?? 0) + 1);
|
|
14520
15231
|
}
|
|
15232
|
+
var resolveMelodyForm = (choice, rnd) => {
|
|
15233
|
+
const c = (choice ?? "").trim() || "auto";
|
|
15234
|
+
if (c === "motif" || c === "ostinato" || c === "through") return c;
|
|
15235
|
+
const r = rnd();
|
|
15236
|
+
if (r < 0.25) return "ostinato";
|
|
15237
|
+
if (r < 0.4) return "through";
|
|
15238
|
+
return "motif";
|
|
15239
|
+
};
|
|
14521
15240
|
var groovyCells = (cells, groove, rnd) => {
|
|
14522
15241
|
const hasSixteenth = (c) => c.value.some((v) => Math.abs(v) <= SIXTEENTH);
|
|
14523
15242
|
if (groove === "eighth") {
|
|
@@ -14651,7 +15370,7 @@ var nearestChordTone = (targetSemi, tones, minWeight, preferColor = false) => {
|
|
|
14651
15370
|
var MELODY_LOW = 60;
|
|
14652
15371
|
var MELODY_HIGH = 81;
|
|
14653
15372
|
var MELODY_CENTER = (MELODY_LOW + MELODY_HIGH) / 2;
|
|
14654
|
-
var harmonyPitch = (melodySemi, tones, prevHarmony, offset, parallel, against) => {
|
|
15373
|
+
var harmonyPitch = (scale, melodySemi, tones, prevHarmony, offset, parallel, against) => {
|
|
14655
15374
|
const lo = Math.max(-12, Math.min(offset, 0) - 7);
|
|
14656
15375
|
const hi = Math.min(12, Math.max(offset, 0) + 7);
|
|
14657
15376
|
let best = null;
|
|
@@ -14669,7 +15388,8 @@ var harmonyPitch = (melodySemi, tones, prevHarmony, offset, parallel, against) =
|
|
|
14669
15388
|
const g = Math.abs(semi - against) % 12;
|
|
14670
15389
|
clash = g === 3 || g === 4 || g === 8 || g === 9 || g === 7 ? 0 : g === 0 ? 0.5 : 1.2;
|
|
14671
15390
|
}
|
|
14672
|
-
const
|
|
15391
|
+
const offCore = scale.strict && isOutsideCore(scale, semi) ? 1.5 : 0;
|
|
15392
|
+
const cost = stay + clash + offCore + Math.abs(delta - offset) * (parallel ? 1.4 : 0.7) + (3 - tone.weight) * 0.4;
|
|
14673
15393
|
if (cost < bestCost) {
|
|
14674
15394
|
bestCost = cost;
|
|
14675
15395
|
best = { semi, fifth: tone.fifth };
|
|
@@ -14692,7 +15412,7 @@ var clampSemi = (semi, low, high) => {
|
|
|
14692
15412
|
while (s > high) s -= 12;
|
|
14693
15413
|
return s;
|
|
14694
15414
|
};
|
|
14695
|
-
var leapTarget = (from, tones, rnd) => {
|
|
15415
|
+
var leapTarget = (from, tones, rnd, maxLeap = MAX_LEAP_SEMITONES) => {
|
|
14696
15416
|
const candidates = [];
|
|
14697
15417
|
for (const tone of tones) {
|
|
14698
15418
|
const base = pitchClass(tone.semi);
|
|
@@ -14700,7 +15420,7 @@ var leapTarget = (from, tones, rnd) => {
|
|
|
14700
15420
|
const semi = base + oct * 12;
|
|
14701
15421
|
if (semi < MELODY_LOW || semi > MELODY_HIGH) continue;
|
|
14702
15422
|
const gap = Math.abs(semi - from);
|
|
14703
|
-
if (gap >= 3 && gap <=
|
|
15423
|
+
if (gap >= 3 && gap <= maxLeap) candidates.push(semi);
|
|
14704
15424
|
}
|
|
14705
15425
|
}
|
|
14706
15426
|
if (candidates.length === 0) return null;
|
|
@@ -14714,40 +15434,43 @@ var leapTarget = (from, tones, rnd) => {
|
|
|
14714
15434
|
];
|
|
14715
15435
|
return pick(weighted.length > 0 ? weighted : candidates, rnd);
|
|
14716
15436
|
};
|
|
14717
|
-
var landOn = (degrees, scaleIndex) => {
|
|
15437
|
+
var landOn = (scale, degrees, scaleIndex) => {
|
|
14718
15438
|
if (degrees.length === 0) return;
|
|
15439
|
+
const size = scaleSize(scale);
|
|
14719
15440
|
const last = degrees[degrees.length - 1];
|
|
14720
|
-
const index = (last %
|
|
15441
|
+
const index = (last % size + size) % size;
|
|
14721
15442
|
let delta = scaleIndex - index;
|
|
14722
|
-
if (delta >
|
|
14723
|
-
if (delta < -
|
|
15443
|
+
if (delta > size / 2) delta -= size;
|
|
15444
|
+
if (delta < -size / 2) delta += size;
|
|
14724
15445
|
degrees[degrees.length - 1] = last + delta;
|
|
14725
15446
|
};
|
|
14726
|
-
var landPitch = (pitches, scaleIndex) => {
|
|
15447
|
+
var landPitch = (scale, pitches, scaleIndex) => {
|
|
14727
15448
|
if (pitches.length === 0) return;
|
|
15449
|
+
const size = scaleSize(scale);
|
|
14728
15450
|
const last = pitches[pitches.length - 1];
|
|
14729
|
-
const degree = semitoneToDegree(last);
|
|
14730
|
-
const index = (degree %
|
|
15451
|
+
const degree = semitoneToDegree(scale, last);
|
|
15452
|
+
const index = (degree % size + size) % size;
|
|
14731
15453
|
let delta = scaleIndex - index;
|
|
14732
|
-
if (delta >
|
|
14733
|
-
if (delta < -
|
|
15454
|
+
if (delta > size / 2) delta -= size;
|
|
15455
|
+
if (delta < -size / 2) delta += size;
|
|
14734
15456
|
pitches[pitches.length - 1] = clampSemi(
|
|
14735
|
-
degreeToPitch(degree + delta).semi,
|
|
15457
|
+
degreeToPitch(scale, degree + delta).semi,
|
|
14736
15458
|
MELODY_LOW,
|
|
14737
15459
|
MELODY_HIGH
|
|
14738
15460
|
);
|
|
14739
15461
|
};
|
|
14740
|
-
var barDegrees = (role, slots, tones, style, motifContour, startDegree, contourOffset, repeatShift, barHeadWeight, preferColor, quarterSteps, rnd) => {
|
|
15462
|
+
var barDegrees = (role, slots, tones, style, scale, motifContour, startDegree, contourOffset, repeatShift, barHeadWeight, preferColor, quarterSteps, rnd) => {
|
|
14741
15463
|
const noteCount = slots.length;
|
|
14742
15464
|
const out = [];
|
|
14743
15465
|
if (role === "motif" || role === "sequence" || role === "climax" || role === "answer") {
|
|
14744
15466
|
const shift = (role === "sequence" ? pick([-2, -1, 1, 2], rnd) : role === "climax" ? 5 : 0) + repeatShift;
|
|
14745
15467
|
if (style.pentatonicMotif) {
|
|
14746
|
-
const
|
|
15468
|
+
const startCore = degreeToCore(scale, startDegree);
|
|
14747
15469
|
for (let i2 = 0; i2 < noteCount; i2++)
|
|
14748
15470
|
out.push(
|
|
14749
|
-
|
|
14750
|
-
|
|
15471
|
+
coreToDegree(
|
|
15472
|
+
scale,
|
|
15473
|
+
startCore + shift + motifContour[(contourOffset + i2) % motifContour.length]
|
|
14751
15474
|
)
|
|
14752
15475
|
);
|
|
14753
15476
|
} else {
|
|
@@ -14767,9 +15490,9 @@ var barDegrees = (role, slots, tones, style, motifContour, startDegree, contourO
|
|
|
14767
15490
|
for (let i2 = 0; i2 < noteCount; i2++)
|
|
14768
15491
|
out.push(startDegree + dir2 * (i2 < peak ? i2 : peak * 2 - i2 - 1));
|
|
14769
15492
|
} else if (style.runShape === "broken") {
|
|
14770
|
-
const arp = tones.map((t) => semitoneToDegree(clampSemi(t.semi, 60, 71))).sort((a, b) => a - b);
|
|
15493
|
+
const arp = tones.map((t) => semitoneToDegree(scale, clampSemi(t.semi, 60, 71))).sort((a, b) => a - b);
|
|
14771
15494
|
for (let i2 = 0; i2 < noteCount; i2++) {
|
|
14772
|
-
const oct = Math.floor(i2 / arp.length) *
|
|
15495
|
+
const oct = Math.floor(i2 / arp.length) * scaleSize(scale);
|
|
14773
15496
|
const idx = dir2 > 0 ? i2 % arp.length : arp.length - 1 - i2 % arp.length;
|
|
14774
15497
|
out.push(arp[idx] + dir2 * oct);
|
|
14775
15498
|
}
|
|
@@ -14792,7 +15515,10 @@ var barDegrees = (role, slots, tones, style, motifContour, startDegree, contourO
|
|
|
14792
15515
|
return out;
|
|
14793
15516
|
}
|
|
14794
15517
|
if (role === "cadence") {
|
|
14795
|
-
const tonic = semitoneToDegree(
|
|
15518
|
+
const tonic = semitoneToDegree(
|
|
15519
|
+
scale,
|
|
15520
|
+
clampSemi(72, MELODY_LOW, MELODY_HIGH)
|
|
15521
|
+
);
|
|
14796
15522
|
for (let i2 = 0; i2 < noteCount; i2++) {
|
|
14797
15523
|
if (style.cadenceShape === "descend") {
|
|
14798
15524
|
out.push(tonic + noteCount - 1 - i2);
|
|
@@ -14800,7 +15526,9 @@ var barDegrees = (role, slots, tones, style, motifContour, startDegree, contourO
|
|
|
14800
15526
|
const shape = [4, 2, 0];
|
|
14801
15527
|
out.push(tonic + shape[Math.min(i2, shape.length - 1)]);
|
|
14802
15528
|
} else if (style.cadenceShape === "leap-up") {
|
|
14803
|
-
out.push(
|
|
15529
|
+
out.push(
|
|
15530
|
+
i2 === noteCount - 1 ? tonic : tonic - scaleSize(scale) + Math.min(i2, 4)
|
|
15531
|
+
);
|
|
14804
15532
|
} else {
|
|
14805
15533
|
out.push(i2 === 0 && noteCount > 1 ? tonic + 1 : tonic);
|
|
14806
15534
|
}
|
|
@@ -14835,8 +15563,9 @@ var barDegrees = (role, slots, tones, style, motifContour, startDegree, contourO
|
|
|
14835
15563
|
for (let i2 = 0; i2 < out.length; i2++) {
|
|
14836
15564
|
if (!slots[i2].isStrong) continue;
|
|
14837
15565
|
out[i2] = semitoneToDegree(
|
|
15566
|
+
scale,
|
|
14838
15567
|
nearestChordTone(
|
|
14839
|
-
degreeToPitch(out[i2]).semi,
|
|
15568
|
+
degreeToPitch(scale, out[i2]).semi,
|
|
14840
15569
|
tones,
|
|
14841
15570
|
barHeadWeight,
|
|
14842
15571
|
preferColor
|
|
@@ -14847,9 +15576,9 @@ var barDegrees = (role, slots, tones, style, motifContour, startDegree, contourO
|
|
|
14847
15576
|
if (slots[i2].isStrong) continue;
|
|
14848
15577
|
if (slots[i2].value >= quarterSteps) {
|
|
14849
15578
|
if (rnd() < style.leapAffinity) {
|
|
14850
|
-
const from = degreeToPitch(out[i2 - 1]).semi;
|
|
14851
|
-
const target = leapTarget(from, tones, rnd);
|
|
14852
|
-
if (target !== null) out[i2] = semitoneToDegree(target);
|
|
15579
|
+
const from = degreeToPitch(scale, out[i2 - 1]).semi;
|
|
15580
|
+
const target = leapTarget(from, tones, rnd, style.maxLeap);
|
|
15581
|
+
if (target !== null) out[i2] = semitoneToDegree(scale, target);
|
|
14853
15582
|
}
|
|
14854
15583
|
continue;
|
|
14855
15584
|
}
|
|
@@ -14859,20 +15588,20 @@ var barDegrees = (role, slots, tones, style, motifContour, startDegree, contourO
|
|
|
14859
15588
|
}
|
|
14860
15589
|
return out;
|
|
14861
15590
|
};
|
|
14862
|
-
var fitMotif = (degrees, slots, tones, prevSemi, quarterSteps, pentatonic, preferShift) => {
|
|
15591
|
+
var fitMotif = (degrees, slots, tones, prevSemi, quarterSteps, scale, pentatonic, preferShift, maxShift = 3) => {
|
|
14863
15592
|
let best = degrees;
|
|
14864
15593
|
let bestShift = 0;
|
|
14865
15594
|
let bestScore = Number.NEGATIVE_INFINITY;
|
|
14866
15595
|
let preferScore = Number.NEGATIVE_INFINITY;
|
|
14867
15596
|
let preferMoved = null;
|
|
14868
|
-
for (let shift = -
|
|
15597
|
+
for (let shift = -maxShift; shift <= maxShift; shift++) {
|
|
14869
15598
|
const moved = degrees.map(
|
|
14870
|
-
(d) => pentatonic ?
|
|
15599
|
+
(d) => pentatonic ? coreToDegree(scale, degreeToCore(scale, d) + shift) : d + shift
|
|
14871
15600
|
);
|
|
14872
15601
|
let score = 0;
|
|
14873
15602
|
for (let i2 = 0; i2 < moved.length; i2++) {
|
|
14874
15603
|
const semi = clampSemi(
|
|
14875
|
-
degreeToPitch(moved[i2]).semi,
|
|
15604
|
+
degreeToPitch(scale, moved[i2]).semi,
|
|
14876
15605
|
MELODY_LOW,
|
|
14877
15606
|
MELODY_HIGH
|
|
14878
15607
|
);
|
|
@@ -14881,7 +15610,7 @@ var fitMotif = (degrees, slots, tones, prevSemi, quarterSteps, pentatonic, prefe
|
|
|
14881
15610
|
score += important ? w * 3 : w;
|
|
14882
15611
|
}
|
|
14883
15612
|
const head = clampSemi(
|
|
14884
|
-
degreeToPitch(moved[0]).semi,
|
|
15613
|
+
degreeToPitch(scale, moved[0]).semi,
|
|
14885
15614
|
MELODY_LOW,
|
|
14886
15615
|
MELODY_HIGH
|
|
14887
15616
|
);
|
|
@@ -14904,7 +15633,7 @@ var shapeBar = (degrees, slots, tones, prevSemi, opts) => {
|
|
|
14904
15633
|
const out = [];
|
|
14905
15634
|
let prev = prevSemi;
|
|
14906
15635
|
if (opts.preserveContour) {
|
|
14907
|
-
const raw = degrees.map((d) => degreeToPitch(d).semi);
|
|
15636
|
+
const raw = degrees.map((d) => degreeToPitch(opts.scale, d).semi);
|
|
14908
15637
|
const lo = Math.min(...raw);
|
|
14909
15638
|
const hi = Math.max(...raw);
|
|
14910
15639
|
let shift = 0;
|
|
@@ -14918,30 +15647,42 @@ var shapeBar = (degrees, slots, tones, prevSemi, opts) => {
|
|
|
14918
15647
|
}
|
|
14919
15648
|
for (let i2 = 0; i2 < degrees.length; i2++) {
|
|
14920
15649
|
let semi = clampSemi(
|
|
14921
|
-
degreeToPitch(degrees[i2]).semi,
|
|
15650
|
+
degreeToPitch(opts.scale, degrees[i2]).semi,
|
|
14922
15651
|
MELODY_LOW,
|
|
14923
15652
|
MELODY_HIGH
|
|
14924
15653
|
);
|
|
14925
|
-
const limit = i2 === 0 ? MAX_BAR_LEAP_SEMITONES :
|
|
15654
|
+
const limit = i2 === 0 ? MAX_BAR_LEAP_SEMITONES : opts.maxLeap;
|
|
14926
15655
|
if (!opts.allowLeap && Math.abs(semi - prev) > limit) {
|
|
14927
15656
|
semi = clampSemi(
|
|
14928
|
-
walk(prev, Math.sign(semi - prev) * 3),
|
|
15657
|
+
walk(opts.scale, prev, Math.sign(semi - prev) * 3),
|
|
14929
15658
|
MELODY_LOW,
|
|
14930
15659
|
MELODY_HIGH
|
|
14931
15660
|
);
|
|
14932
15661
|
}
|
|
14933
15662
|
if (!opts.allowArpeggio && i2 >= 2 && Math.abs(out[i2 - 1] - out[i2 - 2]) > STEP_SEMITONES) {
|
|
14934
15663
|
const back = -Math.sign(out[i2 - 1] - out[i2 - 2]);
|
|
14935
|
-
semi = clampSemi(
|
|
15664
|
+
semi = clampSemi(
|
|
15665
|
+
walk(opts.scale, out[i2 - 1], back),
|
|
15666
|
+
MELODY_LOW,
|
|
15667
|
+
MELODY_HIGH
|
|
15668
|
+
);
|
|
14936
15669
|
}
|
|
14937
15670
|
if (toneWeight(semi, tones) === 0 && (slots[i2].isStrong || slots[i2].value >= opts.quarterSteps)) {
|
|
14938
15671
|
const resolved = semi + 1;
|
|
14939
|
-
const useResolved = resolved <= MELODY_HIGH && !
|
|
15672
|
+
const useResolved = resolved <= MELODY_HIGH && !scalePcs(opts.scale).has(pitchClass(resolved)) && toneWeight(resolved, tones) >= 2 && resolved !== prev && opts.rnd() < opts.chromaticAffinity;
|
|
14940
15673
|
if (useResolved) {
|
|
14941
15674
|
semi = resolved;
|
|
14942
15675
|
} else {
|
|
14943
|
-
const up = clampSemi(
|
|
14944
|
-
|
|
15676
|
+
const up = clampSemi(
|
|
15677
|
+
walk(opts.scale, semi, 1),
|
|
15678
|
+
MELODY_LOW,
|
|
15679
|
+
MELODY_HIGH
|
|
15680
|
+
);
|
|
15681
|
+
const down = clampSemi(
|
|
15682
|
+
walk(opts.scale, semi, -1),
|
|
15683
|
+
MELODY_LOW,
|
|
15684
|
+
MELODY_HIGH
|
|
15685
|
+
);
|
|
14945
15686
|
const score = (s) => toneWeight(s, tones) * 2 + (i2 > 0 && s === prev ? -3 : 0);
|
|
14946
15687
|
semi = score(down) >= score(up) ? down : up;
|
|
14947
15688
|
}
|
|
@@ -14949,7 +15690,14 @@ var shapeBar = (degrees, slots, tones, prevSemi, opts) => {
|
|
|
14949
15690
|
out.push(semi);
|
|
14950
15691
|
prev = semi;
|
|
14951
15692
|
}
|
|
14952
|
-
applyPentatonic(
|
|
15693
|
+
applyPentatonic(
|
|
15694
|
+
out,
|
|
15695
|
+
slots,
|
|
15696
|
+
tones,
|
|
15697
|
+
prevSemi,
|
|
15698
|
+
opts.quarterSteps / 2,
|
|
15699
|
+
opts.scale
|
|
15700
|
+
);
|
|
14953
15701
|
applyOctaveJumps(out, slots, opts.octaveAffinity, opts.rnd);
|
|
14954
15702
|
return out;
|
|
14955
15703
|
};
|
|
@@ -14966,27 +15714,27 @@ var applyOctaveJumps = (out, slots, affinity, rnd) => {
|
|
|
14966
15714
|
out[i2] = canUp && (!canDown || rnd() < 0.5) ? up : down;
|
|
14967
15715
|
}
|
|
14968
15716
|
};
|
|
14969
|
-
var applyPentatonic = (out, slots, tones, prevSemi, shortSteps) => {
|
|
15717
|
+
var applyPentatonic = (out, slots, tones, prevSemi, shortSteps, scale) => {
|
|
14970
15718
|
for (let i2 = 0; i2 < out.length; i2++) {
|
|
14971
15719
|
const semi = out[i2];
|
|
14972
|
-
if (!
|
|
14973
|
-
if (tones.some((t) => pitchClass(t.semi) === pitchClass(semi)))
|
|
15720
|
+
if (!isOutsideCore(scale, semi)) continue;
|
|
15721
|
+
if (!scale.strict && tones.some((t) => pitchClass(t.semi) === pitchClass(semi)))
|
|
15722
|
+
continue;
|
|
14974
15723
|
const before = i2 === 0 ? prevSemi : out[i2 - 1];
|
|
14975
15724
|
const after = i2 + 1 < out.length ? out[i2 + 1] : null;
|
|
14976
15725
|
const inByStep = Math.abs(semi - before) <= STEP_SEMITONES;
|
|
14977
15726
|
const outByStep = after !== null && Math.abs(after - semi) <= STEP_SEMITONES;
|
|
14978
|
-
if (inByStep || outByStep) continue;
|
|
14979
|
-
if (!slots[i2].isStrong && slots[i2].value <= shortSteps)
|
|
14980
|
-
|
|
14981
|
-
const
|
|
14982
|
-
const
|
|
15727
|
+
if (scale.strict ? inByStep && outByStep : inByStep || outByStep) continue;
|
|
15728
|
+
if (!scale.strict && !slots[i2].isStrong && slots[i2].value <= shortSteps)
|
|
15729
|
+
continue;
|
|
15730
|
+
const up = clampSemi(walk(scale, semi, 1), MELODY_LOW, MELODY_HIGH);
|
|
15731
|
+
const down = clampSemi(walk(scale, semi, -1), MELODY_LOW, MELODY_HIGH);
|
|
15732
|
+
const score = (s) => (isOutsideCore(scale, s) ? -4 : 0) + toneWeight(s, tones) + (s === before ? -3 : 0) + (after !== null ? -Math.abs(after - s) / 12 : 0);
|
|
14983
15733
|
out[i2] = score(down) >= score(up) ? down : up;
|
|
14984
15734
|
}
|
|
14985
15735
|
};
|
|
14986
|
-
var DIATONIC_PCS = new Set(MAJOR_SCALE2.map((d) => d.semi));
|
|
14987
15736
|
var SHARP_FIFTHS = [0, 7, 2, 9, 4, -1, 6, 1, 8, 3, 10, 5];
|
|
14988
15737
|
var FLAT_FIFTHS = [0, -5, 2, -3, 4, -1, -6, 1, -4, 3, -2, 5];
|
|
14989
|
-
var diatonicFifth = (semi) => degreeToPitch(semitoneToDegree(semi)).fifth;
|
|
14990
15738
|
var nearestOctaveOf = (near, semi) => {
|
|
14991
15739
|
const pc = pitchClass(semi);
|
|
14992
15740
|
let best = pc;
|
|
@@ -15001,7 +15749,7 @@ var nearestOctaveOf = (near, semi) => {
|
|
|
15001
15749
|
}
|
|
15002
15750
|
return best;
|
|
15003
15751
|
};
|
|
15004
|
-
var applyChromatic = (pitches, fifths, slots, tones, opts) => {
|
|
15752
|
+
var applyChromatic = (scale, pitches, fifths, slots, tones, opts) => {
|
|
15005
15753
|
const last = pitches.length - 1;
|
|
15006
15754
|
for (let i2 = 0; i2 < pitches.length; i2++) {
|
|
15007
15755
|
const tone = tones.find(
|
|
@@ -15009,7 +15757,8 @@ var applyChromatic = (pitches, fifths, slots, tones, opts) => {
|
|
|
15009
15757
|
);
|
|
15010
15758
|
if (tone) fifths[i2] = tone.fifth;
|
|
15011
15759
|
}
|
|
15012
|
-
const
|
|
15760
|
+
const pcs = scalePcs(scale);
|
|
15761
|
+
const altered = tones.filter((t) => !pcs.has(pitchClass(t.semi)));
|
|
15013
15762
|
for (let i2 = 0; i2 < pitches.length; i2++) {
|
|
15014
15763
|
if (opts.keepLast && i2 === last) continue;
|
|
15015
15764
|
if (!slots[i2].isStrong && slots[i2].value < opts.quarterSteps) continue;
|
|
@@ -15037,7 +15786,7 @@ var applyChromatic = (pitches, fifths, slots, tones, opts) => {
|
|
|
15037
15786
|
const span = Math.abs(after - before);
|
|
15038
15787
|
const target = span === 2 ? before + dir : span === 3 ? after - dir : null;
|
|
15039
15788
|
if (target === null) continue;
|
|
15040
|
-
if (
|
|
15789
|
+
if (pcs.has(pitchClass(target))) continue;
|
|
15041
15790
|
if (target === before || target === after) continue;
|
|
15042
15791
|
if (target < MELODY_LOW || target > MELODY_HIGH) continue;
|
|
15043
15792
|
pitches[i2] = target;
|
|
@@ -15045,7 +15794,8 @@ var applyChromatic = (pitches, fifths, slots, tones, opts) => {
|
|
|
15045
15794
|
lastAltered = i2;
|
|
15046
15795
|
}
|
|
15047
15796
|
};
|
|
15048
|
-
var draw = (options, resolvedKey, rnd) => {
|
|
15797
|
+
var draw = (options, resolvedKey, scale, rnd) => {
|
|
15798
|
+
const center = resolveCenter(scale);
|
|
15049
15799
|
const stepsPerBar = options.stepsPerBar;
|
|
15050
15800
|
const edo = options.edo === 31 ? 31 : 12;
|
|
15051
15801
|
const scaleStep = (v) => Math.max(1, Math.round(Math.abs(v) * stepsPerBar / BASE_STEPS_PER_BAR)) * Math.sign(v);
|
|
@@ -15073,7 +15823,7 @@ var draw = (options, resolvedKey, rnd) => {
|
|
|
15073
15823
|
const totalBars = sectionPlan.reduce((sum, s) => sum + s.bars, 0);
|
|
15074
15824
|
const relativeKinds = /* @__PURE__ */ new Set();
|
|
15075
15825
|
let relativeShift = 0;
|
|
15076
|
-
if (rnd() < 0.25) {
|
|
15826
|
+
if (rnd() < 0.25 && !center) {
|
|
15077
15827
|
for (const kind of pick(
|
|
15078
15828
|
[["prechorus"], ["bridge"], ["prechorus", "bridge"]],
|
|
15079
15829
|
rnd
|
|
@@ -15183,42 +15933,42 @@ var draw = (options, resolvedKey, rnd) => {
|
|
|
15183
15933
|
barKeyShift[b] = s.keyShift;
|
|
15184
15934
|
}
|
|
15185
15935
|
}
|
|
15186
|
-
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;
|
|
15936
|
+
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;
|
|
15187
15937
|
const withoutTonic = (pool, root) => {
|
|
15188
|
-
const isTonic = (c) => root === "Am" ? /^Am/.test(c) : /^C(?![#b]|m)/.test(c);
|
|
15938
|
+
const isTonic = (c) => center ? center.tonicPattern.test(c) : root === "Am" ? /^Am/.test(c) : /^C(?![#b]|m)/.test(c);
|
|
15189
15939
|
const out = pool.filter((p) => !p.some(isTonic));
|
|
15190
15940
|
return out.length > 0 ? out : pool;
|
|
15191
15941
|
};
|
|
15192
|
-
const homeRoot = resolvedKey.mode === "minor" ? "Am" : "C";
|
|
15942
|
+
const homeRoot = center ? center.tonic : resolvedKey.mode === "minor" ? "Am" : "C";
|
|
15193
15943
|
const progA = pick(
|
|
15194
15944
|
floating ? withoutTonic(progAPool, homeRoot) : progAPool,
|
|
15195
15945
|
rnd
|
|
15196
15946
|
);
|
|
15197
|
-
const progBPool = SECTION_B_PROGRESSIONS.filter(
|
|
15947
|
+
const progBPool = (center ? center.b : SECTION_B_PROGRESSIONS).filter(
|
|
15198
15948
|
(p) => p.join("|") !== progA.join("|")
|
|
15199
15949
|
);
|
|
15200
15950
|
const progB = pick(
|
|
15201
15951
|
floating ? withoutTonic(progBPool, homeRoot) : progBPool,
|
|
15202
15952
|
rnd
|
|
15203
15953
|
);
|
|
15204
|
-
const progRelativePool = SECTION_A_PROGRESSIONS.filter(
|
|
15954
|
+
const progRelativePool = center ? center.a : SECTION_A_PROGRESSIONS.filter(
|
|
15205
15955
|
(p) => resolvedKey.mode === "minor" ? !p[0].startsWith("Am") : p[0].startsWith("Am")
|
|
15206
15956
|
);
|
|
15207
15957
|
const progRelative = pick(
|
|
15208
15958
|
floating ? withoutTonic(progRelativePool, homeRoot) : progRelativePool,
|
|
15209
15959
|
rnd
|
|
15210
15960
|
);
|
|
15211
|
-
const progCPool = SECTION_C_PROGRESSIONS.filter(
|
|
15961
|
+
const progCPool = (center ? center.c : SECTION_C_PROGRESSIONS).filter(
|
|
15212
15962
|
(p) => p.join("|") !== progA.join("|") && p.join("|") !== progB.join("|")
|
|
15213
15963
|
);
|
|
15214
15964
|
const progC = pick(
|
|
15215
15965
|
floating ? withoutTonic(progCPool, homeRoot) : progCPool,
|
|
15216
15966
|
rnd
|
|
15217
15967
|
);
|
|
15218
|
-
const tonic = progA[0].startsWith("Am") ? "Am" : "C";
|
|
15219
|
-
const progHalf = pick(SECTION_A2_DERIVATIONS, rnd)(progA);
|
|
15220
|
-
const progFull = pick(SECTION_A3_DERIVATIONS, rnd)(progA, tonic);
|
|
15221
|
-
const progDeceptive = pick(SECTION_DECEPTIVE_DERIVATIONS, rnd)(progA, tonic);
|
|
15968
|
+
const tonic = center ? center.tonic : progA[0].startsWith("Am") ? "Am" : "C";
|
|
15969
|
+
const progHalf = center ? pick(MODAL_HALF_DERIVATIONS, rnd)(progA, center) : pick(SECTION_A2_DERIVATIONS, rnd)(progA);
|
|
15970
|
+
const progFull = center ? pick(MODAL_FULL_DERIVATIONS, rnd)(progA, center) : pick(SECTION_A3_DERIVATIONS, rnd)(progA, tonic);
|
|
15971
|
+
const progDeceptive = center ? pick(MODAL_DECEPTIVE_DERIVATIONS, rnd)(progA, center) : pick(SECTION_DECEPTIVE_DERIVATIONS, rnd)(progA, tonic);
|
|
15222
15972
|
let lastChorusBar = -1;
|
|
15223
15973
|
for (const section of sectionPlan)
|
|
15224
15974
|
if (section.kind === "chorus" || section.kind === "outro")
|
|
@@ -15265,7 +16015,7 @@ var draw = (options, resolvedKey, rnd) => {
|
|
|
15265
16015
|
progression[bar - 1] = transposeChordName("G7", shift - prev);
|
|
15266
16016
|
}
|
|
15267
16017
|
}
|
|
15268
|
-
if (rnd() < 0.3) {
|
|
16018
|
+
if (rnd() < 0.3 && !center) {
|
|
15269
16019
|
const tonicNames = tonic === "Am" ? ["Am", "Am7"] : ["C", "CM7"];
|
|
15270
16020
|
const spots = [];
|
|
15271
16021
|
for (let bar = 0; bar + 1 < totalBars; bar++) {
|
|
@@ -15286,21 +16036,27 @@ var draw = (options, resolvedKey, rnd) => {
|
|
|
15286
16036
|
const sourceOf = (kind) => kind === "chorus" || kind === "interlude" || kind === "drop_chorus" ? "b" : kind === "prechorus" ? "a2" : kind === "bridge" ? "c" : "a";
|
|
15287
16037
|
const landingOf = (section) => {
|
|
15288
16038
|
if (section.spec.landing === null) return null;
|
|
15289
|
-
const
|
|
15290
|
-
|
|
15291
|
-
|
|
15292
|
-
|
|
16039
|
+
const relativeHere = relativeKinds.has(section.kind);
|
|
16040
|
+
const tonicDegree = relativeHere ? scale.tonic === 5 ? 0 : 5 : scale.tonic;
|
|
16041
|
+
const size = scaleSize(scale);
|
|
16042
|
+
let landing = (section.spec.landing + tonicDegree) % size;
|
|
16043
|
+
if (floating && landing === tonicDegree)
|
|
16044
|
+
landing = (landing + pick([2, 4], rnd)) % size;
|
|
15293
16045
|
return landing;
|
|
15294
16046
|
};
|
|
16047
|
+
const form = resolveMelodyForm(options.form, rnd);
|
|
15295
16048
|
const units2 = [];
|
|
15296
16049
|
for (const section of sectionPlan) {
|
|
15297
16050
|
const unitCount = Math.max(1, Math.round(section.bars / 2));
|
|
15298
16051
|
const src = sourceOf(section.kind);
|
|
15299
16052
|
for (let u = 0; u < unitCount; u++) {
|
|
15300
16053
|
if (!section.spec.melody) {
|
|
16054
|
+
const solo2 = section.kind === "interlude";
|
|
15301
16055
|
units2.push({
|
|
15302
|
-
|
|
15303
|
-
|
|
16056
|
+
// 見せ場なので走句と山を交互に置く。`hold` のままだと
|
|
16057
|
+
// リズム型が最も薄いものになり、ソロにならない。
|
|
16058
|
+
role: solo2 ? u % 2 === 0 ? "run" : "climax" : "hold",
|
|
16059
|
+
source: solo2 ? "solo" : "silent",
|
|
15304
16060
|
landing: null,
|
|
15305
16061
|
section
|
|
15306
16062
|
});
|
|
@@ -15309,16 +16065,31 @@ var draw = (options, resolvedKey, rnd) => {
|
|
|
15309
16065
|
const isLast = u === unitCount - 1;
|
|
15310
16066
|
if (u % 2 === 0) {
|
|
15311
16067
|
units2.push({
|
|
15312
|
-
|
|
15313
|
-
|
|
16068
|
+
// リフ主体の曲は**変形しない**。セクエンツもオクターブ上げも入れず、
|
|
16069
|
+
// 同じ型を回し続ける。セクションの対比は編曲側(ドラム・楽器・レイヤ)
|
|
16070
|
+
// が担う——ヤツメ穴型の曲がまさにその作りで、120小節を通して
|
|
16071
|
+
// 5半音のセルが変わらない。
|
|
16072
|
+
role: form === "ostinato" ? "motif" : form === "through" ? (
|
|
16073
|
+
// 通し作曲は素材を戻さない。`step` の書法(アーチ・谷・波)で
|
|
16074
|
+
// 独立した線を書き、たまに走句と山を挟んで単調さを避ける。
|
|
16075
|
+
u % 3 === 2 ? "run" : u % 3 === 1 ? "climax" : "step"
|
|
16076
|
+
) : section.kind === "bridge" ? "step" : section.kind === "chorus" ? "climax" : src === "a2" || u > 0 ? "sequence" : "motif",
|
|
16077
|
+
// リフ型は素材も1つに揃える(`sourceOf` でセクションごとに
|
|
16078
|
+
// 変えると、そこだけ別の型が始まってオスティナートにならない)。
|
|
16079
|
+
source: form === "ostinato" ? "a" : src,
|
|
15314
16080
|
landing: null,
|
|
15315
16081
|
section
|
|
15316
16082
|
});
|
|
15317
16083
|
} else {
|
|
15318
16084
|
const landing = landingOf(section);
|
|
16085
|
+
const riff = form === "ostinato" && !(isLast && landing === 0);
|
|
15319
16086
|
units2.push({
|
|
15320
|
-
role: isLast && landing === 0 ? "cadence" : "
|
|
15321
|
-
|
|
16087
|
+
role: isLast && landing === 0 ? "cadence" : riff ? "motif" : (
|
|
16088
|
+
// 通し作曲は「問いと答え」で閉じない。answer は問いのリズムを
|
|
16089
|
+
// 受けて着地音だけ変える形なので、そのままだと反復が戻る。
|
|
16090
|
+
form === "through" ? "step" : "answer"
|
|
16091
|
+
),
|
|
16092
|
+
source: riff ? "a" : "answer",
|
|
15322
16093
|
landing: isLast ? landing : null,
|
|
15323
16094
|
section
|
|
15324
16095
|
});
|
|
@@ -15336,6 +16107,7 @@ var draw = (options, resolvedKey, rnd) => {
|
|
|
15336
16107
|
const restatementOf = (bar) => {
|
|
15337
16108
|
const curSec = sectionAt(sectionPlan, bar);
|
|
15338
16109
|
if (!curSec.spec.melody) return null;
|
|
16110
|
+
if (form === "through") return null;
|
|
15339
16111
|
if (curSec.restatement) {
|
|
15340
16112
|
const firstSec = sectionPlan.find(
|
|
15341
16113
|
(s) => s.kind === curSec.kind && !s.restatement
|
|
@@ -15357,14 +16129,19 @@ var draw = (options, resolvedKey, rnd) => {
|
|
|
15357
16129
|
}
|
|
15358
16130
|
return null;
|
|
15359
16131
|
};
|
|
16132
|
+
const registerSpread = form === "ostinato" ? rnd() ** 2 * 0.5 : 0.25 + rnd() * 0.75;
|
|
15360
16133
|
const style = {
|
|
15361
16134
|
groove: pick(["eighth", "sixteenth"], rnd),
|
|
15362
16135
|
arcPeriod: pick([4, 8, 8, 16], rnd),
|
|
15363
16136
|
arcPhase: pick([0, 1, 2], rnd),
|
|
15364
|
-
arcAmp:
|
|
16137
|
+
arcAmp: 5 * registerSpread,
|
|
15365
16138
|
// オクターブ跳躍は参考曲では音程の1.0%しかない。上げすぎると音域が広がる。
|
|
15366
|
-
octaveAffinity: 0.
|
|
15367
|
-
|
|
16139
|
+
octaveAffinity: 0.18 * registerSpread,
|
|
16140
|
+
maxLeap: pick(LEAP_CEILINGS, rnd),
|
|
16141
|
+
// **音階を厳しく締める曲は必ず中核音の歩数で組む。** ダイアトニックの度数で輪郭を
|
|
16142
|
+
// 作ると、琉球音階なのにレやラが輪郭の中に入り込む。ファ・シを自由に使う
|
|
16143
|
+
// 陽・民謡だけが、曲ごとに掛けたり掛けなかったりする({@link ComposeScale.strict})。
|
|
16144
|
+
pentatonicMotif: rnd() < 0.55 || scale.strict,
|
|
15368
16145
|
runShape: pick(["scale", "turn", "broken", "zigzag"], rnd),
|
|
15369
16146
|
stepShape: pick(
|
|
15370
16147
|
["arch", "valley", "ascend", "descend", "wave", "pivot"],
|
|
@@ -15382,7 +16159,11 @@ var draw = (options, resolvedKey, rnd) => {
|
|
|
15382
16159
|
// 界隈曲らしさ:調の外の音(クロマチック)や微小な逸脱を積極的に許容する。
|
|
15383
16160
|
// 刻みを細かくすると経過音の置き場所が増えるので、同じ係数でも変化音は増える。
|
|
15384
16161
|
// 参考曲の1.75倍まで伸びていたぶんを引く。
|
|
15385
|
-
|
|
16162
|
+
// **音階を厳しく締める曲は変化音を控える。** 半音の経過音は長調・短調の泣きメロの
|
|
16163
|
+
// 芯だが、琉球・都節・律ではその半音が音階の外にしか無く、入れたぶんだけ
|
|
16164
|
+
// 音階の色が薄まる(実測で嬰ヘが3%出て、音階内のラ2%より多いという逆転が
|
|
16165
|
+
// 起きていた)。0 にはしない——民族音階の実際の曲にも装飾の半音は出る。
|
|
16166
|
+
chromaticAffinity: (rnd() < 0.2 ? 0 : 0.12 + rnd() * 0.33) * (scale.strict ? 0.4 : 1),
|
|
15386
16167
|
barHeadWeight: rnd() < 0.5 ? 3 : 2,
|
|
15387
16168
|
bassStyle: pick(
|
|
15388
16169
|
[
|
|
@@ -15409,8 +16190,11 @@ var draw = (options, resolvedKey, rnd) => {
|
|
|
15409
16190
|
subInterval: pick([3, 4, 8, 9], rnd)
|
|
15410
16191
|
};
|
|
15411
16192
|
const motifPool = groovyCells(MOTIF_CELLS, style.groove, rnd);
|
|
15412
|
-
const
|
|
15413
|
-
const
|
|
16193
|
+
const targetRestRatio = 0.02 + rnd() ** 2 * 0.42;
|
|
16194
|
+
const targetNotesPerBar = Math.max(
|
|
16195
|
+
2.8,
|
|
16196
|
+
Math.min(9.5, 7.4 - 6 * targetRestRatio + (rnd() * 4 - 2))
|
|
16197
|
+
);
|
|
15414
16198
|
const cellNotes = (c) => c.value.filter((v) => v > 0).length;
|
|
15415
16199
|
const cellRest = (c) => {
|
|
15416
16200
|
let rest = 0;
|
|
@@ -15433,9 +16217,13 @@ var draw = (options, resolvedKey, rnd) => {
|
|
|
15433
16217
|
return pool[pool.length - 1];
|
|
15434
16218
|
};
|
|
15435
16219
|
const pickCell = (pool, densityMul = 1) => {
|
|
15436
|
-
|
|
16220
|
+
const want = targetRestRatio / Math.max(0.5, densityMul);
|
|
16221
|
+
const tol = Math.max(0.08, want * 0.6);
|
|
16222
|
+
const near = pool.filter((c) => Math.abs(cellRest(c) - want) <= tol);
|
|
16223
|
+
const from = near.length > 0 ? near : pool;
|
|
16224
|
+
let best = weightedPick(from);
|
|
15437
16225
|
for (let i2 = 0; i2 < 2; i2++) {
|
|
15438
|
-
const c = weightedPick(
|
|
16226
|
+
const c = weightedPick(from);
|
|
15439
16227
|
if (cellDistance(c, densityMul) < cellDistance(best, densityMul))
|
|
15440
16228
|
best = c;
|
|
15441
16229
|
}
|
|
@@ -15537,7 +16325,7 @@ var draw = (options, resolvedKey, rnd) => {
|
|
|
15537
16325
|
if (breathBars.has(source)) breathBars.add(bar);
|
|
15538
16326
|
continue;
|
|
15539
16327
|
}
|
|
15540
|
-
const isB = units2[u].source === "b";
|
|
16328
|
+
const isB = units2[u].source === "b" || units2[u].source === "solo";
|
|
15541
16329
|
const isA2 = units2[u].source === "a2";
|
|
15542
16330
|
const isC = units2[u].source === "c";
|
|
15543
16331
|
const isPrechorusEnd = units2[u].section.kind === "prechorus" && bar === units2[u].section.startBar + units2[u].section.bars - 1;
|
|
@@ -15587,6 +16375,7 @@ var draw = (options, resolvedKey, rnd) => {
|
|
|
15587
16375
|
const harmony = [];
|
|
15588
16376
|
const harmony2 = [];
|
|
15589
16377
|
const pad = [];
|
|
16378
|
+
const solo = [];
|
|
15590
16379
|
const melodyDurations = [];
|
|
15591
16380
|
const barTension = new Array(totalBars).fill(0);
|
|
15592
16381
|
let restSteps = 0;
|
|
@@ -15597,9 +16386,9 @@ var draw = (options, resolvedKey, rnd) => {
|
|
|
15597
16386
|
let chromaticNotes = 0;
|
|
15598
16387
|
let sungBars = 0;
|
|
15599
16388
|
let prevSemi = pick([60, 64, 65, 67, 69, 72, 74, 76], rnd);
|
|
15600
|
-
const pickFigure = (gapSteps,
|
|
16389
|
+
const pickFigure = (gapSteps, scale2) => {
|
|
15601
16390
|
const fits = ANSWER_FIGURES.filter(
|
|
15602
|
-
(f) => f.reduce((sum, v) => sum +
|
|
16391
|
+
(f) => f.reduce((sum, v) => sum + scale2(Math.abs(v)), 0) <= gapSteps
|
|
15603
16392
|
);
|
|
15604
16393
|
return fits.length === 0 ? null : pick(fits, rnd);
|
|
15605
16394
|
};
|
|
@@ -15657,8 +16446,9 @@ var draw = (options, resolvedKey, rnd) => {
|
|
|
15657
16446
|
slots,
|
|
15658
16447
|
tones,
|
|
15659
16448
|
style,
|
|
16449
|
+
scale,
|
|
15660
16450
|
motifContour,
|
|
15661
|
-
semitoneToDegree(headSemi),
|
|
16451
|
+
semitoneToDegree(scale, headSemi),
|
|
15662
16452
|
contourOffset,
|
|
15663
16453
|
repeatShift,
|
|
15664
16454
|
headWeight,
|
|
@@ -15674,7 +16464,8 @@ var draw = (options, resolvedKey, rnd) => {
|
|
|
15674
16464
|
...plannedDegrees[source]
|
|
15675
16465
|
);
|
|
15676
16466
|
const landing = units2[unitOf(bar)].landing;
|
|
15677
|
-
if (landing !== null && barInUnit(bar) === 1)
|
|
16467
|
+
if (landing !== null && barInUnit(bar) === 1)
|
|
16468
|
+
landOn(scale, degrees, landing);
|
|
15678
16469
|
plannedDegrees[bar] = [...degrees];
|
|
15679
16470
|
const isMotifBar = source !== null || role === "motif" || role === "sequence" || role === "climax" || role === "answer";
|
|
15680
16471
|
let fitted = degrees;
|
|
@@ -15686,13 +16477,18 @@ var draw = (options, resolvedKey, rnd) => {
|
|
|
15686
16477
|
tones,
|
|
15687
16478
|
prevSemi,
|
|
15688
16479
|
quarterSteps,
|
|
16480
|
+
scale,
|
|
15689
16481
|
style.pentatonicMotif,
|
|
15690
|
-
motifShiftMemo.get(shiftKey) ?? null
|
|
16482
|
+
motifShiftMemo.get(shiftKey) ?? null,
|
|
16483
|
+
// リフ型は和音へ寄せない。同じセルを回し続けるのが役目。
|
|
16484
|
+
form === "ostinato" ? 0 : 3
|
|
15691
16485
|
);
|
|
15692
16486
|
fitted = r.degrees;
|
|
15693
16487
|
motifShiftMemo.set(shiftKey, r.shift);
|
|
15694
16488
|
}
|
|
15695
16489
|
const pitches = shapeBar(fitted, slots, tones, prevSemi, {
|
|
16490
|
+
scale,
|
|
16491
|
+
maxLeap: style.maxLeap,
|
|
15696
16492
|
allowLeap: role === "climax",
|
|
15697
16493
|
allowArpeggio: role === "climax" || role === "run" && style.runShape === "broken" || role === "cadence" && style.cadenceShape !== "descend",
|
|
15698
16494
|
quarterSteps,
|
|
@@ -15707,16 +16503,19 @@ var draw = (options, resolvedKey, rnd) => {
|
|
|
15707
16503
|
rnd,
|
|
15708
16504
|
preserveContour: isMotifBar
|
|
15709
16505
|
});
|
|
15710
|
-
if (landing !== null && barInUnit(bar) === 1)
|
|
15711
|
-
|
|
15712
|
-
|
|
16506
|
+
if (landing !== null && barInUnit(bar) === 1)
|
|
16507
|
+
landPitch(scale, pitches, landing);
|
|
16508
|
+
const fifths = pitches.map((semi) => scaleFifth(scale, semi));
|
|
16509
|
+
applyChromatic(scale, pitches, fifths, slots, tones, {
|
|
15713
16510
|
affinity: style.chromaticAffinity,
|
|
15714
16511
|
quarterSteps,
|
|
15715
16512
|
shortSteps: scaleStep(EIGHTH),
|
|
15716
16513
|
keepLast: landing !== null && barInUnit(bar) === 1,
|
|
15717
16514
|
rnd
|
|
15718
16515
|
});
|
|
15719
|
-
const
|
|
16516
|
+
const unitSource = units2[unitOf(bar)].source;
|
|
16517
|
+
const isSolo = unitSource === "solo";
|
|
16518
|
+
const silent = unitSource === "silent" || isSolo;
|
|
15720
16519
|
const barHead = pitches[0];
|
|
15721
16520
|
let tensionSum = 0;
|
|
15722
16521
|
let tensionSteps = 0;
|
|
@@ -15724,7 +16523,7 @@ var draw = (options, resolvedKey, rnd) => {
|
|
|
15724
16523
|
const semi = pitches[i2];
|
|
15725
16524
|
tensionSum += (3 - toneWeight(semi, tones)) / 3 * slots[i2].value;
|
|
15726
16525
|
tensionSteps += slots[i2].value;
|
|
15727
|
-
if (role !== "climax") {
|
|
16526
|
+
if (!silent && role !== "climax") {
|
|
15728
16527
|
const gap = Math.abs(semi - prevSemi);
|
|
15729
16528
|
maxLeap = Math.max(maxLeap, gap);
|
|
15730
16529
|
intervals++;
|
|
@@ -15733,10 +16532,25 @@ var draw = (options, resolvedKey, rnd) => {
|
|
|
15733
16532
|
}
|
|
15734
16533
|
const slot = slots[i2];
|
|
15735
16534
|
if (silent) {
|
|
16535
|
+
if (isSolo) {
|
|
16536
|
+
const ks = barKeyShift[bar];
|
|
16537
|
+
const fifthShiftSolo = ks === 0 ? 0 : SEMITONE_TO_FIFTH_SHIFT[(ks % 12 + 12) % 12];
|
|
16538
|
+
solo.push({
|
|
16539
|
+
startStep: barStart + slot.at,
|
|
16540
|
+
pitchUnits: spelledToUnits(
|
|
16541
|
+
semi + ks,
|
|
16542
|
+
fifths[i2] + fifthShiftSolo,
|
|
16543
|
+
edo
|
|
16544
|
+
),
|
|
16545
|
+
durationSteps: slot.value,
|
|
16546
|
+
// ソロは前に出る声部なので、歌メロより気持ち強く弾く。
|
|
16547
|
+
velocity: slot.at === 0 ? 116 : slot.value <= scaleStep(SIXTEENTH) ? 96 : 106
|
|
16548
|
+
});
|
|
16549
|
+
}
|
|
15736
16550
|
prevSemi = semi;
|
|
15737
16551
|
continue;
|
|
15738
16552
|
}
|
|
15739
|
-
if (!
|
|
16553
|
+
if (!scalePcs(scale).has(pitchClass(semi))) chromaticNotes++;
|
|
15740
16554
|
const k = barKeyShift[bar];
|
|
15741
16555
|
const fifthShift = k === 0 ? 0 : SEMITONE_TO_FIFTH_SHIFT[(k % 12 + 12) % 12];
|
|
15742
16556
|
melody.push({
|
|
@@ -15790,7 +16604,7 @@ var draw = (options, resolvedKey, rnd) => {
|
|
|
15790
16604
|
subSemi = pushSub(
|
|
15791
16605
|
cursor,
|
|
15792
16606
|
step,
|
|
15793
|
-
i2 === 0 ? subSemi : walk(subSemi, subDir)
|
|
16607
|
+
i2 === 0 ? subSemi : walk(scale, subSemi, subDir)
|
|
15794
16608
|
);
|
|
15795
16609
|
placed++;
|
|
15796
16610
|
}
|
|
@@ -15814,7 +16628,7 @@ var draw = (options, resolvedKey, rnd) => {
|
|
|
15814
16628
|
subSemi = pushSub(
|
|
15815
16629
|
cursor,
|
|
15816
16630
|
step,
|
|
15817
|
-
index === 0 ? subSemi : walk(subSemi, subDir * (index % 2 === 0 ? 1 : -1))
|
|
16631
|
+
index === 0 ? subSemi : walk(scale, subSemi, subDir * (index % 2 === 0 ? 1 : -1))
|
|
15818
16632
|
);
|
|
15819
16633
|
index++;
|
|
15820
16634
|
}
|
|
@@ -15824,7 +16638,11 @@ var draw = (options, resolvedKey, rnd) => {
|
|
|
15824
16638
|
pushSub(0, stepsPerBar, subSemi);
|
|
15825
16639
|
} else if (subStyle === "long-short") {
|
|
15826
16640
|
subSemi = pushSub(0, scaleStep(DOT_HALF), subSemi);
|
|
15827
|
-
pushSub(
|
|
16641
|
+
pushSub(
|
|
16642
|
+
scaleStep(DOT_HALF),
|
|
16643
|
+
scaleStep(QUARTER),
|
|
16644
|
+
walk(scale, subSemi, subDir)
|
|
16645
|
+
);
|
|
15828
16646
|
} else if (role === "cadence") {
|
|
15829
16647
|
pushSub(0, stepsPerBar, subSemi);
|
|
15830
16648
|
} else {
|
|
@@ -15839,6 +16657,7 @@ var draw = (options, resolvedKey, rnd) => {
|
|
|
15839
16657
|
const written = [];
|
|
15840
16658
|
for (let i2 = 0; i2 < slots.length; i2++) {
|
|
15841
16659
|
const hTone = harmonyPitch(
|
|
16660
|
+
scale,
|
|
15842
16661
|
pitches[i2],
|
|
15843
16662
|
tones,
|
|
15844
16663
|
last,
|
|
@@ -15909,6 +16728,7 @@ var draw = (options, resolvedKey, rnd) => {
|
|
|
15909
16728
|
const nextTones = chordTones(progression[(bar + 1) % totalBars]);
|
|
15910
16729
|
const A = clampSemi(
|
|
15911
16730
|
walk(
|
|
16731
|
+
scale,
|
|
15912
16732
|
nextTones[0] ? clampSemi(nextTones[0].semi, BASS_LOW, BASS_HIGH) : R,
|
|
15913
16733
|
-1
|
|
15914
16734
|
),
|
|
@@ -15965,7 +16785,7 @@ var draw = (options, resolvedKey, rnd) => {
|
|
|
15965
16785
|
let bassCursor = 0;
|
|
15966
16786
|
for (const [semi, value] of bassCell) {
|
|
15967
16787
|
const len = scaleStep(value);
|
|
15968
|
-
const fifth = semi === R || semi === O ? rootTone.fifth : semi === F ? fifthTone?.fifth ?? rootTone.fifth : semi === T ? thirdTone?.fifth ?? rootTone.fifth :
|
|
16788
|
+
const fifth = semi === R || semi === O ? rootTone.fifth : semi === F ? fifthTone?.fifth ?? rootTone.fifth : semi === T ? thirdTone?.fifth ?? rootTone.fifth : scaleFifth(scale, semi);
|
|
15969
16789
|
const k = barKeyShift[bar];
|
|
15970
16790
|
const fifthShift = k === 0 ? 0 : SEMITONE_TO_FIFTH_SHIFT[(k % 12 + 12) % 12];
|
|
15971
16791
|
barBass.push({
|
|
@@ -16027,7 +16847,7 @@ var draw = (options, resolvedKey, rnd) => {
|
|
|
16027
16847
|
const after = melody[i2 + 2];
|
|
16028
16848
|
if (after && Math.floor(after.startStep / stepsPerBar) === barIdx) {
|
|
16029
16849
|
const afterSemi = Math.round(after.pitchUnits / UNITS_PER_SEMITONE) - (barKeyShift[barIdx] ?? 0);
|
|
16030
|
-
if (!
|
|
16850
|
+
if (!scalePcs(scale).has(pitchClass(afterSemi))) continue;
|
|
16031
16851
|
}
|
|
16032
16852
|
const nextRole = barRoles[barIdx];
|
|
16033
16853
|
let tieProb = 0.3;
|
|
@@ -16048,11 +16868,13 @@ var draw = (options, resolvedKey, rnd) => {
|
|
|
16048
16868
|
melodyDurations[i2] += melodyDurations[i2 + 1];
|
|
16049
16869
|
melodyDurations.splice(i2 + 1, 1);
|
|
16050
16870
|
}
|
|
16051
|
-
const
|
|
16052
|
-
|
|
16053
|
-
|
|
16054
|
-
|
|
16055
|
-
|
|
16871
|
+
for (const voice of [harmony, harmony2]) {
|
|
16872
|
+
const nxtIdx = voice.findIndex((h) => h.startStep === nxt.startStep);
|
|
16873
|
+
if (nxtIdx < 0) continue;
|
|
16874
|
+
const curIdx = voice.findIndex((h) => h.startStep === cur.startStep);
|
|
16875
|
+
if (curIdx >= 0)
|
|
16876
|
+
voice[curIdx].durationSteps += voice[nxtIdx].durationSteps;
|
|
16877
|
+
voice.splice(nxtIdx, 1);
|
|
16056
16878
|
}
|
|
16057
16879
|
i2--;
|
|
16058
16880
|
}
|
|
@@ -16106,17 +16928,20 @@ var draw = (options, resolvedKey, rnd) => {
|
|
|
16106
16928
|
};
|
|
16107
16929
|
const shiftUnits = semitonesToUnits(rootShift, edo);
|
|
16108
16930
|
if (shiftUnits !== 0)
|
|
16109
|
-
for (const list of [melody, submelody, bass, harmony, harmony2, pad])
|
|
16931
|
+
for (const list of [melody, submelody, bass, harmony, harmony2, pad, solo])
|
|
16110
16932
|
for (const n of list) n.pitchUnits = n.pitchUnits + shiftUnits;
|
|
16111
16933
|
const octave = useOctaveLayer ? melody.filter(
|
|
16112
16934
|
(n) => n.durationSteps >= quarterSteps || rnd() < octaveCoverage
|
|
16113
16935
|
).map((n) => ({ ...n, velocity: Math.max(40, n.velocity - 26) })) : [];
|
|
16114
16936
|
return {
|
|
16937
|
+
form,
|
|
16115
16938
|
chordProgression,
|
|
16116
16939
|
chordPattern,
|
|
16117
16940
|
rootShift,
|
|
16118
16941
|
keyName: resolvedKey.keyName,
|
|
16119
16942
|
keyLabel: resolvedKey.keyLabel,
|
|
16943
|
+
scaleId: scale.id,
|
|
16944
|
+
scaleLabel: scale.label,
|
|
16120
16945
|
moodLabel: resolvedKey.moodLabel,
|
|
16121
16946
|
bpm,
|
|
16122
16947
|
sections: sectionPlan,
|
|
@@ -16136,6 +16961,7 @@ var draw = (options, resolvedKey, rnd) => {
|
|
|
16136
16961
|
harmony2,
|
|
16137
16962
|
octave,
|
|
16138
16963
|
pad,
|
|
16964
|
+
solo,
|
|
16139
16965
|
melodyDurations,
|
|
16140
16966
|
restSteps,
|
|
16141
16967
|
totalSteps: Math.max(1, sungBars) * stepsPerBar,
|
|
@@ -16195,7 +17021,7 @@ var evaluate = (d, recent) => {
|
|
|
16195
17021
|
Math.min(...recent.map((r) => featureDistance(fingerprint, r))) / 1
|
|
16196
17022
|
);
|
|
16197
17023
|
const at = (b, v) => band(v, b[0], b[1], b[2], b[3]);
|
|
16198
|
-
const atc = (key, v) =>
|
|
17024
|
+
const atc = (key, v) => plausibleBand(v, CORPUS_BANDS[key]);
|
|
16199
17025
|
const peakBand = d.bars > 24 ? [0, 1, Math.round(d.bars / 16), Math.round(d.bars / 8) + 2] : HAND_BANDS.climaxPeaks;
|
|
16200
17026
|
const scoreBreakdown = {
|
|
16201
17027
|
entropy: atc("entropy", entropy),
|
|
@@ -16231,9 +17057,16 @@ var evaluate = (d, recent) => {
|
|
|
16231
17057
|
tensionResolve: d.tonal.floating ? 1 : tension.resolve,
|
|
16232
17058
|
novelty
|
|
16233
17059
|
};
|
|
17060
|
+
const forgiven = new Set(
|
|
17061
|
+
Object.entries(WEIGHTS).filter(([key]) => BUDGETED_KEYS.has(key)).map(([key, weight]) => ({
|
|
17062
|
+
key,
|
|
17063
|
+
deficit: weight * (1 - (scoreBreakdown[key] ?? 0))
|
|
17064
|
+
})).sort((a, b) => b.deficit - a.deficit).slice(0, DEVIATION_BUDGET).filter((e) => e.deficit > 0).map((e) => e.key)
|
|
17065
|
+
);
|
|
16234
17066
|
let weighted = 0;
|
|
16235
17067
|
let weightSum = 0;
|
|
16236
17068
|
for (const [key, weight] of Object.entries(WEIGHTS)) {
|
|
17069
|
+
if (forgiven.has(key)) continue;
|
|
16237
17070
|
weighted += (scoreBreakdown[key] ?? 0) * weight;
|
|
16238
17071
|
weightSum += weight;
|
|
16239
17072
|
}
|
|
@@ -16265,49 +17098,74 @@ var composeSong = (options) => {
|
|
|
16265
17098
|
const recent = options.recent ?? [];
|
|
16266
17099
|
const count = Math.max(1, options.drawCount ?? DRAW_COUNT);
|
|
16267
17100
|
const resolvedKey = resolveComposeKey(options.baseKey, rnd);
|
|
16268
|
-
|
|
16269
|
-
|
|
16270
|
-
|
|
17101
|
+
const scale = resolveComposeScale(
|
|
17102
|
+
options.scale,
|
|
17103
|
+
resolvedKey.mode === "minor",
|
|
17104
|
+
rnd
|
|
17105
|
+
);
|
|
17106
|
+
const valid = [];
|
|
17107
|
+
const invalid = [];
|
|
16271
17108
|
let rejected = 0;
|
|
16272
17109
|
for (let attempt = 1; attempt <= count; attempt++) {
|
|
16273
|
-
const
|
|
16274
|
-
const { stats, ok } = evaluate(
|
|
16275
|
-
if (
|
|
16276
|
-
|
|
16277
|
-
|
|
16278
|
-
|
|
16279
|
-
|
|
16280
|
-
|
|
16281
|
-
|
|
16282
|
-
|
|
16283
|
-
|
|
16284
|
-
|
|
16285
|
-
|
|
16286
|
-
|
|
16287
|
-
|
|
16288
|
-
|
|
16289
|
-
|
|
16290
|
-
|
|
16291
|
-
|
|
16292
|
-
|
|
16293
|
-
|
|
16294
|
-
|
|
16295
|
-
tonal: d.tonal,
|
|
16296
|
-
melody: d.melody,
|
|
16297
|
-
submelody: d.submelody,
|
|
16298
|
-
bass: d.bass,
|
|
16299
|
-
harmony: d.harmony,
|
|
16300
|
-
harmony2: d.harmony2,
|
|
16301
|
-
octave: d.octave,
|
|
16302
|
-
pad: d.pad,
|
|
16303
|
-
stats: { ...stats, attempts: attempt, rejected }
|
|
16304
|
-
};
|
|
17110
|
+
const d2 = draw(options, resolvedKey, scale, rnd);
|
|
17111
|
+
const { stats, ok } = evaluate(d2, recent);
|
|
17112
|
+
if (ok) valid.push({ d: d2, stats });
|
|
17113
|
+
else {
|
|
17114
|
+
rejected++;
|
|
17115
|
+
invalid.push({ d: d2, stats });
|
|
17116
|
+
}
|
|
17117
|
+
}
|
|
17118
|
+
const pool = valid.length > 0 ? valid : invalid;
|
|
17119
|
+
const top = Math.max(...pool.map((c) => c.stats.score));
|
|
17120
|
+
const weights = pool.map(
|
|
17121
|
+
(c) => Math.exp((c.stats.score - top) / SELECT_TEMPERATURE)
|
|
17122
|
+
);
|
|
17123
|
+
const total = weights.reduce((a, b) => a + b, 0);
|
|
17124
|
+
let ticket = rnd() * total;
|
|
17125
|
+
let chosen = pool[pool.length - 1];
|
|
17126
|
+
for (let i2 = 0; i2 < pool.length; i2++) {
|
|
17127
|
+
ticket -= weights[i2];
|
|
17128
|
+
if (ticket <= 0) {
|
|
17129
|
+
chosen = pool[i2];
|
|
17130
|
+
break;
|
|
17131
|
+
}
|
|
16305
17132
|
}
|
|
16306
|
-
const
|
|
17133
|
+
const d = chosen.d;
|
|
17134
|
+
const result = {
|
|
17135
|
+
// ドラム・楽器・編曲プランは勝った候補にだけ後から付ける(メロディに
|
|
17136
|
+
// 依存しないので候補ごとに引いても採点は動かず、候補数ぶん無駄になる)。
|
|
17137
|
+
drum: "",
|
|
17138
|
+
instrument: "",
|
|
17139
|
+
arrange: EMPTY_ARRANGE,
|
|
17140
|
+
chordProgression: d.chordProgression,
|
|
17141
|
+
chordPattern: d.chordPattern,
|
|
17142
|
+
rootShift: d.rootShift,
|
|
17143
|
+
keyName: d.keyName,
|
|
17144
|
+
keyLabel: d.keyLabel,
|
|
17145
|
+
scaleId: scale.id,
|
|
17146
|
+
scaleLabel: scale.label,
|
|
17147
|
+
form: d.form,
|
|
17148
|
+
moodLabel: d.moodLabel,
|
|
17149
|
+
bpm: d.bpm,
|
|
17150
|
+
sections: d.sections,
|
|
17151
|
+
bars: d.bars,
|
|
17152
|
+
vocal: d.vocal,
|
|
17153
|
+
tonal: d.tonal,
|
|
17154
|
+
melody: d.melody,
|
|
17155
|
+
submelody: d.submelody,
|
|
17156
|
+
bass: d.bass,
|
|
17157
|
+
harmony: d.harmony,
|
|
17158
|
+
harmony2: d.harmony2,
|
|
17159
|
+
octave: d.octave,
|
|
17160
|
+
pad: d.pad,
|
|
17161
|
+
solo: d.solo,
|
|
17162
|
+
stats: { ...chosen.stats, attempts: count, rejected }
|
|
17163
|
+
};
|
|
16307
17164
|
result.stats.attempts = count;
|
|
16308
17165
|
result.stats.rejected = rejected;
|
|
16309
17166
|
result.drum = pickBuiltinDrum(result, rnd);
|
|
16310
17167
|
result.instrument = pickBuiltinInstrument(result, rnd);
|
|
17168
|
+
result.arrange = buildArrangePlan(result, rnd);
|
|
16311
17169
|
return result;
|
|
16312
17170
|
};
|
|
16313
17171
|
var pickBuiltinDrum = (song, rnd) => {
|
|
@@ -16319,6 +17177,80 @@ var pickBuiltinDrum = (song, rnd) => {
|
|
|
16319
17177
|
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"];
|
|
16320
17178
|
return pick(pool, rnd);
|
|
16321
17179
|
};
|
|
17180
|
+
var EMPTY_ARRANGE = {
|
|
17181
|
+
backing: [],
|
|
17182
|
+
sparkle: null,
|
|
17183
|
+
padSections: [],
|
|
17184
|
+
lead: null,
|
|
17185
|
+
bassLayer: null
|
|
17186
|
+
};
|
|
17187
|
+
var LOUD_KINDS = ["prechorus", "chorus", "bridge"];
|
|
17188
|
+
var QUIET_KINDS = [
|
|
17189
|
+
"intro",
|
|
17190
|
+
"verse",
|
|
17191
|
+
"interlude",
|
|
17192
|
+
"drop_chorus",
|
|
17193
|
+
"outro"
|
|
17194
|
+
];
|
|
17195
|
+
var CHORUS_KINDS = ["chorus", "drop_chorus"];
|
|
17196
|
+
var buildArrangePlan = (song, rnd) => {
|
|
17197
|
+
const present = new Set(song.sections.map((s) => s.kind));
|
|
17198
|
+
const narrow = (kinds) => {
|
|
17199
|
+
const hit = kinds.filter((k) => present.has(k));
|
|
17200
|
+
return hit.length === 0 ? null : hit;
|
|
17201
|
+
};
|
|
17202
|
+
const base = {
|
|
17203
|
+
pattern: song.chordPattern,
|
|
17204
|
+
sections: null,
|
|
17205
|
+
octave: 0
|
|
17206
|
+
};
|
|
17207
|
+
const others = chordPatternPool(song.bpm).filter((p) => p !== base.pattern);
|
|
17208
|
+
const backing = [base];
|
|
17209
|
+
const addKinds = pick(
|
|
17210
|
+
[LOUD_KINDS, CHORUS_KINDS, LOUD_KINDS, QUIET_KINDS],
|
|
17211
|
+
rnd
|
|
17212
|
+
);
|
|
17213
|
+
const second = pick(others, rnd);
|
|
17214
|
+
backing.push({
|
|
17215
|
+
pattern: second,
|
|
17216
|
+
sections: narrow(addKinds),
|
|
17217
|
+
octave: 0
|
|
17218
|
+
});
|
|
17219
|
+
if (rnd() < 0.55) {
|
|
17220
|
+
const rest = others.filter((p) => p !== second);
|
|
17221
|
+
backing.push({
|
|
17222
|
+
pattern: pick(rest.length > 0 ? rest : others, rnd),
|
|
17223
|
+
// 2本目と逆側へ置く(両方サビに寄せると、サビだけ団子になる)。
|
|
17224
|
+
sections: narrow(addKinds === QUIET_KINDS ? LOUD_KINDS : QUIET_KINDS),
|
|
17225
|
+
octave: 0
|
|
17226
|
+
});
|
|
17227
|
+
}
|
|
17228
|
+
const sparklePool = chordPatternPool(song.bpm).filter(
|
|
17229
|
+
(p) => p !== "block" && !backing.some((b) => b.pattern === p)
|
|
17230
|
+
);
|
|
17231
|
+
const sparkle = sparklePool.length > 0 && rnd() < 0.7 ? {
|
|
17232
|
+
pattern: pick(sparklePool, rnd),
|
|
17233
|
+
sections: narrow(pick([LOUD_KINDS, CHORUS_KINDS], rnd)) ?? CHORUS_KINDS,
|
|
17234
|
+
octave: 1
|
|
17235
|
+
} : null;
|
|
17236
|
+
const padSections = narrow(
|
|
17237
|
+
pick(
|
|
17238
|
+
[
|
|
17239
|
+
["prechorus", "chorus", "bridge", "drop_chorus"],
|
|
17240
|
+
["chorus", "drop_chorus"],
|
|
17241
|
+
["prechorus", "chorus", "bridge", "drop_chorus"],
|
|
17242
|
+
["bridge", "chorus"]
|
|
17243
|
+
],
|
|
17244
|
+
rnd
|
|
17245
|
+
)
|
|
17246
|
+
) ?? [];
|
|
17247
|
+
const lead = rnd() < 0.75 ? {
|
|
17248
|
+
sections: narrow(pick([CHORUS_KINDS, LOUD_KINDS], rnd)) ?? CHORUS_KINDS,
|
|
17249
|
+
octave: rnd() < 0.5 ? 0 : 1
|
|
17250
|
+
} : null;
|
|
17251
|
+
const bassLayer = rnd() < 0.25 ? { sections: narrow(CHORUS_KINDS) ?? CHORUS_KINDS, octave: 1 } : null;
|
|
17252
|
+
return { backing, sparkle, padSections, lead, bassLayer };
|
|
17253
|
+
};
|
|
16322
17254
|
var pickBuiltinInstrument = (song, rnd) => {
|
|
16323
17255
|
const eighth = BASE_STEPS_PER_BAR / 8;
|
|
16324
17256
|
const short = song.melody.filter((n) => n.durationSteps <= eighth).length / Math.max(1, song.melody.length);
|
|
@@ -16429,6 +17361,492 @@ var composeLyrics = (melody, options) => {
|
|
|
16429
17361
|
return out.join("");
|
|
16430
17362
|
};
|
|
16431
17363
|
|
|
17364
|
+
// src/instrument-presets.ts
|
|
17365
|
+
var INSTRUMENT_PRESETS = {
|
|
17366
|
+
// --- STANDARD: 汎用性と完成度重視 ---
|
|
17367
|
+
piano: {
|
|
17368
|
+
displayName: "\u30B0\u30E9\u30F3\u30C9\u30D4\u30A2\u30CE",
|
|
17369
|
+
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",
|
|
17370
|
+
melody: "Acoustic Grand Piano",
|
|
17371
|
+
submelody: "Vibraphone",
|
|
17372
|
+
bass: "Electric Bass (finger)",
|
|
17373
|
+
chord: "Pad 2 (warm)",
|
|
17374
|
+
solo: "Electric Guitar (clean)",
|
|
17375
|
+
// **Glockenspiel は使わない。音源側のサンプルが音程を外している**(実聴で確認)。
|
|
17376
|
+
// 音域の問題(G5〜の高音楽器)なら {@link GM_BRIGHT_CEILING} で下げれば済むが、
|
|
17377
|
+
// ピッチそのものがずれているものは置き場所を変えても直らない。同じ役割
|
|
17378
|
+
// (サビの上に乗る明るい音板)で、素直に鳴る Celesta へ差し替えてある。
|
|
17379
|
+
// ※ {@link GM_INSTRUMENT_RANGE} / {@link GM_BRIGHT_CEILING} の Glockenspiel の
|
|
17380
|
+
// 項は残す。手で選んだときの置き場所の判断はそのまま要るため。
|
|
17381
|
+
chorusLead: "Celesta",
|
|
17382
|
+
chordAlt: "Electric Piano 1",
|
|
17383
|
+
sparkle: "Music Box",
|
|
17384
|
+
bassAlt: "Acoustic Bass",
|
|
17385
|
+
harmonyAlt: "Choir Aahs"
|
|
17386
|
+
},
|
|
17387
|
+
acoustic: {
|
|
17388
|
+
displayName: "\u30A2\u30B3\u30FC\u30B9\u30C6\u30A3\u30C3\u30AF",
|
|
17389
|
+
description: "\u751F\u697D\u5668\u306E\u6E29\u304B\u307F\u3092\u91CD\u8996\u3002\u30D5\u30A9\u30FC\u30AF\u3084\u30DD\u30C3\u30D7\u30B9\u306B\u3002",
|
|
17390
|
+
melody: "Acoustic Guitar (steel)",
|
|
17391
|
+
submelody: "Harmonica",
|
|
17392
|
+
bass: "Acoustic Bass",
|
|
17393
|
+
chord: "Acoustic Guitar (nylon)",
|
|
17394
|
+
solo: "Overdriven Guitar",
|
|
17395
|
+
chorusLead: "String Ensemble 1",
|
|
17396
|
+
chordAlt: "Acoustic Grand Piano",
|
|
17397
|
+
sparkle: "Celesta",
|
|
17398
|
+
bassAlt: "Electric Bass (finger)",
|
|
17399
|
+
harmonyAlt: "Choir Aahs"
|
|
17400
|
+
},
|
|
17401
|
+
jazz_night: {
|
|
17402
|
+
displayName: "\u30B8\u30E3\u30BA\u30FB\u30CA\u30A4\u30C8",
|
|
17403
|
+
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",
|
|
17404
|
+
melody: "Electric Piano 1",
|
|
17405
|
+
submelody: "Flute",
|
|
17406
|
+
bass: "Acoustic Bass",
|
|
17407
|
+
chord: "Electric Guitar (jazz)",
|
|
17408
|
+
solo: "Tenor Sax",
|
|
17409
|
+
chorusLead: "Muted Trumpet",
|
|
17410
|
+
chordAlt: "Vibraphone",
|
|
17411
|
+
sparkle: "Celesta",
|
|
17412
|
+
bassAlt: "Electric Bass (finger)",
|
|
17413
|
+
harmonyAlt: "Choir Aahs"
|
|
17414
|
+
},
|
|
17415
|
+
// --- MODERN & VIBE: エッジの効いた現代的な響き ---
|
|
17416
|
+
synth_pop: {
|
|
17417
|
+
displayName: "\u30B7\u30F3\u30BB\u30DD\u30C3\u30D7",
|
|
17418
|
+
description: "80s\u301C\u73FE\u4EE3\u307E\u3067\u3002\u629C\u3051\u308B\u30EA\u30FC\u30C9\u3068\u592A\u3044\u30D9\u30FC\u30B9\u306E\u738B\u9053\u3002",
|
|
17419
|
+
melody: "Lead 2 (sawtooth)",
|
|
17420
|
+
submelody: "Lead 4 (chiff)",
|
|
17421
|
+
bass: "Synth Bass 2",
|
|
17422
|
+
chord: "Pad 3 (polysynth)",
|
|
17423
|
+
solo: "Distortion Guitar",
|
|
17424
|
+
chorusLead: "Synth Brass 1",
|
|
17425
|
+
chordAlt: "Electric Piano 2",
|
|
17426
|
+
sparkle: "FX 3 (crystal)",
|
|
17427
|
+
bassAlt: "Synth Bass 1",
|
|
17428
|
+
harmonyAlt: "Synth Choir"
|
|
17429
|
+
},
|
|
17430
|
+
cyber_punk: {
|
|
17431
|
+
displayName: "\u30B5\u30A4\u30D0\u30FC\u30D1\u30F3\u30AF",
|
|
17432
|
+
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",
|
|
17433
|
+
melody: "Lead 8 (bass + lead)",
|
|
17434
|
+
submelody: "Lead 5 (charang)",
|
|
17435
|
+
bass: "Synth Bass 2",
|
|
17436
|
+
chord: "Pad 8 (sweep)",
|
|
17437
|
+
solo: "Distortion Guitar",
|
|
17438
|
+
chorusLead: "Lead 7 (fifths)",
|
|
17439
|
+
chordAlt: "Pad 4 (choir)",
|
|
17440
|
+
sparkle: "FX 3 (crystal)",
|
|
17441
|
+
bassAlt: "Synth Bass 1",
|
|
17442
|
+
harmonyAlt: "Synth Choir"
|
|
17443
|
+
},
|
|
17444
|
+
rock: {
|
|
17445
|
+
displayName: "\u30CF\u30FC\u30C9\u30ED\u30C3\u30AF",
|
|
17446
|
+
description: "\u6B6A\u307F\u30AE\u30BF\u30FC\u3068\u91CD\u539A\u306A\u30D9\u30FC\u30B9\u3067\u3001\u30D1\u30EF\u30FC\u3092\u524D\u9762\u306B\u3002",
|
|
17447
|
+
melody: "Distortion Guitar",
|
|
17448
|
+
submelody: "Rock Organ",
|
|
17449
|
+
bass: "Electric Bass (pick)",
|
|
17450
|
+
chord: "Overdriven Guitar",
|
|
17451
|
+
solo: "Distortion Guitar",
|
|
17452
|
+
chorusLead: "Brass Section",
|
|
17453
|
+
chordAlt: "Electric Guitar (clean)",
|
|
17454
|
+
sparkle: "Electric Guitar (muted)",
|
|
17455
|
+
bassAlt: "Electric Bass (finger)",
|
|
17456
|
+
harmonyAlt: "Choir Aahs"
|
|
17457
|
+
},
|
|
17458
|
+
// --- WORLD & CLASSIC: 特定のジャンル・地域 ---
|
|
17459
|
+
orchestra: {
|
|
17460
|
+
displayName: "\u30AA\u30FC\u30B1\u30B9\u30C8\u30E9",
|
|
17461
|
+
description: "\u58EE\u5927\u306A\u7269\u8A9E\u3092\u4E88\u611F\u3055\u305B\u308B\u3001\u7BA1\u5F26\u697D\u5668\u306E\u91CD\u539A\u306A\u97FF\u304D\u3002",
|
|
17462
|
+
melody: "French Horn",
|
|
17463
|
+
submelody: "Pizzicato Strings",
|
|
17464
|
+
bass: "Cello",
|
|
17465
|
+
chord: "Tremolo Strings",
|
|
17466
|
+
solo: "Violin",
|
|
17467
|
+
chorusLead: "Trumpet",
|
|
17468
|
+
chordAlt: "String Ensemble 1",
|
|
17469
|
+
sparkle: "Orchestral Harp",
|
|
17470
|
+
bassAlt: "Contrabass",
|
|
17471
|
+
harmonyAlt: "Choir Aahs"
|
|
17472
|
+
},
|
|
17473
|
+
japanese_wa: {
|
|
17474
|
+
displayName: "\u548C\u98A8\u30FB\u96C5",
|
|
17475
|
+
description: "\u7434\u3068\u4E09\u5473\u7DDA\u306E\u7E4A\u7D30\u306A\u8ABF\u3079\u306B\u3001\u5C3A\u516B\u306E\u60C5\u7DD2\u3092\u6DFB\u3048\u3066\u3002",
|
|
17476
|
+
melody: "Koto",
|
|
17477
|
+
submelody: "Shamisen",
|
|
17478
|
+
bass: "Taiko Drum",
|
|
17479
|
+
chord: "Shakuhachi",
|
|
17480
|
+
solo: "Shakuhachi",
|
|
17481
|
+
// piano プリセットと同じ理由で Glockenspiel を避ける(音源のピッチずれ)。
|
|
17482
|
+
chorusLead: "Celesta",
|
|
17483
|
+
chordAlt: "Kalimba",
|
|
17484
|
+
sparkle: "Music Box",
|
|
17485
|
+
bassAlt: "Acoustic Bass",
|
|
17486
|
+
harmonyAlt: "Choir Aahs"
|
|
17487
|
+
},
|
|
17488
|
+
arabic_exotic: {
|
|
17489
|
+
displayName: "\u30A8\u30AD\u30BE\u30C1\u30C3\u30AF",
|
|
17490
|
+
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",
|
|
17491
|
+
melody: "Sitar",
|
|
17492
|
+
submelody: "Bagpipe",
|
|
17493
|
+
bass: "Fretless Bass",
|
|
17494
|
+
chord: "Kalimba",
|
|
17495
|
+
solo: "Shanai",
|
|
17496
|
+
chorusLead: "Steel Drums",
|
|
17497
|
+
chordAlt: "Orchestral Harp",
|
|
17498
|
+
sparkle: "Tinkle Bell",
|
|
17499
|
+
bassAlt: "Acoustic Bass",
|
|
17500
|
+
harmonyAlt: "Choir Aahs"
|
|
17501
|
+
},
|
|
17502
|
+
// --- FANTASY & ATMOSPHERE: 雰囲気と余韻 ---
|
|
17503
|
+
fantasy_rpg: {
|
|
17504
|
+
displayName: "\u30D5\u30A1\u30F3\u30BF\u30B8\u30FCRPG",
|
|
17505
|
+
description: "\u30AA\u30AB\u30EA\u30CA\u3068\u30CF\u30FC\u30D7\u304C\u7D21\u3050\u3001\u5192\u967A\u3068\u9B54\u6CD5\u306E\u4E16\u754C\u89B3\u3002",
|
|
17506
|
+
melody: "Ocarina",
|
|
17507
|
+
submelody: "Celesta",
|
|
17508
|
+
bass: "Timpani",
|
|
17509
|
+
chord: "Orchestral Harp",
|
|
17510
|
+
solo: "Pan Flute",
|
|
17511
|
+
chorusLead: "Choir Aahs",
|
|
17512
|
+
chordAlt: "String Ensemble 2",
|
|
17513
|
+
sparkle: "Tinkle Bell",
|
|
17514
|
+
bassAlt: "Contrabass",
|
|
17515
|
+
harmonyAlt: "Choir Aahs"
|
|
17516
|
+
},
|
|
17517
|
+
ambient_cloud: {
|
|
17518
|
+
displayName: "\u30A2\u30F3\u30D3\u30A8\u30F3\u30C8",
|
|
17519
|
+
description: "\u8F2A\u90ED\u3092\u307C\u304B\u3057\u305F\u97F3\u8272\u3067\u3001\u6DF1\u3044\u6CA1\u5165\u611F\u3068\u4F59\u97FB\u3092\u6F14\u51FA\u3002",
|
|
17520
|
+
melody: "Lead 6 (voice)",
|
|
17521
|
+
submelody: "Music Box",
|
|
17522
|
+
bass: "Synth Bass 1",
|
|
17523
|
+
chord: "Pad 7 (halo)",
|
|
17524
|
+
solo: "Lead 3 (calliope)",
|
|
17525
|
+
chorusLead: "Synth Choir",
|
|
17526
|
+
chordAlt: "Pad 5 (bowed)",
|
|
17527
|
+
sparkle: "FX 3 (crystal)",
|
|
17528
|
+
bassAlt: "Synth Bass 2",
|
|
17529
|
+
harmonyAlt: "Synth Choir"
|
|
17530
|
+
},
|
|
17531
|
+
retro_game: {
|
|
17532
|
+
displayName: "8-bit \u30EC\u30C8\u30ED",
|
|
17533
|
+
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",
|
|
17534
|
+
melody: "Lead 1 (square)",
|
|
17535
|
+
submelody: "Lead 2 (sawtooth)",
|
|
17536
|
+
bass: "Synth Bass 1",
|
|
17537
|
+
chord: "Clavinet",
|
|
17538
|
+
solo: "Lead 8 (bass + lead)",
|
|
17539
|
+
chorusLead: "Lead 4 (chiff)",
|
|
17540
|
+
chordAlt: "Lead 5 (charang)",
|
|
17541
|
+
sparkle: "Xylophone",
|
|
17542
|
+
bassAlt: "Synth Bass 2",
|
|
17543
|
+
harmonyAlt: "Lead 6 (voice)"
|
|
17544
|
+
}
|
|
17545
|
+
};
|
|
17546
|
+
var GM_INSTRUMENT_RANGE = {
|
|
17547
|
+
// 鍵盤・音板
|
|
17548
|
+
"Acoustic Grand Piano": [21, 108],
|
|
17549
|
+
"Electric Piano 1": [28, 103],
|
|
17550
|
+
Clavinet: [36, 96],
|
|
17551
|
+
Celesta: [60, 108],
|
|
17552
|
+
Glockenspiel: [79, 108],
|
|
17553
|
+
"Music Box": [72, 108],
|
|
17554
|
+
Vibraphone: [53, 89],
|
|
17555
|
+
Kalimba: [60, 84],
|
|
17556
|
+
"Orchestral Harp": [23, 104],
|
|
17557
|
+
// 弦・撥弦
|
|
17558
|
+
"Acoustic Guitar (steel)": [40, 83],
|
|
17559
|
+
"Acoustic Guitar (nylon)": [40, 83],
|
|
17560
|
+
"Electric Guitar (clean)": [40, 86],
|
|
17561
|
+
"Electric Guitar (jazz)": [40, 86],
|
|
17562
|
+
"Overdriven Guitar": [40, 88],
|
|
17563
|
+
"Distortion Guitar": [40, 88],
|
|
17564
|
+
Violin: [55, 103],
|
|
17565
|
+
Cello: [36, 76],
|
|
17566
|
+
"String Ensemble 1": [28, 100],
|
|
17567
|
+
"Tremolo Strings": [28, 100],
|
|
17568
|
+
"Pizzicato Strings": [28, 96],
|
|
17569
|
+
Sitar: [48, 79],
|
|
17570
|
+
Shamisen: [48, 84],
|
|
17571
|
+
Koto: [41, 77],
|
|
17572
|
+
// ベース
|
|
17573
|
+
"Acoustic Bass": [28, 60],
|
|
17574
|
+
"Electric Bass (finger)": [28, 67],
|
|
17575
|
+
"Electric Bass (pick)": [28, 67],
|
|
17576
|
+
"Fretless Bass": [28, 67],
|
|
17577
|
+
"Synth Bass 1": [24, 72],
|
|
17578
|
+
"Synth Bass 2": [24, 72],
|
|
17579
|
+
// 管
|
|
17580
|
+
Flute: [60, 96],
|
|
17581
|
+
"Pan Flute": [60, 91],
|
|
17582
|
+
Shakuhachi: [62, 86],
|
|
17583
|
+
Ocarina: [60, 84],
|
|
17584
|
+
Harmonica: [60, 96],
|
|
17585
|
+
Bagpipe: [62, 86],
|
|
17586
|
+
Shanai: [60, 86],
|
|
17587
|
+
"Tenor Sax": [44, 75],
|
|
17588
|
+
Trumpet: [55, 82],
|
|
17589
|
+
"Muted Trumpet": [55, 82],
|
|
17590
|
+
"French Horn": [41, 77],
|
|
17591
|
+
"Brass Section": [41, 84],
|
|
17592
|
+
// 声・打・オルガン
|
|
17593
|
+
"Choir Aahs": [43, 84],
|
|
17594
|
+
"Synth Choir": [43, 84],
|
|
17595
|
+
"Steel Drums": [55, 86],
|
|
17596
|
+
"Taiko Drum": [30, 60],
|
|
17597
|
+
Timpani: [36, 57],
|
|
17598
|
+
"Rock Organ": [36, 96],
|
|
17599
|
+
// シンセ(実物が無いので一般的な使用域)
|
|
17600
|
+
"Synth Brass 1": [36, 96],
|
|
17601
|
+
"Lead 1 (square)": [36, 96],
|
|
17602
|
+
"Lead 2 (sawtooth)": [36, 96],
|
|
17603
|
+
"Lead 3 (calliope)": [48, 96],
|
|
17604
|
+
"Lead 4 (chiff)": [48, 96],
|
|
17605
|
+
"Lead 5 (charang)": [40, 96],
|
|
17606
|
+
"Lead 6 (voice)": [43, 91],
|
|
17607
|
+
"Lead 7 (fifths)": [36, 84],
|
|
17608
|
+
"Lead 8 (bass + lead)": [28, 91],
|
|
17609
|
+
"Pad 2 (warm)": [24, 96],
|
|
17610
|
+
"Pad 3 (polysynth)": [24, 96],
|
|
17611
|
+
"Pad 7 (halo)": [24, 96],
|
|
17612
|
+
"Pad 8 (sweep)": [24, 96]
|
|
17613
|
+
};
|
|
17614
|
+
var GM_BRIGHT_CEILING = {
|
|
17615
|
+
Glockenspiel: 72,
|
|
17616
|
+
"Tinkle Bell": 72,
|
|
17617
|
+
"Music Box": 79,
|
|
17618
|
+
Celesta: 84,
|
|
17619
|
+
Kalimba: 79,
|
|
17620
|
+
"Steel Drums": 84,
|
|
17621
|
+
"FX 3 (crystal)": 79
|
|
17622
|
+
};
|
|
17623
|
+
var OCTAVE_FIT_TOLERANCE = 3;
|
|
17624
|
+
var fitInstrumentOctave = (semitoneRange, instrument, wanted) => {
|
|
17625
|
+
const range = GM_INSTRUMENT_RANGE[instrument];
|
|
17626
|
+
if (!range || !semitoneRange) return wanted;
|
|
17627
|
+
const hi = Math.min(range[1], GM_BRIGHT_CEILING[instrument] ?? range[1]);
|
|
17628
|
+
let octave = wanted;
|
|
17629
|
+
while (octave > wanted - 2) {
|
|
17630
|
+
if (semitoneRange[1] + octave * 12 <= hi + OCTAVE_FIT_TOLERANCE) break;
|
|
17631
|
+
octave--;
|
|
17632
|
+
}
|
|
17633
|
+
return octave;
|
|
17634
|
+
};
|
|
17635
|
+
|
|
17636
|
+
// src/advanced-layers.ts
|
|
17637
|
+
var buildAdvancedLayers = (song, config) => {
|
|
17638
|
+
const { edo, stepsPerBar, preset } = config;
|
|
17639
|
+
const semitoneRange = (notes) => {
|
|
17640
|
+
if (notes.length === 0) return null;
|
|
17641
|
+
let lo = Number.POSITIVE_INFINITY;
|
|
17642
|
+
let hi = Number.NEGATIVE_INFINITY;
|
|
17643
|
+
for (const n of notes) {
|
|
17644
|
+
const semi = n.pitchUnits / UNITS_PER_SEMITONE;
|
|
17645
|
+
if (semi < lo) lo = semi;
|
|
17646
|
+
if (semi > hi) hi = semi;
|
|
17647
|
+
}
|
|
17648
|
+
return [Math.round(lo), Math.round(hi)];
|
|
17649
|
+
};
|
|
17650
|
+
const fit = (notes, slot, wanted) => fitInstrumentOctave(semitoneRange(notes), preset[slot], wanted);
|
|
17651
|
+
const kindAtBar = (bar) => song.sections.find(
|
|
17652
|
+
(sec) => bar >= sec.startBar && bar < sec.startBar + sec.bars
|
|
17653
|
+
)?.kind ?? null;
|
|
17654
|
+
const onlyIn = (notes, kinds) => {
|
|
17655
|
+
if (!kinds) return notes;
|
|
17656
|
+
const want = new Set(kinds);
|
|
17657
|
+
return notes.filter((n) => {
|
|
17658
|
+
const kind = kindAtBar(Math.floor(n.startStep / stepsPerBar));
|
|
17659
|
+
return kind !== null && want.has(kind);
|
|
17660
|
+
});
|
|
17661
|
+
};
|
|
17662
|
+
const chordNotes = (pattern, velocityShift = 0) => buildChordPlacements({
|
|
17663
|
+
edo,
|
|
17664
|
+
chordStr: song.chordProgression,
|
|
17665
|
+
patternType: pattern,
|
|
17666
|
+
rootShift: song.rootShift,
|
|
17667
|
+
bpm: song.bpm,
|
|
17668
|
+
stepsPerBar
|
|
17669
|
+
}).map((p) => ({
|
|
17670
|
+
startStep: p.startStep,
|
|
17671
|
+
pitchUnits: p.pitchUnits,
|
|
17672
|
+
durationSteps: p.durationSteps,
|
|
17673
|
+
velocity: Math.max(30, p.velocity + velocityShift)
|
|
17674
|
+
}));
|
|
17675
|
+
const plan = song.arrange;
|
|
17676
|
+
const kindsPresent = [...new Set(song.sections.map((sec) => sec.kind))];
|
|
17677
|
+
const LOUD = ["chorus", "drop_chorus"];
|
|
17678
|
+
const loudKinds = kindsPresent.filter((k) => LOUD.includes(k));
|
|
17679
|
+
const quietKinds = kindsPresent.filter((k) => !LOUD.includes(k));
|
|
17680
|
+
const splittable = loudKinds.length > 0 && quietKinds.length > 0;
|
|
17681
|
+
const leadNotes = plan.lead ? onlyIn(song.melody, plan.lead.sections) : [];
|
|
17682
|
+
const leadOctave = fit(leadNotes, "chorusLead", plan.lead?.octave ?? 0);
|
|
17683
|
+
const leadLayer = {
|
|
17684
|
+
index: 1,
|
|
17685
|
+
notes: leadNotes,
|
|
17686
|
+
octave: leadOctave,
|
|
17687
|
+
// ユニゾンで重ねるときは、オクターブ上より前に出やすいので少し引く。
|
|
17688
|
+
volume: leadOctave === 0 ? 54 : 62,
|
|
17689
|
+
slot: "chorusLead"
|
|
17690
|
+
};
|
|
17691
|
+
const bassNotes = plan.bassLayer ? onlyIn(song.bass, plan.bassLayer.sections) : [];
|
|
17692
|
+
const bassOctave = fit(bassNotes, "bass", plan.bassLayer?.octave ?? 0);
|
|
17693
|
+
const wantBassLayer = plan.bassLayer !== null && bassOctave !== 0;
|
|
17694
|
+
const bassLayer = wantBassLayer ? {
|
|
17695
|
+
index: 5,
|
|
17696
|
+
notes: bassNotes,
|
|
17697
|
+
octave: bassOctave,
|
|
17698
|
+
volume: 58,
|
|
17699
|
+
slot: "bass"
|
|
17700
|
+
} : {
|
|
17701
|
+
index: 5,
|
|
17702
|
+
notes: splittable ? onlyIn(song.bass, loudKinds) : [],
|
|
17703
|
+
octave: 0,
|
|
17704
|
+
volume: 92,
|
|
17705
|
+
slot: "bassAlt"
|
|
17706
|
+
};
|
|
17707
|
+
const padNotes = onlyIn(song.pad, plan.padSections);
|
|
17708
|
+
const layers = [
|
|
17709
|
+
{ index: 0, notes: song.melody, octave: 0, volume: 104, slot: "melody" },
|
|
17710
|
+
leadLayer,
|
|
17711
|
+
// t2 ハモリ。**セクションで分割しない。**
|
|
17712
|
+
// 一度 t12 と loud/quiet で分けてみたが、ハモリは音の87%が盛り上がる側にあり、
|
|
17713
|
+
// 71%の曲は静かな側に1音も無い——分割すると t2 が空になって中身が t12 へ移る。
|
|
17714
|
+
// 「トラック番号と役割の対応は固定」(ピアノロールのどこに何があるかが曲ごとに
|
|
17715
|
+
// 動くとユーザーが編集できない)という原則にも反するので、ここは丸ごと持つ。
|
|
17716
|
+
{ index: 2, notes: song.harmony, octave: 0, volume: 82 },
|
|
17717
|
+
// t3 サブメロ。t14 が間奏ソロを持たないとき、そちらへ盛り上がる側を渡して
|
|
17718
|
+
// こちらは静かな側だけ持つ。対旋律・合いの手がセクションで音色替えする。
|
|
17719
|
+
{
|
|
17720
|
+
index: 3,
|
|
17721
|
+
notes: song.solo.length === 0 && splittable ? onlyIn(song.submelody, quietKinds) : song.submelody,
|
|
17722
|
+
octave: 0,
|
|
17723
|
+
volume: 86,
|
|
17724
|
+
slot: "submelody"
|
|
17725
|
+
},
|
|
17726
|
+
// t4。t5 が `bassAlt` で盛り上がる側を持つときは、こちらは静かな側だけ持つ
|
|
17727
|
+
// (分割であって間引きではない——2本合わせて元のベースが漏れなく鳴る)。
|
|
17728
|
+
{
|
|
17729
|
+
index: 4,
|
|
17730
|
+
notes: !wantBassLayer && splittable ? onlyIn(song.bass, quietKinds) : song.bass,
|
|
17731
|
+
octave: 0,
|
|
17732
|
+
volume: 92,
|
|
17733
|
+
slot: "bass"
|
|
17734
|
+
},
|
|
17735
|
+
bassLayer,
|
|
17736
|
+
// **パッドは伴奏用の楽器で、伴奏より1.5オクターブ高いところを鳴らす。**
|
|
17737
|
+
// そのまま置くとナイロンギターで10半音、カリンバで9半音、尺八で7半音ぶん
|
|
17738
|
+
// 音域を突き抜ける。楽器に合わせて下げる。
|
|
17739
|
+
{
|
|
17740
|
+
index: 6,
|
|
17741
|
+
notes: padNotes,
|
|
17742
|
+
octave: fit(padNotes, "chord", 0),
|
|
17743
|
+
volume: 64,
|
|
17744
|
+
slot: "chord"
|
|
17745
|
+
}
|
|
17746
|
+
];
|
|
17747
|
+
const backingVolumes = [62, 54, 50];
|
|
17748
|
+
for (let i2 = 0; i2 < 3; i2++) {
|
|
17749
|
+
const layer = plan.backing[i2];
|
|
17750
|
+
layers.push({
|
|
17751
|
+
index: 7 + i2,
|
|
17752
|
+
notes: layer ? onlyIn(chordNotes(layer.pattern), layer.sections) : [],
|
|
17753
|
+
octave: layer?.octave ?? 0,
|
|
17754
|
+
volume: backingVolumes[i2],
|
|
17755
|
+
slot: i2 % 2 === 0 ? "chordAlt" : "chord"
|
|
17756
|
+
});
|
|
17757
|
+
}
|
|
17758
|
+
const sparkleNotes = plan.sparkle ? onlyIn(chordNotes(plan.sparkle.pattern, -14), plan.sparkle.sections) : [];
|
|
17759
|
+
layers.push(
|
|
17760
|
+
{
|
|
17761
|
+
index: 10,
|
|
17762
|
+
notes: sparkleNotes,
|
|
17763
|
+
// 装飾は伴奏と別の音色にする(以前はここも `chord` の使い回しだった)。
|
|
17764
|
+
octave: fit(sparkleNotes, "sparkle", plan.sparkle?.octave ?? 0),
|
|
17765
|
+
volume: 56,
|
|
17766
|
+
slot: "sparkle"
|
|
17767
|
+
},
|
|
17768
|
+
// 掛け合い(デュエット)の相手。**歌入り作曲のときだけ**中身が入る。
|
|
17769
|
+
{ index: 11, notes: [], octave: 0, volume: 104, slot: "melody" },
|
|
17770
|
+
// 2声目のハモリ(主旋律を上下から挟む3声)と、主旋律のオクターブ下の重ね。
|
|
17771
|
+
// どちらも曲ごとに出るかどうかが決まる(`song.vocal`)。
|
|
17772
|
+
// t12。3声目のハモリは曲ごとに出るかが決まり、実測28%。
|
|
17773
|
+
//
|
|
17774
|
+
// 出ない曲では**パッド(t6)が鳴っていないセクション**を、別の音色
|
|
17775
|
+
// (`harmonyAlt` =声もの・柔らかい持続音)で受け持つ。パッドはセクション種別の
|
|
17776
|
+
// 39%しか覆っておらず補集合は常に存在するので、ここは**いま何も鳴っていない
|
|
17777
|
+
// 場所に持続音を足す**ことになる——重ねでも写しでもなく、純粋な追加。
|
|
17778
|
+
song.harmony2.length > 0 ? { index: 12, notes: song.harmony2, octave: 0, volume: 74 } : (() => {
|
|
17779
|
+
const rest = plan.padSections ? kindsPresent.filter((k) => !plan.padSections?.includes(k)) : [];
|
|
17780
|
+
const notes = rest.length > 0 ? onlyIn(song.pad, rest) : [];
|
|
17781
|
+
return {
|
|
17782
|
+
index: 12,
|
|
17783
|
+
notes,
|
|
17784
|
+
octave: fit(notes, "harmonyAlt", 0),
|
|
17785
|
+
volume: 60,
|
|
17786
|
+
slot: "harmonyAlt"
|
|
17787
|
+
};
|
|
17788
|
+
})(),
|
|
17789
|
+
// t13。既定は**主旋律のオクターブ下の重ね**で、歌入り作曲ではここに歌詞が付く
|
|
17790
|
+
// (オクターブ下でハモる歌手。単なる写しではない)。
|
|
17791
|
+
//
|
|
17792
|
+
// ただしこの層は曲ごとに出るかどうかが決まり、実測で**18%しか鳴らない**。
|
|
17793
|
+
// 残り82%はトラックが1本まるごと遊ぶ。オクターブ等価の写しに常設の価値は
|
|
17794
|
+
// 無いが、**空けておく価値はもっと無い**ので、層が無い曲では
|
|
17795
|
+
// 「t1(サビ重ね)が担当しないセクションの主旋律を、別の楽器でなぞる」層に回す。
|
|
17796
|
+
// t1 は CHORUS/LOUD 側を持つので、こちらは静かな側を持つ——結果として
|
|
17797
|
+
// **セクションの境目で主旋律に付く音色が入れ替わる**。1トラック1楽器の制約下で
|
|
17798
|
+
// 「パートごとに楽器が変わる」を作れるのは、この書き分けだけ。
|
|
17799
|
+
song.octave.length > 0 ? {
|
|
17800
|
+
index: 13,
|
|
17801
|
+
notes: song.octave,
|
|
17802
|
+
octave: -1,
|
|
17803
|
+
volume: 56,
|
|
17804
|
+
slot: "melody"
|
|
17805
|
+
} : (() => {
|
|
17806
|
+
const leadKinds = new Set(plan.lead?.sections ?? []);
|
|
17807
|
+
const quiet = song.sections.filter((sec) => sec.spec.melody && !leadKinds.has(sec.kind)).map((sec) => sec.kind);
|
|
17808
|
+
const notes = quiet.length > 0 ? onlyIn(song.melody, quiet) : [];
|
|
17809
|
+
const slot = ["solo", "chorusLead", "submelody", "chordAlt"].find(
|
|
17810
|
+
(k) => preset[k] !== preset.melody && preset[k] !== preset.chord
|
|
17811
|
+
) ?? "submelody";
|
|
17812
|
+
return {
|
|
17813
|
+
index: 13,
|
|
17814
|
+
notes,
|
|
17815
|
+
// ユニゾンで置く。**音色だけを変えるのが狙い**なので、
|
|
17816
|
+
// オクターブを動かすと「オクターブ写し」に戻ってしまう。
|
|
17817
|
+
octave: fit(notes, slot, 0),
|
|
17818
|
+
volume: 58,
|
|
17819
|
+
slot
|
|
17820
|
+
};
|
|
17821
|
+
})(),
|
|
17822
|
+
// **間奏のソロ。** 音が入るのは間奏の小節だけなので、この1本だけを
|
|
17823
|
+
// 別の楽器にしても他のセクションの鳴りは変わらない。歌の音域をそのまま
|
|
17824
|
+
// 渡すと管楽器が上へ抜ける(テナーサックスで10半音)ので、ここも合わせる。
|
|
17825
|
+
// t14。**間奏のソロ。** ただし間奏は既定の構成(`DEFAULT_SECTIONS`)に無く、
|
|
17826
|
+
// テンプレートも `jpop_standard` しか含まないので、実測で**0%**——設計上の
|
|
17827
|
+
// 出番が既定では一度も来ないトラックだった。
|
|
17828
|
+
// 間奏が無い曲では、サブメロの盛り上がる側を `solo` の音色で受け持つ
|
|
17829
|
+
// (t3 は静かな側。分割なので音数は増えない)。
|
|
17830
|
+
song.solo.length > 0 ? {
|
|
17831
|
+
index: 14,
|
|
17832
|
+
notes: song.solo,
|
|
17833
|
+
octave: fit(song.solo, "solo", 0),
|
|
17834
|
+
volume: 100,
|
|
17835
|
+
slot: "solo"
|
|
17836
|
+
} : (() => {
|
|
17837
|
+
const notes = splittable ? onlyIn(song.submelody, loudKinds) : [];
|
|
17838
|
+
return {
|
|
17839
|
+
index: 14,
|
|
17840
|
+
notes,
|
|
17841
|
+
octave: fit(notes, "solo", 0),
|
|
17842
|
+
volume: 86,
|
|
17843
|
+
slot: "solo"
|
|
17844
|
+
};
|
|
17845
|
+
})()
|
|
17846
|
+
);
|
|
17847
|
+
return layers;
|
|
17848
|
+
};
|
|
17849
|
+
|
|
16432
17850
|
// src/delay.ts
|
|
16433
17851
|
var DELAY_DIVISIONS = [
|
|
16434
17852
|
{ value: "4", label: "4\u5206", beats: 1 },
|
|
@@ -16849,6 +18267,34 @@ var buildUI = (target, options) => {
|
|
|
16849
18267
|
<span class="dtm-grow"></span>
|
|
16850
18268
|
<span class="dtm-hint" data-dtm="compose-key-hint"></span>
|
|
16851
18269
|
</div>
|
|
18270
|
+
<div class="dtm-row" data-dtm="compose-scale-row">
|
|
18271
|
+
<span class="dtm-label">\u97F3\u968E</span>
|
|
18272
|
+
<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">
|
|
18273
|
+
<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>
|
|
18274
|
+
<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>
|
|
18275
|
+
<optgroup label="\u30DA\u30F3\u30BF\u30C8\u30CB\u30C3\u30AF\uFF085\u97F3\u97F3\u968E\uFF09">
|
|
18276
|
+
<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>
|
|
18277
|
+
<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>
|
|
18278
|
+
<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>
|
|
18279
|
+
<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>
|
|
18280
|
+
<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>
|
|
18281
|
+
</optgroup>
|
|
18282
|
+
<optgroup label="\u30C1\u30E3\u30FC\u30C1\u30E2\u30FC\u30C9\uFF087\u97F3\u97F3\u968E\uFF09">
|
|
18283
|
+
<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>
|
|
18284
|
+
<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>
|
|
18285
|
+
<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>
|
|
18286
|
+
<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>
|
|
18287
|
+
</optgroup>
|
|
18288
|
+
<optgroup label="\u7279\u6B8A\u97F3\u968E\uFF08\u97F3\u7A0B\u96C6\u5408\u3054\u3068\u5165\u308C\u66FF\u308F\u308B\uFF09">
|
|
18289
|
+
<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>
|
|
18290
|
+
<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>
|
|
18291
|
+
<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>
|
|
18292
|
+
<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>
|
|
18293
|
+
</optgroup>
|
|
18294
|
+
</select>
|
|
18295
|
+
<span class="dtm-grow"></span>
|
|
18296
|
+
<span class="dtm-hint" data-dtm="compose-scale-hint"></span>
|
|
18297
|
+
</div>
|
|
16852
18298
|
</div>
|
|
16853
18299
|
<div class="dtm-row">
|
|
16854
18300
|
<span class="dtm-label">\u5168\u4F53\u30B7\u30D5\u30C8</span>
|
|
@@ -17051,6 +18497,8 @@ var buildUI = (target, options) => {
|
|
|
17051
18497
|
composeSectionsLen: sel("compose-sections-len"),
|
|
17052
18498
|
composeKey: sel("compose-key"),
|
|
17053
18499
|
composeKeyHint: sel("compose-key-hint"),
|
|
18500
|
+
composeScale: sel("compose-scale"),
|
|
18501
|
+
composeScaleHint: sel("compose-scale-hint"),
|
|
17054
18502
|
macroComposeVocal: sel("macro-compose-vocal"),
|
|
17055
18503
|
macroComposeInfo: sel("macro-compose-info"),
|
|
17056
18504
|
macroClear: sel("macro-clear"),
|
|
@@ -17085,115 +18533,12 @@ var buildUI = (target, options) => {
|
|
|
17085
18533
|
};
|
|
17086
18534
|
};
|
|
17087
18535
|
|
|
17088
|
-
// src/instrument-presets.ts
|
|
17089
|
-
var INSTRUMENT_PRESETS = {
|
|
17090
|
-
// --- STANDARD: 汎用性と完成度重視 ---
|
|
17091
|
-
piano: {
|
|
17092
|
-
displayName: "\u30B0\u30E9\u30F3\u30C9\u30D4\u30A2\u30CE",
|
|
17093
|
-
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",
|
|
17094
|
-
melody: "Acoustic Grand Piano",
|
|
17095
|
-
submelody: "Vibraphone",
|
|
17096
|
-
bass: "Electric Bass (finger)",
|
|
17097
|
-
chord: "Pad 2 (warm)"
|
|
17098
|
-
},
|
|
17099
|
-
acoustic: {
|
|
17100
|
-
displayName: "\u30A2\u30B3\u30FC\u30B9\u30C6\u30A3\u30C3\u30AF",
|
|
17101
|
-
description: "\u751F\u697D\u5668\u306E\u6E29\u304B\u307F\u3092\u91CD\u8996\u3002\u30D5\u30A9\u30FC\u30AF\u3084\u30DD\u30C3\u30D7\u30B9\u306B\u3002",
|
|
17102
|
-
melody: "Acoustic Guitar (steel)",
|
|
17103
|
-
submelody: "Harmonica",
|
|
17104
|
-
bass: "Acoustic Bass",
|
|
17105
|
-
chord: "Acoustic Guitar (nylon)"
|
|
17106
|
-
},
|
|
17107
|
-
jazz_night: {
|
|
17108
|
-
displayName: "\u30B8\u30E3\u30BA\u30FB\u30CA\u30A4\u30C8",
|
|
17109
|
-
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",
|
|
17110
|
-
melody: "Electric Piano 1",
|
|
17111
|
-
submelody: "Flute",
|
|
17112
|
-
bass: "Acoustic Bass",
|
|
17113
|
-
chord: "Electric Guitar (jazz)"
|
|
17114
|
-
},
|
|
17115
|
-
// --- MODERN & VIBE: エッジの効いた現代的な響き ---
|
|
17116
|
-
synth_pop: {
|
|
17117
|
-
displayName: "\u30B7\u30F3\u30BB\u30DD\u30C3\u30D7",
|
|
17118
|
-
description: "80s\u301C\u73FE\u4EE3\u307E\u3067\u3002\u629C\u3051\u308B\u30EA\u30FC\u30C9\u3068\u592A\u3044\u30D9\u30FC\u30B9\u306E\u738B\u9053\u3002",
|
|
17119
|
-
melody: "Lead 2 (sawtooth)",
|
|
17120
|
-
submelody: "Lead 4 (chiff)",
|
|
17121
|
-
bass: "Synth Bass 2",
|
|
17122
|
-
chord: "Pad 3 (polysynth)"
|
|
17123
|
-
},
|
|
17124
|
-
cyber_punk: {
|
|
17125
|
-
displayName: "\u30B5\u30A4\u30D0\u30FC\u30D1\u30F3\u30AF",
|
|
17126
|
-
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",
|
|
17127
|
-
melody: "Lead 8 (bass + lead)",
|
|
17128
|
-
submelody: "Lead 5 (charang)",
|
|
17129
|
-
bass: "Synth Bass 2",
|
|
17130
|
-
chord: "Pad 8 (sweep)"
|
|
17131
|
-
},
|
|
17132
|
-
rock: {
|
|
17133
|
-
displayName: "\u30CF\u30FC\u30C9\u30ED\u30C3\u30AF",
|
|
17134
|
-
description: "\u6B6A\u307F\u30AE\u30BF\u30FC\u3068\u91CD\u539A\u306A\u30D9\u30FC\u30B9\u3067\u3001\u30D1\u30EF\u30FC\u3092\u524D\u9762\u306B\u3002",
|
|
17135
|
-
melody: "Distortion Guitar",
|
|
17136
|
-
submelody: "Rock Organ",
|
|
17137
|
-
bass: "Electric Bass (pick)",
|
|
17138
|
-
chord: "Overdriven Guitar"
|
|
17139
|
-
},
|
|
17140
|
-
// --- WORLD & CLASSIC: 特定のジャンル・地域 ---
|
|
17141
|
-
orchestra: {
|
|
17142
|
-
displayName: "\u30AA\u30FC\u30B1\u30B9\u30C8\u30E9",
|
|
17143
|
-
description: "\u58EE\u5927\u306A\u7269\u8A9E\u3092\u4E88\u611F\u3055\u305B\u308B\u3001\u7BA1\u5F26\u697D\u5668\u306E\u91CD\u539A\u306A\u97FF\u304D\u3002",
|
|
17144
|
-
melody: "French Horn",
|
|
17145
|
-
submelody: "Pizzicato Strings",
|
|
17146
|
-
bass: "Cello",
|
|
17147
|
-
chord: "Tremolo Strings"
|
|
17148
|
-
},
|
|
17149
|
-
japanese_wa: {
|
|
17150
|
-
displayName: "\u548C\u98A8\u30FB\u96C5",
|
|
17151
|
-
description: "\u7434\u3068\u4E09\u5473\u7DDA\u306E\u7E4A\u7D30\u306A\u8ABF\u3079\u306B\u3001\u5C3A\u516B\u306E\u60C5\u7DD2\u3092\u6DFB\u3048\u3066\u3002",
|
|
17152
|
-
melody: "Koto",
|
|
17153
|
-
submelody: "Shamisen",
|
|
17154
|
-
bass: "Taiko Drum",
|
|
17155
|
-
chord: "Shakuhachi"
|
|
17156
|
-
},
|
|
17157
|
-
arabic_exotic: {
|
|
17158
|
-
displayName: "\u30A8\u30AD\u30BE\u30C1\u30C3\u30AF",
|
|
17159
|
-
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",
|
|
17160
|
-
melody: "Sitar",
|
|
17161
|
-
submelody: "Bagpipe",
|
|
17162
|
-
bass: "Fretless Bass",
|
|
17163
|
-
chord: "Kalimba"
|
|
17164
|
-
},
|
|
17165
|
-
// --- FANTASY & ATMOSPHERE: 雰囲気と余韻 ---
|
|
17166
|
-
fantasy_rpg: {
|
|
17167
|
-
displayName: "\u30D5\u30A1\u30F3\u30BF\u30B8\u30FCRPG",
|
|
17168
|
-
description: "\u30AA\u30AB\u30EA\u30CA\u3068\u30CF\u30FC\u30D7\u304C\u7D21\u3050\u3001\u5192\u967A\u3068\u9B54\u6CD5\u306E\u4E16\u754C\u89B3\u3002",
|
|
17169
|
-
melody: "Ocarina",
|
|
17170
|
-
submelody: "Celesta",
|
|
17171
|
-
bass: "Timpani",
|
|
17172
|
-
chord: "Orchestral Harp"
|
|
17173
|
-
},
|
|
17174
|
-
ambient_cloud: {
|
|
17175
|
-
displayName: "\u30A2\u30F3\u30D3\u30A8\u30F3\u30C8",
|
|
17176
|
-
description: "\u8F2A\u90ED\u3092\u307C\u304B\u3057\u305F\u97F3\u8272\u3067\u3001\u6DF1\u3044\u6CA1\u5165\u611F\u3068\u4F59\u97FB\u3092\u6F14\u51FA\u3002",
|
|
17177
|
-
melody: "Lead 6 (voice)",
|
|
17178
|
-
submelody: "Music Box",
|
|
17179
|
-
bass: "Synth Bass 1",
|
|
17180
|
-
chord: "Pad 7 (halo)"
|
|
17181
|
-
},
|
|
17182
|
-
retro_game: {
|
|
17183
|
-
displayName: "8-bit \u30EC\u30C8\u30ED",
|
|
17184
|
-
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",
|
|
17185
|
-
melody: "Lead 1 (square)",
|
|
17186
|
-
submelody: "Lead 2 (sawtooth)",
|
|
17187
|
-
bass: "Synth Bass 1",
|
|
17188
|
-
chord: "Clavinet"
|
|
17189
|
-
}
|
|
17190
|
-
};
|
|
17191
|
-
|
|
17192
18536
|
// src/macro-state.ts
|
|
17193
18537
|
var MACRO_STORAGE_KEYS = {
|
|
17194
18538
|
template: "dtm-macro:template",
|
|
17195
18539
|
sections: "dtm-macro:sections",
|
|
17196
18540
|
key: "dtm-macro:key",
|
|
18541
|
+
scale: "dtm-macro:scale",
|
|
17197
18542
|
shift: "dtm-macro:shift",
|
|
17198
18543
|
transpose: "dtm-macro:transpose"
|
|
17199
18544
|
};
|
|
@@ -19353,6 +20698,7 @@ var COMPOSE_INFO_HTML = `
|
|
|
19353
20698
|
<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>
|
|
19354
20699
|
<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>
|
|
19355
20700
|
<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>
|
|
20701
|
+
<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>
|
|
19356
20702
|
</ul>
|
|
19357
20703
|
<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>
|
|
19358
20704
|
<h4>\u3067\u304D\u3042\u304C\u308A\u306E\u9078\u3073\u65B9</h4>
|
|
@@ -19371,6 +20717,18 @@ var COMPOSE_INFO_HTML = `
|
|
|
19371
20717
|
<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>
|
|
19372
20718
|
</ul>
|
|
19373
20719
|
<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>
|
|
20720
|
+
<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>
|
|
20721
|
+
<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>
|
|
20722
|
+
<ul>
|
|
20723
|
+
<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>
|
|
20724
|
+
<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>
|
|
20725
|
+
<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>
|
|
20726
|
+
<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>
|
|
20727
|
+
</ul>
|
|
20728
|
+
<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>
|
|
20729
|
+
<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>
|
|
20730
|
+
<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>
|
|
20731
|
+
<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>
|
|
19374
20732
|
<h4>\u305D\u306E\u307B\u304B</h4>
|
|
19375
20733
|
<ul>
|
|
19376
20734
|
<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>
|
|
@@ -19637,26 +20995,6 @@ var pickComposeVocal = (exclude) => {
|
|
|
19637
20995
|
const list = pool.length > 0 ? pool : COMPOSE_VOCAL_POOL;
|
|
19638
20996
|
return list[Math.floor(Math.random() * list.length)] ?? "klatt";
|
|
19639
20997
|
};
|
|
19640
|
-
var ADVANCED_COMPOSE_LAYOUT = [
|
|
19641
|
-
{ index: 0, part: "melody", octave: 0, volume: 104 },
|
|
19642
|
-
{ index: 1, part: "melody", octave: 1, volume: 62 },
|
|
19643
|
-
{ index: 2, part: "harmony", octave: 0, volume: 82 },
|
|
19644
|
-
{ index: 3, part: "submelody", octave: 0, volume: 86 },
|
|
19645
|
-
{ index: 4, part: "bass", octave: 0, volume: 92 },
|
|
19646
|
-
{ index: 5, part: "bass", octave: -1, volume: 58 },
|
|
19647
|
-
{ index: 6, part: "pad", octave: 0, volume: 64 },
|
|
19648
|
-
{ index: 7, part: "block", octave: 0, volume: 62 },
|
|
19649
|
-
{ index: 8, part: "arpeggio", octave: 0, volume: 54 },
|
|
19650
|
-
{ index: 9, part: "offbeat", octave: 0, volume: 50 },
|
|
19651
|
-
{ index: 10, part: "uwamono", octave: 1, volume: 56 },
|
|
19652
|
-
// 掛け合い(デュエット)の相手。**歌入り作曲のときだけ**中身が入る。
|
|
19653
|
-
// 作曲だけならメロディは t0 が全部持つので、ここは空のまま。
|
|
19654
|
-
{ index: 11, part: "duet", octave: 0, volume: 104 },
|
|
19655
|
-
// 2声目のハモリ(主旋律を上下から挟む3声)と、主旋律のオクターブ下の重ね。
|
|
19656
|
-
// どちらも曲ごとに出るかどうかが決まる(`song.vocal`)。
|
|
19657
|
-
{ index: 12, part: "harmony2", octave: 0, volume: 74 },
|
|
19658
|
-
{ index: 13, part: "melody", octave: -1, volume: 56 }
|
|
19659
|
-
];
|
|
19660
20998
|
var LYRIC_MODEL_CATEGORIES = [
|
|
19661
20999
|
{
|
|
19662
21000
|
label: "kusa\u30D7\u30EA\u30BB\u30C3\u30C8",
|
|
@@ -19812,7 +21150,7 @@ var mountDAW = (target, options = {}) => {
|
|
|
19812
21150
|
showChord,
|
|
19813
21151
|
showMidiSearch,
|
|
19814
21152
|
// 「作曲」は simple では役割固定の4トラックへ、advanced では15トラックへ
|
|
19815
|
-
// 編曲を展開する({@link
|
|
21153
|
+
// 編曲を展開する({@link buildAdvancedLayers})。どちらでも出す。
|
|
19816
21154
|
showCompose: true
|
|
19817
21155
|
});
|
|
19818
21156
|
refs.masterVolume.value = String(options.masterVolume ?? 50);
|
|
@@ -20006,6 +21344,14 @@ var mountDAW = (target, options = {}) => {
|
|
|
20006
21344
|
while (customVocalsMap.has(`custom${n}`)) n++;
|
|
20007
21345
|
return `custom${n}`;
|
|
20008
21346
|
};
|
|
21347
|
+
const getVocalIconSrc = (lyricModel) => {
|
|
21348
|
+
if (!lyricModel) return void 0;
|
|
21349
|
+
const customDef = customVocalsMap.get(lyricModel);
|
|
21350
|
+
if (customDef !== void 0)
|
|
21351
|
+
return customDef.iconUrl || FALLBACK_VOCAL_ICON;
|
|
21352
|
+
const imgKey = VOICE_IMAGE_KEY[lyricModel.toLowerCase()];
|
|
21353
|
+
return imgKey ? VOICE_IMAGES[imgKey] : void 0;
|
|
21354
|
+
};
|
|
20009
21355
|
let selectedNotes = [];
|
|
20010
21356
|
let selectionRect = null;
|
|
20011
21357
|
let copiedNotes = [];
|
|
@@ -20139,6 +21485,7 @@ var mountDAW = (target, options = {}) => {
|
|
|
20139
21485
|
vocalTension: t1?.vocalTension ?? 50,
|
|
20140
21486
|
vocalOctaveUnison: t1?.vocalOctaveUnison ?? "none",
|
|
20141
21487
|
trackInstrument: t1?.trackInstrument ?? "",
|
|
21488
|
+
composeSlot: null,
|
|
20142
21489
|
trackCompression: t1?.trackCompression ?? 0,
|
|
20143
21490
|
trackWidth: t1?.trackWidth ?? 100,
|
|
20144
21491
|
trackReverbSend: t1?.trackReverbSend ?? 0,
|
|
@@ -21190,25 +22537,38 @@ var mountDAW = (target, options = {}) => {
|
|
|
21190
22537
|
refs.undoBtn.disabled = !core.canUndo();
|
|
21191
22538
|
refs.redoBtn.disabled = !core.canRedo();
|
|
21192
22539
|
};
|
|
21193
|
-
const
|
|
22540
|
+
const updateTrackTabs = () => {
|
|
21194
22541
|
refs.trackTabs.innerHTML = "";
|
|
21195
22542
|
trackPillEls.clear();
|
|
21196
22543
|
for (const [i2, t] of trackStates.entries()) {
|
|
21197
22544
|
const [r, g, b] = t.config.color;
|
|
21198
22545
|
const isActive = t.config.id === activeTrackId;
|
|
21199
22546
|
const btn = document.createElement("button");
|
|
21200
|
-
|
|
22547
|
+
const vocalIconSrc = getVocalIconSrc(t.lyricModel);
|
|
22548
|
+
btn.className = `dtm-pill ${isActive ? "dtm-pill--active" : ""} ${vocalIconSrc ? "dtm-pill--vocal" : ""}`;
|
|
21201
22549
|
btn.style.setProperty("--dtm-pill-color", `rgb(${r},${g},${b})`);
|
|
22550
|
+
if (vocalIconSrc) {
|
|
22551
|
+
btn.style.setProperty(
|
|
22552
|
+
"--dtm-pill-icon",
|
|
22553
|
+
`url(${JSON.stringify(vocalIconSrc)})`
|
|
22554
|
+
);
|
|
22555
|
+
}
|
|
21202
22556
|
btn.title = `Track ${i2 + 1}: ${t.config.name}`;
|
|
21203
22557
|
btn.setAttribute(
|
|
21204
22558
|
"aria-label",
|
|
21205
|
-
`Track ${i2 + 1}: ${t.config.name}${isActive ? " (\u9078\u629E\u4E2D)" : ""}`
|
|
22559
|
+
`Track ${i2 + 1}: ${t.config.name}${isActive ? " (\u9078\u629E\u4E2D)" : ""}${vocalIconSrc ? "\uFF08\u30DC\u30FC\u30AB\u30EB\u9078\u629E\u4E2D\uFF09" : ""}`
|
|
21206
22560
|
);
|
|
21207
|
-
|
|
22561
|
+
const labelEl = document.createElement("span");
|
|
22562
|
+
labelEl.className = "dtm-pill__label";
|
|
22563
|
+
labelEl.textContent = String(i2 + 1);
|
|
22564
|
+
btn.appendChild(labelEl);
|
|
21208
22565
|
btn.addEventListener("click", () => switchTrack(t.config.id));
|
|
21209
22566
|
refs.trackTabs.appendChild(btn);
|
|
21210
22567
|
trackPillEls.set(t.config.id, btn);
|
|
21211
22568
|
}
|
|
22569
|
+
};
|
|
22570
|
+
const updateTrackPanel = () => {
|
|
22571
|
+
updateTrackTabs();
|
|
21212
22572
|
const active = getActive();
|
|
21213
22573
|
const activeIndex = trackStates.findIndex(
|
|
21214
22574
|
(t) => t.config.id === activeTrackId
|
|
@@ -21525,6 +22885,7 @@ var mountDAW = (target, options = {}) => {
|
|
|
21525
22885
|
syncInstDisabled();
|
|
21526
22886
|
instSel.addEventListener("change", () => {
|
|
21527
22887
|
active.trackInstrument = instSel.value;
|
|
22888
|
+
active.composeSlot = null;
|
|
21528
22889
|
const trackIndex = trackStates.indexOf(active);
|
|
21529
22890
|
options.onTrackInstrumentChange?.(trackIndex, active.trackInstrument);
|
|
21530
22891
|
persistTrack1(active);
|
|
@@ -21928,6 +23289,7 @@ var mountDAW = (target, options = {}) => {
|
|
|
21928
23289
|
redrawAll();
|
|
21929
23290
|
fireLyricsChange(active);
|
|
21930
23291
|
reloadVoicesForModel(active.lyricModel);
|
|
23292
|
+
updateTrackTabs();
|
|
21931
23293
|
});
|
|
21932
23294
|
lyricCustomGuide.addEventListener("click", () => {
|
|
21933
23295
|
showModal("\u30AB\u30B9\u30BF\u30E0\u97F3\u58F0(.koe)\u306E\u4F7F\u3044\u65B9", KOE_INFO_HTML);
|
|
@@ -22461,6 +23823,7 @@ var mountDAW = (target, options = {}) => {
|
|
|
22461
23823
|
}
|
|
22462
23824
|
trackStates.forEach((t, i2) => {
|
|
22463
23825
|
if (applyActiveOnly && i2 !== activeTrackIndex) return;
|
|
23826
|
+
t.composeSlot = null;
|
|
22464
23827
|
const name = normalizeInstrumentName(meta.trackInstruments?.[i2] ?? "");
|
|
22465
23828
|
if (t.trackInstrument !== name) {
|
|
22466
23829
|
t.trackInstrument = name;
|
|
@@ -22712,7 +24075,7 @@ var mountDAW = (target, options = {}) => {
|
|
|
22712
24075
|
const p = programOfInstrumentName(t.trackInstrument);
|
|
22713
24076
|
if (p !== null) program = p;
|
|
22714
24077
|
} else if (!t.lyricModel) {
|
|
22715
|
-
const role = DECLARED_ROLE[t.config.id] ?? "melody";
|
|
24078
|
+
const role = t.composeSlot ?? DECLARED_ROLE[t.config.id] ?? "melody";
|
|
22716
24079
|
const instName = autoPreset[role] ?? autoPreset.melody;
|
|
22717
24080
|
const p = programOfInstrumentName(instName);
|
|
22718
24081
|
if (p !== null) program = p;
|
|
@@ -23081,7 +24444,7 @@ var mountDAW = (target, options = {}) => {
|
|
|
23081
24444
|
if (!stats) continue;
|
|
23082
24445
|
const role = DECLARED_ROLE[t.config.id] ?? classifyTrackRole(stats, t.config.id === topSingleVoiceId);
|
|
23083
24446
|
roleByTrackId.set(t.config.id, role);
|
|
23084
|
-
const instName = autoPreset[role];
|
|
24447
|
+
const instName = autoPreset[t.composeSlot ?? role] ?? autoPreset[role];
|
|
23085
24448
|
t.trackInstrument = instName;
|
|
23086
24449
|
const trackIndex = trackStates.indexOf(t);
|
|
23087
24450
|
options.onTrackInstrumentChange?.(trackIndex, instName);
|
|
@@ -23232,6 +24595,15 @@ var mountDAW = (target, options = {}) => {
|
|
|
23232
24595
|
refs.composeKey.value = savedKey;
|
|
23233
24596
|
}
|
|
23234
24597
|
}
|
|
24598
|
+
const savedScale = readMacroSetting("scale");
|
|
24599
|
+
if (savedScale && refs.composeScale) {
|
|
24600
|
+
const hasOption = Array.from(refs.composeScale.options).some(
|
|
24601
|
+
(opt) => opt.value === savedScale
|
|
24602
|
+
);
|
|
24603
|
+
if (hasOption) {
|
|
24604
|
+
refs.composeScale.value = savedScale;
|
|
24605
|
+
}
|
|
24606
|
+
}
|
|
23235
24607
|
const savedShift = readMacroSetting("shift");
|
|
23236
24608
|
if (savedShift && refs.shiftSelect) {
|
|
23237
24609
|
const hasOption = Array.from(refs.shiftSelect.options).some(
|
|
@@ -23294,6 +24666,20 @@ var mountDAW = (target, options = {}) => {
|
|
|
23294
24666
|
});
|
|
23295
24667
|
updateComposeKeyHint();
|
|
23296
24668
|
}
|
|
24669
|
+
const updateComposeScaleHint = () => {
|
|
24670
|
+
if (!refs.composeScale || !refs.composeScaleHint) return;
|
|
24671
|
+
const desc = getComposeScaleDescription(refs.composeScale.value);
|
|
24672
|
+
refs.composeScaleHint.textContent = desc;
|
|
24673
|
+
refs.composeScaleHint.title = desc;
|
|
24674
|
+
};
|
|
24675
|
+
const composeScale = refs.composeScale;
|
|
24676
|
+
if (composeScale) {
|
|
24677
|
+
composeScale.addEventListener("change", () => {
|
|
24678
|
+
writeMacroSetting("scale", composeScale.value);
|
|
24679
|
+
updateComposeScaleHint();
|
|
24680
|
+
});
|
|
24681
|
+
updateComposeScaleHint();
|
|
24682
|
+
}
|
|
23297
24683
|
if (refs.shiftSelect) {
|
|
23298
24684
|
refs.shiftSelect.addEventListener("change", () => {
|
|
23299
24685
|
writeMacroSetting("shift", refs.shiftSelect.value);
|
|
@@ -23314,6 +24700,7 @@ var mountDAW = (target, options = {}) => {
|
|
|
23314
24700
|
sections: selectedComposeSections(),
|
|
23315
24701
|
template: tmpl,
|
|
23316
24702
|
baseKey: refs.composeKey?.value ?? "any",
|
|
24703
|
+
scale: refs.composeScale?.value ?? "auto",
|
|
23317
24704
|
// 直近に作った曲の特徴を渡すと、それらから離れた候補に加点される。
|
|
23318
24705
|
// 「作曲」を続けて押したときに似た曲が並ぶのを防ぐ。
|
|
23319
24706
|
recent: recentComposeFingerprints
|
|
@@ -23347,45 +24734,39 @@ var mountDAW = (target, options = {}) => {
|
|
|
23347
24734
|
}
|
|
23348
24735
|
track.core.endBatch();
|
|
23349
24736
|
};
|
|
24737
|
+
const shouldAutoInstrument = !currentInstrument || currentInstrument === "auto" || currentInstrument === autoComposeInstrument;
|
|
24738
|
+
if (shouldAutoInstrument && song.instrument) {
|
|
24739
|
+
currentInstrument = song.instrument;
|
|
24740
|
+
autoComposeInstrument = song.instrument;
|
|
24741
|
+
options.onInstrumentChange?.(song.instrument);
|
|
24742
|
+
}
|
|
23350
24743
|
if (isAdvanced) {
|
|
23351
|
-
|
|
24744
|
+
const layers = buildAdvancedLayers(song, {
|
|
24745
|
+
edo: renderConfig.edo,
|
|
24746
|
+
stepsPerBar: renderConfig.stepsPerBar,
|
|
24747
|
+
preset: INSTRUMENT_PRESETS[currentInstrument] ?? INSTRUMENT_PRESETS.piano
|
|
24748
|
+
});
|
|
24749
|
+
for (const layer of layers) {
|
|
23352
24750
|
const track = trackStates[layer.index];
|
|
23353
24751
|
if (!track) continue;
|
|
23354
|
-
|
|
23355
|
-
edo: renderConfig.edo,
|
|
23356
|
-
chordStr: song.chordProgression,
|
|
23357
|
-
patternType: "arpeggio",
|
|
23358
|
-
rootShift: song.rootShift,
|
|
23359
|
-
bpm: song.bpm,
|
|
23360
|
-
stepsPerBar: renderConfig.stepsPerBar
|
|
23361
|
-
}).map((p) => ({
|
|
23362
|
-
startStep: p.startStep,
|
|
23363
|
-
pitchUnits: p.pitchUnits,
|
|
23364
|
-
durationSteps: p.durationSteps,
|
|
23365
|
-
velocity: Math.max(30, p.velocity - 14)
|
|
23366
|
-
})) : buildChordPlacements({
|
|
23367
|
-
edo: renderConfig.edo,
|
|
23368
|
-
chordStr: song.chordProgression,
|
|
23369
|
-
patternType: layer.part,
|
|
23370
|
-
rootShift: song.rootShift,
|
|
23371
|
-
bpm: song.bpm,
|
|
23372
|
-
stepsPerBar: renderConfig.stepsPerBar
|
|
23373
|
-
}).map((p) => ({
|
|
23374
|
-
startStep: p.startStep,
|
|
23375
|
-
pitchUnits: p.pitchUnits,
|
|
23376
|
-
durationSteps: p.durationSteps,
|
|
23377
|
-
velocity: p.velocity
|
|
23378
|
-
}));
|
|
23379
|
-
writeTrackAt(layer.index, notes);
|
|
24752
|
+
writeTrackAt(layer.index, layer.notes);
|
|
23380
24753
|
track.trackOctave = layer.octave;
|
|
23381
24754
|
track.volume = layer.volume;
|
|
23382
24755
|
track.core.setVolume(layer.volume);
|
|
24756
|
+
track.composeSlot = layer.notes.length > 0 ? layer.slot ?? null : null;
|
|
24757
|
+
if (layer.notes.length === 0 && track.trackInstrument) {
|
|
24758
|
+
track.trackInstrument = "";
|
|
24759
|
+
options.onTrackInstrumentChange?.(layer.index, "");
|
|
24760
|
+
}
|
|
23383
24761
|
}
|
|
23384
24762
|
for (let i2 = 0; i2 < trackStates.length; i2++) {
|
|
23385
|
-
if (
|
|
24763
|
+
if (layers.some((l) => l.index === i2)) continue;
|
|
23386
24764
|
writeTrackAt(i2, []);
|
|
24765
|
+
const t = trackStates[i2];
|
|
24766
|
+
if (t) t.composeSlot = null;
|
|
23387
24767
|
}
|
|
23388
24768
|
} else {
|
|
24769
|
+
for (const t of trackStates) t.composeSlot = null;
|
|
23389
24770
|
writeTrack("melody", song.melody);
|
|
23390
24771
|
writeTrack("submelody", song.submelody);
|
|
23391
24772
|
writeTrack("bass", song.bass);
|
|
@@ -23402,12 +24783,6 @@ var mountDAW = (target, options = {}) => {
|
|
|
23402
24783
|
refs.drumSelect.value = song.drum;
|
|
23403
24784
|
options.onDrumChange?.(song.drum);
|
|
23404
24785
|
applyDrumPatternFont(song.drum);
|
|
23405
|
-
const shouldAutoInstrument = !currentInstrument || currentInstrument === "auto" || currentInstrument === autoComposeInstrument;
|
|
23406
|
-
if (shouldAutoInstrument && song.instrument) {
|
|
23407
|
-
currentInstrument = song.instrument;
|
|
23408
|
-
autoComposeInstrument = song.instrument;
|
|
23409
|
-
options.onInstrumentChange?.(song.instrument);
|
|
23410
|
-
}
|
|
23411
24786
|
if (withVocal) {
|
|
23412
24787
|
autoComposeVocalTracks.clear();
|
|
23413
24788
|
const melodyTrack = isAdvanced ? trackStates[0] : trackStates.find((t) => t.config.id === "melody");
|
|
@@ -24644,6 +26019,7 @@ var mountDAW = (target, options = {}) => {
|
|
|
24644
26019
|
if (!t) return;
|
|
24645
26020
|
const name = normalizeInstrumentName(instrumentName);
|
|
24646
26021
|
t.trackInstrument = name;
|
|
26022
|
+
t.composeSlot = null;
|
|
24647
26023
|
if (t.config.id === activeTrackId) updateTrackPanel();
|
|
24648
26024
|
},
|
|
24649
26025
|
noteToCanvas: (step, pitch) => {
|
|
@@ -24767,8 +26143,9 @@ var playSingingMML = async (mml, options = {}) => {
|
|
|
24767
26143
|
});
|
|
24768
26144
|
const ownsCtx = !options.audioContext;
|
|
24769
26145
|
const ctx = options.audioContext ?? new AudioContext();
|
|
24770
|
-
const
|
|
26146
|
+
const rawDestination = options.destination ?? ctx.destination;
|
|
24771
26147
|
const useSynth = options.synth ?? !options.onPlayNote;
|
|
26148
|
+
const destination = createSafetyLimiter(ctx, rawDestination);
|
|
24772
26149
|
const synth = useSynth ? createSynth(ctx, destination) : null;
|
|
24773
26150
|
const pauseWhenHidden = options.pauseWhenHidden ?? ownsCtx;
|
|
24774
26151
|
let playing = false;
|
|
@@ -25773,21 +27150,29 @@ var createDtmStudio = async (options = {}) => {
|
|
|
25773
27150
|
};
|
|
25774
27151
|
applyGlueCompression(options.masterCompression ?? 0);
|
|
25775
27152
|
const setMasterCompression = (amount) => applyGlueCompression(amount);
|
|
25776
|
-
const safetyLimiter = audioCtx.createDynamicsCompressor();
|
|
25777
|
-
safetyLimiter.threshold.value = -1;
|
|
25778
|
-
safetyLimiter.knee.value = 0;
|
|
25779
|
-
safetyLimiter.ratio.value = 20;
|
|
25780
|
-
safetyLimiter.attack.value = 1e-3;
|
|
25781
|
-
safetyLimiter.release.value = 0.1;
|
|
25782
|
-
glueMakeup.connect(safetyLimiter);
|
|
25783
27153
|
const fadeGain = audioCtx.createGain();
|
|
25784
27154
|
fadeGain.gain.value = 1;
|
|
25785
|
-
safetyLimiter.connect(fadeGain);
|
|
25786
27155
|
fadeGain.connect(options.destination ?? audioCtx.destination);
|
|
27156
|
+
const safetyLimiter = createSafetyLimiter(audioCtx, fadeGain);
|
|
27157
|
+
glueMakeup.connect(safetyLimiter);
|
|
27158
|
+
const FADE_RESTORE_SEC = 0.02;
|
|
27159
|
+
const rampFadeGainToUnity = (from, at) => {
|
|
27160
|
+
fadeGain.gain.setValueAtTime(from, at);
|
|
27161
|
+
fadeGain.gain.linearRampToValueAtTime(1, at + FADE_RESTORE_SEC);
|
|
27162
|
+
};
|
|
27163
|
+
const restoreFadeGainIfMuted = () => {
|
|
27164
|
+
const current = fadeGain.gain.value;
|
|
27165
|
+
if (current >= 1) return;
|
|
27166
|
+
const now = audioCtx.currentTime;
|
|
27167
|
+
fadeGain.gain.cancelScheduledValues(now);
|
|
27168
|
+
rampFadeGainToUnity(current, now);
|
|
27169
|
+
};
|
|
25787
27170
|
const scheduleFade = (params) => {
|
|
25788
|
-
|
|
27171
|
+
const now = audioCtx.currentTime;
|
|
27172
|
+
const current = fadeGain.gain.value;
|
|
27173
|
+
fadeGain.gain.cancelScheduledValues(now);
|
|
25789
27174
|
if (!params) {
|
|
25790
|
-
|
|
27175
|
+
rampFadeGainToUnity(current, now);
|
|
25791
27176
|
return;
|
|
25792
27177
|
}
|
|
25793
27178
|
const { fadeInStartAt, fadeInEndAt, fadeOutStartAt, fadeOutEndAt } = params;
|
|
@@ -25795,13 +27180,12 @@ var createDtmStudio = async (options = {}) => {
|
|
|
25795
27180
|
fadeGain.gain.setValueAtTime(0, fadeInStartAt);
|
|
25796
27181
|
fadeGain.gain.linearRampToValueAtTime(1, fadeInEndAt);
|
|
25797
27182
|
} else {
|
|
25798
|
-
|
|
27183
|
+
rampFadeGainToUnity(current, now);
|
|
25799
27184
|
}
|
|
25800
27185
|
if (fadeOutStartAt !== void 0 && fadeOutEndAt !== void 0) {
|
|
25801
27186
|
fadeGain.gain.setValueAtTime(1, fadeOutStartAt);
|
|
25802
27187
|
fadeGain.gain.linearRampToValueAtTime(0, fadeOutEndAt);
|
|
25803
|
-
|
|
25804
|
-
fadeGain.gain.setValueAtTime(1, fadeOutEndAt + 2);
|
|
27188
|
+
rampFadeGainToUnity(0, fadeOutEndAt + 2);
|
|
25805
27189
|
}
|
|
25806
27190
|
};
|
|
25807
27191
|
const clipMeter = createClipMeter(audioCtx, glueMakeup);
|
|
@@ -25861,8 +27245,7 @@ var createDtmStudio = async (options = {}) => {
|
|
|
25861
27245
|
};
|
|
25862
27246
|
};
|
|
25863
27247
|
const resumeAudio = () => {
|
|
25864
|
-
|
|
25865
|
-
fadeGain.gain.setValueAtTime(1, audioCtx.currentTime);
|
|
27248
|
+
restoreFadeGainIfMuted();
|
|
25866
27249
|
if (audioCtx.state === "closed") return Promise.resolve();
|
|
25867
27250
|
return audioCtx.resume();
|
|
25868
27251
|
};
|
|
@@ -26073,12 +27456,6 @@ var createDtmStudio = async (options = {}) => {
|
|
|
26073
27456
|
await listReady;
|
|
26074
27457
|
nameToKey = await buildNameToKeyMapping();
|
|
26075
27458
|
await Promise.all([drumReady, loadPreset(defaultPreset)]);
|
|
26076
|
-
const restoreFadeGainIfMuted = () => {
|
|
26077
|
-
if (fadeGain.gain.value < 1) {
|
|
26078
|
-
fadeGain.gain.cancelScheduledValues(audioCtx.currentTime);
|
|
26079
|
-
fadeGain.gain.setValueAtTime(1, audioCtx.currentTime);
|
|
26080
|
-
}
|
|
26081
|
-
};
|
|
26082
27459
|
const playDrum = (e) => {
|
|
26083
27460
|
if (!sfDrum.font) return;
|
|
26084
27461
|
if (e.when === 0) restoreFadeGainIfMuted();
|
|
@@ -26829,7 +28206,7 @@ var createDtmStudio = async (options = {}) => {
|
|
|
26829
28206
|
};
|
|
26830
28207
|
const setMasterVolume = (volume) => {
|
|
26831
28208
|
const g = Math.max(0, Math.min(100, volume)) / 100;
|
|
26832
|
-
masterGain.gain.
|
|
28209
|
+
masterGain.gain.setTargetAtTime(g, audioCtx.currentTime, 0.02);
|
|
26833
28210
|
};
|
|
26834
28211
|
let recordDestNode = null;
|
|
26835
28212
|
const createMediaStreamDestination = () => {
|
|
@@ -26911,10 +28288,13 @@ var createDtmStudio = async (options = {}) => {
|
|
|
26911
28288
|
export {
|
|
26912
28289
|
A4_HZ,
|
|
26913
28290
|
A4_UNITS,
|
|
28291
|
+
BLUES_SCALE,
|
|
26914
28292
|
BREATH_MARK,
|
|
26915
28293
|
CENTS_PER_UNIT,
|
|
26916
28294
|
COMPOSE_KEYS,
|
|
26917
28295
|
COMPOSE_MOOD_GROUPS,
|
|
28296
|
+
COMPOSE_SCALES,
|
|
28297
|
+
COMPOSE_SCALE_IDS,
|
|
26918
28298
|
CORPUS_BANDS,
|
|
26919
28299
|
CORPUS_SIZE,
|
|
26920
28300
|
DAW_CSS,
|
|
@@ -26934,7 +28314,11 @@ export {
|
|
|
26934
28314
|
FADE_IN_MARK,
|
|
26935
28315
|
FADE_OUT_MARK,
|
|
26936
28316
|
GLOBAL_STORAGE_KEYS,
|
|
28317
|
+
GM_BRIGHT_CEILING,
|
|
26937
28318
|
GM_INSTRUMENT_NAMES,
|
|
28319
|
+
GM_INSTRUMENT_RANGE,
|
|
28320
|
+
HARMONIC_MINOR_SCALE,
|
|
28321
|
+
HUNGARIAN_SCALE,
|
|
26938
28322
|
INSTRUMENT_PRESETS,
|
|
26939
28323
|
KEY_COUNT,
|
|
26940
28324
|
KOE_BASE_URL,
|
|
@@ -26944,6 +28328,7 @@ export {
|
|
|
26944
28328
|
LinkedList,
|
|
26945
28329
|
MACRO_STORAGE_KEYS,
|
|
26946
28330
|
MAJOR_KEY_IDS,
|
|
28331
|
+
MAJOR_SCALE2 as MAJOR_SCALE,
|
|
26947
28332
|
MAX_VOCAL_VOLUME,
|
|
26948
28333
|
MICRO_STEP,
|
|
26949
28334
|
MINOR_KEY_IDS,
|
|
@@ -27012,10 +28397,12 @@ export {
|
|
|
27012
28397
|
featureVector,
|
|
27013
28398
|
fifthToStep,
|
|
27014
28399
|
fifthToUnits,
|
|
28400
|
+
fitInstrumentOctave,
|
|
27015
28401
|
formatMmlMeta,
|
|
27016
28402
|
freqFromPitch,
|
|
27017
28403
|
generateRandomPattern,
|
|
27018
28404
|
getComposeKeyDescription,
|
|
28405
|
+
getComposeScaleDescription,
|
|
27019
28406
|
getDrumPatternKeys,
|
|
27020
28407
|
getMidiBPM,
|
|
27021
28408
|
icon,
|
|
@@ -27051,9 +28438,13 @@ export {
|
|
|
27051
28438
|
readGlobalSetting,
|
|
27052
28439
|
readMacroSections,
|
|
27053
28440
|
readMacroSetting,
|
|
28441
|
+
resolveCenter,
|
|
27054
28442
|
resolveComposeKey,
|
|
28443
|
+
resolveComposeScale,
|
|
27055
28444
|
resolveDrumPattern,
|
|
27056
28445
|
resolveLoopPoint,
|
|
28446
|
+
scaleDegrees,
|
|
28447
|
+
scaleSize,
|
|
27057
28448
|
semitonesToUnits,
|
|
27058
28449
|
shiftNotes,
|
|
27059
28450
|
showLoadingOverlay,
|