電子楽器を作ってみたいんだが

もう4年くらい前か、GAINERというのが一部で流行ってたので買ってみたけど、けっきょく使いこなせなかった。やりたかったことは、練習用のサイレントアコーディオン作成*1。バイオリンなどのメジャーな楽器はサイレント楽器が出ていて音をあまり出さずに練習できる。アコーディオンもローランドからVアコーディオンというシリーズが出てるけど、アコーディオン形が千差万別で、自分のとは合わない*2



電子楽器の原理としてはそんなに複雑でもないはず。ボタンのON/OFFと、蛇腹内部の気圧の変位がわかれば音は出せるはずなので、デジタルなボタンと圧力センサーでできるんじゃなかろうか。胴体は自分で作れるわけもなく、壊れたものを再利用するか、キットを買ってきて電子用にするか。とりあえずウッドストック キッズアコーディオンとかの安価な子供用のおもちゃでもいい。
まあそんな風にずっと思っていたところにRaspberry Piを買ったから、試してみない理由はない。



圧力センサーは後回しにして、とりあえずキーボードのa、s、dに音を割り当てて、ブレッドボード上のスイッチのON/OFFで音が変わるようにしてみた(自分のアコーディオンは蛇腹の押し引きで音が変わる、ダイアトニックというタイプなので。この点はハーモニカと同じ。)。音はMIDIで出して、音源はTiMidity。いろんなところから借りて来たコードなので作りはひどい。試してみると、遅延もひどくて話にならない。考えてみれば、これまでボタンを押す長さを表すプログラムとかには縁がなかったので、そこから考え直しつつ*3ボトルネックを解消するしかないかなぁ。それが一段落したところで、あらためて圧力センサーを組み込めるように、アナログ回路のお勉強か。


soundkey.py

#!/usr/bin/python

import os, sys
import tty
from select import select
import pygame
import pygame.midi
from time import sleep
import RPi.GPIO as GPIO

class NotTTYException(Exception): pass

class TerminalFile:
    def __init__(self,infile):
        if not infile.isatty():
            raise NotTTYException()
        self.file=infile

        #prepare for getch
        self.save_attr=tty.tcgetattr(self.file)
        newattr=self.save_attr[:]
        newattr[3] &= ~tty.ECHO & ~tty.ICANON
        tty.tcsetattr(self.file, tty.TCSANOW, newattr)

    def __del__(self):
        #restoring stdin
        import tty  #required this import here
        tty.tcsetattr(self.file, tty.TCSADRAIN, self.save_attr)

    def getch(self):
        if select([self.file],[],[],0)[0]:
            c=self.file.read(1)
        else:
            c=''
        return c

if __name__=="__main__":
    s=TerminalFile(sys.stdin)
    print "Press q to quit..."

    pygame.init()
    pygame.midi.init()

    GPIO.setmode(GPIO.BCM)
    GPIO.setup(24,GPIO.IN)

    instrument = 0
    note = 74
    volume = 127
    port = 2
    
    midiOutput = pygame.midi.Output(port, 1)
    midiOutput.set_instrument(instrument)

    key = s.getch()
    inputValue = GPIO.input(24)
    while key!="q":
      if key == "a":
        if inputValue == True:
          note = 60
        else:
          note = 61
      elif key == "s": 
        if inputValue == True:
          note = 62
        else:
          note = 63
      elif key == "d": 
        if inputValue == True:
          note = 64
        else:
          note = 65
      midiOutput.note_on(note,volume)
      key = s.getch()
      inputValue = GPIO.input(24)
      sleep(1)
      midiOutput.note_off(note,volume)


    del midiOutput
    pygame.midi.quit()
    
    print "-- END --"

*1:本番用となると難度がさらに跳ね上がるだろうな

*2:演奏は下手くそで何曲かゆっくり弾けるくらい。それもこれもサイレント楽器がないから!

*3:pygameライブラリでできるかと思ったけどウィンドウ無しだと使えなそう