Поліфонічні звуки від мікроконтролера?


14

Я можу випускати одноманітні звуки, перемикаючи один штифт ( із різною швидкістю ), підключений до п’єзозвуку.

Як я можу генерувати два змішаних аудіосигналу в програмному забезпеченні для створення поліфонії?

Ось код, який я використовую для відтворення простої мелодії.

#define F_CPU 8000000UL // 8MHz
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/delay.h>

// number of timer0 overflows/sec
#define INT_PER_SEC 31250

// Frequencies (in Hz) of notes
#define F_FSH_4 370
#define F_A_4 440
#define F_B_4 494
#define F_E_4 330
#define F_CSH_5 554
#define F_D_5 587
#define F_FSH_5 740
#define F_CSH_4 277
#define F_GSH_4 415

// number of timer0 overflows for notes
#define REST -1 // special case
#define FSH_4 INT_PER_SEC/F_FSH_4
#define A_4 INT_PER_SEC/F_A_4
#define B_4 INT_PER_SEC/F_B_4
#define E_4 INT_PER_SEC/F_E_4
#define CSH_5 INT_PER_SEC/F_CSH_5
#define D_5 INT_PER_SEC/F_D_5
#define FSH_5 INT_PER_SEC/F_FSH_5
#define CSH_4 INT_PER_SEC/F_CSH_4
#define GSH_4 INT_PER_SEC/F_GSH_4

#define SEMIQUAVER_TIME 60  // ms
#define BREATH_TIME 20      // ms

volatile uint32_t intrs = 0;
volatile int32_t curNote = REST;

// TIMER0 overflow
ISR(TIMER0_OVF_vect)
{
    if (curNote == REST)
        intrs = 0;
    else
    {
        intrs++;
        if (intrs >= curNote)
        {
            PORTD ^= _BV(PD4);
            intrs = 0;
        }
    }
}


void play(int32_t note, uint32_t len)
{
    int i;
    curNote = note;
    for (i = 0; i< len; i++)
        _delay_ms(SEMIQUAVER_TIME);
    curNote = REST;
    _delay_ms(BREATH_TIME);
}

int main(void)
{
    /* setup clock divider. Timer0 overflows on counting to 256.
     * 8Mhz / 1 (CS0=1) = 8000000 increments/sec. Overflows every 256, so 31250
     * overflow interrupts/sec */
    TCCR0B |= _BV(CS00);

    // enable overflow interrupts
    TIMSK0 |= _BV(TOIE0);

    // PD4 as output
    DDRD = _BV(PD4);

    TCNT0 = 0;
    intrs = 0;

    curNote = REST;

    // enable interrupts
    sei();

    while (1)
    {
        // Axel F
        play(FSH_4, 2);
        play(REST, 2);
        play(A_4, 3);
        play(FSH_4, 2);
        play(FSH_4, 1);
        play(B_4, 2);
        play(FSH_4, 2);
        play(E_4, 2);
        play(FSH_4, 2);
        play(REST, 2);
        play(CSH_5, 3);
        play(FSH_4, 2);
        play(FSH_4, 1);
        play(D_5, 2);
        play(CSH_5, 2);
        play(A_4, 2);
        play(FSH_4, 2);
        play(CSH_5, 2);
        play(FSH_5, 2);
        play(FSH_4, 1);
        play(E_4, 2);
        play(E_4, 1);
        play(CSH_4, 2);
        play(GSH_4, 2);
        play(FSH_4, 6);
        play(REST, 12);
    }
}

Гей, чи може ця річ випромінювати людську мову? Я маю на увазі як слова?
Rick_2047

1
Подивіться на Cantarino - code.google.com/p/tinkerit/wiki/Cantarino
Тобі Джаффі

@Joby ресурс, який ви дали, був чудовим, але я побачив демонстрацію, він насправді не говорить нічого чутного.
Rick_2047

Не без ЦАПу, ні.
Тобі Джаффі

@Joby, що у тебе з DAC?
Rick_2047

Відповіді:


8

Ну один простий трюк - використовувати два штифта з ШІМ і прив’язати їх до протилежних сторін динаміка. Потім модулюйте кожен штифт з різною швидкістю, і ви можете грати дві ноти відразу ... в основному динамік змішує їх разом для вас. Більше двох приміток, і вам доведеться це робити в програмному забезпеченні, як згадувалося.


1
Якщо ви використовуєте ШІМ (комутація на набагато більшій частоті, ніж бажаний сигнал), то ви вже можете змішувати кілька сигналів разом, використовуючи лише один вихідний штифт.
ендоліт

5

Стандартний спосіб отримання поліфонії - це переривання з деякою фіксованою швидкістю переривання (найчастіше 8000 Гц або 44100 Гц), отримання "високого" (+1) або "низького" (-1) (або чогось проміжного) від кожного джерела звуку , складіть усі числа, щоб отримати загальну кількість, а потім надішліть це загальне число з ЦАП.

Як говорили інші, тут, з трохи кмітливості, швидкісний ШІМ може замінити ЦАП.

На сторінці «Поліфонія мікроконтролерів» наведено ще кілька деталей та порад.


3

Я думаю, що ця хороша старовинна маленька гейм для DOS для ПК використовувала справжній поліфонічний звук через динамік ПК: Digger .

Я не знаю, як вони це зробили, але ви можете завантажити вихідний код C з сайту.


Я все ще чую мелодію в голові
Тобі Джаффі

2

Це може допомогти -> простий PWM ЦАП


Щоб змусити Arduino відтворювати ноти асинхронно, вам знадобиться використовувати систему, схожу на MIDI - з окремими командами для замітки та відмітки тощо, вбудована тональна бібліотека робить це, але не робить поліфонії - але остання версія виглядає як це - code.google.com/p/rogue-code/wiki/ToneLibraryDocumentation
Джим

2

ви можете просто додати дві квадратні хвилі і використовувати швидкий Pwm для виведення "аналогового" сигналу на динамік.

ось ще один інший метод, якщо вам подобається ігровий звук, швидкий і брудний:

https://gitweb.bl0rg.net/cgi-bin/gitweb.cgi?p=arduinisten.git;a=blob;f=projekte/soundz/arpeggio/arpeggio.pde;h=6ceb64a57916c094e87e5983c07b5dd1b4623083h;


2

Якщо ви використовуєте програмне забезпечення для часових подій вашого динаміка, найпростішим підходом є, мабуть, створення двох незалежних потоків даних та чергування між ними. Цей підхід може працювати досить добре, незалежно від того, чи керується вихід динаміка за допомогою штифта вводу / виводу або ЦАП. Наприклад:

int селектор;
uint16_t фаза [8], частота [8];

анулювання переривання (недійсність) { селектор ++; селектор & = 7; фаза [селектор] + частота [селектор]; DAC_OUT = синусоїда [фаза [селектор] >> 8]; }

Сказане - важливий підхід, який я використовував у музичній скриньці на основі PIC у 1996 році (використовуючи асемблерний код, а не C). Зауважте, що частота переривань повинна бути в 8 разів перевищує ефективну частоту вибірки, але кожен переривання повинен виконувати обробку лише для одного голосу. Зауважте, що якщо фільтрація на виході хороша, такий підхід дасть 3 біт ефективнішої роздільної здатності ЦАП, ніж додавання зразків чисельним шляхом та їх виведення, але він створюватиме багато шуму зі швидкістю вибірки та їх кратністю. Таким чином, фільтрування навіть важливіше, ніж це було б інакше.


1

Раніше це робили на старих ігрових системах і в часи " колонок ПК ", але я не знаю як.

Спочатку здогадайтесь: подумайте про хвилю, яку ви ідеально зробите, а потім уявіть, як перекрутити її у сильно обрізану квадратну форму, а потім створіть цю квадратну форму, переключивши вихід у відповідний час. Хоча було б багато інтермодуляції .

Друга думка: Чи можете ви значно збільшити частоту коливань та вихідних аналогових сигналів у стилі ШІМ ?


2
Я пам'ятаю, як давно дивився на емулятор NES, і я вважаю, що вони використовували три форми хвилі з програмованою частотою. Дві квадратні хвилі і одна трикутна хвиля.
mjh2007

... і одне джерело шуму, мабуть. en.wikipedia.org/wiki/NES_Sound_Format
endolith

1

Як уже згадувалося, ви могли зробити це так само, як це було зроблено з динаміком ПК (який підтримує лише ввімкнення / вимкнення, додатково прикріплений до контролера ШІМ). В основному моє розуміння методу полягає в тому, що ви включаєте і вимикаєте динамік. досить швидко, щоб він ніколи не був повністю включений або вимкнений (дещо схоже на те, як працює джерело живлення в режимі комутації.) Це дозволяє динаміку постійно рухатися між увімкнутими і вимкнутими, генеруючи аналоговий сигнал.

Єдине, що вам потрібен справжній динамік (я думаю, що п’єзо рухається так швидко, що надто швидко виходить на повну і повністю вимикається), і вам потрібно мати можливість перемикати біт досить швидко. Я зробив кілька експериментів і придумав максимальну швидкість близько 5 МГц, яка повинна бути достатньою для аудіосигналу 11,025 Гц (можливо, найкращої якості, на яку ви могли сподіватися.)

Звичайно 11025 Гц @ 8 біт - це 11 кілобайт / секунда, що набагато швидше, ніж швидкість послідовного порту. Це дозволить зберегти аудіозапис у спалах, можливо, секунду чи дві вартості звуку, тому ви майже обмежені для відтворення аудіо, створеного на льоту, за умови, що залишається достатньо вільного часу для процесора, щоб вивернути динамік!

Існує ще кілька інших методів, щоб досягти цього, і, схоже, вже існує реалізація для Arduino описаного вище методу.


2
Ви можете використовувати фільтр перед динаміком, щоб згладити ШІМ, незалежно від того, наскільки швидко рухається сам динамік.
ендоліт


1

На мить відтворюйте звук A, як, можливо, 50 мс, потім звук B і перемикайтесь вперед і назад. Ідея полягає в тому, щоб переключитися швидше, ніж може сказати вухо, і це буде звучати як грати одночасно.


1

Я вважаю, що для Arduino є бібліотека тонів, яка виконує два тони. Ви повинні мати можливість адаптувати код до використовуваного чіпа AVR. На arduino.cc також є кілька чудових потоків генерації сигналів

Якщо ви вирішили додати ЦАП, у мене є приклад осцилятора з числовим контролем на http://wiblocks.luciani.org/docs/app-notes/nb1a-nco.html Чотири незалежні вихідні канали. Квадратний ЦАП і довідник лише близько 2 доларів або близько того.


0

Ось мій код для відтворення 2 мелодій одночасно. Вибачте, вам потрібно зареєструватися до AVR виродків, щоб отримати доступ.


4
Я б дав вам нагороду, якщо ви опублікували код тут, або десь мені не потрібен обліковий запис ...
Toby Jaffey
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.