static void filter_preproc_midichord(MidiFilter* self) { int c,k,i; int identical_cfg = 1; int newchord = 0; for (i=0; i < 10; ++i) { if ((*self->cfg[i+2]) != 0) newchord |= 1<<i; if (floor(self->lcfg[i+2]) != floor(*self->cfg[i+2])) { identical_cfg = 0; } } if (floor(self->lcfg[1]) != floor(*self->cfg[1])) { identical_cfg = 0; } if (identical_cfg) return; const int newscale = RAIL(floor(*self->cfg[1]), 0, 11); const int oldscale = RAIL(floor(self->lcfg[1]), 0, 11); for (c=0; c < 16; ++c) { for (k=0; k < 127; ++k) { if (self->memCM[c][k] == 0) continue; if (self->memCI[c][k] == -1000) continue; const uint8_t vel = self->memCM[c][k]; const int t0 = (k + 12 - oldscale) % 12; const int t1 = (k + 12 - newscale) % 12; const int oldchord = self->memCI[c][k]; int chord = newchord; if (! filter_midichord_isonscale(t1)) { chord = 1; } for (i=0; i < 10 ; ++i) { if ((chord & (1<<i)) == (oldchord & (1<<i)) && !(chord & (1<<i))) { continue; } if ((chord & (1<<i)) == (oldchord & (1<<i)) && (filter_midichord_halftoneoffset(t0, i) == filter_midichord_halftoneoffset(t1, i)) && t0 == t1) { continue; } if (oldchord & (1<<i)) { filter_midichord_noteoff(self, 0, c, k + filter_midichord_halftoneoffset(t0, i), 0); } if (chord & (1<<i)) { filter_midichord_noteon(self, 0, c, k + filter_midichord_halftoneoffset(t1, i), vel); } } self->memCI[c][k] = chord; } } }
static void filter_preproc_enforcescale(MidiFilter* self) { if (floorf(self->lcfg[1]) == floorf(*self->cfg[1])) return; const int scale = RAIL(floorf(*self->cfg[1]), 0, 11); int c,k; uint8_t buf[3]; buf[2] = 0; for (c=0; c < 16; ++c) { for (k=0; k < 127; ++k) { if (self->memCS[c][k] ==0) continue; if (filter_enforcescale_check(scale, k)) { self->memCI[c][k] = 0; continue; } buf[0] = MIDI_NOTEOFF | c; buf[1] = midi_limit_val(k); buf[2] = 0; forge_midimessage(self, 0, buf, 3); self->memCS[c][k] = 0; self->memCI[c][k] = 0; } } }
static void filter_preproc_keyrange(MidiFilter* self) { if ( floorf(self->lcfg[1]) == floorf(*self->cfg[1]) && floorf(self->lcfg[2]) == floorf(*self->cfg[2]) && floorf(self->lcfg[3]) == floorf(*self->cfg[3]) ) return; int c,k; uint8_t buf[3]; buf[2] = 0; const int mode = RAIL(floorf(*self->cfg[3]),0, 3); const uint8_t low = midi_limit_val(floorf(*self->cfg[1])); const uint8_t upp = midi_limit_val(floorf(*self->cfg[2])); for (c=0; c < 16; ++c) { for (k=0; k < 127; ++k) { const uint8_t vel = self->memCM[c][k]; if (vel == 0) continue; if (mode != 0 && (k >= low && k <= upp) ^ (mode == 2)) continue; buf[0] = MIDI_NOTEOFF | c; buf[1] = midi_limit_val(k + self->memCI[c][k]); forge_midimessage(self, 0, buf, 3); self->memCM[c][k] = 0; } } }
static void filter_preproc_mapkeyscale(MidiFilter* self) { int i; int identical_cfg = 1; int keymap[12]; for (i=0; i < 12; ++i) { keymap[i] = RAIL(floorf(*self->cfg[i+1]), -13, 12); if (floorf(self->lcfg[i+1]) != floorf(*self->cfg[i+1])) { identical_cfg = 0; } } if (identical_cfg) return; int c,k; uint8_t buf[3]; buf[2] = 0; for (c=0; c < 16; ++c) { for (k=0; k < 127; ++k) { int note; const int n = 1 + k%12; if (!self->memCM[c][k]) continue; if (floorf(self->lcfg[n]) == floorf(*self->cfg[n])) continue; note = k + self->memCI[c][k]; if (midi_valid(note)) { note = midi_limit_val(note); if (self->memCS[c][note] > 0) { self->memCS[c][note]--; if (self->memCS[c][note] == 0) { buf[0] = MIDI_NOTEOFF | c; buf[1] = note; buf[2] = 0; forge_midimessage(self, 0, buf, 3); } } } note = k + keymap[k%12]; if (midi_valid(note)) { note = midi_limit_val(note); buf[0] = MIDI_NOTEON | c; buf[1] = note; buf[2] = self->memCM[c][k]; self->memCI[c][k] = note - k; self->memCS[c][note]++; if (self->memCS[c][note] == 1) { forge_midimessage(self, 0, buf, 3); } } else { self->memCM[c][k] = 0; self->memCI[c][k] = -1000; } } } }
static void filter_preproc_ntabdelay(MidiFilter* self) { int i,c,k; if (*self->cfg[4] != 0 && self->lcfg[4] == 0) for (c=0; c < 16; ++c) for (k=0; k < 127; ++k) { self->memCM[c][k] = 0; // remember velocity of note-on self->memCI[c][k] = -1; // remember time of note-on } float newbpm = MAX(*self->cfg[2], 1.0); if (*self->cfg[1] && (self->available_info & NFO_BPM)) { newbpm = self->bpm; } if (newbpm <= 0) newbpm = 60; if (self->memF[0] == newbpm && *self->cfg[2] == self->lcfg[2]) return; const float oldbpm = self->memF[0]; self->memF[0] = newbpm; const float old_grid = RAIL((self->lcfg[3]), 1/256.0, 4.0); const double old_samples_per_beat = 60.0 / oldbpm * self->samplerate; const float new_grid = RAIL((*self->cfg[3]), 1/256.0, 4.0); const double new_samples_per_beat = 60.0 / newbpm * self->samplerate; const double fact = (new_grid * new_samples_per_beat) / (old_grid * old_samples_per_beat); const int max_delay = self->memI[0]; const int roff = self->memI[1]; const int woff = self->memI[2]; for (i=0; i < max_delay; ++i) { const int off = (i + roff) % max_delay; if (self->memQ[off].size > 0) { self->memQ[off].reltime = rint(self->memQ[off].reltime * fact); } if (off == woff) break; } }
static void filter_midi_keyrange(MidiFilter* self, uint32_t tme, const uint8_t* const buffer, uint32_t size) { const int mode = RAIL(floorf(*self->cfg[3]),0, 3); const uint8_t chs = midi_limit_chn(floorf(*self->cfg[0]) -1); const uint8_t chn = buffer[0] & 0x0f; uint8_t mst = buffer[0] & 0xf0; if (size != 3 || !(mst == MIDI_NOTEON || mst == MIDI_NOTEOFF) || !(floorf(*self->cfg[0]) == 0 || chs == chn) || mode == 0 ) { forge_midimessage(self, tme, buffer, size); return; } const uint8_t low = midi_limit_val(floorf(*self->cfg[1])); const uint8_t upp = midi_limit_val(floorf(*self->cfg[2])); const uint8_t key = buffer[1] & 0x7f; const uint8_t vel = buffer[2] & 0x7f; if (mst == MIDI_NOTEON && vel ==0 ) { mst = MIDI_NOTEOFF; } switch(mst) { case MIDI_NOTEON: if ((key >= low && key <= upp) ^ (mode == 2)) { forge_midimessage(self, tme, buffer, size); self->memCM[chn][key] = vel; } break; case MIDI_NOTEOFF: if (self->memCM[chn][key] > 0) { forge_midimessage(self, tme, buffer, size); } self->memCM[chn][key] = 0; break; } }
void filter_midi_sostenuto(MidiFilter* self, const uint32_t tme, const uint8_t* const buffer, const uint32_t size) { const uint8_t chs = midi_limit_chn(floorf(*self->cfg[0]) -1); const uint32_t delay = floor(self->samplerate * RAIL((*self->cfg[1]), 0, 120)); const int pedal = RAIL(*self->cfg[2], 0, 2); int state; const uint8_t chn = buffer[0] & 0x0f; const uint8_t vel = buffer[2] & 0x7f; uint8_t mst = buffer[0] & 0xf0; /* pedal CC 64 -- TODO make CC (and theshold) configurable !? */ if (size == 3 && mst == MIDI_CONTROLCHANGE && (buffer[1]) == 64) { self->memI[16 + chn] = vel > 63 ? 1 : 0; } if (size != 3 || !(mst == MIDI_NOTEON || mst == MIDI_NOTEOFF) || !(floorf(*self->cfg[0]) == 0 || chs == chn) ) { forge_midimessage(self, tme, buffer, size); return; } switch(pedal) { default: case 0: state = 0; break; case 1: state = 1; break; case 2: state = self->memI[16 + chn]; break; } if (mst == MIDI_NOTEON && vel ==0 ) { mst = MIDI_NOTEOFF; } if (size == 3 && mst == MIDI_NOTEON && state == 1) { const uint8_t chn = buffer[0] & 0x0f; const uint8_t key = buffer[1] & 0x7f; if (sostenuto_check_dup(self, chn, key, -1)) { /* note was already on, * send note off + immediate note on, again */ uint8_t buf[3]; buf[0] = MIDI_NOTEOFF | chn; buf[1] = key; buf[2] = 0; forge_midimessage(self, tme, buf, size); } forge_midimessage(self, tme, buffer, size); } else if (size == 3 && mst == MIDI_NOTEOFF && state == 1) { const uint8_t chn = buffer[0] & 0x0f; const uint8_t key = buffer[1] & 0x7f; if (!sostenuto_check_dup(self, chn, key, tme + delay)) { // queue note-off if not already queued MidiEventQueue *qm = &(self->memQ[self->memI[2]]); memcpy(qm->buf, buffer, size); qm->size = size; qm->reltime = tme + delay; self->memI[2] = (self->memI[2] + 1) % self->memI[0]; } } else { forge_midimessage(self, tme, buffer, size); } /* only note-off are queued in the buffer. * Interleave delay-buffer with messages sent in-process above * to retain sequential order. */ self->memI[3] = tme + 1; filter_postproc_sostenuto(self); self->memI[3] = -1; }
static void filter_preproc_sostenuto(MidiFilter* self) { int i; const int max_delay = self->memI[0]; const int roff = self->memI[1]; const int woff = self->memI[2]; const int pedal = RAIL(*self->cfg[2], 0, 2); int state; if (self->lcfg[1] == *self->cfg[1] && (self->lcfg[2] == *self->cfg[2] && self->lcfg[2] < 2)) { /* no change: same pedal state for all channels and same time */ for (i=32; i < 48; ++i) { /* remember per channel pedal state */ self->memI[i] = pedal & 1; } return; } /* adjust time if changed || per-channel pedal state */ const float diff = *self->cfg[1] - self->lcfg[1]; const int delay = rint(self->samplerate * diff); for (i=0; i < max_delay; ++i) { const int off = (i + roff) % max_delay; if (pedal == 2) { const uint8_t chn = self->memQ[off].buf[0] & 0x0f; const int ostate = self->memI[32 + chn]; state = self->memI[16 + chn]; if (self->lcfg[1] == *self->cfg[1] && state == ostate) { /* no change: same pedal state for this channels and same time */ if (off == woff) break; continue; } } else { state = pedal & 1; } if (self->memQ[off].size > 0) { if (state == 0) { self->memQ[off].reltime = 0; } else { self->memQ[off].reltime = MAX(0, self->memQ[off].reltime + delay); } } if (off == woff) break; } self->memI[3] = 1; filter_postproc_sostenuto(self); self->memI[3] = -1; /* remember per channel pedal state */ for (i=16; i < 32; ++i) { if (pedal < 2) { self->memI[16+i] = pedal & 1; } else { self->memI[16+i] = self->memI[i]; } } }
static void filter_midi_enforcescale(MidiFilter* self, uint32_t tme, const uint8_t* const buffer, uint32_t size) { const int chs = midi_limit_chn(floorf(*self->cfg[0]) -1); const int scale = RAIL(floorf(*self->cfg[1]), 0, 11); const int mode = RAIL(floorf(*self->cfg[2]), 0, 2); const uint8_t chn = buffer[0] & 0x0f; const uint8_t key = buffer[1] & 0x7f; uint8_t mst = buffer[0] & 0xf0; if (midi_is_panic(buffer, size)) { filter_enforcescale_panic(self, chn, tme); } if (size != 3 || !(mst == MIDI_NOTEON || mst == MIDI_NOTEOFF || mst == MIDI_POLYKEYPRESSURE) || !(floorf(*self->cfg[0]) == 0 || chs == chn) ) { forge_midimessage(self, tme, buffer, size); return; } int transp = 0; if (!filter_enforcescale_check(scale, key)) { switch (mode) { case 1: transp = -1; break; case 2: transp = +1; break; case 0: /* discard */ default: return; } } if (!midi_valid(key + transp)) { return; } if (!filter_enforcescale_check(scale, key + transp)) { return; } int note; uint8_t buf[3]; memcpy(buf, buffer, 3); switch (mst) { case MIDI_NOTEON: note = key + transp; if (midi_valid(note)) { buf[1] = note; self->memCS[chn][note]++; if (self->memCS[chn][note] == 1) forge_midimessage(self, tme, buf, size); } self->memCI[chn][key] = transp; break; case MIDI_NOTEOFF: note = key + self->memCI[chn][key]; if (midi_valid(note)) { buf[1] = note; if (self->memCS[chn][note] > 0) { self->memCS[chn][note]--; if (self->memCS[chn][note] == 0) forge_midimessage(self, tme, buf, size); self->memCI[chn][key] = 0; } } break; case MIDI_POLYKEYPRESSURE: note = key + transp; if (midi_valid(note)) { buf[1] = note; forge_midimessage(self, tme, buf, size); } break; } }
static void run(LV2_Handle instance, uint32_t n_samples) { XfadeControl* self = (XfadeControl*)instance; const float xfade = *self->xfade; const float shape = RAIL(*self->shape, 0.0, 1.0); const int mode = (int) RAIL(*self->mode, 0.0, 1.0); const uint32_t fade_len = (n_samples >= FADE_LEN) ? FADE_LEN : n_samples; float gain[IPORTS]; float gainP[IPORTS]; float gainL[IPORTS]; if (mode == 1) { /* V-fade - non overlapping */ if (xfade < 0) { gainL[0] = 1.0; gainP[0] = 1.0; gainL[1] = 1.0 + RAIL(xfade, -1.0, 0.0); gainP[1] = sqrt(1.0 + RAIL(xfade, -1.0, 0.0)); } else if (xfade > 0) { gainL[0] = 1.0 - RAIL(xfade, 0.0, 1.0); gainP[0] = sqrt(1.0 - RAIL(xfade, 0.0, 1.0)); gainL[1] = 1.0; gainP[1] = 1.0; } else { gainL[0] = 1.0; gainL[1] = 1.0; gainP[0] = 1.0; gainP[1] = 1.0; } } else { /* X-fade overlapping */ gainL[1] = 0.5 + RAIL(xfade, -1.0, 1.0)/2.0; gainL[0] = 1.0 - gainL[1]; /* equal power gain */ if (xfade == -1.0) { gainP[0] = 1.0; gainP[1] = 0.0; } else if (xfade == 1.0) { gainP[0] = 0.0; gainP[1] = 1.0; } else { gainP[1] = sqrt(.5 + RAIL(xfade/2.0, -.5, .5)); gainP[0] = sqrt(.5 - RAIL(xfade/2.0, -.5, .5)); } } gain[0] = shape * gainP[0] + (1.0 - shape) * gainL[0]; gain[1] = shape * gainP[1] + (1.0 - shape) * gainL[1]; #if 0 // debug #define VALTODB(V) (20.0f * log10f(V)) printf("%.2fdB %.2fdB ||A: %.2f %.2f || B: %.2f %.2f || s:%.2f m:%d\n", VALTODB(gain[0]), VALTODB(gain[1]), gainL[0], gainL[1], gainP[0], gainP[1], shape, mode ); #endif for (int c = 0; c < CHANNELS; ++c) { uint32_t pos = 0; if (self->c_amp[0] == gain[0] && self->c_amp[1] == gain[1]) { for (pos = 0; pos < n_samples; pos++) { self->output[c][pos] = self->input[0][c][pos] * gain[0] + self->input[1][c][pos] * gain[1]; } } else { for (pos = 0; pos < n_samples; pos++) { self->output[c][pos] = self->input[0][c][pos] * SMOOTHGAIN(self->c_amp[0], gain[0]) + self->input[1][c][pos] * SMOOTHGAIN(self->c_amp[1], gain[1]); } } } self->c_amp[0] = gain[0]; self->c_amp[1] = gain[1]; }
static void filter_midi_mapkeyscale(MidiFilter* self, uint32_t tme, const uint8_t* const buffer, uint32_t size) { int i; const int chs = midi_limit_chn(floorf(*self->cfg[0]) -1); int keymap[12]; for (i=0; i < 12; ++i) { keymap[i] = RAIL(floorf(*self->cfg[i+1]), -13, 12); } const uint8_t chn = buffer[0] & 0x0f; uint8_t mst = buffer[0] & 0xf0; if (midi_is_panic(buffer, size)) { filter_mapkeyscale_panic(self, chn, tme); } if (size != 3 || !(mst == MIDI_NOTEON || mst == MIDI_NOTEOFF || mst == MIDI_POLYKEYPRESSURE) || !(floorf(*self->cfg[0]) == 0 || chs == chn) ) { forge_midimessage(self, tme, buffer, size); return; } const uint8_t key = buffer[1] & 0x7f; const uint8_t vel = buffer[2] & 0x7f; if (mst == MIDI_NOTEON && vel ==0 ) { mst = MIDI_NOTEOFF; } int note; uint8_t buf[3]; memcpy(buf, buffer, 3); switch (mst) { case MIDI_NOTEON: if (keymap[key%12] < -12) return; note = key + keymap[key%12]; // TODO keep track of dup result note-on -- see enforcescale.c if (midi_valid(note)) { buf[1] = note; self->memCS[chn][note]++; if (self->memCS[chn][note] == 1) { forge_midimessage(self, tme, buf, size); } self->memCM[chn][key] = vel; self->memCI[chn][key] = note - key; } break; case MIDI_NOTEOFF: note = key + self->memCI[chn][key]; if (midi_valid(note)) { buf[1] = note; if (self->memCS[chn][note] > 0) { self->memCS[chn][note]--; if (self->memCS[chn][note] == 0) forge_midimessage(self, tme, buf, size); } } self->memCM[chn][key] = 0; self->memCI[chn][key] = -1000; break; case MIDI_POLYKEYPRESSURE: if (keymap[key%12] < -12) return; note = key + keymap[key%12]; if (midi_valid(note)) { buf[1] = note; forge_midimessage(self, tme, buf, size); } break; } }
static void filter_midi_midichord(MidiFilter* self, uint32_t tme, const uint8_t* const buffer, uint32_t size) { int i; const int chs = midi_limit_chn(floor(*self->cfg[0]) -1); const int scale = RAIL(floor(*self->cfg[1]), 0, 11); int chord = 0; for (i=0; i < 10 ; ++i) { if ((*self->cfg[i+2]) != 0) chord |= 1<<i; } const uint8_t chn = buffer[0] & 0x0f; uint8_t mst = buffer[0] & 0xf0; if (midi_is_panic(buffer, size)) { filter_midichord_panic(self, chn, tme); } if (size != 3 || !(mst == MIDI_NOTEON || mst == MIDI_NOTEOFF || mst == MIDI_POLYKEYPRESSURE) || !(floor(*self->cfg[0]) == 0 || chs == chn) ) { forge_midimessage(self, tme, buffer, size); return; } const uint8_t key = buffer[1] & 0x7f; const uint8_t vel = buffer[2] & 0x7f; const int tonika = (key + 12 - scale) % 12; if (! filter_midichord_isonscale(tonika)) { chord = 1; } switch (mst) { case MIDI_NOTEON: self->memCI[chn][key] = chord; self->memCM[chn][key] = vel; for (i=0; i < 10 ; ++i) { if (!(chord & (1<<i))) continue; filter_midichord_noteon(self, tme, chn, key + filter_midichord_halftoneoffset(tonika, i), vel); } break; case MIDI_NOTEOFF: chord = self->memCI[chn][key]; for (i=0; i < 10 ; ++i) { if (!(chord & (1<<i))) continue; filter_midichord_noteoff(self, tme, chn, key + filter_midichord_halftoneoffset(tonika, i), vel); } self->memCI[chn][key] = -1000; self->memCM[chn][key] = 0; break; case MIDI_POLYKEYPRESSURE: for (i=0; i < 10 ; ++i) { uint8_t buf[3]; if (!(chord & (1<<i))) continue; int note = key + filter_midichord_halftoneoffset(tonika, i); if (midi_valid(note)) { buf[0] = buffer[0]; buf[1] = note; buf[2] = buffer[2]; forge_midimessage(self, tme, buf, size); } } break; } }
static void run(LV2_Handle instance, uint32_t n_samples) { uint32_t i,c; BalanceControl* self = (BalanceControl*)instance; const float balance = *self->balance; const float trim = db_to_gain(*self->trim); float gain_left = 1.0; float gain_right = 1.0; const int ascnt = self->samplerate / UPDATE_FREQ; const uint32_t capacity = self->notify->atom.size; lv2_atom_forge_set_buffer(&self->forge, (uint8_t*)self->notify, capacity); lv2_atom_forge_sequence_head(&self->forge, &self->frame, 0); /* reset after state restore */ if (self->queue_stateswitch) { self->queue_stateswitch = 0; self->peak_integrate_pref = self->state[0] * self->samplerate; self->meter_falloff = self->state[1] / UPDATE_FREQ; self->peak_hold = self->state[2] * UPDATE_FREQ; self->peak_integrate_pref = MAX(0, self->peak_integrate_pref); self->peak_integrate_pref = MIN(self->peak_integrate_pref, self->peak_integrate_max); self->meter_falloff = MAX(0, self->meter_falloff); self->meter_falloff = MIN(self->meter_falloff, 1000); self->peak_hold = MAX(0, self->peak_hold); self->peak_hold = MIN(self->peak_hold, 60 * UPDATE_FREQ); reset_uicom(self); send_cfg_to_ui(self); } /* Process incoming events from GUI */ if (self->control) { LV2_Atom_Event* ev = lv2_atom_sequence_begin(&(self->control)->body); while(!lv2_atom_sequence_is_end(&(self->control)->body, (self->control)->atom.size, ev)) { if (ev->body.type == self->uris.atom_Blank || ev->body.type == self->uris.atom_Object) { const LV2_Atom_Object* obj = (LV2_Atom_Object*)&ev->body; if (obj->body.otype == self->uris.blc_meters_on) { if (self->uicom_active == 0) { reset_uicom(self); send_cfg_to_ui(self); self->uicom_active = 1; } } if (obj->body.otype == self->uris.blc_meters_off) { self->uicom_active = 0; } if (obj->body.otype == self->uris.blc_meters_cfg) { const LV2_Atom* key = NULL; const LV2_Atom* value = NULL; lv2_atom_object_get(obj, self->uris.blc_cckey, &key, self->uris.blc_ccval, &value, 0); if (value && key) { update_meter_cfg(self, ((LV2_Atom_Int*)key)->body, ((LV2_Atom_Float*)value)->body); } } } ev = lv2_atom_sequence_next(ev); } } /* pre-calculate parameters */ if (balance < 0) { gain_right = 1.0 + RAIL(balance, -1.0, 0.0); } else if (balance > 0) { gain_left = 1.0 - RAIL(balance, 0.0, 1.0); } switch ((int) *self->unitygain) { case 1: { /* maintain amplitude sum */ const double gaindiff = (gain_left - gain_right); gain_left = 1.0 + gaindiff; gain_right = 1.0 - gaindiff; } break; case 2: { /* equal power*/ if (balance < 0) { gain_right = MAX(.5, gain_right); gain_left = db_to_gain(-gain_to_db(gain_right)); } else { gain_left = MAX(.5, gain_left); gain_right = db_to_gain(-gain_to_db(gain_left)); } } case 0: /* 'tradidional' balance */ break; } if (*(self->phase[C_LEFT])) gain_left *=-1; if (*(self->phase[C_RIGHT])) gain_right *=-1; /* keep track of input levels -- only if GUI is visiable */ if (self->uicom_active) { for (c=0; c < CHANNELS; ++c) { for (i=0; i < n_samples; ++i) { /* input peak meter */ const float ps = fabsf(self->input[c][i]); if (ps > self->p_peak_in[c]) self->p_peak_in[c] = ps; if (self->peak_integrate_pref < 1) { const float psm = ps * ps; if (psm > self->p_peak_inM[c]) self->p_peak_inM[c] = psm; continue; } /* integrated level, peak */ const int pip = (self->peak_integrate_pos + i ) % self->peak_integrate_pref; const double p_sig = SQUARE(self->input[c][i]); self->p_peak_inP[c] += p_sig - self->p_peak_inPi[c][pip]; self->p_peak_inPi[c][pip] = p_sig; /* peak of integrated signal */ const float psm = self->p_peak_inP[c] / (double) self->peak_integrate_pref; if (psm > self->p_peak_inM[c]) self->p_peak_inM[c] = psm; } } } /* process audio -- delayline + balance & gain */ process_channel(self, gain_left * trim, C_LEFT, n_samples); process_channel(self, gain_right * trim, C_RIGHT, n_samples); /* swap/assign channels */ uint32_t pos = 0; if (self->c_monomode != (int) *self->monomode) { /* smooth change */ const uint32_t fade_len = (n_samples >= FADE_LEN) ? FADE_LEN : n_samples; for (; pos < fade_len; pos++) { const float gain = (float)pos / (float)fade_len; float x1[CHANNELS], x2[CHANNELS]; channel_map_change(self, self->c_monomode, pos, x1); channel_map_change(self, (int) *self->monomode, pos, x2); self->output[C_LEFT][pos] = x1[C_LEFT] * (1.0 - gain) + x2[C_LEFT] * gain; self->output[C_RIGHT][pos] = x1[C_RIGHT] * (1.0 - gain) + x2[C_RIGHT] * gain; } } channel_map(self, (int) *self->monomode, pos, n_samples); self->c_monomode = (int) *self->monomode; /* audio processing done */ if (!self->uicom_active) { return; } /* output peak meter */ for (c=0; c < CHANNELS; ++c) { for (i=0; i < n_samples; ++i) { /* peak */ const float ps = fabsf(self->output[c][i]); if (ps > self->p_peak_out[c]) self->p_peak_out[c] = ps; if (self->peak_integrate_pref < 1) { const float psm = ps * ps; if (psm > self->p_peak_outM[c]) self->p_peak_outM[c] = psm; continue; } /* integrated level, peak */ const int pip = (self->peak_integrate_pos + i ) % self->peak_integrate_pref; const double p_sig = SQUARE(self->output[c][i]); self->p_peak_outP[c] += p_sig - self->p_peak_outPi[c][pip]; self->p_peak_outPi[c][pip] = p_sig; /* peak of integrated signal */ const float psm = self->p_peak_outP[c] / (double) self->peak_integrate_pref; if (psm > self->p_peak_outM[c]) self->p_peak_outM[c] = psm; } } if (self->peak_integrate_pref > 0) { self->peak_integrate_pos = (self->peak_integrate_pos + n_samples ) % self->peak_integrate_pref; } /* simple output phase correlation */ for (i=0; i < n_samples; ++i) { const double p_pos = SQUARE(self->output[C_LEFT][i] + self->output[C_RIGHT][i]); const double p_neg = SQUARE(self->output[C_LEFT][i] - self->output[C_RIGHT][i]); /* integrate over 500ms */ self->p_phase_outP += p_pos - self->p_phase_outPi[self->phase_integrate_pos]; self->p_phase_outN += p_neg - self->p_phase_outNi[self->phase_integrate_pos]; self->p_phase_outPi[self->phase_integrate_pos] = p_pos; self->p_phase_outNi[self->phase_integrate_pos] = p_neg; self->phase_integrate_pos = (self->phase_integrate_pos + 1) % self->phase_integrate_max; } /* abs peak hold */ #define PKM(A,CHN,ID) \ { \ const float peak = VALTODB(self->p_peak_##A[CHN]); \ if (peak > self->p_max_##A[CHN]) { \ self->p_max_##A[CHN] = peak; \ self->p_tme_##A[CHN] = 0; \ forge_kvcontrolmessage(&self->forge, &self->uris, ID, self->p_max_##A[CHN]); \ } else if (self->peak_hold <= 0) { \ (self->p_tme_##A[CHN])=0; /* infinite hold */ \ } else if (self->p_tme_##A[CHN] <= self->peak_hold) { \ (self->p_tme_##A[CHN])++; \ } else if (self->meter_falloff == 0) { \ self->p_max_##A[CHN] = peak; \ forge_kvcontrolmessage(&self->forge, &self->uris, ID, self->p_max_##A[CHN]); \ } else { \ self->p_max_##A[CHN] -= self->meter_falloff; \ self->p_max_##A[CHN] = MAX(peak, self->p_max_##A[CHN]); \ forge_kvcontrolmessage(&self->forge, &self->uris, ID, self->p_max_##A[CHN]); \ } \ } /* RMS meter */ #define PKF(A,CHN,ID) \ { \ float dbp = VALTODB(sqrt(2.0 * self->p_peak_##A##M[CHN])); \ if (dbp > self->p_vpeak_##A[CHN]) { \ self->p_vpeak_##A[CHN] = dbp; \ } else if (self->meter_falloff == 0) { \ self->p_vpeak_##A[CHN] = dbp; \ } else { \ self->p_vpeak_##A[CHN] -= self->meter_falloff; \ self->p_vpeak_##A[CHN] = MAX(dbp, self->p_vpeak_##A[CHN]); \ } \ forge_kvcontrolmessage(&self->forge, &self->uris, ID, (self->p_vpeak_##A [CHN])); \ } /* report peaks to UI */ self->p_peakcnt += n_samples; if (self->p_peakcnt > ascnt) { PKF(in, C_LEFT, METER_IN_LEFT) PKF(in, C_RIGHT, METER_IN_RIGHT); PKF(out, C_LEFT, METER_OUT_LEFT); PKF(out, C_RIGHT, METER_OUT_RIGHT); PKM(in, C_LEFT, PEAK_IN_LEFT); PKM(in, C_RIGHT, PEAK_IN_RIGHT); PKM(out, C_LEFT, PEAK_OUT_LEFT); PKM(out, C_RIGHT, PEAK_OUT_RIGHT); #define RMSF(A) sqrt( ( (A) / (double)self->phase_integrate_max ) + 1.0e-12 ) double phase = 0.0; const double phasdiv = self->p_phase_outP + self->p_phase_outN; if (phasdiv >= 1.0e-6) { phase = (RMSF(self->p_phase_outP) - RMSF(self->p_phase_outN)) / RMSF(phasdiv); } else if (self->p_phase_outP > .001 && self->p_phase_outN > .001) { phase = 1.0; } forge_kvcontrolmessage(&self->forge, &self->uris, PHASE_OUT, phase); self->p_peakcnt -= ascnt; for (c=0; c < CHANNELS; ++c) { self->p_peak_in[c] = -INFINITY; self->p_peak_out[c] = -INFINITY; self->p_peak_inM[c] = -INFINITY; self->p_peak_outM[c] = -INFINITY; } } /* report values to UI - if changed*/ float bal = gain_to_db(fabsf(gain_left)); if (bal != self->p_bal[C_LEFT]) { forge_kvcontrolmessage(&self->forge, &self->uris, GAIN_LEFT, bal); } self->p_bal[C_LEFT] = bal; bal = gain_to_db(fabsf(gain_right)); if (bal != self->p_bal[C_RIGHT]) { forge_kvcontrolmessage(&self->forge, &self->uris, GAIN_RIGHT, bal); } self->p_bal[C_RIGHT] = bal; if (self->p_dly[C_LEFT] != self->c_dly[C_LEFT]) { forge_kvcontrolmessage(&self->forge, &self->uris, DELAY_LEFT, (float) self->c_dly[C_LEFT] / self->samplerate); } self->p_dly[C_LEFT] = self->c_dly[C_LEFT]; if (self->p_dly[C_RIGHT] != self->c_dly[C_RIGHT]) { forge_kvcontrolmessage(&self->forge, &self->uris, DELAY_RIGHT, (float) self->c_dly[C_RIGHT] / self->samplerate); } self->p_dly[C_RIGHT] = self->c_dly[C_RIGHT]; }
static void filter_midistrum_process(MidiFilter* self, int tme) { int i; const int max_collect = 1 + rintf(self->samplerate * (*self->cfg[3]) / 1000.0); if (self->memI[5] == 0) return; // no notes collected if (MSC_DIFF(self->memI[3], self->memI[4]) + tme < 0) { /* collection time not over */ if (self->memI[5] < MAX_STRUM_CHORDNOTES) { /* buffer is not full, either */ return; } } float bpm = (*self->cfg[1]); if (*self->cfg[0] && (self->available_info & NFO_BPM)) { bpm = self->bpm; } if (bpm <= 0) bpm = 60; const int strum_time = floor(self->samplerate * (*self->cfg[4]) * 60.0 / bpm); int dir = 0; // 0: down (low notes first), 1: up (high-notes first) switch ((int) floorf(*self->cfg[2])) { case 0: // always down break; case 1: // always up dir = 1; break; case 2: // alternate dir = (self->memI[6]) ? 1 : 0; break; case 3: // depending on beat.. 1,2,3,4 down ;; 1+,2+,3+,4+ up if ((self->available_info & NFO_BEAT)) { const double samples_per_beat = 60.0 / self->bpm * self->samplerate; if (ROUND_PARTIAL_BEATS(self->beat_beats + ((tme - max_collect) / samples_per_beat), 12.0) >= 0.5) { dir = 1; } } break; case 4: // depending on 8th if ((self->available_info & NFO_BEAT)) { const double samples_per_beat = 60.0 / self->bpm * self->samplerate; const float pos = ROUND_PARTIAL_BEATS(self->beat_beats + ((tme - max_collect) / samples_per_beat), 16.0) * 2.0; if ( pos - floorf(pos) >= 0.5) { dir = 1; } } break; } self->memI[6] = !dir; int reltime = MSC_DIFF(self->memI[4], self->memI[3]); int tdiff = strum_time / self->memI[5]; float spdcfg = -(*self->cfg[5]); float velcfg = (*self->cfg[6]) / -112.0; spdcfg += (*self->cfg[7]) * (2.0 * random() / (float)RAND_MAX - 1.0); velcfg += (*self->cfg[8]) * (2.0 * random() / (float)RAND_MAX - 1.0); spdcfg = RAIL(spdcfg, -1.0, 1.0); const float veladj = RAIL(velcfg, -1.0, 1.0); const float spdadj = fabsf(spdcfg); const int spddir = spdcfg < 0 ? 1 : 0; /* sort notes by strum direction.. */ for (i=0; i < self->memI[5]; ++i) { int nextup = -1; int ii; for (ii=0; ii < self->memI[5]; ++ii) { if (self->memS[ii].size == 0) continue; if (nextup < 0) { nextup = ii; continue;} if (dir) { if (self->memS[nextup].buf[1] < self->memS[ii].buf[1] ) nextup = ii; } else { if (self->memS[nextup].buf[1] > self->memS[ii].buf[1] ) nextup = ii; } } if ((self->memI[2] + 1) % self->memI[0] == self->memI[1]) { break; } /* velocity adjustment */ int vel = self->memS[nextup].buf[2] & 0x7f; const float p0 = (float)(i+1.0) / (float)(self->memI[5] + 1.0); vel -= fabsf(veladj) * 56.0; if (veladj < 0) vel += fabsf(veladj) * 112.0 * p0; else vel += fabsf(veladj) * 112.0 * (1.0 - p0); self->memS[nextup].buf[2] = RAIL(vel, 1, 127); /* speed adjustment */ const float p1 = (float)(i+1.0) / (float)(self->memI[5]); float sfact = pow(spdadj+1.0, p1) - spdadj; if (spddir) { sfact = sfact ==0 ? 0 : 1.0 / sqrt(sfact); } MidiEventQueue *qm = &(self->memQ[self->memI[2]]); memcpy(qm->buf, self->memS[nextup].buf, self->memS[nextup].size); qm->size = self->memS[nextup].size; qm->reltime = reltime + rint((float)(tdiff * i) * sfact); self->memI[2] = (self->memI[2] + 1) % self->memI[0]; self->memS[nextup].size = 0; // mark as processed } self->memI[5] = 0; }
void filter_midi_ntabdelay(MidiFilter* self, const uint32_t tme, const uint8_t* const buffer, const uint32_t size) { int i; float bpm = MAX(*self->cfg[2], 1.0); if (*self->cfg[1] && (self->available_info & NFO_BPM)) { bpm = self->bpm; } if (bpm <= 0) bpm = 60; if (midi_is_panic(buffer, size)) { filter_ntapdelay_panic(self, buffer[0]&0x0f, tme); } forge_midimessage(self, tme, buffer, size); const uint8_t chs = midi_limit_chn(floor(*self->cfg[0]) -1); const uint8_t chn = buffer[0] & 0x0f; uint8_t mst = buffer[0] & 0xf0; if (size != 3 || !(mst == MIDI_NOTEON || mst == MIDI_NOTEOFF || mst == MIDI_POLYKEYPRESSURE) || !(floor(*self->cfg[0]) == 0 || chs == chn) ) { return; } if ((self->memI[2] + 1) % self->memI[0] == self->memI[1]) { return; } const float grid = RAIL((*self->cfg[3]), 1/256.0, 4.0); const double samples_per_beat = 60.0 / bpm * self->samplerate; const uint8_t key = buffer[1] & 0x7f; const uint8_t vel = buffer[2] & 0x7f; uint8_t buf[3]; memcpy(buf, buffer, 3); /* treat note-on w/velocity==0 as note-off */ if (mst == MIDI_NOTEON && vel == 0) { mst = MIDI_NOTEOFF; buf[0] = MIDI_NOTEOFF | chn; } if (mst == MIDI_NOTEON) { self->memCI[chn][key] = tme + rint(grid * samples_per_beat); self->memCM[chn][key] = vel; } else if (mst == MIDI_NOTEOFF) { self->memCI[chn][key] = -1; self->memCM[chn][key] = 0; } for (i=0; i < RAIL(*self->cfg[4], 0, 128); ++i) { int delay = rint( grid * samples_per_beat * (i+1.0)); buf[2] = RAIL(rint(vel + (i+1.0) * (*self->cfg[5])), 1, 127); MidiEventQueue *qm = &(self->memQ[self->memI[2]]); memcpy(qm->buf, buf, 3); qm->size = size; qm->reltime = tme + delay; self->memI[2] = (self->memI[2] + 1) % self->memI[0]; if ((self->memI[2] + 1) % self->memI[0] == self->memI[1]) { return; } } }
static void filter_postproc_ntabdelay(MidiFilter* self) { int i,c,k; const int max_delay = self->memI[0]; const int roff = self->memI[1]; const int woff = self->memI[2]; const uint32_t n_samples = self->n_samples; int skipped = 0; float bpm = MAX(*self->cfg[2], 1.0); if (*self->cfg[1] && (self->available_info & NFO_BPM)) { bpm = self->bpm; } if (bpm <= 0) bpm = 60; const float grid = RAIL((*self->cfg[3]), 1/256.0, 4.0); const double samples_per_beat = 60.0 / bpm * self->samplerate; /* add note-on/off for held notes.. * TODO: use a preallocated stack-like structure */ if (*self->cfg[4] == 0) for (c=0; c < 16; ++c) for (k=0; k < 127; ++k) { if (self->memCM[c][k] == 0) continue; if (self->memCI[c][k] >= n_samples) { self->memCI[c][k] -= n_samples; continue; } while (1) { self->memCM[c][k] = RAIL(rint(self->memCM[c][k] + (*self->cfg[5])), 1, 127); /* enqueue note-off + note-on */ MidiEventQueue *qm = &(self->memQ[self->memI[2]]); qm->buf[0] = MIDI_NOTEOFF | c; qm->buf[1] = k; qm->buf[2] = 0; qm->size = 3; qm->reltime = self->memCI[c][k]; self->memI[2] = (self->memI[2] + 1) % self->memI[0]; if ((self->memI[2] + 1) % self->memI[0] == self->memI[1]) { self->memCI[c][k] += ceil(grid * samples_per_beat); break; } qm = &(self->memQ[self->memI[2]]); qm->buf[0] = MIDI_NOTEON | c; qm->buf[1] = k; qm->buf[2] = self->memCM[c][k]; qm->size = 3; qm->reltime = self->memCI[c][k]; self->memI[2] = (self->memI[2] + 1) % self->memI[0]; if ((self->memI[2] + 1) % self->memI[0] == self->memI[1]) { self->memCI[c][k] += ceil(grid * samples_per_beat); break; } self->memCI[c][k] += ceil(grid * samples_per_beat); if (self->memCI[c][k] >= n_samples) { break; } } self->memCI[c][k] -= n_samples; } /* dequeue delayline */ for (i=0; i < max_delay; ++i) { const int off = (i + roff) % max_delay; if (self->memQ[off].size > 0) { if (self->memQ[off].reltime < n_samples) { if (self->memQ[off].size == 3 && (self->memQ[off].buf[0] & 0xf0) == MIDI_NOTEON) { const uint8_t chn = self->memQ[off].buf[0] & 0x0f; const uint8_t key = self->memQ[off].buf[1] & 0x7f; self->memCS[chn][key]++; if (self->memCS[chn][key] > 1) { // send a note-off first uint8_t buf[3]; buf[0] = MIDI_NOTEOFF | chn; buf[1] = key; buf[2] = 0; forge_midimessage(self, self->memQ[off].reltime, buf, 3); } forge_midimessage(self, self->memQ[off].reltime, self->memQ[off].buf, self->memQ[off].size); } else if (self->memQ[off].size == 3 && (self->memQ[off].buf[0] & 0xf0) == MIDI_NOTEOFF) { const uint8_t chn = self->memQ[off].buf[0] & 0x0f; const uint8_t key = self->memQ[off].buf[1] & 0x7f; if (self->memCS[chn][key] > 0) { self->memCS[chn][key]--; if (self->memCS[chn][key] == 0) { forge_midimessage(self, self->memQ[off].reltime, self->memQ[off].buf, self->memQ[off].size); } } } else { forge_midimessage(self, self->memQ[off].reltime, self->memQ[off].buf, self->memQ[off].size); } self->memQ[off].size = 0; if (!skipped) self->memI[1] = (self->memI[1] + 1) % max_delay; } else { self->memQ[off].reltime -= n_samples; skipped = 1; } } else if (!skipped) self->memI[1] = off; if (off == woff) break; } }