Author: Mario Román
GitHub: https://github.com/M42/sum-of-waves
This notebook contains code to a sound file (specifically, a 16bit PCM WAV file) into a pdf file containing the mathematical formula of the sound wave. For an example of input and output, you can check the files "test2.wav
" and "output.pdf
" in the GitHub repository.
We use the Fast Fourier Transform algorithm to express the wave as a sum of sinusoidal functions, and the complete sum is translated to a LaTeX
file, which can be used to produce the final pdf
.
In this first step, we are going to open the sound file and make a simple plot of the signal, using matplotlib
. The sound file:
To convert multiple sound files to this format, you can use sound editing programs, such as Audacity.
In [1]:
%matplotlib inline
import matplotlib.pyplot as plt
import numpy as np
import wave
import sys
In [2]:
# Only opens 16bit PCM WAV files.
# The format can be changed in Audacity.
spf = wave.open('test2.wav','r')
In [3]:
# Only opens Mono files
if spf.getnchannels() == 2:
print 'Just mono files'
sys.exit(0)
In [4]:
# Extracts the signal
signal = spf.readframes(-1)
signal = np.fromstring(signal, 'Int16')
In [5]:
# Prints the signal
plt.figure(1)
plt.title('Signal Wave...')
plt.plot(signal)
Out[5]:
In [6]:
Y = np.fft.fft(signal)
plt.figure(2)
plt.title('Fourier transform')
plt.plot(Y)
Out[6]:
In [7]:
Y
Out[7]:
In [14]:
lfile = open("latex.tex","w")
N = str(len(Y))
lfile.write("\\documentclass{scrartcl}\n\\usepackage{amsmath}\n\\begin{document}\n")
lfile.write("\\allowdisplaybreaks[1]\n")
lfile.write("\\title{Hungarian March}\n\\subtitle{First 8 seconds!}\n")
# Huge files cause a memory error in pdflatex
# We split in small files
j = 0
ffile = open("latex"+str(0)+".tex","w")
ffile.write("\\begin{align*}\n")
for k in range(len(Y)):
j = j+1
if j==28:
j=0
ffile.write("\\end{align*}\n")
lfile.write("\\input{latex"+str((k-1)/28)+".tex}\n")
ffile.close()
ffile = open("latex"+str(k/28)+".tex","w")
ffile.write("\\begin{align*}\n")
ffile.write(str(Y[k]) + "e^{ \\frac{j \\tau}{" + N + "} " + str(k) + "t } && + \\\\ \n")
ffile.write("\\end{align*}\n")
lfile.write("\\end{document}")
lfile.close()
In [8]:
# Inverses the fast fourier transform
yinv = np.fft.ifft(Y)
newsignal = yinv.real.astype(np.int16)
newsignal = newsignal.copy(order='C')
In [9]:
# Recreates the wave file
spfw = wave.open('test3.wav','w')
spfw.setnchannels(spf.getnchannels())
spfw.setsampwidth(spf.getsampwidth())
spfw.setframerate(spf.getframerate())
spfw.writeframes(newsignal)