37 lines
1.2 KiB
Python
37 lines
1.2 KiB
Python
from math import pi, sin
|
|
|
|
SAMPLE_RATE = 44_100
|
|
INT16_MAX = 2**15 - 1
|
|
|
|
def synth(note):
|
|
buf = [0] * 512
|
|
for i, _ in enumerate(buf):
|
|
note.phase = (note.phase + note.freq / SAMPLE_RATE) % 1.0
|
|
# oscillator
|
|
match note.waveform:
|
|
case "saw": sample = 2 * note.phase - 1.0
|
|
case "square": sample = 1.0 if note.phase < 0.5 else -1.0
|
|
case "sine": sample = sin(2 * pi * note.phase)
|
|
case "triangle": sample = 4 * abs(note.phase - 0.5) - 1.0
|
|
case _: sample = 0.0
|
|
# envelope
|
|
target = 1 if note.playing else 0
|
|
if target == 1:
|
|
note.gain = min(note.gain + 1 / (0.010 * SAMPLE_RATE), 0.2) # attack
|
|
else:
|
|
note.gain = max(note.gain - 1 / (0.050 * SAMPLE_RATE), 0) # release
|
|
|
|
# signal processing
|
|
if note.waveshaping:
|
|
drive = 2
|
|
sample *= abs(sample) * drive
|
|
#sample = tanh(drive * sample)
|
|
if note.lowpass:
|
|
note.lp += 0.05 * (sample - note.lp)
|
|
sample = note.lp * note.gain
|
|
else:
|
|
sample = sample * note.gain
|
|
# convert to 16-bit signed integer and feed to buffer
|
|
buf[i] = int(sample * INT16_MAX)
|
|
return buf
|