@minto-ai/huoshan-tts
Version:
借助“火山引擎在线语音合成API”实现浏览器端“文本转语音
99 lines (80 loc) • 3.24 kB
text/typescript
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