如何将频谱图矩阵转换为wav文件

How to convert a spectrogram matrix into wav file

有没有一种方法可以将表示灰度频谱图的矩阵(值非复数且介于 0 和 1 之间)(如下图所示)转换回声音文件,例如wav文件? 解释了如何使用 istft 函数对 seewave 频谱图进行处理。但是,就我而言,我发现有两个问题需要解决:

  1. 原始频谱图(由signal::specgram获得)丢失并且矩阵尺寸与原始频谱图不同(即频率和时间都被上/或下采样),而每行的精确频率和时间值并且每一列都是已知的
  2. 矩阵值介于 0 和 1 之间,并不像 istft
  3. 所要求的那样复杂

此外,原始谱图的维度、原始波对象的采样频率以及用于获得原始谱图的window长度和重叠是已知的。

谢谢!

音频只是一条随时间摆动的曲线,这种摆动反映了您的耳膜或麦克风拾音膜……这个信号在时域中,其中轴是 X 轴上的时间和 Y 轴上的曲线高度……典型的 CD优质音频每秒有 44,100 个样本,这意味着您每秒捕获此音频曲线上的点数......捕获的是音频曲线高度,而时间是隐含的,因为知道每个样本都是以已知采样率捕获的......所以样本速率是数字音频的两个关键音频属性之一……位深度是另一个属性……如果您投入两个字节(16 位)来记录 CD 质量曲线高度,您会得到 2 的 16 次方(2^ 16 == 65536 ) 不同的可能值来存储曲线高度

强调原始音频信号的关键在于时域(X 是时间 Y 是曲线高度)...当您将一组这些样本发送到 fft 调用时,数据会转换到频域(X 是频率 Y 是幅度 [能量])所以时间的直接维度已经消失但被融入到整个频域数据的概念中......在决定你输入的样本数量时需要权衡fft 调用(样本 window 大小)即增加频域信号的频率分辨率(降低 incr_freq )你需要更多的音频样本来输入 fft 调用但是为了获得时间特异性您需要尽可能少的样本的频率域,您可以通过获得较低的频率分辨率和较低的峰值频率(较低的奈奎斯特极限)来支付费用

要生成频谱图,您将这个曲线高度数组(时域)的 4096 个样本的内存缓冲区输入傅里叶变换(fft),这将 return 返回相同的数组(频域)数组元素的数量但是这次每个元素存储一个复数,您可以从中计算幅度(能级)和相位......数组元素零是可以忽略的直流偏置......每个数组元素代表一个不同的频率可以计算频率增量的地方

with sample_rate of 44100 samples per second, and one second worth of samples ( 44100 )
this gives you a frequency increment resolution of 1 hertz ... IE each freq bin is 1 Hertz apart

incr_freq := sample_rate / number_of_samples

nyquist_limit_index := int(number_of_samples / 2)

这是遍历数组的方法 complex_fft(在 go 而不是 r)

for index_fft, curr_complex := range complex_fft { // we really only use half this range + 1

    if index_fft <= nyquist_limit_index && curr_freq >= min_freq && curr_freq < max_freq {

        curr_real = real(curr_complex) // pluck out real portion of complex number
        curr_imag = imag(curr_complex) // ditto for imaginary portion

        curr_mag = 2.0 * math.Sqrt(curr_real*curr_real+curr_imag*curr_imag) / number_of_samples

        curr_theta = math.Atan2(curr_imag, curr_real)

        curr_dftt := discrete_fft{

            real:      2.0 * curr_real,
            imaginary: 2.0 * curr_imag,
            magnitude: curr_mag,
            theta:     curr_theta,
        }

随着时间的推移,您重复上述过程,将下一组 4096 个样本输入 fft api 调用,这样您就可以收集一组时域数组对及其相应的频域表示

创建您的图的过程已经完成了这个重复过程,这就是为什么时间显示为 X 轴的原因...在您的图上,每个垂直数据条代表单个 fft 调用的输出,其中其结果幅度显示为该垂直条的深色部分和图中较亮的点显示较低的能量频率......只有在生成该图的过程随时间推移之后,数据才可用于绘制下一个垂直条,因为该图从左到右进展因此时间轴穿过底部的 X 轴

另一个重要的见解是要注意您可以从音频(时域)开始...填充 window 个样本(例如 4096)并将此数组发送到 fft 调用中以获得新的每个频率的幅度和相位的数组(频率域)...这是纯粹的魔法,然后您可以在此频率域数组上执行傅里叶逆变换( ifft )以获得时域中的数组,该数组将匹配(到第一个大约)你的原始输入音频信号

因此,在您的情况下,在图上从左到右遍历您的数据,并且对于作为单频域阵列的每组垂直幅度值(由灰度表示)执行此傅里叶逆变换,这将为您提供原始音频信号(时域)仅适用于非常短的时间段(由 4096 音频样本或类似的定义)...此原始音频是 wav 文件的有效负载部分...对下一个垂直重复此过程列数据,直到您从左到右遍历整个图...将这一系列有效负载缓冲区拼接成一个 wav 文件