Files

261 lines
5.8 KiB
JavaScript
Raw Permalink Normal View History

// 音频管理工具 - 环境白噪音与音效管理
// 背景音频管理器(用于环境白噪音)
let bgmManager = null;
// 音效上下文缓存
const soundEffects = {};
// 当前环境音类型
let currentAmbienceType = 'silent';
// 音量渐变定时器
let fadeTimer = null;
/**
* 初始化背景音频管理器
*/
export const initBGM = () => {
if (!bgmManager) {
bgmManager = wx.getBackgroundAudioManager();
bgmManager.title = '见素-环境音';
bgmManager.epname = '环境白噪音';
bgmManager.singer = '见素';
}
return bgmManager;
};
/**
* 播放环境白噪音
* @param {string} type - 环境音类型: 'silent' | 'wind' | 'rain' | 'guqin' | 'white' | 'forest' | 'stream'
* @param {boolean} fade - 是否淡入
*/
export const playAmbience = (type = 'wind', fade = true) => {
const bgm = initBGM();
// 如果相同类型且正在播放,不重复操作
if (currentAmbienceType === type && bgm.currentTime > 0) {
return;
}
currentAmbienceType = type;
// 静音模式
if (type === 'silent') {
fadeOutAndStop();
return;
}
// 音频资源映射(使用本地音频)
const audioMap = {
wind: '/assets/audios/wind.mp3', // 风铃
rain: '/assets/audios/rain.mp3', // 雨声
guqin: '/assets/audios/guqin.mp3', // 古琴
white: '/assets/audios/white.mp3', // 白噪音
forest: '/assets/audios/forest.mp3', // 森林
stream: '/assets/audios/stream.mp3' // 溪流
};
// 音频类型名称映射
const typeNameMap = {
wind: '风铃',
rain: '雨落',
guqin: '古琴',
white: '白噪音',
forest: '森林',
stream: '溪流'
};
const src = audioMap[type];
if (!src) return;
// 设置音频属性
bgm.title = `见素 - ${typeNameMap[type] || '环境音'}`;
bgm.singer = '环境音';
bgm.coverImgUrl = '';
// 监听错误事件
bgm.onError((err) => {
console.error('音频播放错误:', err);
wx.showToast({
title: '音频加载失败',
icon: 'none'
});
});
// 淡入效果
if (fade) {
bgm.volume = 0;
bgm.src = src;
bgm.play();
fadeIn(0.3, 1000); // 1秒内淡入到30%音量
} else {
bgm.volume = 0.3;
bgm.src = src;
bgm.play();
}
console.log(`播放环境音: ${type}`);
};
/**
* 淡入音量
* @param {number} targetVolume - 目标音量 0-1
* @param {number} duration - 淡入时长 ms
*/
const fadeIn = (targetVolume = 0.3, duration = 1000) => {
if (!bgmManager) return;
clearInterval(fadeTimer);
const step = targetVolume / (duration / 50); // 每50ms调整一次
fadeTimer = setInterval(() => {
if (bgmManager.volume < targetVolume) {
bgmManager.volume = Math.min(bgmManager.volume + step, targetVolume);
} else {
clearInterval(fadeTimer);
}
}, 50);
};
/**
* 淡出并停止
* @param {number} duration - 淡出时长 ms
*/
export const fadeOutAndStop = (duration = 500) => {
if (!bgmManager) return;
clearInterval(fadeTimer);
const startVolume = bgmManager.volume;
const step = startVolume / (duration / 50);
fadeTimer = setInterval(() => {
if (bgmManager.volume > 0.01) {
bgmManager.volume = Math.max(bgmManager.volume - step, 0);
} else {
clearInterval(fadeTimer);
bgmManager.stop();
currentAmbienceType = 'silent';
}
}, 50);
};
/**
* 播放音效
* @param {string} type - 音效类型
* @param {object} options - 配置选项
*/
export const playSoundEffect = (type, options = {}) => {
const { volume = 1, loop = false } = options;
// 音效资源映射
const effectMap = {
flip: '/assets/audios/paper.mp3', // 翻页/纸张摩擦声
success: '/assets/audios/success.mp3', // 成功
inkDrop: '/assets/audios/inkdrop.mp3', // 水滴/入墨声
swipe: '/assets/audios/swipe.mp3', // 滑动
tap: '/assets/audios/tap.mp3', // 点击
breathe: '/assets/audios/breathe.mp3', // 呼吸
char: '/assets/audios/char.mp3' // 字显现
};
const src = effectMap[type];
if (!src) return;
// 复用或创建音频上下文
if (!soundEffects[type]) {
soundEffects[type] = wx.createInnerAudioContext();
}
const ctx = soundEffects[type];
ctx.src = src;
ctx.volume = volume;
ctx.loop = loop;
ctx.stop();
try {
ctx.play();
} catch (err) {
console.log('音效播放失败:', err);
}
return ctx;
};
/**
* 停止指定音效
* @param {string} type - 音效类型
*/
export const stopSoundEffect = (type) => {
if (soundEffects[type]) {
soundEffects[type].stop();
}
};
/**
* 停止所有音效
*/
export const stopAllSoundEffects = () => {
Object.keys(soundEffects).forEach(type => {
soundEffects[type].stop();
});
};
/**
* 停止环境音
*/
export const stopAmbience = () => {
fadeOutAndStop();
};
/**
* 获取当前环境音类型
*/
export const getCurrentAmbience = () => currentAmbienceType;
/**
* 切换环境音
* @param {string} type - 环境音类型
*/
export const toggleAmbience = (type) => {
if (currentAmbienceType === type) {
playAmbience('silent');
} else {
playAmbience(type);
}
};
/**
* 呼吸震动效果 - 配合名字逐字显现
* @param {number} duration - 总时长 ms
* @param {number} intensity - 震动强度 light/medium/heavy
*/
export const breatheVibration = (duration = 2000, intensity = 'light') => {
const interval = duration / 4; // 分4次震动
let count = 0;
const vibrate = () => {
if (count < 4) {
wx.vibrateShort({ type: intensity });
count++;
setTimeout(vibrate, interval);
}
};
vibrate();
};
/**
* 清理音频资源
*/
export const cleanup = () => {
clearInterval(fadeTimer);
if (bgmManager) {
bgmManager.stop();
}
Object.keys(soundEffects).forEach(type => {
soundEffects[type].destroy();
delete soundEffects[type];
});
};