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

辽宁网站制作购物网站英文介绍

辽宁网站制作,购物网站英文介绍,关于《大学物理》网站资源建设的思路,网站建设最新新闻演示资产系统中的一个 bug 我们留下了个问题#xff0c;你现在可以看到#xff0c;移动时它没有选择正确的资产。我们知道问题的原因#xff0c;就在之前我就预见到这个问题会出现。问题是我们的标签系统没有处理周期性边界的匹配问题。当处理像角度这种周期性的标签时你现在可以看到移动时它没有选择正确的资产。我们知道问题的原因就在之前我就预见到这个问题会出现。问题是我们的标签系统没有处理周期性边界的匹配问题。当处理像角度这种周期性的标签时系统不知道如何匹配最接近的值这就是问题的根源。因此今天我们需要花一点时间在黑板上讲解这个问题看看该如何修复它。 黑板周期性标签匹配 我们面临的问题是如何处理周期性的标签匹配。昨天有人提出了一个很好的建议即为了统一处理所有标签或许我们可以引入“所有标签都是周期性”的概念对于那些不想作为周期性处理的标签我们可以为它们设置一个非常大的周期。这是一个非常不错的思路。接下来我将详细解释一下我们遇到的问题并探讨如何实施这个建议即让所有标签都有一个周期但将其设置为非常大以免影响那些不需要周期性处理的标签。 问题的根源 我们的核心问题在于使用了一个叫做 atan2 的函数。这个函数的作用是将一个方向向量转换为一个角度表示物体朝向的方向。举个例子当我们使用方向向量如速度向量时atan2 会将其转化为一个角度这样就能得到一个标量值用作标签值。我们可以根据这个标签值来从资产库中匹配对应的精灵比如玩家移动的方向或者其他物体的移动方向。 问题出现在 周期性 上。atan2 返回的角度是周期性的意味着当角度转动一圈360度时它会回到初始位置。比如如果我们转动了360度就会回到0度而不是转到一个新的角度。为了匹配资产我们不能简单地比较两个角度的标量值像0度和360度虽然它们看起来差距很大但它们其实是相同的都是代表同一个方向。因此我们需要一种方式来判断这些看似不同的值其实是接近的这就是周期性带来的问题。 atan2 的输出范围 atan2 返回的结果是围绕0对称的它给出的角度范围是 -180 到 180而不是从0到360。换句话说如果角度是0atan2 会返回 -180 到 180 之间的值分别表示逆时针和顺时针的180度。如果用弧度来表示它的范围是 -π 到 π。因此我们的目标是让这个匹配机制适应这样的角度范围。 解决方案 我们可以将角度范围编码成 -π 到 π这样的匹配会比较容易。比如某个标签值可能对应 0、±π/2、π 和 -π/2这样就能够很自然地进行匹配。而且负π和π实际上是一样的应该匹配到同一个标签。 对于那些不需要周期性处理的标签我们可以简单地为它们设置一个非常大的范围比如从 -100000 到 100000这样就避免了它们与周期性标签冲突因为这个范围远远超过了我们需要处理的角度范围。只要这个范围足够大不会与周期性标签的范围交错就可以避免错误匹配。 总结来说通过将周期性标签的范围设置为 -π 到 π对于不需要周期性匹配的标签设置一个很大的范围这样就能够高效且准确地处理标签匹配问题。 黑板“邻域运算符” 问题的核心是如何在匹配过程中处理周期性角度。在周期性标签的匹配中当我们有一个角度 A 和一个角度 B假设我们想要将这两个角度与一个已设置为 π 的角度进行匹配时我们需要避免计算出 A 和 B 与 π 的差异非常大导致不正确的匹配。换句话说我们希望能够处理这种情况使得无论角度如何旋转能够正确地认为它们是接近的。 问题的背景 对于周期性角度我们希望当角度 A 和角度 B 相差很大时能够将它们视为接近的而不是认为它们在圆的两侧相差接近 360 度。例如当 A 是 350 度B 是 10 度时它们实际上应该是非常接近的因为在 360 度的周期内它们实际上只相差 20 度。这个问题的解决方案是引入一个“邻域操作符”neighborhood operator。 邻域操作符的作用 邻域操作符的作用是计算两个角度的最近距离而不是简单地通过角度值来比较它们的大小。邻域操作符将两个值映射到它们之间的最小距离而这个距离是相对的考虑了周期性的因素。 假设我们有两个角度 A 和 B我们希望计算 A 在 B 的邻域中时应该如何调整。我们不关心得到的邻域值本身而是关心调整后的角度之间的差异。具体地如果我们有一个角度 A当前角度值为正值且距离 B 很远我们希望通过邻域操作符将 A 调整成负值使其更加接近 B。这样两个角度之间的差异将变得更小而不是通过直接计算它们的差值可能得到一个很大的正数来产生错误的匹配。 举例说明 假设 A 的值是 350 度B 的值是 10 度。直接计算它们的差值会得到 350 度和 10 度之间的差值是 340 度这会被认为它们距离很远。通过邻域操作符处理后A 的角度会变为 -10 度即顺时针旋转 10 度而 B 的角度依然是 10 度这样它们之间的差值就变成了 0 度也就是完全匹配。这个调整是通过邻域操作符来实现的。 实现思路 在实现时我们可以将邻域操作符视作一个函数接受两个角度值作为输入输出它们之间最小的差异。这意味着如果两个角度值相差超过 180 度例如 A 是 350 度B 是 10 度我们会通过周期性调整将其“拉近”到较小的范围从而获得更精确的匹配结果。 简单来说邻域操作符的功能就是根据周期性调整角度的差值使得它们始终保持在最小的范围内从而确保匹配过程的正确性。 总结 为了处理周期性角度的匹配问题我们需要使用邻域操作符来计算角度之间的最小差距而不是直接计算它们的差异。这使得我们可以在角度的周期性范围内避免因大范围的旋转而导致错误的匹配确保角度在匹配时总是能够准确地找到最接近的值。 黑板“邻域距离” 在这里我们实际上并不需要一个“邻域算子”Neighborhood Operator因为我们并不关心生成这个“a”我们真正关心的是计算“邻域距离”。所以我们的目标是做一个类似于邻域操作的过程但我们只关心计算两个值之间的距离而不需要生成具体的邻域值。 我们不需要实际生成邻域值只需要计算它们的距离就可以了这样可以让整个过程变得更简单。虽然在某些情况下确实需要进行邻域操作例如插值时但在这种情况下我们只关心两个角度之间的最短距离而不需要真正生成邻域。因此我们只需要计算距离即可而不需要实际执行复杂的邻域操作。 接下来假设我们已经知道所有值都在一个特定的范围内比如在-π到π之间我们就可以根据这个范围来判断角度之间的关系。具体来说正数和负数总是有方向上的差异但这并不影响它们之间的距离计算因为无论如何我们都能够在一个周期范围内进行计算。 在这种情况下最简单的做法是检查这两个角度的符号即它们的正负如果它们的符号不同那么它们就可能不在同一个邻域内。否则它们就可能在相同的邻域内。 然而在进一步思考后我们发现其实并不需要专门进行符号检查。我们可以简化流程直接跳过这一步。总的来说我们只需要关注如何处理这两个角度之间的最短距离而不需要关心它们是否在同一个邻域内。 黑板将一个负范围的点的符号改变计算它到正范围点的距离 我们有两个数一个是正数一个是负数目标是计算它们之间的距离。首先我们发现它们的符号不同因此我们想要改变其中一个数的符号使其变成与另一个数相同。具体来说我们希望将负数变成正数。 为了做到这一点我们可以通过以下方式来操作负数的旋转负旋转其实就是从零开始绕一圈的正向距离加上多出来的部分。因此我们可以从负π开始向正方向进行旋转直到到达目标数B的位置这样就变成了正旋转。 例如如果B是负数我们可以通过从负π开始顺时针旋转得到B实际上就是等于B加上整个范围2π。所以B变成正数的操作就是将B加上这个周期范围即加上2π。 这个过程说明负数通过加上整个周期2π就可以转化为对应的正数。这样我们就可以用这种方式来处理符号不同的数值使它们符合我们需要的范围和计算要求。 黑板将一个正数移动到负数 如果我们有一个正数想要将其转化为负数过程和之前的情况类似但这次是进行负旋转。 负数转正数 如果我们有一个负数我们可以通过加上整个周期2π使其变成正数。这样通过顺时针旋转的方式可以将负数转变为正数。 正数转负数 如果我们想要把一个正数变成负数步骤就有所不同。具体来说我们需要从正数的位置例如π的位置开始进行逆时针的旋转。 以正数A为例假设A位于[0, π]范围内要将其转变为负数可以按照以下步骤 从π的地方开始逆时针旋转到A的位置。这时候我们需要从π位置开始逆时针旋转到A这相当于减去一个π即我们需要将A减去π因为π是最大正数。 例如如果A是一个正数位于(0, π)之间我们可以将其转换为负数方法是将这个数减去π使其变成负数。 总结 对于负数转正数我们通过加上2π来实现。对于正数转负数我们通过减去π来实现。 这个过程就相当于在单位圆上进行旋转改变角度的符号通过加或者减掉2π或π来实现符号的转换。 黑板做这个邻域计算的完整公式 我们讨论的是如何计算两个数之间的“邻域”neighborhood这个操作实际上并不是特别复杂我们可以通过计算它们之间的差距来完成。 1. 正数和负数之间的转化 如果我们有一个正数和一个负数并且想要计算它们之间的距离我们首先需要确定它们的符号。如果这两个数符号不同一个是负数一个是正数我们可以通过调整其中一个数的符号使得两个数具有相同的符号。具体来说如果我们想把一个负数变为正数方法是加上一个周期 2 π 2\pi 2π。反之如果我们想把一个正数变为负数方法是减去 π \pi π。 2. 计算两个数之间的距离 如果两个数符号相同我们可以直接计算它们的距离即它们的差值。如果两个数符号不同则我们需要做一些额外的操作。我们可以将负数转化为正数或者正数转化为负数来让它们具有相同的符号然后再计算它们之间的差距。在计算时我们可以用一种简化的方式避免进行符号判断。我们可以分别计算两个数之间的差距然后选择较小的距离作为最终结果。 3. 具体操作 假设我们有两个角度值分别是 θ \theta θ 和 ϕ \phi ϕ。 如果 θ \theta θ 是负数而 ϕ \phi ϕ 是正数我们可以通过加上周期来将负数转为正数。如果 θ \theta θ 是正数而 ϕ \phi ϕ 是负数我们可以通过减去 π \pi π 来将正数转为负数。 无论是正负数之间的转换核心操作是计算它们之间的“差距”。我们可以通过加减周期的方式将符号统一然后计算差值。 4. 简化计算 不需要显式判断符号我们可以直接计算两者之间的距离 首先计算 θ − ϕ \theta - \phi θ−ϕ。然后计算 θ − (range) × sin ⁡ ( θ ) \theta - \text{(range)} \times \sin(\theta) θ−(range)×sin(θ)其中 range 是整个范围的大小例如 2 π 2\pi 2π。然后取这两个差值的最小值即可得到两个数之间的实际距离。 5. 结论 通过简化的操作我们可以避免使用条件分支来判断符号而是直接计算两种情况的差值最终选择较小的距离。这样既避免了分支操作也提高了计算效率。 game_asset.h将 HalfTagRange 添加到游戏资产 在进行资产匹配时我们希望将周期性periodicity引入到资产中以确保匹配的准确性和一致性。为了实现这一点我们需要对周期的理解和管理。 1. 理解周期性 我们并不需要为每个标签tag都单独设置一个周期。实际上周期通常是由标签的类型决定的因此只需要为每种标签类型定义一个周期即可。这样周期性实际上是和标签类型紧密相关的而不是每个标签实例都需要一个单独的周期。 2. 周期的存储和管理 在资产中每个标签tag通常会有一个周期字段这个周期字段可以命名为 tag period 或者 half tag range它表示标签的周期范围。这个“半标签范围”HalfTagRange可以理解为每种标签类型对应的周期的一半。例如如果一个标签的周期是 2 π 2\pi 2π那么半周期就是 π \pi π。这样我们在管理标签时只需要在资产的标签中为每个标签类型存储一次周期值而不需要为每个标签实例都单独存储周期。这样可以减少存储空间并提高效率。 3. 实际操作 每次在处理资产标签时只需要知道每种标签的周期范围就可以进行相应的操作。例如对于每种标签类型我们可以在标签结构中定义一个字段来存储周期信息如 tag period并根据该值来进行计算。通过这种方式标签的周期性可以高效地管理和应用从而简化了资产匹配的过程。 4. 总结 不需要为每个标签单独定义周期而是可以通过定义标签类型的周期或者半周期来管理周期性。这样我们只需存储每种标签类型的周期范围而在实际处理时直接使用这些周期信息。这种方法不仅简化了周期的管理也提高了资产匹配过程的效率和准确性。 game_asset.cpp为每个 TagType 设置 HalfTagRange 大多数情况下我们并不关心周期性问题周期性标签的出现频率远低于非周期性标签。因此我们可以采取一种简化的方式来处理标签的周期性。以下是处理流程的详细步骤 1. 初始化资产时的周期性处理 在初始化游戏资产时我们可以遍历所有的标签类型并为每种标签类型设置一个周期范围。对于大多数标签类型我们不需要关心周期性所以可以将它们的周期设置为一个非常大的数字。这个大数字的作用是标识这些标签类型没有周期性即它们的周期范围几乎是无穷大的。这个值可以是一个极大值只要它是我们永远不会使用的值就行因为它只是占位符并不会实际影响计算。 2. 处理周期性标签 对于需要周期性处理的标签类型我们不需要事先知道所有这些标签只需要关注那些确实具有周期性的标签。目前已经知道的一个周期性标签是“朝向方向”facing direction它的周期是 π \pi π即无论朝哪个方向最大旋转角度是 π \pi π180度。对于这种情况我们可以直接将其周期设置为 π \pi π而其他不需要周期性处理的标签则保持为一个非常大的值。 3. 具体实现 在初始化过程中对于所有标签类型我们先给它们设置一个默认的大周期值如 1 0 10 10^{10} 1010 或其他极大值。然后对于确实需要周期性处理的标签如朝向方向我们单独为它们设置实际的周期值如 π \pi π。这样周期性标签的处理就能被单独标识出来并在后续的计算中正确处理而其他标签类型则无需进行周期性计算。 4. 总结 大部分标签都不涉及周期性所以我们为这些标签设置一个非常大的周期值表示它们不需要周期性处理。只有少数几个标签会涉及周期性处理如朝向方向这些标签的周期值设置为实际的周期值如 π \pi π。通过这种方法可以在初始化时简化标签的周期性处理并在需要时进行特定的周期性计算。 在 BestMatchAsset 中使用 HalfTagRange 在进行标签匹配时目的是确保匹配结果是合理的并且能够正确计算标签之间的差异。以下是实现这一过程的详细步骤 1. 计算差异 在进行标签匹配时我们首先计算两个值之间的差异假设这两个值分别是 A A A 和 B B B那么它们之间的差异就是 A − B A - B A−B。但为了确保差异计算时考虑周期性我们需要引入“邻域差异”这个概念。也就是说计算时不仅仅是简单地减去 A A A 和 B B B 的差值还要考虑它们之间的周期性差异特别是在涉及周期性标签时。 2. 处理符号问题 在计算差异时需要检查两个值的符号正负。如果两个值的符号不同那么我们需要进行符号转换以确保差异的计算符合周期性要求。为了实现这个功能可以使用正弦函数sine function来辅助判断。如果符号不同可以根据需要调整差异确保计算结果在期望的周期范围内。 3. 符号判断和调整 如果没有现成的正弦函数实现我们可以通过简单的条件语句如 if 语句来判断 A A A 和 B B B 的符号并根据符号的不同做出适当的调整。判断符号的方式可以通过比较 A A A 和 B B B 的大小来实现如果 A A A 和 B B B 符号不同则需要调整差异值。 4. 最终实现 可以在标签匹配时通过判断标签的符号来决定是否需要调整差异值。如果符号相同直接计算差值。如果符号不同则需要调整差值确保结果正确地反映周期性影响。 5. 总结 在进行标签匹配时我们首先计算两个标签的差异并根据需要调整周期性差异。通过符号判断和正弦函数确保计算结果符合周期性要求。最终我们通过条件语句如 if来判断符号并调整差异从而确保匹配过程合理且准确。 game_intrinsics.h编写一个 real32 版本的 SignOf 在进行操作时遇到一些问题可能会觉得有些麻烦。为了简化工作可以假设将来会实现一个更好的版本来处理这些问题。经过一定的调整现在已经实现了所需的功能可以有效地进行操作。 game_asset.cpp继续将 (Half)TagRange 添加到 BestMatchAsset 为了处理某些标签类型的范围我们需要首先计算标签的半范围然后根据标签类型的范围调整。具体操作是我们将标签的范围TagRange乘以正弦值并进行一些运算来确定最终的范围。 接着我们通过计算两个数的差异比如 a 和 b来得到两种不同的距离值然后通过取最小值来找到最佳匹配。这意味着我们会选择这两个差异值中较小的那个以便获得更准确的结果。 此外为了优化工作我们可以使用一个新的变量 TagRange 来替代半范围计算这样可以简化操作。还可以使用 tau即 2π替代 π以便让数学计算更加一致和简洁。总之通过这些优化操作最终能得到更好的匹配结果。 调试器进入 BestMatchAsset 首先进入到相关代码部分查看资产组的内容。查看当前的匹配逻辑。当前的匹配是对两个值进行比较初步结果是将 0 和 0 进行匹配显然这两个数的差异为 0因此结果也会是 0并且没有特别的变化。 接下来我们看到程序在进行计算时计算了两个值之间的差异同时还会计算另一种可能的差异即完整的一个周期tau。这种计算是正确的因为对于周期性的匹配问题考虑整个周期是很重要的。这样处理后程序能够正确地处理周期性差异确保匹配的准确性。 玩游戏并查看我们新功能 接下来我们对计算出的两个差异值取最小值这样结果依然是 0然后继续进行下一步操作。之后通过加权计算得到最终的差异值DIF。这种方法在标签匹配上看起来更为准确。 通过这种方式我们能够实现更精确的方向匹配并且成功地加载正确的周期性资产。同时系统也没有任何问题能够顺利处理周期性资产的使用。因此现在的实现已经能够很好地处理这些需求确保一切正常运行。 我们差不多完成了 今天的基本完成了但还剩下半小时的时间。接下来想要处理一些遗留的问题。一个问题是目前系统没有正确地处理位移导致一些效果比如阴影显示不正常。原因是在代码中位移数据被硬编码了但是我们没有真正地回溯这些位移数据。 我打算先看看标准位移的值看是否可以统一使用一个固定值。通过检查发现对于所有对象位移值似乎都是一致的具体数值是 72 和 182适用于所有的对象。因此我想先快速验证一下看看是否可以为所有对象使用相同的位移值。 我计划先在代码中做一个临时的修改看看效果如何。为了调试我将检查加载位图的部分确认一下是否有任何问题。 game_asset.cpp添加 *FileName[] 以便遍历位图并设置 TopDownAlign 为了处理位移问题我计划通过以下方式进行调试。首先我将所有的文件名放入一个数组中然后使用一个循环遍历每个文件名。接下来我将调用 DebugLoadBMP 函数加载每个位图。 在这个过程中我决定通过修改代码来测试加载的效果。首先创建一个 FileName 数组然后将所有相关的文件名添加到该数组中。接着使用一个简单的方式加载位图数据。为了确保一切正常我还会对加载后的数据进行一些调试确保按预期进行处理。 通过使用 TopDownAlign 来调整这些位图我能够对这些位图进行检查确保它们符合需求正确加载并且显示。最终这个操作只是一个调试步骤用来确保没有其他问题干扰确保数据处理准确无误。 调试器查看对齐方式 尝试让调试器以正确的方式显示数据并逐步获取正确的位图数据。这次数据看起来正常了显示为 0.5 和 1.56并且这些值是一致的没有发现任何异常。 接下来我需要做的就是整理这些数据并返回正确的值确保它们可以用于接下来的处理。至此调试过程中的问题已经得到了解决位图数据也加载成功了。 game_asset.cpp将计算出的对齐方式烘焙到英雄位图中 为了确保数据正确现在需要创建一个 V2 的变量这个变量用于表示“英雄对齐”HeroAlign。这个英雄对齐的值已经通过之前的调试读取出来分别是 0.5 和 0.156 等。 接下来每次执行添加位图资产AddBitmapAsset时都可以指定这个对齐值alignment value。这意味着只要设置了这个值就能确保位图的正确对齐方式。 至此这部分的工作就完成了。 运行游戏并检查正确的对齐方式 现在所有的资产都已经正确对齐系统也按照需求运行了。对此我感到满意。虽然目前不确定是否已经完全完成所有工作但至少目前的进展是令人满意的资产系统已经达到了预期目标。 开始讨论资产文件格式 目前所有的资产匹配工作已经完成系统运行得也很平稳感觉一切都在预期之内。因此可能是时候开始考虑资产文件格式了。虽然这可能有些早但从当前的进展来看已经有了合理的基础可以开始讨论资产文件的格式和它的工作方式。我觉得我们不需要在资产文件格式中使用描述符而是希望所有的描述信息都来自代码那一侧。因此感觉现在的状态已经接近完成所有的工作都顺利进行应该可以进入下一阶段了。 game.h向资产流式传输 TODO 中添加两项并优先处理音频 目前资产流式加载系统已经基本完成剩下的工作就是对文件格式的设计。为了完成这部分首先需要确保能够从磁盘加载资产并进行内存管理避免数据无序地加载。接下来需要检查是否还有其他方面需要优化或改进。如果以后需要进行优化那时再处理即可因此现在可以将资产流式加载部分标记为完成。 考虑到接下来要进行文件格式的处理可能需要在这之前先处理音频加载部分。如果没有音频加载功能的支持资产加载系统就无法完全运作因此音频部分是必须解决的问题。接下来的20分钟里可以先完成音频加载的实现确保音频功能能正常工作然后再着手文件格式的设计以确保文件格式能够同时支持音频和视频内容。 game_asset.cpp引入 LoadSound 当前的任务是为音频资源的加载系统做准备。之前已经为音效准备好了资产槽和标签但目前还没有实现加载音频的功能。为了完成这个目标需要实现一个与加载位图类似的音频加载系统。换句话说需要创建一个加载音频的流程功能上与加载位图非常相似。 首先可以借鉴LoadBitmap的概念创建一个LoadSound的功能。这个功能将负责加载音频资源具体来说当音频文件的ID被传入时加载任务会开始然后执行实际的音频加载操作。这个过程会涉及到类似于位图的工作但操作的对象会是音频文件。 为了实现这个目标需要实现以下步骤 音频信息结构需要定义一个类似于位图的音频信息结构其中包括音频的文件名、样本数等数据。加载音频文件创建一个类似DebugLoadBitmap的函数DebugLoadWAV用于加载音频文件。这将确保音频文件能够被正确加载到内存中并提供音频所需的信息。音频ID和槽管理为音频资源分配ID并将其加载到适当的资产槽中这样就能够方便地访问和管理音频资源。 同时创建一个LoadedSound结构体这个结构将存储加载的音频信息例如样本数和音频文件的内存数据。这个结构与位图的LoadedBitmap结构非常相似主要的区别在于它是针对音频数据的。 在功能上音频的加载与位图加载非常相似因此可以考虑将这些功能进行整合减少冗余代码。如果这两个过程在实现过程中越来越相似最终可能会将它们合并为一个通用的加载函数这样可以减少代码量使系统更加简洁高效。 目前还没有实现具体的LoadedSound结构体但可以先假设它的存在并着手开发音频加载的相关功能之后再根据需要进一步完善音频结构体的实现。总的来说音频加载系统的基础功能框架已经初步构建接下来的工作是实现具体的音频加载和管理逻辑。 引入 DEBUGLoadWAV 当前的任务是实现DEBUGLoadWAV函数该函数用于加载WAV格式的音频文件并将其数据解析并存储到适当的结构中以便后续的音频处理。这个过程与DebugLoadBitmap类似都是读取文件并解析内容但WAV文件的解析稍微复杂一些。 实现步骤 读取整个文件 使用DEBUGReadEntireFile函数将WAV文件的全部内容读取到内存中。检查读取是否成功如果失败则终止加载。 解析WAV文件头部信息 WAV文件的格式比BMP文件稍复杂但仍然是标准的RIFF格式。解析WAV文件的RIFF头部确认文件类型是否正确应包含RIFF标识和WAVE格式标签。解析fmt子块提取音频格式信息采样率、通道数、位深度等。解析data子块找到实际的音频数据部分并记录其大小和位置。 存储解析结果 提取出音频的关键信息如 采样率Sample Rate通道数Channels采样深度Bit Depth总样本数Sample Count音频数据指针Data Pointer 创建LoadSound结构体将这些数据存入其中以便后续音频播放或处理。 返回加载结果 确保所有数据正确解析并返回LoadSound结构的指针使其可以用于后续的音频处理流程。 额外优化 由于WAV格式支持不同的编码方式如PCM、ADPCM等当前可以先实现最常见的PCM线性脉冲编码调制格式解析。可以考虑与位图加载流程进行结构化对比以便未来优化代码复用例如抽取通用的“加载资源”方法减少重复代码。 下一步 继续完善DEBUGLoadWAV函数的实现并进行基本的测试确保能够正确解析WAV文件并提取音频数据。检查是否需要调整LoadSound结构的设计以适应不同格式的音频资源管理。 网络展示 WAVE 规格 WAV 文件的格式基于 RIFF资源交换文件格式它由多个数据块Chunk组成每个数据块包含不同的信息如文件头、音频格式和音频数据。 WAV 文件解析流程 读取 RIFF 头部 WAV 文件以 RIFF 作为文件头标识4 字节。之后是文件大小信息4 字节用于指示整个文件的大小。紧接着是 WAVE 标识4 字节表明该文件是 WAV 格式。 解析 fmt 块音频格式信息 fmt 块子块 ID 为 fmt 包含音频数据的格式信息 音频编码格式Audio Format2 字节常见值 1 代表 PCM未压缩的脉冲编码调制其他值可能代表 ADPCM 或其他压缩格式 通道数Number of Channels2 字节如 1 表示单声道2 表示立体声 采样率Sample Rate4 字节如 44100 Hz 表示 44.1kHz。字节率Byte Rate4 字节用于计算数据流的速率。块对齐Block Align2 字节用于存储每个采样块的大小。位深度Bits per Sample2 字节常见值 88 位 PCM1616 位 PCM 解析 data 块音频数据 data 块子块 ID 为 data包含音频的原始 PCM 数据 数据大小Data Size4 字节表示音频数据的总字节数。音频数据Data实际的 PCM 采样值格式取决于 fmt 块中定义的 Bits per Sample。 加载 WAV 文件的实现思路 读取整个文件并确认 RIFF 头是否正确 解析前 12 个字节检查是否以 RIFF 开头是否包含 WAVE 标识。 查找 fmt 块并解析音频格式信息 提取音频格式、通道数、采样率、位深度等信息。 查找 data 块并读取音频数据 提取数据大小并存储音频 PCM 数据。 将解析的音频数据存入 loaded sound 结构 存储采样率、通道数、样本数及数据指针以便后续音频播放。 后续优化 目前仅解析 PCM 格式的 WAV 文件可后续扩展支持 ADPCM 等其他编码格式。结合已有的 bitmap 资源管理方式优化代码结构实现更通用的资源加载机制。 https://www.mmsp.ece.mcgill.ca/Documents/AudioFormats/WAVE/WAVE.html 黑板“IFF” 文件格式 块状文件格式Chunked File Format 是一种层次化数据编码方式广泛用于早期计算机文件格式中。例如IFFInterchange File Format 由 Electronic Arts 在 Amiga 计算机 上引入是最早采用此方法的格式之一。 块状文件格式的基本结构 数据按块Chunk存储 每个块都有一个 ID通常是 4 个 ASCII 字符。之后是 大小字段表示该块的数据长度。紧随其后的是实际的 数据内容。 块的解析方式 读取 ID 确定块的类型。读取 大小字段确定数据长度。如果程序支持该块类型则解析其数据否则跳过该块。部分块可以包含 子块Sub-chunk形成层次结构。 WAV 文件的块结构 WAV 文件采用 RIFFResource Interchange File Format其结构与 IFF 类似 RIFF 块主块 包含 WAVE 标识内部包含多个子块 fmt 块存储音频格式data 块存储 PCM 音频数据其他可选块如 LIST、fact 等 解析 WAV 文件的流程 读取 RIFF 头部确认文件类型是否为 WAVE。遍历文件中的块 识别 fmt 块提取音频格式信息采样率、通道数、位深度等。识别 data 块读取 PCM 数据。遇到未知块则跳过确保兼容扩展格式。 优缺点分析 优点 结构清晰可扩展可添加新块类型而不影响旧软件。易于解析支持跳过未知数据块。适用于存储层次化数据。 缺点 额外的 ID 和 大小字段 增加了文件体积。解析逻辑较复杂需处理不同块类型。现代格式如 JSON、Protocol Buffers提供更高效的替代方案。 总结 块状文件格式是一种早期的数据存储方法在 WAV、AVI、3DS 等格式中广泛应用。尽管 结构灵活但在现代开发中通常使用 更紧凑、高效 的数据格式来代替。 game_asset.cpp引入 WAVE_header 在解析 WAV 文件时我们主要关注 文件头Header 和 数据块Chunk 的基本结构。由于这是调试加载器Debug Loader我们不需要支持所有 WAV 格式只需解析出基本的 PCM 音频数据以便后续处理资产。 WAV 文件基本结构 WAV 文件使用 RIFFResource Interchange File Format 作为容器格式其结构包括多个 块Chunk RIFF 头部文件标识fmt 块音频格式data 块PCM 数据其他可选块如 LIST, fact 等 解析 WAV 文件的初始步骤 1. 读取 WAV 头部 WAV 文件的前 12 字节 定义为 RIFF 头部 4 字节RIFFASCII 编码4 字节整个文件的大小不包括前 8 字节4 字节WAVEASCII 编码 2. 读取 fmt 块音频格式信息 4 字节块 ID通常为 fmt 包括空格4 字节块大小通常为 16表示 PCM 格式2 字节音频编码格式1 表示 PCM2 字节通道数1 单声道2 立体声4 字节采样率如 44100 Hz4 字节字节率 采样率 × 通道数 × 每个样本的字节数2 字节块对齐 通道数 × 每个样本的字节数2 字节每个样本的位数如 16 表示 16 位 PCM 3. 读取 data 块PCM 音频数据 4 字节块 ID通常为 data4 字节数据大小接下来的字节音频 PCM 数据 代码解析 WAV 头部 我们可以用 C 语言的 结构体struct 来定义 WAV 文件头 typedef struct {uint32_t riff_id; // RIFFuint32_t file_size; // 文件总大小 - 8 字节uint32_t wave_id; // WAVE } WaveHeader;然后是 fmt 块 typedef struct {uint32_t fmt_id; // fmt uint32_t fmt_size; // 块大小uint16_t audio_format; // 编码格式1 PCMuint16_t num_channels; // 通道数1 单声道2 立体声uint32_t sample_rate; // 采样率uint32_t byte_rate; // 字节率uint16_t block_align; // 块对齐uint16_t bits_per_sample; // 采样位数 } FmtChunk;最后是 data 块 typedef struct {uint32_t data_id; // datauint32_t data_size; // PCM 数据大小 } DataChunk;调试加载 WAV 文件 在调试加载器中我们可以按照以下步骤解析 WAV 文件 读取 WaveHeader确保是 RIFF 和 WAVE 文件。查找 fmt 块解析音频格式信息。查找 data 块提取 PCM 数据。如果遇到未知块使用 chunk_size 跳过该块。将音频数据存入 LoadedSound 结构体供后续播放。 总结 WAV 文件采用 块状结构解析时按 ID 大小 数据 方式读取。只需解析 “RIFF”, “WAVE”, fmt , “data” 块即可提取 PCM 数据。解析时可跳过 未知块确保兼容不同 WAV 变种格式。由于本次目标是 调试加载器不需要支持所有 WAV 格式只需确保能加载调试所需的 WAV 资源。 引入 WAVE_fmt 在解析 WAV 文件时fmt 块是关键部分之一它存储了音频格式信息。我们需要解析其中的多个字段以确保能够正确读取 PCM 数据。以下是详细解析步骤 解析 fmt 块Format Chunk fmt 块用于定义音频数据的格式包括采样率、通道数、比特深度等。其基本结构如下 偏移量大小 (字节)字段名称说明04fmt (块 ID)该块的标识符固定为 fmt 44chunk_size该块的大小不包括前 8 字节82wFormatTag音频格式1 表示 PCM102nChannels声道数1 单声道2 立体声124nSamplesPerSec采样率Hz164nAvgBytesPerSec平均字节率 采样率 × 通道数 × 每样本字节数202nBlockAlign块对齐大小 通道数 × 每样本字节数222wBitsPerSample每个样本的比特数如 16 表示 16 位 PCM242cbSize可选扩展数据的大小仅对非 PCM 格式有效26可变扩展数据例如 dwChannelMask 和 SubFormat GUID 字段解析 wFormatTag音频格式 该字段决定了 WAV 文件的编码方式 1 PCM标准无压缩格式最常见其他值如 3 IEEE 浮点格式、6 A-law、7 μ-law不作处理 由于我们只支持 PCM因此遇到 wFormatTag ! 1 的 WAV 文件可以直接忽略。 nChannels通道数 1 表示单声道2 表示立体声其他通道数如 5.1、7.1不在调试加载器的支持范围内。 nSamplesPerSec采样率 例如 44100 HzCD 音质48000 Hz专业音频96000 Hz高分辨率音频 nAvgBytesPerSec字节率 计算方式nAvgBytesPerSec nSamplesPerSec * nChannels * (wBitsPerSample / 8)该字段可以用来验证数据完整性但不直接影响 PCM 解析。 nBlockAlign块对齐 计算方式nBlockAlign nChannels * (wBitsPerSample / 8)该字段决定了每个采样帧的大小例如 16-bit 立体声: nBlockAlign 2 × (16 / 8) 48-bit 单声道: nBlockAlign 1 × (8 / 8) 1 解析 PCM 数据时每次读取 nBlockAlign 个字节即可得到完整的采样帧。 wBitsPerSample采样位数 常见值 8 每个样本 8 位无符号16 每个样本 16 位有符号24 或 32 高精度音频 仅支持 16 位 PCM因为它是最广泛使用的格式。 cbSize扩展数据大小可选 仅当 wFormatTag 不是 1 时才存在如 cbSize 22 可能用于 IEEE 浮点格式。由于我们只支持 PCM因此可以忽略该字段。 dwChannelMask通道掩码可选 该字段用于多通道音频如 5.1 或 7.1 声道但调试加载器无需解析。 SubFormat GUID可选 该字段用于非 PCM 格式如 WAVE_FORMAT_EXTENSIBLE但对于 PCM我们可以直接跳过。 WAV 解析结构体 我们可以用 C 语言定义 fmt 块的数据结构 typedef struct {uint32_t fmt_id; // fmt uint32_t fmt_size; // fmt 块大小uint16_t wFormatTag; // 音频格式1 PCMuint16_t nChannels; // 通道数uint32_t nSamplesPerSec; // 采样率Hzuint32_t nAvgBytesPerSec;// 字节率uint16_t nBlockAlign; // 块对齐uint16_t wBitsPerSample; // 采样位数// 如果需要支持 WAVE_FORMAT_EXTENSIBLE可在此扩展结构体 } FmtChunk;解析 WAV 文件的 fmt 块 在调试加载 WAV 文件时我们按照以下步骤解析 fmt 块 读取 fmt 头部前 8 字节确保 ID 为 fmt 。读取 fmt_size确定该块的大小。解析 PCM 相关字段如 nChannels、nSamplesPerSec、wBitsPerSample。若 wFormatTag ! 1则跳过该块不解析。跳过可能的扩展字段直到找到 data 块。 总结 fmt 块是 WAV 文件解析的核心部分决定了音频数据格式。只支持 PCMwFormatTag 1忽略 cbSize 及扩展字段。关键字段包括 nChannels通道数、nSamplesPerSec采样率、wBitsPerSample采样位数。解析时需检查 nBlockAlign 和 nAvgBytesPerSec确保数据正确性。如果遇到非 PCM 格式或不支持的位深度直接跳过该文件。 接下来我们可以继续解析 data 块以获取实际的 PCM 音频数据。 引入 WAVE_chunk 在解析 WAV 文件时我们还需要处理 WAV 文件中的其他数据块chunk。WAV 文件采用 分块chunked格式其中每个数据块都包含 块 ID 和 块大小。我们需要解析这些数据块以正确地读取 WAV 文件的结构。 WAV 文件中的通用块格式 WAV 文件的结构基于 RIFFResource Interchange File Format每个块的基本格式如下 偏移量大小 (字节)字段名称说明04ChunkID数据块的 ID例如 fmt 、data 等44ChunkSize该块的数据大小不包括 ChunkID 和 ChunkSize8ChunkSize数据该块的具体内容 WAV 文件主要包含的块 一个标准的 WAV 文件通常包括以下几个关键块 1. RIFF 头部 ChunkIDRIFF4 字节ChunkSize文件的总大小4 字节FormatWAVE4 字节 该部分定义了整个文件的类型WAV 文件必须以 RIFF 开头并且其格式必须是 WAVE。 2. fmt 块格式块 ChunkIDfmt 4 字节ChunkSize格式块大小通常为 16 或 18 字节PCM 格式时为 16数据内容 wFormatTag音频格式1 PCMnChannels通道数nSamplesPerSec采样率nAvgBytesPerSec平均字节率nBlockAlign块对齐大小wBitsPerSample每个样本的位数 3. data 块音频数据块 ChunkIDdata4 字节ChunkSize音频数据的大小4 字节数据内容实际的 PCM 音频数据 这是 WAV 文件中最重要的数据块它包含了音频的 PCM 采样数据。我们需要找到 data 块并解析其中的音频数据。 解析 WAV 文件的通用方法 为了正确解析 WAV 文件我们需要按照以下步骤处理数据块 读取文件头部 确保 ChunkID 是 RIFF。读取 ChunkSize可忽略。确保 Format 是 WAVE。 遍历文件中的数据块 读取 ChunkID 和 ChunkSize。根据 ChunkID 进行不同的解析 如果 ChunkID 是 fmt 则解析格式信息。如果 ChunkID 是 data则读取音频数据。如果 ChunkID 是其他未知值则跳过该块通过 ChunkSize 跳过相应字节。 读取 data 块的数据 解析 PCM 采样数据支持 8 位或 16 位 PCM。 示例代码 我们可以用 C 语言实现 WAV 解析的基本逻辑 typedef struct {uint32_t ChunkID; // RIFFuint32_t ChunkSize; // 文件总大小uint32_t Format; // WAVE } RIFFHeader;typedef struct {uint32_t ChunkID; // fmt uint32_t ChunkSize; // 块大小uint16_t wFormatTag;uint16_t nChannels;uint32_t nSamplesPerSec;uint32_t nAvgBytesPerSec;uint16_t nBlockAlign;uint16_t wBitsPerSample; } FmtChunk;typedef struct {uint32_t ChunkID; // datauint32_t ChunkSize; // 音频数据大小 } DataChunk;然后我们遍历 WAV 文件的块 FILE *file fopen(example.wav, rb); RIFFHeader riff; fread(riff, sizeof(RIFFHeader), 1, file);// 确保是 WAV 文件 if (riff.ChunkID ! 0x46464952 || riff.Format ! 0x45564157) {printf(错误文件不是 WAV 格式\n);fclose(file);return; }// 遍历数据块 while (!feof(file)) {uint32_t chunkID;uint32_t chunkSize;fread(chunkID, sizeof(uint32_t), 1, file);fread(chunkSize, sizeof(uint32_t), 1, file);if (chunkID 0x20746D66) { // fmt FmtChunk fmt;fread(fmt, sizeof(FmtChunk), 1, file);printf(音频格式: %d, 采样率: %d Hz, 通道数: %d\n,fmt.wFormatTag, fmt.nSamplesPerSec, fmt.nChannels);} else if (chunkID 0x61746164) { // dataprintf(找到数据块大小: %d 字节\n, chunkSize);break; // 读取音频数据} else {fseek(file, chunkSize, SEEK_CUR); // 跳过未知块} }fclose(file);总结 WAV 文件由多个块组成每个块都有 ChunkID 和 ChunkSize。关键块包括 RIFF 头部、fmt 格式块、data 音频数据块。解析 WAV 文件时我们需要遍历所有块并根据 ChunkID 进行不同的处理 fmt 块存储音频格式信息采样率、位深、通道数。data 块存储 PCM 音频数据。未知块跳过处理。 只支持 PCM (wFormatTag 1)遇到其他格式可以忽略。 这样我们就可以正确解析 WAV 文件并提取其中的 PCM 音频数据 #define RIFF_CODE 在解析 WAV 文件时我们需要能够识别文件中的不同数据块chunk而这些数据块是通过 4 字节的 ID 进行标识的例如 fmt 格式块、WAVE数据块和 RIFF文件头。由于 C 语言不允许直接用字符串字面量作为 uint32_t 类型的值因此我们需要一种方法来将 4 个字符转换成一个 32 位整数以便进行高效的比对。 目标将 4 字节字符转换为 32 位整数 为了便于 WAV 解析我们希望能够定义这些块 ID例如 enum {WAVE_ChunkID_fmt RIFF_CODE(f, m, t, ),WAVE_ChunkID_RIFF RIFF_CODE(R, I, F, F),WAVE_ChunkID_WAVE RIFF_CODE(W, A, V, E), };然而C 语言并不支持直接写 fmt 这样的多字符字面量并让它变成 uint32_t 类型因此我们需要定义一个 宏 来自动转换字符串。 实现思路 由于 WAV 文件使用 小端字节序Little Endian 存储数据我们需要确保字符的存储顺序正确。例如 RIFF 在内存中的存储可能是 0x46464952即 R I F F。fmt 在内存中的存储可能是 0x20746D66即 f m t 。 为了确保正确的字节顺序我们可以定义一个 宏 来将 4 个字符转换为 uint32_t 值确保它们按 小端字节序 排列。 宏实现 我们定义一个宏 RIFF_CODE()用于将 4 个字符转换为 32 位整数 #define RIFF_CODE(a, b, c, d) \((uint32_t)(a) | ((uint32_t)(b) 8) | ((uint32_t)(c) 16) | ((uint32_t)(d) 24))这个宏的工作原理如下 a 是最低字节最右边不需要位移。b 左移 8 位占据第二个字节。c 左移 16 位占据第三个字节。d 左移 24 位占据最高字节。 使用示例 通过这个宏我们可以定义 WAV 解析所需的块 ID const uint32_t WAVE_CHUNK_ID_FMT RIFF_CODE(f, m, t, ); const uint32_t WAVE_CHUNK_ID_RIFF RIFF_CODE(R, I, F, F); const uint32_t WAVE_CHUNK_ID_WAVE RIFF_CODE(W, A, V, E);这样我们就可以用这些值与 WAV 文件中的 ChunkID 进行比对确保正确解析数据。 如何验证字节顺序 由于 小端存储 可能导致字符顺序错误我们可以通过读取实际 WAV 文件并打印 ChunkID 来验证 uint32_t chunk_id; fread(chunk_id, sizeof(uint32_t), 1, file); printf(Chunk ID: 0x%X\n, chunk_id);如果打印出的 Chunk ID 和 RIFF_CODE() 计算出的值不匹配则可能需要调整 字节顺序例如更改 RIFF_CODE() 中的移位顺序。 总结 WAV 文件使用 4 字节的 ChunkID 标识数据块例如 fmt 、data 和 RIFF。由于 C 语言不支持直接使用字符串字面量作为 uint32_t 值我们定义了 RIFF_CODE() 宏用来将 4 个字符转换成 32 位整数。RIFF_CODE() 确保字符按小端字节序排列符合 WAV 文件格式要求。通过 RIFF_CODE() 生成的 ChunkID 可以用于比对文件中的数据块确保 WAV 解析正确。 这使得 WAV 解析代码更加清晰易读并且方便扩展其他块类型的处理 解析 WAVE_header 的 ID 在解析 WAV 文件时我们首先需要解析 WAV 头部Wave Header。我们期望 WAV 头部包含 RIFF 块并且 RIFF 块的 ID 字段应包含 RIFF同时 WAVE ID 也应该存在。如果这两个条件都满足那么文件的基本结构就是符合预期的我们可以继续解析其中的具体数据块chunks。 Interchange(立体交叉道, 互换 vt. 交换, 互换 vi. 交替发生) 解析 WAV 头部 WAV 头部的主要结构 RIFF 块Resource Interchange File Format 4 字节的 Chunk ID必须是 RIFF。4 字节的 文件大小。4 字节的 格式必须是 WAVE。 只有在 Chunk ID 是 RIFF 且 Format 是 WAVE 时我们才会继续解析文件。 数据结构示例 typedef struct {uint32_t ChunkID; // 必须是 RIFFuint32_t ChunkSize; // 整个文件大小 - 8uint32_t Format; // 必须是 WAVE } WaveHeader;使用断言assert验证 WAV 文件 由于这只是用于调试的 WAV 解析器而不是最终的资产加载器因此我们可以使用 assert 来验证 WAV 文件是否符合基本格式 WaveHeader* header (WaveHeader*)fileData;// 断言检查是否是有效的 WAV 头部Assert(Header-RIFFID WAVE_ChunkID_RIFF);Assert(Header-WAVEID WAVE_ChunkID_WAVE);这里使用 RIFF_CODE() 宏之前定义过将 4 字节字符串转换为 uint32_t确保 ChunkID 和 Format 是 RIFF 和 WAVE否则程序会在调试阶段崩溃提醒开发者该文件格式错误。 到这里稍微展望一下未来 目前正在进行 WAV 文件加载的编写预计明天能够实现完整的 WAV 文件解析。这不仅有助于完成资产加载的最后阶段同时也能推进音频部分的开发。这样一来整体的开发任务会减少使进度更加顺利。 开发目标 计划在第 200 天左右开始编写正式的游戏逻辑代码因此希望在此之前完成所有核心引擎工作。目前正在清理待办事项希望尽快完成所有和游戏无关的引擎开发工作使后续能够专注于游戏代码的编写。 当前进度 渲染部分已经基本完成但仍有两个主要任务需要解决 调试工具Debug Code这部分相对简单应该不会花费太多时间。字体渲染Fonts这需要较多的工作量仍然是一个待办事项。 WAV 文件解析即将完成 目前已经建立了对 RIFF 结构的解析框架。计划明天完成具体的数据加载以便 WAV 文件能够被正确解析和使用。这一部分完成后音频子系统的主要功能也将基本完善。 后续规划 继续推进 资产加载和音频系统确保它们可以稳定运行。完成调试工具和字体渲染进一步减少待办事项。优化代码减少引擎层面的开发工作以便在第 200 天左右切换到游戏逻辑的开发。 目前整体进度良好正在有条不紊地完成各项核心引擎任务为正式的游戏开发做最后的准备。 对于获取角色精灵能不能只做以下操作 int sprite_to_load (angle (180 / sprites)) / (360 / sprites) % sprites 当前讨论的是角色精灵sprite的加载和角度映射问题。有人提出了一种计算方式 int sprite_to_load (angle 180) / (sprites / 360) % sprites;但这种方式存在多个问题不能直接适用于当前的资产系统。 主要问题 缺乏角度分布的信息 当前的资产系统并没有存储精灵在特定角度上的数量信息。角度的分布可能并不均匀例如某些角度的精灵较多而另一些角度的精灵较少。例如一个 Boss 角色 可能大部分时间是面向前方的因此前方视角的精灵较多而背后视角的精灵较少。 现有系统无需量化Quantization 当前的实现方式已经能够正确处理不同角度的精灵加载而不需要进行额外的量化计算。直接量化角度可能会导致问题例如 某些角度下根本没有可用的精灵导致错误的映射或加载失败。 结论 直接使用这种计算方式不可行原因是它假设了 精灵角度均匀分布但实际情况可能并非如此。现有系统已经能够正确加载精灵并适应 不均匀的角度分布因此不需要进行额外的量化计算。 我有一个关于音频资产结构的联合问题。它需要 SoundLoopable或者 LoopStart / LoopEnd 吗(LoopEnd -1 表示一次性播放的声音) 关于音频资产结构体的问题是否需要添加如 循环起始点、循环结束点 以及将 循环结束点设置为 -1 以表示单次播放的声音目前还不确定。虽然这种功能可能会需要但由于音频系统还没有完全构建好因此目前还不清楚具体需求。 大概的做法是先开发混音器mixer然后根据混音器的需求回过头来调整音频资产系统加入所需的功能和字段。 实现其他音频格式如 MP3 的计划 关于实现其他音频格式如 MP3无法实现因为 MP3 格式有专利受到法律保护不允许实现。即使在 2016 年之后专利可能会过期但在当前仍然不允许实施 MP3 解码。美国的专利系统特别复杂和限制尤其是软件专利给开发带来很多麻烦。 因此虽然理论上可以讲解如何实现 MP3 解码但实际的代码实现是违法的。如果源代码被发布并包含 MP3 播放功能那将是违法的行为。虽然通过直播或说明可能不违法但还是不鼓励这样做。对于其他格式如 FLAC虽然可以用于压缩但由于其压缩率较低通常不到两倍对空间的节省效果并不显著使用起来的意义不大。对于真正需要压缩音频的场景OGG Vorbis 可能是一个更合理的选择但这类格式实现起来复杂且消耗的时间和资源较多因此不太可能在当前实现。 MP3 到底怎么被专利化的 MP3 格式受到了多个专利的保护可以在互联网上找到有关 MP3 专利的详细信息包括专利的持有者和专利过期的时间。根据这些资料MP3 的专利并非在全球范围内统一到期。在一些地区比如美国MP3 专利仍然有效而在其他地方可能早在 2012 年就已经过期。因此在某些地区可能是合法的来使用 MP3 格式的相关代码但在美国使用 MP3 解码或编码相关的技术仍然是违法的。 根据不同的专利信息有些专利可能在 2015 年或 2017 年才会过期具体取决于不同的专利和地区的法律规定。因此尽管在一些地区 MP3 可能不再受专利保护但在美国专利依然存在并限制相关技术的使用。 是的但为什么有人会专利文件扩展名呢 MP3 文件的专利并不是针对文件扩展名而是针对创建音频、以及编码和解码音频所使用的技术。因此仅仅解析 MP3 文件的内容就可能会违反这些专利因为专利保护的就是这些解析技术。虽然这种做法令人难以理解但遗憾的是现行的法律要求遵守这些专利因此在技术上我们不能解析 MP3 文件。 FLAC 是 WAV 的 50% 大小所以它对无损压缩非常有用 FLAC无损压缩并不会像很多人认为的那样将文件压缩到原始 WAV 文件的 50% 大小实际上最好的情况下压缩率大约是 60%。在许多情况下FLAC 的压缩效果要比这个更差甚至接近于无压缩。因此若只是为了节省一些存储空间使用 FLAC 并不值得因为它无法提供显著的节省。 假设一个游戏的总大小为 2GB其中音频占据 500MB如果通过 FLAC 压缩能够节省大约 25%的空间那么最终仅节省 100MB。相对于整个游戏文件大小这种节省是微不足道的。再加上为了实现这种压缩游戏代码将变得更加复杂这样的压缩就没有太大的意义。 如果真需要大幅压缩应该考虑使用像 OGG Vorbis 这样的格式它能够提供 8:1 或更高的压缩比这样的压缩效果才更有实际意义。因此如果目标是有效地减小音频文件的体积选择 FLAC 并不会带来太多好处反而可能增加不必要的复杂性。 https://xiph.org/flac/ https://z-issue.com/wp/flac-compression-level-comparison/ 所以这就是 RAD 为什么不专利他们的东西的原因吗 某些技术并未申请专利是因为认为这类技术的专利制度非常愚蠢因此选择不进行专利申请。
文章转载自:
http://www.morning.rkwlg.cn.gov.cn.rkwlg.cn
http://www.morning.pljxz.cn.gov.cn.pljxz.cn
http://www.morning.lfpzs.cn.gov.cn.lfpzs.cn
http://www.morning.fmry.cn.gov.cn.fmry.cn
http://www.morning.npqps.cn.gov.cn.npqps.cn
http://www.morning.ljbch.cn.gov.cn.ljbch.cn
http://www.morning.mxdiy.com.gov.cn.mxdiy.com
http://www.morning.jjhrj.cn.gov.cn.jjhrj.cn
http://www.morning.xnqjs.cn.gov.cn.xnqjs.cn
http://www.morning.mltsc.cn.gov.cn.mltsc.cn
http://www.morning.tdhxp.cn.gov.cn.tdhxp.cn
http://www.morning.cgtrz.cn.gov.cn.cgtrz.cn
http://www.morning.wbysj.cn.gov.cn.wbysj.cn
http://www.morning.rhsg.cn.gov.cn.rhsg.cn
http://www.morning.gbyng.cn.gov.cn.gbyng.cn
http://www.morning.wmfh.cn.gov.cn.wmfh.cn
http://www.morning.qnklx.cn.gov.cn.qnklx.cn
http://www.morning.lydtr.cn.gov.cn.lydtr.cn
http://www.morning.gdpai.com.cn.gov.cn.gdpai.com.cn
http://www.morning.zqsnj.cn.gov.cn.zqsnj.cn
http://www.morning.ywtbk.cn.gov.cn.ywtbk.cn
http://www.morning.krzrg.cn.gov.cn.krzrg.cn
http://www.morning.sfswj.cn.gov.cn.sfswj.cn
http://www.morning.dnbkz.cn.gov.cn.dnbkz.cn
http://www.morning.ffbp.cn.gov.cn.ffbp.cn
http://www.morning.qxltp.cn.gov.cn.qxltp.cn
http://www.morning.nxfwf.cn.gov.cn.nxfwf.cn
http://www.morning.pghfy.cn.gov.cn.pghfy.cn
http://www.morning.kdjtt.cn.gov.cn.kdjtt.cn
http://www.morning.psxfg.cn.gov.cn.psxfg.cn
http://www.morning.mbpfk.cn.gov.cn.mbpfk.cn
http://www.morning.nclps.cn.gov.cn.nclps.cn
http://www.morning.wcrcy.cn.gov.cn.wcrcy.cn
http://www.morning.jqrp.cn.gov.cn.jqrp.cn
http://www.morning.bpknt.cn.gov.cn.bpknt.cn
http://www.morning.jcypk.cn.gov.cn.jcypk.cn
http://www.morning.mwns.cn.gov.cn.mwns.cn
http://www.morning.wrfk.cn.gov.cn.wrfk.cn
http://www.morning.wkmrl.cn.gov.cn.wkmrl.cn
http://www.morning.sxwfx.cn.gov.cn.sxwfx.cn
http://www.morning.qgmbx.cn.gov.cn.qgmbx.cn
http://www.morning.qgtbx.cn.gov.cn.qgtbx.cn
http://www.morning.grzpc.cn.gov.cn.grzpc.cn
http://www.morning.znkls.cn.gov.cn.znkls.cn
http://www.morning.qshxh.cn.gov.cn.qshxh.cn
http://www.morning.nsrtvu.com.gov.cn.nsrtvu.com
http://www.morning.wckrl.cn.gov.cn.wckrl.cn
http://www.morning.jqkrt.cn.gov.cn.jqkrt.cn
http://www.morning.yrjxr.cn.gov.cn.yrjxr.cn
http://www.morning.wqmyh.cn.gov.cn.wqmyh.cn
http://www.morning.bmqls.cn.gov.cn.bmqls.cn
http://www.morning.qqhersx.com.gov.cn.qqhersx.com
http://www.morning.hhpkb.cn.gov.cn.hhpkb.cn
http://www.morning.smxrx.cn.gov.cn.smxrx.cn
http://www.morning.cywf.cn.gov.cn.cywf.cn
http://www.morning.gsdbg.cn.gov.cn.gsdbg.cn
http://www.morning.yzxhk.cn.gov.cn.yzxhk.cn
http://www.morning.homayy.com.gov.cn.homayy.com
http://www.morning.sfphz.cn.gov.cn.sfphz.cn
http://www.morning.tzkrh.cn.gov.cn.tzkrh.cn
http://www.morning.mkygc.cn.gov.cn.mkygc.cn
http://www.morning.ztqj.cn.gov.cn.ztqj.cn
http://www.morning.qsdnt.cn.gov.cn.qsdnt.cn
http://www.morning.hdrrk.cn.gov.cn.hdrrk.cn
http://www.morning.nqwkn.cn.gov.cn.nqwkn.cn
http://www.morning.xxzjb.cn.gov.cn.xxzjb.cn
http://www.morning.gryzk.cn.gov.cn.gryzk.cn
http://www.morning.fksrg.cn.gov.cn.fksrg.cn
http://www.morning.kphsp.cn.gov.cn.kphsp.cn
http://www.morning.rsmtx.cn.gov.cn.rsmtx.cn
http://www.morning.skmzm.cn.gov.cn.skmzm.cn
http://www.morning.fthqc.cn.gov.cn.fthqc.cn
http://www.morning.qfzjn.cn.gov.cn.qfzjn.cn
http://www.morning.jntdf.cn.gov.cn.jntdf.cn
http://www.morning.jqswf.cn.gov.cn.jqswf.cn
http://www.morning.rwjh.cn.gov.cn.rwjh.cn
http://www.morning.bkxnp.cn.gov.cn.bkxnp.cn
http://www.morning.jhwwr.cn.gov.cn.jhwwr.cn
http://www.morning.gbsfs.com.gov.cn.gbsfs.com
http://www.morning.nbhft.cn.gov.cn.nbhft.cn
http://www.tj-hxxt.cn/news/273782.html

相关文章:

  • 体育网站建设行业发展趋势
  • 红酒企业网站模板免费下载电子商务网站建设 下载
  • 太仓网站开发建设服务外贸快车官网
  • 网站更换主机注意济南网约车公司
  • 丹东做网站的重庆公司直招
  • 微网站 百度地图怎样组建企业网站
  • 兰州百度网站建设新网站建设哪家好
  • 做效果图的外包网站万峰科技.jsp网站开发四酷全书[m]
  • 做漫画网站wordpress 去掉图片链接
  • 潍坊网站制作案例app开发定制公司哪家好做
  • 宝塔怎么做两个网站crm系统营销
  • 百度云电脑版网站入口宁波seo推广优化公司
  • 重庆璧山网站制作公司电话淘宝客推广怎么做网站备案
  • 网站建设主要流程宁波做企业网站公司
  • 做网站要多钱wordpress的数据库在哪里设置
  • wordpress架设专题类网站宁德市房价
  • 网站建设的具体布局在国内可以做国外的网站吗
  • 网站型与商城型有什么区别吗网站建设的技术体会
  • 手机网站网站建设网站做多大的宽高
  • 上海城乡住房建设厅网站什么网站可以找人做软件下载
  • 单位网站建设框架网络营销出来可以干什么工作
  • 江苏中粟建设工程有限公司网站免费的企业名录搜索
  • 做网站公司室内设计网站参考
  • 微博内网站怎么做的燕莎网站建设
  • 网站申请域名网站模板英文
  • 房产网站的建设广州优质网站排名公司
  • 网站的主机地址百度竞价排名算法
  • 做网站自己有模板要花多少钱微营销 网站模板
  • 网站建设的整体设计流程多备份 wordpress
  • 建设手机版网站电子商务网站与建设课件