/* wavetable.cpp */
/*■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■*/
#include <NativeEthernetUdp.h>
#include <NativeEthernet.h>
#include <stdarg.h>
#include <string.h>
#include <limits.h>
#include <EEPROM.h>
#include <stdio.h>
#include <Wire.h>
#include <MIDI.h>
#include <SPI.h>
#include <SD.h>
#include "analyze_fft1024.h"
#include "wavetable.h"
#include "fileio.h"
#include "midi.h"
#include "mmi.h"
//#include "samples/pickedbs_samples.h"
//#include "samples/SynthBass1_samples.h"
//#include "samples/steelstrgtr_samples.h"
//#include "samples/honkytonk_samples.h"
//#include "samples/piano_samples.h"
#include "samples/JBRoomkit1_samples.h" // /home/mja/Desktop/SoundFonts/Drum & Percussion Soundfonts/198-JB KiT.sf2
#include "samples/pianoelectrique_samples.h"
#include "samples/accousticbs_samples.h"
#include "samples/Castanets_samples.h" // /home/mja/Desktop/SoundFonts/Ct4mgm.sf2
#include "samples/vibraphone_samples.h"
#include "samples/WoodBlock_samples.h" // /home/mja/Desktop/SoundFonts/Ct4mgm.sf2
//#pragma GCC optimize ("O0") // ABM - ZZZ - For Debugger
/*■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■*/
#define RX1 0
#define TX1 1
#define TOTAL_MIXERS (12)
#define DEFAULT_MIXER_VOLUME (80)
#define DEFAULT_SGTL5000_VOLUME (80)
#define DEFAULT_WAVETABLE_VOLUME (80)
#define BUFF_SZ (2048)
AudioAnalyzePeak mPeak[TOTAL_MIXERS];
HardwareSerial* mSerial;
AudioSynthWaveform waveform;
AudioControlSGTL5000 sgtl5000;
AudioOutputI2S i2s1;
AudioSynthWavetable wavetable[NUM_TABLE_VOICES];
AudioAnalyzeFFT1024 FFT1024;
AudioMixer4 mixer[TOTAL_MIXERS];
AudioEffectEnvelope envelope;
tsVoices Voices[NUM_TABLE_VOICES];
int8_t sd_card;
tsPresets Presets[NUM_TABLE_VOICES];
tsPresets Drum_Preset_35;
tsPresets Drum_Preset_36;
tsPresets Drum_Preset_40;
tsPresets Drum_Preset_47;
tsPresets Drum_Preset_48;
tsPresets Drum_Preset_52;
tsPresets Drum_Preset_59;
tsPresets Drum_Preset_72;
IntervalTimer OS_Timer;
static volatile bool Five_mS_Timer;
static volatile bool Startup;
static volatile bool LinkReady;
static volatile bool Run_FFT_StateMachine;
static volatile bool RunFFT;
static volatile bool Testing;
static uint32_t FFT_State;
static uint32_t SecondsCounter;
typedef enum
{
FFT_idle,
FFT_activate,
FFT_wait_ready,
FFT_send_2,
FFT_send_3,
FFT_send_4
} teFFTStates;
typedef union
{
uint8_t by[2];
int16_t sh;
} tuDest;
static tuDest Destination [BUFF_SZ];
static char buffer[128];
static bool visible;
/*■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■*/
uint8_t mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED};
IPAddress ip (192, 168, 0, 226);
IPAddress gateway(192, 168, 0, 1);
IPAddress subnet (255, 255, 255, 0);
unsigned int localPort = 8888; // local port to listen on
char packetBuffer[UDP_TX_PACKET_MAX_SIZE]; // buffer to hold incoming packet,
char ReplyBuffer[UDP_TX_PACKET_MAX_SIZE]; // a string to send back
EthernetUDP mUdp;
unsigned int UdpSendIndex;
/*■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■*/
void mProgramChange (byte channel, byte program);
void FreeVoices (void);
/*■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■*/
AudioConnection patchCord[] =
{
{wavetable[0], 0, mixer[0], 0}, {wavetable[1], 0, mixer[0], 1}, {wavetable[2], 0, mixer[0], 2}, {wavetable[3], 0, mixer[0], 3},
{wavetable[4], 0, mixer[1], 0}, {wavetable[5], 0, mixer[1], 1}, {wavetable[6], 0, mixer[1], 2}, {wavetable[7], 0, mixer[1], 3},
{wavetable[8], 0, mixer[2], 0}, {wavetable[9], 0, mixer[2], 1}, {wavetable[10], 0, mixer[2], 2}, {wavetable[11], 0, mixer[2], 3},
{wavetable[12], 0, mixer[3], 0}, {wavetable[13], 0, mixer[3], 1}, {wavetable[14], 0, mixer[3], 2}, {wavetable[15], 0, mixer[3], 3},
{wavetable[16], 0, mixer[4], 0}, {wavetable[17], 0, mixer[4], 1}, {wavetable[18], 0, mixer[4], 2}, {wavetable[19], 0, mixer[4], 3},
{wavetable[20], 0, mixer[5], 0}, {wavetable[21], 0, mixer[5], 1}, {wavetable[22], 0, mixer[5], 2}, {wavetable[23], 0, mixer[5], 3},
{wavetable[24], 0, mixer[6], 0}, {wavetable[25], 0, mixer[6], 1}, {wavetable[26], 0, mixer[6], 2}, {wavetable[27], 0, mixer[6], 3},
{wavetable[28], 0, mixer[7], 0}, {wavetable[29], 0, mixer[7], 1}, {wavetable[30], 0, mixer[7], 2}, {wavetable[31], 0, mixer[7], 3},
{mixer[0], 0, mixer[8], 0}, {mixer[4], 0, mixer[9], 0},
{mixer[1], 0, mixer[8], 1}, {mixer[5], 0, mixer[9], 1},
{mixer[2], 0, mixer[8], 2}, {mixer[6], 0, mixer[9], 2},
{mixer[3], 0, mixer[8], 3}, {mixer[7], 0, mixer[9], 3},
{mixer[8], 0, mixer[10], 0}, {mixer[8], 0, mixer[11], 1},
{mixer[9], 0, mixer[10], 1}, {mixer[9], 0, mixer[11], 2},
{mixer[10], 0, i2s1, 0}, {mixer[10], 0, mixer[11], 0},
{mixer[10], 0, i2s1, 1},
{waveform, 0, envelope, 0}, {waveform, 0, mixer[11], 3}, {waveform, 0, mixer[10], 2},
{envelope, 0, mixer[10], 3},
{mixer[11], FFT1024},
{mixer[0], 0, mPeak[0], 0}, {mixer[1], 0, mPeak[1], 0}, {mixer[2], 0, mPeak[2], 0}, {mixer[3], 0, mPeak[3], 0},
{mixer[4], 0, mPeak[4], 0}, {mixer[5], 0, mPeak[5], 0}, {mixer[6], 0, mPeak[6], 0}, {mixer[7], 0, mPeak[7], 0},
{mixer[8], 0, mPeak[8], 0}, {mixer[9], 0, mPeak[9], 0}, {mixer[10], 0, mPeak[10], 0}
};
/*■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■*/
void ShowPeaks(void)
{
uint32_t lp;
float_t res;
for (lp=0; lp<TOTAL_MIXERS; lp++)
{
if (mPeak[lp].available() == true)
{
res = mPeak[lp].readPeakToPeak();
mSerial->printf("peak-to-peak %02u = %f\n", lp, res);
}
else
{
mSerial->printf("peak-to-peak %02u = na\n", lp);
}
}
}
/*■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■*/
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
void mAfterTouchPoly(uint8_t channel, uint8_t note, uint8_t pressure){mSerial->printf("AfterTouchPolt\n");}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
void mControlChange(byte channel, byte control, byte value) {/*mSerial->printf("ControlChange: chan = %u, control = %u, value = %u\n", channel,control,value);*/}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
//void mProgramChange(byte channel, byte program){mSerial->printf("ProgramChange: chan = %u, program = %u\n", channel, program);}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
void mAfterTouch(byte channel, byte pressure){mSerial->printf("AfterTouch\n");}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
void mPitchChange(byte channel, int pitch){/*mSerial->printf("PitchChange: chan = %u, pitch = %u\n", channel,pitch);*/}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
void mSystemExclusiveChunk(const byte *data, uint16_t length, bool last){mSerial->printf("SystemExclusiveChunk\n");}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
void mSystemExclusive(byte *data, unsigned int length){mSerial->printf("SystemExclusive\n");}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
void mTimeCodeQuarterFrame(byte data){mSerial->printf("TimeCodeQuarterFrame\n");}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
void mSongPosition(uint16_t beats){mSerial->printf("SongPosition\n");}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
void mSongSelect(byte songNumber){mSerial->printf("SongSelect\n");}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
void mTuneRequest(){mSerial->printf("TuneRequest\n");}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
void mClock(){mSerial->printf("Clock\n");}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
void mStart(){mSerial->printf("Start\n");}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
void mContinue(){mSerial->printf("Continue\n");}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
void mStop(){ mSerial->printf("Stop\n");}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
void mActiveSensing(){mSerial->printf("ActiveSensing\n");}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
void mSystemReset(){mSerial->printf("SystemReset\n");}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
void mRealTimeSystem(byte realtimebyte){mSerial->printf("RealTimeSystem\n");}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
//void mNoteOff(uint8_t channel, uint8_t note, uint8_t velocity){mSerial->printf("NoteOff\n");}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
//void mNoteOn(uint8_t channel, uint8_t note, uint8_t velocity){mSerial->printf("NoteOn\n");}
/*■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■*/
void SetupMIDI(void)
{
usbMIDI.setHandleAfterTouchPoly(mAfterTouchPoly);
usbMIDI.setHandleControlChange(mControlChange);
usbMIDI.setHandleAfterTouch(mAfterTouch);
usbMIDI.setHandlePitchChange(mPitchChange);
usbMIDI.setHandleSystemExclusive(mSystemExclusiveChunk);
usbMIDI.setHandleTimeCodeQuarterFrame(mTimeCodeQuarterFrame);
usbMIDI.setHandleSongPosition(mSongPosition);
usbMIDI.setHandleSongSelect(mSongSelect);
usbMIDI.setHandleTuneRequest(mTuneRequest);
usbMIDI.setHandleClock(mClock);
usbMIDI.setHandleStart(mStart);
usbMIDI.setHandleContinue(mContinue);
usbMIDI.setHandleStop(mStop);
usbMIDI.setHandleActiveSensing(mActiveSensing);
usbMIDI.setHandleSystemReset(mSystemReset);
usbMIDI.setHandleRealTimeSystem(mRealTimeSystem);
usbMIDI.setHandleProgramChange(mProgramChange);
usbMIDI.setHandleNoteOff(midiNoteOff);
usbMIDI.setHandleNoteOn (midiNoteOn);
}
/*■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■*/
void PurrAndMeow(void)
{
mSerial->printf("PurrAndMeow\n");
//Ethernet.begin(mac, ip, gateway, gateway, subnet);
delay(200);
if (Ethernet.hardwareStatus() == EthernetNoHardware)
{
mSerial->printf("Ethernet hardware not found\n");
return;
}
if (Ethernet.linkStatus() == LinkOFF)
{
mSerial->printf("Ethernet cable is unplugged\n");
return;
}
delay(100);
mUdp.flush();
mUdp.stop();
delay(100);
mUdp.begin(localPort);
delay(100);
mUdp.begin(localPort);
delay(100);
mSerial->printf("\nEthernet initialised\n");
}
/*■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■*/
void InitEthernet(void)
{
Ethernet.begin(mac, ip, gateway, gateway, subnet);
delay(200);
if (Ethernet.hardwareStatus() == EthernetNoHardware)
{
mSerial->printf("Ethernet hardware not found\n");
return;
}
if (Ethernet.linkStatus() == LinkOFF)
{
mSerial->printf("Ethernet cable is unplugged\n");
return;
}
delay(100);
mUdp.flush();
mUdp.stop();
delay(100);
mUdp.begin(localPort);
delay(100);
mUdp.begin(localPort);
delay(100);
mSerial->printf("\nEthernet initialised\n");
}
/*■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■*/
void UDP_On(void)
{
mSerial->printf("Ready to Start\n");
PurrAndMeow();
}
/*■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■*/
void SetWavetableVolume(uint32_t v)
{
uint32_t lp;
float_t f;
f = (v * DIV127);
for(lp=0; lp<NUM_TABLE_VOICES; lp++)
{
wavetable[lp].amplitude(f);
}
}
/*■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■*/
void SetMixerVolume(uint32_t v)
{
uint32_t i, j;
float_t f;
f = (v * DIV127);
for (i = 0; i < TOTAL_MIXERS; i++)
{
for (j = 0; j < 4; j++)
{
mixer[i].gain(j, f);
}
}
}
/*■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■*/
void ChooseVisible (bool ch) // false = none, true = all];
{
visible = ch;
}
/*■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■*/
void PrintIfVisable(const char * format, ...)
{
if (visible == false)
{
return;
}
va_list args;
va_start (args, format);
vsprintf (buffer,format, args);
va_end (args);
mSerial->printf("%s", buffer);
}
/*■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■*/
void SetSGTLVolume(uint32_t v)
{
float_t f;
f = (v * DIV127);
sgtl5000.lineOutLevel(f);
}
/*■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■*/
void mProgramChange(byte chan, byte program)
{
//PrintFError("~~~ ProgramChange: chan = %u, program = %u ~~~\n", chan, program);
mSerial->printf("ProgramChange: chan = %u, program = %u\n", chan, program);
chan--; // Incoming MIDI channels go from 1 to 16
switch (program)
{
//case 0: Presets[chan].preset_ptr = &piano;Presets[chan].PatchID = 0;Presets[chan].name = "Grand Piano";break;
case 2:
Presets[chan].preset_ptr = &pianoelectrique;
Presets[chan].PatchID = 2;
Presets[chan].name = "Electric Piano";
break;
case 3:
Presets[chan].preset_ptr = &mja; // Ja, 'mja' is Mike's DMAMEM HonkyTonk
Presets[chan].PatchID = 3;
Presets[chan].name = "HonkyTonk";
break;
case 11:
Presets[chan].preset_ptr = &vibraphone;
Presets[chan].PatchID = 11;
Presets[chan].name = "Vibraphone";
break;
case 32:
Presets[chan].preset_ptr = &accousticbs;
Presets[chan].PatchID = 32;
Presets[chan].name = "Accoustic Bass";
break;
default: mSerial->printf("Invalid Program-Change: %u\n",program);
}
}
/*■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■*/
void ShowPresets(void)
{
uint32_t lp;
for(lp=0; lp<NUM_TABLE_VOICES; lp++)
{
if (Presets[lp].PatchID != 0xff)
{
mSerial->printf("Preset No. %u patch is %s\n", (lp+1), Presets[lp].name );
}
}
}
/*■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■*/
void Timex(void)
{
Five_mS_Timer = true;
}
/*■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■*/
void SendUDP(void)
{
#define BUFFER_SIZE (2048)
uint8_t mbuffer[BUFFER_SIZE];
uint32_t lp;
if (LinkReady == false)
{
mSerial->printf("Link not ready - Rx a packet first\n");
}
for (lp=0; lp<BUFFER_SIZE; lp++)
{
mbuffer[lp] = lp;
}
mUdp.beginPacket(mUdp.remoteIP(), mUdp.remotePort());
mUdp.write(mbuffer, BUFFER_SIZE);
mUdp.endPacket();
}
/*■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■*/
void HandleUDP(void)
{
int32_t res;
if (mUdp.parsePacket())
{
mUdp.read(packetBuffer, UDP_TX_PACKET_MAX_SIZE);
LinkReady = true;
res = strncmp(packetBuffer, "GFT", 3);
mSerial->printf("buff = %c%c%c, res = %d\n", packetBuffer[0], packetBuffer[1], packetBuffer[2], res);
if (res == 0)
{
// Do_Some_Meaningful_Work_Pretty-Please_With_Catnip_and_Kitty_treats();
}
}
}
/*■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■*/
void ChooseConfig(bool ch) // true = normal, false = test
{
if (ch == true)
{
Testing = false;
mSerial->printf("Mode: run\n");
waveform.amplitude(0.0);
mixer[10].gain(0, (DEFAULT_MIXER_VOLUME * DIV127));
mixer[10].gain(1, (DEFAULT_MIXER_VOLUME * DIV127));
mixer[10].gain(2, 0.0);
mixer[10].gain(3, 0.0);
mixer[11].gain(0, 0.8);
mixer[11].gain(1, 0.0);
mixer[11].gain(2, 0.0);
mixer[11].gain(3, 0.0);
}
else
{
Testing = true;
mSerial->printf("Mode: test\n");
waveform.amplitude(0.8);
waveform.frequency(440);
waveform.begin(WAVEFORM_SINE);
mixer[10].gain(0, 0.0);
mixer[10].gain(1, 0.0);
mixer[10].gain(2, 0.8);
mixer[10].gain(3, 0.8);
mixer[11].gain(0, 0.0);
mixer[11].gain(1, 0.0);
mixer[11].gain(2, 0.0);
mixer[11].gain(3, 0.8);
}
}
/*■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■*/
void setup(void)
{
pinMode(RX1,INPUT_PULLUP);
pinMode(TX1,INPUT_PULLUP);
AudioMemory(120);
sgtl5000.enable();
// sgtl5000.muteHeadphone();
sgtl5000.volume(0.6); // Headphone
sgtl5000.unmuteLineout();
mSerial = &Serial1;
mSerial->begin(57600);
while(!mSerial);
visible = false;
SetSGTLVolume(DEFAULT_SGTL5000_VOLUME);
SetMixerVolume(DEFAULT_MIXER_VOLUME);
SetWavetableVolume(DEFAULT_WAVETABLE_VOLUME);
// InitEthernet();
SetupMIDI();
ResetMMI();
MIDIinit(); // Does nothing, for now
FreeVoices();
LinkReady = false;
sd_card = 0;
sd_card = check_sd_card();
if (sd_card < 1)
{
mSerial->printf(F("SD Card Error\n"));
}
loadVoice(); // Operates on 'mja', which is Mike's DMAMEM HonkyTonk
for (UdpSendIndex=0; UdpSendIndex<UDP_TX_PACKET_MAX_SIZE; UdpSendIndex++)
{
ReplyBuffer[UdpSendIndex] = 0;
}
ChooseConfig(true); // true = normal, false = test
UdpSendIndex = 0;
OS_Timer.begin(Timex, 5000);
Five_mS_Timer = false;
Run_FFT_StateMachine = false;
RunFFT = false;
FFT_State = FFT_idle;
SecondsCounter = 0;
Startup = true;
mSerial->printf(F("<Initialisation Complete>\n"));
Version();
}
/*■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■*/
/*■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■*/
void TriggerFFT(void)
{
RunFFT = true;
}
/*■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■*/
void FFT_StateMachine_Test(void)
{
static uint32_t lp;
static int16_t* src;
static uint8_t* ptr;
switch (FFT_State)
{
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
case FFT_idle:
if (RunFFT == false)
{
return;
}
FFT1024.startAcquisation();
RunFFT = false;
FFT_State = FFT_wait_ready;
break;
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
case FFT_activate:
if (SecondsCounter > 200)
{
SecondsCounter = 0;
FFT1024.startAcquisation();
FFT_State = FFT_wait_ready;
}
break;
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
case FFT_wait_ready:
if (FFT1024.available() == true)
{
src = FFT1024.readBufferAddress();
for (lp=0; lp<BUFF_SZ; lp++)
{
Destination[lp].sh = *src;
src++;
}
ptr = &Destination[0].by[0];
mUdp.beginPacket(mUdp.remoteIP(), mUdp.remotePort());
mUdp.write(ptr, 1024);
mUdp.endPacket();
FFT_State = FFT_send_2;
}
break;
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
case FFT_send_2:
ptr = &Destination[512].by[0];
mUdp.beginPacket(mUdp.remoteIP(), mUdp.remotePort());
mUdp.write(ptr, 1024);
mUdp.endPacket();
FFT_State = FFT_send_3;
break;
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
case FFT_send_3:
ptr = &Destination[1024].by[0];
mUdp.beginPacket(mUdp.remoteIP(), mUdp.remotePort());
mUdp.write(ptr, 1024);
mUdp.endPacket();
FFT_State = FFT_send_4;
break;
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
case FFT_send_4:
ptr = &Destination[1536].by[0];
mUdp.beginPacket(mUdp.remoteIP(), mUdp.remotePort());
mUdp.write(ptr, 1024);
mUdp.endPacket();
FFT_State = FFT_idle;
break;
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
}
}
#ifdef mike
void FFT_StateMachine_Test(void)
{
static uint32_t lp;
static int16_t* src;
static uint8_t* ptr;
uint16_t sz;
switch (FFT_State)
{
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
case FFT_idle:
if (RunFFT == false)
{
return;
}
FFT1024.startAcquisation();
RunFFT = false;
FFT_State = FFT_wait_ready;
break;
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
case FFT_activate:
if (SecondsCounter > 200)
{
SecondsCounter = 0;
FFT1024.startAcquisation();
FFT_State = FFT_wait_ready;
}
break;
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
case FFT_wait_ready:
if (FFT1024.available() == true)
{
sz = FFT1024.getsize();
mSerial->printf("sz = %u\n", sz);
src = FFT1024.readBufferAddress();
for (lp=0; lp<BUFF_SZ; lp++)
{
Destination[lp].sh = *src;
src++;
}
FFT_State = FFT_send;
}
break;
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
case FFT_send:
ptr = &Destination[0].by[0];
mUdp.beginPacket(mUdp.remoteIP(), mUdp.remotePort());
mUdp.write(ptr, (BUFF_SZ * 2));
mUdp.endPacket();
FFT_State = FFT_idle;
break;
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
}
}
#endif // of #ifdef mike
/*■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■*/
#ifdef mike
void loop(void)
{
uint8_t ch;
uint32_t lp;
float_t res;
int32_t sz;
if (Startup == true)
{
mSerial->printf(F("<ready>\n>"));
Startup = false;
}
usbMIDI.read();
HandleUDP();
if (mSerial->available() > 0)
{
ch = mSerial->read();
ServiceRx(ch);
}
if (Five_mS_Timer == true)
{
Five_mS_Timer = false;
SecondsCounter++;
if (Run_FFT_StateMachine == true)
{
//FFT_StateMachine();
FFT_StateMachine_Test();
Run_FFT_StateMachine = false;
}
else
{
Run_FFT_StateMachine = true;
for(lp=0; lp<NUM_TABLE_VOICES; lp++)
{
if (Voices[lp].release == true)
{
if (--Voices[lp].timer == 0)
{
Voices[lp].release = false;
Voices[lp].playing = false;
}
}
}
if (LinkReady == true)
{
if (mPeak[UdpSendIndex].available() == true)
{
res = mPeak[UdpSendIndex].readPeakToPeak();
sz = sprintf(ReplyBuffer, "%03u %0.4f", UdpSendIndex, res);
mUdp.beginPacket(mUdp.remoteIP(), mUdp.remotePort());
mUdp.write(ReplyBuffer, sz);
mUdp.endPacket();
}
UdpSendIndex++;
if (UdpSendIndex >= TOTAL_MIXERS)
{
UdpSendIndex = 0;
}
}
}
}
}
#endif // of #ifdef mike
void loop(void)
{
uint8_t ch;
// uint32_t lp;
// float_t res;
// int32_t sz;
if (Startup == true)
{
mSerial->printf(F("<ready>\n>"));
Startup = false;
}
usbMIDI.read();
//HandleUDP();
if (mSerial->available() > 0)
{
ch = mSerial->read();
ServiceRx(ch);
}
/*
if (Five_mS_Timer == true)
{
Five_mS_Timer = false;
SecondsCounter++;
if (Run_FFT_StateMachine == true)
{
FFT_StateMachine_Test();
Run_FFT_StateMachine = false;
}
else
{
Run_FFT_StateMachine = true;
for(lp=0; lp<NUM_TABLE_VOICES; lp++)
{
if (Voices[lp].release == true)
{
if (--Voices[lp].timer == 0)
{
Voices[lp].release = false;
Voices[lp].playing = false;
}
}
}
if (LinkReady == true)
{
if (Testing == false)
{
if (mPeak[UdpSendIndex].available() == true)
{
res = mPeak[UdpSendIndex].readPeakToPeak();
sz = sprintf(ReplyBuffer, "%03u %0.4f", UdpSendIndex, res);
mUdp.beginPacket(mUdp.remoteIP(), mUdp.remotePort());
mUdp.write(ReplyBuffer, sz);
mUdp.endPacket();
}
UdpSendIndex++;
if (UdpSendIndex >= TOTAL_MIXERS)
{
UdpSendIndex = 0;
}
}
}
}
}
*/
}
/*■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■*/
void CheckBusyVoices(void)
{
uint32_t lp, num;
num = 0;
for(lp=0; lp<NUM_TABLE_VOICES; lp++)
{
if (Voices[lp].playing == true)
{
num++;
}
}
mSerial->printf("Busy voices = %u\n", num);
}
/*■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■*/
void FreeVoices(void)
{
uint32_t lp;
for(lp=0; lp<NUM_TABLE_VOICES; lp++)
{
Voices[lp].wavetable_ptr = &wavetable[lp];
Voices[lp].playing = false;
Voices[lp].release = false;
Voices[lp].note = 0xff;
Voices[lp].chan = 0xff;
Voices[lp].release = false;
Presets[lp].preset_ptr = &mja; // Ja, mja is Mike's DMAMEM HonkyTonk
Presets[lp].PatchID = 0xff;
Presets[lp].IsItDrum = false;
}
Drum_Preset_35.preset_ptr = &WoodBlock;
Drum_Preset_36.preset_ptr = &JBRoomkit1;
Drum_Preset_40.preset_ptr = &JBRoomkit1;
Drum_Preset_47.preset_ptr = &JBRoomkit1;
Drum_Preset_48.preset_ptr = &Castanets;
Drum_Preset_52.preset_ptr = &JBRoomkit1;
Drum_Preset_59.preset_ptr = &JBRoomkit1;
Drum_Preset_35.DrumNote = 35; // woodblock B3
Drum_Preset_36.DrumNote = 36; // kick1 C3
Drum_Preset_40.DrumNote = 40; // kick5 E3
Drum_Preset_47.DrumNote = 47; // sda4 B3
Drum_Preset_48.DrumNote = 48; // cstnr C4
Drum_Preset_52.DrumNote = 52; // roll1 E4
Drum_Preset_59.DrumNote = 59; // hh2 B4
Drum_Preset_35.Velocity = 120;
Drum_Preset_36.Velocity = 120;
Drum_Preset_40.Velocity = 120;
Drum_Preset_47.Velocity = 120;
Drum_Preset_48.Velocity = 120;
Drum_Preset_52.Velocity = 120;
Drum_Preset_59.Velocity = 120;
//Drum_Preset_72.Velocity = 120;
Drum_Preset_35.IsItDrum = true;
Drum_Preset_36.IsItDrum = true;
Drum_Preset_40.IsItDrum = true;
Drum_Preset_47.IsItDrum = true;
Drum_Preset_48.IsItDrum = true;
Drum_Preset_52.IsItDrum = true;
Drum_Preset_59.IsItDrum = true;
//Drum_Preset_72.IsItDrum = true;
}
/*■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■*/
// void *memcpy(void *dest, const void * src, size_t n)
// memcpy(dest, src, strlen(src)+1);
// #define sz (262144) // 2^18 = Max. DMAMEM - Used by mja structure -
// See 'fileio.cpp'
/*■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■*/