Ви не увійшли.
Приветствую всех. Впервые столкнулся с проблемой , которую не смог решить гуглом и чтением существующих тем на форумах. Итак делаю проект барабанного триггерного модуля , который воспроизводит звук бас-бочки ( звук в формате wav сохранен в памяти программ ) по сигналу с триггера ( как это выглядит на практике можно посмотреть тут https://youtu.be/mbOvT2CbM3Y?t=93 ) . На данный момент проект существует на платформе Teensy 3.2 + Teensy Audio Board и работает прекрасно . Решил перенести на ESP32 в связке с ЦАП pcm5102 . Поскольку для ESP32 нет аудио-библиотеки , которая бы работала подобно Teensy Audio Library пришлось нужную функцию написать самому. Вернее адаптировать под себя найденный пример на просторах интернета. Cуть проста - инициализируется интерфейс I2S , которому в loop() передается порциями данные аудио из wav файла , и когда все данные переданы воспроизведение останавливается сбросом флага. Так вот каждый раз уже после вывода всех аудио данных звучит довольно ощутимый щелчек ( аудио файл и снимок из cubase ниже ) , как при отключении усилителя обычно происходит. Так же и в начале есть подобный эффект , но гораздо менее ощутимый и слышеш только в наушниках ( семпл бас-бочки имеет плавное нарастание и спад громкости в начале и конце соотв. так что этот артефакт результат не самого аудио файла , а именно аппаратной или программной части ESP32 ) . Так вот у меня вопрос - чем это вызванно и как с этим бороться ? В документации по I2S на сайте Espressif я не нашел функции I2S.Mute() или что нибудь подобное . Кроме того попутный вопрос - как правильно "наложить " воспроизведение двух таких семплов друг на друга со смещением по времени . Т.е. допустим у меня уже запустилось воспроизведение семпла один раз и пока оно длится приходит второй сигнал от триггера и нужно запустить еще раз вопроизведение этого же семпла . Изначально я думал в этой ситуации при повторном срабатывании триггера просто возвращать указатель на аудио-данные wav файла в начало и делать так кадый раз пока не перестанут идти сигналы с триггера и файл просто не доиграет до конца. Но теперь мне кажется , что это не лучшая идея т.к. резкое прерывание воспроизведения будет вызывать подобные искажения с щелчками или еще чем похуже. Спасибо заранее за помощь.
Аудио файл записан в линейный вход звуковой карты с выхода ЦАП
https://on.soundcloud.com/drGnZ
//------------------------------------------------------------------------------------------------------------------------
#include "driver/i2s.h"
#include "Kick.h" // файл wav
//------------------------------------------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------------------------------------------
bool isPlaing = true ; // флаг состояния воспроизведения ( играет/не играет )
static const i2s_port_t i2s_num = I2S_NUM_0; // i2s номер порта
unsigned const char* TheData; // указатель на данные wav файла
uint32_t DataIdx=0; // значение смещения указателя "TheData" в процессе передачи порции данных интерфейсу I2S
const uint8_t* nameWav ;
struct WavHeader_Struct
{
// RIFF Section
char RIFFSectionID[4]; // "RIFF"
uint32_t Size; // Size of entire file less 8
char RiffFormat[4]; // "WAVE"
// Format Section
char FormatSectionID[4]; // letters "fmt"
uint32_t FormatSize; // Size of format section less 8
uint16_t FormatID; // 1=uncompressed PCM
uint16_t NumChannels; // 1=mono,2=stereo
uint32_t SampleRate; // 44100, 16000, 8000 etc.
uint32_t ByteRate; // =SampleRate * Channels * (BitsPerSample/8)
uint16_t BlockAlign; // =Channels * (BitsPerSample/8)
uint16_t BitsPerSample; // 8,16,24 or 32
// Data Section
char DataSectionID[4]; // The letters "data"
uint32_t DataSize; // Size of the data that follows
}WavHeader;
//------------------------------------------------------------------------------------------------------------------------
uint32_t currenttime ;
uint32_t looptime ;
//------------------------------------------------------------------------------------------------------------------------
// I2S configuration structures
static const i2s_config_t i2s_config = {
.mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX),
.sample_rate = 44100, // Note, this will be changed later
.bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT,
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
.communication_format = (i2s_comm_format_t)(I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB),
.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1, // high interrupt priority
.dma_buf_count = 8, // 8 buffers
.dma_buf_len = 1024, // 1K per buffer, so 8K of buffer space
.use_apll=0,
.tx_desc_auto_clear= true,
.fixed_mclk=-1
};
// These are the physical wiring connections to our I2S decoder board/chip from the esp32, there are other connections
// required for the chips mentioned at the top (but not to the ESP32), please visit the page mentioned at the top for
// further information regarding these other connections.
static const i2s_pin_config_t pin_config = {
.bck_io_num = 26, // The bit clock connectiom, goes to pin 27 of ESP32
.ws_io_num = 25, // Word select, also known as word select or left right clock
.data_out_num = 27, // Data out from the ESP32, connect to DIN on 38357A
.data_in_num = I2S_PIN_NO_CHANGE // we are not interested in I2S data into the ESP32
};
//------------------------------------------------------------------------------------------------------------------------
void setup() {
memcpy(&WavHeader,&rawData,44); // копируем "заголовочную" часть wav файла в структуру
i2s_driver_install(i2s_num, &i2s_config, 0, NULL); // Инициализация I2S
i2s_set_pin(i2s_num, &pin_config); // Назначаем пины I2S
i2s_set_sample_rates(i2s_num, WavHeader.SampleRate);
TheData=rawData;
nameWav=TheData+44; // смешаем указатель на начало аудио-данных wav файла
}
void loop()
{
playWav();
}
void playWav(void){
size_t BytesWritten;
while(DataIdx!=WavHeader.DataSize && isPlaing )
{
i2s_write(i2s_num,TheData+DataIdx,4,&BytesWritten,1); // выводим данные на I2S , если звуковые данные являются представлением двух байт на каждный канал ,
// мы отдаем интерфейсу четыре байта за один раз
DataIdx+=4; // смещение указателя на четыре байта в массиве данных wav
if (DataIdx>=WavHeader.DataSize){ // если вывели все данные
// возвращаем указатель в началао массива данных
DataIdx=0;
isPlaing=false; // сбрасываем флаг для остановки воспроизведения . Если не сбрасывать , файл будет воспроизводиться зацикленно
}
}
}
Неактивний
Розкажіть, що буде, якщо до або після циклу while додати рядок:
if (!isPlaing) i2s_write(i2s_num,TheData+WavHeader.DataSize-4,4,&BytesWritten,1);
Завтра попробую и отпишусь о результате . Кстати сегодня попробовал связать Teensy и PCM5102 , тоже были артефакты , но не такие , возможно дело в длинных проводах между платами. Или отсутствие MCLK . Потоковое адуио играет нормально ( пробовал интернет-радио воспроизводить ) а вот с короткими семплами беда какая-то.
Неактивний
Попробовал - результат тот же. Мало того , я пробовал изначально обрезать воспроизведение на 6 и 10 кБайт задавая условие
while(DataIdx!=(WavHeader.DataSize - 6144) && isPlaing ) при общем объеме wav файла около 19кБайт и результат тот же. Причем звук бочки меняется естетсвенно , а вот артефакт в конце остается тот же и звучит с тем же интервалом после звука бочки . Teensy + PCM5102 сегодня попробовал с максимально короткими проводами - все нормально. Так что ЦАП исправен и проблема именно в ESP . Есть в наличии ESP8266 попробую еще на ней испытать этот код .
Неактивний
Не знаю , что именно было причиной , ибо этот же семпл на ESP8266 c библиотекой ESP8266-Audio нормально играл . Но почему-то этот же код , скомпилированный для есп32 , давал подобный эффект. В итоге я решил попробовать другой семпл и все стало нормально . Так что вопрос решен .
Неактивний