北京网站设计公司wx成都柚米科技15/seo chinaz

北京网站设计公司wx成都柚米科技15,seo chinaz,淘宝客网站开源,高端模板网站建设价格Web端对接Demo <!DOCTYPE html> <html lang"zh-CN"><head><meta charset"UTF-8"><title>TTS 测试</title> </head><body><h1>TTS 测试页面</h1><textarea id"textInput" rows&…

Web端对接Demo

<!DOCTYPE html>
<html lang="zh-CN"><head><meta charset="UTF-8"><title>TTS 测试</title>
</head><body><h1>TTS 测试页面</h1><textarea id="textInput" rows="4" cols="50">真正的成长,是学会接受自己的不完美。</textarea><br><button onclick="sendText()">发送文本</button><script>class PCMAudioPlayer {constructor(sampleRate) {this.sampleRate = sampleRate;this.audioContext = null;this.audioQueue = [];this.isPlaying = false;this.currentSource = null;const bufferThreshold = 2;}connect() {if (!this.audioContext) {this.audioContext = new (window.AudioContext || window.webkitAudioContext)();}}pushPCM(arrayBuffer) {this.audioQueue.push(arrayBuffer);this._playNextAudio();}/*** 将arrayBuffer转为audioBuffer*/_bufferPCMData(pcmData) {const sampleRate = this.sampleRate; // 设置为 PCM 数据的采样率const length = pcmData.byteLength / 2; // 假设 PCM 数据为 16 位,需除以 2const audioBuffer = this.audioContext.createBuffer(1, length, sampleRate);const channelData = audioBuffer.getChannelData(0);const int16Array = new Int16Array(pcmData); // 将 PCM 数据转换为 Int16Arrayfor (let i = 0; i < length; i++) {// 将 16 位 PCM 转换为浮点数 (-1.0 到 1.0)channelData[i] = int16Array[i] / 32768; // 16 位数据转换范围}let audioLength = length / sampleRate * 1000;console.log(`prepare audio: ${length} samples, ${audioLength} ms`)return audioBuffer;}async _playAudio(arrayBuffer) {if (this.audioContext.state === 'suspended') {await this.audioContext.resume();}const audioBuffer = this._bufferPCMData(arrayBuffer);this.currentSource = this.audioContext.createBufferSource();this.currentSource.buffer = audioBuffer;this.currentSource.connect(this.audioContext.destination);this.currentSource.onended = () => {console.log('Audio playback ended.');this.isPlaying = false;this.currentSource = null;this._playNextAudio(); // Play the next audio in the queue};this.currentSource.start();this.isPlaying = true;}_playNextAudio() {if (this.audioQueue.length > 0 && !this.isPlaying) {// 计算总的字节长度const totalLength = this.audioQueue.reduce((acc, buffer) => acc + buffer.byteLength, 0);const combinedBuffer = new Uint8Array(totalLength);let offset = 0;// 将所有 audioQueue 中的 buffer 拼接到一个新的 Uint8Array 中for (const buffer of this.audioQueue) {combinedBuffer.set(new Uint8Array(buffer), offset);offset += buffer.byteLength;}// 清空 audioQueue,因为我们已经拼接完所有数据this.audioQueue = [];// 发送拼接的 audio 数据给 playAudiothis._playAudio(combinedBuffer.buffer);}}stop() {if (this.currentSource) {this.currentSource.stop(); // 停止当前音频播放this.currentSource = null; // 清除音频源引用this.isPlaying = false; // 更新播放状态}this.audioQueue = []; // 清空音频队列console.log('Playback stopped and queue cleared.');}}let player = new PCMAudioPlayer(24000);player.connect()player.stop()// WebSocket URL 根据实际API文档填写const socket = new WebSocket('wss://ws.coze.cn/v1/audio/speech?authorization=Bearer czs_l8r6XWz7Ogvh8diyHEyls4fnnsV4zPALaZQ019nI8yD8hB4wyDfmNeufVf3kckb6H');socket.onmessage = function (event) {try {const message = JSON.parse(event.data);if (message.event_type === 'speech.audio.update') {const audioData = atob(message.data.delta);console.log('audioData type ', typeof audioData);const arrayBuffer = Uint8Array.from(audioData, c => c.charCodeAt(0)).buffer;player.pushPCM(arrayBuffer)}} catch (error) {console.error('解析消息失败:', error);}};function sendText() {const textInput = document.getElementById('textInput').value;if (textInput) {// 发送文本到WebSocket服务器let append = {"id": "event_id","event_type": "input_text_buffer.append","data": {"delta": textInput}}socket.send(JSON.stringify(append));let submitData = {"id": "event_id","event_type": "input_text_buffer.complete"}socket.send(JSON.stringify(submitData));} else {alert('请输入要转换为语音的文本');}}</script>
</body></html>

PCMAudioPlayer

上面 demo 中的 PCMAudioPlayer 源码来自于阿里云TTS文档,在coze上没有找到怎么播放音频的demo, 想到了阿里云在文档方面做得比较好,结果真有。

下面是我用 AI 模型增加了一些代码注释,方便理解:

class PCMAudioPlayer {constructor(sampleRate) {this.sampleRate = sampleRate;      // 音频采样率(单位:Hz),需与PCM数据实际采样率一致this.audioContext = null;          // Web Audio API上下文实例this.audioQueue = [];              // 存储待播放的PCM数据缓冲区队列this.isPlaying = false;            // 标识当前是否正在播放音频this.currentSource = null;         // 当前播放的音频源节点const bufferThreshold = 2;         // 未使用的缓冲区阈值(代码中未实现逻辑)}// 初始化或恢复Web Audio上下文connect() {if (!this.audioContext) {// 创建音频上下文,兼容旧版webkit前缀this.audioContext = new (window.AudioContext || window.webkitAudioContext)();}}// 将PCM数据推入队列并尝试播放pushPCM(arrayBuffer) {this.audioQueue.push(arrayBuffer);this._playNextAudio();  // 触发播放逻辑}/*** 将16位有符号PCM数据转换为Web Audio兼容的AudioBuffer* @param {ArrayBuffer} pcmData - 原始16位PCM数据* @returns {AudioBuffer} - 标准化音频缓冲区对象*/_bufferPCMData(pcmData) {const sampleRate = this.sampleRate;const length = pcmData.byteLength / 2; // 计算采样点数(16位=2字节)const audioBuffer = this.audioContext.createBuffer(1, length, sampleRate); // 创建单声道缓冲区const channelData = audioBuffer.getChannelData(0);const int16Array = new Int16Array(pcmData);// 将16位有符号整数(-32768~32767)归一化为浮点数(-1.0~1.0)for (let i = 0; i < length; i++) {channelData[i] = int16Array[i] / 32768;  // 32768=2^15(16位有符号最大值)}console.log(`准备音频:${length}个采样点,时长${length/sampleRate*1000}ms`);return audioBuffer;}// 播放单个音频缓冲区async _playAudio(arrayBuffer) {if (this.audioContext.state === 'suspended') {await this.audioContext.resume();  // 恢复挂起的音频上下文}const audioBuffer = this._bufferPCMData(arrayBuffer);this.currentSource = this.audioContext.createBufferSource();this.currentSource.buffer = audioBuffer;this.currentSource.connect(this.audioContext.destination);  // 连接到输出设备// 播放结束事件处理this.currentSource.onended = () => {console.log('音频播放结束');this.isPlaying = false;this.currentSource = null;this._playNextAudio();  // 播放下一个缓冲};this.currentSource.start();  // 启动播放this.isPlaying = true;}// 处理音频队列播放逻辑_playNextAudio() {if (this.audioQueue.length > 0 && !this.isPlaying) {// 合并队列中所有缓冲区(可能影响实时性,适用于非流式场景)const totalLength = this.audioQueue.reduce((acc, buf) => acc + buf.byteLength, 0);const combinedBuffer = new Uint8Array(totalLength);let offset = 0;this.audioQueue.forEach(buffer => {combinedBuffer.set(new Uint8Array(buffer), offset);offset += buffer.byteLength;});this.audioQueue = [];  // 清空队列this._playAudio(combinedBuffer.buffer);  // 播放合并后的数据}}// 立即停止播放并清空队列stop() {if (this.currentSource) {this.currentSource.stop();  // 中止当前音频源this.currentSource = null;this.isPlaying = false;}this.audioQueue = [];console.log('播放已停止,队列已清空');}
}

PCM技术详解

参考音频基础知识及PCM技术详解

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/71630.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

jsherp importItemExcel接口存在SQL注入

一、漏洞简介 很多人说管伊佳ERP&#xff08;原名&#xff1a;华夏ERP&#xff0c;英文名&#xff1a;jshERP&#xff09;是目前人气领先的国产ERP系统虽然目前只有进销存财务生产的功能&#xff0c;但后面将会推出ERP的全部功能&#xff0c;有兴趣请帮点一下 二、漏洞影响 …

【目标检测】【BiFPN】EfficientDet:Scalable and Efficient Object Detection

EfficientDet&#xff1a;可扩展且高效的目标检测 0.论文摘要 模型效率在计算机视觉中变得越来越重要。在本文中&#xff0c;我们系统地研究了用于目标检测的神经网络架构设计选择&#xff0c;并提出了几项关键优化以提高效率。首先&#xff0c;我们提出了一种加权双向特征金…

拖动线条改变区域大小

浏览网页时&#xff0c;经常看到这样一个功能&#xff0c;可以通过拖拽线条&#xff0c;改变左右区域大小 在管理后台中更为常见&#xff0c;菜单的宽度如果固定死&#xff0c;而后续新增的菜单名称又不固定&#xff0c;所以很可能导致换行&#xff0c;样式不太美观&#xff0c…

My first Android application

界面元素组成&#xff1a; 功能代码&#xff1a; /*实现功能&#xff1a;当输入内容后&#xff0c;欢迎文本发生相应改变&#xff0c;并清除掉文本域内容当未输入任何内容时&#xff0c;弹出提示文本以警告用户*/val greetingText findViewById<TextView>(R.id.printer)…

Redis数据结构-String字符串

1.String字符串 字符串类型是Redis中最基础的数据结构&#xff0c;关于数据结构与要特别注意的是&#xff1a;首先Redis中所有的键的类型都是字符串类型&#xff0c;而且其他集中数据结构也都是在字符串类似基础上进行构建&#xff0c;例如列表和集合的元素类型是字符串类型&a…

cline通过硅基流动平台接入DeepSeek-R1模型接入指南

为帮助您更高效、安全地通过硅基流动平台接入DeepSeek-R1模型&#xff0c;以下为优化后的接入方案&#xff1a; DeepSeek-R1硅基流动平台接入指南 &#x1f4cc; 核心优势 成本低廉&#xff1a;注册即送2000万Tokens&#xff08;价值约14元&#xff09;高可用性&#xff1a;规…

Java多线程三:补充知识

精心整理了最新的面试资料&#xff0c;有需要的可以自行获取 点击前往百度网盘获取 点击前往夸克网盘获取 Lambda表达式 简介&#xff1a; 希腊字母表中排序第十一位的字母&#xff0c;英语名称为Lambda避免匿名内部类定义过多其实质属于函数式编程的概念 为什么要使用lam…

装修流程图: 装修前准备 → 设计阶段 → 施工阶段 → 安装阶段 → 收尾阶段 → 入住

文章目录 引言I 毛坯房装修的全流程**1. 装修前准备****1.1 确定装修预算****1.2 选择装修方式****1.3 选择装修公司****1.4 办理装修手续****2. 设计阶段****2.1 量房****2.2 设计方案****2.3 确认方案****3. 施工阶段****3.1 主体拆改****3.2 水电改造****3.3 防水工程****3.…

VBA脚本将DeepSeek嵌入Word中教程

一、获取API-Key 目前我们可以直接只用官网的API来实现&#xff0c;申请这一步是关键 也可以直接访问官网的API平台&#xff1a;https://platform.deepseek.com/ &#xff0c;没注册的注册完登录一下&#xff0c;我们点击到左侧菜单的“APIKeys”按钮&#xff0c;然后点击右侧…

DeepSeek接入Siri(已升级支持苹果手表)完整版硅基流动DeepSeek-R1部署

DeepSeek接入Siri&#xff08;已升级支持苹果手表&#xff09;完整版硅基流动DeepSeek-R1部署 **DeepSeek** 是一款专注于深度学习和人工智能的工具或平台&#xff0c;通常与人工智能、机器学习、自动化分析等领域有关。它的主要功能可能包括&#xff1a;深度学习模型搜索&…

网站搭建基本流程

需求分析&#xff1a; 实现网站搭建的过程&#xff1a;首先进行网站的需求性分析 网站可分为前台系统和后台系统&#xff0c;由不同的功能拆分为不同的模块 如下是一个电商网站可以拆分出的模块&#xff1a; 在编写代码前&#xff0c;我们要先对网站进行架构&#xff0c;通过…

QT实战-基于QWidget实现的异形tip窗口

本文主要介绍了qt中,基于QWidget实现异形tip窗口的几种实现方式,话不多说,先上图, 1.使用QPainter和QPainterPath实现 代码:tipwnd1.h #ifndef TIPWND1_H #define TIPWND1_H#include <QWidget>class TipWnd1 : public QWidget {Q_OBJECTQ_PROPERTY(QColor my_border…

【C++篇】树影摇曳,旋转无声:探寻AVL树的平衡之道

文章目录 从结构到操作&#xff1a;手撕AVL树的实现一、AVL树介绍1.1 什么是AVL树1.2 平衡因子的定义1.3 平衡的意义1.4 AVL树的操作 二、AVL树的节点结构2.1 节点结构的定义&#xff1a; 三、插入操作3.1 插入操作概述3.2 步骤1&#xff1a;按二叉查找树规则插入节点3.3 步骤2…

清华大学deepseek教程第四版 DeepSeek+DeepResearch 让科研像聊天一样简单(附下载)

deepseek使用教程系列 DeepSeekDeepResearch 让科研像聊天一样简单(附下载) https://pan.baidu.com/s/1VMgRmCSEzNvhLZQc8mu6iQ?pwd1234 提取码: 1234 或 https://pan.quark.cn/s/f3d4511b790a

leetcode刷题记录(一百零七)——279. 完全平方数

&#xff08;一&#xff09;问题描述 279. 完全平方数 - 力扣&#xff08;LeetCode&#xff09;279. 完全平方数 - 给你一个整数 n &#xff0c;返回 和为 n 的完全平方数的最少数量 。完全平方数 是一个整数&#xff0c;其值等于另一个整数的平方&#xff1b;换句话说&#x…

利用AFE+MCU构建电池管理系统(BMS)

前言 实际BMS项目中&#xff0c;可能会综合考虑成本、可拓展、通信交互等&#xff0c;用AFE&#xff08;模拟前端&#xff09;MCU&#xff08;微控制器&#xff09;实现BMS&#xff08;电池管理系统&#xff09;。 希望看到这篇博客的朋友能指出错误或提供改进建议。 有纰漏…

基于SpringBoot的智慧家政服务平台系统设计与实现的设计与实现(源码+SQL脚本+LW+部署讲解等)

专注于大学生项目实战开发,讲解,毕业答疑辅导&#xff0c;欢迎高校老师/同行前辈交流合作✌。 技术范围&#xff1a;SpringBoot、Vue、SSM、HLMT、小程序、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、安卓app、大数据、物联网、机器学习等设计与开发。 主要内容&#xff1a;…

[网络] 如何开机自动配置静态IP,并自动启动程序

背景&#xff1a; 需要固定ip地址&#xff0c;并且能够自动启动可执行文件。 流程&#xff1a; 1.在/etc/network/interfaces 中添加 auto eth0 iface eth0 inet staticaddress 192.168.1.100netmask 255.255.255.0gateway 192.168.1.1 2.将下面这行代码添加自动启动脚本 …

打造智能聊天体验:前端集成 DeepSeek AI 助你快速上手

DeepSeek AI 聊天助手集成指南 先看完整效果&#xff1a; PixPin_2025-02-19_09-15-59 效果图&#xff1a; 目录 项目概述功能特点环境准备项目结构组件详解 ChatContainerChatInputMessageBubbleTypeWriter 核心代码示例使用指南常见问题 项目概述 基于 Vue 3 TypeScrip…

Mac 清理缓存,提高内存空间

步骤 1.打开【访达】 2.菜单栏第五个功能【前往】&#xff0c;点击【个人】 3.【command shift J】显示所有文件&#xff0c;打开【资源库】 4.删除【Containers】和【Caches】文件 Containers 文件夹&#xff1a;用于存储每个应用程序的沙盒数据&#xff0c;确保应用程序…