diff options
Diffstat (limited to 'sw/Core/Src/touch.h')
| -rwxr-xr-x | sw/Core/Src/touch.h | 1260 |
1 files changed, 1260 insertions, 0 deletions
diff --git a/sw/Core/Src/touch.h b/sw/Core/Src/touch.h new file mode 100755 index 0000000..91c9a49 --- /dev/null +++ b/sw/Core/Src/touch.h @@ -0,0 +1,1260 @@ +u16 finger_raw[36]; // raw value back from stm +u16 finger_min[36]; // lowest value seen (zero point) +u16 finger_max[36]; // highest value seen (zero point) + +static inline int finger_cap(int sensoridx) { + return finger_raw[sensoridx]; +} +static inline int finger_mincap(int sensoridx) { + return finger_min[sensoridx]; +} +static inline int finger_maxcap(int sensoridx) { + return finger_max[sensoridx]; +} + +typedef struct CalibResult { + u16 pressure[8]; + s16 pos[8]; +} CalibResult; +typedef struct CalibProgress { + float weight[8]; + float pos[8]; + float pressure[8]; +} CalibProgress; +static inline CalibProgress* GetCalibProgress(int sensoridx) { + CalibProgress* p = (CalibProgress*)delaybuf; + return p + sensoridx; +} +CalibResult calibresults[18]; + +typedef union Finger { + s32 x; + struct { + s16 pressure; + s16 pos : 15; + s16 written : 1; + }; +} Finger; +Finger fingers_ui_time[9][8]; // 8 frames for 9 fingers +Finger fingers_synth_time[8][8]; // 8 frames for 8 fingers +Finger fingers_synth_sorted[8][8]; +u8 finger_state; +u8 finger_step; +u16 finger_stepmask; +volatile u8 finger_frame_ui; +volatile u8 finger_frame_synth; +u8 finger_ui_done_this_frame; +u8 waitcounter; +u8 finalwait; +u8 fingerediting = 0; // finger is over some kind of non-musical edit control +u8 prevfingerediting = 0; + +typedef struct euclid_state { + int trigcount; + bool did_a_retrig; + bool supress; + +} euclid_state; + +euclid_state arp_rhythm; +euclid_state seq_rhythm; + + +static inline u8 touch_ui_writingframe(void) { return (finger_frame_ui) & 7; } +static inline u8 touch_ui_frame(void) { return (finger_frame_ui-1)&7; } +static inline u8 touch_ui_prevframe(void) { return (finger_frame_ui -2) & 7; } + +static inline u8 touch_synth_writingframe(void) { return (finger_frame_synth) & 7; } +static inline u8 touch_synth_frame(void) { return (finger_frame_synth - 1) & 7; } +static inline u8 touch_synth_prevframe(void) { return (finger_frame_synth - 2) & 7; } + + +static inline Finger* touch_synth_getlatest(int finger) { return &fingers_synth_time[finger][touch_synth_frame()]; } +static inline Finger* touch_synth_getprev(int finger) { return &fingers_synth_time[finger][touch_synth_prevframe()]; } +static inline Finger* touch_synth_getwriting(int finger) { return &fingers_synth_time[finger][touch_synth_writingframe()]; } +static inline Finger* touch_ui_getwriting(int finger) { return &fingers_ui_time[finger][touch_ui_writingframe()]; } +static inline Finger* touch_ui_getlatest(int finger) { return &fingers_ui_time[finger][touch_ui_frame()]; } +static inline Finger* touch_ui_getprev(int finger) { return &fingers_ui_time[finger][touch_ui_prevframe()]; } + +#define SWAP(a,b) if (a>b) { int t=a; a=b; b=t; } +void sort8(int *dst, const int *src) { + int a0=src[0],a1=src[1],a2=src[2],a3=src[3],a4=src[4],a5=src[5],a6=src[6],a7=src[7]; + SWAP(a0,a1);SWAP(a2,a3);SWAP(a4,a5);SWAP(a6,a7); + SWAP(a0,a2);SWAP(a1,a3);SWAP(a4,a6);SWAP(a5,a7); + SWAP(a1,a2);SWAP(a5,a6);SWAP(a0,a4);SWAP(a3,a7); + SWAP(a1,a5);SWAP(a2,a6); + SWAP(a1,a4);SWAP(a3,a6); + SWAP(a2,a4);SWAP(a3,a5); + SWAP(a3,a4); + dst[0]=a0; dst[1]=a1; dst[2]=a2; dst[3]=a3; dst[4]=a4; dst[5]=a5; dst[6]=a6; dst[7]=a7; +} +#undef SWAP + +void touch_reset_calib(void) { +// memset(finger_max,0,sizeof(finger_max)); + memset(finger_min,-1, sizeof(finger_min)); + memset(finger_raw,0,sizeof(finger_raw)); + memset(calibresults, 0, sizeof(calibresults)); +} + + + +void check_curstep(void) { // enforces invariants + if (rampreset.looplen_step <= 0 || rampreset.looplen_step > 64) + rampreset.looplen_step = 64; + rampreset.loopstart_step_no_offset &= 63; + u8 loopstart_step = (rampreset.loopstart_step_no_offset + step_offset) & 63; + cur_step= (cur_step- loopstart_step) % rampreset.looplen_step; + if (cur_step < 0) + cur_step += rampreset.looplen_step; + cur_step += loopstart_step; +} + +void set_cur_step(u8 newcurstep, bool triggerit) { + //u8 old = cur_step; + cur_step = newcurstep; + check_curstep(); + seq_rhythm.did_a_retrig = triggerit; // make the sound play out once + ticks_since_step = 0; + seq_divide_counter = 0; +} + +void OnLoop(void) { + if (edit_preset_pending != 255) { + SetPreset(edit_preset_pending, false); + edit_preset_pending = 255; + } + if (edit_pattern_pending != 255) { + EditParamQuant(P_SEQPAT, M_BASE, edit_pattern_pending); + edit_pattern_pending = 255; + } + if (pending_loopstart_step !=255) { + u8 loopstart_step = (rampreset.loopstart_step_no_offset + step_offset) & 63; + if (loopstart_step != pending_loopstart_step) { + rampreset.loopstart_step_no_offset = (pending_loopstart_step - step_offset)&63; + ramtime[GEN_PRESET] = millis(); + } + set_cur_step(loopstart_step, seq_rhythm.did_a_retrig); + pending_loopstart_step = 255; + + } + if (edit_sample1_pending != cur_sample1 && edit_sample1_pending!=255) { + EditParamQuant(P_SAMPLE, 0, edit_sample1_pending); + edit_sample1_pending = 255; + } + check_curstep(); +} + + +bool touched_main_area; + +bool got_ui_reset = false; +int tapcount = 0; +void clearlatch(void); + +void reverb_clear(void) { + memset(reverbbuf, 0, (RVMASK + 1) * 2); +} +void delay_clear(void) { + memset(delaybuf, 0, (DLMASK + 1) * 2); +} + + +u16 audioin_holdtime = 0; +s16 audioin_peak = 0; +s16 audioin_hold = 0; +knobsmoother recgain_smooth; +int audiorec_gain_target = 1 << 15; + +int recpos = 0; // this cycles around inside the delay buffer (which we use for a recording buffer) while armed... +int recstartpos = 0; // once we start recording, we note the position in the buffer here +int recreadpos = 0; // ...and this is where we are up to in terms of reading that out and writing it to flash +u8 recsliceidx = 0; +const static bool pre_erase = true; +u32 record_flashaddr_base = 0; + +static inline SampleInfo* getrecsample(void) { return &ramsample; } +static inline u8 getwaveform4(SampleInfo* s, int x) { // x is 0-2047 + if (x < 0 || x >= 2048) + return 0; + return (s->waveform4_b[x >> 1] >> ((x & 1) * 4)) & 15; +} +static inline u8 getwaveform4halfres(SampleInfo* s, int x) { // x 0-1023 + u8 b = s->waveform4_b[x & 1023]; + return maxi(b & 15, b >> 4); +} +static inline u16 getwaveform4zoom(SampleInfo* s, int x, int zoom) { // x is 0-2048. returns average and peak! + if (zoom <= 0) + return getwaveform4(s, x >> zoom); + int samplepairs = 1 << (zoom - 1); + u8* b = &s->waveform4_b[(x>>1) & 1023]; + int avg = 0, peak=0; + u8* bend = &s->waveform4_b[1024]; + for (int i = 0; i < samplepairs && b < bend; ++i, ++b) { + int s0 = b[0] & 15; + int s1 = b[0] >> 4; + avg += s0 + s1; + peak = maxi(peak, maxi(s0, s1)); + } + avg >>= zoom; + return avg+peak*256; +} + +static inline void setwaveform4(SampleInfo* s, int x, int v) { + v = clampi(v, 0, 15); + u8* b = &s->waveform4_b[(x >> 1) & 1023]; + if (x & 1) { + v = maxi(v, (*b) >> 4); + *b = (*b & 0x0f) | (v << 4); + } + else { + v = maxi(v, (*b) & 15); + *b = (*b & 0xf0) | v; + } +} + +void DebugSPIPage(int addr); + +void recording_stop_really(void) { + // clear out the raw audio in the delaybuf + reverb_clear(); + delay_clear(); + ramtime[GEN_SAMPLE] = millis(); // fill in the remaining split points + SampleInfo* s = getrecsample(); + int startsamp = s->splitpoints[recsliceidx]; + int endsamp = s->samplelen; + int n = 8 - recsliceidx; + for (int i = recsliceidx + 1; i < 8; ++i) { + int samp = startsamp + ((endsamp - startsamp) * (i - recsliceidx)) / n; + s->splitpoints[i] = samp; + EmuDebugLog("POST RECORD EVEN SET SPLITPOINT %d to %d\n", i, s->splitpoints[i]); + + } + recsliceidx = 0; + ramtime[GEN_SAMPLE] = millis(); + //DebugSPIPage(0); + //DebugSPIPage(1024*1024*2-65536); + + enable_audio = EA_PLAY; +} + +void recording_stop(void) { + if (enable_audio == EA_PLAY) { + editmode = EM_PLAY; + } + else if (enable_audio == EA_RECORDING) { + enable_audio = EA_STOPPING1; + } + else if (enable_audio >= EA_STOPPING1) { + // do nothing + } + else + enable_audio = EA_PLAY; + +} + +void seq_step(int initial); + +void recording_trigger(void) { + recsliceidx = 0; + SampleInfo* s = getrecsample(); + memset(s, 0, sizeof(SampleInfo)); +#define LEADIN 1024 + int leadin = mini(recpos, LEADIN); + recreadpos = recstartpos = recpos - leadin; + s->samplelen = 0; + s->splitpoints[0] = leadin; + enable_audio = EA_RECORDING; +} + + +void on_shift_hold(int button) { + + if (editmode == EM_PRESET) { + if (shift_down == SB_CLEAR && shift_down_time > 64+4) { + // clear it! + if (last_preset_selection_rotstep>=0 && last_preset_selection_rotstep<64) + copyrequest = last_preset_selection_rotstep + 128; + } + } + + if (editmode == EM_SAMPLE) { + if (enable_audio==EA_PLAY && (shift_down == SB_RECORD || shift_down == SB_PLAY) && shift_down_time > 64) { + knobsmooth_reset(&recgain_smooth, audiorec_gain_target); + record_flashaddr_base = (edit_sample0 & 7) * (2 * MAX_SAMPLE_LEN); + recsliceidx = 0; + recstartpos = 0; + recreadpos = 0; + recpos = 0; + enable_audio = pre_erase ? EA_PREERASE : EA_MONITOR_LEVEL; + } + } +} + +void arp_reset(void); +void ShowMessage(EFont fnt, const char* msg, const char *submsg); + +u8 prev_editmode; +u8 last_edit_param=255; +bool param_sticky = false; +void on_shift_down(void) { + prev_editmode = editmode; + touched_main_area = false; + if (editmode == EM_SAMPLE) { + if (shift_down == SB_PREV) { + + } + else if (shift_down == SB_RECORD || shift_down==SB_RECORD || shift_down==SB_PLAY) { + if (enable_audio == EA_PLAY) { + /* long press */ + } + else if (enable_audio == EA_MONITOR_LEVEL) + enable_audio = EA_ARMED; + else if (enable_audio == EA_ARMED) { + recording_trigger(); + } + else if (enable_audio == EA_RECORDING) { + recording_stop(); + } + } + return; + } + + switch (shift_down) { + case SB_PLAY: // play/pause + if (playmode == PLAY_WAITING_FOR_CLOCK_STOP) { + playmode = PLAY_STOPPED; + OnLoop(); + } + else if (playmode == PLAY_PREVIEW) { + //playmode = PLAYING; + //arp_reset(); + //seq_step(true); + } else if (playmode == PLAY_STOPPED) { + playmode = PLAY_PREVIEW; + seq_step(1); + } + else if (playmode == PLAYING) { + playmode = PLAY_WAITING_FOR_CLOCK_STOP; + } + break; + //case SB_REWIND: // reset + // playclock=loopstart+latency_fix; + // OnLoop(); + // break; + case SB_PREV: // prev + editmode = EM_START; + if (isplaying()) + got_ui_reset = true; + break; + case SB_NEXT: // next + editmode = EM_END; + break; + case SB_RECORD: + knobbase[0] = adc_smooth[4].y2; + knobbase[1] = adc_smooth[5].y2; + recordingknobs = 0; + break; + case SB_CLEAR: // delete/clear. TODO: hold down in preset mode to clear a pattern/sample/preset. in play mode, supress notes. + clearlatch(); + break; + case SB_PRESET: + editmode = EM_PRESET; + last_preset_selection_rotstep = sysparams.curpreset; + break; + case SB_PARAMSA: + if (edit_param >= P_LAST && last_edit_param < P_LAST) + edit_param = last_edit_param, param_sticky = true; + else + param_sticky = false; + if (edit_param<P_LAST && (edit_param %12)>=6) edit_param -=6; + editmode = EM_PARAMSA; + tapcount = 0; + break; + case SB_PARAMSB: + if (edit_param >= P_LAST && last_edit_param < P_LAST) + edit_param = last_edit_param, param_sticky = true; + else + param_sticky = false; + if (edit_param<P_LAST && (edit_param % 12) < 6) edit_param += 6; + editmode = EM_PARAMSB; + break; + } +} + +bool isshortpress(void) { + return (ticks() - last_time_shift_was_untouched) < 250; +} + +void togglearp(void); + +void on_shift_up(int release_button) { + bool shortpress = isshortpress(); + + if (editmode == EM_SAMPLE) { + if (shortpress) { + if (shift_down == SB_PARAMSA) { + ramsample.pitched = !ramsample.pitched; + ramtime[GEN_SAMPLE] = millis(); + } else + if (shift_down == SB_PARAMSB) { + ramsample.loop = (ramsample.loop+1)&3; + ramtime[GEN_SAMPLE] = millis(); + } + else + if (shift_down != SB_RECORD && shift_down!=SB_PLAY) { + recording_stop(); + } + } + return; + } + switch (shift_down) { + case SB_PARAMSA: + case SB_PARAMSB: + editmode = EM_PLAY; + last_edit_param = edit_param; + if (!touched_main_area && !param_sticky) { + edit_param = P_LAST; + edit_mod = 0; + } + // these arent real params, so dont stick on them. + if (edit_param == P_ARPONOFF || edit_param == P_LATCHONOFF) { + edit_param = P_LAST; + edit_mod = 0; + } + break; + case SB_PREV: // prev + //if (!touched_main_area && shift_down_time > 128 / 4 && prev_editmode == EM_PLAY) { + // togglearp(); + // editmode = EM_PLAY; + //} + //else + if (!touched_main_area && shortpress) { + if (isplaying()) { + // got_ui_reset = true; did it on note down already + } + else + set_cur_step(cur_step - 1, !isplaying()); + editmode = EM_PLAY; + } + if (touched_main_area || prev_editmode==editmode) + editmode = EM_PLAY; + break; + case SB_NEXT: // next + if (!touched_main_area && shortpress) { + set_cur_step(cur_step + 1, !isplaying()); + editmode = EM_PLAY; + } + if (touched_main_area || prev_editmode == editmode) + editmode = EM_PLAY; + break; + case SB_PRESET: // preset + if (touched_main_area || prev_editmode == editmode) + editmode = EM_PLAY; + break; + case SB_PLAY: + if (playmode == PLAY_PREVIEW ) + playmode = shortpress ? PLAYING: PLAY_STOPPED; + + break; + case SB_RECORD: + if (shortpress && recordingknobs==0) + recording = !recording; + recordingknobs = 0; + break; + case SB_CLEAR: + if (!isplaying() && recording && editmode == EM_PLAY) { + bool dirty = false; + int q = (cur_step >> 4) & 3; + FingerRecord* fr = &rampattern[q].steps[cur_step & 15][0]; + for (int fi = 0; fi < 8; ++fi, ++fr) { + for (int k = 0; k < 8; ++k) { + if (fr->pressure[k] > 0) + dirty = true; + fr->pressure[k] = 0; + if (fi < 2) { + s8* d = &rampattern[q].autoknob[(cur_step & 15) * 8 + k][fi]; + if (*d) { + *d = 0; dirty = true; + } + } + } + + } + if (dirty) + ramtime[GEN_PAT0 + ((cur_step >> 4) & 3)] = millis(); + set_cur_step(cur_step + 1, false); + } + + break; + } + check_curstep(); +} + + +int prev_prev_total_ui_pressure = 0; +int prev_total_ui_pressure = 0; +int total_ui_pressure = 0; + +typedef struct FingerStorage { + u8 minpos, maxpos; + u8 avgvel; +} FingerStorage; +FingerStorage latch[8]; +bool latch_valid; +void clearlatch(void) { + memset(latch, 0, sizeof(latch)); + latch_valid = false; +} + + +static inline int randrange(int mn, int mx) { + return mn + (((rand() & 255) * (mx - mn)) >> 8); +} + + + +int param_eval_finger(u8 paramidx, int fingeridx, Finger* f); +u8 synthfingerdown_nogatelen_internal; +u8 synthfingersupress_nogatelen; +bool read_from_seq = false; + + +FingerRecord* readpattern(int fi) { + if (rampattern_idx == cur_pattern && shift_down != SB_CLEAR) { + return &rampattern[(cur_step >> 4) & 3].steps[cur_step & 15][fi]; + } // pattern is ok? + return 0; +} + +/////////////////// XXXXX MIDI HERE? + // bitmask of 'midi pitch override' and 'midi pressure override' + // midipitch + // here: if real pressure, clear both + // here: if pressure override, set it as midi channel aftertouch + midi note pressure + // in plinky.c midi note down: inc next voice index; set both override bits; set voice midi pitch and channel and velocity + // in plinky.c midi note up: clear pressure override bit + // in the synth - override pitch if bit is set +u8 midi_pressure_override, midi_pitch_override; +u8 midi_notes[8]; +u8 midi_velocities[8]; +u8 midi_aftertouch[8]; +u8 midi_channels[8] = { 255,255,255,255,255,255,255,255 }; +u8 midi_chan_aftertouch[16]; +s16 midi_chan_pitchbend[16]; +u8 midi_next_finger; +u8 midi_lsb[32]; +u8 find_midi_note(u8 chan, u8 note) { + for (int fi = 0; fi < 8; ++fi) if (midi_notes[fi] == note && midi_channels[fi] == chan) + return fi; + return 255; +} +u8 find_midi_free_channel(void) { + u8 numfingerdown = 0; + + for (int attempt = 0; attempt < 16; ++attempt) { + u8 ch = (midi_next_finger++) & 7; + bool fingerdown = touch_synth_getlatest(ch)->pressure > 0 && (midi_pressure_override&(1<<ch))==0; // synth_dst_finger>0, and midi_pressure_override bit is not set + if (fingerdown) { + if (attempt < 8) { + numfingerdown++; + if (numfingerdown == 8) + return 255; // all fingers using channels! NO ROOM! TOUGH + } + continue; + } + if (attempt >=8 || midi_channels[ch] == 255) + return ch; + } + // give up + return (midi_next_finger++) & 7; +} + +bool is_finger_an_edit_operation(int fi); + +void finger_synth_update(int fi) { + if (fi == 0) { + total_ui_pressure = 0; + } + int bit = 1 << fi; + int frame_ui = (finger_frame_ui-1) & 7; + if (finger_ui_done_this_frame & bit) + frame_ui = (frame_ui + 1) & 7; +// int prevframe_ui = (frame_ui - 1) & 7; + int prevprevframe_ui = (frame_ui - 2) & 7; +// int prev4frame_ui = (frame_ui - 4) & 7; + Finger* uif = &fingers_ui_time[fi][frame_ui]; +// Finger* uif_prev = &fingers_ui_time[fi][prevframe_ui]; + Finger* uif_prevprev = &fingers_ui_time[fi][prevprevframe_ui]; +// Finger* uif_prev4= &fingers_ui_time[fi][prev4frame_ui]; + Finger* synth_dst_finger = &fingers_synth_time[fi][finger_frame_synth]; +// Finger* synth_prev_finger = &fingers_synth_time[fi][(finger_frame_synth-1)&7]; + + int p = uif->pressure; +// int prevp = uif_prev->pressure; + int prevprevp = uif_prevprev->pressure; +// int prev4p = uif_prev4->pressure; +// bool fingerup = (p <= 0 && prevprevp <= 0 && prev4p<=0); + bool pressure_not_rapidly_decreasing = (p > (prevprevp)); // we do this BEFORE compensating for edit mode, so that we dont accidentally see it as increasing after edit ends + if (editmode != EM_SAMPLE) { + if ((fingerediting | prevfingerediting) & bit) + p = -256; + else if (shift_down == SB_CLEAR) + p = -256; + else if (is_finger_an_edit_operation(fi)) + p = -256; + } + + + //if (fi == 0) + // DebugLog("process finger0 pressure %d %f\n", p); + + // MIDI HERE + + + if (p > 0) { + midi_pressure_override &= ~bit; + midi_pitch_override &= ~bit; + } + else if (midi_pressure_override & bit) { + u8 chan = midi_channels[fi]; + p = 1+(midi_velocities[fi] + maxi(midi_aftertouch[fi], midi_chan_aftertouch[chan]))*16; + pressure_not_rapidly_decreasing = (p > (prevprevp) ); // update for midi + } + + /////////////////// + + synth_dst_finger->pressure = p; +// int total_ui_pressure_before_me = total_ui_pressure; + total_ui_pressure += maxi(0, p); + + //if (uif->written) // written is only set if we are confident to update the position + synth_dst_finger->pos = uif->pos; + //else + // synth_dst_finger->pos = synth_prev_finger->pos; + + int phase0 = calcseqsubstep(0, 8); + if (fi==0) + read_from_seq = false; + bool any_fingers_down = (total_ui_pressure > 0 || prev_total_ui_pressure > 0); + if (fi==7 && shift_down!=SB_CLEAR && total_ui_pressure > 0 && total_ui_pressure >= prev_total_ui_pressure) { + // update latch from ui state + for (int fi=0;fi<8;++fi) { + u8 maxpos = 0, minpos = 255, maxpressure = 0; + Finger* f = fingers_synth_time[fi]; + for (int j = 0; j < 8; ++j, ++f) { + u8 p = clampi((f->pos + 4) / 8, 0, 255); + minpos = mini(p, minpos); + maxpos = maxi(p, maxpos); + u8 pr = clampi(f->pressure / 12, 0, 255); + maxpressure = maxi(maxpressure, pr); + } + //if (avgvel > latch[fi].avgvel+1 || pressure_not_rapidly_decreasing) + { +// if (fi == 4) EmuDebugLog("latch pressure %d, tot %d prev %d\n", maxpressure, total_ui_pressure, prev_total_ui_pressure); + latch[fi].avgvel = maxpressure; + latch[fi].minpos = minpos; + latch[fi].maxpos = maxpos; + } + } + latch_valid = true; + } // latch fingers down! + + // recording + static u8 last_rec_step=255; + static u8 last_rec_phase = 0; + static u8 step_filled = 0; + int q = (cur_step >> 4) & 3; + FingerRecord* fr = &rampattern[q].steps[cur_step & 15][fi]; + bool want_recording_on = any_fingers_down && recording && rampattern_idx == cur_pattern ; // && (isplaying() || pressure_increasing) + + if (recording && rampattern_idx == cur_pattern && fi < 2) { // check for knob recording? + int k = fi; + float knob = adc_smooth[4 + k].y2; + if (shift_down == SB_RECORD && fabsf(knob - knobbase[k]) > 0.01f) + recordingknobs |= 1 << k; + } + if (shift_down == SB_CLEAR && recording) + want_recording_on = true; + if (want_recording_on) { + if (last_rec_step != cur_step) { + // new step! blank it out + // DebugLog("cear step %d (fi=%d)\r\n", cur_step, fi); + for (int fi = 0; fi < 8; ++fi) { + FingerRecord* fr = &rampattern[q].steps[cur_step & 15][fi]; + memset(fr, 0, sizeof(FingerRecord)); + } + for (int k = 0; k < 2; ++k) + if (recordingknobs&(1<<k)) for (int i = 0; i < 8; ++i) + rampattern[q].autoknob[(cur_step & 15) * 8 + i][k] = 0; + if (playmode != PLAYING && phase0 != 0) { + // force the sequencer step clock back to the start of the step! + phase0 = 0; + ticks_since_step = 0; + seq_divide_counter = 0; + } + step_filled = 0; + last_rec_phase = phase0; + last_rec_step = cur_step; + } + ramtime[GEN_PAT0 + ((cur_step >> 4) & 3)] = millis(); + int pressure = clampi((synth_dst_finger->pressure+512) / 12, 0, 255); + int pos = clampi(synth_dst_finger->pos / 8, 0, 255); + if (shift_down == SB_CLEAR) { + if (fi<2) + for (int i=0;i<8;++i) + rampattern[q].autoknob[(cur_step & 15) * 8 + i][fi] = 0; + pressure = 0; + } + if (phase0 < last_rec_phase) + step_filled = 1; + if (step_filled) { + // scroll right! but dont record lift offs + if (phase0!=last_rec_phase && (isplaying() || pressure_not_rapidly_decreasing)) { + for (int i = 0; i < 7; ++i) fr->pressure[i] = fr->pressure[i + 1]; + for (int i = 0; i < 3; ++i) fr->pos[i] = fr->pos[i + 1]; + fr->pressure[7] = pressure; + fr->pos[3] = pos; + } + } + else { + // fill from left! + fr->pressure[phase0] = maxi(fr->pressure[phase0], pressure); + for (int phase = phase0 + 1; phase < 8; ++phase) + fr->pressure[phase] = 0; + for (int phase = phase0 / 2; phase < 4; ++phase) + fr->pos[phase] = pos; + + } + } + if (recording && rampattern_idx == cur_pattern && fi < 2 && recordingknobs>0) { + int k = fi; + float knob = adc_smooth[4 + k].y2; + if (recordingknobs & (1 << k)) { + if (isplaying()) + rampattern[q].autoknob[(cur_step & 15) * 8 + phase0][k] = clampi((int)(knob * 127.f), -127, 127); + else for (int i = 0; i < 8; ++i) + rampattern[q].autoknob[(cur_step & 15) * 8 + i][k] = clampi((int)(knob * 127.f), -127, 127); + ramtime[GEN_PAT0 + ((cur_step >> 4) & 3)] = millis(); + } + } + + if (fi == 7) { + last_rec_step = cur_step; + last_rec_phase = phase0; + if (!want_recording_on) + last_rec_step = 255; + } + if (!any_fingers_down) { + + // read from pattern + FingerRecord *fr = readpattern(fi); + if (fr && (isplaying() || seq_rhythm.did_a_retrig)) { + read_from_seq = true; + + int pr = fr->pressure[phase0] * 12; + int pos = fr->pos[phase0 / 2]; + synth_dst_finger->pressure = (pr && !seq_rhythm.supress) ? randrange(pr, pr+12)-512 : -1024; + synth_dst_finger->pos = randrange(pos * 8, pos * 8 + 8); + synth_dst_finger->written = 1; + } + // read from latch + bool latchon = ((rampreset.flags & FLAGS_LATCH)) ; + if (latch_valid && latchon && shift_down != SB_CLEAR) { + int latchvel = latch[fi].avgvel * 12; + if (latchvel >= synth_dst_finger->pressure) { + int mnpos = latch[fi].minpos * 8 + 2, mxpos = latch[fi].maxpos * 8 + 6; + int avgpos = (mnpos + mxpos) / 2; + int range = (mxpos - mnpos) / 4; + synth_dst_finger->pos = randrange(avgpos-range,avgpos+range); + synth_dst_finger->pressure = latchvel ? randrange(latchvel - 12, latchvel) : -1024; + synth_dst_finger->written = 1; + } + } + + } + + float gate_cv = adc_smooth[7].y2; + synth_dst_finger->pressure = (int)((synth_dst_finger->pressure + 256) * gate_cv) - 256; + + //if (fi == 0) + // DebugLog("finger0 pressure %d %f\n", synth_dst_finger->pressure, gate_cv); + + + //if (fi==7) + // DebugLog("frame_ui %d frame_synth %d uif %d synth %d\n", finger_frame_ui, finger_frame_synth, uif->pressure, synth_dst_finger->pressure); + + + if (synth_dst_finger->pressure > 0) { + synthfingerdown_nogatelen_internal |= bit; + } + else { + synthfingerdown_nogatelen_internal &= ~bit; + synthfingersupress_nogatelen &= ~bit; + } + // ///////////////////////////////////////// + int gatelen = param_eval_finger(P_GATE_LENGTH, fi, synth_dst_finger) >> 8; + if (gatelen < 256 && !isgrainpreview()) { + int phase = (rampreset.flags & FLAGS_ARP) ? calcarpsubstep(0, 256) : calcseqsubstep(0, 256); + int suppress_seq=false; + if (read_from_seq) + suppress_seq = (!seq_rhythm.did_a_retrig && !isplaying()); + else + suppress_seq = (synthfingersupress_nogatelen & bit); + if (rampreset.flags & FLAGS_ARP) + suppress_seq |= !arp_rhythm.did_a_retrig; + //suppress_seq = !arp_rhythm.did_a_retrig; + if (phase > gatelen || suppress_seq) { + synth_dst_finger->pressure = -1024; + if (!read_from_seq && !(rampreset.flags & FLAGS_ARP)) { + if (synthfingerdown_nogatelen & bit) + synthfingersupress_nogatelen |=bit; // once we've supressed, we keep supressing! + } + } + } + else { + if (!isplaying() && read_from_seq && !seq_rhythm.did_a_retrig) { + synth_dst_finger->pressure = -1024; + } + } + // ///////////////////////////////////////// + + /* test hold fingers down + if (fi > 0 && fi < 5) { + synth_dst_finger->pos = 128; + synth_dst_finger->pressure = (fi==1)?2047:1024; + } + */ + +#define ENABLE_TEST_TONE 0 + if (ENABLE_TEST_TONE) if (fi == 5) { + synth_dst_finger->pressure = 1500; + synth_dst_finger->pos = 128; + } + /* + static int log3=0; + if (log3>0 && fi==3) { + DebugLog("%d %d (%d)\r\n",synth_dst_finger->pressure, synth_dst_finger->pos, written); + if (synth_dst_finger->pressure<=0) + log3--; + }*/ + + static s16 prevpressure[8]; + + if (prevpressure[fi]<= 0 && synth_dst_finger->pressure > 0) { + // the finger has just gone down! lets go fix a bunch of positions in the history + Finger* of = fingers_synth_time[fi]; + int newp = synth_dst_finger->pos; + int numfix=0; + for (int h = 0; h < 8; ++h, of++) if (h != finger_frame_synth) { + if (of->pressure <= 0) { + of->pos = (of->pos & 3) ^ newp; + numfix++; + } + } + /* + DebugLog("fi %d fixed %d vol=%d -> %d pos = %d\r\n", fi, numfix, synth_prev_finger->pressure, synth_dst_finger->pressure, newp); + sort8((int*)fingers_synth_sorted[fi], (int*)fingers_synth_time[fi]); + for (int i=0;i<8;++i) DebugLog("%d ",fingers_synth_sorted[fi][i].pos); + DebugLog("\r\n"); + log3=10; + */ + } + prevpressure[fi] = synth_dst_finger->pressure; + + sort8((int*)fingers_synth_sorted[fi], (int*)fingers_synth_time[fi]); + + + +} + +void finger_editing(int fi, int frame); + + +#ifdef EMU +int htsc; +typedef struct TSC_IOConfigTypeDef { + u32 ChannelIOs; + u32 SamplingIOs; +}TSC_IOConfigTypeDef; +typedef int TSC_GroupStatusTypeDef; +#define TSC_GROUP1_IO1 (1<<0) +#define TSC_GROUP1_IO2 (1<<1) +#define TSC_GROUP1_IO3 (1<<2) +#define TSC_GROUP1_IO4 (1<<3) +#define TSC_GROUP2_IO1 (1<<4) +#define TSC_GROUP2_IO2 (1<<5) +#define TSC_GROUP2_IO3 (1<<6) +#define TSC_GROUP2_IO4 (1<<7) +#define TSC_GROUP3_IO1 (1<<8) +#define TSC_GROUP3_IO2 (1<<9) +#define TSC_GROUP3_IO3 (1<<10) +#define TSC_GROUP3_IO4 (1<<11) +#define TSC_GROUP4_IO1 (1<<12) +#define TSC_GROUP4_IO2 (1<<13) +#define TSC_GROUP4_IO3 (1<<14) +#define TSC_GROUP4_IO4 (1<<15) +#define TSC_GROUP5_IO1 (1<<16) +#define TSC_GROUP5_IO2 (1<<17) +#define TSC_GROUP5_IO3 (1<<18) +#define TSC_GROUP5_IO4 (1<<19) +#define TSC_GROUP6_IO1 (1<<20) +#define TSC_GROUP6_IO2 (1<<21) +#define TSC_GROUP6_IO3 (1<<22) +#define TSC_GROUP6_IO4 (1<<23) +#define TSC_GROUP7_IO1 (1<<24) +#define TSC_GROUP7_IO2 (1<<25) +#define TSC_GROUP7_IO3 (1<<26) +#define TSC_GROUP7_IO4 (1<<27) + +#define ENABLE 1 +#define TSC_GROUP_COMPLETED 1 +u32 _chanios; +void HAL_TSC_IOConfig(int* htsc, TSC_IOConfigTypeDef* config) { _chanios = config->ChannelIOs; } +void HAL_TSC_IODischarge(int *htsc, int enable) {} +void HAL_TSC_Start(int* htsc) {} +void HAL_TSC_Stop(int* htsc) {} +TSC_GroupStatusTypeDef HAL_TSC_GroupGetStatus(int* htsc, int groupidx) { + return TSC_GROUP_COMPLETED; +} +short HAL_TSC_GroupGetValue(int* htsc, int groupidx) { + // hacked so groupidx is actually 0-35 sensor idx + groupidx %= 18; + int fingeridx = groupidx / 2; + extern int emutouch[9][2]; + int pos = emutouch[fingeridx][1]; + int pressure = emutouch[fingeridx][0]; + int a = pressure * (2048 - pos); + int b = pressure * (pos); + if (fingeridx == 8) { + int t = a; a = b; b = t; // oops I swapped the pins + } + if (groupidx&1) a = b; + a >>= 10; + a += 2048; +// if (groupidx == 0) +// printf("hello finger 0 %d %d = %d\n", pos, pressure, (2048 * 2048) / a); + a += rand() & 31; + return (2048 * 2048) / a; +} +#endif + +#define FF0 TSC_GROUP1_IO2+TSC_GROUP4_IO2 +#define FF1 TSC_GROUP2_IO2+TSC_GROUP5_IO2 +#define FF2 TSC_GROUP3_IO3+TSC_GROUP6_IO2 +#define FF3 TSC_GROUP1_IO3+TSC_GROUP4_IO3 +#define FF4 TSC_GROUP2_IO3+TSC_GROUP5_IO3 +#define FF5 TSC_GROUP3_IO4+TSC_GROUP6_IO3 +#define FF6 TSC_GROUP1_IO4+TSC_GROUP4_IO4 +#define FF7 TSC_GROUP2_IO4+TSC_GROUP5_IO4 +#define FF8a TSC_GROUP7_IO2 +#define FF8b TSC_GROUP7_IO3 +#define SS0 TSC_GROUP1_IO1+TSC_GROUP4_IO1 +#define SS1 TSC_GROUP2_IO1+TSC_GROUP5_IO1 +#define SS2 TSC_GROUP3_IO2+TSC_GROUP6_IO1 +#define SS3 TSC_GROUP1_IO1+TSC_GROUP4_IO1 +#define SS4 TSC_GROUP2_IO1+TSC_GROUP5_IO1 +#define SS5 TSC_GROUP3_IO2+TSC_GROUP6_IO1 +#define SS6 TSC_GROUP1_IO1+TSC_GROUP4_IO1 +#define SS7 TSC_GROUP2_IO1+TSC_GROUP5_IO1 +#define SS8a TSC_GROUP7_IO1 +#define SS8b TSC_GROUP7_IO1 + +int raw_isdown(int srcidx) { + int a = finger_cap(srcidx * 2) - finger_mincap(srcidx*2); + int b = finger_cap(srcidx * 2 + 1) - finger_mincap(srcidx * 2 + 1); + return (a + b > 1000) ? 1 : 0; +} + +static inline int finger_rawpos(int a, int b) { + return clampi(((b - a) << 12) / (a+b+ 1), -32767, 32767); +} + +static inline int finger_rawpressure(int a, int b) { + return clampi(a + b, 0, 32767); +} + +void update_finger(int srcidx) { + int dstidx = srcidx; + if (dstidx >= 9) dstidx -= 9; + int a = finger_cap(srcidx*2); + int b = finger_cap(srcidx*2+1); + int amin = finger_mincap(srcidx * 2); + int bmin = finger_mincap(srcidx * 2 + 1); + int rawpressure = finger_rawpressure(a-amin,b-bmin); + int rawpos = finger_rawpos(a, b); + int pos = rawpos, pressure = rawpressure; + +// if (pressure>500) DebugLog("%d %d\r\n", pressure, pos); + + // scale pos and pressure by calibration + const CalibResult* c = &calibresults[srcidx]; + if (c->pressure[0] != 0) { // if we dont have any calibration data, we just pass thru the raw values + int prev = c->pos[0] - (c->pos[1] - c->pos[0]); // extrapolate below 0 + int reversed = c->pos[7] < c->pos[0]; + int maxp; + if ((rawpos < prev) ^ reversed) { + pos = -128; + maxp = c->pressure[0]; + } + else { + pos = 8 * 256 + 128; + maxp = c->pressure[7]; + for (int x = 0; x <= 8; ++x) { + int next; + if (x == 8) next = c->pos[7] + (c->pos[7] - c->pos[6]); // extrapolate + else next = c->pos[x]; + if ((rawpos < next) ^ reversed) { + int diff = next-prev; + + int t = diff ? ((rawpos - prev) * 256) / diff : 0; + pos = x * 256 - 128 + t; + int prevp = c->pressure[maxi(0, x - 1)]; + int nextp = c->pressure[mini(7, x)]; + maxp = prevp + (((nextp - prevp) * t) >> 8); + break; + } + prev = next; + } + } + if (maxp < 1000) maxp = 1000; + pressure = (rawpressure * 4096) / maxp - 2048; + // if (pressure>100) DebugLog("%d %d\r\n", pressure, pos); + } + + int frame = finger_frame_ui; + ASSERT(frame >= 0 && frame < 8); + int prevframe = (frame - 1) & 7; + int fi = dstidx; + Finger* uif = &fingers_ui_time[fi][frame]; + Finger* prev_uif = &fingers_ui_time[fi][prevframe]; + uif->pressure = pressure; + //bool written = 0; + if (pressure > 0 && pressure > prev_uif->pressure - 128) { // not significantly lifting finger off + uif->pos = clampi(pos, 0, 2047); + //written = 1; + } + else + uif->pos = prev_uif->pos; + uif->written = 1;//written; + // else dont even write pos! let it be old random values + + + + if (enable_audio <= EA_OFF) { + return; + } + + if (fi == 8) { + Finger* oldf = &fingers_ui_time[fi][(frame-2)&7]; + int button = uif->pos>>8; + if (shift_down != SB_NOT_PRESSED) { + int oldpos = shift_down * 256 + 128; + if (abs(oldpos - uif->pos) < 192) // a bit of hysteresis + button = shift_down; + } + int midbutton = prev_uif->pos>>8; + int oldbutton = oldf->pos>>8; + bool valid=oldf->pressure>700 && uif->pressure>700 && abs(uif->pos-oldf->pos)<60; + if (shift_down == SB_NOT_PRESSED) + valid&= oldbutton==midbutton && button==oldbutton; + + if (valid) { + if (shift_down != button) { + // check for ghosted presses + Finger* f0 = touch_ui_getwriting(button); + Finger* fl = touch_ui_getwriting(maxi(0, button - 1)); + Finger* fr = touch_ui_getwriting(mini(7, button + 1)); + if ( + (f0->pressure > 256 && f0->pos >= 6 * 256) || + (fl->pressure > 256 && fl->pos >= 7 * 256) || + (fr->pressure > 256 && fr->pos >= 7 * 256)) + shift_down = SB_GHOSTED; // ghosted press! they have a finger on a nearby strip, maybe it was an accident. + else { + shift_down = button; + shift_down_time = 0; + on_shift_down(); + } + } + } else if (uif->pressure<=0) { + if (shift_down >= 0) + on_shift_up(button); + shift_down = SB_NOT_PRESSED; + } + if (shift_down >= 0) { + shift_down_time++; + on_shift_hold(button); + } + if (uif->pressure <= 0) + last_time_shift_was_untouched = ticks(); + + //DebugLog("%d %d %02x\r\n", maxi(0,pressure), valid ? button*256 : -256, finger_stepmask); + + } + else { + finger_editing(fi, finger_frame_ui); + finger_ui_done_this_frame |= 1 << fi; + } +} + +u32 fingererror=0; + +void touch_update(void) { +again: + waitcounter++; +#define MAX_STEPS 13 // 13 steps that generate 36 sensor readings. + static u8 const sensororder[MAX_STEPS][8] = { + { 0, 2, 4, 1, 3, 5, 16}, // first step does a group of first three touch + half of strip + { 6, 8,10, 7, 9,11, 17}, // second step does next 3 touch in a group + other half of step + {12,14, 13,15}, // third step does last 2 touch in a group + {18,19}, // remaining steps do single fingers at a time + {20,21}, + {22,23}, + {24,25}, + {26,27}, + {28,29}, + {30,31}, + {32,33}, + {34},{35} }; // this is actually two steps, doh pin wiring + // the bitmask version of the above table: + static u32 const chansio[MAX_STEPS] = {FF0 + FF1 + FF2 + FF8a,FF3 + FF4 + FF5 + FF8b, FF6 + FF7, FF0,FF1,FF2,FF3,FF4,FF5,FF6,FF7,FF8a,FF8b}; + static u32 const sampio[MAX_STEPS] = {SS0 + SS1 + SS2 + SS8a,SS3 + SS4 + SS5 + SS8b, SS6 + SS7, SS0,SS1,SS2,SS3,SS4,SS5,SS6,SS7,SS8a,SS8b }; + if (finger_state == 0) { + TSC_IOConfigTypeDef config={0}; + config.ChannelIOs= chansio[finger_step]; + config.SamplingIOs=sampio[finger_step]; + HAL_TSC_IOConfig(&htsc, &config); + HAL_TSC_IODischarge(&htsc, ENABLE); + finger_state++; + return; + } + if (finger_state == 1) { + finger_state++; + //return; // more discharge time ! + } + if (finger_state == 2) { + HAL_TSC_Start(&htsc); + finger_state++; + return; + } + u32 chans = chansio[finger_step]; + int subchan = 0; + bool errorstate=false; +#ifndef EMU + if (HAL_TSC_GetState(&htsc)==HAL_TSC_STATE_ERROR) { + errorstate=true; + } +#endif + for (int grp = 0; grp < 7; ++grp) { + if (!(chans & (0xf << (grp * 4)))) + continue; + TSC_GroupStatusTypeDef status = HAL_TSC_GroupGetStatus(&htsc, grp); + int oidx=sensororder[finger_step][subchan++]; + if (status != TSC_GROUP_COMPLETED) { + if (errorstate) { + fingererror|=(1<<oidx); + } + else + return;// not done yet + } + else { + fingererror&=~(1<<oidx); + } + short v = finger_raw[oidx] = (1<<23)/maxi(129, +#ifdef EMU + HAL_TSC_GroupGetValue(&htsc, oidx)); +#else + HAL_TSC_GroupGetValue(&htsc, grp)); +#endif +// if (oidx == 3 * 2 + 1) v = finger_min[1]; FAKE AN ERROR +// if (oidx == 4) v = finger_min[3]; // FAKE AN ERROR + if (v > finger_max[oidx]) + finger_max[oidx] = v; + if (v < finger_min[oidx]) + finger_min[oidx] = v; + //if (oidx == 34 || oidx == 35 || oidx == 16 || oidx == 17) { + // DebugLog("%d = %d\n", oidx, v); + //} + } + prevfingerediting = fingerediting; + HAL_TSC_Stop(&htsc); + // update fingers and decide next step + bool calib = (enable_audio == EA_OFF); + switch (finger_step) { + case 0: { // group of fingers 0,1,2 plus half of strip + finger_stepmask = 7; // always do the first 3 steps, doh + bool d0 = raw_isdown(0), d1 = raw_isdown(1), d2 = raw_isdown(2), d8 = raw_isdown(8); + int numdown = d0 + d1 + d2 + d8*2; + if (numdown <= 1 || calib) { + update_finger(0); + update_finger(1); + update_finger(2); + // do the shift finger in the next one + } + else { + if (d0) finger_stepmask |= 1 << (3 + 0); else update_finger(0); + if (d1) finger_stepmask |= 1 << (3 + 1); else update_finger(1); + if (d2) finger_stepmask |= 1 << (3 + 2); else update_finger(2); + } + } + break; + case 1: { // group of fingers 3,4,5 plus half of strip + bool d3 = raw_isdown(3), d4 = raw_isdown(4), d5 = raw_isdown(5), d8 = raw_isdown(8); + int numdown = d3 + d4 + d5 + d8 * 2; + if (numdown <= 1 || calib) { + update_finger(3); + update_finger(4); + update_finger(5); + update_finger(8); + } + else { + if (d3) finger_stepmask |= 1 << (3 + 3); else update_finger(3); + if (d4) finger_stepmask |= 1 << (3 + 4); else update_finger(4); + if (d5) finger_stepmask |= 1 << (3 + 5); else update_finger(5); + if (d8) finger_stepmask |= (1 << (3 + 8)) + (1 << (3 + 9)); else update_finger(8); // strip is two steps alas + } + } + break; + case 2: { // group of fingers 6,7 + bool d6 = raw_isdown(6), d7 = raw_isdown(7); + int numdown = d6 + d7; + if (numdown <= 1 || calib) { + update_finger(6); + update_finger(7); + } + else { + if (d6) finger_stepmask |= 1 << (3 + 6); else update_finger(6); + if (d7) finger_stepmask |= 1 << (3 + 7); else update_finger(7); + } + } + break; + default: // 3...10: individual fingers + update_finger(9 + finger_step - 3); + break; + case 11: // half of strip. do nothing :( + break; + case 12: // second half of strip! yay! + update_finger(9 + 8); + break; + } + finger_state = 0; + // find next step that is active + while (finger_step < MAX_STEPS) { + finger_step++; + if (calib) + break; + if (finger_stepmask & (1 << finger_step)) + break; + } + + // move on to next step! + if (finger_step == MAX_STEPS) { + finalwait = waitcounter; + waitcounter = 0; + finger_step = 0; + finger_frame_ui = (finger_frame_ui + 1) & 7; + finger_ui_done_this_frame=0; + } + goto again; +} + |
