Raztua
Использование сценариев 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 г.

Оригинальные посты на официальном форуме Ableton

Комментариев нет:

Отправить комментарий