首页 > 解决方案 > Python librosa 错误“音频缓冲区不是 Fortran 连续的”

问题描述

我在用librosa

只是loadstft我遇到了错误Audio buffer is not Fortran-contiguous

我google了一下,发现我需要添加np.asfortranarray,所以我添加了这些句子但徒劳无功。

a, sr = librosa.load("mywave.wav",sr=self.sr,mono=False)

print(a.shape) #(2, 151199)

a[0] = np.asfortranarray(a[0])# try to avoide Fortran-contiguous
a[1] = np.asfortranarray(a[1])

# but this returns error
#Audio buffer is not Fortran-contiguous. Use numpy.asfortranarray to ensure Fortran contiguity.    

stft_L = librosa.stft(a[0], n_fft=self.stft_frame,hop_length= self.hop_frame, window='hann') 

我第一次编写这段代码时(可能是半年前),它奏效了。

有什么解决办法吗??

标签: pythonnumpyaudiolibrosa

解决方案


您误解了 C 与 Fortran 连续内存布局是什么,以及这意味着您可以做什么和不能做什么。例如,改变数组中一行的内存布局

a[0] = np.asfortranarray(a[0])

没有意义,因为内存布局决定了 line 是什么

为了说明这一点,让我们看一些 Fortran 连续数据

x = np.asfortranarray(np.arange(12).reshape(3, 4))
x.flags.f_contiguous
# True

x
# array([[ 0,  1,  2,  3],
#        [ 4,  5,  6,  7],
#        [ 8,  9, 10, 11]])

在内部,该 2D 数组当然是线性保存的,C-/Fortran-contigouity 决定是行还是列先出现:

x.flatten('A')
# array([ 0,  4,  8,  1,  5,  9,  2,  6, 10,  3,  7, 11])

np.asfortranarray(x).flatten('A')
# array([ 0,  4,  8,  1,  5,  9,  2,  6, 10,  3,  7, 11])

np.ascontiguousarray(x).flatten('A')
# array([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11])

Fortran 内存布局是列优先的,即列一起在内存中。C 内存是行优先的,即行在内存中保持在一起。

真正令人困惑的是,该数组中的视图可以是连续的,也可以不是:

x.flags.f_contiguous, x[0].flags.f_contiguous
# (True, False)

x显然是连续的,但x[0]不是。那是因为[0, 1, 2, 3]在内存中不是相邻的。

你试图做什么

a = x.copy('A')

a.flags.f_contiguous, a[0].flags.f_contiguous
# (True, False)

a[0] = np.asfortranarray(a[0])
a[1] = np.asfortranarray(a[1])

a.flags.f_contiguous, a[0].flags.f_contiguous
# (True, False)

将不起作用,因为更改单行的布局没有意义。

现在出现了令人困惑的部分:如果您有一个 Fortran 连续数组并且希望第一行是 Fortran 连续的,则不能将数组更改为 Fortran 连续:

a = x.copy('A')

a = np.asfortranarray(a)
a.flags.f_contiguous, a[0].flags.f_contiguous
# (True, False)

因为列是连续的,但不是行。

相反,如果您将数组更改为 C 连续

a = x.copy('A')

a = np.ascontiguousarray(a)
a.flags.f_contiguous, a[0].flags.f_contiguous
# (False, True)

这意味着行现在是连续的。

另一种解决方案是简单地复制数据

a = x.copy('A')

a[0].copy().flags.f_contiguous
# True

因为复制会将数据写入一个新的、线性的、连续的数组中。

那么最终的解决方案呢?

a, sr = librosa.load("mywave.wav")
stft_L = librosa.stft(a[0].copy())

但是 librosa最近也取消了对连续性的需求,所以这个问题应该会在未来慢慢消失。


推荐阅读