#pragma once u8 arpbits; // the output of the arpeggiator - which fingers are down bool arpretrig; // causes the notes to re-attack s8 curarpfinger; s8 arpoctave; u8 arpdir; s8 arp_nonpedalfinger; u8 arpused,arpused2; s8 arpmode; s32 freearpclock; #ifdef WIN32 int __builtin_popcount(int x) { int c = 0; while (x) { c++; x &= x - 1; } return c; } int __builtin_popcountll(unsigned long long x) { int c = 0; while (x) { c++; x &= x - 1; } return c; } int __builtin_ctzll(unsigned long long x) { if (!x) return 64; int c = 0; while (!(x&(1ull<= curarpfinger); } u8 nextdown(u8 allowedfingers) { s8 prevarpfinger = curarpfinger; while (1) { curarpfinger = (curarpfinger - 1) & 7; if (allowedfingers & (1 << curarpfinger)) break; } return (prevarpfinger <= curarpfinger); } void arp_reset_impl(bool partial) { // a 'partial' reset is used when it panics that none of the fingers that are down match the currently set arp bits. #ifdef EMU if (curarpfinger >= 0) EmuDebugLog("!!ARP RESET\r\n"); #endif arpretrig = false; arp_rhythm.trigcount = 0; arpbits = 0; arpused = 0; arpused2 = 0; arp_nonpedalfinger = -2; freearpclock = 0; arp_divide_counter = 0; ticks_since_arp = 0; if (!partial) { curarpfinger = -1; arpoctave = 0; arpdir = 0; } } void arp_reset(void) { arp_reset_impl(false); } static inline void arp_reset_partial(void) { arp_reset_impl(true); } bool euclidstuff(euclid_state *s, int patlen, int prob, int arpmode) { int aprob = clampi((abs(prob) + 256) >> 9, 0, 128); int apatlen = abs(patlen); bool click; if (apatlen <= 1) { if (arpmode == ARP_ALL) click = true; else click = (rand() & 127) < aprob; } else { float k = aprob * (1.f / 128.f); //arpeuclid / (float) (abspatlen); click = (floor(s->trigcount * k) != floor(s->trigcount * k - k)); // euclidian rhythms! } // printf("%d: %d\n", arptrigcount, arpretrig); s->trigcount++; //arpretrig = true; bool step; // do we go to the next step? if (apatlen > 0) { s->trigcount %= apatlen; } if ((patlen < 0) ^ (prob < 0)) { // if patlen or prob are negative, then we clock at a regular rate but silence some steps step = true; s->supress = !click; } else { // if they're both pos (or neg), then we simply clock at the erratic rate. step = click; int gatelen = param_eval_int(P_GATE_LENGTH, any_rnd, env16, pressure16) >> 8; bool do_you_want_silence_in_long_bits = gatelen < 256; s->supress = do_you_want_silence_in_long_bits ? !click : false; } s->did_a_retrig = click; // if (!click) { // int i = 1; // } return step; } bool arpupwards(u8 allowedfingers, int minoctave, int maxoctave) { bool wrap = nextup(allowedfingers); if (wrap) { if (++arpoctave > maxoctave) { if (arpmode == ARP_UPDOWN || arpmode == ARP_PEDALUPDOWN) { arpdir = 1; arpoctave = maxoctave; nextdown(allowedfingers); nextdown(allowedfingers); } else if (arpmode == ARP_UPDOWNREP || arpmode == ARP_UPDOWN8) { arpdir = 1; arpoctave = maxoctave; nextdown(allowedfingers); } else arpoctave = minoctave; } } return wrap; } bool arpdownwards(u8 allowedfingers, int minoctave, int maxoctave) { bool wrap = nextdown(allowedfingers); if (wrap) { if (--arpoctave < minoctave) { if (arpmode == ARP_UPDOWN || arpmode == ARP_PEDALUPDOWN) { arpdir = 0; arpoctave = minoctave; nextup(allowedfingers); nextup(allowedfingers); } else if (arpmode == ARP_UPDOWNREP || arpmode == ARP_UPDOWN8) { arpdir = 0; arpoctave = minoctave; nextup(allowedfingers); } else arpoctave = maxoctave; } } return wrap; } void arprandom(u8 allowedfingers, int minoctave, int maxoctave) { arpoctave = minoctave + (rand() % (maxoctave + 1 - minoctave)); u8 left = allowedfingers & ~arpused; if (left == 0) { arpused = 0; left = allowedfingers; } curarpfinger = -1; arpbits = pickrandombit(left); arpused |= arpbits; if (arpmode == ARP_RANDOM2 || arpmode == ARP_RANDOM28) { // pick a second random! u8 left = allowedfingers & ~arpused2; left &= ~(1 << curarpfinger); if (left == 0) { arpused2 = 0; left = allowedfingers & ~(1 << curarpfinger); } if (left) { u8 bit = pickrandombit(left); arpused2 |= bit; arpbits |= bit; } } } extern int audiotime; void arptrig(u8 fingerdown_music) { // try to find a higher finger if (fingerdown_music == 0) { arp_reset(); return; } int arpoctaves = param_eval_int(P_ARPOCT, any_rnd, env16, pressure16); int arppatlen = param_eval_int(P_ARPLEN, any_rnd, env16, pressure16); int prob = param_eval_int(P_ARPPROB, any_rnd, env16, pressure16); bool arpstep = euclidstuff(&arp_rhythm, arppatlen, prob, arpmode); arpretrig = arp_rhythm.did_a_retrig; #ifdef EMU static int pt = 0; int delta = audiotime - pt; if (delta > 2048 && pt) { int i = 1; } pt = audiotime; EmuDebugLog("arp %d %d %d\r\n", arpstep, arpretrig,delta); #endif if (!arpstep) return; arpbits = 0; u8 allowedfingers = fingerdown_music; if (arpmode >= ARP_UP8) allowedfingers = 0xff; int maxoctave = (arpoctaves+1) / 2; int minoctave = maxoctave - arpoctaves; switch (arpmode) { default: return; case ARP_ALL: arpbits = allowedfingers; // in chord mode, with no euclid rhythm, we randomly drop chord notes if (abs(arppatlen) <= 1) { int aprob = abs(prob); for (int i = 0; i < 8; ++i) if (arpbits & (1 << i)) { bool click = (rand() & 32767) < (aprob>>1); if (!click) arpbits ^= (1 << i); } } break; case ARP_PEDALDOWN: case ARP_PEDALUP: case ARP_PEDALUPDOWN: { if (arp_nonpedalfinger >= 0 && allowedfingers & (1 << arp_nonpedalfinger)) { //for pedal, if we have a remembered arpfinger, we just play that curarpfinger = arp_nonpedalfinger; arp_nonpedalfinger = -2; } else { //otherwise we are due to play the pedal, we instead remove the pedal note from the allowed fingers //then we do the logic as usual u8 allowed_no_pedal = allowedfingers & (allowedfingers - 1); if (allowed_no_pedal == 0) allowed_no_pedal = allowedfingers; if (arpmode == ARP_PEDALDOWN || (arpmode == ARP_PEDALUPDOWN && arpdir)) arpdownwards(allowed_no_pedal, minoctave, maxoctave); else arpupwards(allowed_no_pedal, minoctave, maxoctave); // actually, we're gonna play the pedal! wooahahah arp_nonpedalfinger = curarpfinger; arpbits = allowedfingers ^ allowed_no_pedal; curarpfinger = -1; } break; } case ARP_UPDOWN: case ARP_UPDOWN8: case ARP_UPDOWNREP: if (arpdir) arpdownwards(allowedfingers, minoctave, maxoctave); else arpupwards(allowedfingers, minoctave, maxoctave); break; case ARP_UP: case ARP_UP8: arpupwards(allowedfingers,minoctave,maxoctave); break; case ARP_DOWN: case ARP_DOWN8: arpdownwards(allowedfingers, minoctave, maxoctave); break; case ARP_RANDOM: case ARP_RANDOM8: case ARP_RANDOM2: case ARP_RANDOM28: arprandom(allowedfingers,minoctave,maxoctave); break; } if (arp_rhythm.supress) arpbits = 0; else if (curarpfinger >= 0 && curarpfinger < 8) { arpbits |= 1 << curarpfinger; } synthfingertrigger |= arpbits; } void seq_reset(void ) { ticks_since_step = 0; seq_divide_counter = 0; seq_rhythm.trigcount = 0; seq_used_bits = 0; seq_dir = 0; } void seq_step(int initial) { // initial means - this is the initial clock pulse when switching into play mode int seqpatlen = param_eval_int(P_SEQLEN, any_rnd, env16, pressure16); int prob = param_eval_int(P_SEQPROB, any_rnd, env16, pressure16); bool controlled_by_gatecv = seqdiv < 0; if (initial>0) { arp_reset(); seq_divide_counter = 0; ticks_since_step = 0; seq_used_bits |= ((uint64_t)1) << (cur_step & 63); if (!controlled_by_gatecv) { bool seqretrig = euclidstuff(&seq_rhythm, seqpatlen, prob, -1); (void)seqretrig; } return; } seq_divide_counter++; if (initial>=0) if (seq_divide_counter <= seqdiv || controlled_by_gatecv) // if initial is negative, we FORCE a step return; seq_divide_counter = 0; // EmuDebugLog("last_step_period %d\n", last_step_period); last_step_period = ticks_since_step; ticks_since_step = 0; seq_divide_counter = 0; int prevstep = cur_step; if (!isplaying()) { seq_rhythm.did_a_retrig = false; } else { // playing! // actually advance! bool seqretrig = euclidstuff(&seq_rhythm, seqpatlen, prob, -1); if (!seqretrig) return; u8 loopstart_step = (rampreset.loopstart_step_no_offset + step_offset) & 63; int seqmode = param_eval_int(P_SEQMODE, any_rnd, env16, pressure16); switch (seqmode) { default: case SEQ_FWD: set_cur_step(cur_step + 1, true); if (cur_step <= prevstep) OnLoop(); break; case SEQ_BACK: set_cur_step(cur_step - 1, true); if (cur_step >= prevstep) OnLoop(); break; case SEQ_PAUSE: break; case SEQ_PINGPONG: { bool looped = false; int end = rampreset.looplen_step + loopstart_step - 1; if (seq_dir == 0 && cur_step >= end) { seq_dir = 1; looped = true; } else if (seq_dir == 1 && cur_step <= loopstart_step) { seq_dir = 0; looped = true; } set_cur_step(cur_step + (seq_dir ? -1 : 1), true); if (looped) OnLoop(); break; } case SEQ_PINGPONGREP: { int end = rampreset.looplen_step + loopstart_step - 1; if (seq_dir == 0 && cur_step >= end) { seq_dir = 1; set_cur_step(end, true); OnLoop(); } else if (seq_dir == 1 && cur_step <= loopstart_step) { seq_dir = 0; set_cur_step(loopstart_step, true); OnLoop(); } else set_cur_step(cur_step + (seq_dir ? -1 : 1), true); break; } case SEQ_RANDOM: { int len = rampreset.looplen_step & 63; uint64_t mask = len ? (((uint64_t)1) << len) - 1 : ~0ull; uint64_t bits = mask & ~(seq_used_bits >> loopstart_step); // bitmask of which steps we are allowed to choose from bool looped = false; if (!bits) { seq_used_bits = 0; bits = mask; // reset! looped = true; } int n = bits ? rand() % __builtin_popcountll(bits) : 1; // pick a random bit number while (n-- > 0) bits &= bits - 1; // peel off the bits int step = bits ? __builtin_ctzll(bits) : 0; set_cur_step(loopstart_step + step, true); if (looped) OnLoop(); break; } } seq_used_bits |= ((uint64_t)1) << (cur_step & 63); if (playmode == PLAY_WAITING_FOR_CLOCK_STOP) { playmode = PLAY_STOPPED; seq_rhythm.did_a_retrig = false; } } } void update_arp(bool clock) { arpretrig = false; // bool called_trig = false; arpmode = ((rampreset.flags & FLAGS_ARP)) ? param_eval_int(P_ARPMODE, any_rnd, env16, pressure16) : -1; if (arpmode>=0 && !isgrainpreview()) { int div = param_eval_int(P_ARPDIV, any_rnd, env16, pressure16); if (div < 0) { u32 dclock = (u32)(table_interp(pitches, 32768 + (-div >> 2)) * (1 << 24)); freearpclock -= dclock; clock = freearpclock < 0; if (clock) { freearpclock += 1<<31; arp_divide_counter = 0; } div = 0; } else { div = divisions[(clampi(div, 0,65535) * DIVISIONS_MAX) >>16]-1; } if (arp_divide_counter > div) arp_divide_counter = 0; if (clock) { if (arp_divide_counter <= 0) { // called_trig = true; last_arp_period = ticks_since_arp; /* if (last_arp_period < 31 || last_arp_period>32) { EmuDebugLog("arp %d\r\n", last_arp_period); int i = 1; } */ ticks_since_arp = 0; arptrig(synthfingerdown_nogatelen); arp_divide_counter = 0; } arp_divide_counter++; } } } void OnGotReset(void) { u8 loopstart_step = (rampreset.loopstart_step_no_offset + step_offset) & 63; set_cur_step(loopstart_step, false); bpm_clock_phase = 0; seq_reset(); arp_reset(); seq_step(1); OnLoop(); } extern volatile u8 gotclkin; volatile u8 gotclkin=0; int update_clock(void) { // returns 1 for clock, 2 for half clock, 0 for neither tick++; bool gotclock = false; //////////////////////////////////////////// eurorack clock input // int gate_input_max = 65536; static u8 prevgotclk=0; u8 newgotclk=gotclkin; if(newgotclk!=prevgotclk) { prevgotclk=newgotclk; gotclock=true; external_clock_enable=true; } /* for (int i = 0; i < ADC_SAMPLES * ADC_CHANS; i += ADC_CHANS) { if (adcbuf[i + ADC_CLK] <= 0) clk_in_high = true; if (adcbuf[i + ADC_RESET] <= 0) reset_in_high = true; gate_input_max = mini(gate_input_max, adcbuf[i + ADC_GATE]); } */ if (/*(reset_in_high && !reset_in_high_prev) || */got_ui_reset) { // TODO - if audio in level is turned down, look for pulses? OnGotReset(); } else if (playmode == PLAYING && seqdiv < 0 && getgatesense()) { // gate cv controls step static bool curgate_digital = true; float curgate = GetADCSmoothed(ADC_GATE); float thresh = curgate_digital ? 0.01f : 0.02f; bool newgate_digital = curgate > thresh; if (newgate_digital && !curgate_digital) { seq_step(-1); // force a step } curgate_digital = newgate_digital; } got_ui_reset = false; // clk_in_high_prev = clk_in_high; // reset_in_high_prev = reset_in_high; #define ACCURATE_FS 31250 //////////////////////////////////////////// intenral clock if (!external_clock_enable) { bpm10x = ((param_eval_int(P_TEMPO, any_rnd, env16, pressure16) * 1200) >> 16) + 1200; u32 dclock = ((1 << 18) * bpm10x) / ((ACCURATE_FS * 600 / 32) / BLOCK_SAMPLES); bpm_clock_phase += dclock; if (bpm_clock_phase > 1 << 21) { bpm_clock_phase &= (1 << 21) - 1; gotclock = true; } //if (playmode == PLAY_WAITING_FOR_CLOCK) { // bpm_clock_phase = 0; // gotclock = true; //} } ////////////////////////////////////////////////////// clock advance ticks_since_clock++; ticks_since_step++; ticks_since_arp++; // if (playmode == PLAY_PREVIEW && shift_down==SB_PLAY) -- maybe eat a single clock if the finger is still down? if (!gotclock) { if (ticks_since_clock == last_clock_period / 2) { SetOutputCVClk(0); seq_step(0); return 2; } return 0; } SetOutputCVClk(65535); if (external_clock_enable) { // figure out bpm from the external clock's last 2 periods float avgclockperiod_per_sec = (ticks_since_clock + last_clock_period) * (0.5f * BLOCK_SAMPLES / ACCURATE_FS); float guessed_bpm = (1200.f / 8.f) / maxf(1.f / 16.f, avgclockperiod_per_sec); guessed_bpm+=(bpm10x-guessed_bpm)*(1.f-0.2f); // smooth it a bit bpm10x = (int)(guessed_bpm+0.5f); } last_clock_period = ticks_since_clock; ticks_since_clock = 0; int initial = 0; if (playmode == PLAY_WAITING_FOR_CLOCK_START) { playmode = PLAYING; initial = 1; // also sync the arp! arp_reset(); } seq_step(initial); return true; }