Exemple #1
0
void
filter_midi_onechannelfilter(MidiFilter* self,
		uint32_t tme,
		const uint8_t* const buffer,
		uint32_t size)
{
	if (size > 3) {
		forge_midimessage(self, tme, buffer, size);
		return;
	}

	int chn = buffer[0]&0x0f;
	switch (buffer[0] & 0xf0) {
		case MIDI_NOTEOFF:
		case MIDI_NOTEON:
		case MIDI_POLYKEYPRESSURE:
		case MIDI_CONTROLCHANGE:
		case MIDI_PROGRAMCHANGE:
		case MIDI_CHANNELPRESSURE:
		case MIDI_PITCHBEND:
			if (rintf(*(self->cfg[0])) == chn + 1) {
				forge_midimessage(self, tme, buffer, size);
			}
			break;
		default:
			forge_midimessage(self, tme, buffer, size);
			break;
	}
}
static void filter_preproc_miditranspose(MidiFilter* self) {
	if (floor(self->lcfg[1]) == floor(*self->cfg[1])) return;
	const int transp = rint(*(self->cfg[1]));

	int c,k;
	uint8_t buf[3];
	buf[2] = 0;
	for (c=0; c < 16; ++c) {
#if 0 /* send "all notes off" */
		buf[0] = MIDI_CONTROLCHANGE | c;
		buf[1] = 123;
		forge_midimessage(self, tme, buf, 3);

		// send "all sound off"
		buf[0] = 0xb0 | i;
		buf[1] = 120;
		forge_midimessage(self, tme, buf, 3);
#else /* re-transpose playing notes */
		for (k=0; k < 127; ++k) {
			if (!self->memCM[c][k]) continue;

			buf[0] = MIDI_NOTEOFF | c;
			buf[1] = midi_limit_val(k + self->memCI[c][k]);
			buf[2] = 0;
			forge_midimessage(self, 0, buf, 3);

			buf[0] = MIDI_NOTEON | c;
			buf[1] = midi_limit_val(k + transp);
			buf[2] = self->memCM[c][k];
			self->memCI[c][k] = transp;
			forge_midimessage(self, 0, buf, 3);
		}
#endif
	}
}
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;
			}
		}
	}
}
Exemple #4
0
/* *****************************************************************************
 * the actual "process" function, called for every midi event
 */
static void
filter_midimessage (MidiMap* self,
                    uint32_t tme,
                    const uint8_t* const mmsg,
                    const uint32_t size)
{
	if (!self->rules || size > MAX_MSG) {
		/* just foward */
		forge_midimessage (self, tme, mmsg, size);
		return;
	}

	bool matched = false;

	// TODO if "match-all" is set, use tree with masked status-bit as
	// 1st level hash-table
	const unsigned int rc = self->rules->count;
	for (unsigned int i = 0; i < rc; ++i) {
		Rule *r = &self->rules->rule[i];
		uint8_t msg[MAX_MSG];
		uint32_t b;

		if ((r->len != size)) {
			continue;
		}
		bool match = true;
		for (b = 0; b < size && match; ++b) {
			// TODO also allow >= or <= comparators
			if ((mmsg[b] & r->mask[b]) != r->match[b]) {
				match = false;
			}
		}
		if (!match) {
			continue;
		}

		for (b = 0; b < r->len; ++b) {
			// TODO also allow += and *= operators
			// and map bytes ?
			msg[b] = (mmsg[b] & r->tx_mask[b]) | r->tx_set[b];
		}
		for (;b < r->tx_len; ++b) {
			msg[b] = r->tx_set[b];
		}

		forge_midimessage (self, tme, msg, r->tx_len);
		matched = true;
		if (!self->rules->match_all) {
			break;
		}
	}

	if (!matched && self->rules->forward_unmatched) {
		forge_midimessage (self, tme, mmsg, size);
	}
}
Exemple #5
0
static void
filter_postproc_midistrum(MidiFilter* self)
{
	int i;
	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;

	filter_midistrum_process(self, n_samples);

	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;
	}

	self->memI[3] = (self->memI[3] + n_samples)%MSC_MAX;
}
Exemple #6
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;
		}
	}
}
Exemple #7
0
static void
filter_postproc_sostenuto(MidiFilter* self)
{
	int i;
	const int max_delay = self->memI[0];
	const int roff = self->memI[1];
	const int woff = self->memI[2];
	uint32_t n_samples = self->n_samples;
	int skipped = 0;

	/* only process until given time */
	if (self->memI[3] > 0)
		n_samples = MIN(self->memI[3], n_samples);

	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) {
				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 {
				/* don't decrement time if called from filter_midi_sostenuto() */
				if (self->memI[3] < 0) {self->memQ[off].reltime -= n_samples;}
				skipped = 1;
			}
		} else if (!skipped) self->memI[1] = off;

		if (off == woff) break;
	}
}
Exemple #8
0
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;
		}
	}
}
Exemple #9
0
static inline void filter_midistrum_panic(MidiFilter* self, const uint8_t c, const uint32_t tme) {
	int i,k;
	const int max_delay = self->memI[0];
	for (i=0; i < max_delay; ++i) {
		if (self->memQ[i].size == 3
				&& (self->memQ[i].buf[0] & 0xf0) != 0xf0
				&& (self->memQ[i].buf[0] & 0x0f) != c)
			continue;
		self->memQ[i].size = 0;
	}

	self->memI[4] = 0; // collection stattime
	self->memI[5] = 0; // collected notes
	self->memI[6] = 0; // stroke direction

	for (k=0; k < 127; ++k) {
		if (self->memCS[c][k]) {
			uint8_t buf[3];
			buf[0] = MIDI_NOTEOFF | c;
			buf[1] = k; buf[2] = 0;
			forge_midimessage(self, tme, buf, 3);
		}
		self->memCS[c][k] = 0; // count note-on per key
	}
}
Exemple #10
0
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;
	}
}
Exemple #11
0
static inline void filter_midichord_noteon(MidiFilter* self, uint32_t tme, uint8_t chn, int note, uint8_t vel) {
	uint8_t buf[3];
	if (!midi_valid(note)) return;
	buf[0] = MIDI_NOTEON | chn;
	buf[1] = note;
	buf[2] = vel;
	self->memCS[chn][note]++;
	if (self->memCS[chn][note] == 1) {
		forge_midimessage(self, tme, buf, 3);
	}
}
Exemple #12
0
static inline void filter_enforcescale_panic(MidiFilter* self, const uint8_t c, const uint32_t tme) {
	int k;
	for (k=0; k < 127; ++k) {
		if (self->memCS[c][k] > 0) {
			uint8_t buf[3];
			buf[0] = MIDI_NOTEOFF | c;
			buf[1] = k;
			buf[2] = 0;
			forge_midimessage(self, tme, buf, 3);
		}
		self->memCI[c][k] = 0; // current key transpose
		self->memCS[c][k] = 0; // count note-on per key
	}
}
Exemple #13
0
static inline void filter_midichord_panic(MidiFilter* self, const uint8_t c, const uint32_t tme) {
	int k;
	for (k=0; k < 127; ++k) {
		if (self->memCS[c][k] > 0) {
			uint8_t buf[3];
			buf[0] = MIDI_NOTEOFF | c;
			buf[1] = k;
			buf[2] = 0;
			forge_midimessage(self, tme, buf, 3);
		}
		self->memCI[c][k] = -1000; // current chord for this key
		self->memCS[c][k] = 0; // count note-on per key
		self->memCM[c][k] = 0; // last known velocity for this key
	}
}
Exemple #14
0
static void mctl_cb(int fnid, const char *fn, unsigned char val, midiCCmap *mm, void *arg) {
  B3S* b3s = (B3S*)arg;
#ifdef DEBUGPRINT
  fprintf(stderr, "xfn: %d (\"%s\", %d) mm:%s\n", fnid, fn, val, mm?"yes":"no");
#endif
  if (b3s->midiout && mm) {
    while (mm) {
#ifdef DEBUGPRINT
      fprintf(stderr, "MIDI FEEDBACK %d %d %d\n", mm->channel, mm->param, val);
#endif
      uint8_t msg[3];
      msg[0] = 0xb0 | (mm->channel&0x0f); // Control Change
      msg[1] = mm->param;
      msg[2] = val;
      forge_midimessage(&b3s->forge, &b3s->uris, msg, 3);
      mm = mm->next;
    }
  }
  if (b3s->midiout && fn && !b3s->suspend_ui_msg) {
    forge_kvcontrolmessage(&b3s->forge, &b3s->uris, fn, (int32_t) val);
  }
}
static inline void filter_ntapdelay_panic(MidiFilter* self, const uint8_t c, const uint32_t tme) {
	int i,k;
	const int max_delay = self->memI[0];
	for (i=0; i < max_delay; ++i) {
		if (self->memQ[i].size == 3
				&& (self->memQ[i].buf[0] & 0xf0) != 0xf0
				&& (self->memQ[i].buf[0] & 0x0f) != c)
			continue;
		self->memQ[i].size = 0;
	}

	for (k=0; k < 127; ++k) {
		if (self->memCS[c][k]) {
			uint8_t buf[3];
			buf[0] = MIDI_NOTEOFF | c;
			buf[1] = k; buf[2] = 0;
			forge_midimessage(self, tme, buf, 3);
		}
		self->memCS[c][k] = 0; // count note-on per key post-delay
		self->memCM[c][k] = 0; // remember velocity of note-on
		self->memCI[c][k] = -1; // remember time of note-on
	}
}
Exemple #16
0
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;
	}
}
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;
		}
	}
}
Exemple #18
0
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_miditranspose(MidiFilter* self,
		uint32_t tme,
		const uint8_t* const buffer,
		uint32_t size)
{
	const int chs = midi_limit_chn(floor(*self->cfg[0]) -1);
	const int transp = rint(*(self->cfg[1]));

	const uint8_t chn = buffer[0] & 0x0f;
	const uint8_t key = buffer[1] & 0x7f;
	const uint8_t vel = buffer[2] & 0x7f;
	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)
		 )
	{
		forge_midimessage(self, tme, buffer, size);
		return;
	}

	if (mst == MIDI_NOTEON && vel ==0 ) {
		mst = MIDI_NOTEOFF;
	}

	int note;
	uint8_t buf[3];

	buf[0] = buffer[0];
	buf[1] = buffer[1];
	buf[2] = buffer[2];

	switch (mst) {
		case MIDI_NOTEON:
			note = key + transp;
			if (midi_valid(note)) {
				buf[1] = note;
				forge_midimessage(self, tme, buf, size);
			}
			self->memCM[chn][key] = vel;
			self->memCI[chn][key] = transp;
			break;
		case MIDI_NOTEOFF:
			note = key + self->memCI[chn][key];
			if (midi_valid(note)) {
				buf[1] = note;
				forge_midimessage(self, tme, buf, size);
			}
			self->memCM[chn][key] = 0;
			self->memCI[chn][key] = -1000;
			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;
	}
}
Exemple #21
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;
	}
}
Exemple #22
0
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_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;
	}
}