CosyVoice icon indicating copy to clipboard operation
CosyVoice copied to clipboard

flow match cache版本推理出现爆音,同时prompt文本过长,推理时稳定出现合成音频前面带有prompt中的音频

Open donstang opened this issue 8 months ago • 7 comments

代码版本采用最新的版本,做流式推理。

load_jit=False, load_trt=False, fp16=False, use_flow_cache=True

使用inference_zero_shot推理

出现两个问题: 1、音频出现爆音

2、合成音频前面带有prompt音频的内容

badcase.zip

donstang avatar Apr 15 '25 08:04 donstang

推理代码提供一下

aluminumbox avatar Apr 15 '25 13:04 aluminumbox

推理代码提供一下

推理代码采用的官方的inference的代码,流式输入的方式推理会稳定复现,非流式输入不会出现。

donstang avatar Apr 16 '25 01:04 donstang

同样,我也遇到了此问题,inference_zero_shot流式推理遇到爆音,想问下解决了吗

wuwei12345 avatar Apr 18 '25 02:04 wuwei12345

如果指的是流式音频开头的爆音,是因为模型返回数据包含了wav的文件头,我尝试将第一个chunk丢弃后便不再出现爆音

nine-turns avatar Apr 18 '25 14:04 nine-turns

第二个问题解决了吗?我这边也出现同样的问题

lw3259111 avatar Apr 29 '25 11:04 lw3259111

推理时稳定出现合成音频前面带有prompt中的音频 我正在遭遇通用的问题,至于流式推理块前的爆音如楼上所说是wav头文件引起的

LIEGU0317 avatar May 24 '25 06:05 LIEGU0317

推理代码提供一下

def tts_stream_speech_synthesis_sync(self, text_generator): '''TTS
Args: text_generator: yield生成器

    Returns:
        bool: 是否成功
    '''
    try:
        if self.callback and self.callback.on_open:
            self.callback.on_open()

        # 流式推理,每一段文本生成一个音频块 _用于忽略块数
        for _, result in enumerate(self.cosyvoice.inference_zero_shot(
            text_generator,
            self.prompt_txt,
            self.prompt_speech_16k,
            stream=True  #流式推理
        )):
            # 获取原始音频数据
            audio_tensor = result['tts_speech']
            original_sample_rate = 24000  # CosyVoice2 默认输出采样率
            
            # 如果采样率不是16kHz,进行重采样
            if original_sample_rate != 16000:
                resampler = torchaudio.transforms.Resample(
                    orig_freq=original_sample_rate,
                    new_freq=16000
                )
                audio_tensor = resampler(audio_tensor)
            
            # 确保音频数据是单声道
            if audio_tensor.shape[0] > 1:
                audio_tensor = audio_tensor.mean(dim=0, keepdim=True)
            
            # 音量归一化处理
            audio_numpy = audio_tensor.numpy()
            max_abs = np.max(np.abs(audio_numpy))
            if max_abs > 0:
                # 将音量归一化到0.8,留出一些余量防止爆音
                audio_numpy = audio_numpy * (0.8 / max_abs)
            
            # 将音频数据转换为16位PCM格式的字节
            pcm_data = (audio_numpy * 32767).astype(np.int16).tobytes()
            
            if self.callback and self.callback.on_data:
                self.callback.on_data(pcm_data)

        # 完成回调
        if self.callback and self.callback.on_complete:
            self.callback.on_complete()
        return True
    except Exception as e:
        logger.error(f"TTS过程中发生错误: {str(e)}")
        if self.callback and self.callback.on_error:
            self.callback.on_error(str(e))
        return False

async def ws_msg_send_task_run(self): audio_processor = AudioProcessor() remain_data = b'' while True: await asyncio.sleep(0.1) while not self.ws_send_msg.empty(): # 从消息队列中获取消息 message = self.ws_send_msg.get() # 二进制数据: PCM-16bit 音频数据 if isinstance(message, bytes): samples_per_frame = int(audio_processor.frame_duration_ms * audio_processor.sample_rate / 1000)*2 message = remain_data + message # 切片, 编码, 打包, 发送 for i in range(0, len(message), samples_per_frame): frame_slice = message[i:i + samples_per_frame] if len(frame_slice) == samples_per_frame: # 编码当前帧并发送 opus_data = audio_processor.encode_audio(frame_slice) bin_data = audio_processor.pack_bin_frame(type=0, version=self.protocol_version, payload=opus_data) await self.ws_send_binary(bin_data) else: # 最后一帧不足时, 保留 remain_data = frame_slice pass # JSON数据 else: await self.ws_send_json(message)

LIEGU0317 avatar May 24 '25 06:05 LIEGU0317