假设我使用Python的soundfile读取一个WAV文件,
import soundfile
x, fs = soundfile.read("test.wav")数组x位于float32和max(x) = 1, min(x) = -1中。也就是说:x中的每个示例都是一个介于-1和1之间的float32数。我对它做了一些操作,得到了y。现在,我想将y保存到WAV文件中。假设y现在的值大于1(和/或小于-1),我使用
soundfile.write("processed.wav", y, fs)SoundFile如何处理超出的值?它是做剪裁(如果y[t] > 1是采用y[t] = 1)还是规范化(将整个信号除以max(abs(y)))还是其他什么?
我没有在文档中找到答案:https://pysoundfile.readthedocs.io/en/latest/#soundfile.write
import numpy as np
import soundfile as sf
x = np.array([0,0.5,0.75, 1, 2])
sf.write("x.wav", x, 1)
y, fs = sf.read("x.wav")
print(y)产出如下:
[0. 0.5 0.75 0.99996948 0.99996948]所以看起来确实有剪裁,但我想确定。我能控制soundfile.write处理超值的方式吗?
发布于 2021-09-30 11:03:49
这里要回答的重要问题不仅仅是声谱做了什么,而是如何确认这种行为。
让我们保持这个整洁的小示例程序,它有一些额外的注释是:
import numpy as np
import soundfile as sf
x = np.array([0,0.5,0.75, 1, 2]) # x.dtype is 'float64'
sf.write("x.wav", x, 1) # a wav at sampling rate 1 Hz
y, fs = sf.read("x.wav")
print(y)WAV可以在采样率和数据格式(或位深度)上有一些不同的味道。奇数行为的一个潜在因素是1Hz采样率。谢天谢地,在这种情况下,它没有影响,但这将是一个好主意,以避免潜在的问题产生奇怪的价值观。坚持一个标准的抽样率,直到你可以确定行为。
Soundfile的文档本身并不是不透明的,但是您确实需要对信息进行一点搜索。对于我们看到的write()方法
子类型(str,可选)-默认值参见default_subtype(),所有可能的值参见available_subtypes()。
然而,另一个重要的信息实际上在data字段下面。
数据类型没有选择写入文件的数据类型。音频数据将转换为给定的子类型。将int值写入浮点文件不会将值缩放到[-1.0,1.0]。如果将值
np.array([42], dtype='int32')写入subtype='FLOAT'文件,则该文件将包含np.array([42.], dtype='float32')。
基本上,数据类型不是由样本数据推断的,而是将缩放到subtype。
当我们查看default_subtype时,我们发现WAV的缺省值是16位PCM。
最棘手的一点是,当使用read读取信息时,声音文件会做些什么?
好的做法是用其他的东西来证实这种行为。如果第二种读取数据的方法报告了同样的信息,那么我们已经破解了。如果不是,那么这意味着至少有一个方法正在更改数据,因此您必须尝试第三个方法(以此类推)。
读取数据并确保数据未被更改的一个好方法是使用十六进制编辑器读取数据。
现在让我们提醒自己,我们来自soundfile.read()的输出是:
[0. 0.5 0.75 0.99996948 0.99996948]上面的十六进制示例创建了一个文件:
52494646 2E000000 57415645 666D7420 10000000 01000100 01000000 02000000 02001000 64617461 0A000000 00000040 0060FF7F FF7F我们知道它是16位样本,所以最后10个字节是我们感兴趣的(每个样本2字节,总共5个样本)。
16位是签名的,所以我们有一个±2^{15}的swing,即32768 (不要担心书呆子,我马上就到)
0000 0040 0060 FF7F FF7F啊,但那是小endian格式的。所以,让我们把它转过来,让它更容易看到。
0000 4000 6000 7FFF 7FFF每一个依次
0000是0,很好,很简单:[0.0]4000是16384,或32768 * 0.5:[0.5]6000是24576,或32768 * 0.75:[0.75]7FFF是32767,正好是可以描述的峰值正振幅。由于振幅被缩放到32767,这就是当读取数据时出现轻微错误的原因:32767 / 32768等于0.99996948 (有一点舍入误差)。
让我们通过翻转最后两个样本的负值来确认这种行为。
import numpy as np
import soundfile as sf
x = np.array([0,0.5,0.75, -1, -2]) # x.dtype is 'float64'
sf.write("x.wav", x, 1) # a wav at sampling rate 1 Hz
y, fs = sf.read("x.wav")
print(y)在大endian格式中,我们的十六进制数据现在是
0000 4000 6000 8000 80008000是-32768作为一个16位有符号整数.
由此,我们可以确认我们的数据正在被裁剪(而不是规范化或包装)。
https://stackoverflow.com/questions/69388531
复制相似问题