Ср мар 06, 2024 08:59:16
Ср мар 06, 2024 10:54:04
Ср мар 06, 2024 10:58:48
Ср мар 06, 2024 17:52:55
Чт мар 07, 2024 05:00:31
Чт мар 07, 2024 09:18:59
olegue писал(а):я внимательно и очень вдумчиво несколько раз перечитал...
shaaimars писал(а):я не уверен, что смогу нормально наладить связь между двумя смартфонами
shaaimars писал(а):Планируется использовать отдельную плату-кодек, большинство из которых нынче выдают I2S сигнал....
Чт мар 07, 2024 11:53:08
Чт мар 07, 2024 15:47:44
Чт мар 07, 2024 19:40:43
Пт мар 08, 2024 11:28:13
shaaimars писал(а):Вроде бы их используют в первую очередь как специальный быстродействующий 16-и-более-битный АЦП для качественной записи звука, ввиду отсутствия такового в esp32 и тем более в мегах. Поправьте меня, если не так.
Пт мар 08, 2024 18:39:47
Пт мар 08, 2024 23:49:30
Сб мар 30, 2024 19:02:22
Вс мар 31, 2024 13:03:20
Вт апр 16, 2024 19:31:18
Ср апр 17, 2024 20:44:31
Пн апр 29, 2024 21:57:46
#include <Wire.h>
#include <SparkFun_WM8960_Arduino_Library.h>
#include "FS.h"
#include "SD.h"
// Click here to get the library: http://librarymanager/All#SparkFun_WM8960
WM8960 codec;
// Include I2S driver
#include <driver/i2s.h>
// Connections to I2S
#define I2S_WS 25
#define I2S_SD 17
#define I2S_SDO 4
#define I2S_SCK 16
// Use I2S Processor 0
#define I2S_PORT I2S_NUM_0
// Define input buffer length
#define bufferLen 64
uint8_t sBuffer[bufferLen*2];
size_t bytesIn = 0;
size_t bytesOut = 0;
boolean is_recording = false;
int file_num = 0;
byte header[44] = {};
fs::File fContent;
size_t audio_data_size = 0;
int testcounter = 0;
void setup() {
Serial.begin(115200);
Serial.println("Example 8 - I2S Passthough");
pinMode(33, INPUT);
Wire.begin();
if (codec.begin() == false) //Begin communication over I2C
{
Serial.println("The I2S device did not respond. Please check wiring.");
while (1)
; // Freeze
}
Serial.println("I2S device is connected properly.");
codec_setup();
// Set up I2S
i2s_install();
i2s_setpin();
i2s_start(I2S_PORT);
}
void loop() {
// Get I2S data and place in data buffer
esp_err_t result = i2s_read(I2S_PORT, &sBuffer, bufferLen, &bytesIn, portMAX_DELAY);
testcounter++;
if (result == ESP_OK) {
// Продолжение записи если флаг = 1
if (is_recording) {
// Запись
audio_data_size += fContent.write(sBuffer, bufferLen*2);
// Если сигнала на запись нет, убираем флаг, прекращаем запись и меняем header
if (digitalRead(33) == 0) {
is_recording = false;
Serial.println("recording ended");
CreateWavHeader(header, audio_data_size);
fContent.seek(0);
fContent.write((const byte *)header, sizeof(header));
fContent.close();
SD.end();
Serial.println("File closed, card demounted succesfully");
}
}
// Если флага записи нет
else {
// Если есть сигнал на запись, создаем файл и ставим флаг на запись
if (digitalRead(33) == 1) {
is_recording = true;
file_num++;
if (!SD.begin()) {
Serial.println("Card Mount Failed");
} else {
Serial.println("Card mounted successfully");
}
fContent = SD.open("/file" + String(file_num, DEC) + ".wav", FILE_WRITE);
fContent.write((const byte *)header, sizeof(header));
Serial.println("file" + String(file_num, DEC) + " file created, recording started");
}
}
// Send what we just received back to the codec
esp_err_t result_w = i2s_write(I2S_PORT, &sBuffer, bytesIn, &bytesOut, portMAX_DELAY);
// If there was an I2S write error, let us know on the serial terminal
if (result_w != ESP_OK) {
Serial.print("I2S write error.");
}
}
// DelayMicroseconds(300); // Only hear to demonstrate how much time you have
// to do things.
// Do not do much in this main loop, or the audio won't pass through correctly.
// With default settings (64 samples in buffer), you can spend up to 300
// microseconds doing something in between passing each buffer of data
// You can tweak the buffer length to get more time if you need it.
// When bufferlength is 64, then you get ~300 microseconds
// When bufferlength is 128, then you get ~600 microseconds
// Note, as you increase bufferlength, then you are increasing latency between
// ADC input to DAC output.
// Latency may or may not be desired, depending on the project.
}
void codec_setup() {
// General setup needed
codec.enableVREF();
codec.enableVMID();
// Setup signal flow to the ADC
codec.enableLMIC();
codec.enableRMIC();
// Connect from INPUT1 to "n" (aka inverting) inputs of PGAs.
codec.connectLMN1();
codec.connectRMN1();
// Disable mutes on PGA inputs (aka INTPUT1)
codec.disableLINMUTE();
codec.disableRINMUTE();
// Set pga volumes
codec.setLINVOLDB(0.00); // Valid options are -17.25dB to +30dB (0.75dB steps)
codec.setRINVOLDB(0.00); // Valid options are -17.25dB to +30dB (0.75dB steps)
// Set input boosts to get inputs 1 to the boost mixers
codec.setLMICBOOST(WM8960_MIC_BOOST_GAIN_0DB);
codec.setRMICBOOST(WM8960_MIC_BOOST_GAIN_0DB);
// Connect from MIC inputs (aka pga output) to boost mixers
codec.connectLMIC2B();
codec.connectRMIC2B();
// Enable boost mixers
codec.enableAINL();
codec.enableAINR();
// Disconnect LB2LO (booster to output mixer (analog bypass)
// For this example, we are going to pass audio throught the ADC and DAC
codec.disableLB2LO();
codec.disableRB2RO();
// Connect from DAC outputs to output mixer
codec.enableLD2LO();
codec.enableRD2RO();
// Set gainstage between booster mixer and output mixer
// For this loopback example, we are going to keep these as low as they go
codec.setLB2LOVOL(WM8960_OUTPUT_MIXER_GAIN_NEG_21DB);
codec.setRB2ROVOL(WM8960_OUTPUT_MIXER_GAIN_NEG_21DB);
// Enable output mixers
codec.enableLOMIX();
codec.enableROMIX();
// CLOCK STUFF, These settings will get you 44.1KHz sample rate, and class-d
// freq at 705.6kHz
codec.enablePLL(); // Needed for class-d amp clock
codec.setPLLPRESCALE(WM8960_PLLPRESCALE_DIV_2);
codec.setSMD(WM8960_PLL_MODE_FRACTIONAL);
codec.setCLKSEL(WM8960_CLKSEL_PLL);
codec.setSYSCLKDIV(WM8960_SYSCLK_DIV_BY_2);
codec.setBCLKDIV(4);
codec.setDCLKDIV(WM8960_DCLKDIV_16);
codec.setPLLN(7);
codec.setPLLK(0x86, 0xC2, 0x26); // PLLK=86C226h
//codec.setADCDIV(0); // Default is 000 (what we need for 44.1KHz)
//codec.setDACDIV(0); // Default is 000 (what we need for 44.1KHz)
codec.setWL(WM8960_WL_16BIT);
codec.enablePeripheralMode();
//codec.enableMasterMode();
//codec.setALRCGPIO(); // Note, should not be changed while ADC is enabled.
// Enable ADCs and DACs
codec.enableAdcLeft();
codec.enableAdcRight();
codec.enableDacLeft();
codec.enableDacRight();
codec.disableDacMute();
//codec.enableLoopBack(); // Loopback sends ADC data directly into DAC
codec.disableLoopBack();
// Default is "soft mute" on, so we must disable mute to make channels active
codec.disableDacMute();
codec.enableHeadphones();
codec.enableOUT3MIX(); // Provides VMID as buffer for headphone ground
Serial.println("Volume set to +0dB");
codec.setHeadphoneVolumeDB(0.00);
Serial.println("Codec Setup complete. Listen to left/right INPUT1 on Headphone outputs.");
}
void i2s_install() {
// Set up I2S Processor configuration
const i2s_driver_config_t i2s_config = {
.mode = i2s_mode_t(I2S_MODE_MASTER | I2S_MODE_RX | I2S_MODE_TX),
.sample_rate = 44100,
.bits_per_sample = i2s_bits_per_sample_t(16),
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
.communication_format = i2s_comm_format_t(I2S_COMM_FORMAT_STAND_MSB),
.intr_alloc_flags = 0,
.dma_buf_count = 8,
.dma_buf_len = bufferLen,
.use_apll = false,
.tx_desc_auto_clear = false,
.fixed_mclk = 0,
.mclk_multiple = i2s_mclk_multiple_t(I2S_MCLK_MULTIPLE_DEFAULT),
.bits_per_chan = i2s_bits_per_chan_t(I2S_BITS_PER_CHAN_DEFAULT)
};
i2s_driver_install(I2S_PORT, &i2s_config, 0, NULL);
}
void i2s_setpin() {
// Set I2S pin configuration
const i2s_pin_config_t pin_config = {
.mck_io_num = I2S_PIN_NO_CHANGE,
.bck_io_num = I2S_SCK,
.ws_io_num = I2S_WS,
.data_out_num = I2S_SDO,
.data_in_num = I2S_SD
};
i2s_set_pin(I2S_PORT, &pin_config);
}
void CreateWavHeader(byte *header, int waveDataSize) {
header[0] = 'R';
header[1] = 'I';
header[2] = 'F';
header[3] = 'F';
unsigned int fileSizeMinus8 = waveDataSize + 44 - 8;
header[4] = (byte)(fileSizeMinus8 & 0xFF);
header[5] = (byte)((fileSizeMinus8 >> 8) & 0xFF);
header[6] = (byte)((fileSizeMinus8 >> 16) & 0xFF);
header[7] = (byte)((fileSizeMinus8 >> 24) & 0xFF);
header[8] = 'W';
header[9] = 'A';
header[10] = 'V';
header[11] = 'E';
header[12] = 'f';
header[13] = 'm';
header[14] = 't';
header[15] = ' ';
header[16] = 0x10; // linear PCM
header[17] = 0x00;
header[18] = 0x00;
header[19] = 0x00;
header[20] = 0x01; // linear PCM
header[21] = 0x00;
header[22] = 0x02; // stereo
header[23] = 0x00;
header[24] = 0x44; // sampling rate 44100
header[25] = 0xAC;
header[26] = 0x00;
header[27] = 0x00;
header[28] = 0x10; // Byte/sec = 44100x2x2 = 176400
header[29] = 0xB1;
header[30] = 0x02;
header[31] = 0x00;
header[32] = 0x04; // 16bit stereo
header[33] = 0x00;
header[34] = 0x10; // 16bit
header[35] = 0x00;
header[36] = 'd';
header[37] = 'a';
header[38] = 't';
header[39] = 'a';
header[40] = (byte)(waveDataSize & 0xFF);
header[41] = (byte)((waveDataSize >> 8) & 0xFF);
header[42] = (byte)((waveDataSize >> 16) & 0xFF);
header[43] = (byte)((waveDataSize >> 24) & 0xFF);
}
52 49 46 46 a4 64 21 00 57 41 56 45 66 6d 74 20
R I F F d ! W A V E f m t
10 00 00 00 01 00 02 00 44 ac 00 00 10 b1 02 00
D
04 00 10 00 64 61 74 61 80 64 21 00 16 00 01 80
d a t a d !
16 80 00 80 13 00 00 80 12 00 03 80 0b 00 01 00
03 00 04 00 f8 ff 01 00 f3 ff 02 80 f2 ff 02 80
f0 7f 01 80 ee ff 03 00 f0 ff 01 00 f2 7f 04 80
fa ff 03 80 f9 7f 03 80 f9 7f 02 80 f7 ff 00 80
f6 7f 03 80 f4 7f 01 80 f4 7f 05 80 f5 ff 00 00
Вт апр 30, 2024 12:41:13
Ср май 01, 2024 19:00:07
и да... никаких выходов шумодава не требуется... делает проще - ESP32 непрерывно цифрует звук или шум с рации...
Чт май 02, 2024 11:28:20
shaaimars писал(а):Зачем изобретать колесо, если есть готовый выход?