@onjmin/dtm 2.1.2 → 2.1.3
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 +16 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.js +139 -9
- package/dist/index.mjs +139 -9
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -2077,6 +2077,13 @@ type DawOptions = {
|
|
|
2077
2077
|
customVocals?: CustomVocalDef[];
|
|
2078
2078
|
defaultBpm?: number;
|
|
2079
2079
|
initialMML?: string;
|
|
2080
|
+
/**
|
|
2081
|
+
* ループ再生の初期状態(既定 false)。
|
|
2082
|
+
* MML読み込み時に #loop=on があればそちらが優先される。
|
|
2083
|
+
*/
|
|
2084
|
+
initialLoop?: boolean;
|
|
2085
|
+
/** ループ再生のON/OFFが変化したときに呼ばれる */
|
|
2086
|
+
onLoopChange?: (loop: boolean) => void;
|
|
2080
2087
|
/** 利用規約への同意画面の表示をスキップするかどうか */
|
|
2081
2088
|
skipConsent?: boolean;
|
|
2082
2089
|
/**
|
|
@@ -2123,6 +2130,10 @@ type DawInstance = {
|
|
|
2123
2130
|
loadMIDI: (bytes: Uint8Array) => void | Promise<void>;
|
|
2124
2131
|
exportMIDI: () => Blob;
|
|
2125
2132
|
setBpm: (bpm: number) => void;
|
|
2133
|
+
/** 現在のループ再生状態(ON/OFF)を返す */
|
|
2134
|
+
getLoop: () => boolean;
|
|
2135
|
+
/** ループ再生状態を設定する。UIおよび再生シーケンサへ反映される。 */
|
|
2136
|
+
setLoop: (loop: boolean) => void;
|
|
2126
2137
|
getPlaybackState: () => PlaybackState;
|
|
2127
2138
|
getCurrentPlayStep: () => number;
|
|
2128
2139
|
forcePauseAt: (step: number) => void;
|
|
@@ -2787,6 +2798,11 @@ type MmlMeta = {
|
|
|
2787
2798
|
* チャンネルストリップ共通のパラメータ(歌詞トラック固有の `vocalDelay`/`d`トークンとは別軸)。
|
|
2788
2799
|
*/
|
|
2789
2800
|
trackDelaySend?: Record<number, number>;
|
|
2801
|
+
/**
|
|
2802
|
+
* ループ再生の指定(#loop=on / off)。BGM等で曲末停止せずシームレスにループさせる。
|
|
2803
|
+
* 省略時はオフ。
|
|
2804
|
+
*/
|
|
2805
|
+
loop?: boolean;
|
|
2790
2806
|
};
|
|
2791
2807
|
/** MMLからトップレベル宣言を抽出する */
|
|
2792
2808
|
declare const parseMmlMeta: (mml: string) => MmlMeta;
|
package/dist/index.d.ts
CHANGED
|
@@ -2077,6 +2077,13 @@ type DawOptions = {
|
|
|
2077
2077
|
customVocals?: CustomVocalDef[];
|
|
2078
2078
|
defaultBpm?: number;
|
|
2079
2079
|
initialMML?: string;
|
|
2080
|
+
/**
|
|
2081
|
+
* ループ再生の初期状態(既定 false)。
|
|
2082
|
+
* MML読み込み時に #loop=on があればそちらが優先される。
|
|
2083
|
+
*/
|
|
2084
|
+
initialLoop?: boolean;
|
|
2085
|
+
/** ループ再生のON/OFFが変化したときに呼ばれる */
|
|
2086
|
+
onLoopChange?: (loop: boolean) => void;
|
|
2080
2087
|
/** 利用規約への同意画面の表示をスキップするかどうか */
|
|
2081
2088
|
skipConsent?: boolean;
|
|
2082
2089
|
/**
|
|
@@ -2123,6 +2130,10 @@ type DawInstance = {
|
|
|
2123
2130
|
loadMIDI: (bytes: Uint8Array) => void | Promise<void>;
|
|
2124
2131
|
exportMIDI: () => Blob;
|
|
2125
2132
|
setBpm: (bpm: number) => void;
|
|
2133
|
+
/** 現在のループ再生状態(ON/OFF)を返す */
|
|
2134
|
+
getLoop: () => boolean;
|
|
2135
|
+
/** ループ再生状態を設定する。UIおよび再生シーケンサへ反映される。 */
|
|
2136
|
+
setLoop: (loop: boolean) => void;
|
|
2126
2137
|
getPlaybackState: () => PlaybackState;
|
|
2127
2138
|
getCurrentPlayStep: () => number;
|
|
2128
2139
|
forcePauseAt: (step: number) => void;
|
|
@@ -2787,6 +2798,11 @@ type MmlMeta = {
|
|
|
2787
2798
|
* チャンネルストリップ共通のパラメータ(歌詞トラック固有の `vocalDelay`/`d`トークンとは別軸)。
|
|
2788
2799
|
*/
|
|
2789
2800
|
trackDelaySend?: Record<number, number>;
|
|
2801
|
+
/**
|
|
2802
|
+
* ループ再生の指定(#loop=on / off)。BGM等で曲末停止せずシームレスにループさせる。
|
|
2803
|
+
* 省略時はオフ。
|
|
2804
|
+
*/
|
|
2805
|
+
loop?: boolean;
|
|
2790
2806
|
};
|
|
2791
2807
|
/** MMLからトップレベル宣言を抽出する */
|
|
2792
2808
|
declare const parseMmlMeta: (mml: string) => MmlMeta;
|
package/dist/index.js
CHANGED
|
@@ -4395,7 +4395,7 @@ var NATURAL_STEPS2 = {
|
|
|
4395
4395
|
};
|
|
4396
4396
|
var isNatural = (ch) => Object.hasOwn(NATURAL_STEPS2[12], ch);
|
|
4397
4397
|
var clamp3 = (value, lo, hi) => Math.min(hi, Math.max(lo, value));
|
|
4398
|
-
var META_DIRECTIVE = /#(inst|drum|drumfont|volume|drumvolume|reverb|reverbdecay|reverbpredelay|delay|delaydiv|mastercomp|fadein|fadeout|mode|edo)=([\w:-]+)/gi;
|
|
4398
|
+
var META_DIRECTIVE = /#(inst|drum|drumfont|volume|drumvolume|reverb|reverbdecay|reverbpredelay|delay|delaydiv|mastercomp|fadein|fadeout|mode|edo|loop)=([\w:-]+)/gi;
|
|
4399
4399
|
var TRACK_INST_DIRECTIVE = /#t(\d+)inst=([^#;\r\n]+)/gi;
|
|
4400
4400
|
var TRACK_COMP_DIRECTIVE = /#t(\d+)comp=(\d+)/gi;
|
|
4401
4401
|
var TRACK_WIDTH_DIRECTIVE = /#t(\d+)width=(\d+)/gi;
|
|
@@ -4448,6 +4448,9 @@ var parseMmlMeta = (mml) => {
|
|
|
4448
4448
|
} else if (key === "edo") {
|
|
4449
4449
|
const e = Number.parseInt(m[2], 10);
|
|
4450
4450
|
if (e === 12 || e === 31) meta.edo = e;
|
|
4451
|
+
} else if (key === "loop") {
|
|
4452
|
+
const v = m[2].toLowerCase();
|
|
4453
|
+
meta.loop = v === "on" || v === "1" || v === "true";
|
|
4451
4454
|
}
|
|
4452
4455
|
}
|
|
4453
4456
|
for (const m of mml.matchAll(TRACK_INST_DIRECTIVE)) {
|
|
@@ -4551,6 +4554,7 @@ var formatMmlMeta = (meta, space = "") => {
|
|
|
4551
4554
|
parts.push(`#fadeout=${meta.fadeOut}`);
|
|
4552
4555
|
if (meta.mode) parts.push(`#mode=${meta.mode}`);
|
|
4553
4556
|
if (meta.edo !== void 0 && meta.edo !== 12) parts.push(`#edo=${meta.edo}`);
|
|
4557
|
+
if (meta.loop) parts.push("#loop=on");
|
|
4554
4558
|
if (meta.trackInstruments) {
|
|
4555
4559
|
for (const [idx, name] of Object.entries(meta.trackInstruments)) {
|
|
4556
4560
|
if (name) parts.push(`#t${idx}inst=${name}`);
|
|
@@ -5078,7 +5082,11 @@ var createSequencer = (options) => {
|
|
|
5078
5082
|
if (!active) return;
|
|
5079
5083
|
const sps = secondsPerStep();
|
|
5080
5084
|
const time = options.getAudioTime() - startTime;
|
|
5081
|
-
|
|
5085
|
+
try {
|
|
5086
|
+
options.onTick(getWrappedPlayStep(time, sps));
|
|
5087
|
+
} catch (err2) {
|
|
5088
|
+
console.error("[sequencer] error in onTick callback:", err2);
|
|
5089
|
+
}
|
|
5082
5090
|
animationId = requestAnimationFrame(animate);
|
|
5083
5091
|
};
|
|
5084
5092
|
const stop = () => {
|
|
@@ -10840,6 +10848,7 @@ var mountMmlPlayer = (target, mml, options = {}) => {
|
|
|
10840
10848
|
options.onStop?.();
|
|
10841
10849
|
};
|
|
10842
10850
|
let isSeeking = false;
|
|
10851
|
+
let lastCommittedStep = null;
|
|
10843
10852
|
const seekTo = (step) => {
|
|
10844
10853
|
const clamped = Math.min(maxStep, Math.max(0, Math.round(step)));
|
|
10845
10854
|
renderPlayhead(clamped);
|
|
@@ -10851,16 +10860,42 @@ var mountMmlPlayer = (target, mml, options = {}) => {
|
|
|
10851
10860
|
play(clamped);
|
|
10852
10861
|
}
|
|
10853
10862
|
};
|
|
10854
|
-
|
|
10863
|
+
const commitSeek = () => {
|
|
10864
|
+
isSeeking = false;
|
|
10865
|
+
const step = Number(seekInput.value);
|
|
10866
|
+
if (lastCommittedStep !== step) {
|
|
10867
|
+
lastCommittedStep = step;
|
|
10868
|
+
seekTo(step);
|
|
10869
|
+
}
|
|
10870
|
+
};
|
|
10871
|
+
seekInput.addEventListener("pointerdown", (e) => {
|
|
10855
10872
|
isSeeking = true;
|
|
10873
|
+
lastCommittedStep = null;
|
|
10874
|
+
try {
|
|
10875
|
+
seekInput.setPointerCapture(e.pointerId);
|
|
10876
|
+
} catch {
|
|
10877
|
+
}
|
|
10856
10878
|
});
|
|
10857
10879
|
seekInput.addEventListener("input", () => {
|
|
10858
10880
|
renderPlayhead(Number(seekInput.value));
|
|
10859
10881
|
syncSeekFill();
|
|
10860
10882
|
});
|
|
10861
10883
|
seekInput.addEventListener("change", () => {
|
|
10884
|
+
commitSeek();
|
|
10885
|
+
});
|
|
10886
|
+
seekInput.addEventListener("pointerup", (e) => {
|
|
10887
|
+
try {
|
|
10888
|
+
seekInput.releasePointerCapture(e.pointerId);
|
|
10889
|
+
} catch {
|
|
10890
|
+
}
|
|
10891
|
+
commitSeek();
|
|
10892
|
+
});
|
|
10893
|
+
seekInput.addEventListener("pointercancel", (e) => {
|
|
10894
|
+
try {
|
|
10895
|
+
seekInput.releasePointerCapture(e.pointerId);
|
|
10896
|
+
} catch {
|
|
10897
|
+
}
|
|
10862
10898
|
isSeeking = false;
|
|
10863
|
-
seekTo(Number(seekInput.value));
|
|
10864
10899
|
});
|
|
10865
10900
|
playBtn.addEventListener("click", () => {
|
|
10866
10901
|
if (playing) pause();
|
|
@@ -12405,19 +12440,45 @@ var mountChordPlayer = (target, chords, options = {}) => {
|
|
|
12405
12440
|
}
|
|
12406
12441
|
play(idx);
|
|
12407
12442
|
};
|
|
12408
|
-
|
|
12443
|
+
let lastCommittedSec = null;
|
|
12444
|
+
const commitSeek = () => {
|
|
12445
|
+
isSeeking = false;
|
|
12446
|
+
if (totalSec <= 0) return;
|
|
12447
|
+
const sec = Number(seekInput.value);
|
|
12448
|
+
if (lastCommittedSec !== sec) {
|
|
12449
|
+
lastCommittedSec = sec;
|
|
12450
|
+
const idx = getActiveIndexBySec(sec);
|
|
12451
|
+
seekTo(idx >= 0 ? idx : Math.max(0, chordEvents.length - 1));
|
|
12452
|
+
}
|
|
12453
|
+
};
|
|
12454
|
+
seekInput.addEventListener("pointerdown", (e) => {
|
|
12409
12455
|
isSeeking = true;
|
|
12456
|
+
lastCommittedSec = null;
|
|
12457
|
+
try {
|
|
12458
|
+
seekInput.setPointerCapture(e.pointerId);
|
|
12459
|
+
} catch {
|
|
12460
|
+
}
|
|
12410
12461
|
});
|
|
12411
12462
|
seekInput.addEventListener("input", () => {
|
|
12412
12463
|
updateTimeDisplay(Number(seekInput.value));
|
|
12413
12464
|
syncSeekFill();
|
|
12414
12465
|
});
|
|
12415
12466
|
seekInput.addEventListener("change", () => {
|
|
12467
|
+
commitSeek();
|
|
12468
|
+
});
|
|
12469
|
+
seekInput.addEventListener("pointerup", (e) => {
|
|
12470
|
+
try {
|
|
12471
|
+
seekInput.releasePointerCapture(e.pointerId);
|
|
12472
|
+
} catch {
|
|
12473
|
+
}
|
|
12474
|
+
commitSeek();
|
|
12475
|
+
});
|
|
12476
|
+
seekInput.addEventListener("pointercancel", (e) => {
|
|
12477
|
+
try {
|
|
12478
|
+
seekInput.releasePointerCapture(e.pointerId);
|
|
12479
|
+
} catch {
|
|
12480
|
+
}
|
|
12416
12481
|
isSeeking = false;
|
|
12417
|
-
if (totalSec <= 0) return;
|
|
12418
|
-
const sec = Number(seekInput.value);
|
|
12419
|
-
const idx = getActiveIndexBySec(sec);
|
|
12420
|
-
seekTo(idx >= 0 ? idx : Math.max(0, chordEvents.length - 1));
|
|
12421
12482
|
});
|
|
12422
12483
|
const stop = () => {
|
|
12423
12484
|
if (isLoading) {
|
|
@@ -15530,6 +15591,15 @@ var buildUI = (target, options) => {
|
|
|
15530
15591
|
</select>
|
|
15531
15592
|
<button class="dtm-infobtn" data-dtm="edo-info" title="\u97F3\u5F8B\u306E\u89E3\u8AAC">${icon("info", 12)}</button>
|
|
15532
15593
|
</div>
|
|
15594
|
+
<div class="dtm-row">
|
|
15595
|
+
<span class="dtm-label">\u30EB\u30FC\u30D7\u518D\u751F</span>
|
|
15596
|
+
<label class="dtm-toggle">
|
|
15597
|
+
<input type="checkbox" data-dtm="loop-toggle">
|
|
15598
|
+
<span data-dtm="loop-toggle-label">OFF</span>
|
|
15599
|
+
</label>
|
|
15600
|
+
<span class="dtm-grow"></span>
|
|
15601
|
+
<button class="dtm-infobtn" data-dtm="loop-info" title="\u30EB\u30FC\u30D7\u518D\u751F\u306E\u89E3\u8AAC">${icon("info", 12)}</button>
|
|
15602
|
+
</div>
|
|
15533
15603
|
<div class="dtm-row">
|
|
15534
15604
|
<span class="dtm-label">\u5168\u4F53\u97F3\u91CF</span>
|
|
15535
15605
|
<input type="range" class="dtm-range dtm-grow" data-dtm="master-volume" value="50" min="0" max="100">
|
|
@@ -15867,6 +15937,9 @@ var buildUI = (target, options) => {
|
|
|
15867
15937
|
vScrollThumb: sel("vscroll-thumb"),
|
|
15868
15938
|
hScroll: sel("hscroll"),
|
|
15869
15939
|
hScrollThumb: sel("hscroll-thumb"),
|
|
15940
|
+
loopToggle: sel("loop-toggle"),
|
|
15941
|
+
loopToggleLabel: sel("loop-toggle-label"),
|
|
15942
|
+
loopInfoBtn: sel("loop-info"),
|
|
15870
15943
|
masterVolume: sel("master-volume"),
|
|
15871
15944
|
masterVolumeLabel: sel("master-volume-label"),
|
|
15872
15945
|
masterComp: sel("master-comp"),
|
|
@@ -18050,6 +18123,16 @@ var TRACK_DELAYSEND_INFO_HTML = `
|
|
|
18050
18123
|
<p>[delay]\u30D1\u30CD\u30EB\u306E\u639B\u304B\u308A\u5177\u5408\u304C0%\u3060\u3068\u3001\u3053\u3053\u3092\u3044\u304F\u3089\u4E0A\u3052\u3066\u3082\u7121\u97F3\u306E\u307E\u307E\u3067\u3059\u3002\u300C\u9001\u308A\u91CF\uFF08\u3053\u306E\u30C8\u30E9\u30C3\u30AF\u304C\u3069\u308C\u3060\u3051\u63D0\u4F9B\u3059\u308B\u304B\uFF09\u300D\u3068\u300C\u30DE\u30B9\u30BF\u306E\u30C7\u30A3\u30EC\u30A4\u8A2D\u5B9A\uFF08\u5B9F\u969B\u306B\u3069\u3093\u306A\u7E70\u308A\u8FD4\u3057\u304C\u639B\u304B\u308B\u304B\uFF09\u300D\u306E\u4E8C\u6BB5\u69CB\u3048\u306B\u306A\u3063\u3066\u3044\u308B\u305F\u3081\u3067\u3059\u3002\u4E21\u65B9\u3092\u78BA\u8A8D\u3057\u3066\u304F\u3060\u3055\u3044\u3002</p>
|
|
18051
18124
|
</div>
|
|
18052
18125
|
`;
|
|
18126
|
+
var LOOP_INFO_HTML = `
|
|
18127
|
+
<div class="dtm-modal-body-content">
|
|
18128
|
+
<h4>\u4F55\u3092\u3059\u308B\u8A2D\u5B9A\u304B</h4>
|
|
18129
|
+
<p>\u30EB\u30FC\u30D7\u518D\u751F\u3092\u6709\u52B9\u306B\u3057\u307E\u3059\u3002ON\u306B\u3059\u308B\u3068\u3001\u518D\u751F\u304C\u66F2\u672B\u3067\u505C\u6B62\u305B\u305A\u3001\u5148\u982D\u304B\u3089\u30B7\u30FC\u30E0\u30EC\u30B9\u306B\u7E70\u308A\u8FD4\u3055\u308C\u307E\u3059\u3002</p>
|
|
18130
|
+
<h4>MML\u51FA\u529B\u3078\u306E\u53CD\u6620</h4>
|
|
18131
|
+
<p>\u30EB\u30FC\u30D7\u518D\u751F\u304CON\u306E\u5834\u5408\u3001MML\u751F\u6210\u6642\u306B <code>#loop=on</code> \u30E1\u30BF\u884C\u304C\u51FA\u529B\u3055\u308C\u307E\u3059\u3002\u57CB\u3081\u8FBC\u307F\u30D7\u30EC\u30A4\u30E4\u30FC\u3084\u518D\u751F\u5C02\u7528\u30D7\u30EC\u30A4\u30E4\u30FC\uFF08mountPlayer / mountChordPlayer\uFF09\u3067\u3082\u3053\u306EMML\u3092\u8AAD\u307F\u8FBC\u3080\u3053\u3068\u3067\u81EA\u52D5\u7684\u306B\u30EB\u30FC\u30D7\u518D\u751F\u3055\u308C\u307E\u3059\u3002</p>
|
|
18132
|
+
<h4>BGM\u3084\u30B2\u30FC\u30E0\u97F3\u697D\u5411\u3051</h4>
|
|
18133
|
+
<p>Web\u30B5\u30A4\u30C8\u306EBGM\u3084\u30B2\u30FC\u30E0\u306E\u30B9\u30C6\u30FC\u30B8\u66F2\u306A\u3069\u3001\u9014\u5207\u308C\u305A\u306B\u30EB\u30FC\u30D7\u3055\u305B\u305F\u3044\u66F2\u306E\u5236\u4F5C\u306B\u6700\u9069\u3067\u3059\u3002</p>
|
|
18134
|
+
</div>
|
|
18135
|
+
`;
|
|
18053
18136
|
var MASTER_COMP_INFO_HTML = `
|
|
18054
18137
|
<div class="dtm-modal-body-content">
|
|
18055
18138
|
<h4>\u4F55\u3092\u3059\u308B\u8A2D\u5B9A\u304B</h4>
|
|
@@ -18595,6 +18678,18 @@ var mountDAW = (target, options = {}) => {
|
|
|
18595
18678
|
options.singingVoices?.setVolume(masterVolume / 100);
|
|
18596
18679
|
};
|
|
18597
18680
|
applyMasterVolume(masterVolume);
|
|
18681
|
+
let loopEnabled = options.initialLoop ?? false;
|
|
18682
|
+
const applyLoop = (enabled) => {
|
|
18683
|
+
loopEnabled = enabled;
|
|
18684
|
+
if (refs.loopToggle) {
|
|
18685
|
+
refs.loopToggle.checked = enabled;
|
|
18686
|
+
}
|
|
18687
|
+
if (refs.loopToggleLabel) {
|
|
18688
|
+
refs.loopToggleLabel.textContent = enabled ? "ON" : "OFF";
|
|
18689
|
+
}
|
|
18690
|
+
options.onLoopChange?.(enabled);
|
|
18691
|
+
};
|
|
18692
|
+
applyLoop(loopEnabled);
|
|
18598
18693
|
const snapToEdoGrid = (u) => {
|
|
18599
18694
|
const upr = renderConfig.unitsPerRow ?? UNITS_PER_SEMITONE;
|
|
18600
18695
|
return units(Math.round(u / upr) * upr);
|
|
@@ -19656,6 +19751,7 @@ var mountDAW = (target, options = {}) => {
|
|
|
19656
19751
|
getPlayStartStep: () => playStartStep,
|
|
19657
19752
|
getDrumPattern: (currentBar) => resolveDrumPattern(currentDrumPattern, drumPatterns, currentBar),
|
|
19658
19753
|
getSoloTrackId: () => isSolo ? activeTrackId : null,
|
|
19754
|
+
getLoop: () => loopEnabled,
|
|
19659
19755
|
getAudioTime,
|
|
19660
19756
|
onPlayNote: (e) => {
|
|
19661
19757
|
if (audioMutedTracks.has(e.trackId)) return;
|
|
@@ -19683,6 +19779,19 @@ var mountDAW = (target, options = {}) => {
|
|
|
19683
19779
|
getMaxOffsetX()
|
|
19684
19780
|
);
|
|
19685
19781
|
renderer.setDrawOffset(currentOffsetX, currentOffsetY);
|
|
19782
|
+
} else if (currentPlayStep < currentOffsetX / renderConfig.stepWidth) {
|
|
19783
|
+
const visibleBars = Math.max(
|
|
19784
|
+
1,
|
|
19785
|
+
Math.round(visibleSteps / renderConfig.stepsPerBar)
|
|
19786
|
+
);
|
|
19787
|
+
currentOffsetX = clamp5(
|
|
19788
|
+
Math.floor(
|
|
19789
|
+
currentPlayStep / (visibleBars * renderConfig.stepsPerBar)
|
|
19790
|
+
) * visibleBars * renderConfig.stepsPerBar * renderConfig.stepWidth,
|
|
19791
|
+
0,
|
|
19792
|
+
getMaxOffsetX()
|
|
19793
|
+
);
|
|
19794
|
+
renderer.setDrawOffset(currentOffsetX, currentOffsetY);
|
|
19686
19795
|
}
|
|
19687
19796
|
redrawAll();
|
|
19688
19797
|
},
|
|
@@ -19798,8 +19907,18 @@ var mountDAW = (target, options = {}) => {
|
|
|
19798
19907
|
options.onScheduleFade?.(params);
|
|
19799
19908
|
}
|
|
19800
19909
|
if (streaming && voices) {
|
|
19910
|
+
let loopLengthSec;
|
|
19911
|
+
let loopStartSec;
|
|
19912
|
+
if (loopEnabled) {
|
|
19913
|
+
const endStep = getSongEndStepExact();
|
|
19914
|
+
const sps = 60 / bpm / 48;
|
|
19915
|
+
loopStartSec = 0;
|
|
19916
|
+
loopLengthSec = endStep * sps;
|
|
19917
|
+
}
|
|
19801
19918
|
voices.startStream(streamTracks, sequencer.getStartTime(), {
|
|
19802
19919
|
isAudible: (t) => !isSolo || t.id === activeTrackId,
|
|
19920
|
+
loopLengthSec,
|
|
19921
|
+
loopStartSec,
|
|
19803
19922
|
onScheduled: (t, note, t0) => {
|
|
19804
19923
|
if (!t.id) return;
|
|
19805
19924
|
flashTrackPill(t.id, t0 - getAudioTime(), note.durationSec);
|
|
@@ -20811,6 +20930,7 @@ var mountDAW = (target, options = {}) => {
|
|
|
20811
20930
|
fadeOut: Math.round(fadeOutSec * 10),
|
|
20812
20931
|
mode,
|
|
20813
20932
|
edo: renderConfig.edo,
|
|
20933
|
+
loop: loopEnabled ? true : void 0,
|
|
20814
20934
|
trackInstruments: trackInstMeta,
|
|
20815
20935
|
trackCompression: trackCompMeta,
|
|
20816
20936
|
trackWidth: trackWidthMeta,
|
|
@@ -20840,6 +20960,7 @@ var mountDAW = (target, options = {}) => {
|
|
|
20840
20960
|
fadeOut: Math.round(fadeOutSec * 10),
|
|
20841
20961
|
mode,
|
|
20842
20962
|
edo: renderConfig.edo,
|
|
20963
|
+
loop: loopEnabled ? true : void 0,
|
|
20843
20964
|
trackInstruments: trackInstMeta,
|
|
20844
20965
|
trackCompression: trackCompMeta,
|
|
20845
20966
|
trackWidth: trackWidthMeta,
|
|
@@ -21053,6 +21174,7 @@ var mountDAW = (target, options = {}) => {
|
|
|
21053
21174
|
}
|
|
21054
21175
|
applyEdo(meta.edo ?? 12);
|
|
21055
21176
|
refs.edoSelect.value = String(renderConfig.edo ?? 12);
|
|
21177
|
+
applyLoop(meta.loop ?? false);
|
|
21056
21178
|
if (meta.drumVolume !== void 0) {
|
|
21057
21179
|
drumVolume = meta.drumVolume;
|
|
21058
21180
|
refs.drumVolume.value = String(meta.drumVolume);
|
|
@@ -21565,6 +21687,12 @@ var mountDAW = (target, options = {}) => {
|
|
|
21565
21687
|
refs.edoInfoBtn.addEventListener("click", () => {
|
|
21566
21688
|
showModal("\u97F3\u5F8B\u306E\u89E3\u8AAC", EDO_INFO_HTML);
|
|
21567
21689
|
});
|
|
21690
|
+
refs.loopToggle.addEventListener("change", () => {
|
|
21691
|
+
applyLoop(refs.loopToggle.checked);
|
|
21692
|
+
});
|
|
21693
|
+
refs.loopInfoBtn.addEventListener("click", () => {
|
|
21694
|
+
showModal("\u30EB\u30FC\u30D7\u518D\u751F\u306E\u89E3\u8AAC", LOOP_INFO_HTML);
|
|
21695
|
+
});
|
|
21568
21696
|
refs.masterVolume.addEventListener("input", () => {
|
|
21569
21697
|
applyMasterVolume(Number.parseInt(refs.masterVolume.value, 10) || 0);
|
|
21570
21698
|
});
|
|
@@ -22966,6 +23094,8 @@ var mountDAW = (target, options = {}) => {
|
|
|
22966
23094
|
},
|
|
22967
23095
|
exportMIDI: exportMIDI2,
|
|
22968
23096
|
setBpm,
|
|
23097
|
+
getLoop: () => loopEnabled,
|
|
23098
|
+
setLoop: (loop) => applyLoop(loop),
|
|
22969
23099
|
getPlaybackState: () => playbackState,
|
|
22970
23100
|
getCurrentPlayStep,
|
|
22971
23101
|
forcePauseAt,
|
package/dist/index.mjs
CHANGED
|
@@ -4213,7 +4213,7 @@ var NATURAL_STEPS2 = {
|
|
|
4213
4213
|
};
|
|
4214
4214
|
var isNatural = (ch) => Object.hasOwn(NATURAL_STEPS2[12], ch);
|
|
4215
4215
|
var clamp3 = (value, lo, hi) => Math.min(hi, Math.max(lo, value));
|
|
4216
|
-
var META_DIRECTIVE = /#(inst|drum|drumfont|volume|drumvolume|reverb|reverbdecay|reverbpredelay|delay|delaydiv|mastercomp|fadein|fadeout|mode|edo)=([\w:-]+)/gi;
|
|
4216
|
+
var META_DIRECTIVE = /#(inst|drum|drumfont|volume|drumvolume|reverb|reverbdecay|reverbpredelay|delay|delaydiv|mastercomp|fadein|fadeout|mode|edo|loop)=([\w:-]+)/gi;
|
|
4217
4217
|
var TRACK_INST_DIRECTIVE = /#t(\d+)inst=([^#;\r\n]+)/gi;
|
|
4218
4218
|
var TRACK_COMP_DIRECTIVE = /#t(\d+)comp=(\d+)/gi;
|
|
4219
4219
|
var TRACK_WIDTH_DIRECTIVE = /#t(\d+)width=(\d+)/gi;
|
|
@@ -4266,6 +4266,9 @@ var parseMmlMeta = (mml) => {
|
|
|
4266
4266
|
} else if (key === "edo") {
|
|
4267
4267
|
const e = Number.parseInt(m[2], 10);
|
|
4268
4268
|
if (e === 12 || e === 31) meta.edo = e;
|
|
4269
|
+
} else if (key === "loop") {
|
|
4270
|
+
const v = m[2].toLowerCase();
|
|
4271
|
+
meta.loop = v === "on" || v === "1" || v === "true";
|
|
4269
4272
|
}
|
|
4270
4273
|
}
|
|
4271
4274
|
for (const m of mml.matchAll(TRACK_INST_DIRECTIVE)) {
|
|
@@ -4369,6 +4372,7 @@ var formatMmlMeta = (meta, space = "") => {
|
|
|
4369
4372
|
parts.push(`#fadeout=${meta.fadeOut}`);
|
|
4370
4373
|
if (meta.mode) parts.push(`#mode=${meta.mode}`);
|
|
4371
4374
|
if (meta.edo !== void 0 && meta.edo !== 12) parts.push(`#edo=${meta.edo}`);
|
|
4375
|
+
if (meta.loop) parts.push("#loop=on");
|
|
4372
4376
|
if (meta.trackInstruments) {
|
|
4373
4377
|
for (const [idx, name] of Object.entries(meta.trackInstruments)) {
|
|
4374
4378
|
if (name) parts.push(`#t${idx}inst=${name}`);
|
|
@@ -4896,7 +4900,11 @@ var createSequencer = (options) => {
|
|
|
4896
4900
|
if (!active) return;
|
|
4897
4901
|
const sps = secondsPerStep();
|
|
4898
4902
|
const time = options.getAudioTime() - startTime;
|
|
4899
|
-
|
|
4903
|
+
try {
|
|
4904
|
+
options.onTick(getWrappedPlayStep(time, sps));
|
|
4905
|
+
} catch (err2) {
|
|
4906
|
+
console.error("[sequencer] error in onTick callback:", err2);
|
|
4907
|
+
}
|
|
4900
4908
|
animationId = requestAnimationFrame(animate);
|
|
4901
4909
|
};
|
|
4902
4910
|
const stop = () => {
|
|
@@ -10658,6 +10666,7 @@ var mountMmlPlayer = (target, mml, options = {}) => {
|
|
|
10658
10666
|
options.onStop?.();
|
|
10659
10667
|
};
|
|
10660
10668
|
let isSeeking = false;
|
|
10669
|
+
let lastCommittedStep = null;
|
|
10661
10670
|
const seekTo = (step) => {
|
|
10662
10671
|
const clamped = Math.min(maxStep, Math.max(0, Math.round(step)));
|
|
10663
10672
|
renderPlayhead(clamped);
|
|
@@ -10669,16 +10678,42 @@ var mountMmlPlayer = (target, mml, options = {}) => {
|
|
|
10669
10678
|
play(clamped);
|
|
10670
10679
|
}
|
|
10671
10680
|
};
|
|
10672
|
-
|
|
10681
|
+
const commitSeek = () => {
|
|
10682
|
+
isSeeking = false;
|
|
10683
|
+
const step = Number(seekInput.value);
|
|
10684
|
+
if (lastCommittedStep !== step) {
|
|
10685
|
+
lastCommittedStep = step;
|
|
10686
|
+
seekTo(step);
|
|
10687
|
+
}
|
|
10688
|
+
};
|
|
10689
|
+
seekInput.addEventListener("pointerdown", (e) => {
|
|
10673
10690
|
isSeeking = true;
|
|
10691
|
+
lastCommittedStep = null;
|
|
10692
|
+
try {
|
|
10693
|
+
seekInput.setPointerCapture(e.pointerId);
|
|
10694
|
+
} catch {
|
|
10695
|
+
}
|
|
10674
10696
|
});
|
|
10675
10697
|
seekInput.addEventListener("input", () => {
|
|
10676
10698
|
renderPlayhead(Number(seekInput.value));
|
|
10677
10699
|
syncSeekFill();
|
|
10678
10700
|
});
|
|
10679
10701
|
seekInput.addEventListener("change", () => {
|
|
10702
|
+
commitSeek();
|
|
10703
|
+
});
|
|
10704
|
+
seekInput.addEventListener("pointerup", (e) => {
|
|
10705
|
+
try {
|
|
10706
|
+
seekInput.releasePointerCapture(e.pointerId);
|
|
10707
|
+
} catch {
|
|
10708
|
+
}
|
|
10709
|
+
commitSeek();
|
|
10710
|
+
});
|
|
10711
|
+
seekInput.addEventListener("pointercancel", (e) => {
|
|
10712
|
+
try {
|
|
10713
|
+
seekInput.releasePointerCapture(e.pointerId);
|
|
10714
|
+
} catch {
|
|
10715
|
+
}
|
|
10680
10716
|
isSeeking = false;
|
|
10681
|
-
seekTo(Number(seekInput.value));
|
|
10682
10717
|
});
|
|
10683
10718
|
playBtn.addEventListener("click", () => {
|
|
10684
10719
|
if (playing) pause();
|
|
@@ -12223,19 +12258,45 @@ var mountChordPlayer = (target, chords, options = {}) => {
|
|
|
12223
12258
|
}
|
|
12224
12259
|
play(idx);
|
|
12225
12260
|
};
|
|
12226
|
-
|
|
12261
|
+
let lastCommittedSec = null;
|
|
12262
|
+
const commitSeek = () => {
|
|
12263
|
+
isSeeking = false;
|
|
12264
|
+
if (totalSec <= 0) return;
|
|
12265
|
+
const sec = Number(seekInput.value);
|
|
12266
|
+
if (lastCommittedSec !== sec) {
|
|
12267
|
+
lastCommittedSec = sec;
|
|
12268
|
+
const idx = getActiveIndexBySec(sec);
|
|
12269
|
+
seekTo(idx >= 0 ? idx : Math.max(0, chordEvents.length - 1));
|
|
12270
|
+
}
|
|
12271
|
+
};
|
|
12272
|
+
seekInput.addEventListener("pointerdown", (e) => {
|
|
12227
12273
|
isSeeking = true;
|
|
12274
|
+
lastCommittedSec = null;
|
|
12275
|
+
try {
|
|
12276
|
+
seekInput.setPointerCapture(e.pointerId);
|
|
12277
|
+
} catch {
|
|
12278
|
+
}
|
|
12228
12279
|
});
|
|
12229
12280
|
seekInput.addEventListener("input", () => {
|
|
12230
12281
|
updateTimeDisplay(Number(seekInput.value));
|
|
12231
12282
|
syncSeekFill();
|
|
12232
12283
|
});
|
|
12233
12284
|
seekInput.addEventListener("change", () => {
|
|
12285
|
+
commitSeek();
|
|
12286
|
+
});
|
|
12287
|
+
seekInput.addEventListener("pointerup", (e) => {
|
|
12288
|
+
try {
|
|
12289
|
+
seekInput.releasePointerCapture(e.pointerId);
|
|
12290
|
+
} catch {
|
|
12291
|
+
}
|
|
12292
|
+
commitSeek();
|
|
12293
|
+
});
|
|
12294
|
+
seekInput.addEventListener("pointercancel", (e) => {
|
|
12295
|
+
try {
|
|
12296
|
+
seekInput.releasePointerCapture(e.pointerId);
|
|
12297
|
+
} catch {
|
|
12298
|
+
}
|
|
12234
12299
|
isSeeking = false;
|
|
12235
|
-
if (totalSec <= 0) return;
|
|
12236
|
-
const sec = Number(seekInput.value);
|
|
12237
|
-
const idx = getActiveIndexBySec(sec);
|
|
12238
|
-
seekTo(idx >= 0 ? idx : Math.max(0, chordEvents.length - 1));
|
|
12239
12300
|
});
|
|
12240
12301
|
const stop = () => {
|
|
12241
12302
|
if (isLoading) {
|
|
@@ -15348,6 +15409,15 @@ var buildUI = (target, options) => {
|
|
|
15348
15409
|
</select>
|
|
15349
15410
|
<button class="dtm-infobtn" data-dtm="edo-info" title="\u97F3\u5F8B\u306E\u89E3\u8AAC">${icon("info", 12)}</button>
|
|
15350
15411
|
</div>
|
|
15412
|
+
<div class="dtm-row">
|
|
15413
|
+
<span class="dtm-label">\u30EB\u30FC\u30D7\u518D\u751F</span>
|
|
15414
|
+
<label class="dtm-toggle">
|
|
15415
|
+
<input type="checkbox" data-dtm="loop-toggle">
|
|
15416
|
+
<span data-dtm="loop-toggle-label">OFF</span>
|
|
15417
|
+
</label>
|
|
15418
|
+
<span class="dtm-grow"></span>
|
|
15419
|
+
<button class="dtm-infobtn" data-dtm="loop-info" title="\u30EB\u30FC\u30D7\u518D\u751F\u306E\u89E3\u8AAC">${icon("info", 12)}</button>
|
|
15420
|
+
</div>
|
|
15351
15421
|
<div class="dtm-row">
|
|
15352
15422
|
<span class="dtm-label">\u5168\u4F53\u97F3\u91CF</span>
|
|
15353
15423
|
<input type="range" class="dtm-range dtm-grow" data-dtm="master-volume" value="50" min="0" max="100">
|
|
@@ -15685,6 +15755,9 @@ var buildUI = (target, options) => {
|
|
|
15685
15755
|
vScrollThumb: sel("vscroll-thumb"),
|
|
15686
15756
|
hScroll: sel("hscroll"),
|
|
15687
15757
|
hScrollThumb: sel("hscroll-thumb"),
|
|
15758
|
+
loopToggle: sel("loop-toggle"),
|
|
15759
|
+
loopToggleLabel: sel("loop-toggle-label"),
|
|
15760
|
+
loopInfoBtn: sel("loop-info"),
|
|
15688
15761
|
masterVolume: sel("master-volume"),
|
|
15689
15762
|
masterVolumeLabel: sel("master-volume-label"),
|
|
15690
15763
|
masterComp: sel("master-comp"),
|
|
@@ -17868,6 +17941,16 @@ var TRACK_DELAYSEND_INFO_HTML = `
|
|
|
17868
17941
|
<p>[delay]\u30D1\u30CD\u30EB\u306E\u639B\u304B\u308A\u5177\u5408\u304C0%\u3060\u3068\u3001\u3053\u3053\u3092\u3044\u304F\u3089\u4E0A\u3052\u3066\u3082\u7121\u97F3\u306E\u307E\u307E\u3067\u3059\u3002\u300C\u9001\u308A\u91CF\uFF08\u3053\u306E\u30C8\u30E9\u30C3\u30AF\u304C\u3069\u308C\u3060\u3051\u63D0\u4F9B\u3059\u308B\u304B\uFF09\u300D\u3068\u300C\u30DE\u30B9\u30BF\u306E\u30C7\u30A3\u30EC\u30A4\u8A2D\u5B9A\uFF08\u5B9F\u969B\u306B\u3069\u3093\u306A\u7E70\u308A\u8FD4\u3057\u304C\u639B\u304B\u308B\u304B\uFF09\u300D\u306E\u4E8C\u6BB5\u69CB\u3048\u306B\u306A\u3063\u3066\u3044\u308B\u305F\u3081\u3067\u3059\u3002\u4E21\u65B9\u3092\u78BA\u8A8D\u3057\u3066\u304F\u3060\u3055\u3044\u3002</p>
|
|
17869
17942
|
</div>
|
|
17870
17943
|
`;
|
|
17944
|
+
var LOOP_INFO_HTML = `
|
|
17945
|
+
<div class="dtm-modal-body-content">
|
|
17946
|
+
<h4>\u4F55\u3092\u3059\u308B\u8A2D\u5B9A\u304B</h4>
|
|
17947
|
+
<p>\u30EB\u30FC\u30D7\u518D\u751F\u3092\u6709\u52B9\u306B\u3057\u307E\u3059\u3002ON\u306B\u3059\u308B\u3068\u3001\u518D\u751F\u304C\u66F2\u672B\u3067\u505C\u6B62\u305B\u305A\u3001\u5148\u982D\u304B\u3089\u30B7\u30FC\u30E0\u30EC\u30B9\u306B\u7E70\u308A\u8FD4\u3055\u308C\u307E\u3059\u3002</p>
|
|
17948
|
+
<h4>MML\u51FA\u529B\u3078\u306E\u53CD\u6620</h4>
|
|
17949
|
+
<p>\u30EB\u30FC\u30D7\u518D\u751F\u304CON\u306E\u5834\u5408\u3001MML\u751F\u6210\u6642\u306B <code>#loop=on</code> \u30E1\u30BF\u884C\u304C\u51FA\u529B\u3055\u308C\u307E\u3059\u3002\u57CB\u3081\u8FBC\u307F\u30D7\u30EC\u30A4\u30E4\u30FC\u3084\u518D\u751F\u5C02\u7528\u30D7\u30EC\u30A4\u30E4\u30FC\uFF08mountPlayer / mountChordPlayer\uFF09\u3067\u3082\u3053\u306EMML\u3092\u8AAD\u307F\u8FBC\u3080\u3053\u3068\u3067\u81EA\u52D5\u7684\u306B\u30EB\u30FC\u30D7\u518D\u751F\u3055\u308C\u307E\u3059\u3002</p>
|
|
17950
|
+
<h4>BGM\u3084\u30B2\u30FC\u30E0\u97F3\u697D\u5411\u3051</h4>
|
|
17951
|
+
<p>Web\u30B5\u30A4\u30C8\u306EBGM\u3084\u30B2\u30FC\u30E0\u306E\u30B9\u30C6\u30FC\u30B8\u66F2\u306A\u3069\u3001\u9014\u5207\u308C\u305A\u306B\u30EB\u30FC\u30D7\u3055\u305B\u305F\u3044\u66F2\u306E\u5236\u4F5C\u306B\u6700\u9069\u3067\u3059\u3002</p>
|
|
17952
|
+
</div>
|
|
17953
|
+
`;
|
|
17871
17954
|
var MASTER_COMP_INFO_HTML = `
|
|
17872
17955
|
<div class="dtm-modal-body-content">
|
|
17873
17956
|
<h4>\u4F55\u3092\u3059\u308B\u8A2D\u5B9A\u304B</h4>
|
|
@@ -18413,6 +18496,18 @@ var mountDAW = (target, options = {}) => {
|
|
|
18413
18496
|
options.singingVoices?.setVolume(masterVolume / 100);
|
|
18414
18497
|
};
|
|
18415
18498
|
applyMasterVolume(masterVolume);
|
|
18499
|
+
let loopEnabled = options.initialLoop ?? false;
|
|
18500
|
+
const applyLoop = (enabled) => {
|
|
18501
|
+
loopEnabled = enabled;
|
|
18502
|
+
if (refs.loopToggle) {
|
|
18503
|
+
refs.loopToggle.checked = enabled;
|
|
18504
|
+
}
|
|
18505
|
+
if (refs.loopToggleLabel) {
|
|
18506
|
+
refs.loopToggleLabel.textContent = enabled ? "ON" : "OFF";
|
|
18507
|
+
}
|
|
18508
|
+
options.onLoopChange?.(enabled);
|
|
18509
|
+
};
|
|
18510
|
+
applyLoop(loopEnabled);
|
|
18416
18511
|
const snapToEdoGrid = (u) => {
|
|
18417
18512
|
const upr = renderConfig.unitsPerRow ?? UNITS_PER_SEMITONE;
|
|
18418
18513
|
return units(Math.round(u / upr) * upr);
|
|
@@ -19474,6 +19569,7 @@ var mountDAW = (target, options = {}) => {
|
|
|
19474
19569
|
getPlayStartStep: () => playStartStep,
|
|
19475
19570
|
getDrumPattern: (currentBar) => resolveDrumPattern(currentDrumPattern, drumPatterns, currentBar),
|
|
19476
19571
|
getSoloTrackId: () => isSolo ? activeTrackId : null,
|
|
19572
|
+
getLoop: () => loopEnabled,
|
|
19477
19573
|
getAudioTime,
|
|
19478
19574
|
onPlayNote: (e) => {
|
|
19479
19575
|
if (audioMutedTracks.has(e.trackId)) return;
|
|
@@ -19501,6 +19597,19 @@ var mountDAW = (target, options = {}) => {
|
|
|
19501
19597
|
getMaxOffsetX()
|
|
19502
19598
|
);
|
|
19503
19599
|
renderer.setDrawOffset(currentOffsetX, currentOffsetY);
|
|
19600
|
+
} else if (currentPlayStep < currentOffsetX / renderConfig.stepWidth) {
|
|
19601
|
+
const visibleBars = Math.max(
|
|
19602
|
+
1,
|
|
19603
|
+
Math.round(visibleSteps / renderConfig.stepsPerBar)
|
|
19604
|
+
);
|
|
19605
|
+
currentOffsetX = clamp5(
|
|
19606
|
+
Math.floor(
|
|
19607
|
+
currentPlayStep / (visibleBars * renderConfig.stepsPerBar)
|
|
19608
|
+
) * visibleBars * renderConfig.stepsPerBar * renderConfig.stepWidth,
|
|
19609
|
+
0,
|
|
19610
|
+
getMaxOffsetX()
|
|
19611
|
+
);
|
|
19612
|
+
renderer.setDrawOffset(currentOffsetX, currentOffsetY);
|
|
19504
19613
|
}
|
|
19505
19614
|
redrawAll();
|
|
19506
19615
|
},
|
|
@@ -19616,8 +19725,18 @@ var mountDAW = (target, options = {}) => {
|
|
|
19616
19725
|
options.onScheduleFade?.(params);
|
|
19617
19726
|
}
|
|
19618
19727
|
if (streaming && voices) {
|
|
19728
|
+
let loopLengthSec;
|
|
19729
|
+
let loopStartSec;
|
|
19730
|
+
if (loopEnabled) {
|
|
19731
|
+
const endStep = getSongEndStepExact();
|
|
19732
|
+
const sps = 60 / bpm / 48;
|
|
19733
|
+
loopStartSec = 0;
|
|
19734
|
+
loopLengthSec = endStep * sps;
|
|
19735
|
+
}
|
|
19619
19736
|
voices.startStream(streamTracks, sequencer.getStartTime(), {
|
|
19620
19737
|
isAudible: (t) => !isSolo || t.id === activeTrackId,
|
|
19738
|
+
loopLengthSec,
|
|
19739
|
+
loopStartSec,
|
|
19621
19740
|
onScheduled: (t, note, t0) => {
|
|
19622
19741
|
if (!t.id) return;
|
|
19623
19742
|
flashTrackPill(t.id, t0 - getAudioTime(), note.durationSec);
|
|
@@ -20629,6 +20748,7 @@ var mountDAW = (target, options = {}) => {
|
|
|
20629
20748
|
fadeOut: Math.round(fadeOutSec * 10),
|
|
20630
20749
|
mode,
|
|
20631
20750
|
edo: renderConfig.edo,
|
|
20751
|
+
loop: loopEnabled ? true : void 0,
|
|
20632
20752
|
trackInstruments: trackInstMeta,
|
|
20633
20753
|
trackCompression: trackCompMeta,
|
|
20634
20754
|
trackWidth: trackWidthMeta,
|
|
@@ -20658,6 +20778,7 @@ var mountDAW = (target, options = {}) => {
|
|
|
20658
20778
|
fadeOut: Math.round(fadeOutSec * 10),
|
|
20659
20779
|
mode,
|
|
20660
20780
|
edo: renderConfig.edo,
|
|
20781
|
+
loop: loopEnabled ? true : void 0,
|
|
20661
20782
|
trackInstruments: trackInstMeta,
|
|
20662
20783
|
trackCompression: trackCompMeta,
|
|
20663
20784
|
trackWidth: trackWidthMeta,
|
|
@@ -20871,6 +20992,7 @@ var mountDAW = (target, options = {}) => {
|
|
|
20871
20992
|
}
|
|
20872
20993
|
applyEdo(meta.edo ?? 12);
|
|
20873
20994
|
refs.edoSelect.value = String(renderConfig.edo ?? 12);
|
|
20995
|
+
applyLoop(meta.loop ?? false);
|
|
20874
20996
|
if (meta.drumVolume !== void 0) {
|
|
20875
20997
|
drumVolume = meta.drumVolume;
|
|
20876
20998
|
refs.drumVolume.value = String(meta.drumVolume);
|
|
@@ -21383,6 +21505,12 @@ var mountDAW = (target, options = {}) => {
|
|
|
21383
21505
|
refs.edoInfoBtn.addEventListener("click", () => {
|
|
21384
21506
|
showModal("\u97F3\u5F8B\u306E\u89E3\u8AAC", EDO_INFO_HTML);
|
|
21385
21507
|
});
|
|
21508
|
+
refs.loopToggle.addEventListener("change", () => {
|
|
21509
|
+
applyLoop(refs.loopToggle.checked);
|
|
21510
|
+
});
|
|
21511
|
+
refs.loopInfoBtn.addEventListener("click", () => {
|
|
21512
|
+
showModal("\u30EB\u30FC\u30D7\u518D\u751F\u306E\u89E3\u8AAC", LOOP_INFO_HTML);
|
|
21513
|
+
});
|
|
21386
21514
|
refs.masterVolume.addEventListener("input", () => {
|
|
21387
21515
|
applyMasterVolume(Number.parseInt(refs.masterVolume.value, 10) || 0);
|
|
21388
21516
|
});
|
|
@@ -22784,6 +22912,8 @@ var mountDAW = (target, options = {}) => {
|
|
|
22784
22912
|
},
|
|
22785
22913
|
exportMIDI: exportMIDI2,
|
|
22786
22914
|
setBpm,
|
|
22915
|
+
getLoop: () => loopEnabled,
|
|
22916
|
+
setLoop: (loop) => applyLoop(loop),
|
|
22787
22917
|
getPlaybackState: () => playbackState,
|
|
22788
22918
|
getCurrentPlayStep,
|
|
22789
22919
|
forcePauseAt,
|
package/package.json
CHANGED