REAPER КРУТ! Показ аккордов и текстов песен в реальном времени в браузере (через веб-сокеты)
В ходе подготовки к концерту появилась необходимость показывать тексты песен и аккорды во время репетиций. Конечно, можно было бы всё распечатать, и мы, собственно, так и сделали, но когда новые люди изучают новые песни, порой непонятно сколько времени нужно держать аккорд, какая сейчас строчка (особенно когда вокалиста нет на репе), что будет дальше и т.д. Поэтому было решено разработать небольшую автоматическую систему для показа и текста, и аккордов, и их длительностей. А как бонус, текущую строку текста песни можно выводить зрителям в зале на экран, и зрителям в трансляции в другой позиции и с другим оформлением, и также вокалистам или музыкантам на stage-мониторы перед сценой или на или планшеты/телефоны. И всё это в REAPER, и всё это автоматически! 🤯
Ниже рассказываю как это реализовано и как этим всем воспользоваться, так что добро пожаловать под кат 😉
Вот небольшое оглавление для удобства и возможности быстрого перехода:
- Причины и что вообще побудило к созданию этой системы
- Возможности системы
- Как всё работает
- Скачать, настроить, использовать
Причины и что вообще побудило к созданию этой системы
Обычно текст песен на экране показывается совершенно разными способами, начиная от ручного прокручивания первого попавшегося сайта или показа презентации в PowerPoint с заранее заготовленными слайдиками и заканчивая профессиональными программами по типу ProPresenter. Но каждый из этих способов требует наличия человека, причём, довольно-таки внимательного)) А как часто бывает, что человека отвлекут, либо он плохо знает песню и поэтому пропускает момент переключения… )
Более продвинутый вариант — автоматизировать переключение слайдов и/или фоновых видосов в ProPresenter, передавая миди-сообщения из DAW через midi-loopback или по сети. Такое тоже имеет место быть, и в нашей ситуации я даже начинал создавать тексты песен в том же ProPresenter, и даже настроил переключение слайдов по midi, но всё это как-то не то… не так эпично что ль 🙂 Да и вопрос с показом аккордов тоже оставался открытым. И не давала покоя мысль ещё больше автоматизировать это дело… Несколько вечеров, и готово! И самим хорошо, и с остальными поделиться можно, ведь если это понадобилось мне, скорей всего кому-то тоже может понадобиться, как показывает практика )
Единственный минус: всё завязано на REAPER, но рипер крут, и как бы почему бы и нет, если у нас (да и у много кого ещё) всё и так работает через него (и плейбэки, и метроном, и гайды, и управление светом, и т.д.).
Возможности системы
Ниже небольшое видео (без звука), где:
- запуск скрипта в REAPER (скрипт добавить надо, он в комплекте с программой идёт)
- запуск программы проксирования
- видно красивое меню, которое «раздаёт» эта самая программа (файлики хранятся в открытом виде, обычные html файлы)
- демонстрация показа аккордов, и прокручиваемого текста. Всё открыто в двух сгруппированных вкладках браузера для показа одновременной работы разных разделов (на самом деле весьма удобно видеть и текст, и аккорды сразу)
На входе встречает красивое меню, где можно выбрать нужный раздел:
- Chords — аккорды. Показываются как просто списком на экранах побольше, так и просто прокручиваемые аккорды на экранах поменьше. Внизу пишется также название текущего трека (берётся из региона), время на таймлайне и BPM, а также показывается текущий статус: воспроизведение, пауза, стоп. Блоки с аккордами имеют разную высоту, что соответствует их длительности. Сразу наглядно видно как долго держать аккорд, но на всякий случай пишется ещё и время (в секундах) и количество ударов метронома для каждого аккорда, типа 12/4 или 2/4. Имеется возможность приблизить, отдалить, отцентрировать (если прокрутили вдруг) и переключиться в полноэкранный режим.
- Lyrics — текущая строка текста. Это может пригодиться для вывода на экран в зале или в трансляцию. Обычная веб-страница, которая в реальном времени получает и показывает текущий текст, а при вставке в OBS, vMix или другие программы можно подстроить внешний вид, убрать фон, изменить размер и т.д. А если есть возможность подредактировать CSS стили (как в том же OBS), то можно ещё и шрифт поменять и ещё там эффектов на текст накинуть при необходимости. Но вообще, исходный код всех страниц открыт, так что можно менять на своё усмотрение, добавлять свои страницы и пункты в меню, но об этом ниже 😉
- Scroll Lyrics — прокручиваемый текст. А вот это уже больше подходит для stage-монитора для вокалиста, чтоб не только текущую строчку видел, но и следующие тоже заранее мог подсмотреть. Хотя в любом случае текст нужно показывать не в тот самый момент, когда он пропевается, а чуть заранее, но тут уже по своим нуждам тоже можно настроить всё и располагать тексты где нужно на таймлайне рипера, ведь именно оттуда берётся текст, но об этом позже)
В этом режиме можно в URL добавить параметр?vignette, и тогда вокруг текущей подсвечиваемой строки появится виньетка, чтоб сфокусироваться на главном 🙂
А начинается всё с захода на IP адрес или на rc.reaper.fm/ИМЯ, где запущена программа-прокси для рипера, которая и позволяет всей этой системе более оптимально работать без лишних запросов, но подробней об этом в следующем разделе — как это всё работает)
А позже был создан сервис https://r.qofa.ru — аналог rc.reaper.fm, только без указания имени, ведь оно не нужно, когда есть единая точка входа с меню
Как всё работает
REAPER крут тем, что поддерживает разные контроллеры, а также управление по MIDI и OSC. Но ещё более крут он тем, что у него есть встроенный веб-интерфейс с неплохими дефолтными страницами, через которые можно и дорожками управлять, и мониторингом, и визуальный клик иметь, и ещё там что-то 🤩
(всё это находится в настройках, в Control/OSC/web)
Также есть замечательное расширение ReaPack, позволяющее прям из рипера ставить дополнительные скрипты, разрабатываемые сообществом, и также можно подключать дополнительные репозитории, и ставить ещё больше всяких скриптов… В общем, не зря есть шутка, что в рипере пишут не музыку, а скрипты 😅
За основу были взяты скрипты и интерфейсы от замечательного автора X-Raym, у которого очень много разработок на все случаи жизни:
Но не было ничего для показа аккордов. Да и изучив работу текущих скриптов и как вообще происходит общение с рипером, я немного поразился… Только представьте: каждые 10 миллисекунд идёт обращение к риперу за получением информации! Это 10 раз в секунду! А, минутку… Речь идёт о JS1, так что это 100 раз в секунду 👀
Со стороны рипера нужно запустить скрипт, который найдёт дорожку с текстом или возьмёт выделенную дорожку, найдёт на ней все текстовые item-ы (это такие специальные элементы в рипере, просто для заметок, в них даже картинки можно засовывать), преобразует это в json формат и сохранит в EXTSTATE (ссыль на документацию REAPER API). А затем со стороны веб-интерфейса (который сначала нужно в любом случае настроить, выбрав порт и страницу), идёт обращение к риперу для получения готового JSON с позициями и текстами, а потом 100 раз в секунду запрашивается текущая позиция курсора воспроизведения, чтоб показывать текст, соответствующий нужному времени.
По такому же принципу я сделал Lua-скрипт-модуль для рипера, который ищет дорожку с названием Chords (регистр не важен), забирает её текстовые элементы, сохраняет тоже в extstate под своим ключом, и потом это всё красиво рисуется на веб-страничке, но ещё и с компенсацией сетевой задержки, потому что нужно было добиться максимального совпадения кликов метронома в ушах и включения аккордов, это важно!
Именно таким образом вся эта система работала какое-то время, но было замечено, что веб-сервер, встроенный в REAPER, не справляется, если одновременно несколько клиентов пытаются получить данные. Даже уменьшение частоты запросов не сильно помогло, а ещё нужно было для каждой отдельной страницы (для аккордов, текста и прокручиваемого текста) настраивать отдельный веб-интерфейс и давать ему отдельное имя для rc.reaper.fm. Конечно же можно было не настраивать отдельно всё это, и в любом настроенном веб-интерфейсе просто написать имя нужной страницы, но это ещё сложней, ведь названия там непростые… Ладно, не суть)
💡 В голову пришла идея накатать по-быстрому свой прокси-сервер, который с одной стороны будет обращаться к риперу в единственном экземпляре со своим интервалом, а с другой стороны будет раздавать полученную информацию подключенным клиентам, сколько бы их не было. Сказано — сделано!
На Go написан веб-сервер с поддержкой веб-сокетов2, и получилось довольно универсально, ведь:
- можно переопределить свою главную страницу, в которой теперь красивое меню (на самом деле, можно и в риперовские страницы это засунуть)
- можно добавить остальные нужные страницы, подправить их под свои нужды
- можно переопределить файл main.js, в котором есть базовые функции для связи с рипером (по AJAX3), этот файл взят из стандартной поставки рипера и доработан. Удалось поменять всё так, что если есть поддержка веб-сокетов, то будут использованы именно веб-сокеты, а если нет, то будет по-старому работать. Поэтому с точки зрения использования этих функций ничего не изменилось, можно даже не сильно переписывать используемые страницы
- веб-сервер работает так: сначала ищет файл по точному пути, переданному в URL, потом пробует
имя + .html, потом пробуетимя/index.html, а если и это не найдено, то запрос проксируется в рипер без изменений. Таким образом можно накидывать своих красивостей, не теряя при этом возможности дёргать рипер напрямую, вызывая его API-функции или запрашивая какие-то данные - все получаемые от рипера данные этот веб-сервер на Go отправляет всем клиентам. Причём, не просто отправляет всё, а только изменившиеся части, что сокращает количество трафика. Можно было бы заморочиться и следить за тем, кто из клиентов что запрашивает, собирать это в единый запрос для рипера, а потом парсить ответы и отправлять клиентам только то, что нужно, каждому своё, но… на текущем этапе это уже перебор, к тому же, так уж вышло, что всем клиентам (тут я имею ввиду разные странички с разным функционалом) всегда нужно значение
TRANSPORT(отвечает за статус воспроизведения, текущую позицию и т.д.), а все остальные данные подгружаются при старте, поэтому это никак не мешает работе всего остального. Просто и гениально 🙂 - поддерживается также
rc.reaper.fm, можно задать своё имя, и тогда программа при старте отправит на сервера рипера информацию о своём локальном адресе, и тогда остальным клиентам, находящимся в этой же сети, не нужно будет узнавать IP адрес и порт для подключения к интерфейсу, а достаточно будет зайти наrc.reaper.fm/ws, и они попадут в интерфейс независимо от настроек сети и т.д. Вместоwsможно поставить своё имя, но по-умолчанию оно такое. Для реализации этой фичи пришлось немножко отреверсинжинирить общение рипера с этим внешним сервисом. Оказалось ничего сложного тоже, зато теперь как удобно заходить по постоянному адресу в интерфейс 🙂
(только для этого интернет нужен, но по IP адресу или внутреннему имени хоста заходить можно и без интернета) - по аналогии с rc.reaper.fm создан сервис https://r.qofa.ru, в котором не требуется указание имени, а в остальном принцип работы идентичен: в той же локальной сети, где запущена программа, можно перейти по адресу r.qofa.ru, а оттуда уже будет редирект на IP и порт, которые слушает программа. УДОБНО!
- на будущее сделана публикация в mDNS, чтоб можно было обнаружить этот сервис. Пока не используется, хотя прикольно, что оно есть и работает (ниже скриншот обнаружения с телефона через mDNS Discovery)
Программа кроссплатформенная, и если переопределить дефолтные настройки (-reaper-url), то можно подключаться к риперу, запущенному на другом устройстве, если вдруг нужно. Хотя обычно незачем, и работает всё шустро, памяти занимает тоже мало.
Пройдёмся немножко по некоторым настройкам:
- -addr — адрес и порт, которые будет слушать программа, куда будут обращаться остальные клиенты
- -poll-get-keys — тут можно перечислить (через точку с запятой) команды для рипера, которые периодически будут запрашиваться из рипера, а их результат публиковаться по веб-сокетам всем клиентам одновременно (вау!). Можно оставить по-умолчанию, там есть всё, что нужно для работы и аккордов, и текстов.
- -poll-interval — интервал запросов к риперу. 80 миллисекунд оказалось вполне достаточно и для текстов, и для комфортного показа аккордов (а чтоб аккорды не дёргались, есть небольшая инерция)
- -reaper-rc-name — имя для
rc.reaper.fm. По-умолчаниюws, но можно (и даже нужно) переопределить, иначе в лучшем случае, если кто-то, находясь в другой сети, запустит программу и переопределит свой адрес по этому же имени, то другой не сможет зайти, увидит весёлое сообщение, что сети разные) - -reaper-url — адрес настроенного веб-интерфейса в рипере (выбранная страница не важна). Можно на этом же компьютере, можно на другом, где он запущен. Если программа запускается там же, где и рипер, то можно указать
http://localhost:PORT, где port — это порт веб-интерфейса, настроенный в рипере. По-умолчанию указан порт8088, и именно на такой порт у меня настроен рипер, так что я даже не трогаю дефолтные настройки (хотя после публикации этой статьи как минимум дефолтное имя нужно будет переопределять, кажется :D). Если программа не сможет подключиться, она будет каждую секунду об этом упоминать в консоли, пытаясь переподключиться, ну, и работать всё остальное, соответственно, тоже не будет, пока не будет связи с рипером - -ws-path — это лучше не менять, это для работы веб-сокетов
- -www-root-path — указывается путь до статичных файлов из папки www, которая идёт в комплекте с программой. Без необходимости тоже лучше не менять, потому что просто незачем 🙂
Теперь можно использовать хоть десяток одновременно работающих клиентов, никто друг другу мешать не будет, главное, чтоб wi-fi сеть выдержала, но как показывает практика, на wi-fi 5 ГГц работает всё просто замечательно 🙂
Программа сама обращается к риперу с указанным интервалом, и все клиенты получают данные, не устраивая ddos атаку на рипер 😀
Протестирована одновременная работа с нескольких вкладок на компьютере, на планшете, на нескольких телефонах, на проекторе с Android (о, это вообще удобно! Или если телевизор с браузером, тоже да), и всё отработало хорошо)
Ещё немного про скрипты.
Ранее для работы всей системы приходилось запускать три отдельных скрипта в рипере, для чего прям в рипере на панельку были добавлены кнопочки для их запуска. Причём, для аккордов и прокручиваемого текста скрипты были разовые — запустил, они своё дело сделали и завершились. А для показа текущего текста скрипт работал постоянно в фоне, проверяя текущий элемент с текстом и сохраняя во всё тот же extstate нужные данные. Теперь же всё объединено в один скрипт, немного оптимизировано, поэтому теперь достаточно запускать лишь один единственный скрипт, который также идёт в комплекте. Чуть позже он будет выложен в репозиторий для ReaPack, но пока ручками, ничего сложного в этом нет 🙂
Так что теперь можно добавить лишь одну кнопочку для запуска скрипта. А даже если её не добавить, на странице с аккордами есть ссылка, нажатие на которую запускает нужный скрипт и всё начинает работать.
Как скачать и с чего начать
Если кратко, то:
- Скачать архив с программой и дополнительными файликами отсюда: https://github.com/karamush/reaper-ws-proxy/releases/latest (выбираем для своей операционной системы и архитектуры)
- Добавить дорожки в рипере (Lyrics и/или Chords). Названия должны совпадать, регистр не важен, но дорожки ищутся именно по названию
- Добавить на эти дорожки элементы (
Insert -> Empty item) и прописать в них аккорды и тексты на соответствующих дорожках, разместить элементы можно где нужно по времени и растянуть на сколько нужно - Добавить скрипт, назначить кнопку
- Запустить скрипт, запустить приложение, зайти по адресу, который выдаст приложение или по r.qofa.ru
Чуть более полно и наглядно уже написано в описании к репозиторию в пункте установка и ниже, так что можно глянуть там.
На этом пока что всё, но можно изучить страницу репозитория, там и демок побольше, и информации полезной тоже побольше, но статья в будущем ещё будет дополняться тоже)
- js или JavaScript — такой интересный язык программирования, где в одной секунде 1000 миллисекунд, а 2+2=22, а не 4 😀 ↩︎
- веб-сокеты — классная технология, позволяющая серверу самому отправлять данные клиенту, без необходимости клиенту постоянно дёргать сервер по ajax и спрашивать «ну чё там, есть чё???» ↩︎
- AJAX — Asynchronous Javascript and XML. Тоже классная технология, но не такая классная как веб-сокеты, но позволяет подгружать данные с сервера без перезагрузки страницы ↩︎








Добавить комментарий