-
1
-
2
-
3
-
4
-
5
-
6
-
7
-
8
-
9
-
10
-
11
-
12
-
13
-
14
-
15
-
16
-
17
-
18
-
19
-
20
-
21
-
22
-
23
-
24
-
25
-
26
-
27
-
28
-
29
-
30
-
31
-
32
-
33
-
34
-
35
-
36
-
37
-
38
-
39
-
40
-
41
-
42
-
43
-
44
-
45
-
46
-
47
import math
from pyaudio import PyAudio, paUInt8
def generate_sine_wave(frequency, duration, volume=0.2, sample_rate=22050):
''' Generate a tone at the given frequency.
Limited to unsigned 8-bit samples at a given sample_rate.
The sample rate should be at least double the frequency.
'''
if sample_rate < (frequency * 2):
print('Warning: sample_rate must be at least double the frequency '
f'to accurately represent it:\n sample_rate {sample_rate}'
f' ≯ {frequency*2} (frequency {frequency}*2)')
num_samples = int(sample_rate * duration)
rest_frames = num_samples % sample_rate
pa = PyAudio()
stream = pa.open(
format=paUInt8,
channels=1, # mono
rate=sample_rate,
output=True,
)
# make samples
s = lambda i: volume * math.sin(2 * math.pi * frequency * i / sample_rate)
samples = (int(s(i) * 0x7F + 0x80) for i in range(num_samples))
# write several samples at a time
for buf in zip( *([samples] * sample_rate) ):
stream.write(bytes(buf))
# fill remainder of frameset with silence
stream.write(b'\x80' * rest_frames)
stream.stop_stream()
stream.close()
pa.terminate()
generate_sine_wave(
# see http://www.phy.mtu.edu/~suits/notefreqs.html
frequency=440, # Hz, waves per second C6
duration=0.2, # seconds to play sound
volume=0.25, # 0..1 how loud it is
sample_rate=44100, # number of samples per second: 11025, 22050, 44100
)