Skip to content

Commit

Permalink
a bit of de-clicking, BOOT button cycles dirs
Browse files Browse the repository at this point in the history
Started ADSR modification; added buttons.ino; voice assignment score calculations improvement; basic velocity; float type is implicitly forced where auto-promotion to double type can occur.
  • Loading branch information
copych authored Mar 31, 2024
1 parent 2ec7f28 commit e8786aa
Show file tree
Hide file tree
Showing 10 changed files with 543 additions and 346 deletions.
147 changes: 42 additions & 105 deletions ESP32_SD_Sampler/ESP32_SD_sampler.ino
Original file line number Diff line number Diff line change
Expand Up @@ -15,24 +15,15 @@ CRGB leds[1];
//SET_LOOP_TASK_STACK_SIZE(80000);

// =============================================================== MIDI interfaces ===============================================================

#ifdef MIDI_VIA_SERIAL
/*
// default settings for Hairless midi is 115200 8-N-1
struct CustomBaudRateSettings : public MIDI_NAMESPACE::DefaultSerialSettings {
static const long BaudRate = 115200;
};
struct SerialMIDISettings : public MIDI_NAMESPACE::DefaultSettings {
static const long BaudRate = 115200;
static const bool Use1ByteParsing = false;
};
MIDI_NAMESPACE::SerialMIDI<HardwareSerial, CustomBaudRateSettings> serialMIDI(Serial);
MIDI_NAMESPACE::MidiInterface<MIDI_NAMESPACE::SerialMIDI<HardwareSerial, SerialMIDISettings>> MIDI((MIDI_NAMESPACE::SerialMIDI<HardwareSerial, SerialMIDISettings>&)serialMIDI);
*/
struct CustomBaudRate : public midi::DefaultSettings{
static const long BaudRate = 115200;
static const bool Use1ByteParsing = false;

struct CustomBaudRateSettings : public MIDI_NAMESPACE::DefaultSettings {
static const long BaudRate = 115200;
static const bool Use1ByteParsing = false;
};
MIDI_CREATE_CUSTOM_INSTANCE(HardwareSerial, Serial0, MIDI, CustomBaudRate);
MIDI_NAMESPACE::SerialMIDI<HardwareSerial, CustomBaudRateSettings> serialMIDI(Serial);
MIDI_NAMESPACE::MidiInterface<MIDI_NAMESPACE::SerialMIDI<HardwareSerial, CustomBaudRateSettings>> MIDI((MIDI_NAMESPACE::SerialMIDI<HardwareSerial, CustomBaudRateSettings>&)serialMIDI);

#endif

Expand Down Expand Up @@ -126,60 +117,64 @@ static void IRAM_ATTR audio_task(void *userData) { // core 0 task
static void control_task(void *userData) { // core 1 task
vTaskDelay(10);
DEBUG ("core 1 control task run");
static int passby = 0;
while (true) {
Sampler.fillBuffer();
static uint32_t passby = 0;
while (true) {
/*
if (timer2_fired) {
timer2_fired = false;
timeClick();
}
*/
/*
if (passby >> 8 == 1) {
passby=0;
}
passby++;
*/
Sampler.fillBuffer();

#ifdef MIDI_VIA_SERIAL
MIDI.read();

#endif

#ifdef MIDI_VIA_SERIAL2
MIDI2.read();
#ifdef RGB_LED
if (passby >> 12 == 1) {
passby=0;
leds[0].setHue(random(255));
FastLED.show();
}
#endif
#endif
passby++;

processButtons();
}
}

// =============================================================== SETUP() ===============================================================
void setup() {

#ifdef DEBUG_ON
Serial.begin(115200);
#endif

#ifdef DEBUG_ON
Serial.begin(115200);
#endif

DEBUG("CARD: BEGIN()");
DEBUG("CARD: BEGIN");
Card.begin();
delay(1000);
delay(100);
#ifdef RGB_LED
FastLED.addLeds<WS2812, RGB_LED, GRB>(leds, 1);
FastLED.setBrightness(1);
#endif
//Card.testReadSpeed(READ_BUF_SECTORS,8);
DEBUG("REVERB: INIT()");
DEBUG("REVERB: INIT");
Reverb.Init();
MidiInit(); // init midi input and handling of midi events

DEBUG("MIDI: INIT");
MidiInit();

DEBUG("SAMPLER: INIT()");
DEBUG("SAMPLER: INIT");
Sampler.init(&Card);
Sampler.setCurrentFolder(1);
Sampler.setCurrentFolder(2);

DEBUG("I2S: INIT");
i2sInit();

initButtons();

xTaskCreatePinnedToCore( audio_task, "SynthTask", 6000, NULL, 25, &SynthTask, 0 );

xTaskCreatePinnedToCore( control_task, "ControlTask", 4000, NULL, 8, &ControlTask, 1 );
Expand All @@ -198,85 +193,27 @@ DEBUG("I2S: INIT");
timerAlarmEnable(timer2);
DEBUG ("Timer(s) started");
*/
#ifdef C_MAJOR_ON_START
delay(100);
Sampler.noteOn(60,100);
Sampler.noteOn(64,100);
Sampler.noteOn(67,100);
delay(1000);
Sampler.noteOff(60, false);
Sampler.noteOff(64, false);
Sampler.noteOff(67, false);
#endif
DEBUG ("Setup() DONE");
heap_caps_print_heap_info(MALLOC_CAP_8BIT);
}


void loop() {
//timeClick();
//delay(1);

#ifdef RGB_LED
leds[0].setHue(1); //green
FastLED.setBrightness(1);
FastLED.show();
#endif
vTaskDelete(NULL);
}

/*
void timeClick() {
DEBF("MAIN: Active voices: %d of %d\r\n", Sampler.getActiveVoices(), MAX_POLYPHONY);
static int state = 0;
static bool OnOff = true;
state ++;
switch (state) {
case 0:
OnOff = false;
break;
case 1:
OnOff = true;
break;
case 2:
OnOff = false;
state = -1; // becomes 0 next time
break;
}
const int noteMin = 40 ;
const int noteMax = 80 ;
const int notePoly = MAX_POLYPHONY;
const int veloMin = 10;
const int veloMax = 127;
static int veloStep = 7;
static int iNoteOn = noteMin;
static int iNoteOff = noteMin;
static int velo = veloMin;
if (iNoteOn < noteMin) iNoteOn = (noteMax - noteMin + 1) + iNoteOn;
if (iNoteOn > noteMax) iNoteOn = iNoteOn - (noteMax - noteMin + 1);
iNoteOff = iNoteOn - notePoly;
if (iNoteOff < noteMin) iNoteOff = (noteMax - noteMin + 1) + iNoteOff;
if (iNoteOff > noteMax) iNoteOff = iNoteOff - (noteMax - noteMin + 1);
taskYIELD();
Sampler.noteOn((uint8_t)iNoteOn, (uint8_t)velo);
Sampler.noteOff((uint8_t)iNoteOff, false);
if (OnOff) {
#ifdef RGB_LED
leds[0].setHue(random(255));
FastLED.setBrightness(1);
FastLED.show();
#endif
} else {
#ifdef RGB_LED
FastLED.setBrightness(0);
FastLED.show();
#endif
}
//DEBF("Note on %d @ %d , off %d\r\n", iNoteOn , velo , iNoteOff);
velo += veloStep;
if (velo > veloMax) {
velo = veloMax;
veloStep = -veloStep;
}
if (velo < veloMin) {
velo = veloMin;
veloStep = -veloStep;
}
iNoteOn++;
}
*/
37 changes: 23 additions & 14 deletions ESP32_SD_Sampler/adsr.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@

// note that ADSR_SEG_SUSTAIN value is not used in this implementation and the GetCurrentSegment() will return ADSR_SEG_DECAY eventhough ADSR_SEG_SUSTAIN would be correct
// if you need it
enum { ADSR_SEG_IDLE, ADSR_SEG_ATTACK, ADSR_SEG_DECAY, ADSR_SEG_SUSTAIN, ADSR_SEG_RELEASE };

/** adsr envelope module
Original author(s) : Paul Batchelor
Expand All @@ -18,50 +17,54 @@ Remake by Steffan DIedrichsen, May 2021
Modified by Copych, Jan 2024
*/


class Adsr
{
public:
enum eSegment_t { ADSR_SEG_IDLE, ADSR_SEG_ATTACK, ADSR_SEG_DECAY, ADSR_SEG_SUSTAIN, ADSR_SEG_RELEASE, ADSR_SEG_HARD_RELEASE };
enum eEnd_t { END_REGULAR, END_FAST, END_NOW };
Adsr() {}
~Adsr() {}

/** Initializes the Adsr module.
\param sample_rate - The sample rate of the audio engine being run.
*/
void Init(float sample_rate, int blockSize = 1);
void init(float sample_rate, int blockSize = 1);

/**
\function Retrigger forces the envelope back to attack phase
\param hard resets the history to zero, results in a click.
*/
void Retrigger(bool hard);
void retrigger(eEnd_t hardness);

/**
\function End forces the envelope to idle phase
\param hard resets the history to zero, results in a click.
*/
void End(bool hard);
void end(eEnd_t hardness);

/** Processes one sample through the filter and returns one sample.
*/
float Process();
float process();


/** Sets time
Set time per segment in seconds
*/
void SetTime(int seg, float time);
void SetAttackTime(float timeInS, float shape = 0.0f);
void SetDecayTime(float timeInS);
void SetReleaseTime(float timeInS);
void setTime(int seg, float time);
void setAttackTime(float timeInS, float shape = 0.0f);
void setDecayTime(float timeInS);
void setReleaseTime(float timeInS);
void setHardReleaseTime(float timeInS);

private:
void SetTimeConstant(float timeInS, float& time, float& coeff);
void setTimeConstant(float timeInS, float& time, float& coeff);

public:
/** Sustain level
\param sus_level - sets sustain level, 0...1.0
*/
inline void SetSustainLevel(float sus_level)
inline void setSustainLevel(float sus_level)
{
sus_level = (sus_level <= 0.f) ? -0.001f // forces envelope into idle
: (sus_level > 1.f) ? 1.f : sus_level;
Expand All @@ -70,11 +73,15 @@ class Adsr
/** get the current envelope segment
\return the segment of the envelope that the phase is currently located in.
*/
inline uint8_t GetCurrentSegment() ;
inline eSegment_t getCurrentSegment() ;
/** Tells whether envelope is active
\return true if the envelope is currently in any stage apart from idle.
*/
inline bool isRunning() const { return mode_ != ADSR_SEG_IDLE; }
/** Tells whether envelope is active
\return true if the envelope is currently in any stage apart from idle.
*/
inline bool IsRunning() const { return mode_ != ADSR_SEG_IDLE; }
inline bool isIdle() const { return mode_ == ADSR_SEG_IDLE; }

private:
float sus_level_{0.f};
Expand All @@ -86,10 +93,12 @@ class Adsr
float attackTime_{-1.0f};
float decayTime_{-1.0f};
float releaseTime_{-1.0f};
float hardReleaseTime_{-1.0f};
float attackD0_{0.f};
float decayD0_{0.f};
float releaseD0_{0.f};
float hardReleaseD0_{0.f};
int sample_rate_;
uint8_t mode_{ADSR_SEG_IDLE};
eSegment_t mode_{ADSR_SEG_IDLE};
bool gate_{false};
};
Loading

0 comments on commit e8786aa

Please sign in to comment.