Цифровой эквалайзер на Teensy 4.1: от идеи до работающего прототипа

Если ты читаешь это, скорее всего ты уже знаешь, что такое эквалайзер, и хочешь собрать его сам — на реальной железке, а не в симуляции. Teensy 4.1 для этой задачи подходит почти идеально: мощный ARM Cortex-M7 на 600 МГц, встроенный аудио-кодек через дополнительную плату, и готовая библиотека Audio Library, которая серьёзно упрощает жизнь. Разберёмся, как это всё собрать и заставить работать.

Почему именно Teensy 4.1

Обычные Arduino не тянут обработку звука в реальном времени — у них слишком мало мощности и нет аппаратной поддержки I2S. Teensy 4.1 — это другой мир. 600 МГц, 1 МБ оперативки, аппаратный I2S, поддержка 32-битной аудиообработки с плавающей точкой в библиотеке. Ты можешь сделать 10-полосный эквалайзер с минимальной задержкой, и процессор при этом не будет задыхаться.

Важный момент: сама Teensy 4.1 не имеет аудио-выхода. Нужна дополнительная плата — Teensy Audio Board. Без неё ты сможешь обрабатывать цифровой сигнал, но не сможешь подключить наушники или колонки.

Что понадобится для сборки

  • Teensy 4.1
  • Teensy Audio Board (версия с чипом SGTL5000 или WM8731)
  • USB-кабель для прошивки
  • Наушники или активные колонки (3.5 мм джек)
  • Источник звука: линейный выход, другой аудио-плеер, или можно организовать петлю для тестирования
  • Arduino IDE с установленным Teensyduino

Audio Board подключается к Teensy напрямую через разъём — никаких проводов и пайки для базовой конфигурации. Убедись, что плата вставлена правильно: контакты Audio Board совпадают с портом SPI на Teensy 4.1.

Установка инструментов

  1. Скачай Arduino IDE с официального сайта (версия 1.8 или 2.x — обе работают).
  2. Установи Teensyduino — это расширение для Arduino IDE, которое добавляет поддержку Teensy. Скачать с сайта pjrc.com.
  3. В Arduino IDE выбери плату: Tools → Board → Teensy 4.1.
  4. Убедись, что в Tools → USB Type выбрано Serial + MIDI + Audio — это нужно, чтобы Teensy определялась как аудио-устройство.

Как устроен эквалайзер в библиотеке Teensy Audio

Библиотека Audio работает по принципу блоков, соединённых между собой. Каждый блок — это узел, который делает что-то со звуком: усиливает, фильтрует, задерживает. Ты создаёшь нужные блоки и соединяешь их в цепочку.

Для эквалайзера основной строительный блок — это AudioFilterStateVariable или AudioEffectEnvelope, но удобнее всего использовать AudioFilterBiquad для полочных фильтров или готовый подход через несколько фильтров, каждый на своей частоте.

Типичная цепочка выглядит так: источник звука → несколько полосовых фильтров → сумматор → выход. Каждый фильтр отвечает за свою частотную полосу, ты регулируешь усиление в каждой полосе, и всё это смешивается обратно.

Простой 3-полосный эквалайзер

Начнём с базового варианта — три полы: низкие, средние и высокие частоты. Это даёт понимание принципа, и дальше ты сможешь расширить до 5, 7 или 10 полос.

Вот скелет кода для 3-полосного эквалайзера:


#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>

// Выход через I2S на Audio Board
AudioOutputI2S           i2s1;
AudioControlSGTL5000     sgtl5000_1;

// Гармонический генератор для теста (замени на реальный источник)
AudioSynthWaveformSine   sine1;

// Полосовые фильтры
AudioFilterStateVariable filterLow;
AudioFilterStateVariable filterMid;
AudioFilterStateVariable filterHigh;

// Усилители для каждой полосы (коэффициент усиления)
AudioMultiply             gainLow;
AudioMultiply             gainMid;
AudioMultiply             gainHigh;

// Сумматор
AudioMixer4              mixer1;

// Соединения
AudioConnection          patchCord1(sine1, 0, filterLow, 0);
AudioConnection          patchCord2(sine1, 0, filterMid, 0);
AudioConnection          patchCord3(sine1, 0, filterHigh, 0);

AudioConnection          patchCord4(filterLow, 0, gainLow, 0);
AudioConnection          patchCord5(filterMid, 0, gainMid, 0);
AudioConnection          patchCord6(filterHigh, 0, gainHigh, 0);

AudioConnection          patchCord7(gainLow, 0, mixer1, 0);
AudioConnection          patchCord8(gainMid, 0, mixer1, 1);
AudioConnection          patchCord9(gainHigh, 0, mixer1, 2);

AudioConnection          patchCord10(mixer1, 0, i2s1, 0);
AudioConnection          patchCord11(mixer1, 0, i2s1, 1);

void setup() {
  AudioMemory(12);

  sgtl5000_1.enable();
  sgtl5000_1.volume(0.5);

  // Низкие частоты: фильтр нижних частот на 250 Гц
  filterLow.frequency(250);
  filterLow.resonance(0.7);

  // Средние частоты: полосовой фильтр на 1000 Гц
  filterMid.frequency(1000);
  filterMid.resonance(1.0);

  // Высокие частоты: фильтр верхних частот на 4000 Гц
  filterHigh.frequency(4000);
  filterHigh.resonance(0.7);

  // Начальное усиление — единица (без изменений)
  gainLow.gain(1.0);
  gainMid.gain(1.0);
  gainHigh.gain(1.0);

  // Все каналы микшера на полную
  mixer1.gain(0, 1.0);
  mixer1.gain(1, 1.0);
  mixer1.gain(2, 1.0);
  mixer1.gain(3, 0.0);

  sine1.frequency(440);
  sine1.amplitude(0.5);
}

void loop() {
  // Здесь можно считывать потенциометры и менять усиление
}

Обрати внимание на AudioMemory(12) — это выделение памяти для аудио-буферов. Чем больше блоков и соединений, тем больше памяти нужно. Для 10-полосного эквалайзера может потребоваться 20–30 блоков памяти.

Управление с потенциометров

Чтобы эквалайзер был полезен, нужны физические ручки. Подключи три потенциометра к аналоговым входам Teensy 4.1 (пины A0, A1, A2) и в loop() считывай их положение:


void loop() {
  // Потенциометр на A0 управляет низкими частотами
  float lowGain = analogRead(A0) / 1023.0 * 2.0; // от 0 до 2.0
  gainLow.gain(lowGain);

  // A1 — средние
  float midGain = analogRead(A1) / 1023.0 * 2.0;
  gainMid.gain(midGain);

  // A2 — высокие
  float highGain = analogRead(A2) / 1023.0 * 2.0;
  gainHigh.gain(highGain);

  delay(10); // небольшая задержка для стабильности
}

Диапазон от 0 до 2.0 означает, что ты можешь как ослаблять полосу (0), так и усиливать в два раза (2.0). Если нужно больше усиления — увеличь верхнюю границу, но помни о клиппинге.

Сравнение подходов к реализации

Есть несколько способов сделать эквалайзер на Teensy. Выбор зависит от того, что тебе важнее: простота, качество звука или гибкость.

Подход Библиотечные блоки Качество фильтров Сложность Задержка
State Variable (полочные) AudioFilterStateVariable Среднее, подходит для музыки Низкая Минимальная
Biquad (параметрический) AudioFilterBiquad Хорошее, точный контроль частоты Средняя Минимальная
FFT-фильтрация AudioAnalyzeFFT1024 Отличное, но сложное в настройке Высокая Заметная (блоки по 1024 сэмпла)
Внешний DSP-процессор Зависит от чипа Высокая Минимальная

Для первого проекта бери State Variable — он проще всего настраивается и даёт приличный результат. Если нужна точная настройка конкретной частоты — переходи на Biquad. FFT имеет смысл, когда ты делаешь визуализатор спектра параллельно с обработкой.

Расширение до 5 и 10 полос

Принцип тот же, просто добавляешь больше фильтров. Для классического 10-полосого эквалайзера стандартные частоты октавные: 31 Гц, 62 Гц, 125 Гц, 250 Гц, 500 Гц, 1 кГц, 2 кГц, 4 кГц, 8 кГц, 16 кГц.

Но есть нюанс: если ты используешь 10 фильтров State Variable, каждый из них обрабатывает весь сигнал, а не только «свою» полосу. Это значит, что суммарная характеристика не будет складываться чисто. Для более точного разделения лучше использовать Biquad с типом bandpass для средних полос и lowpass/highpass для крайних.

Пример настройки Biquad для полосы на 1 кГц:


filter1.frequency(1000);
filter1.Q(1.414); // добротность для ровной АЧХ
filter1.setBandpass(); // если поддерживается в твоей версии библиотеки

В некоторых версиях Teensy Audio Library тип фильтра задаётся через отдельный метод. Проверь документацию своей версии — библиотека обновляется, и API может отличаться.

Подключение реального источника звука

Для теста синусоидальный генератор подходит, но в реальности нужен внешний аудио-вход. Audio Board имеет линейный вход (Line In) — подключи туда выход телефона, плеера или другого источника.

В коде замени генератор на линейный вход:


AudioInputI2S            i2sIn;

// Вместо sine1 используем вход
AudioConnection          patchCord1(i2sIn, 0, filterLow, 0);
AudioConnection          patchCord2(i2sIn, 0, filterMid, 0);
AudioConnection          patchCord3(i2sIn, 0, filterHigh, 0);

Не забудь включить вход в setup():


sgtl5000_1.inputSelect(AUDIO_INPUT_LINEIN);
sgtl5000_1.lineInLevel(5); // уровень входа, подбирай под свой источник

Уровень входа — это частый источник проблем. Если звук хрипит, уменьши lineInLevel. Если слишком тихо — увеличь, но не выше максимального значения для твоей платы.

Частые ошибки и как их избежать

  • Не хватает памяти. Если прошивка скомпилировалась, но звук тормозит или пропадает — увеличь параметр AudioMemory(). Каждый блок потребляет память, и 12 — это минимум для простых проектов.
  • Неправильное питание. Teensy 4.1 может потреблять до 250 мА при полной нагрузке, плюс Audio Board. Питание через USB от компьютера обычно достаточно, но если подключаешь периферию — убедись, что USB-порт даёт достаточно тока.
  • Земляные петли. Если слышен гул 50/60 Гц, это проблема с заземлением. Попробуй питать Teensy и источник звука от одного USB-хаба или используй изолированный вход.
  • Клиппинг при усилении. Если усиливаешь полосу больше чем в 2 раза, цифровой сигнал может превысить максимум и начать клиппить. Лучше ослаблять ненужные полосы, чем усилить одну до предела.
  • Забыл про output level. После микшера сигнал может быть слишком горячим. Добавь финальный контроль громкости через sgtl5000_1.volume() или через дополнительный блок AudioMultiply перед выходом.

Что выбрать под свою задачу

Нужен простой тонконтроль для наушников? — 3-полосный State Variable, три потенциометра, минимальный код. Соберёшь за вечер.

Хочешь параметрический эквалайзер для комнатной коррекции? — 5–7 полос с Biquad, точная настройка частот и Q. Можно даже сделать сохранение настроек в EEPROM.

Делаешь визуализатор + эквалайзер? — добавь AudioAnalyzeFFT1024 параллельно с фильтрами. FFT пойдёт на дисплей, а фильтры на выход. Учти, что FFT добавляет задержку.

Нужна минимальная задержка для живого выступления? — избегай FFT, используй только Biquad фильтры, уменьшай размер аудио-буферов (но следи за перегрузкой процессора).

Оптимизация и отладка

Библиотека Teensy Audio имеет удобный инструмент — Audio System Design Tool (веб-страница на сайте pjrc.com). Ты рисуешь схему блоков графически, а она генерирует код соединений. Это экономит кучу времени и помогает не запутаться в patchCord’ах.

Для отладки используй AudioMemoryUsage() — выводит в Serial Monitor, сколько блоков памяти занято. Если память подходит к пределу, процессор начнёт деградировать.

Ещё полезная функция — AudioProcessorUsage() — показывает загрузку процессора в процентах для каждого блока. Если какой-то фильтр жрёт больше 80%, пора оптимизировать.

Сохранение настроек и продвинутые фичи

Если хочешь, чтобы эквалайзер запоминал настройки между перезагрузками, используй EEPROM:


#include <EEPROM.h>

// Сохранение
EEPROM.put(0, lowGain);
EEPROM.put(4, midGain);
EEPROM.put(8, highGain);

// Загрузка при старте
EEPROM.get(0, lowGain);
EEPROM.get(4, midGain);
EEPROM.get(8, highGain);

Для более сложных проектов можно добавить MIDI-управление — Teensy 4.1 умеет работать как MIDI-устройство, и ты сможешь управлять полосами с контроллера или DAW. В библиотеке есть готовые классы AudioControlMidi.

Итог

Цифровой эквалайзер на Teensy 4.1 — это реальный, рабочий проект, который можно собрать за один вечер. Начни с 3-полосного варианта на State Variable фильтрах, добавь потенциометры, добейся чистого звучания. Потом расширяй до 5–10 полос, экспериментируй с Biquad, добавляй сохранение настроек и MIDI.

Главное — не пытайся сразу сделать идеальный 10-полосный параметрический эквалайзер. Сначала застави работать простой вариант, пойми, как ведут себя фильтры, как складываются полосы. Потом уже усложняй. Так ты получишь работающий проект, а не недоделанный хлам.

Если застрял — смотри примеры в самой библиотеке Teensy Audio (File → Examples → Audio). Там есть демки с фильтрами, микшерами и эффектами, которые можно комбинировать под свой проект.

Radio-Blog.ru