Звуковий синтезатор на atmega48

Мир всім, товариші! Це знову нудьгуючий я. Хто там мене втрачав. Радійте, друзі мої, бо нині я тут і хочу запропонувати увазі громадськості свою нову саморобку, вироблену на світло по натхненню і від нудьги - синтезатор на ATmega48.

Все почалося з того, що я був в істотному ступені натхненний «маленької фугою» Баха. Потім прийшли вихідні, які, як уже відомо, наганяють на мене нудьгу більш всіх інших днів тижня, тим самим спонукаючи на виготовлення різноманітних девайсів. І нині я вирішив знічев'я накидати на макетке маленький синтезатор, який грає маленьку фугу. Отже, до справи!

Спершу я вирішив визначитися з діапазоном майбутнього інструменту, для чого запитав у мами (вона у мене музикант), які октави найбільш споживані в більшості мелодій. Виявилося, що їх три - мала, перша і друга. Звичайно, найбільше мене цікавили кількісні характеристики нот, т. Е. Частоти. На щастя, сторінка з усім необхідним знайшлася дуже швидко. Виявилося, що найвища очікувана нота - сі другої октави - має частоту всього лише 988 Гц (приблизно), так що весь звукоряд можна з успіхом генерувати ШІМ ЦАП-му (так, це буде не прямокутник, як в більшості подібних конструкцій, а довільний семпл). З цих міркувань вимальовується наступна схема:

Апаратний канал ШІМ підключений до найпростішого фільтру - інтегруючого RC-ланцюжку, що має частоту зрізу близько півтора кілогерц (насправді ставив те, що було під рукою - вийшло вдало). Далі варто класичний двотактний повторювач, розгойдуватися пятідесятіомний динамік (він теж валявся в засіках з незапам'ятних часів). С4 видаляє постійну складову, щоб нічого ненароком не задимилося. Світлодіод був встромлений для налагоджувальних цілей, та так і залишений - тепер він зазначає зчитування черговий ноти.

Ну ось, тепер можна приступати безпосередньо до генерування звуків. Як вже говорилося, я вибрав WT-синтез - т. Е. Використовується масив вибірок, що задає форму сигналу. В принципі, в планах добути органний семпл і використовувати його, але на етапі налагодження я зашив звичайний синус.

Семпл один, нот багато. Як міняти висоту тону? Є два класичних методу - часткова вибірка з масиву при незмінній частоті дискретизації і зміна частоти дискретизації при послідовній вибірці. В картинках:

Вибираємо кожну другу точку, щоб збільшити частоту в два рази:

Збільшуємо частоту дискретизації в два рази, щоб збільшити частоту в два рази:

Очевидно, що змінювати частоту в ціле число раз найпростіше першим методом. Але ставлення нот в октаві не ціла. І тому для формування гами не залишається нічого іншого, як застосувати другий - частота дискретизації задається таймером, і міняти її можна набагато вільніше. А ось для переходу між октавами цілком логічно застосовувати як раз часткову вибірку з масиву - адже частоти нот в сусідніх октавах розрізняються саме в два рази. Таким чином, для програвання заданої ноти потрібна наступна інформація:

1. Інкремент лічильника масиву. Вибираємо кожен елемент - отримуємо ноту вихідної октави, вибираємо кожен другий - отримуємо ту ж ноту на октаву вище, кожен четвертий - на дві октави вище, і т. П.
2. Власне, номер ноти. Я задав в пам'яті масив, де за номерами нот записані значення затримки для таймера, контролюючого висновок значень в ЦАП.
3. Затримка до обробки наступної ноти.

Видно, що семпл потрібно брати для найнижчою планованої октави, бо найпростіше підвищувати його частоту. Щоб знизити її на октаву, необхідна інтерполяція, а це вже не так просто.

У самій же октаві треба ореінтіроваться на найвищу ноту, і ось чому. Частота Шиман становить приблизно 32кГц. Звідки випливає, що робити частоту дискретизації вище 16кГц, в загальному, безглуздо. Але зміна частоти дискретизації використовується для переходу між нотами в октаві, при цьому найвища частота відповідає найвищій ноті. Це і є обмежуючим фактором. Тобто зразковий семпл треба формувати для сі малої октави. Розрахунок показує, що для максимальної частоти дискретизації в районі 16кГц він повинен містити 64 точки.

Разом, я використовував три таймера: восьмібітних T / C0 використовується як ШІМ-генератор, T / C2 ним керує (його період задає частоту дискретизації), а шістнадцятибітну T / C1 займається читанням нот і конфигурированием перших двох таймерів і себе самого (встановлює інкремент масиву семпли, відповідний октаві, потрібний період для T / C2 і для себе самого). Прошивка написана на C в AVR-Studio + WinAVR (AVR-GCC).

Все в зборі (печатку нерозробляв):

Звуковий синтезатор на atmega48

Октав я використовую всього три, а нот в кожної з них (рахуючи дієз і бемоль) дванадцять. Тобто для нумерації і того, і іншого можна вкластися в чотири біта, що дає можливість організувати примітивне стиснення, упакувавши все це в один байт. А ось під тривалість ноти я віддав два чесних байта. Т.ч. мелодія має вигляд масиву, розбитого на блоки по три байта - в старшій тетраде інкремент, відповідний октаві, в молодшій номер ноти. Наступні два байта - тривалість в тиках. Маркер кінця - три нуля.

Однак очевидно, що руками переводити мелодію в вищеописаний формат досить важко, тому я написав простенький парсер, що генерує сішний масив із спрощеної латинської записи нот (консольний додаток в Code Blocks + MinGW). Наприклад, початок маленької фуги виглядає так (тут мені теж допомогла мама):

Тобто <октава><нота>[Дієз / бемоль]<длительность (знаменатель)>[Точка (збільшення тривалості в півтора рази)]

Вихідні тексти / бінарники прошивки і конвертера є в аттаче.

Загалом, на сьогодні все. Висловлюю подяку своїй мамі за допомогу в музичних питаннях.

Схожі статті