DIY-микрофон i2s для Raspberry Pi

Моя цель - предложение широкого ассортимента товаров и услуг на постоянно высоком качестве обслуживания по самым выгодным ценам.

DIY микрофон i2s для Raspberry Pi с компрессором, лимитером, фильтрами НЧ и ВЧ и даже «голосом Буратино» на Teensy 3.6.

В детстве я часами зависал у витрины музыкального магазина на Нижней Масловке: меня гипнотизировали чехословацкие и болгарские гитары, синтезаторы Поливокс, электроорганы, акустические колонки, наушники, микрофоны и катушечные магнитофоны. В музыкальном магазине была особая аура, пусть с запахом скрипичной канифоли и рояльного лака. Разумеется, меня зачаровывали электрогитары (и не только из-за сверкающих звукоснимателей и тяжелой колковой механики, целлулоидных вставок), многочисленные гитарные педали — тогда еще наука музыки не знала слова «гитарный процессор». Были педали-ящички фэйзеры, фланжеры, «исказители» и только-только появившиеся цифровые ревербераторы Лель. Цифровые устройства стоили баснословных денег, но обещали заманчивые дальние дали!

Наверное, любой мальчишка, пожирающий глазами музыкальные витрины, мечтает подключить микрофон к усилителю, пропустить звук через загадочный ящик с цифровыми микросхемами и напевать то голосом Карабаса-Барабаса, то Буратино.

Прошли годы, я уже не посещаю музыкальные магазины, но… Когда на авито я увидел микроконтроллер Teensy, меня накрыла мощная волна ностальгии!

А так как мой домашний компьютер это Raspberry Pi 4, как известно, без микрофонного входа, то музыкальные эльфы и феи подсказали мне идею сделать цифровой микрофон на микроконтроллере… с древними эффектами.

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

Итак, после двух-трех дней изучения форума Teensy, я наконец-то написал первую программу для цифрового микрофона. Да, с возможностью включить фланжер, ревербератор, фильтры НЧ и ВЧ, светодиодами, мигающими разноцветными огнями (пиковые индикаторы «под старину»). Как вишенка на торте — с собственным «генератором огибающей», что позволяет добиться, например, сустейна. Ох, сустейн, сладкое словечко моей юности!

Ниже я привожу код для IDE Arduino микрофона для Raspberry Pi и не только. Хотя это 16-битный микрофон, звук у него неплохой.


#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
// Переменные для фланжера, если он нужен
// #define FLANGE_DELAY_LENGTH (8*AUDIO_BLOCK_SAMPLES)
// short delayline[FLANGE_DELAY_LENGTH];
// int s_idx = FLANGE_DELAY_LENGTH/8;
// int s_depth = FLANGE_DELAY_LENGTH/8;
// double s_freq = .0625;
// Настройка эффекта "granular", например, "голос Буратино"
// #define GRANULAR_MEMORY_SIZE 12800 // 290 ms 44.1 kHz
// int16_t granularMemory[GRANULAR_MEMORY_SIZE];
// Объявляем функции лимитера-компрессора
	void envelope_setup();
	void envelope_trigger();
	void envelope_limiter();
// На указанные pin's заведены двухцветные светодиоды
byte ledFFT1 = 36;
byte ledFFT2 = 37;
byte ledPeak = 18;
byte ledRMS = 19;
// Подключение микрофона i2s. В данном случае это микрофон INMP441
AudioInputI2S i2s;
// Фильтры.
AudioFilterBiquad biquad;
AudioFilterStateVariable filter;
// Пиковые индикаторы, Фурье и прочее
AudioAnalyzePeak peak;
AudioAnalyzeRMS RMS;
AudioAnalyzeFFT256 FFT;
// Усилители.
AudioAmplifier ampFFT;
AudioAmplifier ampRMS;
AudioAmplifier ampPEAK;
AudioAmplifier ampOut;
AudioAmplifier bypass;
// Выход USB
AudioOutputUSB usbOut;
// Микшер на четыре канала
AudioMixer4 mixer;
// Генераторы: белый и розовый шумы
AudioSynthNoisePink pink;
AudioSynthNoiseWhite noise;
// Огибающая.
AudioEffectEnvelope envelope;
// Ревербератор, фланжер и т.д.
// AudioEffectFreeverb freeverb;
// AudioEffectGranular granular;
// AudioEffectFlange flange;
// Усилители для настройки индикаторов
AudioConnection out0(biquad, ampPEAK);
AudioConnection out1(ampOut, ampRMS);
AudioConnection out2(ampOut, ampFFT);
// Индикаторы FFT, RMS-peak
AudioConnection indRMS(ampRMS, RMS);
AudioConnection indFFT(ampFFT, FFT);
AudioConnection indPeak(ampPEAK, peak);
// Выход микрофона, фильтрация ВЧ, НЧ
AudioConnection micL(i2s, 0, filter, 0);
// Для правого канала
// AudioConnection micR(i2s, 1, filter, 0);
// Фильтрация
AudioConnection filterIn(filter, 2, biquad, 0);
// Подключаем устройства
AudioConnection pc0(biquad, bypass);
// Лимитер или компрессор.
AudioConnection pc3(biquad, envelope);
// Для "granular"
// AudioConnection pc3(biquad, granular);
// Микшер
AudioConnection mixIn0(bypass, 0, mixer, 0);
AudioConnection mixIn1(envelope, 0, mixer, 1);
// Генераторы шума, подключаемые к микшеру.
AudioConnection mixIn2(noise, 0, mixer, 2);
AudioConnection mixIn3(pink, 0, mixer, 3);
// Выход микшера на усилитель
AudioConnection ampIn(mixer, ampOut);
// Выход на USB. Правый и левый каналы
AudioConnection usbL(ampOut, 0, usbOut, 0);
AudioConnection usbR(ampOut, 0, usbOut, 1);
// Настройка индикаторов-светодиодов, Фурье
void fft_meter(const float fft) {
    if (fft > 0.50) {
        digitalWrite(ledFFT2, HIGH);
        digitalWrite(ledFFT1, LOW);
    } else {
        digitalWrite(ledFFT1, HIGH);
        digitalWrite(ledFFT2, LOW);
    }
    delay(fft*100);
}
// Светодиоды, RMS
void rms_meter(const float rms) {
    analogWrite(ledRMS, 0 + rms*100);
    for (int i; i < rms*100; i++) {
    }
    delay(rms*100);
}
void setup() {
// Инициализация светодиодов перегрузки и уровня
    pinMode(ledFFT1, OUTPUT);
    pinMode(ledFFT2, OUTPUT);
    pinMode(ledPeak, OUTPUT);
    pinMode(ledRMS, OUTPUT);
    digitalWrite(ledFFT1, HIGH);
    digitalWrite(ledFFT2, HIGH);
    analogWrite(ledPeak, 0);
// Выделение памяти
    AudioMemory (320);
// Фильтры
    filter.frequency(60);
// Устанавливаем частоту среза фильтра
// Резонанс фильтра. Q от 0,7 до 5,0, если > 0,707 усилит сигнал около частоты
    filter.resonance(0.7);
// В октавах управляющий сигнал изменяеть частоту угла фильтра
// Диапазон от 0 до 7 октав
// Можно выбрать фильтры Butterworth или Linkwitz-Riley и др.
    filter.octaveControl(-0.5);
// Срезает все, что выше указанной частоты
// biquad.setHighpass(0, 80, 0.26);
// Срезает все, что ниже указанной частоты
// biquad.setBandpass(stage, frequency, Q);
// Полоса пропускания - разница между верхней и нижней частотами среза.
    biquad.setLowpass(0, 16000, 0.54);
// Режектор. Q контролирует ширину отклоняемых частот
    biquad.setNotch(0, 50, 0.3);
// Полочный фильтр нижних частот ослабляет или усиливает сигналы ниже указанной частоты.
// Частота управляет средней точкой наклона, усиление установлено в дБ
// Последний параметр управляет крутизной перехода усиления.
// Значение 1 дает максимальную крутизну
    biquad.setLowShelf(0, 60, -1.5, 0.54);
// Фильтр верхних частот ослабляет или усиливает сигналы выше указанной частоты.
    biquad.setHighShelf(0, 16000, -0.5, 0.25);
// Усилитель перед usb-выходом
// «Уровень» - любое число с плавающей запятой от 0 до 32767.0
// От 0 до 1.0 ослабляет сигнал, а выше 1.0 усиливает
// Отрицательные числа инвертируют сигнал
    ampOut.gain(5.5);
    bypass.gain(1.2);
    mixer.gain(0, 0);
// Индикация
    ampFFT.gain(4);
    ampRMS.gain(3);
    ampPEAK.gain(1);
// Микшер огибающей
    mixer.gain(1, 4);
// Каналы микшера розового или белого шума
// noise.amplitude(0);
// От 0 (off) до 1.0. По умолчанию выключено
    mixer.gain(2, 0);
    pink.amplitude(0.02);
    mixer.gain(3, 0.02);
// Включить ревербератор
// freeverb.roomsize(0);
// дампинг-фактор от 0 до 1.0
// freeverb.damping(1);
// Включить фланжер
// flange.begin(delayline,FLANGE_DELAY_LENGTH,s_idx,s_depth,s_freq);
// flange.voices(s_idx,s_depth,s_freq);
// Здесь можно встроить "granular" - сделать голос Буратино или наоборот
// granular.begin(granularMemory, GRANULAR_MEMORY_SIZE);
// granular.beginFreeze(grainLength);
// granular.beginPitchShift(grainLength);
// granular.stop();
}
elapsedMillis fps;
void loop() {
    float Peak = 0;
    float fft, rms;
// Светодиодные индикаторы
    if(fps > 24) {
        if (peak.available()) {
            fps = 0;
            Peak = peak.read();
            if (Peak >= 0.1) {
                envelope_limiter();
                peak_meter(Peak);
            } else envelope_trigger();
        }
    }

    if (FFT.available()) {
        fft = FFT.read(1,126);
        if (fft >= 0.1) {
            fft_meter(fft);
        }
    } else {
        digitalWrite(ledFFT1, HIGH);
        digitalWrite(ledFFT2, HIGH);
    }

    if (RMS.available()) {
        rms = RMS.read();
        if (rms >= 0.1) {
            rms_meter(rms);
        }
    } else {
        analogWrite(ledRMS, 255);
    }
}
// Включаем "granular"
// granular.beginPitchShift (32);
// granular.setSpeed(1.3);
// Настройка генератора огибающей
void envelope_setup() {
    if (!envelope.isActive() || !envelope.isSustain()) {
        envelope.noteOn();
        envelope.attack(0);
// Время удержания, по умолчанию 2,5 миллисекунды, макс. 11880 миллисекунд
// envelope.hold(milliseconds);
        envelope.decay(0);
// Время затухания, по умолчанию 35 миллисекунд, максимум 11880 миллисекунд
        envelope.sustain(0.3);
        envelope.release(600);
    }
}
void envelope_trigger() {
    if (!envelope.isActive() || !envelope.isSustain()) {
// Истина, если фильтр находится в любой из своих 6 фаз
// envelope.isActive();
// Истина, когда огибающая находится в фазе сустейна
// envelope.isSustain();
// Включаем генератор
        envelope.noteOn();
// Задержка от noteOn() до attack(), по умолчанию 0
// envelope.delay(0);
// Время атаки, по умолчанию 10,5 миллисекунды, макс. 11880 миллисекунд
        envelope.attack(0);
// Время удержания, по умолчанию 2,5 миллисекунды
        envelope.hold(1);
// Время затухания, по умолчанию 35 миллисекунд
        envelope.decay(1);
// Уровень сустейна. От 0 до 1,0
// Усиление будет поддерживаться после decay(), но до вызова noteOff()
// Фаза сустейна определяется вызовом release()
        envelope.sustain(0.8);
// Время спада, по умолчанию 300 миллисекунд
        envelope.release(200);
// Фаза отключения
        envelope.noteOff();
    }
}
void envelope_limiter() {
// Время спуска, огибающая передает сигнал
// 0 - отключение функции (без дополнительной задержки)
// По умолчанию 5 миллисекунд
    envelope.releaseNoteOn(5);
// Фаза отключения
    envelope.noteOff();
}

Источник: https://habr.com/ru/post/655407/


Интересные статьи

Интересные статьи

Сравнительно недавно Raspberry Pi Foundation выпустила плату Raspberry Pi Pico, основанную на микроконтроллере (Micro Controller Unit, MCU) RP2040. Эта плата привлекла большое внимание чл...
Хочу рассказать, как я собрал себе кросс-компилятор для Raspberry Pi4 с помощью crosstool-ng. Возможно кому-то тема покажется слишком примитивной и скучной. Я и сам поначалу думал, что ...
Кто не знает о семействе одноплатных компьютеров Raspberry Pi, на основе которых было сделано бесчисленное множество самоделок. Сегодня хотим с вами поделиться переводом обзора Raspberr...
Есть одна проблема, которую я пытаюсь решить уже несколько лет. Как быть, если хочется носить Raspberry Pi на шее, на шнурке, но при этом не хотелось бы, тоже на шее, носить громоздки...
Ваш сайт работает на 1С-Битрикс? Каждому клиенту вы даёте собственную скидку или назначаете персональную цену на товар? Со временем в вашей 1С сложилась непростая логика ценообразования и формирования...