Создание и синтезатор Arduino без библиотеки тонов

Я думаю о том, чтобы попытаться сделать синтезатор Arduino, используя настоящий аналоговый выход на Due. Однако я хотел бы иметь возможность воспроизводить несколько нот одновременно на одном зуммере. Возможно ли это и как мне это сделать?

, 👍1

Обсуждение

что такое "зуммер"? .... он может воспроизводить разные тона?, @jsotola


2 ответа


Лучший ответ:

1

Вам просто нужно добавить формы волны. Например, если вы хотите играть чистых тонов (самый простой и скучный тембр), вы генерируете синус поднимите волну для каждого из них и сложите их вместе:

struct Note {
    float frequency;
    float phase;
    bool is_active;
} notes[MAX_NOTES];

void output_sample()
{
    static uint32_t previous_time;
    uint32_t now = micros();
    uint32_t elapsed_time = now - previous_time;
    previous_time = now;
    float output = 0;
    for (int i = 0; i < MAX_NOTES; i++) {
        Note *note = &notes[i];
        if (note->is_active) {
            output += cos(note->phase);
            note->phase += 2*M_PI*note->frequency*1e-6*elapsed_time;
            if (note->phase >= 2*M_PI) {
                note->phase -= 2*M_PI;
            }
        }
    }
    analogWrite(DAC_PIN, 2048 + round(output * (2047.0 / MAX_NOTES)));
}

Функция output_sample() должна вызываться как можно чаще. возможный. Вы можете изменить массив notes в любое время, чтобы добавить, удалить или изменить примечания.

Здесь есть место для оптимизации, например:

  • сохранение 2*M_PI*note->frequency*1e-6 в качестве «частоты», чтобы сохранить некоторые расчеты

  • используя волновую таблицу вместо функции cos() (я не знаю, как хорошо в трансцендентальной математике)

  • заменив elapsed_time на константу, если вам удастся вывести образцы с фиксированной скоростью.


Правка: я написал: «Вы можете изменить массив notes в любое время, чтобы добавить, удалить или изменить заметки». Вот как начать или остановить ноту, т.е. добавить или удалить его из списка активных заметок:

// Начать заметку. Возвращает индекс для использования с stop_note() или -1, если
// мы не смогли запустить заметку, потому что мы уже выводим
// максимальное количество одновременных нот.
int start_note(float frequency)
{
    int i;  // индекс заметки в массиве notes[]

    // Находим свободный слот в массиве.
    for (i = 0; i < MAX_NOTES; i++)
        if (!notes[i].is_active) break;  // найденный

    // Не удалось найти свободный слот?
    if (i == MAX_NOTES) return -1;

    // Настраиваем параметры заметки.
    notes[i].frequency = frequency;
    notes[i].phase = 0;
    notes[i].is_active = true;
    return i;
}

// Остановить заметку с заданным индексом.
void stop_note(int index)
{
    if (index >=0 && index < MAX_NOTES)
        notes[index].is_active = false;
}
,

Как добавить сюда заметки? Я не особо разбираюсь в структурах., @Someone

@Someone: вы находите ячейку в массиве, где is_active имеет значение false, устанавливаете желаемую частоту и устанавливаете is_active на true., @Edgar Bonet

как добавить элемент в массив заметок?, @Someone


0

Звук — это не что иное, как несколько простых волн, объединенных в одну. Итак, теоретически вы можете воспроизвести столько звуков (тонов), сколько захотите, на одном контакте. Если вы хотите перейти на настоящий аналоговый сигнал, вам, вероятно, следует использовать синусоидальную волну для генерации звука. Однако в этом случае вы можете сделать следующее: Либо сделайте функцию, которая была бы способна генерировать синусоидальную волну нужной вам частоты. В случае истинного аналога это, вероятно, будет сделано путем вычисления фактических значений греха и использования map(). преобразование функций 0–1 в 0–1024 и запись на вывод. Частоту можно регулировать, изменяя задержку между каждым шагом изменения напряжения или значения DAC. Однако это не позволит использовать несколько частот. В качестве альтернативы для одновременного воспроизведения нескольких частот вам потребуется вычислить инверсию Фурье всех волн, которые вы хотите воспроизвести. воспроизвести и отправить результаты на DAC.

,

И вам нужно будет использовать динамик вместо зуммера, так как они могут воспроизводить один тон за раз., @Coder_fox

«_Инверсия Фурье_» — это ненужный математический жаргон для того, что представляет собой просто _сумму_ тонов., @Edgar Bonet

@EdgarBonet да, в основном это сумма., @Coder_fox

Как мне это сделать?, @Someone

@Someone Написание кода, который будет выполнять описанное выше. Я включил гиперссылки, чтобы помочь понять, что имеется в виду и как это использовать. Кроме того, посетите страницу https://www.arduino.cc/reference/en/, которая содержит много информации о том, как выполнять математические и логические операции на языке Arduino, а также о том, как управлять аппаратным обеспечением Arduino., @Coder_fox

Смешивание звуков не так просто, как их математическое суммирование (а также суммирование и усреднение для понижения уровня). Я совершил эту ошибку несколько лет назад, и результаты были дерьмовыми. Как только я нашел подходящую функцию микширования звука, я никогда не оглядывался назад..., @Majenko