1

I am using librosa

Just load and stft, I hit the error Audio buffer is not Fortran-contiguous

I googled around and found I need to add np.asfortranarray,So I add these sentences but in vain.

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') 

At first time I made this code, (maybe half a year ago), it worked.

Is there any solution??

whitebear
  • 11,200
  • 24
  • 114
  • 237

1 Answers1

1

You are misunderstanding what C- vs Fortran-contiguous memory layout is, and what that means you can do and can't do. For example, changing the memory layout of a line in an array

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

makes no sense, as the memory layout dictates what a line is.

To illustrate that a little bit, lets have a look at some Fortran-contiguous data

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]])

Internally, that 2D array is of course saved linearly, and the C-/Fortran-contigouity dictates whether lines or columns come first:

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-memory layout is column-first, i.e. columns stay together in memory. C-memory is row-first, i.e. rows stay together in memory.

What can be really confusing is the fact that views in that array can be contiguous, or not:

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

x is obviously contiguous, but x[0] is not. That is because [0, 1, 2, 3] are not next to each other in memory.

What you tried to do

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)

will not work, because changing the layout of a single line makes no sense.

Now here comes the confusing part: If you have a Fortran-contiguous array and you want the first line to be Fortran-contiguous, you can't change the array to be Fortran-contiguous:

a = x.copy('A')

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

because columns are contiguous, but not rows.

If instead you change the array to be C-contigous

a = x.copy('A')

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

which means rows are now contiguous.

Another solution is to simply take a copy of the data

a = x.copy('A')

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

as taking a copy will write the data into a new, linear, and contiguous array.

So the final solution?

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

But librosa also removed the need for contiguity recently, so this problem should slowly disappear in the future.

Nils Werner
  • 34,832
  • 7
  • 76
  • 98