#!/usr/bin/env python3 import os import serial import time from enum import IntEnum from models.utils import note_map from tkinter import * import tkinter as tk from tkinter import ttk if __name__ == "__main__": if os.name == 'nt': print('Windows machine!') ser = serial.Serial() ser.baudrate = 115200 ser.port = 'COM11' # CHANGE THIS COM PORT ser.open() else: print('Not windows machine!') ser = serial.Serial('/dev/ttyUSB0') ser.baudrate = 115200 class Command(IntEnum): SET_MOD_FCW = 1 SET_MOD_SHIFT = 2 START_PLAY = 3 STOP_PLAY = 4 SET_SYNTH_SHIFT = 5 RESET = 6 def cmd(command: Command, args: bytearray): # Write the command code ser.write(bytearray([int(command)])) time.sleep(0.001) # Write the argument from lowest byte to next for b in args: ser.write(bytearray([b])) time.sleep(0.001) time.sleep(0.002) def fcw_to_bytearray(fcw: int) -> bytearray: bytes = [] for byte_idx in range(3): mask = 0xFF << (8 * byte_idx) fcw_byte = (fcw & mask) >> (8 * byte_idx) bytes.append(fcw_byte) return bytearray(bytes) def freq_to_fcw(freq: float, fsamp: int = 60000, pa_bits: int = 24) -> int: return int(round((freq / fsamp) * 2**pa_bits)) cmd(Command.RESET, bytearray([])) cmd(Command.SET_MOD_SHIFT, bytearray([0])) cmd(Command.SET_MOD_FCW, fcw_to_bytearray(freq_to_fcw(0))) cmd(Command.START_PLAY, fcw_to_bytearray(freq_to_fcw(440))) time.sleep(0.1) cmd(Command.START_PLAY, fcw_to_bytearray(freq_to_fcw(220))) time.sleep(0.1) cmd(Command.START_PLAY, fcw_to_bytearray(freq_to_fcw(110))) time.sleep(0.1) cmd(Command.STOP_PLAY, fcw_to_bytearray(freq_to_fcw(110))) os.system('xset r off') # see https://stackoverflow.com/questions/27215326/tkinter-keypress-keyrelease-events def keyup(e): char = chr(e.keysym_num) if char in note_map: cmd(Command.STOP_PLAY, fcw_to_bytearray(freq_to_fcw(note_map[char]))) def keydown(e): char = chr(e.keysym_num) if char in note_map: cmd(Command.START_PLAY, fcw_to_bytearray(freq_to_fcw(note_map[char]))) def change_mod_fcw(val): if int(val) == 0: freq = 0 else: freq = int(round(10**(int(val) / 1000))) cmd(Command.SET_MOD_FCW, fcw_to_bytearray(freq_to_fcw(freq))) mod_fcw_freq["text"] = "Modulator Frequency (Hz): {}".format(freq) def change_mod_shift(val): cmd(Command.SET_MOD_SHIFT, bytearray([int(val)])) root = Tk() frm = tk.Frame(root) frm.grid() frm.bind("<KeyPress>", keydown) frm.bind("<KeyRelease>", keyup) tk.Label(frm, text="FM Synth").grid(column=0, row=0) mod_fcw = tk.Scale(frm, from_=0, to=4500, length=1000, tickinterval=1000, label="Modulator Freq (Log scale)", orient=HORIZONTAL, command=change_mod_fcw) mod_fcw.grid(column=0, row=1) mod_fcw.set(0) mod_fcw_freq = tk.Label(frm, text="") mod_fcw_freq.grid(column=0, row=2) mod_shift = tk.Scale(frm, from_=0, to=10, length=600, tickinterval=1, label="Modulator Shift", orient=HORIZONTAL, command=change_mod_shift) mod_shift.grid(column=0, row=3) mod_shift.set(0) tk.Label(frm, text="Type in this window to play notes").grid(column=0, row=4) tk.Button(frm, text="Quit", command=root.destroy).grid(column=0, row=5) frm.pack() frm.focus_set() root.mainloop() os.system('xset r on')