Оно компилируется, работает, и позволяет заглянуть в потроха MIDI файлов.
Правда, оно написано но новой модной версии С++, позволяющей удивительные (для старого меня) конструкции — см. рис. 1. И требующей установить компилятор clang.
Понятно, придётся всё это адаптировать к ардуиновскому С++. Но пока я считаю, что это самый короткий путь для меня чтобы получить код, сканирующий любой MIDI файл и позволяюший мне узнать про этот файл всё, что мне надо.
Отдельное удивление вызвал факт, что программа LMMS (которую я использую для создания MIDI файлов) задаёт темп воспроизведения не в заголовке MIDI файла (как я ожидал после изучения формата MIDI файлов), а с помощью МЕТА-команды. Это несколько усложняет дело, но уже хорошо, что я знаю, как там задаётся темп на самом деле.
Ну, в общем, худшие подозрения оправдались: там нет никакого такого поля в заголовке файла, в котором бы были указаны номера использованных каналов. В MIDI файлах хранится тупо поток MIDI команд, которые «как есть» отправляются в синтезатор. А номер MIDI-канала, как известно, является частью статус-байта каждой команды. Т.е. придётся перебирать все команды (точнее все статус-байты) в записанном потоке, чтобы составить список используемых каналов. Это всё для того, чтобы проверять, что MIDI-каналы, использованные в файле авто-аккомпанемента, не пересекаются с каналами, связанными с клавиатурами баяна. (В первой версии буду просто проверять, что всегда используется 10-й канал, т.е. стандартный канал ударных инструментов.)
Осталось либо найти готовую библиотеку чтение MIDI файлов, либо писать собственный сканер. Но поиск таких библиотек — это уже будет задача на следующий вечер.
Алгоритм простейший: перебираем все 128 каналов по очереди, смотрим в каких каналах есть активность. Берём самое большое обнаруженное «окно» и выбираем канал, находящийся в самой середине этого окна. Само собой, всё происходит без участия человека.
Выбором канала будет заниматься передатчик (т.е. баян).
По моей задумке, после того, как канал для передачи выбран, передатчик начнёт в этом канале посылать спец-сигнал. А приёмник при включении будет сканировать все каналы в поисках этого сигнала. В результате должно получиться выбрать свободный канал и установить связь совсем без участия человека.
В общем-то, можно начинать писать прошивку приемника, который будет принимать байтики из баяна и отправлять их в MIDI порт.
И начать надо с алогритма поиска свободного канала (на стороне передатчика) и автоматического поиска передатчика на всех каналах (на стороне приемника). Не хочу вручную каналы связи задавать; пусть само трудится.
Те мелодии, которые встроены сейчас в прошивку v1.00, — это по сути последовательность миди-команд. Раз уж у нас будет контроллер, в котором дофига памяти, почему бы не читать MIDI-файлы с флешки?
Теоретически, можно будет вообще любые «минусовки» проигрывать, не только партию ударных.
Здесь показываю упомянутый ранее новый способ выбора инструмента.
В целом, этот экран повторяет тот же самый интерфейс, который используется в самом синтезаторе ATEMP. Можно перебирать группы инструментов, а потом выбирать инструмент внутри группы. Или же просто продолжая нажимать стрелки вправо-влево можно перебрать вообще все звуки, которые реализованы в синтезаторе.
Мне не нравится, как сейчас в текущей версии прошивки происходит выбор инструментов. Если для какого-то инструмента (номера программы в терминах MIDI) есть варианты звучания (разные «банки», переключаемые MIDI командой CC 0 vv), то надо сначала выбрать номер инструмента, а потом перебирать все доступные для него варианты звучания. И при этом видишь только номера инструментов и номера вариантов; очень много нажатий кнопок (даже в адаптированном к синтезатору варианте) и совершенно никакой наглядности.
Делаю экспериментальный вариант спец-экрана для выбора инструмента. Будет два селектора: «группа инструментов» (пианино, электронные пианино, органы, гитары, и т.п.) и «инструмент внутри группы». И чтобы перебирались не номера, которые фиг запомнишь, а нормальные названия групп и инструментов (текстом).
И беда пришла , откуда не ждал. Я, ни в чём себе не отказывая, добавил все названия всех групп инструментов на руссском, каждое название длиной до 20 символов (ширина экрана). И прошивка перестала влезать во флеш-память. 🙁 Там оставалось свободным примерно 6 килобайт флеш-памяти, и табличка с текстом заняла их все, и даже больше.
Пришлось утоптать тексты: ограничил длину названий 15-ю символами и, главное, перевёл всё обратно на английский. В результате осталось свободным примерно 2 килобайта флеша.
Этого достаточно для добавления поддержки одного синтезатора, но недостаточно для дальнейшего развития, когда понадобится поддерживать несколько синтезаторов. Ну и объём кода тоже наверняка увеличится ещё.
А значит надо менять платформу.
Изучив варианты, я думаю, что остановлюсь на RP2040-Zero (см. рис. 1). Там 2 процессора, 264 кб ОЗУ, 2 Мб флеша. И оно давно поддерживается средой Arduino IDE. У меня есть одна внешняя зависимость: библиотека подержки OLED экрана GyverOLED; так вот она, вроде, нормально компилится для RP2040 (работу пока проверить не на чем). Т.е. переход вполне реален. Надо заказать пару контроллеров и слепить прототипчик.
Там, правда, нет встроенной EEPROM памяти. И это жирный минус. Придётся лепить внешнюю микросхему AT24C256. Но это решаемо.
Проект MIDI-баяна я опубликовал ранее, а сегодня я туда добавил коротенький видео-обзор. (Лишний раз убедился, что видео-блогер из меня не получится. Для выступлений перед камерой нужна спец-привычка, чтобы с одной стороны не тупить, а с другой стороны всё говорить правильно с первого раза.)
Но тем не менее, из непродолжительной эксплуатации инструмента я уже сделал несколько выводов.
Во-первых, надо добавить режим Portamento (если он нормально поддерживается моим синтезатором). Для этого нужна будет одна дополнительная настройка в списке параметров звука. Это не проблема. Но нужна будет ещё кнопка активации этого самого режима; без кнопки нехорошо. И единственный способ организовать такую кнопку — это сделать программируемые кнопки быстрого доступа к настройкам ещё более многофункциональными: чтобы можно было их переключать в разные режимы работы специальной системной настройкой. Т.е., например, кнопка F4 может быть настроена либо как кнопка быстрого доступа, либо как кнопка активации режима Portamento. Общая идея, как такое можно сделать, у меня уже есть. Но программирования там будет довольно много, больше, чем на 1 вечер.
Во-вторых, режим работы «активного меха» (т.е. датчика давления) надо делать частью данных пресета. Потому что для одних инструментов (аккордеон, орган, и может ещё какие-то) регулировка громкости мехом звучит очень органично, а, например, для фортепиано или гитары — не звучит совсем. Это тоже понятно как делать, и работы там очень немного.
В-третьих, с активным мехом не получается сделать резкий акцент (атаку), как на настоящей пневматике. Тремоло мехом тоже совершенно не звучит. Думаю, дело в том, что измерения с датчика берутся слишком редко. Сейчас там настроено 20 раз в секунду, но похоже, надо снимать показания чаще, т.к. за секунду в режиме тремоло можно мехом дёрнуть туда-сюда 6-8 раз. И если учесть, что данные с датчика фильтруются (фильтр «экспоненциальное бегущее среднее»), то данные с датчика просто не успевают за мехом.
В-четвёртых, хочется сделать «инженерное меню», в котором задавать как частоту опроса датчика давления, так и параметры фильтрации. Если делать «тяп-ляп», то там говно вопрос, можно всё сделать за вечер. Но тот вариант «тяп-ляп», который у меня сейчас в голове, будет некрасив архитектурно. Надо придумать «красивый» вариант.
В-пятых, четырёх кнопок быстрого доступа явно мало. Надо бы расширить их количество. И я уже понимаю, как. Нужно будет научить прошивку различать однократное, двойное, тройное и т.д. нажатия кнопок быстрого доступа. (Думаю, что пока можно будет остановиться на тройном). Это я тоже понимаю, как сделать. Но там работы тоже много, примерно на недельку, если вечерами.
В-шестых, я в первой версии прошивки тупанул, и использовал 32-разрядные счётчики таймеров, хотя вполне хватило бы 16-разрядных. Надо будет переделать. (И тем самым сэкономить примерно 60 байтов ОЗУ).
Продолжаю накапливать идеи для реализации во второй версии прошивки.
Во время завершающего этапа сборки MIDI-баяна я сделал пару фотографий. Вижу смысл поделиться сопутствующими деталями.
Для проверки того, насколько хорошо уложены жгуты проводов, мне пришлось снять заднюю декоративную крышку (см. рис. 1). Воспользовался случаем, чтобы показать, как устранено провисание платы датчиков 3-го ряда. На самой плате я так сильно, как только мог, затянул пластиковые стяжки. И за образовавшиеся петли подтянул плату к металлическим распоркам.
Рис. 1
Последней операцией по герметизации правого полукорпуса было закрепление MIDI гнезда. Сами гнёзда я герметизировал ранее. А сейчас обмазал MIDI гнездо снаружи силиконовым герметиком и установил его на место. Раньше я думал, что надо это гнездо фиксировать на термоклей изнутри. Но сейчас подумал, что усилие при выдёргивании MIDI провода там довольно большое, поэтому всё-таки просверлил 2 отверстия Ø3 мм и закрепил гнездо винтами М3. В просверленные отверстия винты вошли очень плотно; пришлось их даже вкручивать. Ну и затянул я их на совесть. Теперь гнездо держится сверх-надёжно.
Рис. 2
Ну и припаял плату панели управления к проводам, продетым в отверстие в декоративной решётке (см. рис. 3 и 4). В результате конструкция получилась «плохо разборная», но частые разборки этого всего и не планируются. А если всё-таки придётся отделять панель управления, то отпаивать провода от платы я уже не буду, а вместо этого разрежу провода, предварительно их пометив.