How to turn a keyboard into a piano with Python

Somehow I became interested in music theory. But, alas, I don't have a piano, so I went in search of a program with the following functionality: after pressing a button, a certain note sounds. At first I looked at highly professional programs, but they have too, too many functions. And this is very good, but at the current moment of my life, I simply do not need it. This will only interfere and distract. In programs with less functionality, the most inconvenient interface. So I decided to just write such a program myself. Details under the cut.






A little about MIDI

MIDI -     . , . :





  1. midi , .





  2. . , noteon – ; noteoff – ; change_program – , control_change – , , , . .





  3. : – , , , .; , ; ( 16), , . , .





MIDI- Mido

Mido – python, MIDI- . .





:





from mido import MidiFile
 
mid = MidiFile('song.mid')
for i, track in enumerate(mid.tracks):
    print('Track {}: {}'.format(i, track.name))
    for msg in track:
        print(msg)
      
      



:





from mido import Message, MidiFile, MidiTrack, second2tick
 
 
mid = MidiFile()
 
track = MidiTrack()
mid.tracks.append(track)
time = int(second2tick(0.1, 480, 500000))
for i in range(100):
    track.append(Message('program_change', program=12, time=0))
    track.append(Message('note_on', note=64, velocity=64, time=time))
    track.append(Message('note_off', note=64, velocity=64, time=time))
 
mid.save('new_song.mid')
      
      



«time». .





c keyboard.





:





import keyboard
 
 
def hook(key):
    if key.event_type == "down":
        print("{} press".format(key.name))
    if key.event_type == "up":
        print("{} release".format(key.name))
 
keyboard.hook(hook)
keyboard.wait("esc")
      
      



{key: note} ( ):





import keyboard
 
 
keys = {}
note = 48
def hook(key):
    global note

    if key.event_type == "down":
        if key.name != "esc":
            keys.update({key.name: note})
            note += 1

    if key.event_type == "up":
        if key.name == "esc":
            print(keys)
 
keyboard.hook(hook)
keyboard.wait()
      
      



e mido

python-rtmidi.





( ):





>>> mido.get_output_names()
['Microsoft GS Wavetable Synth 0']
      
      



:





import keyboard
import mido
 
 
port = mido.open_output('Microsoft GS Wavetable Synth 0')
keys = keys = {'1': 48, '2': 49, '3': 50, '4': 51, '5': 52, '6': 53, '7': 54, '8': 55, '9': 56, '0': 57, '-': 58, '=': 59, 'q': 60, 'w': 61, 'e': 62, 'r': 63, 't': 64, 'y': 65, 'u': 66, 'i': 67, 'o': 68, 'p': 69, '[': 70, ']': 71, 'a': 72, 's': 73, 'd': 74, 'f': 75, 'g': 76, 'h': 77, 'j': 78, 'k': 79, 'l': 80, ';': 81, "'": 82, 'enter': 83}
pressed_keys = {key: False for key in keys.keys()}
 
 
def hook(key):
    if key.event_type == "down":
        if key.name in keys:
            if not pressed_keys[key.name]:
                port.send(mido.Message('note_on', note=keys[key.name]))
                pressed_keys[key.name] = True
 
    if key.event_type == "up":
        if key.name in keys:
            port.send(mido.Message('note_off', note=keys[key.name]))
            pressed_keys[key.name] = False
 
keyboard.hook(hook)
keyboard.wait()
      
      



– . midi wav .





e fluidsynth

Fluidsynth – .





fluidsynth ( Windows):





  1. fluidsynth Windows .





  2. «fluidsynth\bin» path. « », ; « », «Path», «», «» «fluidsynth\bin».





  3. .





  4. fluidsynth. midi «fluidsynth FluidR3_GM.sf2 file_name.mid». .





pyfluidsynth.





  1. pyfluidsynth ( github) .





  2. 1.5 ( , , ). «fluidsynth\bin» «libfluidsynth-3.dll» ( , ). «fluidsynth.py» «pyfluidsynth», «lib = find_library('fluidsynth') or…» ( ) «fluidsynth» «libfluidsynth-3.dll» ( ).





  3. «pyfluidsynth» «py setup.py install». .





numpy.





:





import time
import fluidsynth
 
fs = fluidsynth.Synth()
fs.start()
 
sfid = fs.sfload("FluidR3_GM.sf2")
fs.program_select(0, sfid, 0, 0)
 
 
for i in range(10):
    fs.noteon(0, 60, 30)
    fs.noteon(0, 67, 30)
    fs.noteon(0, 76, 30)
 
    time.sleep(1.0)
 
    fs.noteoff(0, 60)
    fs.noteoff(0, 67)
    fs.noteoff(0, 76)
 
time.sleep(1.0)
 
fs.delete()
      
      



keyboard:





import keyboard
import mido
import fluidsynth
 
 
fs = fluidsynth.Synth()
fs.start()
sfid = fs.sfload("FluidR3_GM.sf2")
fs.program_select(0, sfid, 0, 41)
 
 
keys = {'1': 48, '2': 49, '3': 50, '4': 51, '5': 52, '6': 53, '7': 54, '8': 55, '9': 56, '0': 57, '-': 58, '=': 59, 'q': 60, 'w': 61, 'e': 62, 'r': 63, 't': 64, 'y': 65, 'u': 66, 'i': 67, 'o': 68, 'p': 69, '[': 70, ']': 71, 'a': 72, 's': 73, 'd': 74, 'f': 75, 'g': 76, 'h': 77, 'j': 78, 'k': 79, 'l': 80, ';': 81, "'": 82, 'enter': 83}
pressed_keys = {key: False for key in keys.keys()}
 
 
def hook(key):
    if key.event_type == "down":
        if key.name in keys:
            if not pressed_keys[key.name]:
                fs.noteon(0, keys[key.name], 127)
                pressed_keys[key.name] = True
 
    if key.event_type == "up":
        if key.name in keys:
            fs.noteoff(0, keys[key.name])
            pressed_keys[key.name] = False
 
keyboard.hook(hook)
keyboard.wait()
      
      



midi wav

:





fluidsynth -F melody.wav FluidR3_GM.sf2 melody.mid
      
      



. !








All Articles