Использование сценариев MIDI Remote beta
Всем привет.
Не так давно я купил SparkLE (пошаговый секвенсор от Arturia), и решил написать сценарий MIDI Remote для этой железки. Я ничего не знал о программировании на Python и всём таком. Я рад, что такие люди, как Ханс Петров и Жюльен Бейльхад оставили много советов, описывающих, как работают сценарии MIDI Remote. Спасибо им, т.к. я смог написать альфа-версию своего пошагового секвенсора. Теперь, когда я лучше понимаю, как работают сценарии MIDI Remote, я решил начать новый сценарий с нуля, пойти более гибким путём.
Как создать сценарий MIDI Remote?
Все файлы вашего сценария должны быть в одной папке, которая должна находиться тут:
Ableton Live\Resources\MIDI Remote Scripts\<Имя вашего сценария>
Для инициализации вашего сценария вы должны создать в этой папке файл __init__.py. Его можно сделать, используя Notepad++, Ulipad или любой другой текстовый редактор. Этот файл является обязательным, т.к. он сообщает Live, что вы хотите инициализировать сценарий. Для SparkLE я написал такой файл __init__.py:
# вы импортируете основную программу во время инициализации вашего сценария from sparkLE2 import sparkLE2 # эта функция сообщает Live, что вы создаёте новый сценарий MIDI Remote def create_instance(c_instance): # в результате инициализации создаётся главный объект вашего сценария return sparkLE2(c_instance)
Другой файл содержит сам сценарий. Он должен иметь такое имя, которое было использовано во время импорта в файл __init__.py. Сценарий, приведённый ниже, не делает НИЧЕГО, но соответствует всем требованиям к работающему сценарию.
# Для совместимости с Live 9. Необходимо писать в первой строке сценария. from __future__ import with_statement import Live # импортируется модуль Live, чтобы можно было использовать его содержимое from _Framework.ControlSurface import ControlSurface # импортируется модуль ControlSurface # описывается главный класс — потомок базового класса ControlSurface class sparkLE2(ControlSurface): __module__ = __name__ # тут хранится имя класса __doc__ = "Sparkle function" # тут хранится документация # конструктор класса (вызывается при создании объекта этого класса) def __init__(self, c_instance): # вызывается конструктор класса-родителя (ControlSurface) ControlSurface.__init__(self, c_instance) # не знаю, зачем это используется, но так требуется в сценариях для Live 9 with self.component_guard(): self.__c_instance = c_instance
Вот и всё! Вы создали свой первый бесполезный сценарий.
Как отлаживать сценарий?
Чтобы увидеть эффект после изменения сценария, вы должны закрыть и снова открыть Live (Notepad++ при этом закрывать не обязательно). Для отладки сценария вы можете использовать файл регистрации (журнал), создаваемый Live. Этот файл можно найти здесь (Windows):
C:\Users\Raztua\AppData\Roaming\Ableton\Live 9.1\Preferences\Log.txt
Все ошибки регистрируются в этом файле. Для контроля выполнения сценария вы можете использовать два метода (функции):
- self.show_message('ваше сообщение') # выводит текст в строке состояния Live
- self._log_message('ваше сообщение') # оставляет сообщение в журнале
Привет, мир
Чтобы сделать этот классический пример, мы добавим в класс метод, который напишет «Привет, мир» в журнале и в строке состояния. Этот метод будет вызываться во время создания главного объекта.
from __future__ import with_statement import Live from _Framework.ControlSurface import ControlSurface class sparkLE2(ControlSurface): __module__ = __name__ __doc__ = "Sparkle function" def __init__(self, c_instance): ControlSurface.__init__(self, c_instance) with self.component_guard(): self.__c_instance = c_instance # вызывает метод «helloworld» во время создания главного объекта self.helloworld() # описываем метод «helloworld» def helloworld(self) # (у методов класса в Питоне принято всегда указывать аргумент «self») self.log_message('helloworld') self.show_message('helloworld')
Отправка и получение MIDI
Отправка MIDI
Мой SparkLE использует только сообщения MIDI Note при «общении» с компьютером (он также использует SysEx, но я не буду говорить об этом). Сообщения MIDI Note — это последовательность (в терминологии Питона — кортеж) из трёх целых чисел. Например, (144, 60, 10) — это клавиша C3 (До малой октавы, значение 60), которая нажата (значение 144) на канале 0 со скоростью 100. Первое число говорит о двух параметрах: клавиша нажата (сообщение note on — это значение 144) на первом канале (каналы нумеруются от 0 до 15)
- 144 + 0 = 144
Если я захочу отправить сообщение note off (значение 128) для клавиши C3 на втором канале, я должен буду отправить последовательность (128 + 1 = 129, 60, 0)
Я буду использовать только сообщения note on и note off, чтобы зажигать светодиоды на контроллере. Функция, использующаяся для отправки MIDI-сообщений, это self._send_midi(<отправляемый кортеж>).
Получение MIDI
Существует два способа получить MIDI-сообщение:
1. Косвенно. Если вы не программируете что-либо на контроллере относительно этой кнопки, она будет автоматически сопоставлена с Live. Следующая часть сценария позволяет использовать автоматическое сопоставление из Live.
- def build_midi_map(self, midi_map_handle):
- ControlSurface.build_midi_map(self, midi_map_handle)
2. Явно. Если вы хотите выполнять определённые действия, когда клавиша нажата, вы должны явно направить сообщение и использовать метод «.add_value_listener» следующим образом:
- <ButtonElement>.add_value_listener('действия для выполнения по нажатию клавиши', identify_sender = True)
Создание элемента кнопки (ButtonElement)
Для того, чтобы использовать кнопку контроллера в сценарии, вы должны импортировать класс ButtonElement. Чтобы использовать константы, связанные с MIDI-нотами и сообщениями CC (control change), необходимо импортировать модуль InputControlElement. В начале сценария мы добавим:
- from _Framework.ButtonElement import ButtonElement
- from _Framework.InputControlElement import *
Затем мы создадим элемент кнопки, связанный с одной из клавиш (pad) контроллера (в моём случае — площадка 50). Это запишется следующим образом:
- self.pad = ButtonElement(not IS_MOMENTARY, MIDI_NOTE_TYPE, 0, 18)
Практический пример
Целью этого примера является создание сценария, который будет подсвечивать площадку 61 и записывать в журнал строку «HelloWorld» при нажатии на площадку 60.
from __future__ import with_statement import Live from _Framework.ControlSurface import ControlSurface from _Framework.ButtonElement import ButtonElement from _Framework.InputControlElement import * IS_MOMENTARY = True class sparkLE2(ControlSurface): __module__ = __name__ __doc__ = "Sparkle function" def __init__(self, c_instance): ControlSurface.__init__(self, c_instance) with self.component_guard(): self.__c_instance = c_instance self.show_message('Script initiated') # Создаём объект ButtonElement и задаём ему имя Pad1. Значение IS_MOMENTARY является истиной. # Это означает, что кнопка будет отправлять сообщение не только при нажатии, но и при отжатии. self.Pad1 = ButtonElement(IS_MOMENTARY, MIDI_NOTE_TYPE, 0, 60) # Добавляем слушателя значения — метод self.helloworld. # Этот метод будет вызываться при каждом нажатии Pad1. self.Pad1.add_value_listener(self.helloworld, identify_sender = False) # этот метод Live вызывает автоматически, когда контроллер будет отключен def disconnect(self): self.turn_led_off(60) self.turn_led_off(61) def helloworld(self, value): # value — значение, передаваемое кнопкой контроллера if value > 0: # value > 0, когда площадка находится в нажатом состоянии self.log_message(self, 'hello world') self.turn_led_on(61) else: self.turn_led_off(61) def turn_led_on(self, value): self._send_midi((144, value, 64)) def turn_led_off(self, value): self._send_midi((128, value, 64))
Слоты клипов, клипы и ноты
К текущему сету (song) можно обратиться с помощью метода:
- self.actual_song = Live.Application.get_application().get_document()
Этот метод даёт доступ к дорожкам, клипам и другим элементам сета.
Создание клипа
Чтобы выбрать первый слот на первой дорожке, нужно написать следующее:
- self.first_clipslot = self.actual_song.tracks[0].clip_slots[0]
Создадим клип в этом слоте:
- self.first_clipslot.create_clip(length)
Добавление нот
Добавим ноту в клип (например, C3 на втором такте длиной в половину такта и скоростью 64):
- self.first_clip = self.first_clipslot.clip
- # аргументом должен быть кортеж кортежей вида ((нота, начало, длина, скорость, отключена),)
- self.first_clip.set_notes(((60, 1.0, 0.5, 64, False),))
Доступ к нотам и их удаление
Чтобы получить все ноты из диапазона от C3 до C4 между первым и 1.5 тактом, запишем следующее:
- # аргументы: начальный такт, основная нота, длина выбора, диапазон нот
- self.first_clip.get_notes(1.0, 60, 0.5, 2)
Чтобы удалить все ноты из диапазона от C3 до C4 между первым и 1.5 тактом, запишем следующее:
- # аргументы: начальный такт, основная нота, длина выбора, диапазон нот
- self.first_clip.remove_notes(1.0, 60, 0.5, 2)
Режим сессии
Сессии представляют собой группы клипов, которые отображаются в Live цветными рамками (rings). Цель данного сценария — использовать мои площадки 50 и 51 для перемещения сессии влево и вправо.
from __future__ import with_statement import Live from _Framework.ControlSurface import ControlSurface from _Framework.ButtonElement import ButtonElement from _Framework.InputControlElement import * # этот компонент будет использоваться для создания сессии from _Framework.SessionComponent import SessionComponent IS_MOMENTARY = True class sparkLE2(ControlSurface): __module__ = __name__ __doc__ = "Sparkle function" def __init__(self, c_instance): ControlSurface.__init__(self, c_instance) with self.component_guard(): self.__c_instance = c_instance # создаём объекты для площадок self.Pad_left = ButtonElement(IS_MOMENTARY, MIDI_NOTE_TYPE, 0, 60) self.Pad_right = ButtonElement(IS_MOMENTARY, MIDI_NOTE_TYPE, 0, 61) self.create_session_control() # создаём сессию (описание метода ниже) # связываем сессию с главным объектом — появляется рамка self.set_highlighting_session_component(self.Session) def create_session_control(self): width = 1 # ширина сессии height = 8 # высота сессии # здесь создаётся сессия, которой назначается имя «Session» self.Session = SessionComponent(width, height) self.Session.set_offsets(0, 0) # смещение от верхнего левого угла (дорожка1, сцена1) self.Session._do_show_highlight() # для того, чтобы у сессии могла появиться рамка # назначаем кнопки для перемещения сессии self.Session.set_track_bank_buttons(self.Pad_right, self.Pad_left)
Автор: Raztua
Декабрь, 2013 г.
Перевод: Владимир Зевахин
Февраль, 2015 г.
Комментариев нет:
Отправить комментарий