[Python, Программирование] Превращаем клавиатуру в пианино с помощью python

Автор Сообщение
news_bot ®

Стаж: 6 лет 9 месяцев
Сообщений: 27286

Создавать темы news_bot ® написал(а)
18-Апр-2021 16:31


Как-то заинтересовался я теорией музыки. Но пианино, увы, у меня нет, поэтому я отправился в поиски программы со следующий функционалом: после нажатия на кнопку звучит определенная нота. Сперва я посмотрел высокопрофессиональные программы, но в них слишком, уж слишком много функций. И это очень хорошо, но на текущем моменте моей жизни мне это попросту ненужно. Это будет только мешать и отвлекать. В программах с меньшим функционалом максимально неудобный интерфейс. Потому я решил просто написать такую программу сам. Подробности под катом.Немножко о 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()
Воспроизведения нот в реальном времени с помощью 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 просто так нельзя.Воспроизведения нот в реальном времени с помощью 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
Спасибо за прочтение статьи. Удачи!
===========
Источник:
habr.com
===========

Похожие новости: Теги для поиска: #_python, #_programmirovanie (Программирование), #_python, #_fluidsynth, #_mido, #_midi, #_python, #_programmirovanie (
Программирование
)
Профиль  ЛС 
Показать сообщения:     

Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы

Текущее время: 22-Ноя 05:00
Часовой пояс: UTC + 5