Initial commit
This commit is contained in:
commit
91a1e2e312
22 files changed
+885
No files matched your search
@@ -0,0 +1,99 @@
|
||||
import importlib
|
||||
from tkinter import Frame, Tk
|
||||
|
||||
import synth
|
||||
from pyalsa import Alsa
|
||||
|
||||
SAMPLE_RATE = 44_100
|
||||
LATENCY = 50_000 # 50ms
|
||||
INT16_MAX = 2**15 - 1
|
||||
alsa = Alsa(SAMPLE_RATE, LATENCY)
|
||||
|
||||
keys = "qzsedftgyhujk"
|
||||
base_freq = 261.6256 # C4, piano middle C
|
||||
keys_map = [0] * len(keys)
|
||||
|
||||
|
||||
def keydown(e):
|
||||
if e.keysym in keys:
|
||||
i = keys.index(e.keysym)
|
||||
keys_map[i] = 1
|
||||
|
||||
|
||||
def keyup(e):
|
||||
if e.keysym in keys:
|
||||
i = keys.index(e.keysym)
|
||||
keys_map[i] = 0
|
||||
|
||||
|
||||
def key_to_freq(i):
|
||||
if 0 <= i < len(keys):
|
||||
return base_freq * (2 ** (i / 12))
|
||||
return 0
|
||||
|
||||
|
||||
root = Tk()
|
||||
|
||||
|
||||
# note parameters: freq, volume
|
||||
# note state: phase, volume
|
||||
class Note:
|
||||
def __init__(self):
|
||||
self.freq = 0
|
||||
self.vol = 0
|
||||
self.phase = 0
|
||||
self.gain = 0
|
||||
self.playing = False
|
||||
self.waveform = "sine"
|
||||
self.attack = 0.01
|
||||
self.release = 0.05
|
||||
self.waveshaping = False
|
||||
self.lowpass = False
|
||||
self.lp = 0
|
||||
|
||||
|
||||
def reload_synth(event):
|
||||
importlib.reload(synth)
|
||||
print("reloaded synth module")
|
||||
|
||||
|
||||
def update(root, note):
|
||||
pressed_key = keys_map.index(1) if 1 in keys_map else -1
|
||||
note_freq = key_to_freq(pressed_key)
|
||||
if note_freq != note.freq:
|
||||
note.freq = note_freq
|
||||
if not note.playing and note_freq != 0:
|
||||
note.playing = True
|
||||
if note.playing and note_freq == 0:
|
||||
note.playing = False
|
||||
buf = synth.synth(note)
|
||||
alsa.write(buf) # send sound to alsa
|
||||
root.after(0, update, root, note) # schedule next update
|
||||
|
||||
|
||||
def toggle_note_waveform(e):
|
||||
waves = ["sine", "saw", "square", "triangle"]
|
||||
current = waves.index(note.waveform)
|
||||
note.waveform = waves[(current + 1) % len(waves)]
|
||||
print("waveform:", note.waveform)
|
||||
|
||||
def toggle_note_waveshaping(e):
|
||||
note.waveshaping = not note.waveshaping
|
||||
print("waveshaping:", note.waveshaping)
|
||||
|
||||
def toggle_note_lowpass(e):
|
||||
note.lowpass = not note.lowpass
|
||||
print("lowpass:", note.lowpass)
|
||||
|
||||
note = Note()
|
||||
frame = Frame(root, width=100, height=100)
|
||||
frame.bind("<KeyPress>", keydown)
|
||||
frame.bind("<KeyRelease>", keyup)
|
||||
root.bind_all("<Control-r>", reload_synth)
|
||||
root.bind_all("w", toggle_note_waveform)
|
||||
root.bind_all("x", toggle_note_waveshaping)
|
||||
root.bind_all("c", toggle_note_lowpass)
|
||||
frame.pack()
|
||||
frame.focus_set()
|
||||
root.after(100, update, root, note)
|
||||
root.mainloop()
|
||||
Reference in new issue
Block a user