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 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; } }
void filter_midi_midistrum(MidiFilter* self, const uint32_t tme, const uint8_t* const buffer, const uint32_t size) { uint8_t mst = buffer[0] & 0xf0; if (size > 3) { forge_midimessage(self, tme, buffer, size); return; } if (midi_is_panic(buffer, size)) { filter_midistrum_panic(self, buffer[0]&0x0f, tme); } if (size != 3 || !(mst == MIDI_NOTEON || mst == MIDI_NOTEOFF)) { if ((self->memI[2] + 1) % self->memI[0] == self->memI[1]) { return; // queue full } MidiEventQueue *qm = &(self->memQ[self->memI[2]]); memcpy(qm->buf, buffer, size); qm->size = size; qm->reltime = tme; self->memI[2] = (self->memI[2] + 1) % self->memI[0]; 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); const int max_collect = 1 + rintf(self->samplerate * (*self->cfg[3]) / 1000.0); const uint8_t key = buffer[1] & 0x7f; const uint8_t vel = buffer[2] & 0x7f; if (mst == MIDI_NOTEON && vel ==0 ) { mst = MIDI_NOTEOFF; } // check if we're overdue -> process collected notes, reset collection mode filter_midistrum_process(self, tme); /* add note-ons to collection */ if (mst == MIDI_NOTEON) { int i; if (self->memI[5] == 0) { self->memI[4] = (tme + max_collect + self->memI[3]) % MSC_MAX; } #if 0 if ((self->available_info & NFO_BEAT)) { const double samples_per_beat = 60.0 / self->bpm * self->samplerate; printf("NOTE ON: %ld, %f || %f\n", self->pos_frame + tme, self->bar_beats + (float)tme / samples_per_beat, self->beat_beats + (float)tme / samples_per_beat); } #endif // check if note-on for this key is already queued -> skip for (i=0; i < self->memI[5]; ++i) { if (self->memS[i].size == 3 && self->memS[i].buf[2] == key) { return; } } MidiEventQueue *qm = &(self->memS[self->memI[5]]); memcpy(qm->buf, buffer, size); qm->size = size; self->memI[5]++; } /* delay note-off by max-latency (= collection-time + strum-time) */ else if (mst == MIDI_NOTEOFF) { #if 0 // TODO -- shorten delay time IF possible int delay = strum_time + 1; if (self->memI[5] > 0) { delay += 1 + MSC_DIFF(self->memI[4], (self->memI[3] + tme)%MSC_MAX); printf("add.. %d\n" , MSC_DIFF(self->memI[4], (self->memI[3] + tme)%MSC_MAX)); } #else const int delay = strum_time + max_collect; #endif // TODO filter out ignored dups from (ignored note-on) above 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]; } }
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; } }
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; } } }