gengx
This commit is contained in:
@@ -1,238 +1,2 @@
|
||||
"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;
|
||||
"use strict";var R=Object.defineProperty;var B=(l,t,e)=>t in l?R(l,t,{enumerable:!0,configurable:!0,writable:!0,value:e}):l[t]=e;var m=(l,t,e)=>(B(l,typeof t!="symbol"?t+"":t,e),e);const i=require("../../common/vendor.js");class d{constructor(t,e,o=1){m(this,"list",[]);m(this,"cursor",0);m(this,"warmedUp",!1);m(this,"targetVolume",1);this.src=t,this.size=e,this.targetVolume=o}create(){for(let t=0;t<this.size;t++){const e=i.index.createInnerAudioContext();e.src=this.src,e.obeyMuteSwitch=!1,e.autoplay=!1,e.volume=this.targetVolume,this.list.push(e)}}setVolume(t){this.targetVolume=Math.max(0,Math.min(1,t)),this.list.forEach(e=>{try{e.volume=this.targetVolume}catch{}})}warmUp(){this.warmedUp||(this.list.length===0&&this.create(),this.list.forEach(t=>{try{t.volume=0,t.play(),setTimeout(()=>{try{t.stop(),t.volume=this.targetVolume}catch{}},60)}catch{}}),this.warmedUp=!0)}play(){this.list.length===0&&(this.create(),this.warmUp());const t=this.list[this.cursor];this.cursor=(this.cursor+1)%this.list.length;try{this.list.forEach(e=>{try{e.stop()}catch{}}),t.play()}catch{try{t.play()}catch{}}}destroy(){this.list.forEach(t=>{var e;try{(e=t.destroy)==null||e.call(t)}catch{}}),this.list=[],this.warmedUp=!1}}const F="https://gz-1349751149.cos.ap-guangzhou.myqcloud.com/uploads/file/20260526/20260526105128557ef8669.mp3";function K(l={}){const{initialBpm:t=80,bpmMin:e=40,bpmMax:o=240,clickSrc:z=F,accentSrc:U,poolSize:f=4,volume:A=1,silent:I=!1,onBeat:v}=l,M=i.ref(t),u=i.ref(!1),c=i.ref(0),E=i.ref(!1),w=i.ref(l.accentEvery??4),b=i.computed(()=>6e4/M.value);let s=null,a=null,y=null,g=0;const S=()=>{I||(s||(s=new d(z,f,A),s.warmUp()),U&&!a&&(a=new d(U,Math.max(2,Math.ceil(f/2)),A),a.warmUp()))},D=r=>{r&&a?a.play():s&&s.play()},V=()=>{if(!u.value)return;const r=Math.max(1,w.value),h=c.value%r===0;E.value=h,D(h),v==null||v(c.value,h),c.value++,g+=b.value;const p=Math.max(0,g-Date.now());y=setTimeout(V,p)},T=()=>{u.value||(S(),u.value=!0,c.value=0,g=Date.now(),V())},_=()=>{u.value=!1,y&&(clearTimeout(y),y=null)},C=r=>{M.value=Math.max(e,Math.min(o,Math.round(r)))},q=r=>{w.value=Math.max(1,Math.min(16,Math.round(r))),c.value=0},L=(r,h)=>{const p=u.value;p&&_(),s==null||s.destroy(),a==null||a.destroy(),s=null,a=null,s=new d(r,f),h&&(a=new d(h,Math.max(2,Math.ceil(f/2))));const n=i.index.createInnerAudioContext();n.src=r,n.obeyMuteSwitch=!1,n.volume=.4;try{n.play(),setTimeout(()=>{var x;try{(x=n.destroy)==null||x.call(n)}catch{}},500)}catch{}p&&T()},O=()=>{try{i.index.setInnerAudioOption({obeyMuteSwitch:!1,mixWithOther:!0})}catch{}S()};return i.onUnmounted(()=>{_(),s==null||s.destroy(),a==null||a.destroy(),s=null,a=null}),{bpm:M,isPlaying:u,beatIndex:c,isAccent:E,intervalMs:b,accentEvery:w,start:T,stop:_,setBpm:C,setAccentEvery:q,updateAudioSrc:L,preload:O}}exports.useMetronome=K;
|
||||
//# sourceMappingURL=../../../.sourcemap/mp-weixin/training/hooks/useMetronome.js.map
|
||||
|
||||
Reference in New Issue
Block a user