Realtime MIDI Player
- Войдите на сайт для отправки комментариев
Режим самоизоляции позволил уделить время многим проектам, которые были в планах, но до которых хронически не доходили руки.
Хронологически первым оказался проект MIDI-box - устройства, позволяющего либо формировать поток MIDI команд, либо добавлять свои MIDI команды к существующему потоку. http://arduino.ru/forum/proekty/midi-boxmidi-sintezator
Вероятно, этот же проект окажется и хронологически последним. По крайней мере, в процессе его реализации возникали и возникают новые идеи и новые проекты, способствующие его продвижению либо достаточно обособленные части, допускающие самостоятельную публикацию.
Первая из таких публикаций (кроме основной) - разработанный для этого проекта класс меню:
http://arduino.ru/forum/proekty/menyu-dlya-dvukhstrochnogo-displeya
Следующим является настоящий проект.
Но в планах присутствует еще парочка.
Вопрос - как долго еще продлится самоизоляция...
В процессе работы над проектом MIDI-box, подразумевающем как принятие и анализ входного потока команд, так и формирование выходного, вдруг внезапно обнаружился недостаток устройств, которые могли бы создавать нужный входной поток либо принимать выходной.
Собственно, в наличии присутствовали только MIDI клавиатура и компьютер. Компьютер, конечно, устройство довольно универсальное. Особенно, если на нем не только пользоваться общеупотребительным софтом, но и писать свой. Но все равно не слишком удобное.
Поэтому возникла идея параллельной разработки еще двух устройств:
- автономного проигрывателя MIDI-файлов, которое, в отличие от аналогичных устройств, на выходе давало бы не Audio, а MIDI,
- автономного проигрывателя реалтаймового потока MIDI команд, которое на входе получало бы MIDI, а на выходе давало Audio.
Т.е. вместо стандартного одного устройства MIDI-файл->Audio для наладки аппаратуры должно быть два разных: MIDI-файл->Realtime MIDI и Realtime MIDI->Audio.
Прикинув, что второе намного проще, именно с него решил и начать.
За основу был выбран ардуиновский шилд MP3 проигрывателя на VS1053B. Собственно, особенностью данного контроллера является то, что он проектировался для проигрывания не только MP3, но и множества других, в числе которых *.mid. А если загрузить в него небольшую программу, то он способен воспроизводить и раелтаймовое MIDI. Эта программа (в двоичных кодах) в И-нете была найдена.
Реалтаймовый проигрыватель, собранный на макетке
Правда следует сказать, что конструкторы шилда разрабатывали его исключительно для MP3, поэтому даже не потрудились вывести наружу последовательный порт, по которому передается стандартный MIDI сигнал. Пришлось, так же как и программу в кодах, передавать его через SPI, причем, с некоторыми изменениями протокола.
Я думаю, каждый компьютерщик на том или ином отрезке своей бурной жизни предпринимал попытки разгона компьютера. Были модели, которые удавалось разгонять в полтора раза и более, но обычно эффект не превосходил 20-30%. А чип VS1053B допускает разгон штатными средствами в 5 раз, причем в 4.5 раза его допускается разгонять в долговременном режиме. А для MIDI это важно. Ведь декодирование MP3 - это всего два стереоканала. В терминологии музыки - две ноты. Ну, еще постобработка - пусть вдвое тяжелее декодирования, т.е. порядка 6 "голых" нот без постобработки. А если разогнать в 4.5 раза, то уже получится 27 "голых" нот или 23 ноты с постобработкой смикшированного сигнала (цифры, конечно, очень условные, верно показаны лишь порядки величин и общая тенденция). При простом же воспроизведении MP3 файлов нужды в разгоне нет, и чип VS1052B таким образом экономит питание, т.к. он предназначен для работы в том числе и в портативных проигрывателях.
Собственно, вопрос этот возник по попытке воспроизвести на VS1053B оркестрового MIDI файла: значительную часть нот синтезатор просто проглатывал. Разгон исправил ситуацию. Поэтому было решено режим разгона сделать основным режимом устройства, для чего найденную в И-нете последовательность команд пришлось дополнить еще и дополнительными командами разгона - от себя лично.
устройство было собрано на заготовке ардуиновского шилда и куске макетки для пайки
Ардуиновские шилды имеют ряд неприятных особенностей. Одну из них я уже упоминал - наружу выведены далеко не все нужные сигналы. Другая - все приводится к 5-вольтовым уровням. Т.е. если я работаю с 3.3-вольтовым контроллером, то должен заботиться о сопряжении с преобразователями уровня, которые стоят между 3.3-вольтовым ведомым устройством и внешним разъемом шилда, выдавая наружу 5 Вольт.
Собственно, для конструкции решено было использовать Blue Pill, т.к. при цене где-то между Arduino MINI и arduino NANO он имеет полноценные как USB, так и Serial. И уж намного дешевле Arduino Micro или Leonardo, имеющими нужные порты. Не говоря о Меге, которая озадачивает еще и размерами.
Так вот, только часть ножек Blue Pill толерантна к 5 В. А в проекте нужно было одновременно использовать Serial, SPI и I2C. Первый - для приема MIDI сигнала, второй - для управления VS1053B, а третий - для отображения на дисплее последних пришедших команд (тоже очень полезно для отладки MIDI аппаратуры). Так что выбор подходящей комбинации оказался не слишком широким.
Вот тут и пришла засада. Сначала собрал и заставил работать все на макетке. Потом - начал разводить плату. Когда я четверть века назад занимался аналоговой техникой, вполне спокойно разводил и травил однослойные платы. При первых же опытах с цифровой (еще в то время) обнаружил, что одного слоя для цифровых устройств явно недостаточно. Ну а с появлением современных мелковыводных деталей рисовать от руки дорожки лаком для ногтей и вовсе оказалось нереальным (с учетом "изменившегося" за последние четверть века зрения). Поэтому сейчас для всех конструкций использую исключиетльно макетки для пайки (или заготовки ардуиновских шилдов, без которых трудно, т.к. "отцы основатели" позаботились о нестандартном расположении контактов).
Так вот, о засаде: в процессе разводки платы оказалось, что гораздо удобнее изменить комбинацию интерфейсов. Хорошо, решил опробовать это, не разбирая макет, просто переткнув провода. Полдня бился, но так и не сумел заставить работать устройство в новой конфигурации. Решил, что утро вечера мудренее и отложил разбирательство на завтра. Конечно, быстрее, проще и дешевле было бы отказаться от идеи переназначения - распаять три лишних провода не весть какая работа, но тут - дело принципа: надо же разобраться!
Вечером перед сном имею тенденцию почитать, что пишут в И-нете. Ну и заодно решил провентилировать возникший вопрос. На одном из англоязычных форумов обнаружил ссылку на errata по похожему случаю, цитирую последнюю:
Да уж...
Предыдущий пост отправлен 8 мая, код дописан 9 мая, а до того, чтобы завершить публикацию, руки все не доходят.
Итак, схема:
AUDIO OUT - это 3.5 мм гнездо, расположенное на шилде аппаратного синтезатора VS1053B.
Код для последнего - в следующих двух файлах:
VS1053B_MIDI.h
и VS1053B_MIDI.cpp
О разгоне модуля я уже говорил, о том, что с ним, в отсутствие распаянного порта, приходится общаться по SPI, - тоже. Так вот, максимальная частота SPI сильно зависит от частоты работы самого модуля. Поэтому сначала в него на частоте SPI 1 MHz загружается программа, осуществляющая помимо прочего и разгон, а потом, с уже разогнанным, общение происходит на частоте SPI 4 MHz.
В "комплект" модулей входят также файлы MIDIfn.h и MIDIfn.cpp, опубликованные в 6-м сообщении связанного проекта: http://arduino.ru/forum/proekty/midi-boxmidi-sintezator , поэтому повторять здесь их не буду. Собственно, в этих файла - базовый класс MIDI, а его наследник, используемый в данном проекте выглядит так:
файл MIDIplay.h
и MIDIplay.cpp
В устройстве используется мой любимый OLED дисплей 128х64, для которого я еще в первые дни своего знакомства с Ардуино написал библиотечку, впоследствии опубликованную: http://arduino.ru/forum/proekty/asoled-kompaktnaya-biblioteka-dlya-oled-displeya-128kh64-s-kirillitsei-utf-8
Но в данном проекте от нее используется по сути только инициализация дисплея. Да и задача стояла простая: показывать 8 последних пришедших MIDI команд. Что удобнее в 16-чном виде. Поэтому и фонт нарисовал специально для этого проекта, состоящий всего из 16 цифр.
Но работа с растровым дисплеем - занятие довольно медленное. Особенно по последовательному интерфейсу. А еще более особенно, если ради экономии проводов протокол требует передавать дополнительную информацию, в частности, о номере устройства. А совсем уж особенно - если частота работы последовательной шины ограничена величиной 400 кГц. Кстати, последнее меня несколько озадачило: оказалось, библиотека I2C для STM32 поддерживает всего две частоты передачи 100кГц и 400 кГц, причем при любом значении кроме 400000 библиотека устанавливает частоту 100000. Даже на Uno I2C удавалось разогнать почти до 1 МГц, а на Due, я проверял, и сама библиотека и дисплей в частности устойчиво работают на 2 МГц. А вот на STM32 выше 400 кГц - никак. Ну, точнее, со стандартной для него библиотекой. А ковыряться с собственной реализацией I2C для STM32 мне как-то не хотелось - хотелось побыстрее доделать дивайс.
Так вот, о скорости: протокол MIDI сам не очень быстрый - задержка ноты составляет примерно 1 мс. При том, что величины порядка 7-10 мс уже различаются на слух. А вывод на экран - всего 400 Гц. А это порядка 50 мс. В общем, на экран пришлось выводить кусочками по 16 байт.
В программе предусмотрен текстовый экранный буфер, который поддерживается в актуальном состоянии обработчиком MIDI сообщений, благо, он всего 8 строк по 6 символов (MIDI команда - три 16-ричных числа). Затем в перемешку с опросом входящих MIDI команд происходит постепенное отображение на экран, разделенное на 65 этапов: один из которых - это преобразование текстового буфера в графический - объемом 1 кБайт, а остальные 64 - поблочная (длина блока 16 байт) пересылка этого экранного буфера собственно на дисплей. В результате максимальная дополнительная задержке MIDI команды не превосходит 0.6-0.8 мс, что вполне приемлемо. Ну и частота обновления экрана порядка 20 fps, что также не вызывает возражений.
Работа с экраном, как обычно, сосредоточена в двух файлах с оригинальными названиями:
screen.h
и screen.cpp
Ну и в заключение (какая же статья без картинок!) фото, на котором изображена совместная отладка блоков из двух проектов: MIDI-бокса (слева - поставлен на попа, т.к. снизу к нему подключен логический анализатор) и MIDI-плеера (справа, лежит на столе собранный на макетной плате):
Большое спасибо за библиотеку VS1053_MIDI!
Небольшое уточнение, на которое в связи со своей невнимательностью убил час. В файле VS1053_MIDI.cpp в 1-й строке стоит
#include "VS1053B_MIDI.h"
а поскольку и такая библиотека у меня стоит, то компилятор матно ругался на отсутствие объявлений функций. Исправить просто - написать там:
#include "VS1053_MIDI.h"
Это моя невнимательность: файлы на самом деле называются VS1053B_MIDI.*. В тексте поправил.
Приношу свои извинения за доставленные проблемы.
Это моя невнимательность: файлы на самом деле называются VS1053B_MIDI.*. В тексте поправил.
Приношу свои извинения за доставленные проблемы.
А мне как раз понравилось предыдущее название. Под ардуинку - VS1053B_MIDI.*, под STM32 - VS1053_MIDI.*
Хотя Ваша библиотека поинтереснее. Туда бы команды препроцессора на выбор варианта SPI в зависимости от контроллера - так и ей вообще цены бы не было. Сам в них, к сожалению, не силен.
Так наверное, основа у библиотек, как и название, одна и та же. Я ведь не с нуля библиотеку делал, а сначала скачал, что нашел, потом уже переделывал под свои нужды и, кстати, в предыдущем проекте ( http://arduino.ru/forum/proekty/analog-analogovogo-sintezatora ) эта библиотечка использовалась с Мегой 2560.
По поводу препроцессора, так там только с stm32 столько вариантов... Причем, как выяснилось, эти варианты могут еще и зависеть от прочей подключаемой аппаратуры (например, SPI1 на альтернативных пинах вместе с I2C не работает, причем узнать об этом, кроме, разумеется, практики, можно только из errata, - в дэйташите этого нет). В общем, описание универсального случая весьма проблематично.
И выбрать из трех возможных вариантов наиболее приемлемый вариант по умолчанию - тоже проблема, т.к. основные пины для SPI1 не толерантны к 5 Вольтам.
В общем, VS1053B не такое уж распространенное устройство, и если оно используется, то является одним из центральных в системе. А раз так, лучше не держать его в списке универсальных библиотек, а класть каждый раз в папочку конкретного проекта и рихтовать под каждый конкретный случай.
И еще: не люблю директивы препроцессора за то, что они здорово мешают читать исходник.
Ну и сегодня завершаю публикацию проекта в том виде, в каком он на сегодняшний день состоялся. В частности, он уже оказался очень полезен для реализации длящихся в настоящее время проектов, описание которых последует через некоторое время.
Осталось всего два файла, при этом размеры их таковы, что можно обойтись без их сворачивания.
Первый - основная программа. Расширение у нее .ino, а назвать ее может каждый, как душенька пожелает. Тем более с именами файлов я в этой теме уже облажался.
Второй файл - настроечный, называется comm_ctrl.h
Само устройство выглядит так:
Светодиод показывает наличие сигнала Active Sensing, а на экране отображаются последние 8 MIDI команд.
У прибора есть еще одна особенность: при включении питания он воспроизводит органным звуком мажорный аккорд (чтобы продемонстрировать свою работоспособность), а затем НЕ возвращается к настройкам по умолчанию. С точки зрения настройки разрабатываемых устройств именно такое поведение оказалось удобным - есть контроль за тем, не "забывает" ли новое устройство послать команды, инициализирующие синтезатор.
Классно получилось! Корпус выше всяческих похвал! Респект и уважуха!!!
PS поинтересуюсь, аддон для блюпила какой используешь, в настроенной среде от DIMAX не компилируется
Но я там исправил немного ошибок, по большей части касающихся stm32f407, но, возможно, что-то еще.
Андриано, по картинке не ясно - это Кларковский аддон или СТМ?
Стыдно признаться, но - понятия не имею.
Втихаря надеялся, что те, кому нужно, сумеют опознать по картинке.
По каким критериям опознавать то? В тексте модулей что искать?
PS. Судя по ошибкам, которые были для f407, вряд ли это STM.
точно не STM...
а ASOLED.h откуда взять? На 4 версию ругается
А что за ошибки, если кратенько? Критичные?
критичные
Андриано, может строкой json сюда кинешься, так как через менеджер устанавливал она должна быть
Ua6em не знал что вы теперь спец по стм
шутить изволите, да ошибка:
D:\ARDUINO\arduino-1.8.9.new\portable\sketchbook\libraries\ASOLED\ASOLED.cpp:527:21: error: 'TWBR' was not declared in this scope
byte twbrbackup = TWBR;
а ASOLED.h откуда взять? На 4 версию ругается
D:\ARDUINO\arduino-1.8.9.new\portable\sketchbook\libraries\ASOLED\ASOLED.cpp:527:21: error: 'TWBR' was not declared in this scope
byte twbrbackup = TWBR;
Да, ASOLED чуть подрихтована под stm. Собственно, TWBR - это задание частоты i2c на AVR. Все, связанное с ним, убрать полностью, а вместо этого устанавливать частоту i2c стандартным для ARM способом (для чего есть специальная функция. Если не ошибаюсь, .setClock(400000);).
Последние ошибки, которые исправлял, были для 407 - там просто тупо были перенесены структуры из f103, а некоторые из них для f4 заметно отличаются. Но я устанавливал давно, может, сегодня уже и исправили.
Upd. Обнаружил, что все это не на том компе, за которым я сейчас сижу, так что подробности - не сегодня.
Upd2. Сейчас посмотрел, судя по датам, правка коснулась файлов: dac.h, timer.h и rcc4.h. В первых двух добавлены регистры, которых нет в f103, но есть в f407, а в последнем - добавлены устройства (в частности - таймеры), которых не было в f103. Возможно, где-то еще подправлены адреса регистров.
критичные
Андриано, может строкой json сюда кинешься, так как через менеджер устанавливал она должна быть
критичные
Андриано, может строкой json сюда кинешься, так как через менеджер устанавливал она должна быть
Да! Это оно!
Я вижу вы серьезно в теме. Подскажите пожалуйста, нужно на esp8266/32 проиграть midi-файл, через пассивный извещатель. То есть через ШИМ. Как из midi файла получить частоту и длительность нот?
Перерыл весь интернет. Всё как сговорились, показывают как через сайт переконвертировать midi-файл в серию tone() и delay (). Ну это же ерунда...