# Write a 440 Hz Sine Wave to .wav-File using Python and SciPy [closed]

This is my first post on DSP.SE! I'm a student in Computer Sciences and am just getting started with Signals and Systems, thus getting in touch with discrete signals and analyzing them.

I wanted to explore this world a little further and so my first goal is to create a Sine Wave that has a Frequency of 440 Hz and write it to a .wav-File. Of course i have all the calculus in mind, but i can't seem to figure out the problem myself!

So far, i have this:

#!/usr/bin/env python3

import numpy as np
from scipy.io import wavfile

sampleRate = 44100

t = np.linspace(0, 20, sampleRate * 5)  #  Produces a 5 second Audio-File
y = np.sin(440 * t)  #  Should have frequency of 440Hz

wavfile.write('Sine.wav', sampleRate, y)


I understand why this code always creates a File, that is 5 seconds long, but i can't figure out, how to get the frequency right!

Have i even gotten the rest of the code right, Dsp-Guy-wise?

• should maybe be t = np.linspace(0, 5, sampleRate*5 + 1). Nov 6, 2018 at 22:24
• oh, and welcome to dsp.se . this might be a better question for Stack Overflow, but i dunno. Nov 6, 2018 at 22:26
• Thanks for your comment! I already figured the solution out myself, see my answer! Nov 6, 2018 at 22:32
• Actually, maybe math.se would also have been a good fit! I hope i haven't posted absolutely the wrong way Nov 6, 2018 at 22:34

After some experimenting I came up with the following:

#!/usr/bin/env python3

import numpy as np
from scipy.io import wavfile

sampleRate = 44100
frequency = 440
length = 5

t = np.linspace(0, length, sampleRate * length)  #  Produces a 5 second Audio-File
y = np.sin(frequency * 2 * np.pi * t)  #  Has frequency of 440Hz

m = np.max(np.abs(y))
print("m", m)

maxint16 = np.iinfo(np.int16).max  # == 2**15-1
print("maxint16", maxint16)

# You have to Normalize the audio
y = maxint16 * y / m

# You have to convert to int16, else doesn't work
y = y.astype(np.int16)

wavfile.write('Sine.wav', sampleRate, y)


I pulled out one of my math-books and figured out how to write the sine-function:

Since sin(x) has a period of 2pi, sin(2pix) has a period of 1/Frequency of 1Hz. Thus, sin(4402pix) has a Frequency of 440Hz.

The last thing that was unclear to me was how to get the array-length and element-count right!

Opting for a File that has a sample rate of 5 seconds at 44.1 kHz Sample Rate, i need 5 * 44.1k samples, so that was already ok. But since sin(4402pi*x) performs 440 periods until t == 1, the array simply has to have a duration of 5 (5 seconds in my case to be precise). enlarging the array boundaries would have squished the array-values together, resulting in a higher pitched sound.

Sorry to anyone that has already scratched their head, I probably should have thought for a little bit longer!

• Good to see you figured it out. I'd suggest using duration instead of length to avoid confusion -- length usually means "number of elements".
– MBaz
Nov 6, 2018 at 23:31
• how many actual number of elements are produced by linspace()? i think the length of the vector is the last argument to the function (if it's anything like MATLAB's linspace()). in that case, i am pretty sure you want  t = np.linspace(0, length, sampleRate*length+1)  otherwise you will be slightly detuned. this is a "fencepost" or "off-by-one" sorta problem. Nov 6, 2018 at 23:38
• No, it creates exactly as much elements, as the third Argument specified. When i do len(t) i get 220500. 220500/5 = 44100 => SampleRate Nov 7, 2018 at 6:04
• But the Index of the elements is always len() - 1. So if i want to edit the last element of t, i would have to write t[len(t) - 1] = value, at least if i'm not mistaken Nov 7, 2018 at 6:09
• I investigated a little bit: you can set behavior yourself, according to docs.scipy.org/doc/numpy-1.15.0/reference/generated/… in linspace, setting endpoint=False, the last wouldn't bei included in the array, Default is True. Nov 7, 2018 at 6:52