Jan Ostman
Published © GPL3+

Audio Hacking on the ESP8266

Building synthesizers on the ESP8266.

IntermediateProtip1 hour6,724
Audio Hacking on the ESP8266

Story

Read more

Code

Code snippet #1

Plain text
#include "Arduino.h"
#include "ESP8266WiFi.h"
#include "i2s.h"
#include "i2s_reg.h"

void setup() {
  //WiFi.forceSleepBegin();
  //delay(1);
  system_update_cpu_freq(160);

  i2s_begin();
  i2s_set_rate(44100);

}

Code snippet #2

Plain text
void writeDAC(uint16_t DAC) {
 for (uint8_t i=0;i<32;i++) { 
  i2sACC=i2sACC<<1;
  if(DAC >= err) {
    i2sACC|=1;
    err += 0xFFFF-DAC;
  }
    else
  {
    err -= DAC;
  }
 }
 bool flag=i2s_write_sample(i2sACC);
}

Code snippet #3

Plain text
uint8_t phase;
  void loop() {
  writeDAC(0x8000+sine[phase++]);
}

Code snippet #4

Plain text
int16_t sine[256] = {
  0x0000, 0x0324, 0x0647, 0x096a, 0x0c8b, 0x0fab, 0x12c8, 0x15e2,
  0x18f8, 0x1c0b, 0x1f19, 0x2223, 0x2528, 0x2826, 0x2b1f, 0x2e11,
  0x30fb, 0x33de, 0x36ba, 0x398c, 0x3c56, 0x3f17, 0x41ce, 0x447a,
  0x471c, 0x49b4, 0x4c3f, 0x4ebf, 0x5133, 0x539b, 0x55f5, 0x5842,
  0x5a82, 0x5cb4, 0x5ed7, 0x60ec, 0x62f2, 0x64e8, 0x66cf, 0x68a6,
  0x6a6d, 0x6c24, 0x6dca, 0x6f5f, 0x70e2, 0x7255, 0x73b5, 0x7504,
  0x7641, 0x776c, 0x7884, 0x798a, 0x7a7d, 0x7b5d, 0x7c29, 0x7ce3,
  0x7d8a, 0x7e1d, 0x7e9d, 0x7f09, 0x7f62, 0x7fa7, 0x7fd8, 0x7ff6,
  0x7fff, 0x7ff6, 0x7fd8, 0x7fa7, 0x7f62, 0x7f09, 0x7e9d, 0x7e1d,
  0x7d8a, 0x7ce3, 0x7c29, 0x7b5d, 0x7a7d, 0x798a, 0x7884, 0x776c,
  0x7641, 0x7504, 0x73b5, 0x7255, 0x70e2, 0x6f5f, 0x6dca, 0x6c24,
  0x6a6d, 0x68a6, 0x66cf, 0x64e8, 0x62f2, 0x60ec, 0x5ed7, 0x5cb4,
  0x5a82, 0x5842, 0x55f5, 0x539b, 0x5133, 0x4ebf, 0x4c3f, 0x49b4,
  0x471c, 0x447a, 0x41ce, 0x3f17, 0x3c56, 0x398c, 0x36ba, 0x33de,
  0x30fb, 0x2e11, 0x2b1f, 0x2826, 0x2528, 0x2223, 0x1f19, 0x1c0b,
  0x18f8, 0x15e2, 0x12c8, 0x0fab, 0x0c8b, 0x096a, 0x0647, 0x0324,
  0x0000, 0xfcdc, 0xf9b9, 0xf696, 0xf375, 0xf055, 0xed38, 0xea1e,
  0xe708, 0xe3f5, 0xe0e7, 0xdddd, 0xdad8, 0xd7da, 0xd4e1, 0xd1ef,
  0xcf05, 0xcc22, 0xc946, 0xc674, 0xc3aa, 0xc0e9, 0xbe32, 0xbb86,
  0xb8e4, 0xb64c, 0xb3c1, 0xb141, 0xaecd, 0xac65, 0xaa0b, 0xa7be,
  0xa57e, 0xa34c, 0xa129, 0x9f14, 0x9d0e, 0x9b18, 0x9931, 0x975a,
  0x9593, 0x93dc, 0x9236, 0x90a1, 0x8f1e, 0x8dab, 0x8c4b, 0x8afc,
  0x89bf, 0x8894, 0x877c, 0x8676, 0x8583, 0x84a3, 0x83d7, 0x831d,
  0x8276, 0x81e3, 0x8163, 0x80f7, 0x809e, 0x8059, 0x8028, 0x800a,
  0x8000, 0x800a, 0x8028, 0x8059, 0x809e, 0x80f7, 0x8163, 0x81e3,
  0x8276, 0x831d, 0x83d7, 0x84a3, 0x8583, 0x8676, 0x877c, 0x8894,
  0x89bf, 0x8afc, 0x8c4b, 0x8dab, 0x8f1e, 0x90a1, 0x9236, 0x93dc,
  0x9593, 0x975a, 0x9931, 0x9b18, 0x9d0e, 0x9f14, 0xa129, 0xa34c,
  0xa57e, 0xa7be, 0xaa0b, 0xac65, 0xaecd, 0xb141, 0xb3c1, 0xb64c,
  0xb8e4, 0xbb86, 0xbe32, 0xc0e9, 0xc3aa, 0xc674, 0xc946, 0xcc22,
  0xcf05, 0xd1ef, 0xd4e1, 0xd7da, 0xdad8, 0xdddd, 0xe0e7, 0xe3f5,
  0xe708, 0xea1e, 0xed38, 0xf055, 0xf375, 0xf696, 0xf9b9, 0xfcdc
};

Code snippet #5

Plain text
const uint16_t BD16[3796] PROGMEM = {
40, 85, 137, 144, -30, -347, -609, -785, // 0-7

const uint16_t CP16[4445] PROGMEM = {
-42, 74, -1236, -2741, -3134, -11950, -13578, -7572, // 0-7

Code snippet #6

Plain text
uint32_t BD16CNT;
uint32_t CP16CNT;
uint32_t CR16CNT;
uint32_t HH16CNT;
uint32_t HT16CNT;
uint32_t LT16CNT;
uint32_t MT16CNT;
uint32_t CH16CNT;
uint32_t OH16CNT;
uint32_t RD16CNT;
uint32_t RS16CNT;
uint32_t SD16CNT;

#define BD16LEN 3796UL
#define CP16LEN 4445UL
#define CR16LEN 48686UL
#define HH16LEN 1734UL
#define HT16LEN 5802UL
#define LT16LEN 7061UL
#define MT16LEN 7304UL
#define OH16LEN 4772UL
#define RD16LEN 52850UL
#define RS16LEN 1316UL
#define SD16LEN 5577UL

Code snippet #7

Plain text
uint16_t SYNTH909() {
 int32_t DRUMTOTAL=0;
 if (BD16CNT<BD16LEN) DRUMTOTAL+=(pgm_read_word_near(BD16 + BD16CNT++)^32768)-32768;
 if (CP16CNT<CP16LEN) DRUMTOTAL+=(pgm_read_word_near(CP16 + CP16CNT++)^32768)-32768;
 if (CR16CNT<CR16LEN) DRUMTOTAL+=(pgm_read_word_near(CR16 + CR16CNT++)^32768)-32768;
 if (HH16CNT<HH16LEN) DRUMTOTAL+=(pgm_read_word_near(HH16 + HH16CNT++)^32768)-32768;
 if (HT16CNT<HT16LEN) DRUMTOTAL+=(pgm_read_word_near(HT16 + HT16CNT++)^32768)-32768;
 if (LT16CNT<LT16LEN) DRUMTOTAL+=(pgm_read_word_near(LT16 + LT16CNT++)^32768)-32768;
 if (MT16CNT<MT16LEN) DRUMTOTAL+=(pgm_read_word_near(MT16 + MT16CNT++)^32768)-32768;
 if (OH16CNT<OH16LEN) DRUMTOTAL+=(pgm_read_word_near(OH16 + OH16CNT++)^32768)-32768;
 if (RD16CNT<RD16LEN) DRUMTOTAL+=(pgm_read_word_near(RD16 + RD16CNT++)^32768)-32768;
 if (RS16CNT<RS16LEN) DRUMTOTAL+=(pgm_read_word_near(RS16 + RS16CNT++)^32768)-32768;
 if (SD16CNT<SD16LEN) DRUMTOTAL+=(pgm_read_word_near(SD16 + SD16CNT++)^32768)-32768;
 if (DRUMTOTAL>32767) DRUMTOTAL=32767;
 if (DRUMTOTAL<-32767) DRUMTOTAL=-32767;
 DRUMTOTAL+=32768;
 return DRUMTOTAL;
}

Code snippet #8

Plain text
void loop() {
DAC=SYNTH909();

//Pulse Density Modulated 16-bit I2S DAC
for (uint8_t i=0;i<32;i++) { 
  i2sACC=i2sACC<<1;
  if(DAC >= err) {
    i2sACC|=1;
    err += 0xFFFF-DAC;
  }
    else
  {
    err -= DAC;
  }
 }
 bool flag=i2s_write_sample(i2sACC);

Code snippet #9

Plain text
void MidiNoteOn(uint8_t channel, uint8_t note, uint8_t velocity) {

/* 909 MIDI Triggers
Bass Drum MIDI-35
Bass Drum MIDI-36
Rim Shot MIDI-37
Snare Drum MIDI-38
Hand Clap MIDI-39
Snare Drum MIDI-40
Low Tom MIDI-41
Closed Hat MIDI-42
Low Tom MIDI-43
Closed Hat MIDI-44
Mid Tom MIDI-45
Open Hat MIDI-46
Mid Tom MIDI-47
Hi Tom MIDI-48
Crash Cymbal MIDI-49
Hi Tom MIDI-50
Ride Cymbal MIDI-51
*/

if (channel==10) {
if(note==35) BD16CNT=0;
if(note==36) BD16CNT=0;
if(note==37) RS16CNT=0;
if(note==38) SD16CNT=0;
if(note==39) CP16CNT=0;
if(note==40) SD16CNT=0;
if(note==41) LT16CNT=0;
if(note==42) HH16CNT=0;
if(note==43) LT16CNT=0;
if(note==44) HH16CNT=0;
if(note==45) MT16CNT=0;
if(note==46) OH16CNT=0;
if(note==47) MT16CNT=0;
if(note==48) HT16CNT=0;
if(note==49) CR16CNT=0;
if(note==50) HT16CNT=0;
if(note==51) RD16CNT=0;
}
}

Code snippet #10

Plain text
#include <Arduino.h> 
#include "ESP8266WiFi.h"
#include <i2s.h>
#include <i2s_reg.h>
#include <pgmspace.h>
#include <Ticker.h>

uint32_t i2sACC;
uint8_t i2sCNT=32;
uint16_t DAC=0x8000;
uint16_t err;

Code snippet #11

Plain text
int16_t sine[256] = {
0x0000, 0x0324, 0x0647, 0x096a, 0x0c8b, 0x0fab, 0x12c8, 0x15e2,
0x18f8, 0x1c0b, 0x1f19, 0x2223, 0x2528, 0x2826, 0x2b1f, 0x2e11,
0x30fb, 0x33de, 0x36ba, 0x398c, 0x3c56, 0x3f17, 0x41ce, 0x447a,
0x471c, 0x49b4, 0x4c3f, 0x4ebf, 0x5133, 0x539b, 0x55f5, 0x5842,
0x5a82, 0x5cb4, 0x5ed7, 0x60ec, 0x62f2, 0x64e8, 0x66cf, 0x68a6,
0x6a6d, 0x6c24, 0x6dca, 0x6f5f, 0x70e2, 0x7255, 0x73b5, 0x7504,
0x7641, 0x776c, 0x7884, 0x798a, 0x7a7d, 0x7b5d, 0x7c29, 0x7ce3,
0x7d8a, 0x7e1d, 0x7e9d, 0x7f09, 0x7f62, 0x7fa7, 0x7fd8, 0x7ff6,
0x7fff, 0x7ff6, 0x7fd8, 0x7fa7, 0x7f62, 0x7f09, 0x7e9d, 0x7e1d,
0x7d8a, 0x7ce3, 0x7c29, 0x7b5d, 0x7a7d, 0x798a, 0x7884, 0x776c,
0x7641, 0x7504, 0x73b5, 0x7255, 0x70e2, 0x6f5f, 0x6dca, 0x6c24,
0x6a6d, 0x68a6, 0x66cf, 0x64e8, 0x62f2, 0x60ec, 0x5ed7, 0x5cb4,
0x5a82, 0x5842, 0x55f5, 0x539b, 0x5133, 0x4ebf, 0x4c3f, 0x49b4,
0x471c, 0x447a, 0x41ce, 0x3f17, 0x3c56, 0x398c, 0x36ba, 0x33de,
0x30fb, 0x2e11, 0x2b1f, 0x2826, 0x2528, 0x2223, 0x1f19, 0x1c0b,
0x18f8, 0x15e2, 0x12c8, 0x0fab, 0x0c8b, 0x096a, 0x0647, 0x0324,
0x0000, 0xfcdc, 0xf9b9, 0xf696, 0xf375, 0xf055, 0xed38, 0xea1e,
0xe708, 0xe3f5, 0xe0e7, 0xdddd, 0xdad8, 0xd7da, 0xd4e1, 0xd1ef,
0xcf05, 0xcc22, 0xc946, 0xc674, 0xc3aa, 0xc0e9, 0xbe32, 0xbb86,
0xb8e4, 0xb64c, 0xb3c1, 0xb141, 0xaecd, 0xac65, 0xaa0b, 0xa7be,
0xa57e, 0xa34c, 0xa129, 0x9f14, 0x9d0e, 0x9b18, 0x9931, 0x975a,
0x9593, 0x93dc, 0x9236, 0x90a1, 0x8f1e, 0x8dab, 0x8c4b, 0x8afc,
0x89bf, 0x8894, 0x877c, 0x8676, 0x8583, 0x84a3, 0x83d7, 0x831d,
0x8276, 0x81e3, 0x8163, 0x80f7, 0x809e, 0x8059, 0x8028, 0x800a,
0x8000, 0x800a, 0x8028, 0x8059, 0x809e, 0x80f7, 0x8163, 0x81e3,
0x8276, 0x831d, 0x83d7, 0x84a3, 0x8583, 0x8676, 0x877c, 0x8894,
0x89bf, 0x8afc, 0x8c4b, 0x8dab, 0x8f1e, 0x90a1, 0x9236, 0x93dc,
0x9593, 0x975a, 0x9931, 0x9b18, 0x9d0e, 0x9f14, 0xa129, 0xa34c,
0xa57e, 0xa7be, 0xaa0b, 0xac65, 0xaecd, 0xb141, 0xb3c1, 0xb64c,
0xb8e4, 0xbb86, 0xbe32, 0xc0e9, 0xc3aa, 0xc674, 0xc946, 0xcc22,
0xcf05, 0xd1ef, 0xd4e1, 0xd7da, 0xdad8, 0xdddd, 0xe0e7, 0xe3f5,
0xe708, 0xea1e, 0xed38, 0xf055, 0xf375, 0xf696, 0xf9b9, 0xfcdc
};

uint8_t phase=0; //Sine phase counter

Code snippet #12

Plain text
void setup() {
i2s_begin(); //Start the i2s DMA engine
i2s_set_rate(44100); //Set sample rate
pinMode(2, INPUT); //restore GPIOs taken by i2s
pinMode(15, INPUT);
timer1_attachInterrupt(onTimerISR); //Attach our sampling ISR
timer1_enable(TIM_DIV16, TIM_EDGE, TIM_SINGLE);
timer1_write(2000); //Service at 2mS intervall
}

Code snippet #14

Plain text
void ICACHE_RAM_ATTR onTimerISR(){ //Code needs to be in IRAM because its a ISR

while (!(i2s_is_full())) { //Don’t block the ISR if the buffer is full

DAC=0x8000+sine[phase++];

//Pulse Density Modulated 16-bit I2S DAC
for (uint8_t i=0;i<32;i++) { 
  i2sACC=i2sACC<<1;
  if(DAC >= err) {
    i2sACC|=1;
    err += 0xFFFF-DAC;
  }
    else
  {
    err -= DAC;
  }
 }
 bool flag=i2s_write_sample(i2sACC);
}

timer1_write(2000);//Next in 2mS
}

Code snippet #16

Plain text
void setup() {
  Serial.begin(31250); //Start the serial port with default MIDI baudrate
  Serial.swap(); //Move the TX and RX GPIOs to 15 and 13
  i2s_begin(); //Start the i2s DMA engine
  i2s_set_rate(44100); //Set sample rate
  pinMode(2, INPUT); //restore GPIOs taken by i2s
  pinMode(15, INPUT);
  timer1_attachInterrupt(onTimerISR); //Attach our sampling ISR
  timer1_enable(TIM_DIV16, TIM_EDGE, TIM_SINGLE);
  timer1_write(2000); //Service at 2mS intervall
}

Code snippet #17

Plain text
uint8_t MIDISTATE=0;
uint8_t MIDIRUNNINGSTATUS=0;
uint8_t MIDINOTE;
uint8_t MIDIVEL;

Code snippet #18

Plain text
void processMIDI(uint8_t MIDIRX) {

/*
Handling “Running status”
1.Buffer is cleared (ie, set to 0) at power up.
2.Buffer stores the status when a Voice Category Status (ie, 0x80 to 0xEF) is received.
3.Buffer is cleared when a System Common Category Status (ie, 0xF0 to 0xF7) is received.
4.Nothing is done to the buffer when a RealTime Category message is received.
5.Any data bytes are ignored when the buffer is 0.
*/
if ((MIDIRX>0xBF)&&(MIDIRX<0xF8)) {
 MIDIRUNNINGSTATUS=0;
 MIDISTATE=0;
 return;
}
if (MIDIRX>0xF7) return;
if (MIDIRX & 0x80) {
  MIDIRUNNINGSTATUS=MIDIRX;
  MIDISTATE=1;
return;
}
if (MIDIRX < 0x80) {
  if (!MIDIRUNNINGSTATUS) return;
  if (MIDISTATE==1) {
  MIDINOTE=MIDIRX;
  MIDISTATE++;
  return;
}
if (MIDISTATE==2) {
  MIDIVEL=MIDIRX;
  MIDISTATE=1;
  //if (MIDIRUNNINGSTATUS==0x80) handleMIDInoteOFF(MIDIRUNNINGSTATUS,MIDINOTE,MIDIVEL);
  //if (MIDIRUNNINGSTATUS==0x90) handleMIDInoteON(MIDIRUNNINGSTATUS,MIDINOTE,MIDIVEL);
  //if (MIDIRUNNINGSTATUS==0xB0) handleMIDICC(MIDINOTE,MIDIVEL);
}
}
}

Code snippet #20

Plain text
#include <Arduino.h> 
#include "ESP8266WiFi.h"
#include <WiFiClient.h>
#include <WiFiUdp.h>
#include <i2s.h>
#include <i2s_reg.h>
#include <pgmspace.h>
#include "AppleMidi.h"
#include <Ticker.h>
extern “C” {
#include “user_interface.h”
}

char ssid[] = "YourSSID"; //  your network SSID (name)
char pass[] = "YourKEY";    // your network password (use for WPA, or use as key for WEP)

APPLEMIDI_CREATE_INSTANCE(WiFiUDP, AppleMIDI); // see definition in AppleMidi_Defs.h

// Forward declaration
void OnAppleMidiConnected(uint32_t ssrc, char* name);
void OnAppleMidiDisconnected(uint32_t ssrc);
void OnAppleMidiNoteOn(byte channel, byte note, byte velocity);
void OnAppleMidiNoteOff(byte channel, byte note, byte velocity);

uint32_t i2sACC;
uint8_t i2sCNT=32;
uint16_t DAC=0x8000;
uint16_t err;

uint32_t BD16CNT;
uint32_t CP16CNT;
uint32_t CR16CNT;
uint32_t HH16CNT;
uint32_t HT16CNT;
uint32_t LT16CNT;
uint32_t MT16CNT;
uint32_t CH16CNT;
uint32_t OH16CNT;
uint32_t RD16CNT;
uint32_t RS16CNT;
uint32_t SD16CNT;

#define BD16LEN 3796UL
#define CP16LEN 4445UL
#define CR16LEN 48686UL
#define HH16LEN 1734UL
#define HT16LEN 5802UL
#define LT16LEN 7061UL
#define MT16LEN 7304UL
#define OH16LEN 4772UL
#define RD16LEN 52850UL
#define RS16LEN 1316UL
#define SD16LEN 5577UL

const uint16_t BD16[3796] PROGMEM = {
40, 85, 137, 144, -30, -347, -609, -785, // 0-7

Code snippet #21

Plain text
uint16_t SYNTH909() {
  int32_t DRUMTOTAL=0;
  if (BD16CNT<BD16LEN) DRUMTOTAL+=(pgm_read_word_near(BD16 + BD16CNT++)^32768)-32768;
  if (CP16CNT<CP16LEN) DRUMTOTAL+=(pgm_read_word_near(CP16 + CP16CNT++)^32768)-32768;
  if (CR16CNT<CR16LEN) DRUMTOTAL+=(pgm_read_word_near(CR16 + CR16CNT++)^32768)-32768;
  if (HH16CNT<HH16LEN) DRUMTOTAL+=(pgm_read_word_near(HH16 + HH16CNT++)^32768)-32768;
  if (HT16CNT<HT16LEN) DRUMTOTAL+=(pgm_read_word_near(HT16 + HT16CNT++)^32768)-32768;
  if (LT16CNT<LT16LEN) DRUMTOTAL+=(pgm_read_word_near(LT16 + LT16CNT++)^32768)-32768;
  if (MT16CNT<MT16LEN) DRUMTOTAL+=(pgm_read_word_near(MT16 + MT16CNT++)^32768)-32768;
  if (OH16CNT<OH16LEN) DRUMTOTAL+=(pgm_read_word_near(OH16 + OH16CNT++)^32768)-32768;
  if (RD16CNT<RD16LEN) DRUMTOTAL+=(pgm_read_word_near(RD16 + RD16CNT++)^32768)-32768;
  if (RS16CNT<RS16LEN) DRUMTOTAL+=(pgm_read_word_near(RS16 + RS16CNT++)^32768)-32768;
  if (SD16CNT<SD16LEN) DRUMTOTAL+=(pgm_read_word_near(SD16 + SD16CNT++)^32768)-32768;
  if  (DRUMTOTAL>32767) DRUMTOTAL=32767;
  if  (DRUMTOTAL<-32767) DRUMTOTAL=-32767;
  DRUMTOTAL+=32768;
  return DRUMTOTAL;
}

Code snippet #22

Plain text
void setup() {
//WiFi.forceSleepBegin();
//delay(1);
system_update_cpu_freq(160);

//Serial.begin(9600);

WiFi.begin(ssid, pass);

while (WiFi.status() != WL_CONNECTED) {
delay(500);
}

//Serial.print(F(“IP address is “));
//Serial.println(WiFi.localIP());

AppleMIDI.begin(“ESP909”); // ‘ESP909’ will show up as the session name

AppleMIDI.OnReceiveNoteOn(OnAppleMidiNoteOn);

i2s_begin();
i2s_set_rate(44100);
timer1_attachInterrupt(onTimerISR); //Attach our sampling ISR
timer1_enable(TIM_DIV16, TIM_EDGE, TIM_SINGLE);
timer1_write(2000); //Service at 2mS intervall

}

Code snippet #24

Plain text
void ICACHE_RAM_ATTR onTimerISR(){
  
  while (!(i2s_is_full())) { //Don't block the ISR
    
    DAC=SYNTH909();

    //----------------- Pulse Density Modulated 16-bit I2S DAC --------------------
     for (uint8_t i=0;i<32;i++) { 
      i2sACC=i2sACC<<1;
      if(DAC >= err) {
        i2sACC|=1;
        err += 0xFFFF-DAC;
      }
        else
      {
        err -= DAC;
      }
     }
     bool flag=i2s_write_sample(i2sACC);
    //-----------------------------------------------------------------------

  }
  
  timer1_write(2000);//Next in 2mS
}

Code snippet #25

Plain text
void OnAppleMidiNoteOn(byte channel, byte note, byte velocity) {

/* Triggers
Bass Drum MIDI-35
Bass Drum MIDI-36
Rim Shot MIDI-37
Snare Drum MIDI-38
Hand Clap MIDI-39
Snare Drum MIDI-40
Low Tom MIDI-41
Closed Hat MIDI-42
Low Tom MIDI-43
Closed Hat MIDI-44
Mid Tom MIDI-45
Open Hat MIDI-46
Mid Tom MIDI-47
Hi Tom MIDI-48
Crash Cymbal MIDI-49
Hi Tom MIDI-50
Ride Cymbal MIDI-51
*/

if (channel==10) {
if(note==35) BD16CNT=0;
if(note==36) BD16CNT=0;
if(note==37) RS16CNT=0;
if(note==38) SD16CNT=0;
if(note==39) CP16CNT=0;
if(note==40) SD16CNT=0;
if(note==41) LT16CNT=0;
if(note==42) HH16CNT=0;
if(note==43) LT16CNT=0;
if(note==44) HH16CNT=0;
if(note==45) MT16CNT=0;
if(note==46) OH16CNT=0;
if(note==47) MT16CNT=0;
if(note==48) HT16CNT=0;
if(note==49) CR16CNT=0;
if(note==50) HT16CNT=0;
if(note==51) RD16CNT=0;
}
}

Code snippet #26

C/C++
#include <Arduino.h> 
#include "ESP8266WiFi.h"
#include <WiFiClient.h>
#include <WiFiUdp.h>
#include <i2s.h>
#include <i2s_reg.h>
#include <pgmspace.h>
#include "AppleMidi.h"
#include <Ticker.h>
 
extern "C" {
#include "user_interface.h"
}
 
#define GPIO_IN ((volatile uint32_t*) 0x60000318)    // register contains gpio pin values of ESP8266 in read mode + some extra values (need to be truncated)
 
char ssid[] = "YourSSID"; //  your network SSID (name)
char pass[] = "YourKEY";    // your network password (use for WPA, or use as key for WEP)
 
APPLEMIDI_CREATE_INSTANCE(WiFiUDP, AppleMIDI); // see definition in AppleMidi_Defs.h
 
// Forward declaration
void OnAppleMidiConnected(uint32_t ssrc, char* name);
void OnAppleMidiDisconnected(uint32_t ssrc);
void OnAppleMidiNoteOn(byte channel, byte note, byte velocity);
void OnAppleMidiNoteOff(byte channel, byte note, byte velocity);
 
uint32_t i2sACC;
uint8_t i2sCNT=32;
uint16_t DAC=0x8000;
uint16_t err;
 
uint32_t BD16CNT;
uint32_t CP16CNT;
uint32_t CR16CNT;
uint32_t HH16CNT;
uint32_t HT16CNT;
uint32_t LT16CNT;
uint32_t MT16CNT;
uint32_t CH16CNT;
uint32_t OH16CNT;
uint32_t RD16CNT;
uint32_t RS16CNT;
uint32_t SD16CNT;
 
 
uint32_t samplecounter=100;
uint32_t TRIG0, TRIG1, TRIG2, TRIG3, TRIG4, TRIG5, TRIG6, TRIG7, TRIG8, TRIG9, TRIG10;
uint32_t OLDTRIG0,OLDTRIG1,OLDTRIG2,OLDTRIG3,OLDTRIG4,OLDTRIG5,OLDTRIG6,OLDTRIG7,OLDTRIG8,OLDTRIG9,OLDTRIG10;
 
 
#define BD16LEN 3796UL
#define CP16LEN 4445UL
#define CR16LEN 48686UL
#define HH16LEN 1734UL
#define HT16LEN 5802UL
#define LT16LEN 7061UL
#define MT16LEN 7304UL
#define OH16LEN 4772UL
#define RD16LEN 52850UL
#define RS16LEN 1316UL
#define SD16LEN 5577UL
 
const uint16_t BD16[3796] PROGMEM = {
40,  85, 137, 144, -30, -347, -609, -785, // 0-7
 
uint16_t SYNTH909() {
  int32_t DRUMTOTAL=0;
  if (BD16CNT<BD16LEN) DRUMTOTAL+=(pgm_read_word_near(BD16 + BD16CNT++)^32768)-32768;
  if (CP16CNT<CP16LEN) DRUMTOTAL+=(pgm_read_word_near(CP16 + CP16CNT++)^32768)-32768;
  if (CR16CNT<CR16LEN) DRUMTOTAL+=(pgm_read_word_near(CR16 + CR16CNT++)^32768)-32768;
  if (HH16CNT<HH16LEN) DRUMTOTAL+=(pgm_read_word_near(HH16 + HH16CNT++)^32768)-32768;
  if (HT16CNT<HT16LEN) DRUMTOTAL+=(pgm_read_word_near(HT16 + HT16CNT++)^32768)-32768;
  if (LT16CNT<LT16LEN) DRUMTOTAL+=(pgm_read_word_near(LT16 + LT16CNT++)^32768)-32768;
  if (MT16CNT<MT16LEN) DRUMTOTAL+=(pgm_read_word_near(MT16 + MT16CNT++)^32768)-32768;
  if (OH16CNT<OH16LEN) DRUMTOTAL+=(pgm_read_word_near(OH16 + OH16CNT++)^32768)-32768;
  if (RD16CNT<RD16LEN) DRUMTOTAL+=(pgm_read_word_near(RD16 + RD16CNT++)^32768)-32768;
  if (RS16CNT<RS16LEN) DRUMTOTAL+=(pgm_read_word_near(RS16 + RS16CNT++)^32768)-32768;
  if (SD16CNT<SD16LEN) DRUMTOTAL+=(pgm_read_word_near(SD16 + SD16CNT++)^32768)-32768; if (DRUMTOTAL>32767) DRUMTOTAL=32767;
  if  (DRUMTOTAL<-32767) DRUMTOTAL=-32767;
  DRUMTOTAL+=32768;
  return DRUMTOTAL;
}
 
 
void setup() {
  //WiFi.forceSleepBegin();             
  //delay(1);                               
  system_update_cpu_freq(160);
 
  //Serial.begin(9600);
 
  WiFi.begin(ssid, pass);
 
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
  }
 
  //Serial.print(F("IP address is ")); 
  //Serial.println(WiFi.localIP()); 
 
 
  AppleMIDI.begin("ESP909"); // 'ESP909' will show up as the session name
 
  AppleMIDI.OnReceiveNoteOn(OnAppleMidiNoteOn);
 
  i2s_begin();
  i2s_set_rate(44100);
  timer1_attachInterrupt(onTimerISR); //Attach our sampling ISR
  timer1_enable(TIM_DIV16, TIM_EDGE, TIM_SINGLE);
  timer1_write(2000); //Service at 2mS intervall
 
 
}
 
void loop() {
 AppleMIDI.run();
} 
 
void ICACHE_RAM_ATTR onTimerISR(){
 
  while (!(i2s_is_full())) { //Don't block the ISR
 
    DAC=SYNTH909();
 
    //----------------- Pulse Density Modulated 16-bit I2S DAC --------------------
     for (uint8_t i=0;i<32;i++) { 
      i2sACC=i2sACC<<1; if(DAC >= err) {
        i2sACC|=1;
        err += 0xFFFF-DAC;
      }
        else
      {
        err -= DAC;
      }
     }
     bool flag=i2s_write_sample(i2sACC);
    //-----------------------------------------------------------------------
 
  }
 
  timer1_write(2000);//Next in 2mS
}
 
void OnAppleMidiNoteOn(byte channel, byte note, byte velocity) {
 
/* Triggers
Bass Drum MIDI-35
Bass Drum MIDI-36
Rim Shot MIDI-37
Snare Drum MIDI-38
Hand Clap MIDI-39
Snare Drum MIDI-40
Low Tom MIDI-41
Closed Hat MIDI-42
Low Tom MIDI-43
Closed Hat MIDI-44
Mid Tom MIDI-45
Open Hat MIDI-46
Mid Tom MIDI-47
Hi Tom MIDI-48
Crash Cymbal MIDI-49
Hi Tom MIDI-50
Ride Cymbal MIDI-51
*/
 
  if (channel==10) {
    if(note==35) BD16CNT=0;
    if(note==36) BD16CNT=0;
    if(note==37) RS16CNT=0;
    if(note==38) SD16CNT=0;
    if(note==39) CP16CNT=0;
    if(note==40) SD16CNT=0;
    if(note==41) LT16CNT=0;
    if(note==42) HH16CNT=0;
    if(note==43) LT16CNT=0;
    if(note==44) HH16CNT=0;
    if(note==45) MT16CNT=0;
    if(note==46) OH16CNT=0;
    if(note==47) MT16CNT=0;
    if(note==48) HT16CNT=0;
    if(note==49) CR16CNT=0;
    if(note==50) HT16CNT=0;  
    if(note==51) RD16CNT=0;
  }
}

ESP909.ino

Arduino
Error opening file.

rtpMIDI909.ino

Arduino
Error opening file.

Github

https://github.com/lathoub/Arduino-AppleMIDI-Library

Credits

Jan Ostman

Jan Ostman

34 projects • 104 followers
I'm an embeddeds wizard that can turn any pile of electronic junk to something really great. Mc Gyver style.

Comments