Use centralized modules
This commit is contained in:
@@ -1,444 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2021 Marcel Licence
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Dieses Programm ist Freie Software: Sie k�nnen es unter den Bedingungen
|
||||
* der GNU General Public License, wie von der Free Software Foundation,
|
||||
* Version 3 der Lizenz oder (nach Ihrer Wahl) jeder neueren
|
||||
* ver�ffentlichten Version, weiter verteilen und/oder modifizieren.
|
||||
*
|
||||
* Dieses Programm wird in der Hoffnung bereitgestellt, dass es n�tzlich sein wird, jedoch
|
||||
* OHNE JEDE GEW�HR,; sogar ohne die implizite
|
||||
* Gew�hr der MARKTF�HIGKEIT oder EIGNUNG F�R EINEN BESTIMMTEN ZWECK.
|
||||
* Siehe die GNU General Public License f�r weitere Einzelheiten.
|
||||
*
|
||||
* Sie sollten eine Kopie der GNU General Public License zusammen mit diesem
|
||||
* Programm erhalten haben. Wenn nicht, siehe <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file audio_module.ino
|
||||
* @author Marcel Licence
|
||||
* @date 16.12.2021
|
||||
*
|
||||
* @brief this file provides a general audio interface to make it easier working with different platforms
|
||||
*/
|
||||
|
||||
|
||||
#ifdef __CDT_PARSER__
|
||||
#include <cdt.h>
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef ESP8266
|
||||
#include <ESP8266WiFi.h>
|
||||
#include <I2S.h>
|
||||
#include <i2s_reg.h>
|
||||
#endif
|
||||
|
||||
#ifdef ESP32
|
||||
#include <WiFi.h>
|
||||
#endif
|
||||
|
||||
#ifdef TEENSYDUINO
|
||||
#include <Audio.h>
|
||||
#include <Wire.h>
|
||||
#include <SPI.h>
|
||||
#include <SD.h>
|
||||
#include <SerialFlash.h>
|
||||
#endif
|
||||
|
||||
#ifdef ARDUINO_DAISY_SEED
|
||||
#include "DaisyDuino.h"
|
||||
#endif
|
||||
|
||||
#ifdef ARDUINO_RASPBERRY_PI_PICO
|
||||
#include <I2S.h>
|
||||
#endif
|
||||
|
||||
void Audio_Setup(void)
|
||||
{
|
||||
#if (defined ESP8266) || (defined ESP32)
|
||||
WiFi.mode(WIFI_OFF);
|
||||
btStop();
|
||||
#endif
|
||||
|
||||
#if 0 //ndef ESP8266
|
||||
btStop();
|
||||
esp_wifi_deinit();
|
||||
#endif
|
||||
|
||||
#ifdef ESP32_AUDIO_KIT
|
||||
#ifdef ES8388_ENABLED
|
||||
ES8388_Setup();
|
||||
ES8388_SetIn2OoutVOL(0, 0);
|
||||
#else
|
||||
ac101_setup();
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef ESP32
|
||||
setup_i2s();
|
||||
#endif
|
||||
|
||||
#ifdef ESP8266
|
||||
#if 0
|
||||
system_update_cpu_freq(160);
|
||||
i2s_begin();
|
||||
i2s_set_rate(SAMPLE_RATE);
|
||||
#else
|
||||
I2S_init();
|
||||
#endif
|
||||
pinMode(2, INPUT); //restore GPIOs taken by i2s
|
||||
pinMode(15, INPUT);
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef TEENSYDUINO
|
||||
AudioMemory(4);
|
||||
#endif
|
||||
|
||||
#ifdef ARDUINO_SEEED_XIAO_M0
|
||||
SAMD21_Synth_Init();
|
||||
pinMode(DAC0, OUTPUT);
|
||||
#endif
|
||||
|
||||
#ifdef ARDUINO_RASPBERRY_PI_PICO
|
||||
if (!I2S.begin(SAMPLE_RATE))
|
||||
{
|
||||
Serial.println("Failed to initialize I2S!");
|
||||
while (1); // do nothing
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef TEENSYDUINO
|
||||
|
||||
const int ledPin = LED_PIN; /* pin configured in config.h */
|
||||
|
||||
#if 1
|
||||
AudioPlayQueue queue1;
|
||||
AudioPlayQueue queue2;
|
||||
AudioOutputI2S i2s1;
|
||||
AudioConnection patchCord1(queue1, 0, i2s1, 0); /* left channel */
|
||||
AudioConnection patchCord2(queue2, 0, i2s1, 1); /* right channel */
|
||||
#else
|
||||
|
||||
// GUItool: begin automatically generated code
|
||||
AudioInputUSB usb1; //xy=134,545
|
||||
AudioPlayQueue queue1; //xy=258,380
|
||||
AudioPlayQueue queue2; //xy=261,423
|
||||
AudioRecordQueue queue6; //xy=265,557
|
||||
AudioRecordQueue queue5; //xy=274,516
|
||||
AudioPlayQueue queue4; //xy=352,622
|
||||
AudioPlayQueue queue3; //xy=380,530
|
||||
AudioOutputI2S i2s1; //xy=470,393
|
||||
AudioOutputUSB usb2; //xy=494,544
|
||||
AudioConnection patchCord1(usb1, 0, queue5, 0);
|
||||
AudioConnection patchCord2(usb1, 1, queue6, 0);
|
||||
AudioConnection patchCord3(queue1, 0, i2s1, 0);
|
||||
AudioConnection patchCord4(queue2, 0, i2s1, 1);
|
||||
AudioConnection patchCord5(queue3, 0, usb2, 0);
|
||||
AudioConnection patchCord6(queue4, 0, usb2, 1);
|
||||
// GUItool: end automatically generated code
|
||||
#endif
|
||||
|
||||
|
||||
static int16_t sampleBuffer[AUDIO_BLOCK_SAMPLES];
|
||||
static int16_t sampleBuffer2[AUDIO_BLOCK_SAMPLES];
|
||||
static int16_t *queueTransmitBuffer;
|
||||
static int16_t *queueTransmitBuffer2;
|
||||
|
||||
void Teensy_Setup()
|
||||
{
|
||||
pinMode(ledPin, OUTPUT);
|
||||
Midi_Setup();
|
||||
}
|
||||
|
||||
#endif /* TEENSYDUINO */
|
||||
|
||||
#ifdef ARDUINO_DAISY_SEED
|
||||
|
||||
static DaisyHardware hw;
|
||||
static size_t num_channels;
|
||||
|
||||
volatile static bool dataReady = false;
|
||||
static float out_temp[2][48];
|
||||
static float *outCh[2] = {out_temp[0], out_temp[1]};
|
||||
|
||||
void MyCallback(float **in, float **out, size_t size)
|
||||
{
|
||||
for (size_t i = 0; i < size; i++)
|
||||
{
|
||||
|
||||
out[0][i] = out_temp[0][i];
|
||||
out[1][i] = out_temp[1][i];
|
||||
out_temp[0][i] = in[0][i];
|
||||
out_temp[1][i] = in[1][i];
|
||||
}
|
||||
dataReady = true;
|
||||
}
|
||||
|
||||
void DaisySeed_Setup(void)
|
||||
{
|
||||
float sample_rate;
|
||||
// Initialize for Daisy pod at 48kHz
|
||||
hw = DAISY.init(DAISY_SEED, AUDIO_SR_48K);
|
||||
num_channels = hw.num_channels;
|
||||
sample_rate = DAISY.get_samplerate();
|
||||
|
||||
DAISY.begin(MyCallback);
|
||||
}
|
||||
#endif /* ARDUINO_DAISY_SEED */
|
||||
|
||||
#ifdef ARDUINO_SEEED_XIAO_M0
|
||||
|
||||
static int32_t u32buf[SAMPLE_BUFFER_SIZE];
|
||||
|
||||
inline
|
||||
void ProcessAudio(uint16_t *buff, size_t len)
|
||||
{
|
||||
/* convert from u16 to u10 */
|
||||
for (size_t i = 0; i < len; i++)
|
||||
{
|
||||
const int32_t preDiv = 4194304; // 2 ^ (16 + 6)
|
||||
buff[i] = (uint16_t)(0x200 + (u32buf[i] / (preDiv)));
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void Audio_OutputMono(int32_t *samples)
|
||||
{
|
||||
#ifdef ESP8266
|
||||
for (int i = 0; i < SAMPLE_BUFFER_SIZE; i++)
|
||||
{
|
||||
int32_t sig = samples[i];
|
||||
static uint16_t sig16 = 0;
|
||||
sig *= 4;
|
||||
sig16 = sig;
|
||||
while (!I2S_isNotFull())
|
||||
{
|
||||
/* wait for buffer is not full */
|
||||
}
|
||||
writeDAC(0x8000 + sig16);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ESP32
|
||||
float mono[SAMPLE_BUFFER_SIZE];
|
||||
for (int i = 0; i < SAMPLE_BUFFER_SIZE; i++)
|
||||
{
|
||||
float sigf = samples[i];
|
||||
sigf /= INT16_MAX;
|
||||
mono[i] = sigf;
|
||||
}
|
||||
|
||||
i2s_write_stereo_samples_buff(mono, mono, SAMPLE_BUFFER_SIZE);
|
||||
#endif /* ESP32 */
|
||||
|
||||
#ifdef TEENSYDUINO
|
||||
{
|
||||
#ifdef CYCLE_MODULE_ENABLED
|
||||
calcCycleCountPre();
|
||||
#endif
|
||||
queueTransmitBuffer = queue1.getBuffer(); /* blocking? */
|
||||
queueTransmitBuffer2 = queue2.getBuffer();
|
||||
#ifdef CYCLE_MODULE_ENABLED
|
||||
calcCycleCount();
|
||||
#endif
|
||||
if (queueTransmitBuffer)
|
||||
{
|
||||
{
|
||||
for (size_t i = 0; i < AUDIO_BLOCK_SAMPLES; i++)
|
||||
{
|
||||
sampleBuffer[i] = (int16_t)((samples[i]));
|
||||
}
|
||||
|
||||
memcpy(queueTransmitBuffer, sampleBuffer, AUDIO_BLOCK_SAMPLES * 2);
|
||||
memcpy(queueTransmitBuffer2, sampleBuffer, AUDIO_BLOCK_SAMPLES * 2);
|
||||
}
|
||||
queue1.playBuffer();
|
||||
queue2.playBuffer();
|
||||
}
|
||||
}
|
||||
#endif /* TEENSYDUINO */
|
||||
|
||||
#ifdef ARDUINO_DAISY_SEED
|
||||
|
||||
float sig_f[SAMPLE_BUFFER_SIZE];
|
||||
|
||||
#ifdef CYCLE_MODULE_ENABLED
|
||||
calcCycleCountPre();
|
||||
#endif
|
||||
while (!dataReady)
|
||||
{
|
||||
/* just do nothing */
|
||||
}
|
||||
#ifdef CYCLE_MODULE_ENABLED
|
||||
calcCycleCount();
|
||||
#endif
|
||||
|
||||
for (size_t i = 0; i < SAMPLE_BUFFER_SIZE; i++)
|
||||
{
|
||||
sig_f[i] = ((float)samples[i]) * (1.0f / ((float)INT16_MAX));
|
||||
}
|
||||
|
||||
memcpy(out_temp[0], sig_f, sizeof(out_temp[0]));
|
||||
memcpy(out_temp[1], sig_f, sizeof(out_temp[1]));
|
||||
|
||||
dataReady = false;
|
||||
#endif /* ARDUINO_DAISY_SEED */
|
||||
|
||||
#ifdef ARDUINO_SEEED_XIAO_M0
|
||||
#ifdef CYCLE_MODULE_ENABLED
|
||||
calcCycleCountPre();
|
||||
#endif
|
||||
while (!SAMD21_Synth_Process(ProcessAudio))
|
||||
{
|
||||
/* just do nothing */
|
||||
}
|
||||
#ifdef CYCLE_MODULE_ENABLED
|
||||
calcCycleCount();
|
||||
#endif
|
||||
memcpy(u32buf, samples, sizeof(int32_t)*SAMPLE_BUFFER_SIZE);
|
||||
#endif /* ARDUINO_SEEED_XIAO_M0 */
|
||||
|
||||
#ifdef ARDUINO_RASPBERRY_PI_PICO
|
||||
/*
|
||||
* @see https://arduino-pico.readthedocs.io/en/latest/i2s.html
|
||||
* @see https://www.waveshare.com/pico-audio.htm for connections
|
||||
*/
|
||||
int16_t u16int[2 * SAMPLE_BUFFER_SIZE];
|
||||
|
||||
for (int i = 0; i < SAMPLE_BUFFER_SIZE; i++)
|
||||
{
|
||||
u16int[2 * i] = samples[i];
|
||||
u16int[(2 * i) + 1] = samples[i];
|
||||
}
|
||||
#if 1
|
||||
for (int i = 0; i < SAMPLE_BUFFER_SIZE * 2; i++)
|
||||
{
|
||||
I2S.write(u16int[i]);
|
||||
}
|
||||
#else
|
||||
/* this does not work, I do not know why :-/ */
|
||||
static int16_t u16int_buf[2 * SAMPLE_BUFFER_SIZE];
|
||||
memcpy(u16int_buf, u16int, sizeof(u16int));
|
||||
I2S.write(u16int_buf, sizeof(u16int));
|
||||
#endif
|
||||
#endif /* ARDUINO_RASPBERRY_PI_PICO */
|
||||
|
||||
#ifdef ARDUINO_GENERIC_F407VGTX
|
||||
/*
|
||||
* Todo Implementation for the STM32F407VGT6
|
||||
* Can be found on the ST Discovery Board
|
||||
*/
|
||||
#if 0
|
||||
int16_t u16int[2 * SAMPLE_BUFFER_SIZE];
|
||||
|
||||
for (int i = 0; i < SAMPLE_BUFFER_SIZE; i++)
|
||||
{
|
||||
u16int[2 * i] = samples[i];
|
||||
u16int[(2 * i) + 1] = samples[i];
|
||||
}
|
||||
for (int i = 0; i < SAMPLE_BUFFER_SIZE * 2; i++)
|
||||
{
|
||||
I2S.write(u16int[i]);
|
||||
}
|
||||
#endif
|
||||
#endif /* ARDUINO_GENERIC_F407VGTX */
|
||||
}
|
||||
|
||||
#if (defined ESP32) || (defined TEENSYDUINO) || (defined ARDUINO_DAISY_SEED) || (defined ARDUINO_GENERIC_F407VGTX)
|
||||
void Audio_Input(float *left, float *right)
|
||||
{
|
||||
#ifdef ESP32
|
||||
i2s_read_stereo_samples_buff(left, right, SAMPLE_BUFFER_SIZE);
|
||||
#endif /* ESP32 */
|
||||
}
|
||||
|
||||
void Audio_Output(float *left, float *right)
|
||||
{
|
||||
#ifdef ESP32
|
||||
i2s_write_stereo_samples_buff(left, right, SAMPLE_BUFFER_SIZE);
|
||||
#endif /* ESP32 */
|
||||
|
||||
#ifdef TEENSYDUINO
|
||||
{
|
||||
#ifdef CYCLE_MODULE_ENABLED
|
||||
calcCycleCountPre();
|
||||
#endif
|
||||
queueTransmitBuffer = queue1.getBuffer(); /* blocking? */
|
||||
queueTransmitBuffer2 = queue2.getBuffer();
|
||||
#ifdef CYCLE_MODULE_ENABLED
|
||||
calcCycleCount();
|
||||
#endif
|
||||
if (queueTransmitBuffer)
|
||||
{
|
||||
{
|
||||
for (size_t i = 0; i < AUDIO_BLOCK_SAMPLES; i++)
|
||||
{
|
||||
sampleBuffer[i] = (int16_t)(left[i] * INT16_MAX);
|
||||
sampleBuffer2[i] = (int16_t)(right[i] * INT16_MAX);
|
||||
}
|
||||
|
||||
memcpy(queueTransmitBuffer, sampleBuffer, AUDIO_BLOCK_SAMPLES * 2);
|
||||
memcpy(queueTransmitBuffer2, sampleBuffer2, AUDIO_BLOCK_SAMPLES * 2);
|
||||
}
|
||||
|
||||
queue1.playBuffer();
|
||||
queue2.playBuffer();
|
||||
}
|
||||
}
|
||||
#endif /* TEENSYDUINO */
|
||||
|
||||
#ifdef ARDUINO_DAISY_SEED
|
||||
|
||||
#ifdef CYCLE_MODULE_ENABLED
|
||||
calcCycleCountPre();
|
||||
#endif
|
||||
while (!dataReady)
|
||||
{
|
||||
/* just do nothing */
|
||||
}
|
||||
#ifdef CYCLE_MODULE_ENABLED
|
||||
calcCycleCount();
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
for (int i = 0; i < SAMPLE_BUFFER_SIZE; i++)
|
||||
{
|
||||
left[i] = i * (1.0f / ((float)SAMPLE_BUFFER_SIZE));
|
||||
right[i] = i * (1.0f / ((float)SAMPLE_BUFFER_SIZE));
|
||||
}
|
||||
#endif
|
||||
memcpy(out_temp[0], left, sizeof(out_temp[0]));
|
||||
memcpy(out_temp[1], right, sizeof(out_temp[1]));
|
||||
|
||||
|
||||
dataReady = false;
|
||||
|
||||
#endif /* ARDUINO_DAISY_SEED */
|
||||
|
||||
#ifdef ARDUINO_GENERIC_F407VGTX
|
||||
/*
|
||||
* Todo Implementation for the STM32F407VGT6
|
||||
* Can be found on the ST Discovery Board
|
||||
*/
|
||||
#endif /* ARDUINO_GENERIC_F407VGTX */
|
||||
}
|
||||
#endif /* (defined ESP32) || (defined TEENSYDUINO) || (defined ARDUINO_DAISY_SEED) || (defined ARDUINO_GENERIC_F407VGTX) */
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2021 Marcel Licence
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Dieses Programm ist Freie Software: Sie können es unter den Bedingungen
|
||||
* der GNU General Public License, wie von der Free Software Foundation,
|
||||
* Version 3 der Lizenz oder (nach Ihrer Wahl) jeder neueren
|
||||
* veröffentlichten Version, weiter verteilen und/oder modifizieren.
|
||||
*
|
||||
* Dieses Programm wird in der Hoffnung bereitgestellt, dass es nützlich sein wird, jedoch
|
||||
* OHNE JEDE GEWÄHR,; sogar ohne die implizite
|
||||
* Gewähr der MARKTFÄHIGKEIT oder EIGNUNG FÜR EINEN BESTIMMTEN ZWECK.
|
||||
* Siehe die GNU General Public License für weitere Einzelheiten.
|
||||
*
|
||||
* Sie sollten eine Kopie der GNU General Public License zusammen mit diesem
|
||||
* Programm erhalten haben. Wenn nicht, siehe <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/*
|
||||
* this file includes a simple blink task implementation
|
||||
*
|
||||
* Author: Marcel Licence
|
||||
*/
|
||||
|
||||
inline
|
||||
void Blink_Setup(void)
|
||||
{
|
||||
pinMode(LED_PIN, OUTPUT);
|
||||
}
|
||||
|
||||
|
||||
inline
|
||||
void Blink_Process(void)
|
||||
{
|
||||
static bool ledOn = true;
|
||||
if (ledOn)
|
||||
{
|
||||
digitalWrite(LED_PIN, HIGH); // turn the LED on (HIGH is the voltage level)
|
||||
}
|
||||
else
|
||||
{
|
||||
digitalWrite(LED_PIN, LOW); // turn the LED off
|
||||
}
|
||||
ledOn = !ledOn;
|
||||
}
|
||||
@@ -47,6 +47,9 @@
|
||||
#define CONFIG_H_
|
||||
|
||||
|
||||
#define SERIAL_BAUDRATE 115200
|
||||
|
||||
|
||||
//#define BOARD_ML_V1 /* activate this when using the ML PCB V1 */
|
||||
//#define BOARD_ESP32_AUDIO_KIT_AC101 /* activate this when using the ESP32 Audio Kit v2.2 with the AC101 codec */
|
||||
#define BOARD_ESP32_AUDIO_KIT_ES8388 /* activate this when using the ESP32 Audio Kit v2.2 with the ES8388 codec */
|
||||
@@ -69,7 +72,7 @@
|
||||
* include the board configuration
|
||||
* there you will find the most hardware depending pin settings
|
||||
*/
|
||||
#include <ml_boards.h> /* requires https://github.com/marcel-licence/ML_SynthTools */
|
||||
#include <ml_boards.h> /* requires the ML_Synth library: https://github.com/marcel-licence/ML_SynthTools */
|
||||
|
||||
/* our samplerate */
|
||||
#define SAMPLE_RATE 44100
|
||||
@@ -81,7 +84,7 @@
|
||||
|
||||
|
||||
/* on board led */
|
||||
#define LED_PIN 19
|
||||
#define BLINK_LED_PIN 19
|
||||
|
||||
|
||||
#endif /* CONFIG_H_ */
|
||||
|
||||
@@ -0,0 +1,236 @@
|
||||
<h1>Board Build Variants</h1>
|
||||
|
||||
Below you will find a list of build which can be configured and should compile without any problems
|
||||
|
||||
<hr>
|
||||
<a name="espressif_esp32_2_0_2_esp32"></a><b>Core:</b> <a h_ref="https://github.com/espressif/arduino-esp32">ESP32 Arduino </a><br />
|
||||
<b>Version:</b> 2.0.0<br />
|
||||
<b>Board:</b> ESP32 Dev Module<br />
|
||||
<br />
|
||||
<b>Program storage space:</b> 725241 bytes<br />
|
||||
<b>Dynamic memory:</b> 48892 bytes<br />
|
||||
<br />
|
||||
<b>PSRAM:</b> Enabled<br />
|
||||
<b>Partition Scheme:</b> Default 4MB with spiffs (1.2MB APP/1.5MB SPIFFS)<br />
|
||||
<b>CPU Frequency:</b> 240MHz (WiFi/BT)<br />
|
||||
<b>Flash Mode:</b> QIO<br />
|
||||
<b>Flash Frequency:</b> 80MHz<br />
|
||||
<b>Flash Size:</b> 4MB (32Mb)<br />
|
||||
<b>Upload Speed:</b> 921600<br />
|
||||
<b>Arduino Runs On:</b> Core 1<br />
|
||||
<b>Events Run On:</b> Core 1<br />
|
||||
<b>Core Debug Level:</b> None<br />
|
||||
<br />
|
||||
<b>Used libraries:</b><br />
|
||||
<table>
|
||||
<tr>
|
||||
<td>Name</td>
|
||||
<td>Version</td>
|
||||
<td>Url</td>
|
||||
<td>Git</td>
|
||||
<td>Core library</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>ML SynthTools</td>
|
||||
<td>1.0.1</td>
|
||||
<td>https://github.com/marcel-licence/ML_SynthTools</td>
|
||||
<td>https://github.com/marcel-licence/ML_SynthTools.git</td>
|
||||
<td>False</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>WiFi</td>
|
||||
<td>2.0.0</td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td>True</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Wire</td>
|
||||
<td>2.0.0</td>
|
||||
<td>http://arduino.cc/en/Reference/Wire</td>
|
||||
<td></td>
|
||||
<td>True</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Adafruit GFX Library</td>
|
||||
<td>1.10.10</td>
|
||||
<td>https://github.com/adafruit/Adafruit-GFX-Library</td>
|
||||
<td></td>
|
||||
<td>False</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Adafruit SSD1306</td>
|
||||
<td>2.4.5</td>
|
||||
<td>https://github.com/adafruit/Adafruit_SSD1306</td>
|
||||
<td></td>
|
||||
<td>False</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>SPI</td>
|
||||
<td>2.0.0</td>
|
||||
<td>http://arduino.cc/en/Reference/SPI</td>
|
||||
<td></td>
|
||||
<td>True</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Adafruit BusIO</td>
|
||||
<td>1.14.1</td>
|
||||
<td>https://github.com/adafruit/Adafruit_BusIO</td>
|
||||
<td>https://github.com/adafruit/Adafruit_BusIO</td>
|
||||
<td>False</td>
|
||||
</tr>
|
||||
</table><hr>
|
||||
<a name="espressif_2.0.7_esp32_esp32"></a><b>Core:</b> <a h_ref="https://github.com/espressif/arduino-esp32">ESP32 Arduino </a><br />
|
||||
<b>Version:</b> 2.0.7<br />
|
||||
<b>Board:</b> ESP32 Dev Module<br />
|
||||
<br />
|
||||
<b>Program storage space:</b> 789277 bytes<br />
|
||||
<b>Dynamic memory:</b> 53536 bytes<br />
|
||||
<br />
|
||||
<b>JTAG Adapter:</b> Disabled<br />
|
||||
<b>PSRAM:</b> Enabled<br />
|
||||
<b>Partition Scheme:</b> Default 4MB with spiffs (1.2MB APP/1.5MB SPIFFS)<br />
|
||||
<b>CPU Frequency:</b> 240MHz (WiFi/BT)<br />
|
||||
<b>Flash Mode:</b> QIO<br />
|
||||
<b>Flash Frequency:</b> 80MHz<br />
|
||||
<b>Flash Size:</b> 4MB (32Mb)<br />
|
||||
<b>Upload Speed:</b> 921600<br />
|
||||
<b>Arduino Runs On:</b> Core 1<br />
|
||||
<b>Events Run On:</b> Core 1<br />
|
||||
<b>Core Debug Level:</b> None<br />
|
||||
<b>Erase All Flash Before Sketch Upload:</b> Disabled<br />
|
||||
<br />
|
||||
<b>Used libraries:</b><br />
|
||||
<table>
|
||||
<tr>
|
||||
<td>Name</td>
|
||||
<td>Version</td>
|
||||
<td>Url</td>
|
||||
<td>Git</td>
|
||||
<td>Core library</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>ML SynthTools</td>
|
||||
<td>1.0.1</td>
|
||||
<td>https://github.com/marcel-licence/ML_SynthTools</td>
|
||||
<td>https://github.com/marcel-licence/ML_SynthTools.git</td>
|
||||
<td>False</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>WiFi</td>
|
||||
<td>2.0.0</td>
|
||||
<td></td>
|
||||
<td>https://github.com/espressif/arduino-esp32.git</td>
|
||||
<td>True</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Wire</td>
|
||||
<td>2.0.0</td>
|
||||
<td>http://arduino.cc/en/Reference/Wire</td>
|
||||
<td>https://github.com/espressif/arduino-esp32.git</td>
|
||||
<td>True</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Adafruit GFX Library</td>
|
||||
<td>1.10.10</td>
|
||||
<td>https://github.com/adafruit/Adafruit-GFX-Library</td>
|
||||
<td></td>
|
||||
<td>False</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Adafruit SSD1306</td>
|
||||
<td>2.4.5</td>
|
||||
<td>https://github.com/adafruit/Adafruit_SSD1306</td>
|
||||
<td></td>
|
||||
<td>False</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>SPI</td>
|
||||
<td>2.0.0</td>
|
||||
<td>http://arduino.cc/en/Reference/SPI</td>
|
||||
<td>https://github.com/espressif/arduino-esp32.git</td>
|
||||
<td>True</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Adafruit BusIO</td>
|
||||
<td>1.14.1</td>
|
||||
<td>https://github.com/adafruit/Adafruit_BusIO</td>
|
||||
<td>https://github.com/adafruit/Adafruit_BusIO</td>
|
||||
<td>False</td>
|
||||
</tr>
|
||||
</table><hr>
|
||||
<a name="esp32_esp32_esp32"></a><b>Core:</b> <a h_ref="N/A">ESP32 Arduino</a><br />
|
||||
<b>Version:</b> 1.0.6<br />
|
||||
<b>Board:</b> ESP32 Dev Module<br />
|
||||
<br />
|
||||
<b>Program storage space:</b> 769954 bytes<br />
|
||||
<b>Dynamic memory:</b> 49272 bytes<br />
|
||||
<br />
|
||||
<b>PSRAM:</b> Enabled<br />
|
||||
<b>Partition Scheme:</b> Default 4MB with spiffs (1.2MB APP/1.5MB SPIFFS)<br />
|
||||
<b>CPU Frequency:</b> 240MHz (WiFi/BT)<br />
|
||||
<b>Flash Mode:</b> QIO<br />
|
||||
<b>Flash Frequency:</b> 80MHz<br />
|
||||
<b>Flash Size:</b> 4MB (32Mb)<br />
|
||||
<b>Upload Speed:</b> 921600<br />
|
||||
<b>Core Debug Level:</b> None<br />
|
||||
<br />
|
||||
<b>Used libraries:</b><br />
|
||||
<table>
|
||||
<tr>
|
||||
<td>Name</td>
|
||||
<td>Version</td>
|
||||
<td>Url</td>
|
||||
<td>Git</td>
|
||||
<td>Core library</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>ML SynthTools</td>
|
||||
<td>1.0.1</td>
|
||||
<td>https://github.com/marcel-licence/ML_SynthTools</td>
|
||||
<td>https://github.com/marcel-licence/ML_SynthTools.git</td>
|
||||
<td>False</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>WiFi</td>
|
||||
<td>1.0</td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td>True</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Wire</td>
|
||||
<td>1.0.1</td>
|
||||
<td>http://arduino.cc/en/Reference/Wire</td>
|
||||
<td></td>
|
||||
<td>True</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Adafruit GFX Library</td>
|
||||
<td>1.10.10</td>
|
||||
<td>https://github.com/adafruit/Adafruit-GFX-Library</td>
|
||||
<td></td>
|
||||
<td>False</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Adafruit SSD1306</td>
|
||||
<td>2.4.5</td>
|
||||
<td>https://github.com/adafruit/Adafruit_SSD1306</td>
|
||||
<td></td>
|
||||
<td>False</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>SPI</td>
|
||||
<td>1.0</td>
|
||||
<td>http://arduino.cc/en/Reference/SPI</td>
|
||||
<td></td>
|
||||
<td>True</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Adafruit BusIO</td>
|
||||
<td>1.14.1</td>
|
||||
<td>https://github.com/adafruit/Adafruit_BusIO</td>
|
||||
<td>https://github.com/adafruit/Adafruit_BusIO</td>
|
||||
<td>False</td>
|
||||
</tr>
|
||||
</table>
|
||||
-531
@@ -1,531 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2021 Marcel Licence
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Dieses Programm ist Freie Software: Sie können es unter den Bedingungen
|
||||
* der GNU General Public License, wie von der Free Software Foundation,
|
||||
* Version 3 der Lizenz oder (nach Ihrer Wahl) jeder neueren
|
||||
* veröffentlichten Version, weiter verteilen und/oder modifizieren.
|
||||
*
|
||||
* Dieses Programm wird in der Hoffnung bereitgestellt, dass es nützlich sein wird, jedoch
|
||||
* OHNE JEDE GEWÄHR,; sogar ohne die implizite
|
||||
* Gewähr der MARKTFÄHIGKEIT oder EIGNUNG FÜR EINEN BESTIMMTEN ZWECK.
|
||||
* Siehe die GNU General Public License für weitere Einzelheiten.
|
||||
*
|
||||
* Sie sollten eine Kopie der GNU General Public License zusammen mit diesem
|
||||
* Programm erhalten haben. Wenn nicht, siehe <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file es8388.ino
|
||||
* @author Marcel Licence
|
||||
* @date 22.08.2021
|
||||
*
|
||||
* @brief This module is used to initialize the ES8388
|
||||
*
|
||||
* @see ESP32 Audio Kit AC101 codec failure - Get synthesizer projects working based on ES8388 - https://youtu.be/8UB3fYPjqSk
|
||||
* @see https://github.com/espressif/esp-adf/blob/master/components/audio_hal/driver/es8388/es8388.c
|
||||
*/
|
||||
|
||||
|
||||
#ifdef __CDT_PARSER__
|
||||
#include <cdt.h>
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef ES8388_ENABLED
|
||||
/*
|
||||
* http://www.everest-semi.com/pdf/ES8388%20DS.pdf
|
||||
*/
|
||||
|
||||
#include <Wire.h>
|
||||
|
||||
|
||||
/* ES8388 address */
|
||||
//#define ES8388_ADDR 0x20 /*!< 0x22:CE=1;0x20:CE=0*/
|
||||
#define ES8388_ADDR 0x10 /*!< 0x22:CE=1;0x20:CE=0*/
|
||||
|
||||
|
||||
/* ES8388 register */
|
||||
#define ES8388_CONTROL1 0x00
|
||||
#define ES8388_CONTROL2 0x01
|
||||
|
||||
#define ES8388_CHIPPOWER 0x02
|
||||
|
||||
#define ES8388_ADCPOWER 0x03
|
||||
#define ES8388_DACPOWER 0x04
|
||||
|
||||
#define ES8388_CHIPLOPOW1 0x05
|
||||
#define ES8388_CHIPLOPOW2 0x06
|
||||
|
||||
#define ES8388_ANAVOLMANAG 0x07
|
||||
|
||||
#define ES8388_MASTERMODE 0x08
|
||||
/* ADC */
|
||||
#define ES8388_ADCCONTROL1 0x09
|
||||
#define ES8388_ADCCONTROL2 0x0a
|
||||
#define ES8388_ADCCONTROL3 0x0b
|
||||
#define ES8388_ADCCONTROL4 0x0c
|
||||
#define ES8388_ADCCONTROL5 0x0d
|
||||
#define ES8388_ADCCONTROL6 0x0e
|
||||
#define ES8388_ADCCONTROL7 0x0f
|
||||
#define ES8388_ADCCONTROL8 0x10
|
||||
#define ES8388_ADCCONTROL9 0x11
|
||||
#define ES8388_ADCCONTROL10 0x12
|
||||
#define ES8388_ADCCONTROL11 0x13
|
||||
#define ES8388_ADCCONTROL12 0x14
|
||||
#define ES8388_ADCCONTROL13 0x15
|
||||
#define ES8388_ADCCONTROL14 0x16
|
||||
/* DAC */
|
||||
#define ES8388_DACCONTROL1 0x17
|
||||
#define ES8388_DACCONTROL2 0x18
|
||||
#define ES8388_DACCONTROL3 0x19
|
||||
#define ES8388_DACCONTROL4 0x1a
|
||||
#define ES8388_DACCONTROL5 0x1b
|
||||
#define ES8388_DACCONTROL6 0x1c
|
||||
#define ES8388_DACCONTROL7 0x1d
|
||||
#define ES8388_DACCONTROL8 0x1e
|
||||
#define ES8388_DACCONTROL9 0x1f
|
||||
#define ES8388_DACCONTROL10 0x20
|
||||
#define ES8388_DACCONTROL11 0x21
|
||||
#define ES8388_DACCONTROL12 0x22
|
||||
#define ES8388_DACCONTROL13 0x23
|
||||
#define ES8388_DACCONTROL14 0x24
|
||||
#define ES8388_DACCONTROL15 0x25
|
||||
#define ES8388_DACCONTROL16 0x26
|
||||
#define ES8388_DACCONTROL17 0x27
|
||||
#define ES8388_DACCONTROL18 0x28
|
||||
#define ES8388_DACCONTROL19 0x29
|
||||
#define ES8388_DACCONTROL20 0x2a
|
||||
#define ES8388_DACCONTROL21 0x2b
|
||||
#define ES8388_DACCONTROL22 0x2c
|
||||
#define ES8388_DACCONTROL23 0x2d
|
||||
#define ES8388_DACCONTROL24 0x2e
|
||||
#define ES8388_DACCONTROL25 0x2f
|
||||
#define ES8388_DACCONTROL26 0x30
|
||||
#define ES8388_DACCONTROL27 0x31
|
||||
#define ES8388_DACCONTROL28 0x32
|
||||
#define ES8388_DACCONTROL29 0x33
|
||||
#define ES8388_DACCONTROL30 0x34
|
||||
|
||||
|
||||
uint8_t ES8388_ReadReg(uint8_t reg)
|
||||
{
|
||||
Wire.beginTransmission(ES8388_ADDR);
|
||||
Wire.write(reg);
|
||||
Wire.endTransmission(false);
|
||||
|
||||
uint8_t val = 0u;
|
||||
if (1 == Wire.requestFrom(uint16_t(ES8388_ADDR), uint8_t(1), true))
|
||||
{
|
||||
val = Wire.read();
|
||||
}
|
||||
Wire.endTransmission(false);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
bool ES8388_WriteReg(uint8_t reg, uint8_t val)
|
||||
{
|
||||
Wire.beginTransmission(ES8388_ADDR);
|
||||
Wire.write(reg);
|
||||
Wire.write(val);
|
||||
return 0 == Wire.endTransmission(true);
|
||||
}
|
||||
|
||||
bool ES8388_begin(int sda, int scl, uint32_t frequency)
|
||||
{
|
||||
bool ok = Wire.begin(sda, scl, frequency);
|
||||
|
||||
// Reset all registers, readback default as sanity check
|
||||
//ok &= WriteReg(CHIP_AUDIO_RS, 0x123);
|
||||
delay(100);
|
||||
|
||||
Serial.printf("0x00: 0x%02x\n", ES8388_ReadReg(ES8388_CONTROL1));
|
||||
Serial.printf("0x01: 0x%02x\n", ES8388_ReadReg(ES8388_CONTROL2));
|
||||
|
||||
ES8388_WriteReg(ES8388_CONTROL1, 1 << 7); /* do reset! */
|
||||
ES8388_WriteReg(ES8388_CONTROL1, 0x06);
|
||||
ES8388_WriteReg(ES8388_CONTROL2, 0x50);
|
||||
|
||||
ok &= (0x06 == ES8388_ReadReg(ES8388_CONTROL1));
|
||||
ok &= (0x50 == ES8388_ReadReg(ES8388_CONTROL2));
|
||||
return ok;
|
||||
}
|
||||
|
||||
void es8388_read_all()
|
||||
{
|
||||
for (int i = 0; i < 53; i++)
|
||||
{
|
||||
uint8_t reg = 0;
|
||||
reg = ES8388_ReadReg(i);
|
||||
Serial.printf("Reg 0x%02x = 0x%02x\n", i, reg);
|
||||
}
|
||||
}
|
||||
|
||||
void ES8388_SetADCVOL(uint8_t unused, float vol)
|
||||
{
|
||||
#ifdef STATUS_ENABLED
|
||||
Status_ValueChangedInt("ADC Volume /db", (vol - 1) * 97 + 0.5);
|
||||
#endif
|
||||
|
||||
vol *= -192;
|
||||
vol += 192;
|
||||
|
||||
uint8_t volu8 = vol;
|
||||
|
||||
if (volu8 > 192)
|
||||
{
|
||||
volu8 = 192;
|
||||
}
|
||||
|
||||
ES8388_WriteReg(0x10, volu8); // LADCVOL
|
||||
ES8388_WriteReg(0x11, volu8); // RADCVOL
|
||||
}
|
||||
|
||||
void ES8388_SetDACVOL(uint8_t unused, float vol)
|
||||
{
|
||||
#ifdef STATUS_ENABLED
|
||||
Status_ValueChangedInt("DAC Volume /db", (vol - 1) * 97 + 0.5);
|
||||
#endif
|
||||
|
||||
vol *= -192;
|
||||
vol += 192;
|
||||
|
||||
uint8_t volu8 = vol;
|
||||
|
||||
if (volu8 > 192)
|
||||
{
|
||||
volu8 = 192;
|
||||
}
|
||||
|
||||
ES8388_WriteReg(0x1A, volu8); // LDACVOL
|
||||
ES8388_WriteReg(0x1B, volu8); // RDACVOL
|
||||
}
|
||||
|
||||
void ES8388_SetPGAGain(uint8_t unused, float vol)
|
||||
{
|
||||
#ifdef STATUS_ENABLED
|
||||
Status_ValueChangedInt("PGA Gain /db", vol * 24 + 0.25);
|
||||
#endif
|
||||
|
||||
vol *= 8;
|
||||
|
||||
uint8_t volu8 = vol;
|
||||
|
||||
if (volu8 > 8)
|
||||
{
|
||||
volu8 = 8;
|
||||
}
|
||||
// ES8388_ADCCONTROL1
|
||||
ES8388_WriteReg(0x09, volu8 + (volu8 << 4)); // MicAmpL, MicAmpR
|
||||
}
|
||||
|
||||
void ES8388_SetInputCh(uint8_t ch, float var)
|
||||
{
|
||||
if (var > 0)
|
||||
{
|
||||
uint8_t in;
|
||||
switch (ch)
|
||||
{
|
||||
case 0:
|
||||
in = 0;
|
||||
Serial.printf("AdcCh0!\n");
|
||||
break;
|
||||
|
||||
case 1:
|
||||
in = 1;
|
||||
Serial.printf("AdcCh1!\n");
|
||||
break;
|
||||
|
||||
default:
|
||||
Serial.printf("Illegal Input ch!\n");
|
||||
return;
|
||||
}
|
||||
// ES8388_ADCCONTROL2
|
||||
ES8388_WriteReg(0x0A, (in << 6) + (in << 4)); // LINSEL , RINSEL , DSSEL , DSR
|
||||
|
||||
#ifdef STATUS_ENABLED
|
||||
Status_ValueChangedInt("ADC Ch", in);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void ES8388_SetMixInCh(uint8_t ch, float var)
|
||||
{
|
||||
if (var > 0)
|
||||
{
|
||||
uint8_t in = 0;
|
||||
switch (ch)
|
||||
{
|
||||
case 0:
|
||||
in = 0;
|
||||
Serial.printf("MixCh0!\n");
|
||||
break;
|
||||
|
||||
case 1:
|
||||
in = 1;
|
||||
Serial.printf("MixCh1!\n");
|
||||
break;
|
||||
|
||||
case 2:
|
||||
in = 3;
|
||||
Serial.printf("MixChAMPL!\n");
|
||||
break;
|
||||
|
||||
default:
|
||||
Serial.printf("Illegal Mix Input ch!\n");
|
||||
return;
|
||||
}
|
||||
// ES8388_DACCONTROL16
|
||||
ES8388_WriteReg(0x26, in + (in << 3)); // LMIXSEL, RMIXSEL
|
||||
#ifdef STATUS_ENABLED
|
||||
Status_ValueChangedInt("Mix In Ch", in);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void ES8388_SetIn2OoutVOL(uint8_t unused, float vol)
|
||||
{
|
||||
#ifdef STATUS_ENABLED
|
||||
Status_ValueChangedInt("In to out volume /db", (vol - 1) * 16 + 0.5);
|
||||
#endif
|
||||
|
||||
vol *= -5;
|
||||
vol += 7;
|
||||
|
||||
uint8_t volu8 = vol;
|
||||
|
||||
if (volu8 > 7)
|
||||
{
|
||||
volu8 = 7;
|
||||
}
|
||||
|
||||
uint8_t var;
|
||||
|
||||
var = ES8388_ReadReg(0x27) & 0xC0;
|
||||
if (volu8 == 7)
|
||||
{
|
||||
var &= ~ 0x40;
|
||||
}
|
||||
else
|
||||
{
|
||||
var |= 0x40;
|
||||
}
|
||||
ES8388_WriteReg(0x27, (volu8 << 3) + var); // LD2LO, LI2LO, LI2LOVOL
|
||||
|
||||
var = ES8388_ReadReg(0x2A) & 0xC0;
|
||||
if (volu8 == 7)
|
||||
{
|
||||
var &= ~ 0x40;
|
||||
}
|
||||
else
|
||||
{
|
||||
var |= 0x40;
|
||||
}
|
||||
ES8388_WriteReg(0x2A, (volu8 << 3) + var); // RD2RO, RI2RO, RI2ROVOL
|
||||
}
|
||||
|
||||
void ES8388_SetOUT1VOL(uint8_t unused, float vol)
|
||||
{
|
||||
#ifdef STATUS_ENABLED
|
||||
Status_ValueChangedInt("OUT1VOL /db", (vol - 1) * 31 + 0.5);
|
||||
#endif
|
||||
|
||||
vol *= 0x1E;
|
||||
|
||||
uint8_t volu8 = vol;
|
||||
|
||||
if (volu8 > 129)
|
||||
{
|
||||
volu8 = 129;
|
||||
}
|
||||
|
||||
ES8388_WriteReg(0x2E, volu8); // LOUT1VOL
|
||||
ES8388_WriteReg(0x2F, volu8); // ROUT1VOL
|
||||
}
|
||||
|
||||
void ES8388_SetOUT2VOL(uint8_t unused, float vol)
|
||||
{
|
||||
#ifdef STATUS_ENABLED
|
||||
Status_ValueChangedInt("OUT2VOL /db", (vol - 1) * 31 + 0.5);
|
||||
#endif
|
||||
|
||||
vol *= 0x1E;
|
||||
|
||||
uint8_t volu8 = vol;
|
||||
|
||||
if (volu8 > 129)
|
||||
{
|
||||
volu8 = 129;
|
||||
}
|
||||
|
||||
ES8388_WriteReg(0x30, volu8); // LOUT2VOL
|
||||
ES8388_WriteReg(0x31, volu8); // ROUT2VOL
|
||||
}
|
||||
|
||||
void ES8388_Setup()
|
||||
{
|
||||
Serial.printf("Connect to ES8388 codec... ");
|
||||
|
||||
while (not ES8388_begin(ES8388_PIN_SDA, ES8388_PIN_SCL, 400000))
|
||||
{
|
||||
Serial.printf("Failed!\n");
|
||||
delay(1000);
|
||||
}
|
||||
|
||||
ES8388_WriteReg(ES8388_CHIPPOWER, 0xFF); //reset and stop es8388
|
||||
|
||||
|
||||
ES8388_WriteReg(0x00, 0x80); /* reset control port register to default */
|
||||
ES8388_WriteReg(0x00, 0x06); /* restore default value */
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* https://dl.radxa.com/rock2/docs/hw/ds/ES8388%20user%20Guide.pdf
|
||||
*/
|
||||
|
||||
/*
|
||||
* 10.5 Power Down Sequence (To Standby Mode)
|
||||
*/
|
||||
ES8388_WriteReg(0x0F, 0x34); /* ADC Mute */
|
||||
ES8388_WriteReg(0x19, 0x36); /* DAC Mute */
|
||||
|
||||
ES8388_WriteReg(0x02, 0xF3); /* Power down DEM and STM */
|
||||
|
||||
/*
|
||||
* 10.4 The sequence for Start up bypass mode
|
||||
*/
|
||||
/* Set Chip to Slave Mode */
|
||||
ES8388_WriteReg(0x08, 0x00);
|
||||
/* Power down DEM and STM */
|
||||
ES8388_WriteReg(0x02, 0x3F);
|
||||
/* Set same LRCK */
|
||||
ES8388_WriteReg(0x2B, 0x80);
|
||||
/* Set Chip to Play&Record Mode */
|
||||
ES8388_WriteReg(0x00, 0x05);
|
||||
/* Power Up Analog and Ibias */
|
||||
ES8388_WriteReg(0x01, 0x40);
|
||||
#if 0
|
||||
/*
|
||||
* Power down ADC, Power up
|
||||
* Analog Input for Bypass
|
||||
*/
|
||||
ES8388_WriteReg(0x03, 0x3F);
|
||||
#else
|
||||
ES8388_WriteReg(0x03, 0x3F); /* adc also on but no bias */
|
||||
|
||||
ES8388_WriteReg(0x03, 0x00); // PdnAINL, PdinAINR, PdnADCL, PdnADCR, PdnMICB, PdnADCBiasgen, flashLP, Int1LP
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
/*
|
||||
* Power Down DAC, Power up
|
||||
* Analog Output for Bypass
|
||||
*/
|
||||
ES8388_WriteReg(0x04, 0xFC);
|
||||
#else
|
||||
/*
|
||||
* Power up DAC / Analog Output
|
||||
* for Record
|
||||
*/
|
||||
ES8388_WriteReg(0x04, 0x3C);
|
||||
|
||||
|
||||
#if 1
|
||||
/*
|
||||
* Select Analog input channel for ADC
|
||||
*/
|
||||
ES8388_WriteReg(0x0A, 0x80); // LINSEL , RINSEL , DSSEL , DSR
|
||||
|
||||
/* Select PGA Gain for ADC analog input */
|
||||
ES8388_WriteReg(0x09, 0x00); // PGA gain?
|
||||
|
||||
//ES8388_WriteReg(0x0C, 0x18); // DATSEL, ADCLRP, ADCWL, ADCFORMAT
|
||||
//ES8388_WriteReg(0x0C, 0x40); // DATSEL, ADCLRP, ADCWL, ADCFORMAT
|
||||
ES8388_WriteReg(0x0C, 0x0C); // DATSEL, ADCLRP, ADCWL, ADCFORMAT
|
||||
ES8388_WriteReg(0x0D, 0x02); // ADCFsMode , ADCFsRatio
|
||||
//ES8388_WriteReg(0x0D, (1<<5) + 0x03); // ADCFsMode , ADCFsRatio Hasan
|
||||
//ES8388_WriteReg(0x0D, 0); // ADCFsMode , ADCFsRatio Hasan
|
||||
|
||||
/*
|
||||
* Set ADC Digital Volume
|
||||
*/
|
||||
#if 1
|
||||
ES8388_SetADCVOL(0, 1.0f);
|
||||
#else
|
||||
ES8388_WriteReg(0x10, 0x00); // LADCVOL
|
||||
ES8388_WriteReg(0x11, 0x00); // RADCVOL
|
||||
#endif
|
||||
|
||||
/* UnMute ADC */
|
||||
ES8388_WriteReg(0x0F, 0x30); //
|
||||
|
||||
ES8388_WriteReg(0x12, 0x16);
|
||||
|
||||
ES8388_WriteReg(0x17, 0x18); // DACLRSWAP, DACLRP, DACWL, DACFORMAT
|
||||
ES8388_WriteReg(0x18, 0x02); // DACFsMode , DACFsRatio
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Set ADC Digital Volume
|
||||
*/
|
||||
ES8388_WriteReg(0x1A, 0x00);
|
||||
ES8388_WriteReg(0x1B, 0x02);
|
||||
//ES8388_WriteReg(0x1B, (1<<5) + 0x03); // ADCFsMode , ADCFsRatio Hasan
|
||||
//ES8388_WriteReg(0x1B, 0); // ADCFsMode , ADCFsRatio Hasan
|
||||
/* UnMute DAC */
|
||||
ES8388_WriteReg(0x19, 0x32);
|
||||
#endif
|
||||
/*
|
||||
* Setup Mixer
|
||||
*/
|
||||
ES8388_WriteReg(0x26, 0x09);// ES8388_WriteReg(0x26, 0x00);
|
||||
ES8388_WriteReg(0x27, 0xD0); // ES8388_DACCONTROL17
|
||||
ES8388_WriteReg(0x28, 0x38);
|
||||
ES8388_WriteReg(0x29, 0x38);
|
||||
ES8388_WriteReg(0x2A, 0xD0);
|
||||
|
||||
/* Set Lout/Rout Volume */
|
||||
#if 1
|
||||
ES8388_SetOUT1VOL(0, 1);
|
||||
ES8388_SetOUT2VOL(0, 1);
|
||||
#else
|
||||
ES8388_WriteReg(0x2E, 0x1E);
|
||||
ES8388_WriteReg(0x2F, 0x1E);
|
||||
ES8388_WriteReg(0x30, 0x1E);
|
||||
ES8388_WriteReg(0x31, 0x1E);
|
||||
#endif
|
||||
|
||||
/* Power up DEM and STM */
|
||||
#if 0
|
||||
ES8388_WriteReg(0x02, 0xF0);
|
||||
#else
|
||||
ES8388_WriteReg(0x02, 0x00);
|
||||
#endif
|
||||
|
||||
ES8388_SetInputCh(1, 1);
|
||||
ES8388_SetMixInCh(2, 1);
|
||||
ES8388_SetPGAGain(0, 1);
|
||||
ES8388_SetIn2OoutVOL(0, 0);
|
||||
|
||||
Serial.printf("ES8388 setup finished!\n");
|
||||
es8388_read_all();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,327 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2021 Marcel Licence
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Dieses Programm ist Freie Software: Sie können es unter den Bedingungen
|
||||
* der GNU General Public License, wie von der Free Software Foundation,
|
||||
* Version 3 der Lizenz oder (nach Ihrer Wahl) jeder neueren
|
||||
* veröffentlichten Version, weiter verteilen und/oder modifizieren.
|
||||
*
|
||||
* Dieses Programm wird in der Hoffnung bereitgestellt, dass es nützlich sein wird, jedoch
|
||||
* OHNE JEDE GEWÄHR,; sogar ohne die implizite
|
||||
* Gewähr der MARKTFÄHIGKEIT oder EIGNUNG FÜR EINEN BESTIMMTEN ZWECK.
|
||||
* Siehe die GNU General Public License für weitere Einzelheiten.
|
||||
*
|
||||
* Sie sollten eine Kopie der GNU General Public License zusammen mit diesem
|
||||
* Programm erhalten haben. Wenn nicht, siehe <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file esp32_audio_kit_module.ino
|
||||
* @author Marcel Licence
|
||||
* @date 12.10.2021
|
||||
*
|
||||
* @brief This file contains basic stuff to work with the ESP32 Audio Kit V2.2 module
|
||||
*
|
||||
* @see ESP32 Audio Kit AC101 codec failure - Get synthesizer projects working based on ES8388 - https://youtu.be/8UB3fYPjqSk
|
||||
* @see Instructions: http://myosuploads3.banggood.com/products/20210306/20210306011116instruction.pdf
|
||||
* @see Schematic: https://docs.ai-thinker.com/_media/esp32-audio-kit_v2.2_sch.pdf
|
||||
*/
|
||||
|
||||
|
||||
#ifdef __CDT_PARSER__
|
||||
#include <cdt.h>
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef ESP32_AUDIO_KIT
|
||||
|
||||
#ifdef AC101_ENABLED
|
||||
#include "AC101.h" /* only compatible with forked repo: https://github.com/marcel-licence/AC101 */
|
||||
#endif
|
||||
|
||||
|
||||
//#define BUTTON_DEBUG_MSG
|
||||
|
||||
|
||||
|
||||
#define PIN_LED4 (22)
|
||||
#define PIN_LED5 (19)
|
||||
|
||||
|
||||
#ifdef AUDIO_KIT_BUTTON_DIGITAL
|
||||
/*
|
||||
* when not modified and R66-R70 are placed on the board
|
||||
*/
|
||||
#define PIN_KEY_1 (36)
|
||||
#define PIN_KEY_2 (13)
|
||||
#define PIN_KEY_3 (19)
|
||||
#define PIN_KEY_4 (23)
|
||||
#define PIN_KEY_5 (18)
|
||||
#define PIN_KEY_6 (5)
|
||||
|
||||
#define PIN_PLAY PIN_KEY_4
|
||||
#define PIN_VOL_UP PIN_KEY_5
|
||||
#define PIN_VOL_DOWN PIN_KEY_6
|
||||
#endif
|
||||
|
||||
#ifdef AUDIO_KIT_BUTTON_ANALOG
|
||||
/*
|
||||
* modification required:
|
||||
* - remove R66-R70
|
||||
* - insert R60-R64 (0 Ohm or solder bridge)
|
||||
* - insert R55-R59 using 1.8kOhm (recommended but other values might be possible with tweaking the code)
|
||||
*/
|
||||
#ifndef PIN_KEY_ANALOG
|
||||
#define PIN_KEY_ANALOG (36)
|
||||
#endif
|
||||
|
||||
#define KEY_SETTLE_VAL 9 /* use higher value if anaog buton detection is unstable */
|
||||
|
||||
uint32_t keyMin[7] = {4095 - 32, 0, 462 - 32, 925 - 32, 1283 - 32, 1570 - 32, 1800 - 32};
|
||||
uint32_t keyMax[7] = {4095 + 32, 0 + 32, 525 + 32, 1006 + 32, 1374 + 32, 1570 + 32, 1800 + 32 };
|
||||
#endif
|
||||
|
||||
#define OUTPUT_PIN 0
|
||||
#define MCLK_CH 0
|
||||
#define PWM_BIT 1
|
||||
|
||||
#ifdef AC101_ENABLED
|
||||
static AC101 ac;
|
||||
#endif
|
||||
|
||||
/* actually only supporting 16 bit */
|
||||
#define SAMPLE_SIZE_16BIT
|
||||
//#define SAMPLE_SIZE_24BIT
|
||||
//#define SAMPLE_SIZE_32BIT
|
||||
|
||||
#ifndef SAMPLE_RATE
|
||||
#define SAMPLE_RATE 44100
|
||||
#endif
|
||||
#define CHANNEL_COUNT 2
|
||||
#define WORD_SIZE 16
|
||||
#define I2S1CLK (512*SAMPLE_RATE)
|
||||
#define BCLK (SAMPLE_RATE*CHANNEL_COUNT*WORD_SIZE)
|
||||
#define LRCK (SAMPLE_RATE*CHANNEL_COUNT)
|
||||
|
||||
|
||||
typedef void(*audioKitButtonCb)(uint8_t, uint8_t);
|
||||
extern audioKitButtonCb audioKitButtonCallback;
|
||||
|
||||
#ifdef AC101_ENABLED
|
||||
/*
|
||||
* this function could be used to set up the masterclock
|
||||
* it is not necessary to use the ac101
|
||||
*/
|
||||
void ac101_mclk_setup()
|
||||
{
|
||||
// Put a signal out on pin
|
||||
uint32_t freq = SAMPLE_RATE * 512; /* The maximal frequency is 80000000 / 2^bit_num */
|
||||
Serial.printf("Output frequency: %d\n", freq);
|
||||
ledcSetup(MCLK_CH, freq, PWM_BIT);
|
||||
ledcAttachPin(OUTPUT_PIN, MCLK_CH);
|
||||
ledcWrite(MCLK_CH, 1 << (PWM_BIT - 1)); /* 50% duty -> The available duty levels are (2^bit_num)-1, where bit_num can be 1-15. */
|
||||
}
|
||||
|
||||
/*
|
||||
* complete setup of the ac101 to enable in/output
|
||||
*/
|
||||
void ac101_setup()
|
||||
{
|
||||
Serial.printf("Connect to AC101 codec... ");
|
||||
while (not ac.begin(AC101_PIN_SDA, AC101_PIN_SCL))
|
||||
{
|
||||
Serial.printf("Failed!\n");
|
||||
delay(1000);
|
||||
}
|
||||
Serial.printf("OK\n");
|
||||
#ifdef SAMPLE_SIZE_24BIT
|
||||
ac.SetI2sWordSize(AC101::WORD_SIZE_24_BITS);
|
||||
#endif
|
||||
#ifdef SAMPLE_SIZE_16BIT
|
||||
ac.SetI2sWordSize(AC101::WORD_SIZE_16_BITS);
|
||||
#endif
|
||||
|
||||
#if (SAMPLE_RATE==44100)&&(defined(SAMPLE_SIZE_16BIT))
|
||||
ac.SetI2sSampleRate(AC101::SAMPLE_RATE_44100);
|
||||
/*
|
||||
* BCLK: 44100 * 2 * 16 = 1411200 Hz
|
||||
* SYSCLK: 512 * fs = 512* 44100 = 22579200 Hz
|
||||
*
|
||||
* I2S1CLK/BCLK1 -> 512 * 44100 / 44100*2*16
|
||||
* BCLK1/LRCK -> 44100*2*16 / 44100 Obacht ... ein clock cycle goes high and low
|
||||
* means 32 when 32 bits are in a LR word channel * word_size
|
||||
*/
|
||||
ac.SetI2sClock(AC101::BCLK_DIV_16, false, AC101::LRCK_DIV_32, false);
|
||||
ac.SetI2sMode(AC101::MODE_SLAVE);
|
||||
ac.SetI2sWordSize(AC101::WORD_SIZE_16_BITS);
|
||||
ac.SetI2sFormat(AC101::DATA_FORMAT_I2S);
|
||||
#endif
|
||||
|
||||
ac.SetVolumeSpeaker(3);
|
||||
ac.SetVolumeHeadphone(99);
|
||||
|
||||
#if 1
|
||||
ac.SetLineSource();
|
||||
#else
|
||||
ac.SetMicSource(); /* handle with care: mic is very sensitive and might cause feedback using amp!!! */
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
ac.DumpRegisters();
|
||||
#endif
|
||||
|
||||
// Enable amplifier
|
||||
#if 0 /* amplifier only required when speakers attached? */
|
||||
pinMode(GPIO_PA_EN, OUTPUT);
|
||||
digitalWrite(GPIO_PA_EN, HIGH);
|
||||
#endif
|
||||
}
|
||||
#endif /* #ifdef AC101_ENABLED */
|
||||
|
||||
/*
|
||||
* pullup required to enable reading the buttons (buttons will connect them to ground if pressed)
|
||||
*/
|
||||
void button_setup()
|
||||
{
|
||||
#ifdef AUDIO_KIT_BUTTON_DIGITAL
|
||||
// Configure keys on ESP32 Audio Kit board
|
||||
pinMode(PIN_PLAY, INPUT_PULLUP);
|
||||
pinMode(PIN_VOL_UP, INPUT_PULLUP);
|
||||
pinMode(PIN_VOL_DOWN, INPUT_PULLUP);
|
||||
#endif
|
||||
#ifdef AUDIO_KIT_BUTTON_ANALOG_OLD
|
||||
adcAttachPin(PIN_KEY_ANALOG);
|
||||
analogReadResolution(10);
|
||||
analogSetAttenuation(ADC_11db);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef AC101_ENABLED
|
||||
/*
|
||||
* selects the microphone as audio source
|
||||
* handle with care: mic is very sensitive and might cause feedback using amp!!!
|
||||
*/
|
||||
void ac101_setSourceMic(void)
|
||||
{
|
||||
ac.SetMicSource();
|
||||
}
|
||||
|
||||
/*
|
||||
* selects the line in as input
|
||||
*/
|
||||
void ac101_setSourceLine(void)
|
||||
{
|
||||
ac.SetLineSource();
|
||||
}
|
||||
#endif /* #ifdef AC101_ENABLED */
|
||||
|
||||
/*
|
||||
* very bad implementation checking the button state
|
||||
* there is some work required for a better functionality
|
||||
*/
|
||||
void button_loop()
|
||||
{
|
||||
#ifdef AUDIO_KIT_BUTTON_DIGITAL
|
||||
if (digitalRead(PIN_PLAY) == LOW)
|
||||
{
|
||||
Serial.println("PIN_PLAY pressed");
|
||||
if (buttonMapping.key4_pressed != NULL)
|
||||
{
|
||||
buttonMapping.key4_pressed();
|
||||
}
|
||||
}
|
||||
if (digitalRead(PIN_VOL_UP) == LOW)
|
||||
{
|
||||
Serial.println("PIN_VOL_UP pressed");
|
||||
if (buttonMapping.key5_pressed != NULL)
|
||||
{
|
||||
buttonMapping.key5_pressed();
|
||||
}
|
||||
}
|
||||
if (digitalRead(PIN_VOL_DOWN) == LOW)
|
||||
{
|
||||
Serial.println("PIN_VOL_DOWN pressed");
|
||||
if (buttonMapping.key6_pressed != NULL)
|
||||
{
|
||||
buttonMapping.key6_pressed();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifdef AUDIO_KIT_BUTTON_ANALOG
|
||||
static uint32_t lastKeyAD = 0xFFFF;
|
||||
static uint32_t keyAD = 0;
|
||||
static uint8_t pressedKey = 0;
|
||||
static uint8_t newPressedKey = 0;
|
||||
static uint8_t pressedKeyLast = 0;
|
||||
static uint8_t keySettle = 0;
|
||||
|
||||
keyAD = analogRead(PIN_KEY_ANALOG);
|
||||
if (keyAD != lastKeyAD)
|
||||
{
|
||||
//Serial.printf("keyAd: %d\n", keyAD);
|
||||
lastKeyAD = keyAD;
|
||||
|
||||
//pressedKey = 0;
|
||||
for (int i = 0; i < 7; i ++)
|
||||
{
|
||||
if ((keyAD >= keyMin[i]) && (keyAD < keyMax[i]))
|
||||
{
|
||||
newPressedKey = i;
|
||||
}
|
||||
}
|
||||
if (newPressedKey != pressedKey)
|
||||
{
|
||||
keySettle = KEY_SETTLE_VAL;
|
||||
pressedKey = newPressedKey;
|
||||
}
|
||||
}
|
||||
|
||||
if (keySettle > 0)
|
||||
{
|
||||
keySettle--;
|
||||
if (keySettle == 0)
|
||||
{
|
||||
if (pressedKey != pressedKeyLast)
|
||||
{
|
||||
if (pressedKeyLast > 0)
|
||||
{
|
||||
#ifdef BUTTON_DEBUG_MSG
|
||||
Serial.printf("Key %d up\n", pressedKeyLast);
|
||||
#endif
|
||||
if (audioKitButtonCallback != NULL)
|
||||
{
|
||||
audioKitButtonCallback(pressedKeyLast - 1, 0);
|
||||
}
|
||||
}
|
||||
if (pressedKey > 0)
|
||||
{
|
||||
#ifdef BUTTON_DEBUG_MSG
|
||||
Serial.printf("Key %d down\n", pressedKey);
|
||||
#endif
|
||||
if (audioKitButtonCallback != NULL)
|
||||
{
|
||||
audioKitButtonCallback(pressedKey - 1, 1);
|
||||
}
|
||||
}
|
||||
pressedKeyLast = pressedKey;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -83,6 +83,11 @@
|
||||
#endif
|
||||
|
||||
|
||||
#define ML_SYNTH_INLINE_DECLARATION
|
||||
#include <ml_inline.h>
|
||||
#undef ML_SYNTH_INLINE_DECLARATION
|
||||
|
||||
|
||||
/* to avoid the high click when turning on the microphone */
|
||||
static float click_supp_gain = 0.0f;
|
||||
|
||||
|
||||
@@ -1,371 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2022 Marcel Licence
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Dieses Programm ist Freie Software: Sie können es unter den Bedingungen
|
||||
* der GNU General Public License, wie von der Free Software Foundation,
|
||||
* Version 3 der Lizenz oder (nach Ihrer Wahl) jeder neueren
|
||||
* veröffentlichten Version, weiter verteilen und/oder modifizieren.
|
||||
*
|
||||
* Dieses Programm wird in der Hoffnung bereitgestellt, dass es nützlich sein wird, jedoch
|
||||
* OHNE JEDE GEWÄHR,; sogar ohne die implizite
|
||||
* Gewähr der MARKTFÄHIGKEIT oder EIGNUNG FÜR EINEN BESTIMMTEN ZWECK.
|
||||
* Siehe die GNU General Public License für weitere Einzelheiten.
|
||||
*
|
||||
* Sie sollten eine Kopie der GNU General Public License zusammen mit diesem
|
||||
* Programm erhalten haben. Wenn nicht, siehe <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file i2s_interface.ino
|
||||
* @author Marcel Licence
|
||||
* @date 13.10.2021
|
||||
*
|
||||
* @brief this file includes all required function to setup and drive the i2s interface
|
||||
*/
|
||||
|
||||
|
||||
#ifdef __CDT_PARSER__
|
||||
#include <cdt.h>
|
||||
#endif
|
||||
|
||||
|
||||
#include <driver/i2s.h>
|
||||
|
||||
|
||||
/*
|
||||
* no dac not tested within this code
|
||||
* - it has the purpose to generate a quasy analog signal without a DAC
|
||||
*/
|
||||
//#define I2S_NODAC
|
||||
|
||||
|
||||
const i2s_port_t i2s_port_number = I2S_NUM_0;
|
||||
|
||||
/*
|
||||
* please refer to https://www.hackster.io/janost/audio-hacking-on-the-esp8266-fa9464#toc-a-simple-909-drum-synth-0
|
||||
* for the following implementation
|
||||
*/
|
||||
#ifdef I2S_NODAC
|
||||
/* todo integrate code, or external module from hack a day using i2s signal wire as DAC */
|
||||
#else
|
||||
|
||||
bool i2s_write_sample_32ch2(uint8_t *sample);
|
||||
|
||||
bool i2s_write_sample_32ch2(uint8_t *sample)
|
||||
{
|
||||
static size_t bytes_written = 0;
|
||||
static size_t bytes_read = 0;
|
||||
i2s_read(i2s_port_number, (char *)sample, 8, &bytes_read, portMAX_DELAY);
|
||||
|
||||
i2s_write(i2s_port_number, (const char *)sample, 8, &bytes_written, portMAX_DELAY);
|
||||
|
||||
if (bytes_written > 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef SAMPLE_SIZE_24BIT
|
||||
|
||||
bool i2s_write_sample_24ch2(uint8_t *sample);
|
||||
|
||||
bool i2s_write_sample_24ch2(uint8_t *sample)
|
||||
{
|
||||
static size_t bytes_written1 = 0;
|
||||
static size_t bytes_written2 = 0;
|
||||
i2s_write(i2s_port_number, (const char *)&sample[1], 3, &bytes_written1, portMAX_DELAY);
|
||||
i2s_write(i2s_port_number, (const char *)&sample[5], 3, &bytes_written2, portMAX_DELAY);
|
||||
|
||||
if ((bytes_written1 + bytes_written2) > 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
bool i2s_write_stereo_samples(float *fl_sample, float *fr_sample)
|
||||
{
|
||||
#ifdef SAMPLE_SIZE_32BIT
|
||||
static union sampleTUNT
|
||||
{
|
||||
uint64_t sample;
|
||||
int32_t ch[2];
|
||||
} sampleDataU;
|
||||
#endif
|
||||
#ifdef SAMPLE_SIZE_24BIT
|
||||
#if 0
|
||||
static union sampleTUNT
|
||||
{
|
||||
uint8_t sample[8];
|
||||
int32_t ch[2];
|
||||
} sampleDataU;
|
||||
#else
|
||||
static union sampleTUNT
|
||||
{
|
||||
int32_t ch[2];
|
||||
uint8_t bytes[8];
|
||||
} sampleDataU;
|
||||
#endif
|
||||
#endif
|
||||
#ifdef SAMPLE_SIZE_16BIT
|
||||
static union sampleTUNT
|
||||
{
|
||||
uint32_t sample;
|
||||
int16_t ch[2];
|
||||
} sampleDataU;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* using RIGHT_LEFT format
|
||||
*/
|
||||
#ifdef SAMPLE_SIZE_16BIT
|
||||
sampleDataU.ch[0] = int16_t(*fr_sample * 16383.0f); /* some bits missing here */
|
||||
sampleDataU.ch[1] = int16_t(*fl_sample * 16383.0f);
|
||||
#endif
|
||||
#ifdef SAMPLE_SIZE_32BIT
|
||||
sampleDataU.ch[0] = int32_t(*fr_sample * 1073741823.0f); /* some bits missing here */
|
||||
sampleDataU.ch[1] = int32_t(*fl_sample * 1073741823.0f);
|
||||
#endif
|
||||
|
||||
size_t bytes_written = 0;
|
||||
|
||||
#ifdef SAMPLE_SIZE_16BIT
|
||||
i2s_write(i2s_port_number, (const char *)&sampleDataU.sample, 4, &bytes_written, portMAX_DELAY);
|
||||
#endif
|
||||
#ifdef SAMPLE_SIZE_32BIT
|
||||
i2s_write(i2s_port_number, (const char *)&sampleDataU.sample, 8, &bytes_written, portMAX_DELAY);
|
||||
#endif
|
||||
|
||||
if (bytes_written > 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef SAMPLE_BUFFER_SIZE
|
||||
bool i2s_write_stereo_samples_buff(float *fl_sample, float *fr_sample, const int buffLen)
|
||||
{
|
||||
#ifdef SAMPLE_SIZE_32BIT
|
||||
static union sampleTUNT
|
||||
{
|
||||
uint64_t sample;
|
||||
int32_t ch[2];
|
||||
} sampleDataU[SAMPLE_BUFFER_SIZE];
|
||||
#endif
|
||||
#ifdef SAMPLE_SIZE_24BIT
|
||||
#if 0
|
||||
static union sampleTUNT
|
||||
{
|
||||
uint8_t sample[8];
|
||||
int32_t ch[2];
|
||||
} sampleDataU[SAMPLE_BUFFER_SIZE];
|
||||
#else
|
||||
static union sampleTUNT
|
||||
{
|
||||
int32_t ch[2];
|
||||
uint8_t bytes[8];
|
||||
} sampleDataU[SAMPLE_BUFFER_SIZE];
|
||||
#endif
|
||||
#endif
|
||||
#ifdef SAMPLE_SIZE_16BIT
|
||||
static union sampleTUNT
|
||||
{
|
||||
uint32_t sample;
|
||||
int16_t ch[2];
|
||||
} sampleDataU[SAMPLE_BUFFER_SIZE];
|
||||
#endif
|
||||
|
||||
for (int n = 0; n < buffLen; n++)
|
||||
{
|
||||
/*
|
||||
* using RIGHT_LEFT format
|
||||
*/
|
||||
#ifdef SAMPLE_SIZE_16BIT
|
||||
sampleDataU[n].ch[0] = int16_t(fr_sample[n] * 16383.0f); /* some bits missing here */
|
||||
sampleDataU[n].ch[1] = int16_t(fl_sample[n] * 16383.0f);
|
||||
#endif
|
||||
#ifdef SAMPLE_SIZE_32BIT
|
||||
sampleDataU[n].ch[0] = int32_t(fr_sample[n] * 1073741823.0f); /* some bits missing here */
|
||||
sampleDataU[n].ch[1] = int32_t(fl_sample[n] * 1073741823.0f);
|
||||
#endif
|
||||
}
|
||||
|
||||
static size_t bytes_written = 0;
|
||||
|
||||
i2s_write(i2s_port_number, (const char *)&sampleDataU[0].sample, 4 * buffLen, &bytes_written, portMAX_DELAY);
|
||||
|
||||
if (bytes_written > 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
#endif /* #ifdef SAMPLE_BUFFER_SIZE */
|
||||
|
||||
void i2s_read_stereo_samples(float *fl_sample, float *fr_sample)
|
||||
{
|
||||
static size_t bytes_read = 0;
|
||||
|
||||
static union
|
||||
{
|
||||
uint32_t sample;
|
||||
int16_t ch[2];
|
||||
} sampleData;
|
||||
|
||||
|
||||
i2s_read(i2s_port_number, (char *)&sampleData.sample, 4, &bytes_read, portMAX_DELAY);
|
||||
|
||||
//sampleData.ch[0] &= 0xFFFE;
|
||||
//sampleData.ch[1] &= 0;
|
||||
|
||||
/*
|
||||
* using RIGHT_LEFT format
|
||||
*/
|
||||
*fr_sample = ((float)sampleData.ch[0] * (5.5f / 65535.0f));
|
||||
*fl_sample = ((float)sampleData.ch[1] * (5.5f / 65535.0f));
|
||||
}
|
||||
|
||||
#ifdef SAMPLE_BUFFER_SIZE
|
||||
void i2s_read_stereo_samples_buff(float *fl_sample, float *fr_sample, const int buffLen)
|
||||
{
|
||||
#ifdef I2S_DIN_PIN
|
||||
static size_t bytes_read = 0;
|
||||
|
||||
#ifdef SAMPLE_SIZE_16BIT
|
||||
static union
|
||||
{
|
||||
uint32_t sample;
|
||||
int16_t ch[2];
|
||||
} sampleData[SAMPLE_BUFFER_SIZE];
|
||||
#endif
|
||||
|
||||
i2s_read(i2s_port_number, (char *)&sampleData[0].sample, 4 * buffLen, &bytes_read, portMAX_DELAY);
|
||||
|
||||
//sampleData.ch[0] &= 0xFFFE;
|
||||
//sampleData.ch[1] &= 0;
|
||||
|
||||
for (int n = 0; n < buffLen; n++)
|
||||
{
|
||||
/*
|
||||
* using RIGHT_LEFT format
|
||||
*/
|
||||
//fr_sample[n] = ((float)sampleData[n].ch[0] * (5.5f / 65535.0f));
|
||||
//fl_sample[n] = ((float)sampleData[n].ch[1] * (5.5f / 65535.0f));
|
||||
fr_sample[n] = ((float)sampleData[n].ch[0] / (16383.0f));
|
||||
fl_sample[n] = ((float)sampleData[n].ch[1] / (16383.0f));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif /* #ifdef SAMPLE_BUFFER_SIZE */
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* i2s configuration
|
||||
*/
|
||||
i2s_config_t i2s_configuration =
|
||||
{
|
||||
#ifdef I2S_DIN_PIN
|
||||
.mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_RX), // | I2S_MODE_DAC_BUILT_IN
|
||||
#else
|
||||
.mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX),
|
||||
#endif
|
||||
.sample_rate = SAMPLE_RATE,
|
||||
#ifdef I2S_NODAC
|
||||
.bits_per_sample = I2S_BITS_PER_SAMPLE_32BIT,
|
||||
.channel_format = I2S_CHANNEL_FMT_ONLY_LEFT,
|
||||
#ifdef ARDUINO_RUNNING_CORE /* tested with arduino esp32 core version 2.0.2 */
|
||||
.communication_format = I2S_COMM_FORMAT_STAND_I2S,
|
||||
#else
|
||||
.communication_format = (i2s_comm_format_t)I2S_COMM_FORMAT_I2S_MSB,
|
||||
#endif
|
||||
#else
|
||||
#ifdef SAMPLE_SIZE_32BIT
|
||||
.bits_per_sample = I2S_BITS_PER_SAMPLE_32BIT, /* the DAC module will only take the 8bits from MSB */
|
||||
#endif
|
||||
#ifdef SAMPLE_SIZE_24BIT
|
||||
.bits_per_sample = I2S_BITS_PER_SAMPLE_24BIT, /* the DAC module will only take the 8bits from MSB */
|
||||
#endif
|
||||
#ifdef SAMPLE_SIZE_16BIT
|
||||
.bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT, /* the DAC module will only take the 8bits from MSB */
|
||||
#endif
|
||||
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
|
||||
#ifdef ARDUINO_RUNNING_CORE /* tested with arduino esp32 core version 2.0.2 */
|
||||
.communication_format = I2S_COMM_FORMAT_STAND_I2S,
|
||||
#else
|
||||
.communication_format = (i2s_comm_format_t)(I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB),
|
||||
#endif
|
||||
#endif
|
||||
.intr_alloc_flags = 0, // default interrupt priority
|
||||
.dma_buf_count = 8,
|
||||
.dma_buf_len = 64,
|
||||
#ifdef I2S_USE_APLL
|
||||
.use_apll = true,
|
||||
#else
|
||||
.use_apll = false,
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
#ifdef I2S_NODAC
|
||||
i2s_pin_config_t pins =
|
||||
{
|
||||
.bck_io_num = I2S_PIN_NO_CHANGE,
|
||||
.ws_io_num = I2S_PIN_NO_CHANGE,
|
||||
.data_out_num = I2S_NODAC_OUT_PIN,
|
||||
.data_in_num = I2S_PIN_NO_CHANGE
|
||||
};
|
||||
#else
|
||||
i2s_pin_config_t pins =
|
||||
{
|
||||
.bck_io_num = I2S_BCLK_PIN,
|
||||
.ws_io_num = I2S_WCLK_PIN,
|
||||
.data_out_num = I2S_DOUT_PIN,
|
||||
#ifdef I2S_DIN_PIN
|
||||
.data_in_num = I2S_DIN_PIN
|
||||
#else
|
||||
.data_in_num = I2S_PIN_NO_CHANGE
|
||||
#endif
|
||||
};
|
||||
#endif
|
||||
|
||||
void setup_i2s()
|
||||
{
|
||||
i2s_driver_install(i2s_port_number, &i2s_configuration, 0, NULL);
|
||||
i2s_set_pin(I2S_NUM_0, &pins);
|
||||
i2s_set_sample_rates(i2s_port_number, SAMPLE_RATE);
|
||||
i2s_start(i2s_port_number);
|
||||
#ifdef ES8388_ENABLED
|
||||
REG_WRITE(PIN_CTRL, 0xFFFFFFF0);
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO0_U, FUNC_GPIO0_CLK_OUT1);
|
||||
#endif
|
||||
}
|
||||
@@ -1,468 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2021 Marcel Licence
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Dieses Programm ist Freie Software: Sie können es unter den Bedingungen
|
||||
* der GNU General Public License, wie von der Free Software Foundation,
|
||||
* Version 3 der Lizenz oder (nach Ihrer Wahl) jeder neueren
|
||||
* veröffentlichten Version, weiter verteilen und/oder modifizieren.
|
||||
*
|
||||
* Dieses Programm wird in der Hoffnung bereitgestellt, dass es nützlich sein wird, jedoch
|
||||
* OHNE JEDE GEWÄHR,; sogar ohne die implizite
|
||||
* Gewähr der MARKTFÄHIGKEIT oder EIGNUNG FÜR EINEN BESTIMMTEN ZWECK.
|
||||
* Siehe die GNU General Public License für weitere Einzelheiten.
|
||||
*
|
||||
* Sie sollten eine Kopie der GNU General Public License zusammen mit diesem
|
||||
* Programm erhalten haben. Wenn nicht, siehe <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file midi_interface.ino
|
||||
* @author Marcel Licence
|
||||
* @date 04.10.2021
|
||||
*
|
||||
* @brief This file contains an implementation of a simple MIDI interpreter to parse incoming messages
|
||||
*
|
||||
* MIDI_DUMP_Serial1_TO_SERIAL <- when active received data will be output as hex on serial(1)
|
||||
* MIDI_SERIAL1_BAUDRATE <- use define to override baud-rate for MIDI, otherwise default of 31250 will be used
|
||||
*
|
||||
* @see https://www.midi.org/specifications-old/item/table-1-summary-of-midi-message
|
||||
*/
|
||||
|
||||
|
||||
#ifdef __CDT_PARSER__
|
||||
#include <cdt.h>
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* look for midi interface using 1N136
|
||||
* to convert the MIDI din signal to
|
||||
* a uart compatible signal
|
||||
*/
|
||||
|
||||
#ifndef MIDI_SERIAL1_BAUDRATE
|
||||
#define MIDI_SERIAL1_BAUDRATE 31250
|
||||
#endif
|
||||
|
||||
#ifndef MIDI_SERIAL2_BAUDRATE
|
||||
#define MIDI_SERIAL2_BAUDRATE 31250
|
||||
#endif
|
||||
|
||||
/* use define to dump midi data */
|
||||
//#define MIDI_DUMP_SERIAL2_TO_SERIAL
|
||||
|
||||
|
||||
#if (defined MIDI_RX_PIN) || (defined MIDI_RECV_FROM_SERIAL)
|
||||
#define MIDI_PORT_ACTIVE
|
||||
#endif
|
||||
|
||||
#ifdef MIDI_RX1_PIN
|
||||
#define MIDI_PORT1_ACTIVE
|
||||
#endif
|
||||
|
||||
#ifdef MIDI_RX2_PIN
|
||||
#define MIDI_PORT2_ACTIVE
|
||||
#endif
|
||||
|
||||
struct midi_port_s
|
||||
{
|
||||
Stream *serial; /* this can be software or hardware serial */
|
||||
uint32_t inMsgWd ;
|
||||
uint8_t inMsg[3];
|
||||
uint8_t inMsgIndex ;
|
||||
};
|
||||
|
||||
#ifdef ARDUINO_DAISY_SEED
|
||||
HardwareSerial Serial2(USART1);
|
||||
#endif
|
||||
|
||||
#ifdef ARDUINO_GENERIC_F407VGTX
|
||||
HardwareSerial Serial2(USART3); /* PB11 */
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef MIDI_PORT_ACTIVE
|
||||
struct midi_port_s MidiPort;
|
||||
#endif
|
||||
|
||||
#ifdef MIDI_PORT1_ACTIVE
|
||||
struct midi_port_s MidiPort1;
|
||||
#endif
|
||||
|
||||
#ifdef MIDI_PORT2_ACTIVE
|
||||
struct midi_port_s MidiPort2;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* structure is used to build the mapping table
|
||||
*/
|
||||
struct midiControllerMapping
|
||||
{
|
||||
uint8_t channel;
|
||||
uint8_t data1;
|
||||
const char *desc;
|
||||
void(*callback_mid)(uint8_t ch, uint8_t data1, uint8_t data2);
|
||||
#ifdef MIDI_FMT_INT
|
||||
void(*callback_val)(uint8_t userdata, uint8_t value);
|
||||
#else
|
||||
void(*callback_val)(uint8_t userdata, float value);
|
||||
#endif
|
||||
uint8_t user_data;
|
||||
};
|
||||
|
||||
struct midiMapping_s
|
||||
{
|
||||
void (*rawMsg)(uint8_t *msg);
|
||||
#ifdef MIDI_FMT_INT
|
||||
void (*noteOn)(uint8_t ch, uint8_t note, uint8_t vel);
|
||||
void (*noteOff)(uint8_t ch, uint8_t note);
|
||||
void (*pitchBend)(uint8_t ch, uint8_t bend);
|
||||
void (*modWheel)(uint8_t ch, uint8_t value);
|
||||
#else
|
||||
void (*noteOn)(uint8_t ch, uint8_t note, float vel);
|
||||
void (*noteOff)(uint8_t ch, uint8_t note);
|
||||
void (*pitchBend)(uint8_t ch, float bend);
|
||||
void (*modWheel)(uint8_t ch, float value);
|
||||
#endif
|
||||
void (*rttMsg)(uint8_t msg);
|
||||
void (*songPos)(uint16_t pos);
|
||||
|
||||
struct midiControllerMapping *controlMapping;
|
||||
int mapSize;
|
||||
};
|
||||
|
||||
extern struct midiMapping_s midiMapping; /* definition in z_config.ino */
|
||||
|
||||
/* constant to normalize midi value to 0.0 - 1.0f */
|
||||
#define NORM127MUL 0.007874f
|
||||
|
||||
inline void Midi_NoteOn(uint8_t ch, uint8_t note, uint8_t vel)
|
||||
{
|
||||
if (vel > 127)
|
||||
{
|
||||
/* we will end up here in case of problems with the MIDI connection */
|
||||
vel = 127;
|
||||
Serial.printf("to loud note detected!!!!!!!!!!!!!!!!!!!!!!!\n");
|
||||
}
|
||||
|
||||
if (midiMapping.noteOn != NULL)
|
||||
{
|
||||
#ifdef MIDI_FMT_INT
|
||||
midiMapping.noteOn(ch, note, vel);
|
||||
#else
|
||||
midiMapping.noteOn(ch, note, pow(2, ((vel * NORM127MUL) - 1.0f) * 6));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
inline void Midi_NoteOff(uint8_t ch, uint8_t note)
|
||||
{
|
||||
if (midiMapping.noteOff != NULL)
|
||||
{
|
||||
midiMapping.noteOff(ch, note);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* this function will be called when a control change message has been received
|
||||
*/
|
||||
inline void Midi_ControlChange(uint8_t channel, uint8_t data1, uint8_t data2)
|
||||
{
|
||||
for (int i = 0; i < midiMapping.mapSize; i++)
|
||||
{
|
||||
if ((midiMapping.controlMapping[i].channel == channel) && (midiMapping.controlMapping[i].data1 == data1))
|
||||
{
|
||||
if (midiMapping.controlMapping[i].callback_mid != NULL)
|
||||
{
|
||||
midiMapping.controlMapping[i].callback_mid(channel, data1, data2);
|
||||
}
|
||||
if (midiMapping.controlMapping[i].callback_val != NULL)
|
||||
{
|
||||
#ifdef MIDI_FMT_INT
|
||||
midiMapping.controlMapping[i].callback_val(midiMapping.controlMapping[i].user_data, data2);
|
||||
#else
|
||||
midiMapping.controlMapping[i].callback_val(midiMapping.controlMapping[i].user_data, (float)data2 * NORM127MUL);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (data1 == 1)
|
||||
{
|
||||
if (midiMapping.modWheel != NULL)
|
||||
{
|
||||
#ifdef MIDI_FMT_INT
|
||||
midiMapping.modWheel(channel, data2);
|
||||
#else
|
||||
midiMapping.modWheel(channel, (float)data2 * NORM127MUL);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline void Midi_PitchBend(uint8_t ch, uint16_t bend)
|
||||
{
|
||||
float value = ((float)bend - 8192.0f) * (1.0f / 8192.0f) - 1.0f;
|
||||
if (midiMapping.pitchBend != NULL)
|
||||
{
|
||||
midiMapping.pitchBend(ch, value);
|
||||
}
|
||||
}
|
||||
|
||||
inline void Midi_SongPositionPointer(uint16_t pos)
|
||||
{
|
||||
if (midiMapping.songPos != NULL)
|
||||
{
|
||||
midiMapping.songPos(pos);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* function will be called when a short message has been received over midi
|
||||
*/
|
||||
inline void Midi_HandleShortMsg(uint8_t *data, uint8_t cable __attribute__((unused)))
|
||||
{
|
||||
uint8_t ch = data[0] & 0x0F;
|
||||
|
||||
switch (data[0] & 0xF0)
|
||||
{
|
||||
/* note on */
|
||||
case 0x90:
|
||||
if (data[2] > 0)
|
||||
{
|
||||
Midi_NoteOn(ch, data[1], data[2]);
|
||||
}
|
||||
else
|
||||
{
|
||||
Midi_NoteOff(ch, data[1]);
|
||||
}
|
||||
break;
|
||||
/* note off */
|
||||
case 0x80:
|
||||
Midi_NoteOff(ch, data[1]);
|
||||
break;
|
||||
case 0xb0:
|
||||
Midi_ControlChange(ch, data[1], data[2]);
|
||||
break;
|
||||
/* pitchbend */
|
||||
case 0xe0:
|
||||
Midi_PitchBend(ch, ((((uint16_t)data[1])) + ((uint16_t)data[2] << 8)));
|
||||
break;
|
||||
/* song position pointer */
|
||||
case 0xf2:
|
||||
Midi_SongPositionPointer(((((uint16_t)data[1])) + ((uint16_t)data[2] << 8)));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
inline void Midi_RealTimeMessage(uint8_t msg)
|
||||
{
|
||||
if (midiMapping.rttMsg != NULL)
|
||||
{
|
||||
midiMapping.rttMsg(msg);
|
||||
}
|
||||
}
|
||||
|
||||
static void Midi_PortSetup(struct midi_port_s *port)
|
||||
{
|
||||
/* reset the watchdog variables */
|
||||
port->inMsgWd = 0;
|
||||
memset(port->inMsg, 0, sizeof(port->inMsg));
|
||||
port->inMsgIndex = 0;
|
||||
}
|
||||
|
||||
void Midi_Setup()
|
||||
{
|
||||
#ifdef MIDI_RECV_FROM_SERIAL
|
||||
MidiPort.serial = &Serial;
|
||||
#endif /* MIDI_RECV_FROM_SERIAL */
|
||||
|
||||
#ifdef MIDI_PORT_ACTIVE
|
||||
#ifdef SWAP_SERIAL
|
||||
Serial.printf("Switch Serial to Midi!\n");
|
||||
delay(20);
|
||||
Serial.end();
|
||||
Serial.begin(MIDI_BAUDRATE);
|
||||
Serial.swap(); /* using alternative rx and tx pin for Midi communication */
|
||||
delay(20);
|
||||
#endif
|
||||
MidiPort.serial = &Serial;
|
||||
Midi_PortSetup(&MidiPort);
|
||||
#endif
|
||||
|
||||
#ifdef MIDI_PORT1_ACTIVE
|
||||
|
||||
#ifdef MIDI_RX1_PIN
|
||||
#ifdef MIDI_TX1_PIN
|
||||
Serial.printf("Setup Serial1 with %d baud with rx: %d and tx %d\n", MIDI_SERIAL1_BAUDRATE, MIDI_RX1_PIN, MIDI_TX1_PIN);
|
||||
Serial1.begin(MIDI_SERIAL1_BAUDRATE, SERIAL_8N1, MIDI_RX1_PIN, MIDI_TX1_PIN);
|
||||
#else
|
||||
Serial.printf("Setup Serial1 with %d baud with rx: %d only\n", MIDI_SERIAL1_BAUDRATE, MIDI_RX1_PIN);
|
||||
Serial1.begin(MIDI_SERIAL1_BAUDRATE, SERIAL_8N1, MIDI_RX1_PIN);
|
||||
#endif
|
||||
pinMode(MIDI_RX1_PIN, INPUT_PULLUP); /* can be connected to open collector output */
|
||||
#else
|
||||
Serial.printf("Setup Serial1 with %d baud with rx: RX1 pin\n", MIDI_SERIAL1_BAUDRATE);
|
||||
Serial1.begin(MIDI_SERIAL1_BAUDRATE);
|
||||
#endif
|
||||
|
||||
#ifdef ARDUINO_SEEED_XIAO_M0
|
||||
pinMode(PIN_SERIAL1_RX, INPUT_PULLUP);
|
||||
#endif
|
||||
|
||||
MidiPort1.serial = &Serial1;
|
||||
Midi_PortSetup(&MidiPort1);
|
||||
#endif /* MIDI_PORT1_ACTIVE */
|
||||
|
||||
|
||||
#ifdef MIDI_PORT2_ACTIVE
|
||||
|
||||
#ifdef MIDI_RX2_PIN
|
||||
#ifdef MIDI_TX2_PIN
|
||||
Serial.printf("Setup Serial2 with %d baud with rx: %d and tx %d\n", MIDI_SERIAL2_BAUDRATE, MIDI_RX2_PIN, MIDI_TX2_PIN);
|
||||
Serial2.begin(MIDI_SERIAL2_BAUDRATE, SERIAL_8N1, MIDI_RX2_PIN, MIDI_TX2_PIN);
|
||||
#else
|
||||
Serial.printf("Setup Serial2 with %d baud with rx: %d only\n", MIDI_SERIAL2_BAUDRATE, MIDI_RX2_PIN);
|
||||
Serial2.begin(MIDI_SERIAL2_BAUDRATE, SERIAL_8N1, MIDI_RX2_PIN);
|
||||
#endif
|
||||
pinMode(MIDI_RX2_PIN, INPUT_PULLUP); /* can be connected to open collector output */
|
||||
#else
|
||||
Serial.printf("Setup Serial2 with %d baud with rx: RX2 pin\n", MIDI_SERIAL2_BAUDRATE);
|
||||
Serial2.begin(MIDI_SERIAL2_BAUDRATE);
|
||||
#endif
|
||||
|
||||
MidiPort2.serial = &Serial2;
|
||||
Midi_PortSetup(&MidiPort2);
|
||||
Serial.printf("Setup MidiPort2 using Serial2\n");
|
||||
#endif /* MIDI_PORT2_ACTIVE */
|
||||
}
|
||||
|
||||
void Midi_CheckMidiPort(struct midi_port_s *port)
|
||||
{
|
||||
//Choose Serial1 or Serial2 as required
|
||||
|
||||
if (port->serial->available())
|
||||
{
|
||||
uint8_t incomingByte = port->serial->read();
|
||||
|
||||
#ifdef MIDI_DUMP_SERIAL2_TO_SERIAL
|
||||
Serial.printf("%02x", incomingByte);
|
||||
#endif
|
||||
/* ignore live messages */
|
||||
if ((incomingByte & 0xF0) == 0xF0)
|
||||
{
|
||||
Midi_RealTimeMessage(incomingByte);
|
||||
return;
|
||||
}
|
||||
|
||||
if (port->inMsgIndex == 0)
|
||||
{
|
||||
if ((incomingByte & 0x80) != 0x80)
|
||||
{
|
||||
port->inMsgIndex = 1;
|
||||
}
|
||||
}
|
||||
|
||||
port->inMsg[port->inMsgIndex] = incomingByte;
|
||||
port->inMsgIndex += 1;
|
||||
|
||||
if ((port->inMsgIndex >= 3) ||
|
||||
(
|
||||
(((port->inMsg[0] & 0xF0) == 0xD0)
|
||||
|| ((port->inMsg[0] & 0xF0) == 0xC0))
|
||||
&& (port->inMsgIndex >= 2))
|
||||
)
|
||||
{
|
||||
#ifdef MIDI_DUMP_SERIAL2_TO_SERIAL
|
||||
if (port->inMsgIndex >= 3)
|
||||
{
|
||||
Serial.printf("\n>%02x %02x %02x<\n", port->inMsg[0], port->inMsg[1], port->inMsg[2]);
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.printf("\n>%02x %02x<\n", port->inMsg[0], port->inMsg[1]);
|
||||
}
|
||||
#endif
|
||||
Midi_HandleShortMsg(port->inMsg, 0);
|
||||
port->inMsgIndex = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* reset watchdog to allow new bytes to be received
|
||||
*/
|
||||
port->inMsgWd = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (port->inMsgIndex > 0)
|
||||
{
|
||||
port->inMsgWd++;
|
||||
if (port->inMsgWd == 0xFFF)
|
||||
{
|
||||
port->inMsgIndex = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* this function should be called continuously to ensure that incoming messages can be processed
|
||||
*/
|
||||
inline
|
||||
void Midi_Process()
|
||||
{
|
||||
#ifdef MIDI_PORT_ACTIVE
|
||||
Midi_CheckMidiPort(&MidiPort);
|
||||
#endif
|
||||
#ifdef MIDI_PORT1_ACTIVE
|
||||
Midi_CheckMidiPort(&MidiPort1);
|
||||
#endif
|
||||
#ifdef MIDI_PORT2_ACTIVE
|
||||
Midi_CheckMidiPort(&MidiPort2);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef ARDUINO_SEEED_XIAO_M0
|
||||
#ifndef SWAP_SERIAL
|
||||
void Midi_SendShortMessage(uint8_t *msg)
|
||||
{
|
||||
#ifdef MIDI_TX2_PIN
|
||||
MidiPort2.serial->write(msg, 3);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Midi_SendRaw(uint8_t *msg)
|
||||
{
|
||||
#ifdef MIDI_TX2_PIN
|
||||
/* sysex */
|
||||
if (msg[0] == 0xF0)
|
||||
{
|
||||
int i = 2;
|
||||
while (msg[i] != 0xF7)
|
||||
{
|
||||
i++;
|
||||
}
|
||||
MidiPort2.serial->write(msg, i + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
MidiPort2.serial->write(msg, 3);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
|
||||
#define ML_SYNTH_INLINE_DEFINITION
|
||||
#include <ml_inline.h>
|
||||
#undef ML_SYNTH_INLINE_DEFINITION
|
||||
@@ -128,6 +128,7 @@ struct midiMapping_s midiMapping =
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
edirolMapping,
|
||||
sizeof(edirolMapping) / sizeof(edirolMapping[0]),
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user