当前位置: 首页 > news >正文

游戏引擎学习第九天

视频参考:https://www.bilibili.com/video/BV1ouUPYAErK/

修改之前的方波数据,改播放正弦波

在这里插入图片描述

下面主要讲关于浮点数

1. char(字符类型)

  • 大小:1 字节(8 位)
  • 表示方式char 存储的是一个字符的 ASCII 值。由于它是一个整数类型,它在内存中是以 二进制 形式存储的。
    • 有符号 char:表示的值范围通常是 -128127,其符号位决定了值的正负。
    • 无符号 char:范围从 0255

存储示例

  • char c = 'A'; 对应的 ASCII 值是 65,其二进制表示为 01000001

内存示意:

  字符 'A'(ASCII 65)十六进制: 0x41二进制:   01000001

3. int(整数类型)

  • 大小:4 字节(32 位)
  • 表示方式int 存储的是一个整数,采用 二进制补码 表示。
    • 有符号 int:范围通常为 -2,147,483,6482,147,483,647,最高位为符号位。
    • 无符号 int:表示的范围从 04,294,967,295

存储示例

  • int i = -123456; 使用 32 位二进制补码表示:
    • -123456 的二进制补码表示:11111111 11111110 00011101 11000000
      123456 0b00000000 00000001 11100010 01000000
      ~123456 0b11111111 11111110 00011101 10111111 取反
      ~123456+1 0b11111111 11111110 00011101 11000000 +1

在这里插入图片描述

内存示意:

  int i = -123456;二进制补码表示: 11111111 11111110 00011101 11000000十六进制表示: 0xFFFE1DC0

负数补码表示,按位取反+1

5. float(单精度浮点数)

  • 大小:4 字节(32 位)
  • 表示方式float 按照 IEEE 754 标准表示为 32 位浮点数,包括 符号位指数部分尾数(有效数字) 部分。表示方法如下:
    • 符号位(1 位):表示数字的正负。
    • 指数部分(8 位):表示数字的范围,通过偏移量调整。
    • 尾数部分(23 位):表示数字的精度。

表示为:
( − 1 ) 符号 × 1. 尾数 × 2 指数 − 127 (-1)^{\text{符号}} \times 1.\text{尾数} \times 2^{\text{指数}-127} (1)符号×1.尾数×2指数127

存储示例

  • float f = 3.14f; 的 IEEE 754 单精度表示:
    • 3.14 的二进制表示为:0 10000000 10010001111010111000011
#include <cstring>
#include <iostream>void printBinary(float num) {// 将 float 转换为 int(按字节复制)int bits;std::memcpy(&bits, &num, sizeof(bits));// 打印二进制表示for (int i = 31; i >= 0; --i) {std::cout << ((bits >> i) & 1); // 逐位打印if (i == 31 || i == 23)std::cout << " "; // 分隔符,用于区分符号位、指数位、尾数位}std::cout << std::endl;
}int main() {float num = 3.14f;std::cout << "Binary representation of " << num << " is: ";printBinary(num);return 0;
}

在这里插入图片描述

float 32 位

内存示意:

  float f = 3.14f;符号位:0指数部分:10000000尾数部分:10010001111010111000011十六进制表示: 0x4048F5C3

在这里插入图片描述

6. double(双精度浮点数)

在这里插入图片描述

  • 大小:8 字节(64 位)
  • 表示方式double 也按照 IEEE 754 标准表示,但它使用 64 位,包括 符号位指数部分尾数部分。它的精度比 float 更高,具体结构如下:
    • 符号位(1 位)
    • 指数部分(11 位)
    • 尾数部分(52 位)

表示为:
( − 1 ) 符号 × 1. 尾数 × 2 指数 − 1023 (-1)^{\text{符号}} \times 1.\text{尾数} \times 2^{\text{指数}-1023} (1)符号×1.尾数×2指数1023

存储示例

  • double d = 3.141592653589793; 的 IEEE 754 双精度表示:
    • 3.141592653589793 的二进制表示为:0 10000000000 1001001000011111101101010100010001000010110100011000

内存示意:

  double d = 3.141592653589793;符号位:0指数部分:10000000000尾数部分:1001001000011111101101010100010001000010110100011000

double类似只是表示的位数更多了

继续上面修改写入正弦数据

在这里插入图片描述

示例:

假设采样率为 44100 Hz(即每秒采样 44100 个样本),频率为 440 Hz(比如这是标准 A 音符的频率)。

  • 每秒钟你会采集 44100 个样本。
  • 每秒钟会有 440 个周期。

那么一个周期的持续时间(即波周期)就是:

W a v e P e r i o d = 44100 440 ≈ 100.23 毫秒 WavePeriod = \frac{44100}{440} \approx 100.23 \text{ 毫秒} WavePeriod=44044100100.23 毫秒

这意味着,每一个周期(即波的一个完整振荡)需要约 100.23 毫秒的时间。

  • 波周期(WavePeriod) 是波形完成一个周期所需的时间,单位是秒(s)。
  • 采样率(S) 是每秒钟采样多少个点,单位是 样本/秒(Hz)
  • 频率(f) 是波形每秒钟振荡多少次,单位是 赫兹(Hz)

波周期 = 采样率 / 频率 表示了 一个周期占用的时间,即波形完成一个振荡所需要的时间,反映了波形的 频率与采样细节的关系

在这里插入图片描述

优化一下代码把声音写缓存相关代码提出来

在这里插入图片描述

vs watch技巧

在这里插入图片描述

添加模拟手柄改变音频调试

在这里插入图片描述

模拟手柄软件

因为我没有手柄只能用模拟器进行调试
游戏手柄模拟器Gaming Keyboard Splitter
可以到这个完整下载对应的软件Gaming Keyboard Splitter
https://softlookup.com/download.asp?id=280311

我已经传到CSDN
https://download.csdn.net/download/TM1695648164/89982708

软件第一次运行会安装驱动会重启电脑

  1. debug运行程序
  2. 打开模拟手柄软件Gaming Keyboard Splitter
    在这里插入图片描述

在这里插入图片描述

上面测试会听到撕裂的声音切换时

“相位跳变”是指在切换频率时,波形的相位发生了不连续的变化,导致声音出现不自然的突变。为了理解这一点,我们需要从正弦波的相位频率切换时的平滑性角度来分析。

1. 什么是相位?

在波形中,相位指的是波形在某个时间点的状态,通常用一个角度来表示。例如,对于正弦波 sin(θ),其中 θ 表示相位,θ 通常是通过时间、频率和波速来计算的。

对于音频信号,波形的相位描述的是波形的位置(比如峰值、零交点等),以及波形如何在时间轴上前进。不同频率的正弦波具有不同的波长(周期),而相位描述的是这些波形的“开始位置”。

2. 什么是相位跳变?

相位跳变是指在两个连续的波形之间,相位发生了突然变化。当你在播放音频时切换频率时,如果没有处理好相位,就可能会导致新的波形与旧的波形在相位上的不对齐。

  • 相位对齐:指的是两个不同频率的波形在切换时,其相位(起始位置)要相同,或者在一个平滑的过渡过程中对齐。相位对齐确保了波形的过渡是平滑的,没有断裂感。

  • 相位跳变:如果你在切换频率时,新的波形从一个不对齐的相位开始(比如,原本的波形处于一个正半周期,而新的波形从零交点开始),那么这两个波形之间会出现不连续性。这种不连续性会导致音频信号的突变或毛刺声。

3. 为什么频率切换会导致相位跳变?

在频率切换时,如果频率的变化过于突兀,那么相位可能会发生跳变。例如:

  • 假设你正在播放一个频率为 256Hz 的正弦波,这意味着每秒钟播放 256 个完整的波形周期。如果你突然切换到 512Hz 的频率,意味着每秒钟播放的周期数是原来的两倍。如果没有对相位进行平滑过渡,新的频率波形的起始位置可能会不一致(比如一个正弦波的峰值和下一个波形的零交点不对齐),导致两个波形之间的过渡不连贯。

  • 当波形的相位不一致时,你就会听到一种不自然的“呲”声或毛刺声,因为音频信号的突然变化让耳朵感受到强烈的突变。

4. 如何理解和避免相位跳变?

  • 平滑过渡:为了避免相位跳变,最常见的做法是在切换频率时,确保新的频率从平滑过渡的相位开始。这意味着你可以在切换频率之前记录当前频率的相位,并确保新的频率从当前的相位状态开始播放。

  • 相位对齐:如果频率变化较大(比如从 256Hz 跳到 512Hz),你可以通过计算当前的相位并将其对齐到新频率来避免跳变。这样,新的波形从一个平滑的相位开始,不会有突然的相位变化。

  • 渐变过渡:另一种方法是通过渐变的方式逐步调整频率,而不是直接跳到新的频率。通过线性插值或其他平滑过渡方法,可以在一段时间内平滑地过渡到目标频率,从而避免突如其来的波形跳跃。

5. 示例:

假设你有一个频率为 256Hz 的正弦波:

y = sin(2π * 256 * t)

在某一时刻,t = 0 时,sin(0) = 0t = 1/256 时,sin(2π) = 0,等等。

如果你突然从 256Hz 切换到 512Hz:

y = sin(2π * 512 * t)

这时,相位的变化会更加快速。假如没有正确处理相位,那么切换时,新的频率可能从一个不连续的位置开始。例如,之前的正弦波刚刚完成一个周期,而新的频率波形从零交点开始,从而导致两个波形之间的断裂感(即“呲”声)。

6. 避免相位跳变的方法:

  • 记录当前的相位:在频率切换时,记录下当前时刻的相位,然后确保新的频率从该相位继续播放。例如,如果你在 t = 0.1s 时切换频率,可以将当前的相位(例如 2π * 256 * 0.1)保存下来,切换到新的频率时,新的波形从相同的相位位置继续计算。

  • 平滑过渡:在频率变化的过程中,使用渐变方式逐步过渡到目标频率,这样可以避免相位的突变。例如,可以在每个采样周期调整频率增量,而不是直接跳到新频率。

通过这些方法,可以避免频率切换时产生不自然的“呲”声或毛刺声。

在这里插入图片描述

为了解决这个问题
在这里插入图片描述

下面用模拟手柄 StickY 对 上面代码进行测试

基于 AButton 按钮的操作来改变音频频率(ToneHz)和音频波形的周期(WavePeriod),并可能结合了控制器的 Y 轴摇杆 (StickY) 来微调频率。

更新 ToneHz(音频频率)

 // 获取摇杆的 X 和 Y 坐标值(-32768 到 32767)int16 StickX = Pad->sThumbLX;int16 StickY = Pad->sThumbLY;// 根据摇杆的 Y 坐标值调整音调和声音xOffset += StickX >> 12;yOffset += StickY >> 12;// 更新音调频率 (ToneHz),通过摇杆的 Y 值来调节// 这里是将 StickY 映射到频率范围内,使得频率与摇杆的上下运动相关。// 512 是基准频率,StickY 值影响音频频率的变化范围。SoundOutput.ToneHz =512 + (int)(256.0f * ((real32)StickY / 30000.0f));// 计算波周期,基于频率,决定波形的周期SoundOutput.WavePeriod =SoundOutput.SamplesPerSecond / SoundOutput.ToneHz;std::cout << "ToneHz " << SoundOutput.ToneHz << " sThumbLY "<< StickY << std::endl; // 输出音调频率和摇杆值
  • SoundOutput.ToneHz = 512 + (int)(256.0f * ((real32)StickY / 30000.0f));

    • 这行代码根据摇杆的 Y 值 (StickY) 动态计算音频的频率 ToneHz
    • StickY 的值范围是 -32768 到 32767(即摇杆的 Y 轴范围)。将它除以 30000.0f 来归一化到[-1, 1],然后乘以 256.0f 来决定音频频率变化的幅度。
    • 512 是基准频率,通过摇杆的上下动作来改变频率。
  • SoundOutput.WavePeriod = SoundOutput.SamplesPerSecond / SoundOutput.ToneHz;

    • 这行代码计算音频波的周期。波周期是根据音频的采样率 (SamplesPerSecond) 和音调频率 (ToneHz) 来决定的。波周期越短,频率越高,声音听起来越尖锐。

在这里插入图片描述

上面的测试中会出现延时的现象,键盘按下到音频改变有延时

在这里插入图片描述

相关文章:

游戏引擎学习第九天

视频参考:https://www.bilibili.com/video/BV1ouUPYAErK/ 修改之前的方波数据&#xff0c;改播放正弦波 下面主要讲关于浮点数 1. char&#xff08;字符类型&#xff09; 大小&#xff1a;1 字节&#xff08;8 位&#xff09;表示方式&#xff1a;char 存储的是一个字符的 A…...

CondaError: Run ‘conda init‘ before ‘conda activate‘解决办法

已经执行了conda init&#xff0c;但是还是会报错CondaError: Run ‘conda init’ before ‘conda activate’ 原因&#xff1a;权限不够 解决办法&#xff1a;以管理员身份运行cmd&#xff0c;然后进入要操作的文件夹下&#xff0c;重新执行 conda init 和 conda activate 就可…...

如何提高谷歌浏览器的稳定性

谷歌浏览器是全球使用最广泛的网络浏览器之一&#xff0c;以其速度和易用性著称。然而&#xff0c;随着时间的推移&#xff0c;用户可能会遇到一些稳定性问题&#xff0c;比如页面加载缓慢、崩溃或意外关闭等。本文将提供一些实用的技巧来帮助你提高谷歌浏览器的稳定性&#xf…...

Spring基础之——控制反转(IOC)、依赖注入(DI)与切面编程(AOP)概念详解(适合小白,初学者必看)

前言 本篇博客讲详细介绍Spring框架中的两个最核心且最基础的概念&#xff1a;控制反转&#xff08;IOC&#xff09;和面向切面编程&#xff08;AOP&#xff09;。以及如何通过IDEA来构建一个Spring项目&#xff0c;通过实战和理论结合的方式来让大家真的学会Spring这个最流行的…...

java排序算法汇总

一、排序算法我介绍 1.1、介绍 排序也称排序算法(Sort Algorithm)&#xff0c;排序是将一组数据&#xff0c;依指定的顺序进行排列的过程。 1.2、排序的分类&#xff1a; 1) 内部排序&#xff1a;指将需要处理的所有数据都加载到内部存储器中进行排序。 2) 外部排序法&…...

游戏引擎中LOD渲染技术

一.LOD(Level Of Detail) 为了降低GPU渲染压力,根据摄像机距离模型距离将面数较高的模型替换为面数较低的模型. LOD LOD0(distance<10) LOD1(distance<20) LOD2(distance<30) 故通常引擎中MetaMesh是由一个或多个LOD模型构成. MetaMesh mesh mesh.lod1 mesh.lod…...

【MacOS开发环境配置与应用开发--详细教程】

在macOS上进行应用开发&#xff0c;通常使用Xcode作为主要开发环境&#xff0c;Xcode集成了所有必需的工具和资源&#xff0c;支持多种编程语言&#xff0c;如Swift、Objective-C、C等。 MacOS开发环境配置与应用开发 1. 安装Xcode1.1 安装方法1.2 验证安装1.3 配置命令行工具…...

【回溯法】——组合总数

回溯核心思想 回溯算法的关键在于&#xff1a;不合适就退回到上一步具体的&#xff1a;通过枚举法&#xff0c;对所有可能性进行遍历&#xff0c;枚举顺序是一条路走到黑&#xff0c;走到头满足条件后&#xff0c;退一步&#xff0c;再尝试之前没走过的路&#xff0c;直到所有…...

JavaScript 自动化软件:AutoX.js

<div id"content_views" class"htmledit_views" deep"6"><p></p>...

探索Scala编程:图书管理系统实战

在这篇文章中&#xff0c;我们将通过一个简单的图书管理系统项目来深入理解Scala编程。这个项目不仅会帮助你掌握Scala的基本操作&#xff0c;还会让你了解如何使用Scala来处理实际问题。准备好了吗&#xff1f;让我们开始吧&#xff01; 项目目标 我们的目标是创建一个图书管…...

Java之遍历List集合安全地删除元素

Java之遍历List集合安全地删除元素 在Java中&#xff0c;遍历一个List并安全地删除元素是一个需要注意的问题。因为直接在遍历过程中修改集合&#xff08;如删除元素&#xff09;可能会导致ConcurrentModificationException异常。这是因为集合的迭代器在检测到集合在迭代过程中…...

ceph的集群管理

0 环境说明 ip地址主机名额外硬盘是否加入ceph集群10.0.0.141ceph141sdb 300G&#xff0c;sdc 500G是10.0.0.142ceph142sdb 300G&#xff0c;sdc 500G, sdd 1000G否10.0.0.143ceph143sdb 300G&#xff0c;sdc 500G否 在上一篇文章中&#xff0c;已经成功地初始化了一个ceph管…...

STM32 设计的较为复杂的物联网项目,包括智能家居控制系统,涵盖了硬件和软件的详细设计。

使用 STM32 设计的较为复杂的物联网项目&#xff0c;包括智能家居控制系统&#xff0c;涵盖了硬件和软件的详细设计。 一、硬件设计 微控制器&#xff1a;选择 STM32F4 系列微控制器&#xff0c;如 STM32F407ZGT6&#xff0c;具有高性能和丰富的外设资源。 传感器模块&#x…...

Kettle配置数据源错误“Driver class ‘org.gjt.mm.mysql.Driver‘ could not be found”解决记录

问题描述 错误提示&#xff1a;“Driver class ‘org.gjt.mm.mysql.Driver’ could not be found, make sure the ‘MySQL’ driver (jar file) is installed.” 原因分析&#xff1a; 根据错误提示是缺少了相关的数据源连接jar包。 解决方案&#xff1a; 安装对应的Mysql…...

二分搜索的三种方法

首先总的说一下二分搜索。如果区间具有二分性&#xff0c;这个二分性不仅仅是指区间是有序的&#xff0c;而是我们可以通过某一种性质将整个区间分成左区间和右区间。我们通过二分的方法去不断缩小查找的区间&#xff0c;最终让区间内没有元素&#xff0c;这个时候的我们就得到…...

使用python编写工具:快速生成chrome插件相关文件结构

本文将详细分析一段用 wxPython 编写的 Python 应用程序代码。该程序允许用户创建一些特定文件并将它们保存在指定的文件夹中&#xff0c;同时也能够启动 Google Chrome 浏览器并打开扩展页面&#xff0c;自动执行一些操作。 C:\pythoncode\new\crxiterationtaburl.py 全部代码…...

内存、显存和GPU在Transformer架构中承担什么计算任务

目录 内存、显存和GPU在Transformer架构中承担什么计算任务 一、内存、显存和GPU的区别 二、在Transformer架构中的计算任务 内存、显存和GPU在Transformer架构中承担什么计算任务 是计算机系统中重要的组成部分,它们在Transformer架构中承担着不同的计算任务。以下是对这…...

【计算机网络】TCP协议特点3

心跳机制 什么是心跳机制 心跳机制是在计算机系统、网络通信和许多其他技术领域广泛应用的一种机制&#xff0c;用于检测两个实体之间的连接是否仍然活跃&#xff0c;或者设备是否还在正常运行。就是每隔一段时间发送一个固定的消息给服务端&#xff0c;服务端回复一个固定…...

移植LVGL8.2以及移植过程的理解

一、LVGL刷新显示&#xff08;画点 OR 区域刷新颜色&#xff09; 原来LCD的区域填充&#xff0c;由于没用到DMA就是普通的遍历区域块的坐标&#xff0c;需要传入的坐标就是显示区域的x轴起始与x轴尾部。y轴的起始与y轴的尾部。 怎么实现呢&#xff1f; SPI不加DMA实现区域填充…...

动态规划-背包问题——1049.最后一块石头的重量II

1.题目解析 题目来源 1049.最后一块石头的重量II——力扣 测试用例 2.算法原理 首先需要将该问题转化为0-1背包问题后再做分析 1.状态表示 根据数学中的知识我们知道将一个数字分为两个子数后求这两个子数的最小差值&#xff0c;那么就要求这两个子数尽可能接近于原数字的一…...

【C++学习(37)】并发性模式:如生产者-消费者、读写锁等。 架构模式:如MVC、MVVM等。属于23 种设计模式吗? RAII 的关系?

并发性模式(如生产者-消费者、读写锁等)和架构模式(如 MVC、MVVM 等)并不属于 Gang of Four(GoF) 提出的 23 种经典设计模式 中。这些模式是其他领域中的设计模式,虽然它们和 GoF 的设计模式有交集,尤其是在程序架构和资源管理方面,但并不直接包含在 GoF 的 23 种设计…...

[Mysql] Mysql的多表查询----多表关系(下)

4、操作 方式二&#xff1a;创建表之后设置外键约束 外键约束也可以在修改表时添加&#xff0c;但是添加外键约束的前提是&#xff1a;从表中外键列中的数据必须与主表中主键列中的数据一致或者是没有数据。 语法&#xff1a; alter table <从表名> add constr…...

命名空间(namespace)详解(一)

域 在学习命名空间之前&#xff0c;我们首先要了解几种常见的域 一、域的种类 1、类作用域 类作用域是指定义在类内部的成员&#xff08;包括数据成员和成员函数&#xff09;的可见性和访问权限的范围 代码示例&#xff1a; #define _CRT_SECURE_NO_WARNINGS 1#include &…...

HarmonyOS ArkTs 解决流式传输编码问题

工作日志 日期&#xff1a;2024-11-15 标题&#xff1a;HarmonyOS ArkTs 解决流式传输编码问题 问题描述 问题&#xff1a;在处理流式数据的 HTTP 请求时&#xff0c;服务器返回的数据存在编码问题&#xff0c;导致数据无法正确地解码为字符串。部分数据在解码后出现了乱码…...

NPOI 实现Excel模板导出

记录一下使用NPOI实现定制的Excel导出模板&#xff0c;已下实现需求及主要逻辑 所需Json数据 对应参数 List<PurQuoteExportDataCrInput> listData [{"ItemName": "电缆VV3*162*10","Spec": "电缆VV3*162*10","Uom":…...

【OpenGL】OpenGL简介

文章目录 OpenGL概述OpenGL的本质OpenGL相关库核心库窗口管理glutfreeglutglfw 函数加载glewGLAD OpenGL概述 OpenGL(Open Graphics Library) 严格来说&#xff0c;本身并不是一个API&#xff0c;它是一个由Khronos组织制定并维护的规范(Specification)。OpenGL规范严格规定了…...

shell命令笔记

一、shell基本基础知识 1. shell命令中捕获上一个命令执行是否成功&#xff0c;通过判断 $? 是否为0&#xff0c;为0则表示成功&#xff0c;其他错误码则表示执行失败。 2. sheel命令中&#xff0c;变量赋值时默认都是字符串类型。赋值时须注意单引号与双引号的区别&#xf…...

qml显示OpenCV mat图片

文章目录 方式一QQuickPaintedItem 类介绍主要特点使用方法示例代码在 QML 中使用主要方法和属性注意事项编写OpenCV mat显示代码方式二本篇博客介绍在Qt6.5.3 qml项目里介绍如何显示OpenCV mat图片。视频:https://edu.csdn.net/learn/40003/654043?spm=3001.4143 在qml里显示…...

类与对象(2)---类的6个默认成员函数

1.类的6个默认成员函数 任何类在什么都不写时&#xff0c;编译器会自动生成以下6个默认成员函数。 默认成员函数&#xff1a;用户没有显式实现&#xff0c;编译器会生成的成员函数称为默认成员函数。 2.构造函数 2.1构造函数特性 构造函数的主要任务是初始化对象。 它有如下特…...

华为云租户网络-用的是隧道技术

1.验证租户网络是vxlan 2.验证用OVS 2.1控制节点VXLAN 本端ip&#xff08;local ip&#xff09;192.168.31.8 2.2计算节点VXLAN 本端ip&#xff08;local ip&#xff09;192.168.31.11 计算节点用的是bond0做隧道网络 2.3查看bond文件是否主备模式...