Forum Archive

Multi-touch toy piano code

Berg

I read there's a sample code for a multi-touch toy piano in Pythonista. Does anybody know how to find it?
Thanks

omz

It was included as sample code in an older version of Pythonista, but it isn't anymore. Here's the script (with some minor changes to make it compatible with the current version):

# Piano
# 
# A simple multi-touch piano.

from scene import *
import sound
from itertools import chain

class Key (object):
    def __init__(self, frame):
        self.frame = frame
        self.name = None
        self.touch = None
        self.color = (1, 1, 1)
        self.highlight_color = (0.9, 0.9, 0.9)

    def hit_test(self, touch):
        return touch.location in self.frame

class Piano (Scene):
    def setup(self):
        self.white_keys = []
        self.black_keys = []
        white_key_names = ['piano:C3', 'piano:D3', 'piano:E3',
                           'piano:F3', 'piano:G3', 'piano:A3', 
                           'piano:B3', 'piano:C4']
        black_key_names = ['piano:C3#', 'piano:D3#', 'piano:F3#', 
                           'piano:G3#', 'piano:A3#']
        for key_name in chain(white_key_names, black_key_names):
            sound.load_effect(key_name)
        white_positions = range(8)
        black_positions = [0.5, 1.5, 3.5, 4.5, 5.5]
        key_w = self.size.w
        key_h = self.size.h / 8
        for i in range(len(white_key_names)):
            pos = white_positions[i]
            key = Key(Rect(0, pos * key_h, key_w, key_h))
            key.name = white_key_names[i]
            self.white_keys.append(key)
        for i in range(len(black_key_names)):
            pos = black_positions[i]
            key = Key(Rect(0, pos * key_h + 10, key_w * 0.6, key_h - 20))
            key.name = black_key_names[i]
            key.color = (0, 0, 0)
            key.highlight_color = (0.2, 0.2, 0.2)
            self.black_keys.append(key)

    def draw(self):
        stroke_weight(1)
        stroke(0.5, 0.5, 0.5)
        for key in chain(self.white_keys, self.black_keys):
            if key.touch is not None:
                fill(*key.highlight_color)
            else:
                fill(*key.color)
            rect(*key.frame)

    def touch_began(self, touch):
        for key in chain(self.black_keys, self.white_keys):
            if key.hit_test(touch):
                key.touch = touch
                sound.play_effect(key.name)
                return

    def touch_moved(self, touch):
        hit_key = None
        for key in chain(self.black_keys, self.white_keys):
            hit = key.hit_test(touch)
            if hit and hit_key is None:
                hit_key = key
                if key.touch is None:
                    key.touch = touch
                    sound.play_effect(key.name)
            if key.touch == touch and key is not hit_key:
                key.touch = None

    def touch_ended(self, touch):
        for key in chain(self.black_keys, self.white_keys):
            if key.touch == touch:
                key.touch = None

run(Piano())

ccc

FIXED: ~~If you add a 1 as the fourth parameter on the scene.Color() definitions on lines 14, 15, 44, and 45 then this will also run under Python 3.~~

For those who like list comprehensions (not everybody does), you can try:

        white_key_names = ['Piano_' + x for x
                           in 'C3 D3 E3 F3 G3 A3 B3 C4'.split()]
        black_key_namez = ['Piano_' + x for x in 'C3# D3# F3# G3# A3#'.split()]
omz

@ccc I just noticed that I pasted the wrong version... I've edited the post above to make it work in Py3.

RufusVS

Thanks for posting this! I'm new to Pythonista and wouldn't have known what I missed, and music
is one of the main reason I bought the app.
(Later Edit:)
Cut and paste code into Sublime Text editor. Then did some research and found out there's no simple
way to import it into Pythonista. Damn Apple iPhone rules!
(Later:)
Keyed it in and found out I loved the Pythonista editor! It does the best under the circumstances!
But a regular desktop is still easier.
The piano code worked well too. I intend to expand it to record and playback (for my choral music
rehearsal)

Berg

Thank you so much! I'll be playing with this code for a while...