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)