Midi Clockwork

А сегодня мы предадимся прекрасной техноереси и построим АНАЛОГОВОЕ МИДИ.
Ну ладно, не такое уж аналоговое. Но без вычислений. Хорошо-хорошо. Объясню по порядку.
Однажды в “сборке” спросили, есть ли какой-то простой способ превратить аналоговый клок в Midi Sync. И действительно, когда речь заходит о подобных вещах, на ум приходят сразу огромные и не очень процессоры и многофункциональные конвертеры и всякое такое, которые далеко не всегда делают то что нужно, и естественно стоят как чугунный мост.
Конечно это решается какой-нибудь завалявшейся под ножкой дивана ардуино нано. в стиле:
INT0_ISR:
push r16
in r16, SREG
push r16
ldi r16, 0xF8
sts UDR0, r16
pop r16
out SREG, r16
pop r16
reti
Но это скуууууучно. и мы помещаем целый процессор для того чтобы воспроизвести один дрыг, по другому дрыгу извне.
Давайте решим это без лишних когитаторов в тракте.
Задача
Тезисно постановка задачи.
- Извне приходит клок.
- Выдаёт его аудиовыход.
- Формат настраивается, ну который ppqn.
- Длину импульса мы решительно не знаем.
- Наличие DC в сигнале неизвестно. Но выше 5в оно не прыгнет.
В итоге мы настраиваем клок на формат 24ppqn - то есть 24 импульса за одну четвёртую ноту (четверть), ровно так как это в миди работает. Поэтому всё что нам остаётся - это по импульсу сформировать и отправить сообщение по миди.
Посмотрим что мы имеем. Сообщение для отправки импульса синхронизации - 0xf8. Это сообщение реального времени, поэтому оно не зависит от контекста и может приходить всегда в окружении любых других байт. То есть можем слать его и не беспокоиться больше ни о чём.
Формат отправки байта по UART может быть разным. Но для миди всегда один и тот же стандарт. начинается передача со стартового бита - 0, Затем передаются биты нашего сообщения от младшего (LSB) к старшему (MSB) а затем идёт стоп-бит, и это 1. Наше сообщение в двоичной системе выглядит так 11111000.
Поэтому полностью кадр будет выглядеть вот так:
старт LSB 1 2 3 4 5 6 MSB стоп
┈┈┈┈┈┏━━━┳━━━┳━━━┳━━━┳━━━┳━━━┳━━━┳━━━┳━━━┳━━━┓┈┈┈┈┈
1 ┊ 1 ┃ 0 ┃ 0 ┃ 0 ┃ 0 ┃ 1 ┃ 1 ┃ 1 ┃ 1 ┃ 1 ┃ 1 ┃ 1 ┊ 1
┈┈┈┈┈┗━━━┻━━━┻━━━┻━━━┻━━━┻━━━┻━━━┻━━━┻━━━┻━━━┛┈┈┈┈┈
Линия в состоянии покоя тоже имеет значение 1. И это очень удачная конфигурация. Нам не придётся формировать нужный нам байт в сдвиговом регистре и выталкивать из него всё в линию. Всё что нам нужно это просадить линию на 4 такта на частоте миди 31250 Гц.
Но есть одна неприятная сложность. Нам нужно выдерживать на протяжении всех передач единый клок. А внешние импульсы могут приходить вообще когда угодно. Поэтому надо будет придумать как подстроиться и синхронизироваться.
Но давайте начнём решать задачу кусками. Разделяй и властвуй.
План
- Построим генератор частоты для миди - 31250Гц
- Приведём входящий импульс во что-то стандартное и понятное
- Отправка самого сообщения. просадим в нули линию выхода на 4 такта
- Построим схему синхронизации
- Сделаем миди выход. и оформим питание всей схемы
Генератор частоты миди
Это самое простое. Есть прекрасная микросхема 4060. Это счётчик и генератор импульсов. Она нам позволит взять какую-то частоту и поделить её счётчиком до нужной нам. Мы возьмём кварц на 2Мгц и поделим его на 64. Это 6й бит счётчика. Как раз наши 31250 Гц
Подключение стандартное:

Нормализация импульса.
Здесь нам надо сделать 3 вещи. Нормализовать длину импульса. Если он слишком длинный, то превратить его в “иголку”. Убрать лишнее DC если оно есть. Убрать выбросы отрицательного напряжения.
Первые две потребности закроет простой RC фильтр высоких частот. Его конденсатор будет так же действовать как блокировщик DC. А возможные всплески отрицательного напряжения заблокируем диодом.
И поровняем фронты инвертором. Обычно ставят буфер, или два инвертора. Но с инвертированным дальше будет работать проще.

Четыре нуля
Теперь сделаем блок, который отправляет 4 нуля в линию. Для этого нам понадобится классический десятичный счётчик. Заводим его с нашего клока 31250 Гц. А затем соединяем выход тройки Q3 с !CE. В такой конфигурации счётчик работает только когда на выходе не Q3. То есть он добегает с 0 до 3 и сам себя выключает. Но при этом остаётся возможность его сбросить через Reset. и он снова добежит до Q3 и остановится. Так и получаем наш выходной миди сигнал. Всегда единица. а после сброса 4 нуля.

Синхронизация
Это вообще любимая тема всей цифровой электроники. Если увидите грустного фпгашника, подойдите и обнимите его. Потому что наверняка там домены не сходятся и он очень устал.
Но у нас попроще. Всё что нужно сделать. это зафиксировать входной очищенный импульс. и на ближайший восходящий фронт нашего миди клока отправить сообщение. Решается парой D триггеров. один фиксирует факт пришедшего сигнала, включает второй триггер, который по фронту нашего миди клока дёргает счётчик за сброс, а инвертированным сигналом сбрасывает первый D триггер в режим ожидания. И именно для них нам нужен инверсный импульс, потому что у стандартных D триггеров инвертированные входы Set и Reset.

Выход и питание
На этом вся схема готова. осталось только правильно буферизовать выход. Мы использовали всего 1 инвертор и у нас их осталось 5 штук ещё.
Минималистичный сценарий: парой инвертеров буферизуем сигнал. Входы оставшихся трёх, обязательно подтягиваем или к земле или к питанию.

Но если нужно раздавать этот клок на несколько устройств сразу, то можно сделать до 4х выходов вот так.

По питанию. нужно 5в. Брать где угодно хоть с линк порта геймбоя хоть с usb. И обязательно как можно ближе к ногам питания каждой микросхемы повесить мелкий конденсатор.

Вот и всё.
Собрал симуляцию этой схемы в falstad‘е