This commit is contained in:
Your Name
2026-08-11 17:41:36 +08:00
parent cfe4c82c90
commit 03fe4ddf9d
18771 changed files with 3617239 additions and 0 deletions
@@ -0,0 +1,238 @@
"use strict";
var __defProp = Object.defineProperty;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __publicField = (obj, key, value) => {
__defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
return value;
};
const common_vendor = require("../../common/vendor.js");
class AudioPool {
constructor(src, size, volume = 1) {
__publicField(this, "list", []);
__publicField(this, "cursor", 0);
__publicField(this, "warmedUp", false);
__publicField(this, "targetVolume", 1);
this.src = src;
this.size = size;
this.targetVolume = volume;
}
create() {
for (let i = 0; i < this.size; i++) {
const ctx = common_vendor.index.createInnerAudioContext();
ctx.src = this.src;
ctx.obeyMuteSwitch = false;
ctx.autoplay = false;
ctx.volume = this.targetVolume;
this.list.push(ctx);
}
}
setVolume(volume) {
this.targetVolume = Math.max(0, Math.min(1, volume));
this.list.forEach((ctx) => {
try {
ctx.volume = this.targetVolume;
} catch (_) {
}
});
}
/**
* 预热:短暂播放,让音频文件下载/解码到内存
* 真正首次 play 不会再卡冷启动
*/
warmUp() {
if (this.warmedUp)
return;
if (this.list.length === 0)
this.create();
this.list.forEach((ctx) => {
try {
ctx.volume = 0;
ctx.play();
setTimeout(() => {
try {
ctx.stop();
ctx.volume = this.targetVolume;
} catch (_) {
}
}, 60);
} catch (_) {
}
});
this.warmedUp = true;
}
play() {
if (this.list.length === 0) {
this.create();
this.warmUp();
}
const ctx = this.list[this.cursor];
this.cursor = (this.cursor + 1) % this.list.length;
try {
this.list.forEach((c) => {
try {
c.stop();
} catch (_) {
}
});
ctx.play();
} catch (_) {
try {
ctx.play();
} catch (__) {
}
}
}
destroy() {
this.list.forEach((ctx) => {
var _a;
try {
(_a = ctx.destroy) == null ? void 0 : _a.call(ctx);
} catch (_) {
}
});
this.list = [];
this.warmedUp = false;
}
}
const DEFAULT_CLICK_SRC = "https://gz-1349751149.cos.ap-guangzhou.myqcloud.com/uploads/file/20260526/20260526105128557ef8669.mp3";
function useMetronome(options = {}) {
const {
initialBpm = 80,
bpmMin = 40,
bpmMax = 240,
clickSrc = DEFAULT_CLICK_SRC,
accentSrc,
poolSize = 4,
volume = 1,
silent = false,
onBeat
} = options;
const bpm = common_vendor.ref(initialBpm);
const isPlaying = common_vendor.ref(false);
const beatIndex = common_vendor.ref(0);
const isAccent = common_vendor.ref(false);
const accentEveryRef = common_vendor.ref(options.accentEvery ?? 4);
const intervalMs = common_vendor.computed(() => 6e4 / bpm.value);
let clickPool = null;
let accentPool = null;
let timer = null;
let nextTickAt = 0;
const ensureAudio = () => {
if (silent)
return;
if (!clickPool) {
clickPool = new AudioPool(clickSrc, poolSize, volume);
clickPool.warmUp();
}
if (accentSrc && !accentPool) {
accentPool = new AudioPool(accentSrc, Math.max(2, Math.ceil(poolSize / 2)), volume);
accentPool.warmUp();
}
};
const playSound = (accent) => {
if (accent && accentPool) {
accentPool.play();
} else if (clickPool) {
clickPool.play();
}
};
const tick = () => {
if (!isPlaying.value)
return;
const every = Math.max(1, accentEveryRef.value);
const accent = beatIndex.value % every === 0;
isAccent.value = accent;
playSound(accent);
onBeat == null ? void 0 : onBeat(beatIndex.value, accent);
beatIndex.value++;
nextTickAt += intervalMs.value;
const nextDelay = Math.max(0, nextTickAt - Date.now());
timer = setTimeout(tick, nextDelay);
};
const start = () => {
if (isPlaying.value)
return;
ensureAudio();
isPlaying.value = true;
beatIndex.value = 0;
nextTickAt = Date.now();
tick();
};
const stop = () => {
isPlaying.value = false;
if (timer) {
clearTimeout(timer);
timer = null;
}
};
const setBpm = (val) => {
bpm.value = Math.max(bpmMin, Math.min(bpmMax, Math.round(val)));
};
const setAccentEvery = (n) => {
accentEveryRef.value = Math.max(1, Math.min(16, Math.round(n)));
beatIndex.value = 0;
};
const updateAudioSrc = (newClickSrc, newAccentSrc) => {
const wasPlaying = isPlaying.value;
if (wasPlaying)
stop();
clickPool == null ? void 0 : clickPool.destroy();
accentPool == null ? void 0 : accentPool.destroy();
clickPool = null;
accentPool = null;
clickPool = new AudioPool(newClickSrc, poolSize);
if (newAccentSrc) {
accentPool = new AudioPool(newAccentSrc, Math.max(2, Math.ceil(poolSize / 2)));
}
const previewCtx = common_vendor.index.createInnerAudioContext();
previewCtx.src = newClickSrc;
previewCtx.obeyMuteSwitch = false;
previewCtx.volume = 0.4;
try {
previewCtx.play();
setTimeout(() => {
var _a;
try {
(_a = previewCtx.destroy) == null ? void 0 : _a.call(previewCtx);
} catch (_) {
}
}, 500);
} catch (_) {
}
if (wasPlaying)
start();
};
const preload = () => {
try {
common_vendor.index.setInnerAudioOption({
obeyMuteSwitch: false,
mixWithOther: true
});
} catch (_) {
}
ensureAudio();
};
common_vendor.onUnmounted(() => {
stop();
clickPool == null ? void 0 : clickPool.destroy();
accentPool == null ? void 0 : accentPool.destroy();
clickPool = null;
accentPool = null;
});
return {
bpm,
isPlaying,
beatIndex,
isAccent,
intervalMs,
accentEvery: accentEveryRef,
start,
stop,
setBpm,
setAccentEvery,
updateAudioSrc,
preload
};
}
exports.useMetronome = useMetronome;
//# sourceMappingURL=../../../.sourcemap/mp-weixin/training/hooks/useMetronome.js.map