UNPKG

@minto-ai/huoshan-tts

Version:

借助“火山引擎在线语音合成API”实现浏览器端“文本转语音

99 lines (80 loc) 3.24 kB
import type { SerialTaskExecuteContext } from '../handler' import { SerialHandler } from '../handler' class AudioActuator extends SerialHandler<AudioBuffer, never> { private static FADE_DURATION = 0.018 private static MUTE_VOLUME = 0 private static UNMUTE_VOLUME = 1 private audioContext: AudioContext = new AudioContext() private bufferSource: AudioBufferSourceNode | null = null private gainNode: GainNode | null = null private isMute = false public execute( context: SerialTaskExecuteContext<AudioBuffer, never>, ): void { if (context.isLastExecute) { this.taskCompletedCallback() return } this.bufferSource = this.audioContext.createBufferSource() this.bufferSource.buffer = context.taskItem.original! this.gainNode = this.audioContext.createGain() this.bufferSource.connect(this.gainNode) this.gainNode.connect(this.audioContext.destination) if (this.isMute) { this.gainNode.gain.setValueAtTime(AudioActuator.MUTE_VOLUME, this.audioContext.currentTime) } else { this.gainNode.gain.setValueAtTime(AudioActuator.MUTE_VOLUME, this.audioContext.currentTime) this.gainNode.gain.linearRampToValueAtTime(AudioActuator.UNMUTE_VOLUME, this.audioContext.currentTime + AudioActuator.FADE_DURATION) this.gainNode.gain.setValueAtTime(AudioActuator.UNMUTE_VOLUME, this.audioContext.currentTime + context.taskItem.original!.duration - AudioActuator.FADE_DURATION) this.gainNode.gain.linearRampToValueAtTime(AudioActuator.MUTE_VOLUME, this.audioContext.currentTime + context.taskItem.original!.duration) } this.bufferSource.start() this.bufferSource.addEventListener('ended', () => { this.taskCompletedCallback() }) } protected onFinish(): void { if (this.bufferSource) { this.bufferSource.stop() this.bufferSource = null } if (this.gainNode) { this.gainNode.disconnect() this.gainNode = null } if (this.audioContext) { this.audioContext.suspend() this.audioContext = new AudioContext() } this.executeController?.$bus.emit('_audioActuatorFinish') } protected onBeforeFirstExecute(): void { this.executeController?.$bus.emit('_audioActuatorBeforeFirstExecute') } public mute(): void { if (this.gainNode) { this.gainNode.gain.setValueAtTime(AudioActuator.UNMUTE_VOLUME, this.audioContext.currentTime) this.gainNode.gain.linearRampToValueAtTime(AudioActuator.MUTE_VOLUME, this.audioContext.currentTime + AudioActuator.FADE_DURATION) } this.isMute = true } public unmute(): void { if (this.gainNode) { this.gainNode.gain.setValueAtTime(AudioActuator.MUTE_VOLUME, this.audioContext.currentTime) this.gainNode.gain.linearRampToValueAtTime(AudioActuator.UNMUTE_VOLUME, this.audioContext.currentTime + AudioActuator.FADE_DURATION) } this.isMute = false } public pause(): void { if (this.audioContext) { this.audioContext.suspend() } } public resume(): void { if (this.audioContext) { this.audioContext.resume() } } } export default AudioActuator