Prerequisites: Python 3.7, pip.
Install dependencies:
pip install -r requirements.txt
Turn on sound and run:
python ./scale18.py
pyaudio==0.2.11 | |
numpy |
import sys | |
import random | |
import pyaudio | |
import numpy as np | |
SAMPLE_RATE = 44100 | |
SCALE_SIZE = 18 | |
BASE_FREQUENCY = 440.0 | |
BASE_OCTAVE = 4 | |
# (note, octave, length, volume) | |
MELODY = [ | |
(0, 2, 8, 0.5), | |
(1, 2, 8, 0.5), | |
(2, 2, 8, 0.5), | |
(3, 2, 8, 0.5), | |
(4, 2, 8, 0.5), | |
(5, 2, 8, 0.5), | |
(6, 2, 8, 0.5), | |
(7, 2, 8, 0.5), | |
(8, 2, 8, 0.5), | |
(9, 2, 8, 0.5), | |
(10, 2, 8, 0.5), | |
(11, 2, 8, 0.5), | |
(12, 2, 8, 0.5), | |
(13, 2, 8, 0.5), | |
(14, 2, 8, 0.5), | |
(15, 2, 8, 0.5), | |
(16, 2, 8, 0.5), | |
(17, 2, 8, 0.5), | |
] | |
class Synth: | |
def __init__(self): | |
self.pyaudio = pyaudio.PyAudio() | |
self.stream = self.pyaudio.open( | |
format=pyaudio.paFloat32, | |
channels=2, | |
rate=SAMPLE_RATE, | |
output=True | |
) | |
def play_sine(self, frequency, duration=1.0, volume=0.5): | |
samples = (np.sin(2 * np.pi * np.arange(SAMPLE_RATE * duration) * frequency / SAMPLE_RATE)) | |
self.stream.write(volume * samples.astype(np.float32)) | |
def __del__(self): | |
self.stream.stop_stream() | |
self.stream.close() | |
self.pyaudio.terminate() | |
scale = [BASE_FREQUENCY * pow(2, i / SCALE_SIZE) for i in range(SCALE_SIZE)] | |
synth = Synth() | |
for (note, octave, length, volume) in MELODY: | |
assert(note >= 0 and note < SCALE_SIZE) | |
print(f"{note}:{octave}/{length}", end=' ') | |
sys.stdout.flush() | |
frequency = scale[note] * pow(2, octave - BASE_OCTAVE + 1) | |
duration = 16.0 / length | |
synth.play_sine(frequency, duration=duration, volume=volume) | |
print('') | |
del synth |