Добавляем функциональность к музыкальному MIDI-синтезатору на двух чипах AY-3-8910, а также вспоминаем, что общего между музыкой и математикой.
Оглавление
Когда-то у меня был компьютер ZX Spectrum с музыкальным сопроцессором AY-3-8910 (правильнее его называть PSG), и в то время качество его звучания впечатляло. Даже когда стали широко распространены IBM PC, которые по вычислительным возможностям на порядки превосходили Speccy, подобных музыкальных возможностей в них поначалу не было, а первые звуковые карты стоили дорого. Воспоминания о тех временах свежи в памяти, и звук этого PSG мне нравится до сих пор, поэтому различные статьи и проекты на тему использования музыкальных чипов AY-3-8910/8912 вызывают интерес и сейчас.
На Хабре есть материалы, связанные с воспроизведением готовой музыки из файлов с трекерной музыкой на этих чипах, но мне хочется затронуть тему воспроизведения музыки на них с использованием MIDI-интерфейса. Например, собрать устройство, к которому можно подключить MIDI-клавиатуру и самому играть музыку, либо воспроизводить ее из программы-секвенсора в компьютере. Для реализации я выбрал платформу Arduino, которая для меня оказалась оптимальной по простоте освоения и возможностям, и которой более чем достаточно для данной задачи.
В сети нашлось некоторое количество готовых проектов на эту тему — например, такой. Это довольно интересный синтезатор с неплохими возможностями, но на одном чипе AY-3-8910, у которого всего 3 звуковых канала синтеза, поэтому играть полифонию из более чем трех одновременно звучащих нот на нем невозможно. Автор другого проекта решил поставить два чипа, чтобы увеличить полифонию до 6 голосов. Это уже интереснее - проанализируем, что у него получилось.
Dual AY-3-8910 MIDI module
Описание проекта вместе с кодом скетча для Arduino находится здесь. Для начала рассмотрим принципиальную схему устройства.
Устройство состоит из следующих частей:
Arduino Pro Micro
2 чипа AY-3-8910 (далее я их буду называть просто AY)
Звуковой линейный моно-выход (в него объединены все выходные каналы чипов AY)
MIDI-вход на оптронной паре (о том, почему его часть обведена красным, будет ниже)
Существуют разные типы устройств Arduino, отличающиеся размерами, чипом микроконтроллера и т.д. Большинство проектов (особенно обучающих) с использованием данной платформы, описания которых можно найти в сети, реализованы на Arduino Uno. В данном же устройстве используется Arduino Pro Micro – аналог Arduino Leonardo. Мне данный тип нравится своей компактностью и дешевизной, но главное здесь не в этом. При подключении такого устройства по USB в компьютере появляется MIDI-устройство, которое можно выбрать в качестве выходного устройства в программном секвенсоре и играть через него музыку. При этом, MIDI-команды будут передаваться из компьютера непосредственно в Arduino через виртуальный последовательный порт.
Одним из недостатков Arduino является небольшое количество пинов (контактов), которые можно использовать для подачи сигналов к управляемым устройствам. Для управления чипом AY используются 8 контактов (сигналов) шины данных DA0...DA7, сигнал сброса Reset, управляющие сигналы BC1, BC2 и BDIR, а также сигнал Clock для подачи тактовой частоты генератора. Для генерации сигнала тактовой частоты, как и во многих аналогичных проектах, используется аппаратный таймер Arduino. Этот сигнал (в данном случае с частотой 1 МГц) подается на контакты Clock обоих чипов AY. Сигнал сброса Reset также подключен параллельно к обоим чипам, т. к. в рамках текущей задачи нет необходимости независимо сбрасывать состояние двух AY.
Но если подключать остальные сигналы для управления чипами полностью независимо, это потребует минимум 20 контактов, а такого количества свободных пинов у Arduino нет. Автор решил эту проблему следующим образом: 8 пинов Arduino подключил параллельно к контактам DA0...DA7 шины данных обоих чипов AY, сигналы BC1 обоих чипов заземлил (используется только запись в регистры), а сигналами BC2/BDIR обоих чипов управляет независимо. В коде программы автор назвал соответствующие пины Arduino как BC2_A/BDIR_A и BC2_B/BDIR_B для управления записью данных в чипы AY, первый из которых он условно назвал A, а второй B.
Для записи данных в регистр чипа A в коде предназначена процедура writeReg_A, а для записи в регистр чипа B – процедура writeReg_B. Код в них одинаков, за исключением того, что управляющие сигналы для передачи данных подаются на пины BC2_A/BDIR_A и BC2_B/BDIR_B соответственно. Подробно рассматривать принципы управления чипом AY я не буду — это описано в даташите и описании автора проекта (при желании можно найти материалы и на русском языке). Отмечу лишь, что для задания высоты звучания ноты используется тактовая частота (в данном случае 1 МГц), которая делится на 16, а затем — на дополнительный делитель, значение которого и задает нужную частоту звучания.
Принцип работы
Главное достоинство устройства — полифония на 6 голосов. Звуковые выходы (каналы синтезатора) A/B/C обоих чипов AY объединены в один моно-выход. Стерео здесь делать особого смысла нет, т. к. в общем случае непонятно, как автоматически распределять ноты, поступающие по MIDI, по левому/правому каналам. Особенно, если несколько нот играется одновременно, но включаться и выключаться они могут в произвольном порядке.
В общих чертах алгоритм работы устройства выглядит следующим образом — в главном цикле loop 100 раз в секунду осуществляется последовательность действий:
Опрашивается USB MIDI-интерфейс. Если из него получено MIDI-сообщение, оно обрабатывается (процедура handleMidiMessage).
Опрашивается аппаратный MIDI-интерфейс. Если из него получено MIDI-сообщение, оно обрабатывается (процедура handleMidiMessage).
По результатам обработки сообщений выключаются/включаются ноты нужной частоты и громкости в 6 синтезируемых каналах двух чипов AY. Для этого формируются необходимые значения для регистров AY, и если они отличаются от предыдущих (сохраненных в отдельные переменные), то они записываются в регистры.
Обрабатываются не все типы MIDI-сообщений, а только Note on (включение ноты), Note off (выключение ноты) и Control change (для полного выключения звука по командам AllSoundOff, ResetAllControllers, AllNotesOff). Помимо включения музыкальных тонов, с помощью шумовых генераторов чипа AY эмулируется звучание ударных инструментов. Также реализовано автоматические изменение громкости нот с помощью огибающих. В частности, после выключения ноты она еще некоторое время звучит с затуханием громкости — получается более естественное звучание, похожее на реальный инструмент (например, фортепиано).
Самая сложная часть кода — автоматическое распределение нот по свободным каналам синтезатора. Автор проделал хорошую работу — написал алгоритм, который при необходимости включить очередную ноту сначала ищет среди 6 каналов синтезатора свободный, и если не находит, принудительно выключает самую «неважную» из уже играющихся нот. Здесь приходится идти на компромиссы - самыми «важными» нотами считаются самые нижние и самые высокие по звучанию, и они могут быть принудительно выключены только в последнюю очередь. Можно поспорить о правильности такого подхода, но в большинстве случаев, действительно, басы являются важной основой музыкальной композиции, а в самых верхних нотах часто содержится сольная часть мелодии, поэтому выключать их тоже нежелательно.
Первый запуск
После того, как я спаял устройство, подключил по USB к компьютеру и запрограммировал с помощью Arduino IDE (для того, чтобы код собрался, необходимо установить библиотеки MIDIUSB и Arduino MIDI), оно даже сразу заработало. Для проверки я использовал программу-секвенсор Cakewalk (уже несколько лет как бесплатную). В окне выбора выходных MIDI-устройств наш синтезатор выглядит в списке как Arduino Leonardo:
Теперь можно вызвать виртуальную MIDI-клавиатуру и «поиграть» на ней мышью или запустить воспроизведение MIDI-файла:
Как видим, всё работает, и даже встроенный светодиод RX мигает, когда поступают данные. Но когда я подключил к аппаратному MIDI-входу музыкальную клавиатуру и попытался сыграть на ней — в ответ тишина. После некоторых раздумий я полез в сеть и поискал даташит на 6N137 и схемы подключения MIDI-входа к Arduino. Мои подозрения подтвердились — автор немного напутал выводы оптрона. После того, как я заменил обведенную красным часть схемы с оптроном на аналогичную часть отсюда, заработало и получение нажатий клавиш с MIDI-клавиатуры. Правильно эта часть схемы выглядит так (для надежности еще добавлен конденсатор между землей и питанием оптрона):
После того, как устройство полностью заработало, выявились и некоторые его недостатки, вызвавшие у меня желание доработать его.
Первая доработка
На MIDI-клавиатуре, помимо нотных клавиш, есть еще колеса-регуляторы Pitch Bend и Modulation:
Pitch Bend позволяет плавно изменять высоту играемой ноты вверх-вниз (обычно до полутона), а Modulation позволяет включить периодическое «плавание» (вибрато) высоты ноты вверх-вниз (чем больше отклонение от нейтрального положения, тем сильнее «плавает» высота). Но здесь они бездействуют, т.к. в коде скетча для Arduino нет обработки соответствующих сообщений. Я захотел добавить обработку этих регуляторов.
Можно было найти и изучить описание стандарта MIDI, но я поступил проще. Автор предусмотрел распечатку в отладочный COM-порт всех поступающих со входа MIDI-сообщений. Для этого достаточно убрать комментарий в строке #define DEBUG и перепрограммировать Arduino. После этого я подвигал колесо Pitch Bend и увидел, что поступают сообщения с заголовком 0x0E, 0xE0 и значением отклонения в байте 3 в диапазоне от 0x00 до 0x7F (в нейтральном положении значение 0x40). А если подвигать колесо Modulation, то поступают сообщения с заголовком 0x0B, 0xB0, 0x01 и значениями от 0x00 (нет вибрато) до 0x7F (максимальное вибрато) в байте 3. Стало понятно, что в процедуре handleMidiMessage нужно добавить обработку этих двух сообщений и соответственно изменить вычисление частоты ноты, поступившей в сообщении Note on.
Вторая доработка
Как известно, чип AY выдает в каждом канале синтеза прямоугольный звуковой сигнал. В принципе, он уже звучит приятнее, чем просто синус, но все равно достаточно «плоско». Это можно заметить в видеоролике, который приведен выше. Хочется сделать звук более «интересным». В чипе AY нет возможности выбрать другую форму синтезированного сигнала. Но можно попробовать смешать два сигнала при воспроизведении каждой ноты — тем более, что у нас не один чип, а два. Это уменьшит полифонию до трех голосов, но если играть партию на клавиатуре, используя синтезатор как солирующий инструмент, для определенного круга задач этого вполне достаточно.
Если смешать два сигнала с одинаковой частотой, звук станет просто громче в 2 раза. Но если у второго сигнала частоту немного изменить относительно первого, получится более «сочный» звук. Такой эффект обычно называют «detune» (можно перевести как «расстройка музыкального тона»). Можно найти примеры видео, в которых показано, как меняется звук, если крутить ручку «detune» у синтезатора. Чем больше ее отклонение от нуля, тем больше отклонение частоты второго сигнала и заметнее отличие, и тем «сочнее» получается звук (но если перебрать с отклонением, звук начнет сильно искажаться).
Изменение схемы и анализ алгоритма
Чтобы добавить функцию detune, я решил добавить в схему дополнительную кнопку, нажатие которой включает режим смешивания двух звуковых сигналов при включении ноты (а повторное нажатие возвращает исходный режим). В таком режиме алгоритм поиска свободного канала синтезатора нужно ограничить до 3 голосов вместо 6, а при включении звучания ноты в свободном канале первого чипа AY одновременно включать звучание ноты в аналогичном канале второго чипа AY, но с немного другой частотой. Для регулировки отличия частоты второго сигнала от первого я добавил в схему переменный резистор. Как видно по схеме, у Arduino Pro Micro есть еще два свободных пина — A2 и A3, их как раз достаточно для подключения дополнительной кнопки и регулятора:
Для того, чтобы понять, какие изменения нужно внести в алгоритм, понадобился его тщательный анализ. Были выделены процедуры, в которых осуществляется вычисление частоты ноты, которую нужно включить, распределение одновременно воспроизводимых нот по 6 доступным каналам для воспроизведения и собственно включение/выключение нот.
В коде автора имеется таблица note_table с фиксированными значениями делителя тактовой частоты генератора 1 МГц, чтобы с ее помощью получать звуки с частотами нужных нот из MIDI-диапазона. Стало понятно, что первым делом нужно отказаться от этой таблицы и заменить ее на таблицу частот, т. к. для реализации Pitch Bend, модуляции и detune необходимо включать звучание нот не с фиксированными частотами, а пересчитанными "на лету". Второе изменение — если включен режим detune, когда нужно к основной звучащей ноте добавлять еще одну одновременно звучащую ноту, то необходимо распределять ноты при воспроизведении не по всем 6 каналам, а только по трем.
Немного о музыке и математике
Чтобы реализовать первую доработку (и еще одну, о которой пойдет речь ниже), понадобится немного вычислений. Одна из особенностей восприятия звука человеком заключается в том, что для повышения высоты тона на октаву необходимо увеличить частоту звукового сигнала в 2 раза. Например, нота «ля» первой октавы имеет частоту примерно 440 Гц, а нота «ля» второй октавы — частоту 880 Гц. Как получить коэффициент (обозначим его S), на который нужно умножить частоту, чтобы увеличить высоту на один полутон? В октаве 12 полутонов. Поэтому, если умножить частоту на этот коэффициент 12 раз, должно получиться удвоенное значение частоты. В результате S равен корню двенадцатой степени из 2:
Примечание: здесь и далее подразумевается, что используется так называемый равно-темперированный строй, который в большинстве случаев используется и в электронной музыке, и во многих музыкальных инструментах. Подробнее об этом можно прочитать, например, здесь.
Чтобы реализовать функцию Pitch Bend, нужно получить значение еще одного коэффициента. Как мы помним, при отклонении колеса от нейтрального положения поступают сообщения Pitch Bend со значением текущего отклонения. В нейтральном положении значение отклонения равно 0x40. При отклонении вверх возможны значения от 0x41 до 0x7F (максимальное повышение тона), а при отклонении вниз — от 0x3F до 0x00 (максимальное понижение тона). Для простоты будем считать, что при отклонении колеса до максимального положения что вниз, что вверх возможны 63 значения (шага) этого отклонения. Поэтому, нужно рассчитать коэффициент (назовем его pf), на который нужно умножить частоту звучания ноты, чтобы повысить его на 1/63 полутона. При максимальном отклонении колеса частоту нужно будет умножить на этот коэффициент 63 раза, и получить коэффициент S — при этом нота повысится на полутон. Очевидно, что pf равен корню 63-й степени из S:
Чтобы рассчитать частоту F звучания ноты с учетом отклонения колесом Pitch Bend, нужно провести следующие вычисления: от значения отклонения колеса B из MIDI-сообщения отнять 0x40 (нейтральное значение), возвести величину pf в степень с полученным значением и умножить частоту "чистой" ноты F0 на результат:
Функция Modulation (вибрато) реализуется с помощью аналогичных вычислений, только значение дополнительного отклонения тона формируется автоматически с помощью периодической функции. Амплитуда этой функции умножается на текущее значение, полученное из MIDI-сообщения Modulation. Текущее значение отклонения умножается на значение текущего шага модуляции, который постоянно пересчитывается при обновлении состояния 100 раз в секунду.
Для реализации функции detune дополнительное отклонение высоты тона необходимо прочитать из АЦП, к которому подключен переменный резистор.
Изменения в коде
Чтобы реализовать все задуманное, в код были внесены следующие изменения:
добавлены объявления номеров пинов, к которым подключены переменный резистор для регулировки степени detune и кнопка переключения режимов работы
добавлены переменные для хранения текущий значений: g_pitchBend — отклонение высоты тона, g_modDepth - глубина вибрато, а также переменная для хранения номера текущего режима g_detuneType
список возможных значений режимов задан в enum eDetune, где значение eNoDetune означает обычный режим работы, как раньше (при этом возможна полифония до 6 голосов, а в режимах с включенным detune доступно только до 3 голосов)
добавлен класс CBtn для обработки нажатий кнопки с устранением дребезга контактов
таблица note_table с фиксированными значениями делителя базовой частоты звукового генератора для каждой из нот в диапазоне стандарта MIDI заменена на таблицу freq_table со значениями частот тех же нот (каждое значение умножено на 10 для повышения точности)
в класс Voice добавлены переменные: m_note для хранения текущей ноты, m_modstep для хранения текущего шага модуляции (вибрато), m_detune для хранения текущего режима воспроизведения ноты
в функции start класса Voice получение значения делителя базовой частоты из таблицы заменено на вычисление в функции getPitch, также сбрасывается в 0 текущий шаг модуляции m_modstep
добавлена функция getPitch, вычисляющая значение делителя с учетом режима detune, текущих значений отклонения высоты тона и вибрато в переменных g_pitchBend и g_modDepth, а также значения шага вибрато в переменной m_modstep
в функции update100Hz класса Voice добавлена обработка вибрато, а также вычисление делителя базовой частоты на каждом шаге, чтобы вращение регулятора степени detune и колес Pitch Bend и Modulation обрабатывались даже в процессе воспроизведения ноты
в функции startNote теперь проверяется текущий режим работы, и если он отличен от eNoDetune, максимальное количество голосов, в которых может быть включено звучание ноты, уменьшается с 6 до 3, и при включении основной ноты также включается дополнительная нота с включенным режимом detune
в функции включения звука ударного инструмента startPercussion также проверяется текущий режим работы, но только для ограничения максимального количества голосов с 6 до 3
аналогичная проверка режима добавлена в функции выключения «лишней» ноты stopOneNote
в функции выключения звучащей ноты stopNote, если текущий режим отличен от eNoDetune, помимо выключения основной ноты выключается также дополнительная нота с включенным ранее режимом detune
в функции setup добавлена инициализация входных пинов для получения значений с переменного резистора и обработки нажатий кнопки переключения режимов, а также выходного пина для включения/выключения встроенного светодиода TX
в функции handleMidiMessage добавлены: обработка сообщения Pitch Bend (текущее значение отклонения высоты тона сохраняется в переменную g_pitchBend); обработка кода Modulation в сообщении Control Change (текущая глубина вибрато сохраняется в переменную g_modDepth); цикл выключения всех звучащих голосов вынесен в отдельную функцию KillVoices (также в нее добавлен вызов synth_init, которая сбрасывает все внутренние переменные, ответственные за «занятость» каналов и распределение нот по ним)
в функции главного цикла работы loop добавлена обработка нажатия кнопки btnDetune — если она нажата, производится принудительное выключение всех голосов вызовом KillVoices, а затем переключение текущего режима работы в переменной g_detuneType на следующий, а если он отличен от eNoDetune, то включается встроенной светодиод TX для индикации включенного режима detune
Третья доработка
После того, как я реализовал задуманное и проверил в работе, в голову пришла еще одна идея. А что, если при включенном режиме detune добавлять вторую ноту не той же высоты, а на октаву выше или ниже? Это должно дать еще более «сочный» звук — такой эффект обычно называют «октавер». Для этого достаточно частоту ноты дополнительно умножить либо поделить на 2. Потом я решил добавить еще два режима: добавление ноты, сдвинутой не на октаву, а на кварту (5 полутонов) или квинту (7 полутонов) относительно основной ноты. В результате получился набор из целых пяти режимов detune – в коде они перечислены в enum eDetuneType.
Вычисление частоты ноты
Рассмотрим итоговую процедуру getPitch, с помощью которой вычисляется значение делителя частоты с учетом отклонения, модуляции и detune.
Текст процедуры
typedef double freq_t;
const freq_t ayf = 625000.0,
pf = 1.0009172817958015637819657653483, // (2^(1/12))^(1/63)
pf5 = 1.3348398541700343648308318811845, // (2^(1/12))^5
pf7 = 1.4983070768766814987992807320298, // (2^(1/12))^7
dr = 50.0; // detune ratio coefficient
const ushort modlength = 20, modmax = 10; // modulation rate and max depth
ushort getPitch(note_t note, eDetune detune, note_t modstep) {
freq_t freq = freq_table[note - MIDI_MIN], fp = 1.0;
int modval = (modstep > modlength / 2) ? modlength - modstep : modstep,
pitchBend = g_pitchBend + modval * modmax * g_modDepth / 0x7F;
if (pitchBend != 0)
fp = pow(pf, freq_t(pitchBend));
if (detune > eNoDetune) {
fp *= pow(pf, freq_t(analogRead(PIN_DETUNE_RATIO)) / dr);
switch (detune) {
case eDetuneOctUp:
fp *= 2.0;
break;
case eDetuneOctDn:
fp *= 0.5;
break;
case eDetune5:
fp *= pf5;
break;
case eDetune7:
fp *= pf7;
break;
}
}
freq *= fp;
float divider = float(ayf / freq);
return (ushort)divider;
}
Примечание: для вычисления частоты введен дополнительный тип данных freq_t, чтобы при необходимости можно было заменить его. В моем случае этот тип равносилен double.
В таблице freq_table представлены значения частот для каждой из нот MIDI-диапазона (для повышения точности все значения умножены на 10). Сначала в переменную freq копируется значение «чистой» частоты из этой таблицы для текущей ноты. Эта частота будет умножена на коэффициент fp, в начале процедуры в нем значение 1. В зависимости от режима работы и текущих значений всех параметров, этот коэффициент нужно пересчитать.
В переменной modval рассчитывается текущее отклонение высоты тона в соответствии с текущим шагом модуляции modstep, который пересчитывается 100 раз в секунду. Скорость и максимальная амплитуда модуляции в виде пилообразной функции заданы константами modlength и modmax (подобраны экспериментально, можно их изменить по своему усмотрению).
В переменной pitchBend рассчитывается суммарное отклонение, полученное в результате модуляции и отклонения колесом Pitch Bend. Если оно не равно нулю, значение коэффициента fp рассчитывается как pf в степени pitchBend.
Если текущий режим отличен от eNoDetune, нужно добавить небольшое отклонение частоты, полученное из положения переменного резистора. Для этого fp дополнительно умножается на коэффициент, полученный возведением pf в степень значения, считанного из пина, к которому подключен переменный резистор. АЦП на пинах Arduino 10-битный, выдает значения от 0 до 1023. Опытным путем установлено, что считанное значение нужно разделить на коэффициент dr, равный 50, иначе при максимальном отклонении резистора искажения звука слишком велики. Значение подобрано экспериментально, также можно его изменить.
В зависимости от режима detune коэффициент fp дополнительно умножается на 2 или 0.5 (повышение или понижение на октаву), либо на 2 в степени 5/12 или 7/12 (повышение на кварту или квинту).
В конце процедуры значение «чистой» частоты ноты умножается на итоговое значение коэффициента fp, и для получения итогового значения делителя частоты нужно разделить константу 625000 на полученное значение freq. Когда полученное значение делителя будет внесено в регистры, задающие делитель относительно тактовой частоты, на выходе соответствующего звукового канала AY будет включен тон нужной высоты.
Итоговое устройство
Фото готового устройства представлено в заголовке статьи, а его работа во всех реализованных режимах представлена в видеоролике. Линейный выход подключен к активным колонкам, к MIDI-входу подключена клавиатура — можно играть:
Полный код скетча для Arduino Pro Micro представлен в репозитории.
Перспективы
На этом этапе я пока остановился. В дальнейшем в устройство хотелось бы добавить следующее:
запоминание текущего режима работы в энергонезависимой памяти (EEPROM)
дисплей (OLED или LCD), на котором показываются текущий режим работы, уровни громкости в каналах AY, информация о воспроизводимых нотах во всех каналах, положения регуляторов Pitch Bend, Modulation, ручки Detune и т.п.
возможность регулирования величины максимального отклонения тона колесом Pitch Bend, а также глубины и скорости модуляции (например, дополнительными кнопками или энкодерами) и диапазона ручки Detune, также с запоминанием всех значений в EEPROM
разнообразить звучание какими-то готовыми звуковыми эффектами (например, как в играх для ZX Spectrum)
поставить больше чипов AY для увеличения полифонии (или, например, играть на одном чипе готовые трекерные мелодии, а на остальных — сопровождение с MIDI-клавиатуры)
Наверное, можно придумать что-то еще. Если у кого-то есть идеи, предлагайте их в комментариях. Также, я не являюсь специалистом по MIDI, поэтому, если кто-нибудь обнаружил неточности или возможные проблемы в обработке MIDI-сообщений в коде программы, прошу сообщить об этом.
Ссылки по теме
Комментарии (39)
qw1
23.04.2023 16:14+3Как известно, чип AY выдает в каждом канале синтеза прямоугольный звуковой сигнал. В принципе, он уже звучит приятнее, чем просто синус, но все равно достаточно «плоско». Это можно заметить в видеоролике, который приведен выше. Хочется сделать звук более «интересным». В чипе AY нет возможности выбрать другую форму синтезированного сигнала
Вообще-то есть. Регистр огибающей, но он один общий на 3 канала. Через него можно делать не прямоугольники, а всякие "кислотные" треугольники и пилы.
voldemar_d Автор
23.04.2023 16:14Спасибо за идею, я уже немного попробовал с огибающими поэкспериментировать. Тут ещё вопрос, куда выносить управление ими - надо добавлять какие-то дополнительные кнопки и регуляторы, а в этой схеме пины у Arduino уже закончились. Надо делать новую.
matador955
23.04.2023 16:14Для увеличения количества выводов можно использовать различные микросхемы "расширителей портов":
либо простейший сдвиговый регистр типа 74HC595
либо что-то более продвинутое с управлением по i2c
Только смотрите на быстродействие, чтобы не появились значимые задержки в передаче данных до микросхем AY
voldemar_d Автор
23.04.2023 16:14Я уже делал пробный вариант схемы, в которой три AY и OLED дисплей, только без MIDI-входа. Ставил 4 регистра 74HC595, всё нормально работает, скорости хватает. Сейчас вижу, что хватило бы и двух регистров, если шины данных AY параллельно подключить, как в этой схеме.
Если поставить один 74HC165, можно 8 кнопок подключить для переключения режимов и регулировки параметров. В следующем варианте схемы все это попробую, когда руки дойдут.
sdy
23.04.2023 16:14+6Схемы лучше читаются когда нет цепей земля и питание, а используются спец символы 5V и GND, например.
С 10k в коллекторной цепи будут фронты заваленные. Врубайте смело 1k вместо 10к. Все номинальные времянки вообще идут с 350Ом нагрузки.
voldemar_d Автор
23.04.2023 16:14Схему я взял готовую в виде картинки из исходного проекта и подправил в графредакторе. Можете подсказать, в какой программе лучше схемы рисовать? Желательно не очень навороченную. Я попробовал штук 5 разных, в них разные недостатки. В части так вообще готовых чипов на 40 контактов не нашёл.
10к - Вы имеете ввиду в цепи MIDI-входа? Я этот кусок схемы тоже готовый взял. А на что эти времянки влияют? На передачу MIDI-сообщений от клавиатуры?
(Если честно, я больше программист, в железе мало разбираюсь)
AnimeSlave
23.04.2023 16:14+2Можете подсказать, в какой программе лучше схемы рисовать?
Самая простая - Sprint-Layout. Именно для разводки плат, а не рисования схем. Платная, но уже лет 15 по инету можно найти переведённую на русский поломанную версию, которой, по моему, пользуются до сих пор. Ссылки не даю просто потому что я не знаю автора программы, а по первым ссылками в поисковике выпадают уже взломанные.
Для быстрого макетирования есть Fritzing (https://fritzing.org/, https://github.com/fritzing/fritzing-app). И замакетить можно, и схему нарисовать, и плату развести. Но очень странная модель распространения у этой программы. Она как бы опенсорс, но на официальном сайте просят денежку за скачивание собранных бинарников. Поэтому придётся подзаморочиться, и самому собирать бинарники. Хотя для пользователей linux в репозиториях дистрибутивов бывает уже присутствует пакет с собранными бинарниками.
Уровнем повыше - KiCad (https://www.kicad.org/). Это уже полноценный рабочий инструмент. Здесь и схемы нарисовать и развести их. Я лично рекомендую именно эту программу. С ней можно многое сделать.
Есть еще EAGLE (https://www.autodesk.com/products/eagle/free-download), точнее был. После того как его купил Autodesk, бесплатная версия Eagle превратилась в триальную версию Fusion 360 (https://www.autodesk.com/products/fusion-360/trial-intake). Работал в ней мало, поэтому выделить чем-то не смогу.
sdy
23.04.2023 16:14+3По поводу рисования схем, самое сложное для первого раза - это научиться создавать символы в библиотеке. Рисовать несложные схемы практически везде одинаково.
Что я вижу, вам нужно освоить рисование шин данных, спец символов земли и питания, еще полезно освоить ссылки страничные чтобы далеко не таскать цели. Есть практика такая - не водить цепи по листу, а ограничиваться только ссылками. Здорово помогает, кстати. Порты межстраничные скорее всего не нужны на первом этапе. Повторяющиеся части схем можно запихивать в блоки, но это уже на следующем этапе, тут главное во вкус войти. Рисование схем - подобно искусству.
Все это очень хорошо и быстро осваивается в KiCad, есть и другие простые редакторы, но у KiCad есть очень большое преимущество - по нему навалом уроков и пояснений как в ютубе, так и просто текстом. Вот, например, сходу набрал How to draw buses in kicad, в ответ сразу видеоурок:
https://www.youtube.com/watch?v=-WpxeDtoys0&ab_channel=NumatoLab
Скажу по себе, рисование в KiCad очень ламповое и DIY-ное. Реально заходит для любителей.
По поводу 10к заменить на 1к. Сопротивление нагрузки определяет постоянную цепи, которая пропорциональна произведению RC для линейных цепей, но тут явно цепь нелинейная, т.к. фронт и спад разные получаются:
Как итог, в вашем случае с 10к постоянные времени будут примерно раз в 30 больше. Вот и считайте. Вместо 50ns будет 1500ns или 1.5мкс и т.д. При этом скорость переключения также падает, т.к. глаз закрывается. Вместо 10Мб/с получается (очень грубо) - 300кб/с. И вот тут вопрос, какая у вас линейная скорость MIDI? Если 31200б/с, то вроде бюджет есть. Но при этом растет еще такая неприятная вещь как джиттер. Мой совет - чем меньше сопротивление нагрузки, тем лучше всяко. Ставьте 1к, а лучше 350Ом как по даташиту.
Все эти любители звука очень трепетно относятся к таким параметрам как температурная стабильность, так и шумам, причем не только по питанию, но и фазовым.
voldemar_d Автор
23.04.2023 16:14Спасибо за разъяснения. Здесь порт для приёма MIDI вроде на скорости 115200 бод открывается. По крайней мере, при игре с клавиатуры я каких-то тормозов и тем более пропадания нот не замечал. В исходном проекте автор в этом месте никакого резистора не ставил. В общем, в следующем устройстве попробую поменьше резистор поставить.
Javian
23.04.2023 16:14Заинтерисовало есть ли VSTIинструменты для синтеза такой музыки. Нашелся платный Chipsounds. Но в данном случае здесь железный синтезатор по мотивам ZX spectrum, со своей оригинальной идеей.
VSTI конечно гибче если планируется написание музыки.voldemar_d Автор
23.04.2023 16:14Схема, конечно, не особо для написания музыки, больше учебная. Ну и хотелось именно спаять железный синт, а не делать всё в компе.
far-rainbow
23.04.2023 16:14Если планируется написание именно музыки, то подойдёт любой VA синт. От бесплатных и простых до крутой эмуляции DSP56300 с загруженной прошивкой синта Access Virus B или С
PMA
23.04.2023 16:14Я конечно "сварщик ненастоящий", но всё же порекомендовал бы следующее:
Вначале, на каждый из выходов ABC синтезаторной микросхемы 330 Ом резистор, а потом уж соединять все вместе, чтобы выходы друг на дружку меньше влияли.
Опять же, как по мне - для режима detune просится отдельный микшер, чтобы смешивать основной тон (как правило громче звучит) и "дополнительный". Это можно в железе сделать (громкость в коде, но там вроде "градаций мало"), или просто 2 регулятора громкости чтобы сводить в 1 сигнал, ну или с i2c/парралельным интерфейсом микшер прикрутить и рулить им с Ардуино отлавливая какие другие команды midi, например "через так": https://www.learningaboutelectronics.com/Articles/MCP4131-digital-potentiometer-circuit.php
Ну и возможно обратить внимание на вот этот канал и прикрутить "для более нажористого" звука что-то из простых примочек, уже именно в "тёплом аналоговом виде": https://youtube.com@MoritzKlein00
voldemar_d Автор
23.04.2023 16:14Спасибо, поизучаю. Для более нажористого звука я пробовал аж три AY-3-8910 ставить, один из них звук с частотой чуть выше, а ещё один - с частотой чуть ниже основной ноты накладывает. Но в той схеме MIDI-входа не было - несколько кнопок прямо на плате для извлечения нескольких нот. Надо будет вариант и с MIDI-входом сделать.
Daddy_Cool
23.04.2023 16:14Очень интересно! У меня есть миди-клавиатура, но лениво её подключать к компу и запускать софт, если бы можно было подключить её к некой коробочке-синтезатору... Но нужны нормальные тембры. Подсоединил к мелкому ноуту на N3450, всё было ОК, потом прилетело обновление на Win 10 и звук стал тормозить.
PMA
23.04.2023 16:14Боюсь из дешевого только если вероятно что-то типа: Roland SC-88VL SC88 Sound Canvas Midi Sound Module
Daddy_Cool
23.04.2023 16:14+1Сейчас поискал - нашел вот такое.
https://www.musicstore.com/en_OT/EUR/Miditech-Pianobox-Mini/art-SYN0004675-000
83 евро.voldemar_d Автор
23.04.2023 16:14+1Можно на Али купить платку за несколько сотен рублей, допаять немного и получить коробочку с General MIDI:
Daddy_Cool
23.04.2023 16:14Вау! Спасибо!
voldemar_d Автор
23.04.2023 16:14Не за что. Мне уже самому стало интересно это реализовать, заказал себе такую плату :)
voldemar_d Автор
23.04.2023 16:14Бывает отдельная коробочка на двух чипах AY, но цена кусается:
https://www.twistedelectrons.com/ay3
Встречал на Avito некий её самопальный аналог, но тоже недёшево.
В принципе, на основе данного проекта можно самому что-то подобное сделать.
ZvoogHub
23.04.2023 16:14Можно запустить в барузере плаеер споддержкой GM (но без колёсика)
https://surikov.github.io/midi-sounds-react-examples/examples/midi-sounds-example10/build/
и подключить MIDI-клавиатуру.
Можно и на телефоне в браузере запустить если он поддерживает USB-хост (иначе клавиатура не будет читаться).
Daddy_Cool
23.04.2023 16:14На телефоне всё медленно - есть синтезаторы для Андроида, но... они бесполезны из-за ощутимой задержки.
ZvoogHub
23.04.2023 16:14На телефоне всё медленно
Нет.
Кагда появился MIDI компьютеры были раз в 100 медленней нынешних простых телефонов. И всё нормально работало. Сделать тормозную прогу на любой платформе можно.
Daddy_Cool
23.04.2023 16:14Я так понимаю там проблемы в том как Андроид работает со звуком. Я перепробовал несколько синтезаторов на Андроиде - нажимаю на клавишу на миди-клавиатуре - звук получается с задержкой. Телефон Samsung S10e. На айфонах такой проблемы вроде нет.
Если подскажите нетормозящую прогу для Андроида - скажу большое спасибо!
ZvoogHub
23.04.2023 16:14нажимаю на клавишу на миди-клавиатуре - звук получается с задержкой
И причём тут звук или мобилы.
Конкретно реализация андроида у большинства производителей железа передаёт события управления с задержкой.
По своим каким-то причинам которые здесь оффтоп.
SADKO
23.04.2023 16:14Ну, не знаю, при всей моей любви к AY/YM имхо овчинка выделки не стоит. Открывая статью надеялся что автор запилил если не автоттюн огибающей то хотя бы орнаменты, которые мы так любили, что многих до сих пор не отпускает...
...да и современные подростки не знавшие не AY не SIDa, проявляют интерес к этим звукам
voldemar_d Автор
23.04.2023 16:14Орнаменты обязательно хочу запилить. Просто я на данный момент осознал, что если добавлять ещё какие-то режимы, нужен всё-таки экран, на котором текущий режим показывается. Для этого схему надо переделать, здесь уже свободных пинов у Arduino нет. Кроме того, мне регулировка переменным резистором не нравится. Как минимум, хочется линейный поставить, а лучше вообще энкодер, а то и не один, для разных параметров.
Можете пояснить, что имеете ввиду под автотюном огибающей? Слова понятны, но неясно, какой именно эффект означают.
SADKO
23.04.2023 16:14Имелся ввиду расчёт и лукап, значений регистров генератора огибающий и тонального генератора для получения насыщенных басов и кислотных звучков.
Исторически, в первых трекерах, можно было спокойно написать только ноты, а если хотелось получить бас от огибающий, то значение регистра приходилось писать ручками. ЕМНИП в протрекере этот процесс автоматизировали но были какие-то нюансы заставлявшие использовать ASM от Андрея Сендетского...
Там были какие-то нюансы получения кислотных звучков, но за давностию лет я их не помню...
...а экран не знаю, нужен ли, ведь на самом деле, ходовых орнаментов было не так много, а эффекты огибающей как-то рассчитывались, что все дефиниции можно свести к паре контроллеров.
Если вникнуть в музыкальную логику приёмов использования ay можно её подружить с midi не банально, а сделав доступными те самые приёмы для клавишника. Типа если велосити на всю балду, то придать октавной перкусионности, меньше, шумочка, а на легатных хвостах пусть нарастает вибратто , и тд.
voldemar_d Автор
23.04.2023 16:14Для собственно музыки экран, понятно, не нужен. Просто хочется сделать разные режимы - и с огибающей, и с орнаментами, да ещё разными, а когда их будет уже десяток, можно будет запутаться, что именно сейчас включено, особенно если последний включённый режим будет запоминаться в настройках. Ну это так, из разряда хотелок.
Я уже попробовал добавить режим, в котором включается пилообразная огибающая, а делитель частоты этой огибающей меняется всё тем же переменником. Ну да, если частота огибающей достаточно большая, кислотный звук получается. Но интереснее, наверное, если эта частота огибающей не постоянная, а тоже как-то периодически изменяется. В общем, буду пробовать.
Про миди-логику тоже понятно, но здесь у меня пока опыта никакого нет. Можно и клавиатуру с after touch задействовать, но у меня она простая совсем. В общем, тут огромное поле для экспериментов. Если в будущем что-такое реализую, обязательно будет продолжение.
Costic
23.04.2023 16:14+3С интересом прочитал статью. Сам делал похожее устройство, правда с более мощным контроллером и стерео. Один из трёх каналов подмешивается равномерно к правому и левому. Такая схема довольно распространена. Ноты первой октавы выводятся через этот общий канал, вторая, третья, четвёртая октавы - в правый, малая и большая октавы - в левый канал.
Непонятно как лучше делать одновременное проигрывание нескольких нот. Пробовал арпеджио воспроизводить. Возник вопрос с какой скоростью чередовать ноты.
Отдельная тема про эмуляцию инструментов. С ударными довольно просто. Удалось синтезировать приемлемые гитарные звуки. Думаю, и пианино можно сделать. В итоге устал от чиптюна и уже год "отдыхаю".
voldemar_d Автор
23.04.2023 16:14В этом устройстве, которое я сделал, ударные неплохо реализованы автором исходного проекта. Можно включить канал 10 и поиграть на клавиатуре, я что-то не догадался в видео это включить.
Про арпеджио я тоже думал. Скорость можно подгонять под темп, который задаётся в MIDI. Но я пока эту тему ещё не изучал.
Ваша схема содержит куда больше деталей - зачем их столько? Вижу две кнопки - что они делают?
Costic
23.04.2023 16:14Я тоже когда-то собирал на макетке проигрыватель + MIDI-вход. Потом захотелось большего. На фото прототип, отладочная плата для поиска интересных звуков. Не обошлось без ошибок - у 3.3В контроллера выгорели пины BC BDIR (они внутри AY подтянуты к +5В). А написано это в скобках в даташите. :-)
Для расширения звуков я добавил YM2612, но т.к. два пина сжёг, то пришлось резать дорожки снизу платы и городить колхоз. Я планировал звук с AY/YM оцифровать микроконтроллером, микшировать программно, добавить эхо, а потом выводить в ЦАП ES9023. То, как я каналы распределил мне не нравится.Сделал пока мало, "поднимал плату", выявлял ошибки аппаратные, проект на паузе.
Кнопки две - ресет (сброс) и пользовательская, чтобы инструмент не подключать для тестов. К кнопкам я всегда стараюсь ставить RC-фильтр, поэтому проблем с дребезгом у меня нет.
Хотелось бы спросить/почитать про хитрости chiptune. Начальное муз образование у меня есть, но ZX Spectruma у меня не было, только трекерную музыка на 386 мне хорошо знакома - MOD, S3M, XM. Насчёт detune. Может быть надо не ручкой потенциометра крутить, а вычислить гармонику частоты (вторую, третью) и её подмешивать?
voldemar_d Автор
23.04.2023 16:14Собственно, у меня пока тоже нет полного понимания того, какие именно эффекты дальше реализовывать, чтобы получить "спектрумовские" звуки. Кое-что мне подсказали, буду экспериментировать.
В этом проекте у меня не было цели как-то дополнительно звук обрабатывать. Понятно, что можно аналоговый выход AY оцифровать, чтобы на него наложить дополнительные фильтры, ревербератор, фленжер или ещё что-то, но для этого надо ещё один микроконтроллер ставить. Пока что я себе такой задачи не ставил.
voldemar_d Автор
23.04.2023 16:14Про гармонику частоты не очень понял. AY выдаёт прямоугольный сигнал. Этот уже не чистый синус, и в нем и так полно гармоник.
Я хочу потенциометр заменить на энкодер или просто две кнопки плюс/минус, чтобы пошагово отклонение частоты изменять. Можно будет поточнее это делать.
Elmot
Если честно, то не очень понятна цель проекта - использовать именно винтажный чип или сделать миди выход?
voldemar_d Автор
Да, хотелось использовать именно те самые чипы AY-3-8910 и аппаратный MIDI-вход, чтобы можно было без компа с клавиатуры играть. Я взял готовый проект и немного развил его, добавил дополнительные режимы. До этого пробовал делать только плееры AY-музыки из PSG-файлов на Arduino и таком чипе, примеры таких проектов и на Хабре есть. В какой-то мере это и для самообучения, с Arduino я меньше года назад начал что-то делать.