summaryrefslogtreecommitdiff
path: root/sw/Core/Src/edit.h
diff options
context:
space:
mode:
authorStijn Kuipers <stijnkuipers@gmail.com>2023-06-29 16:26:07 +0200
committerStijn Kuipers <stijnkuipers@gmail.com>2023-06-29 16:26:07 +0200
commitfb5a321dd7c2848128b04b306f3e1e59c87a3f70 (patch)
treea8ef6273f9f331ebb1971a9baf20a8c897955612 /sw/Core/Src/edit.h
parentbae7568fd4dd0676b370be8548c7ec95d6521ba1 (diff)
downloadplinky-fb5a321dd7c2848128b04b306f3e1e59c87a3f70.tar.gz
Initial Filedump
Tadaaa!!
Diffstat (limited to 'sw/Core/Src/edit.h')
-rwxr-xr-xsw/Core/Src/edit.h565
1 files changed, 565 insertions, 0 deletions
diff --git a/sw/Core/Src/edit.h b/sw/Core/Src/edit.h
new file mode 100755
index 0000000..e521dc7
--- /dev/null
+++ b/sw/Core/Src/edit.h
@@ -0,0 +1,565 @@
+
+#ifdef EMU
+float knobhistory[512];
+int khi;
+#endif
+
+static inline bool ispow2(int x) {
+ return (x & (x - 1)) == 0;
+}
+
+int time_finger_went_stable;
+int longpress;
+
+u8 fingerstable = 0; // bit set once finger is firmly down
+float fingerstablepos[8];// = {}; // where the finger was when it 'went stable'
+int fingerstableparamstart[8]; // what the param was at that time
+knobsmoother fingerstableparamcur[8]; // what the praam is now, floating point edition
+s8 first_finger_rotstep = 0;
+
+
+
+int preset_section_from_rotstep(int rotstep) {
+ if (rotstep < 0) return -1;
+ if (rotstep < 32) return 0;
+ if (rotstep < 32+24) return 1;
+ if (rotstep < 64) return 2;
+ return 3;
+}
+
+void init_slice_edit(SampleInfo *s, int fi) {
+ recsliceidx = fi;
+ fingerstableparamstart[fi] = /*editpitch ? s->notes[fi] * NOTE_FINGER_SCALE : */s->splitpoints[fi];
+ knobsmooth_reset(&fingerstableparamcur[fi], fingerstableparamstart[fi]);
+}
+
+void on_longpress(int rotstep) {
+ if (editmode != EM_PRESET)
+ return;
+
+ if (rotstep >= 64 - 8 && rotstep < 64) {
+ edit_sample0 = (rotstep & 7);
+ EditParamQuant(P_SAMPLE, 0, edit_sample0 + 1);
+ memcpy(&ramsample, GetSavedSampleInfo(edit_sample0), sizeof(SampleInfo));
+ ramsample1_idx = cur_sample1 = edit_sample0 + 1;
+ edit_sample1_pending = 255;
+ editmode = EM_SAMPLE;
+ // the sample editor goes straight into editing slice pos...
+ init_slice_edit(&ramsample, 7);
+
+ }
+ else {
+ copyrequest = rotstep;
+ }
+}
+
+#define LONGPRESS_THRESH (128 + 32)
+void ResetLongPress(void) {
+ if (longpress <= 0)
+ return;
+ /* no longer needed now we do this on 'up'
+ if (longpress < LONGPRESS_THRESH && longpress>64) {
+ // they cancelled a long press despite having started it
+ if (editmode == EM_PRESET) {
+ if (first_finger_rotstep < 32)
+ SetPreset(copyfrompreset, false);
+ else if (first_finger_rotstep < 64 - 8) {
+ EditParamQuant(P_SEQPAT, M_BASE,copyfrompattern);
+ }
+
+ }
+ }*/
+ longpress = 0;
+ //first_finger_rotstep = -1;
+}
+
+void togglearp(void) {
+ rampreset.flags ^= FLAGS_ARP;
+ ShowMessage(F_32_BOLD, ((rampreset.flags & FLAGS_ARP)) ? "arp on" : "arp off", 0);
+ ramtime[GEN_SYS] = millis();
+}
+void togglelatch(void) {
+ rampreset.flags^= FLAGS_LATCH;
+ ShowMessage(F_32_BOLD, ((rampreset.flags & FLAGS_LATCH)) ? "latch on" : "latch off", 0);
+ ramtime[GEN_SYS] = millis();
+ if (!((rampreset.flags & FLAGS_LATCH)))
+ clearlatch();
+}
+extern int lastencodertime;
+extern float encaccel;
+int lastencodertime = 0;
+static u8 prevencbtn;
+static int encbtndowntime = 0;
+
+bool is_finger_an_edit_operation(int fi) { // return true if a given finger is an editing operation not a note
+ switch (editmode) {
+ case EM_SAMPLE:
+ return true;
+ case EM_PLAY:
+ return (fi == 0 && edit_param < P_LAST);
+ case EM_PARAMSA:
+ case EM_PARAMSB:
+#ifdef NEW_LAYOUT
+ return true;
+#else
+ return (fi == 0 || fi == 7 || fy > 0) || (fy == 0 && fi == 1) || (fy == 0 && fi == 6);
+#endif
+ case EM_PRESET:
+ case EM_START:
+ case EM_END:
+ return true;
+ }
+ return false;
+}
+
+void finger_editing(int fi, int frame) {
+
+ int ev = encval >> 2;
+ if (fi == 0) {
+ if (encbtn) encbtndowntime++;
+ if (!encbtn) {
+ if (encbtndowntime > 500) {
+ HAL_Delay(500);
+#ifndef EMU
+ HAL_NVIC_SystemReset();
+#endif
+ }
+ }
+ if (encbtndowntime > 500) {
+ ShowMessage(F_20_BOLD, "REBOOT!!", "");
+ }
+ else if (encbtndowntime > 250) {
+ ShowMessage(F_20_BOLD, "REBOOT?", "");
+ }
+ if ((ev || encbtn || prevencbtn)) {
+ // ENCODER EDITING
+ lastencodertime = millis();
+ encval -= ev << 2;
+ int pi = edit_param;
+ if (pi >= P_LAST) pi = last_edit_param;
+ if ((pi < P_LAST) && (editmode == EM_PLAY || editmode == EM_PARAMSA || editmode == EM_PARAMSB)) {
+ int cur = GetParam(pi, edit_mod);
+ int prev = cur;
+ int f = param_flags[pi];
+ bool issigned = f & FLAG_SIGNED;
+ issigned |= (edit_mod != M_BASE);
+ if ((f & FLAG_MASK) && edit_mod == 0) {
+ int maxi = f & FLAG_MASK;
+ cur += ev * (FULL / maxi);
+ }
+ else {
+ cur += (int)floorf(0.5f + ev * maxf(1.f, encaccel * encaccel));
+#ifdef DEBUG
+ DebugLog("%d\r\n", (int)(maxf(1.f, encaccel * encaccel) * 100));
+#endif
+ }
+ cur = clampi(cur, issigned ? -FULL : 0, FULL);
+ if (encbtndowntime > 10) {
+ if (encbtndowntime >= 50) {
+ ShowMessage(F_20_BOLD, I_CROSS "Mod Cleared", "");
+ if (encbtndowntime == 50) {
+ for (int mod=1;mod<M_LAST;++mod)
+ EditParamNoQuant(pi, mod, (s16)0);
+ }
+ }
+ else {
+ ShowMessage(F_20_BOLD, I_CROSS "Clear Mod?", "");
+ }
+ }
+ if (!encbtn && prevencbtn && encbtndowntime<=50) {
+ int deflt = (edit_mod) ? 0 : init_params.params[pi][0];
+ if (deflt != 0) {
+ if (cur != deflt) cur = deflt; else cur = 0;
+ }
+ else {
+ if (cur != 0) cur = 0; else cur = FULL;
+ }
+ }
+ if (encbtn && !prevencbtn) {
+ if (pi == P_ARPONOFF) {
+ togglearp();
+ }
+ else if (pi == P_LATCHONOFF) {
+ togglelatch();
+ }
+ else {
+ // used to do clear-param here, but now we do it on RELEASE!
+ }
+ }
+ if (prev != cur) {
+ EditParamNoQuant(pi, edit_mod, (s16)cur);
+ }
+ }
+ else if (editmode == EM_SAMPLE && recsliceidx >= 0 && recsliceidx < 8) {
+ SampleInfo* s = getrecsample();
+ if (s->pitched) {
+ int newnote = clampi(s->notes[recsliceidx] + ev, 0, 96);
+ if (newnote != s->notes[recsliceidx])
+ {
+ s->notes[recsliceidx] = newnote;
+ ramtime[GEN_SAMPLE] = millis();
+ }
+ }
+ else {
+ float smin = recsliceidx ? s->splitpoints[recsliceidx - 1] + 1024.f : 0.f;
+ float smax = (recsliceidx < 7) ? s->splitpoints[recsliceidx + 1] - 1024.f : s->samplelen;
+
+ float sp = clampf(s->splitpoints[recsliceidx] + ev * 512, smin, smax);
+ if (sp != s->splitpoints[recsliceidx]) {
+ s->splitpoints[recsliceidx] = sp;
+ ramtime[GEN_SAMPLE] = millis();
+ }
+ }
+ } // sample mode
+ } // en/encbtn
+ if (!encbtn)
+ encbtndowntime = 0;
+ prevencbtn = encbtn;
+ }
+ Finger* uif = &fingers_ui_time[fi][frame];
+ Finger* uif_prev = &fingers_ui_time[fi][(frame+5)&7];
+ ///////////////////////////////////////// FINGER BASED EDITING
+ bool trig = false;
+ int bit = 1 << fi;
+ bool pressurestable = abs(uif_prev->pressure-uif->pressure)<200;
+ bool posstable = abs(uif_prev->pos - uif->pos) < 32;
+ if (uif->pressure > 100) {
+ int fy = uif->pos >> 8;
+ //if (fi == 7) EmuDebugLog("pressure delta %d, pos delta %d, y=%d\n", abs(uif_prev->pressure - uif->pressure), abs(uif_prev->pos - uif->pos), fy);
+ // finger down
+ bool isediting = is_finger_an_edit_operation(fi);
+
+ if (isediting)
+ fingerediting |= bit;
+ if (posstable && pressurestable) {
+ int fyi = uif->pos >> 8;
+ if (fingerstable == 0) {
+ first_finger_rotstep = fyi + fi * 8;
+ time_finger_went_stable = millis();
+ }
+ if ((fingerstable & bit) == 0) {
+ trig = true;
+ fingerstable |= bit;
+ fingerstablepos[fi] = uif->pos;
+ // if (fi == 7) EmuDebugLog("finger stable y = %d %d\n", uif->pos >> 8, uif->pos);
+ }
+
+ }
+ //bool increasing_pressure = latestf->pressure > previousf->pressure;
+ }
+ else {
+ // finger up!
+ if (uif->pressure<1 && ( fingerstable & bit)) {
+ //onfingerstableup((fingerediting&bit),fi, latestf, previousf);
+ fingerstable &= ~bit;
+ if (editmode == EM_PRESET) {
+ int firstsection = preset_section_from_rotstep(first_finger_rotstep);
+
+ switch (firstsection) {
+ case 0:
+ if (edit_preset_pending == prev_preset_pending || !isplaying()) {
+ if (edit_preset_pending != 255) SetPreset(edit_preset_pending, false);
+ edit_preset_pending = 255;
+ }
+ break;
+ case 1:
+ if (edit_pattern_pending == prev_pattern_pending || !isplaying()) {
+ if (edit_pattern_pending != 255) EditParamQuant(P_SEQPAT, M_BASE, edit_pattern_pending);
+ edit_pattern_pending = 255;
+ }
+ break;
+ case 2:
+ if (edit_sample1_pending == prev_sample1_pending || !isplaying()) {
+ //EmuDebugLog("set edit_sample1_pending to %d\n", edit_sample1_pending);
+ if (edit_sample1_pending != 255) EditParamQuant(P_SAMPLE, M_BASE, edit_sample1_pending);
+ edit_sample1_pending = 255;
+ }
+ break;
+ }
+
+ }
+ }
+ fingerediting &= ~bit;
+ }
+ // fingerpos_smoothed[fi] += (latestf->pos - fingerpos_smoothed[fi]) * fingerpos_k[fi];
+
+ if ((fingerediting & bit) && (fingerstable & bit)) {
+ // finger is down over some editing operation!
+ int fyi = uif->pos >> 8;
+ if (fyi >= 0 && fyi < 8)
+ touched_main_area = true;
+ int step = fyi * 8 + fi;
+ int rotstep = fyi + fi * 8;
+ u8 loopstart_step = (rampreset.loopstart_step_no_offset + step_offset) & 63;
+ bool inloop = ((step - loopstart_step) & 63) < rampreset.looplen_step;
+ int old = edit_param;
+
+
+ switch (editmode) {
+ case EM_SAMPLE: {
+ SampleInfo* s = getrecsample();
+ if (shift_down < 0 && trig) {
+ if (enable_audio == EA_MONITOR_LEVEL) {
+ enable_audio = EA_ARMED;
+ }
+ else if (enable_audio == EA_ARMED) {
+ recording_trigger();
+ }
+ else if (enable_audio == EA_RECORDING && s->samplelen >= BLOCK_SAMPLES) {
+ if (recsliceidx < 7) {
+ recsliceidx++;
+ s->splitpoints[recsliceidx] = s->samplelen - BLOCK_SAMPLES;
+ EmuDebugLog("SET SPLITPOINT %d to %d\n", recsliceidx, s->splitpoints[recsliceidx]);
+ }
+ else {
+ recording_stop();
+ }
+ }
+ }
+ if (enable_audio == EA_RECORDING && s->samplelen >= BLOCK_SAMPLES && longpress > 32) {
+ // long press to stop recording?
+ if (recsliceidx > 0) recsliceidx--;
+ recording_stop();
+ }
+ if (enable_audio == EA_PLAY) {
+ if (trig) {
+ init_slice_edit(s, fi);
+ }
+ if (fingerstable & bit) {
+ float finger_offset = (uif->pos - fingerstablepos[fi]);
+ finger_offset = deadzone(finger_offset, 32.f);
+ //finger_offset = fabsf(finger_offset) * finger_offset * (1.f / 32.f);
+ float target = fingerstableparamstart[fi] - finger_offset * (32000.f / 2048.f);
+ float cur = knobsmooth_update_knob(&fingerstableparamcur[fi], target, 32000.f);
+ /*bool editpitch = false; // fingerstableparamidx[fi];
+ if (editpitch) {
+ cur = clampf(cur, 0.f, 96 * NOTE_FINGER_SCALE);
+ int newnote = (int)(cur * (1.f / NOTE_FINGER_SCALE) + 0.5f);
+ if (s->notes[fi] != newnote) {
+ s->notes[fi] = newnote;
+ EmuDebugLog("FINGER SET NOTE %d to %d\n", fi, newnote);
+ ramtime[GEN_SAMPLE] = millis();
+ }
+ }
+ else */
+ {
+ float smin = fi ? s->splitpoints[fi - 1]+1024.f : 0.f;
+ float smax = (fi < 7) ? s->splitpoints[fi + 1]-1024.f : s->samplelen;
+ if (smin < 0.f) smin = 0.f;
+ if (smax > s->samplelen) smax = s->samplelen;
+ cur = clampf(cur, smin, smax);
+ if (s->splitpoints[fi] != cur) {
+ s->splitpoints[fi] = cur;
+ //EmuDebugLog("FINGER SET SPLITPOINT %d to %d\n", fi, s->splitpoints[fi]);
+ ramtime[GEN_SAMPLE] = millis();
+ }
+ }
+ }
+ }
+ break;
+ } // sample
+ case EM_PARAMSA:
+ case EM_PARAMSB:
+ case EM_PLAY:
+ if (fi > 0 && fi < 7 && fyi >= 0 && fyi < 8) {
+ // Reset mod source when user selects an edit param. Otherwise, the
+ // previous mod source stays selected, and the user would then have
+ // to select the base mod source pad before editing the newly selected
+ // param.
+ edit_mod = M_BASE;
+
+#ifdef NEW_LAYOUT
+ edit_param = (fyi) * 12 + (fi - 1);
+#else
+ edit_param = (fyi - 1) * 12 + (fi - 1);
+#endif
+ if (editmode == EM_PARAMSB) edit_param += 6;
+ if (trig) {
+#ifndef NEW_LAYOUT
+ if (fi == 1 && fyi == 0) {
+ togglearp();
+ }
+ else if (fi == 6 && fyi == 0) {
+ togglelatch();
+ }
+#else
+ if (edit_param == P_ARPONOFF) {
+ togglearp();
+ }
+ else if (edit_param == P_LATCHONOFF) {
+ togglelatch();
+ }
+#endif
+ } // trig
+ if (edit_param<0 || edit_param>P_LAST)
+ edit_param = P_LAST;
+ if (edit_param != old && edit_param < P_LAST) {
+ ShowMessage(F_20_BOLD, paramnames[edit_param], pagenames[edit_param / 6]);
+ }
+ static int firsttaptime;
+ static int lasttaptime;
+
+ if (trig) {
+ if (edit_param == P_TEMPO) {
+ if (ticks() - lasttaptime > 1000)
+ tapcount = 0;
+ lasttaptime = ticks();
+ if (!tapcount)
+ firsttaptime = ticks();
+ tapcount++;
+
+ external_clock_enable = false;
+ if (tapcount > 1) { // tap tempo!
+ float taps_per_minute = (32000.f * (tapcount - 1) * 60.f) / ((ticks() - firsttaptime) * BLOCK_SAMPLES);
+ //DebugLog("%d - %0.1f\n", tapcount, taps_per_minute);
+ bpm10x = clampi((int)(taps_per_minute * 10.f + 0.5f), 300, 2400);
+ EditParamNoQuant(P_TEMPO, 0, ((bpm10x - 1200) * FULL) / 1200);
+ }
+ }
+ else
+ tapcount = 0;
+ }
+
+ }
+ if (edit_param < P_LAST && (edit_param != old || trig)) {
+ fingerstableparamstart[fi] = GetParam(edit_param, edit_mod);
+ knobsmooth_reset(&fingerstableparamcur[fi], fingerstableparamstart[fi]);
+ }
+ if (fi == 7 && fyi >= 0 && fyi < 8 && fyi != edit_mod) {
+ edit_mod = fyi;
+
+ }
+ if (fi == 0 && edit_param < P_LAST && pressurestable) {
+ int pi = edit_param;
+ bool issigned = param_flags[pi] & FLAG_SIGNED;
+ issigned |= (edit_mod != M_BASE);
+ float target = clampf((2048 - 256 - uif->pos) * (FULL / (2048.f - 512.f)), 0.f, FULL);
+ if (issigned)
+ target = target * 2 - FULL;
+ float cur = knobsmooth_update_knob(&fingerstableparamcur[fi], target, FULL);
+ cur = clampf(cur, (issigned) ? -FULL - 0.1f : 0.f, FULL + 0.1f);
+ if (cur < 0.f && fingerstableparamstart[fi]>0)
+ cur = 0.f;
+ if (cur > 0.f && fingerstableparamstart[fi] < 0)
+ cur = 0.f;
+ bool notchat50 = (pi == P_SMP_RATE || pi == P_SMP_TIME);
+ if (notchat50) {
+ if (cur < HALF && fingerstableparamstart[fi]>HALF)
+ cur = HALF;
+ if (cur > HALF && fingerstableparamstart[fi] < HALF)
+ cur = HALF;
+ if (cur < -HALF && fingerstableparamstart[fi]>-HALF)
+ cur = -HALF;
+ if (cur > -HALF && fingerstableparamstart[fi] < -HALF)
+ cur = -HALF;
+
+ }
+#ifdef EMU
+ knobhistory[khi] = cur * (1.f / FULL);
+ khi = (khi + 1) & 511;
+#endif
+ EditParamNoQuant(pi, edit_mod, (s16)cur);
+ }
+ break;
+ case EM_START:
+ // if you click inside the loop, just set pos
+ if (inloop) {
+ if (trig) { // need the trig otherwise when we move the loop, this code fires
+ set_cur_step(step, false);
+ }
+ }
+ else {
+ if ((trig && pending_loopstart_step == step) || !isplaying()) {
+ if (loopstart_step != step) {
+ int newstep = cur_step - loopstart_step + step; // move curstep into new loop
+ loopstart_step = step;
+ rampreset.loopstart_step_no_offset = (step - step_offset) & 63;
+ ramtime[GEN_PRESET] = millis();
+ set_cur_step(newstep, false); // reset our cur step, based on the new loop
+ }
+ pending_loopstart_step = 255;
+ }
+ else
+ pending_loopstart_step = step;
+
+ }
+ break;
+ case EM_END:
+ // set the end of the loop
+ {
+ u8 old = rampreset.looplen_step;
+ rampreset.looplen_step = (step - loopstart_step) + 1;
+ if (rampreset.looplen_step <= 0)
+ rampreset.looplen_step += 64;
+ if (rampreset.looplen_step != old)
+ ramtime[GEN_PRESET] = millis();
+ set_cur_step(cur_step, false); // reset our cur step, based on the new loop
+ } break;
+ case EM_PRESET: {
+ int section = preset_section_from_rotstep(rotstep);
+ int firstsection = preset_section_from_rotstep(first_finger_rotstep);
+ last_preset_selection_rotstep = first_finger_rotstep; // remember what they chose
+ if (section == firstsection) switch (section) {
+ case 0:
+ //if (trig)
+ {
+ copyfrompreset = sysparams.curpreset;
+ prev_preset_pending = edit_preset_pending;
+ }
+ edit_preset_pending = rotstep;
+ break;
+ case 1: {
+ //if (trig)
+ {
+ copyfrompattern = cur_pattern;
+ prev_pattern_pending = edit_pattern_pending;
+ }
+ edit_pattern_pending = rotstep - 32;
+ break; }
+ case 2:
+ {
+ int ns = rotstep - 56 + 1;
+ if (trig) {
+ EmuDebugLog("sample trig on %d\n", ns);
+ prev_sample1_pending = edit_sample1_pending;
+ copyfromsample = cur_sample1;
+ if (ns == copyfromsample)
+ ns = 0;
+ edit_sample1_pending = ns;
+ }
+ break;
+ }
+ } // section switch
+ break;
+ } // preset
+ } // mode
+ }
+
+ if (fi == 7) {
+ if (fingerstable && ispow2(fingerstable)) {
+ // exactly one finger down
+ int fi = 0;
+ for (; fi < 8; ++fi) if (fingerstable & (1 << fi)) break;
+ int fyi = (touch_ui_getlatest(fi)->pos >> 8);
+ int rotstep = fi * 8 + fyi;
+ if (rotstep == first_finger_rotstep) {
+ longpress+=2;
+ if (longpress == LONGPRESS_THRESH) {
+ on_longpress(rotstep);
+ }
+ }
+ else
+ ResetLongPress();
+ }
+ else {
+ // not exactly one finger down
+ ResetLongPress();
+ }
+
+ }
+
+}
+
+
+
+