Fourier transform the wav file read by Python, reverse transform it, and write it again.

Hello everybody

Suddenly I started playing with python and this is the third time, but this time I will play with wav files as well. This time, we will perform Fourier transform on the waveform data read by wav, or restore it by Fourier inverse transform and write it to wav.

Fourier transform

Sound wave

Sound is generated by the vibration of air (sound waves). Furthermore, the vibration is made up of overlapping vibrations of multiple frequencies. In such vibrations of sound, the dominant frequency determines the pitch of the sound, the magnitude of the amplitude determines the loudness of the sound, and the vibrations of various frequencies that are not dominant determine the timbre of the sound.

Fourier transform

Since sound contains various frequencies, it is difficult to analyze it as it is. Therefore, a method was invented to express the sound with some simple superpositions. This is the Fourier series expansion.

f(t) = \sum_k a_k e^{\rm{i}kt}, \ \ \ \ \ e^{\rm{i}kt} = \cos(kt) + \rm{i}\sin(kt)

It's like this. I won't talk about mathematics here, so if you don't understand it, you may want to look it up in Euler's formula. Now, if you know $ a_k $ here, you can approximate this $ f (t) $. How can you find this? Let's use a little trick, but first suppose you observe $ f (t) $ for a certain amount of time, $ T $. Multiply both sides of the previous series expansion by $ e ^ {-\ rm {i} k't} $ and try to integrate.

\int_0^T f(t)e^{-\rm{i}k't}dt = \sum_k a_k \int_0^T e^{\rm ikt - ik't}dt

It will be. If you select $ k $ as $ 2n \ pi / T $ here, the integral on the right side will remain only when $ k = k'$.

a_k = \frac{1}{T} \int_0^T f(t)e^{-\rm ikt}dt

The calculation to find this $ a_k $ is called the Fourier transform. Actually, this integral is approximated by numerical calculation.

Fourier inverse transform

Once you have $ a_k $, the Fourier series expansion is complete. Generating the shape of a function in real space from the distribution of $ a_k $ is called the Fourier inverse transform.

Fourier transform wav file

Well, let's put the theoretical story aside and carry out the actual processing. Same as last time Use jupyter. First, read the wav file as usual.

import wave
import struct
from scipy import fromstring, int16
import numpy as np
from pylab import *
%matplotlib inline

wavfile = '/data/input/test.wav'
wr = wave.open(wavfile, "rb")
ch = wr.getnchannels()
width = wr.getsampwidth()
fr = wr.getframerate()
fn = wr.getnframes()

N = 256
span = 15000

print('Channel', ch)
print('Total number of frames', fn)
print('Sample time', 1.0 * N * span / fr, 'Seconds')

origin = wr.readframes(wr.getnframes())
data = origin[:N * span * ch * width]
wr.close()

print('Current array length', len(origin))
print('Sample sequence length: ', len(data))

When you do this,

Channel 2
Total number of frames 15884224
Sample time 87.07482993197279 seconds
Current array length 63536896
Sample sequence length:  15360000

The result is like this. The reason why the read ʻorigin array length is four times the number of frames seems to be because one frame is 4 bytes because it is stereo and the sample size is 2 (16 bits). ʻOrigin is a byte string, so it's natural. .. ..

For the time being, let's process the extracted data so that it can be easily Fourier transformed.

#Stereo premise
X = np.frombuffer(data, dtype="int16")
left = X[::2]
right = X[1::2]

First, read the sample data with int16 and divide it into the sound heard from the left and the sound heard from the right.

Next, define the Fourier transform and the inverse transform (series expansion). This time we will use numpy fft. fft is a library for FFT (Fast Fourier Transform).

def fourier (x, n, w):
    K = []
    for i in range(0, w-2):
        sample = x[i * n:( i + 1) * n]
        partial = np.fft.fft(sample)
        K.append(partial)
        
    return K

def inverse_fourier (k):
    ret = []
    for sample in k:
        inv = np.fft.ifft(sample)
        ret.extend(inv.real)
        
    print (len(sample))
    return ret

The function fourier returns an array of frequency distributions for each sample interval. The function ʻinverse_fourier` generates a waveform in real space based on the frequency distribution.

This time, I will not do any special processing, just convert the Fourier transform and immediately reverse convert it and write it to wav.

Kl = fourier(left, N, span)
Kr = fourier(right, N, span)
freqlist = np.fft.fftfreq(N, d=1/fr)
amp = [np.sqrt(c.real ** 2 + c.imag ** 2) for c in Kl[2500]]
plot(freqlist, amp, marker= 'o', linestyle='-')
axis([0, fr / 2 , 0, 100000])

amp = [np.sqrt(c.real ** 2 + c.imag ** 2) for c in Kr[2500]]
plot(freqlist, amp, marker= 'o', linestyle='-')

First, try Fourier transform. Then, the frequency distribution for each sample section can be obtained. If you plot the distribution at an appropriate moment, you will get the following result. スクリーンショット 2017-06-08 0.10.34.png

After confirming that the frequency distribution is correct, let's perform inverse conversion.

def combine_wav (left, right):
    ret = []
    number = len(right) if len(left) > len(right) else len(left)
    for i in range(0, number -1):
        data = [int(left[i]), int(right[i])]
        ret.extend(data)
        
    return ret

left_dash = inverse_fourier(Kl)
right_dash = inverse_fourier(Kr)
raw_data = combine_wav(left_dash, right_dash)

outd = struct.pack("h" * len(raw_data), *raw_data)

It's a little annoying, but because it's a stereo sound source, the inverse Fourier of the left sound source and the inverse Fourier of the right sound source are mixed.

#Export
outf = '/data/output/test.wav'
ww = wave.open(outf, 'w')
ww.setnchannels(ch)
ww.setsampwidth(width)
ww.setframerate(fr)
ww.writeframes(outd)
ww.close()

So, I will write it out.

I made something that doesn't feel unnatural even for myself with deafness.

Summary

I converted the contents of the wav file to Fourier and played with it. For the time being, this time it is like this.

reference

numpy.fft

Recommended Posts

Fourier transform the wav file read by Python, reverse transform it, and write it again.
Read the file line by line in Python
Read the file line by line in Python
Read the csv file and display it in the browser
Read the xml file by referring to the Python tutorial
Read json file with Python, format it, and output json
Read and write csv file
Read and write a file
Write and read a file
Read the csv file with jupyter notebook and write the graph on top of it
How to switch the configuration file to be read by Python
[Python] Use this to read and write wav files [wavio]
[PEP8] Take over the Python source code and write it neatly
Read an Excel sheet and loop it line by line Python VBA
Process the gzip file UNLOADed with Redshift with Python of Lambda, gzip it again and upload it to S3
Read the old Gakushin DC application Word file (.doc) from Python and try to operate it.
[Python Kivy] How to get the file path by dragging and dropping
Let's read the RINEX file with Python ①
Write O_SYNC file in C and Python
Read the file by specifying the character code.
Read and write JSON files in Python
Read the file with python and delete the line breaks [Notes on reading the file]
Read CSV file with Python and convert it to DataFrame as it is
[python] Read html file and practice scraping
[Python] Read the specified line in the file
[Implementation example] Read the file line by line with Cython (Python) from the last line
[Python] Precautions when retrieving data by scraping and putting it in the list
Python --Read data from a numeric data file and find the multiple regression line.
[Python] Concatenate a List containing numbers and write it to an output file.
[Python3] Read and write with datetime isoformat with json
Let's write a Python program and run it
Read line by line from a file with Python
I want to replace the variables in the python template file and mass-produce it in another file.
Template of python script to read the contents of the file
File write speed comparison experiment between python 2.7.9 and pypy 2.5.0
[Python] One-liner FFT (Fast Fourier Transform) and other madness
Read and write single precision floating point in Python
Read and write files with Slackbot ~ Bot development with Python ~
The VIF calculated by Python and the VIF calculated by Excel are different .. ??
Read and write NFC tags in python using PaSoRi
Python --Read data from a numeric data file to find the covariance matrix, eigenvalues, and eigenvectors
Recursively get the Excel list in a specific folder with python and write it to Excel.
[Machine learning] Write the k-nearest neighbor method (k-nearest neighbor method) in python by yourself and recognize handwritten numbers.
Read Python csv file
Read the function name from the DB and execute it dynamically
[Python] Open the csv file in the folder specified by pandas
Get the MIME type in Python and determine the file format
[Python] I installed the game from pip and played it
The process of making Python code object-oriented and improving it
Read the VTK file and display the color map with jupyter.
If I thought I didn't see the pyc file recently, it was quarantined in pycache by python3.
Find the white Christmas rate by prefecture with Python and map it to a map of Japan