将精确的音频位置存储为双精度秒是不是安全?

Posted

技术标签:

【中文标题】将精确的音频位置存储为双精度秒是不是安全?【英文标题】:Is it safe to store an exact audio position as seconds in a double?将精确的音频位置存储为双精度秒是否安全? 【发布时间】:2011-04-28 11:20:59 【问题描述】:

我需要将准确的音频位置存储在数据库中,即 SQLite。我可以将帧位置(样本偏移量/通道)存储为整数,但这会在某些文件转换的情况下导致额外的数据维护。

所以我正在考虑将位置存储为以秒为单位的 8 字节实际值,即双精度值,因此在 SQLite 中存储为 REAL。这使得数据库结构更加一致。

但是,给定 192kHz 的最大采样率,双精度是否足以在将值乘以采样率时始终恢复准确的帧位置?

是否存在某个可能发生错误的最大位置?这个最大位置是多少?

PS:这是关于 SQLite REAL 的,也是关于 C 和 Java 的 double 类型,它可能在不同阶段保存位置值。

更新:

由于现在讨论的重点是与转换和舍入相关的风险,因此这是我计划使用的 C 方法:

// Given these types:
int samplerate;
long long framepos;
double position;

// First compute the position in seconds from the framepos:
position = (double) framepos / samplerate;

// Now store the position in an SQLite REAL column, and retrieve it later

// Then compute the framepos back from position, with rounding:
framepos = position * samplerate + 0.5;

这样安全且对称吗?

【问题讨论】:

【参考方案1】:

双精度数为 51 位。根据指数部分,其中一些位将代表整数(在您的情况下为秒),其他位代表秒数。 在 48 KB 时,至少需要 16 位才能获得足够的亚秒精度(如果舍入不是最佳,则需要更多)。剩下 35 位的秒数,将跨越一千年。

因此,即使您在亚秒内需要一两个额外的位来防止舍入,即使 SQL 在将其转换为十进制并在这里和那里转换时丢失了一点或两位精度,您也不在任何地方附近您的双精度数会丢失样本精度。确保你的四舍五入工作正常 - C 倾向于在转换为整数时总是向下舍入,所以即使是一个非常小的转换错误也可能会让你失望 1。

【讨论】:

采样率为 192kHz,即 18 位。比每次转换都会丢失 1 位,因此至少下降 2 位(存储时 1 位,检索时 1 位)。但剩下的 31 位仍然留在百年范围内。 不是 53(52 + 1 隐含)位精度吗? 谢谢你们,这听起来很安全!并感谢您提到四舍五入,我会注意的。 IIUC,风险与转换比存储更相关。 就像 Ben 说的:一个 IEEE-754 double 有 53 位精度。 我刚刚添加到我的问题中的转换和舍入方法对您来说听起来不错吗?【参考方案2】:

我会将它存储为一个(64 位)整数,表示微秒(大约 2**20)。这避免了浮点硬件/软件,所有人都容易理解,并为您提供 0..2**44 秒的范围,即 5.5 万年多一点。

作为替代方案,使用可读的固定精度十进制表示(20 位就足够了)。右对齐,前导零。无论如何,与数据库访问相比,转换成本可以忽略不计。

这些选项的一个优点是任何数据库都可以很容易地知道如何对它们进行排序,对于浮点值来说并不一定很明显。

【讨论】:

嗯,使用这种方法,在执行 pos * samplerate / 10^6 时,您不需要留出大约 18 位空闲以避免整数溢出吗?或者你建议在这个操作中加倍吗? 嗯,是的,有了这个,你得到的 18 位(或更多)比我认为你会得到的范围内的 44 位少。然后,您最多只能计时 72 年左右。讨厌:-) 不,那只是 2 年 ;) 2^26 / 3600 / 24 / 365.25 = 2.1266 ;并带有一个有符号整数,即 1 年。这当然足够了。但我认为四舍五入也可能存在问题。纯整数舍入容易出错。在 IMO 各处使用双打更舒服。并且使用秒作为位置/持续时间是非常自然的。 @oliverg:我的计算出路了 :) 谢谢。但无论如何,您关于“纯整数舍入容易出错”的断言很难接受。固定精度舍入是可预测的,并且不依赖于舍入值的大小。浮点运算有很多很多的陷阱(一个是 NaN 结果),除非绝对必要并且准备好进行仔细的风险和错误分析,否则应该避免它。 也许是我写的关于整数舍入的太快了。但是,上面提到的 C 转换怎么可能失败呢? (请参阅我的问题中的更新)【参考方案3】:

正如 Matthias Wandel 的回答所解释的,可能没有什么可担心的。 OTOH 通过使用整数,您将获得固定的精度,而不考虑可能有用的大小。

比如说,使用一个 64 位整数,并将时间存储为微秒。这为您提供了 1 MHz 的等效采样精度和近 300000 年的范围(如果我的快速计算是正确的)。

编辑即使考虑到时间戳 * sample_rate 需要适合 64 位整数,您仍然有 1.5 年的范围(2**63/1e6/3600/ 24/365/192e3),假设最大采样率为 192kHz。

【讨论】:

请看我对史蒂夫回答的评论 @olivierg:好点;我已经相应地更新了我的答案。不过还是没什么好担心的。

以上是关于将精确的音频位置存储为双精度秒是不是安全?的主要内容,如果未能解决你的问题,请参考以下文章

请问js如何实现多个音频文件依次播放,而不是同时播放?如何实现播放制定位置,如音频3秒到10秒之间

网络音频 api 计时是不是比 setTimeout 更精确

在给定偏移量处将音频剪辑插入原始音频文件

从 x 到 y 秒播放音频

以科学记数法将小(1.0E-12)数字存储为双精度数

如何在 Flutter 中实现音频流应用和安全存储