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


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
Посмотрите на Кантарино - code.google.com/p/tinkerit/wiki/Cantarino
Тоби Джаффей

@ Joby ресурс, который вы дали, был великолепен, но я видел демо, на самом деле он не говорит ничего слышимого. Кто-нибудь еще знает?
Rick_2047

Не без ЦАПа, нет.
Тоби Джаффей

@ Joby, что у тебя с ЦАП?
Rick_2047

Ответы:


8

Один простой прием - использовать два контакта с ШИМ и привязать их к противоположным сторонам динамика. Затем модулируйте каждый вывод с разной скоростью, и вы сможете сыграть две ноты одновременно ... в основном, динамик смешивает их вместе для вас. Более двух заметок, и вам придется делать это в программном обеспечении, как уже упоминалось.


1
Если вы используете ШИМ (переключение на гораздо более высокой частоте, чем требуемый сигнал), то вы уже можете смешивать несколько сигналов вместе, используя только один выходной контакт.
эндолит

5

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

Как уже говорили здесь, с некоторой сообразительностью высокоскоростной ШИМ может заменить ЦАП.

Страница «Полифония микроконтроллера» содержит некоторые дополнительные сведения и советы.


3

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

Я не знаю, как они это сделали, но вы можете скачать исходный код C с сайта.


Я до сих пор слышу мелодию в моей голове
Тоби Джаффей

2

Это может помочь -> простой ШИМ ЦАП


Чтобы заставить 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=6ceb64a57916c094e87e5983c07b5dd1b4623083;hb=HEAD


2

Если вы используете программное обеспечение для определения времени ваших выступлений, возможно, самый простой подход - это генерировать два независимых потока данных и чередовать их. Этот подход может работать довольно хорошо, независимо от того, управляется ли выход динамика через вывод ввода-вывода или ЦАП. Например:

селектор int;
uint16_t phase [8], freq [8];

пустое прерывание { Селектор ++; селектор & = 7; фаза [селектор] + частота [селектор]; DAC_OUT = синусоида [фаза [селектор] >> 8]; }

Выше приведен основной подход, который я использовал в музыкальной шкатулке на основе PIC в 1996 году (с использованием ассемблерного кода, а не C). Обратите внимание, что частота прерываний должна в 8 раз превышать эффективную частоту дискретизации, но каждое прерывание должно выполнять обработку только для одного голоса. Обратите внимание, что если фильтрация выходного сигнала хороша, этот подход даст эффективное разрешение ЦАП на 3 бита больше, чем при численном добавлении выборок и их выводе, но при этом генерируется много шума на частоте дискретизации и ее кратных. Таким образом, фильтрация даже важнее, чем могла бы быть в противном случае.


1

Раньше они делали это на старых игровых системах и во времена « колонок для ПК », но я не знаю как.

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

Вторая мысль: можно ли значительно увеличить частоту генерации и вывода аналоговых сигналов в стиле ШИМ ?


2
Я помню, как смотрел на эмулятор NES давным-давно, и я считаю, что они использовали три сигнала, каждый с программируемой частотой. Две прямоугольные волны и одна треугольная волна.
mjh2007

... и один источник шума, по-видимому. en.wikipedia.org/wiki/NES_Sound_Format
эндолит

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
Я бы дал вам голос, если вы разместите код здесь, или где-то, где мне не нужен аккаунт ...
Тоби Джаффи
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.