1import pyglet
2
3
4class Keyboard:
5    def __init__(self):
6        """A VERY basic semi-realtime synthesizer."""
7        self.window = pyglet.window.Window(720, 480)
8        instructions = "Press keys on your keyboard to play notes."
9        self.instructions = pyglet.text.Label(text=instructions, font_size=20, x=10, y=10)
10        self.current_note = pyglet.text.Label(text="", font_size=33, x=50, y=200)
11
12        self.c4_notes = {"C": 261.63, "C#": 277.183,
13                         "D": 293.66, "D#": 311.127,
14                         "E": 329.63,
15                         "F": 349.23, "F#": 369.994,
16                         "G": 392.00, "G#": 415.305,
17                         "A": 440.00, "A#": 466.164,
18                         "B": 493.88, "R": 0}
19
20        self.key_map = {pyglet.window.key.S: "C#",
21                        pyglet.window.key.D: "D#",
22                        pyglet.window.key.G: "F#",
23                        pyglet.window.key.H: "G#",
24                        pyglet.window.key.J: "A#",
25                        pyglet.window.key.L: "C#",
26                        pyglet.window.key.SEMICOLON: "D#",
27                        pyglet.window.key.Z: "C",
28                        pyglet.window.key.X: "D",
29                        pyglet.window.key.C: "E",
30                        pyglet.window.key.V: "F",
31                        pyglet.window.key.B: "G",
32                        pyglet.window.key.N: "A",
33                        pyglet.window.key.M: "B",
34                        pyglet.window.key.COMMA: "C",
35                        pyglet.window.key.PERIOD: "D",
36                        pyglet.window.key.BACKSLASH: "E"}
37
38        self.note_cache = {}
39
40        @self.window.event
41        def on_key_press(key, mod):
42            try:
43                self.play_note(self.c4_notes[self.key_map[key]])
44                self.current_note.text = "Current note: {0}".format(self.key_map[key])
45            except KeyError:
46                pass
47
48        @self.window.event
49        def on_draw():
50            self.window.clear()
51            self.instructions.draw()
52            self.current_note.draw()
53
54    def play_note(self, frequency, length=0.6):
55        if frequency in self.note_cache:
56            note_wave = self.note_cache[frequency]
57            note_wave.play()
58        else:
59            adsr = pyglet.media.synthesis.ADSREnvelope(0.05, 0.2, 0.1)
60            note_wave = pyglet.media.StaticSource(
61                pyglet.media.synthesis.Sawtooth(duration=length, frequency=frequency, envelope=adsr))
62            self.note_cache[frequency] = note_wave
63            note_wave.play()
64
65
66if __name__ == "__main__":
67    keyboard = Keyboard()
68    pyglet.app.run()
69