Skip to content

Commit

Permalink
Delay: Add param saving
Browse files Browse the repository at this point in the history
  • Loading branch information
qiemem committed Jul 25, 2024
1 parent c2d7083 commit b57f9b7
Show file tree
Hide file tree
Showing 3 changed files with 146 additions and 104 deletions.
197 changes: 108 additions & 89 deletions software/src/HSUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@ typedef int32_t simfloat;

// Hemisphere-specific macros
#define BottomAlign(h) (62 - h)
#define ForEachChannel(ch) for(int_fast8_t ch = 0; ch < 2; ++ch)
#define ForAllChannels(ch) for(int_fast8_t ch = 0; ch < 4; ++ch)
#define ForEachChannel(ch) for (int_fast8_t ch = 0; ch < 2; ++ch)
#define ForAllChannels(ch) for (int_fast8_t ch = 0; ch < 4; ++ch)
#define gfx_offset ((hemisphere % 2) * 64) // Graphics offset, based on the side
#define io_offset (hemisphere * 2) // Input/Output offset, based on the side

Expand Down Expand Up @@ -72,9 +72,9 @@ enum HELP_SECTIONS {

// aliases to ease refactoring
HEMISPHERE_HELP_DIGITALS = HELP_DIGITAL1,
HEMISPHERE_HELP_CVS = HELP_CV1,
HEMISPHERE_HELP_OUTS = HELP_OUT1,
HEMISPHERE_HELP_ENCODER = HELP_EXTRA1,
HEMISPHERE_HELP_CVS = HELP_CV1,
HEMISPHERE_HELP_OUTS = HELP_OUT1,
HEMISPHERE_HELP_ENCODER = HELP_EXTRA1,
};

static constexpr uint32_t HEMISPHERE_SIM_CLICK_TIME = 1000;
Expand All @@ -94,16 +94,18 @@ static constexpr uint32_t HEMISPHERE_PULSE_ANIMATION_TIME_LONG = 1200;
* ----------- = -----------
* denominator max
*
* For example, to convert a parameter with a range of 1 to 100 into value scaled
* to HEMISPHERE_MAX_CV, to be sent to the DAC:
* For example, to convert a parameter with a range of 1 to 100 into value
* scaled to HEMISPHERE_MAX_CV, to be sent to the DAC:
*
* Out(ch, Proportion(value, 100, HEMISPHERE_MAX_CV));
*
*/
constexpr int Proportion(const int numerator, const int denominator, const int max_value) {
simfloat proportion = int2simfloat((int32_t)abs(numerator)) / (int32_t)denominator;
int scaled = simfloat2int(proportion * max_value);
return numerator >= 0 ? scaled : -scaled;
constexpr int Proportion(const int numerator, const int denominator,
const int max_value) {
simfloat proportion =
int2simfloat((int32_t)abs(numerator)) / (int32_t)denominator;
int scaled = simfloat2int(proportion * max_value);
return numerator >= 0 ? scaled : -scaled;
}

/* Proportion CV values into pixels for display purposes.
Expand All @@ -113,31 +115,45 @@ constexpr int Proportion(const int numerator, const int denominator, const int m
* HEMISPHERE_MAX_CV max_pixels
*/
constexpr int ProportionCV(const int cv_value, const int max_pixels) {
// TODO: variable scaling for VOR?
int prop = constrain(Proportion(cv_value, HEMISPHERE_MAX_INPUT_CV, max_pixels), -max_pixels, max_pixels);
return prop;
// TODO: variable scaling for VOR?
int prop =
constrain(Proportion(cv_value, HEMISPHERE_MAX_INPUT_CV, max_pixels),
-max_pixels, max_pixels);
return prop;
}


// Specifies where data goes in flash storage for each selcted applet, and how big it is
// Specifies where data goes in flash storage for each selcted applet, and how
// big it is
typedef struct PackLocation {
size_t location;
size_t size;
size_t location;
size_t size;
} PackLocation;

union FloatBitsPun {
float f;
uint32_t u;
};

// For easy reference: leading bit is sign, then 8 bits for exponent, then 23
// bits for fraction
constexpr uint32_t FloatToBits(float x) { return FloatBitsPun{.f = x}.u; }
constexpr float BitsToFloat(uint32_t n) { return FloatBitsPun{.u = n}.f; }

/* Add value to a 64-bit storage unit at the specified location */
constexpr void Pack(uint64_t &data, const PackLocation p, const uint64_t value) {
data |= (value << p.location);
constexpr void Pack(uint64_t &data, const PackLocation p,
const uint64_t value) {
data |= (value << p.location);
}

/* Retrieve value from a 64-bit storage unit at the specified location and of the specified bit size */
/* Retrieve value from a 64-bit storage unit at the specified location and of
* the specified bit size */
constexpr int Unpack(const uint64_t &data, const PackLocation p) {
uint64_t mask = 1;
for (size_t i = 1; i < p.size; i++) mask |= (0x01 << i);
return (data >> p.location) & mask;
uint64_t mask = 1;
for (size_t i = 1; i < p.size; i++)
mask |= (0x01 << i);
return (data >> p.location) & mask;
}


void gfxPos(int x, int y);
void gfxPrint(int x, int y, const char *str);
void gfxPrint(int x, int y, int num);
Expand All @@ -157,72 +173,75 @@ void gfxIcon(int x, int y, const uint8_t *data);
void gfxHeader(const char *str);

static constexpr uint8_t pad(int range, int number) {
uint8_t padding = 0;
while (range > 1)
{
if (abs(number) < range) padding += 6;
range = range / 10;
}
if (number < 0 && padding > 0) padding -= 6; // Compensate for minus sign
return padding;
uint8_t padding = 0;
while (range > 1) {
if (abs(number) < range)
padding += 6;
range = range / 10;
}
if (number < 0 && padding > 0)
padding -= 6; // Compensate for minus sign
return padding;
}


namespace HS {
enum PopupType {
MENU_POPUP,
CLOCK_POPUP, PRESET_POPUP,
QUANTIZER_POPUP,
};

enum QUANT_CHANNEL {
QUANT_CHANNEL_1,
QUANT_CHANNEL_2,
QUANT_CHANNEL_3,
QUANT_CHANNEL_4,
QUANT_CHANNEL_5,
QUANT_CHANNEL_6,
QUANT_CHANNEL_7,
QUANT_CHANNEL_8,

QUANT_CHANNEL_COUNT
};

extern uint32_t popup_tick; // for button feedback
extern PopupType popup_type;
extern uint8_t qview; // which quantizer's setting is shown in popup
extern bool q_edit;

extern braids::Quantizer quantizer[QUANT_CHANNEL_COUNT]; // global shared quantizers
extern int quant_scale[QUANT_CHANNEL_COUNT];
extern int8_t root_note[QUANT_CHANNEL_COUNT];
extern int8_t q_octave[QUANT_CHANNEL_COUNT];

extern int octave_max;

extern int select_mode;
extern bool cursor_wrap;

extern bool auto_save_enabled;
extern int trigger_mapping[ADC_CHANNEL_LAST];
extern int cvmapping[ADC_CHANNEL_LAST];
extern uint8_t trig_length;
extern uint8_t screensaver_mode;

// --- Quantizer helpers
int GetLatestNoteNumber(int ch);
int Quantize(int ch, int cv, int root = 0, int transpose = 0);
int QuantizerLookup(int ch, int note);
void QuantizerConfigure(int ch, int scale, uint16_t mask = 0xffff);
int GetScale(int ch);
int GetRootNote(int ch);
int SetRootNote(int ch, int root);
void NudgeRootNote(int ch, int dir);
void NudgeOctave(int ch, int dir);
void NudgeScale(int ch, int dir);
void QuantizerEdit(int ch);
void DrawPopup(const int config_cursor = 0, const int preset_id = 0, const bool blink = 0);
void ToggleClockRun();
void PokePopup(PopupType pop);
enum PopupType {
MENU_POPUP,
CLOCK_POPUP,
PRESET_POPUP,
QUANTIZER_POPUP,
};

enum QUANT_CHANNEL {
QUANT_CHANNEL_1,
QUANT_CHANNEL_2,
QUANT_CHANNEL_3,
QUANT_CHANNEL_4,
QUANT_CHANNEL_5,
QUANT_CHANNEL_6,
QUANT_CHANNEL_7,
QUANT_CHANNEL_8,

QUANT_CHANNEL_COUNT
};

extern uint32_t popup_tick; // for button feedback
extern PopupType popup_type;
extern uint8_t qview; // which quantizer's setting is shown in popup
extern bool q_edit;

extern braids::Quantizer
quantizer[QUANT_CHANNEL_COUNT]; // global shared quantizers
extern int quant_scale[QUANT_CHANNEL_COUNT];
extern int8_t root_note[QUANT_CHANNEL_COUNT];
extern int8_t q_octave[QUANT_CHANNEL_COUNT];

extern int octave_max;

extern int select_mode;
extern bool cursor_wrap;

extern bool auto_save_enabled;
extern int trigger_mapping[ADC_CHANNEL_LAST];
extern int cvmapping[ADC_CHANNEL_LAST];
extern uint8_t trig_length;
extern uint8_t screensaver_mode;

// --- Quantizer helpers
int GetLatestNoteNumber(int ch);
int Quantize(int ch, int cv, int root = 0, int transpose = 0);
int QuantizerLookup(int ch, int note);
void QuantizerConfigure(int ch, int scale, uint16_t mask = 0xffff);
int GetScale(int ch);
int GetRootNote(int ch);
int SetRootNote(int ch, int root);
void NudgeRootNote(int ch, int dir);
void NudgeOctave(int ch, int dir);
void NudgeScale(int ch, int dir);
void QuantizerEdit(int ch);
void DrawPopup(const int config_cursor = 0, const int preset_id = 0,
const bool blink = 0);
void ToggleClockRun();
void PokePopup(PopupType pop);

} // namespace HS
47 changes: 34 additions & 13 deletions software/src/applets/Delay.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,11 @@ class Delay : public HemisphereAudioApplet<Mono> {
taps_mixer2.gain(i, j < taps ? 1.0f : 0.0f);
}

float w = wet + InF(1);
float w = 0.01f * wet + InF(1);
CONSTRAIN(w, 0.0f, 1.0f);
feedback_mixer.gain(FB_WET_CH_1, feedback / taps);
feedback_mixer.gain(FB_WET_CH_2, feedback / taps);
float f = 0.01f * feedback / taps;
feedback_mixer.gain(FB_WET_CH_1, f);
feedback_mixer.gain(FB_WET_CH_2, f);
wet_dry_mixer.gain(WD_WET_CH_1, w);
wet_dry_mixer.gain(WD_WET_CH_2, w);
wet_dry_mixer.gain(WD_DRY_CH, 1.0f - w);
Expand All @@ -42,12 +43,12 @@ class Delay : public HemisphereAudioApplet<Mono> {
if (cursor == TIME)
gfxCursor(0, 23, 6 * 7);
gfxPrint(0, 25, "FB: ");
gfxPrint(100 * feedback, 0);
gfxPrint(feedback);
gfxPrint("%");
if (cursor == FEEDBACK)
gfxCursor(0, 32, 6 * 8);
gfxPrint(0, 35, "Wet: ");
gfxPrint(100 * wet, 0);
gfxPrint(wet);
gfxPrint("%");
if (cursor == WET)
gfxCursor(0, 42, 6 * 9);
Expand All @@ -69,12 +70,12 @@ class Delay : public HemisphereAudioApplet<Mono> {
CONSTRAIN(delaySecs, 0.0f, MAX_DELAY_SECS);
break;
case FEEDBACK:
feedback += 0.01f * direction;
CONSTRAIN(feedback, 0.0f, 1.0f);
feedback += direction;
CONSTRAIN(feedback, 0, 100);
break;
case WET:
wet += 0.01f * direction;
CONSTRAIN(wet, 0.0f, 1.0f);
CONSTRAIN(wet, 0, 100);
break;
case TAPS:
taps += direction;
Expand All @@ -83,8 +84,24 @@ class Delay : public HemisphereAudioApplet<Mono> {
break;
}
}
uint64_t OnDataRequest() { return 0; }
void OnDataReceive(uint64_t data) {}

uint64_t OnDataRequest() {
uint64_t data = 0;
Pack(data, delayLoc, FloatToBits(delaySecs));
Pack(data, wetLoc, static_cast<uint8_t>(wet));
Pack(data, fbLoc, static_cast<uint8_t>(feedback));
Pack(data, tapsLoc, static_cast<uint8_t>(taps - 1));
return data;
}

void OnDataReceive(uint64_t data) {
if (data != 0) {
delaySecs = BitsToFloat(Unpack(data, delayLoc));
wet = Unpack(data, wetLoc);
feedback = Unpack(data, fbLoc);
taps = Unpack(data, tapsLoc) + 1;
}
}

protected:
void SetHelp() {}
Expand All @@ -100,10 +117,14 @@ class Delay : public HemisphereAudioApplet<Mono> {

int cursor = TIME;

float delaySecs = 0.1f;
float wet = 1.0f;
float feedback = 0.0f;
float delaySecs = 0.5f;
uint8_t wet = 50;
uint8_t feedback = 0;
int taps = 1;
PackLocation delayLoc{0, 32};
PackLocation wetLoc{32, 7};
PackLocation fbLoc{39, 7};
PackLocation tapsLoc{46, 3};

const uint8_t FB_DRY_CH = 0;
const uint8_t FB_WET_CH_1 = 1;
Expand Down
6 changes: 4 additions & 2 deletions software/src/hemisphere_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -113,8 +113,9 @@ class_name class_name ## _instance[2]
#include "applets/hMIDIIn.h"
#include "applets/hMIDIOut.h"
#ifdef ARDUINO_TEENSY41
#include "applets/Freeverb.h"
// #include "applets/Freeverb.h"
#include "applets/Delay.h"
// #include "applets/Polyform.h"
#endif

////////////////// id cat class name
Expand Down Expand Up @@ -207,7 +208,8 @@ static std::tuple<
StaticApplet<Voltage, 43, 0x10>
#ifdef ARDUINO_TEENSY41
, StaticApplet<Delay, 76, 0x00>
, StaticApplet<Freeverb, 75, 0x00>
// , StaticApplet<Polyform, 76, 0x00>
// , StaticApplet<Freeverb, 75, 0x00>
#endif
> applet_tuple;

Expand Down

0 comments on commit b57f9b7

Please sign in to comment.