UNPKG

minigame-std

Version:

Mini Game Standard Development Library.

101 lines (87 loc) 2.94 kB
import { Err, Ok, RESULT_VOID, type AsyncIOResult, type AsyncVoidIOResult } from 'happy-rusty'; import { isMinaEnv } from '../../macros/env.ts'; import { readFile } from '../fs/mod.ts'; import { bufferSource2Ab } from '../utils/mod.ts'; import type { PlayOptions } from './audio_defines.ts'; /** * Cache AudioContext. */ let audioContext: AudioContext | null; /** * 获取缓存的 AudioContext。 * @returns 返回缓存的 AudioContext。 */ export function getGlobalAudioContext(): AudioContext { audioContext ??= createWebAudioContext(); return audioContext; } /** * 关闭缓存的 AudioContext。 * @returns 返回一个 AsyncVoidIOResult。 */ export async function closeGlobalAudioContext(): AsyncVoidIOResult { try { await audioContext?.close(); audioContext = null; return RESULT_VOID; } catch (e) { return Err(e as DOMException); } } /** * 创建一个 AudioContext。 * 如果要获取缓存的实例,请使用 `getGlobalAudioContext`。 * @returns 返回一个 AudioContext实例。 */ export function createWebAudioContext(): AudioContext { return isMinaEnv() // 两者 API 基本兼容 ? (wx.createWebAudioContext() as unknown as AudioContext) : new AudioContext(); } /** * 播放一个 AudioBuffer。 * @param buffer - 解码后的 AudioBuffer。 * @param options - 播放选项。 * @returns 正在播放的 AudioBufferSourceNode。 */ export function playWebAudioFromAudioBuffer(buffer: AudioBuffer, options?: PlayOptions): AudioBufferSourceNode { const { loop = false, autoDisconnect = true, } = options ?? {}; const context = getGlobalAudioContext(); const source = context.createBufferSource(); source.buffer = buffer; source.loop = loop; source.connect(context.destination); if (autoDisconnect) { source.onended = () => { source.disconnect(); }; } source.start(); return source; } /** * 使用 Buffer 进行解码播放。 * @param buffer - 需要解码的 Buffer。 * @param options - 播放选项。 * @returns 正在播放的 AudioBufferSourceNode。 */ export async function playWebAudioFromArrayBuffer(buffer: BufferSource, options?: PlayOptions): Promise<AudioBufferSourceNode> { const context = getGlobalAudioContext(); const audioBuffer = await context.decodeAudioData(bufferSource2Ab(buffer)); return playWebAudioFromAudioBuffer(audioBuffer, options); } /** * 读取文件并播放。 * @param filePath - 文件路径。 * @param options - 播放选项。 * @returns 正在播放的 AudioBufferSourceNode。 */ export async function playWebAudioFromFile(filePath: string, options?: PlayOptions): AsyncIOResult<AudioBufferSourceNode> { return (await readFile(filePath)).andThenAsync(async buffer => { return Ok(await playWebAudioFromArrayBuffer(buffer, options)); }) }