有效"缩放"或"调整"数字数组的算法(音频重采样)

Phr*_*ogz 17 ruby language-agnostic arrays algorithm audio

进行音频处理(虽然它也可以是图像处理)我有一个数字的一​​维数组.(它们恰好是代表音频样本的16位有符号整数,这个问题可以适用于不同大小的浮点数或整数.)

为了匹配不同频率的音频(例如,将44.1kHz样本与22kHz样本混合),我需要拉伸或压缩值数组以满足特定长度.

将数组减半很简单:丢弃其他每个样本.

[231, 8143, 16341, 2000, -9352, ...] => [231, 16341, -9352, ...]
Run Code Online (Sandbox Code Playgroud)

将数组宽度加倍稍微简单:将每个条目加倍(或者可选地在相邻的"实际"样本之间执行一些插值).

[231, 8143, 16341, 2000, -9352, ...] => [231, 4187, 8143, 12242, 16341, ...]
Run Code Online (Sandbox Code Playgroud)

我想要的是一种处理任何缩放因子的高效,简单的算法,并且(理想情况下)可选地支持在该过程中执行一种或另一种插值.

我的用例恰好是使用Ruby数组,但我很乐意在大多数语言或伪代码中获取答案.

Bra*_*ace 5

您正在寻找的阵列/矩阵数学功能通常可在"科学计算"库中找到. NArray可能是开始Ruby的好地方.


the*_*Man 3

这是我在下班时在几分钟内拼凑出来的东西,然后在晚饭后喝了一杯酒后重新创建:

sample = [231, 8143, 16341, 2000, -9352]
new_sample = []
sample.zip([] * sample.size).each_cons(2) do |a,b|
  a[1] = (a[0] + b[0]).to_f / 2 # <-- simple average could be replaced with something smarter
  new_sample << a
end
new_sample.flatten!
new_sample[-1] = new_sample[-2]
new_sample # => [231, 4187.0, 8143, 12242.0, 16341, 9170.5, 2000, 2000]
Run Code Online (Sandbox Code Playgroud)

我认为这是一个开始,但显然还没有完成,因为它-9352没有传播到最终的数组中。我没有费心将浮点数转换为整数;我想你知道该怎么做。:-)

我想找到一种更好的迭代方式each_cons。我宁愿使用 amap而不是each*,但这工作正常。

以下是循环迭代的内容:

asdf = sample.zip([] * sample.size).each_cons(2).to_a 
asdf # => [[[231, nil], [8143, nil]], [[8143, nil], [16341, nil]], [[16341, nil], [2000, nil]], [[2000, nil], [-9352, nil]]]
Run Code Online (Sandbox Code Playgroud)

each_cons很好,因为它遍历数组返回它的切片,这似乎是建立平均值的有用方法。

[0,1,2,3].each_cons(2).to_a # => [[0, 1], [1, 2], [2, 3]]
Run Code Online (Sandbox Code Playgroud)

编辑:

我更喜欢这个:

sample = [231, 8143, 16341, 2000, -9352]

samples = sample.zip([] * sample.size).each_cons(2).to_a 
new_sample = samples.map { |a,b|
  a[1] = (a[0] + b[0]).to_f / 2
  a
}.flatten
new_sample << sample[-1]
new_sample # => [231, 4187.0, 8143, 12242.0, 16341, 9170.5, 2000, -3676.0, -9352]
Run Code Online (Sandbox Code Playgroud)