Exemplo n.º 1
0
/*****************************************************************************
 * process_all_notes_off()
 *
 * Process all notes off for a single channel.  The events for each channel
 * should have been queued once for each engine already.
 *****************************************************************************/
void
process_all_notes_off(MIDI_EVENT *event, unsigned int part_num)
{
	PART            *part = get_part(part_num);
	VOICE           *voice;
	unsigned int    voice_num;
	int             j;

	PHASEX_DEBUG(DEBUG_CLASS_MIDI_EVENT, "*** All notes off!  Part %d:  event_type=0x%02x\n",
	             (part_num + 1), event->type);

	/* let engine shut off notes gracefully */
	for (voice_num = 0; voice_num < (unsigned int) setting_polyphony; voice_num++) {
		voice = get_voice(part_num, voice_num);
		voice->keypressed = -1;
	}

	/* re-initialize this part's keylists */
	part->head     = NULL;
	part->cur      = NULL;
	part->prev     = NULL;
	part->midi_key = -1;
	part->prev_key = -1;

	/* re-initialize this part's keylist nodes */
	for (j = 0; j < 128; j++) {
		part->keylist[j].midi_key = (short) j;
		part->keylist[j].next     = NULL;
	}
}
Exemplo n.º 2
0
/*****************************************************************************
 * process_program_change()
 *
 * TODO: handle bank and program select controller messages.
 *****************************************************************************/
void
process_program_change(MIDI_EVENT *event, unsigned int part_num)
{
	PHASEX_DEBUG(DEBUG_CLASS_MIDI_EVENT, "-- Program Change:  Part %d:  %d %d\n",
	             (part_num + 1), event->program, event->value);

	midi_select_program(part_num, event->program);
}
Exemplo n.º 3
0
/*****************************************************************************
 * process_all_sound_off()
 *
 * Process all sound off for a single channel by first turning off all notes
 * and then zeroing out all audio buffers.  This event should have already
 * been queued once for each engine already.
 *****************************************************************************/
void
process_all_sound_off(MIDI_EVENT *event, unsigned int part_num)
{
	PHASEX_DEBUG(DEBUG_CLASS_MIDI_EVENT, "*** All notes off!  Part %d:  event_type=0x%02x\n",
	             (part_num + 1), event->type);

	process_all_notes_off(event, part_num);

	init_engine_buffers();
}
Exemplo n.º 4
0
/*****************************************************************************
 * process_controller()
 *
 * TODO:  Before the if-else (or even switch-case) logic gets too much
 * bigger, it would be better to use a lookup table with processing function
 * pointers.
 *****************************************************************************/
void
process_controller(MIDI_EVENT *event, unsigned int part_num)
{
	PARAM           *param;
	unsigned char   j;
	unsigned char   cc; /* last controller touched for midimap updates  */
	int             id; /* parameter id, used for finding callbacks */

	/* get controller number */
	cc = event->controller & 0x7F;

	PHASEX_DEBUG(DEBUG_CLASS_MIDI_TIMING,
	             DEBUG_COLOR_GREEN "ccccc %d:%d=%d ccccc " DEBUG_COLOR_DEFAULT,
	             (part_num + 1), cc, event->value);

	/* 0x78-0x7F (120-127) are channel mode messages. */
	/* for now, just shut notes off */
	/* TODO: polyphony modes needs to map to these */
	if (cc >= 0x78) {
		if (cc == 0x78) {
			process_all_sound_off(event, part_num);
		}
		else {
			process_all_notes_off(event, part_num);
		}
	}
	else if (cc == MIDI_CONTROLLER_HOLD_PEDAL) {
		process_hold_pedal(event, part_num);
	}
	else {

		/* now walk through the params in the matrix */
		for (j = 0; j < 16; j++) {

			/* bail out if we're at the end of this controller chain */
			if ((id = ccmatrix[cc][j]) < 0) {
				break;
			}

			param = get_param(part_num, (unsigned int) id);

			/* set value for parameter */
			param_midi_update(param, event->value & 0x7F);

			/* update gui's copy and mark as updated */
			gui_param_midi_update(param, event->value & 0x7F);
		}
	}

	/* check for active cc edit */
	if (!cc_edit_ignore_midi && cc_edit_active) {
		cc_edit_cc_num = cc;
	}
}
Exemplo n.º 5
0
/*****************************************************************************
 * process_pitchbend()
 *****************************************************************************/
void
process_pitchbend(MIDI_EVENT *event, unsigned int part_num)
{
	PART            *part = get_part(part_num);
	unsigned int    bend_value;

	bend_value = ((unsigned int)(event->lsb & 0x7F) |
	              ((unsigned int)(event->msb & 0x7F) << 7));

	PHASEX_DEBUG(DEBUG_CLASS_MIDI_EVENT,
	             "Received pitchbend event:  2-byte value = %d  (lsb=%d msb=%d)\n",
	             bend_value, event->lsb, event->msb);

	part->pitch_bend_target = ((sample_t)(bend_value) - 8192) * 0.0001220703125; /* 1/8192 */
}
Exemplo n.º 6
0
Arquivo: bank.c Projeto: EQ4/phasex
/*****************************************************************************
 * midi_select_program()
 *****************************************************************************/
void
midi_select_program(unsigned int part_num, unsigned int prog_num)
{
	SESSION     *session = get_current_session();
	PATCH       *patch;

	if (!setting_ignore_midi_program_change) {
		patch = set_active_patch(visible_sess_num, part_num, prog_num);
		init_patch_state(patch);
		PHASEX_DEBUG(DEBUG_CLASS_MIDI_EVENT,
		             "\n*** MIDI Program Change:  part=%d  prog=%d (%d)\n\n",
		             (part_num + 1), prog_num, (prog_num + 1));
		visible_prog_num[part_num]                        = prog_num;
		session_bank[visible_sess_num].prog_num[part_num] = prog_num;
		if ((part_num == visible_part_num)) {
			pending_visible_patch = patch;
		}
		session->modified = 1;
	}
}
Exemplo n.º 7
0
/*****************************************************************************
 * process_aftertouch()
 *****************************************************************************/
void
process_aftertouch(MIDI_EVENT *event, unsigned int part_num)
{
	VOICE       *voice;
	PATCH_STATE *state = get_active_state(part_num);
	int         voice_num;

	PHASEX_DEBUG(DEBUG_CLASS_MIDI_EVENT,
	             "Event Key Presssure:  part=%d  note=%d  velocity=%d\n",
	             (part_num + 1), event->note, event->velocity);

	for (voice_num = 0; voice_num < setting_polyphony; voice_num++) {
		voice = get_voice(part_num, voice_num);
		if (event->note == voice->midi_key) {
			voice->velocity               = event->aftertouch;
			voice->velocity_target_linear = (sample_t) event->aftertouch * 0.01;
			voice->velocity_target_log    =
				velocity_gain_table[state->amp_velocity_cc][event->aftertouch];
		}
	}
}
Exemplo n.º 8
0
/*****************************************************************************
 * process_polypressure()
 *****************************************************************************/
void
process_polypressure(MIDI_EVENT *event, unsigned int part_num)
{
	PART            *part  = get_part(part_num);
	PATCH_STATE     *state = get_active_state(part_num);
	VOICE           *voice;
	int             voice_num;

	PHASEX_DEBUG(DEBUG_CLASS_MIDI_EVENT,
	             "Event Channel Pressure:  part=%d  value=%d\n",
	             (part_num + 1), event->polypressure);

	part->velocity_target = (sample_t) event->polypressure * 0.01;
	for (voice_num = 0; voice_num < setting_polyphony; voice_num++) {
		voice = get_voice(part_num, voice_num);
		if (voice->active) {
			voice->velocity               = event->polypressure;
			voice->velocity_target_linear = (sample_t) event->polypressure * 0.01;
			voice->velocity_target_log    =
				velocity_gain_table[state->amp_velocity_cc][event->polypressure];
		}
	}
}
Exemplo n.º 9
0
/*****************************************************************************
 * process_note_on()
 *
 * Process a note on event for a single part.  Add the note to the current
 * part's keylist and select a voice, stealing one if necessary.  All note on
 * events are processed with process_keytrigger() unless the velocity is set
 * to zero, and process_note_off() is used instead.
 *****************************************************************************/
void
process_note_on(MIDI_EVENT *event, unsigned int part_num)
{
	VOICE           *voice;
	VOICE           *old_voice     = NULL;
	VOICE           *loop_voice;
	PART            *part          = get_part(part_num);
	PATCH_STATE     *state         = get_active_state(part_num);
	int             voice_num;
	int             oldest_age;
	int             free_voice;
	int             steal_voice;
	int             same_key;
	int				osc;
	int				voice_count = 0;

	/* if this is velocity 0 style note off, fall through */
	if (event->velocity > 0) {

		/* keep track of previous to last key pressed! */
		part->prev_key = part->midi_key;
		part->midi_key = event->note;
		part->last_key = event->note;

		/* allocate voice for the different keymodes */
		switch (state->keymode) {
		case KEYMODE_MONO_SMOOTH:
			old_voice = get_voice(part_num, vnum[part_num]);
			old_voice->keypressed = -1;
			/* allocate new voice for staccato in mid-release only. */
			if (old_voice->allocated &&
			    ((old_voice->cur_amp_interval == ENV_INTERVAL_RELEASE) ||
			     (old_voice->cur_amp_interval == ENV_INTERVAL_FADE))) {
				old_voice->keypressed = -1;
				old_voice->cur_amp_interval = ENV_INTERVAL_RELEASE;
				old_voice->cur_amp_sample = -1;
				PHASEX_DEBUG(DEBUG_CLASS_MIDI_NOTE,
				             "voice %2d:  ^^^^^^^  Mono-Smooth:  "
				             "Fading out voice.  (Note On)  ^^^^^^^\n",
				             (old_voice->id + 1));
				vnum[part_num] = (vnum[part_num] + 1) % setting_polyphony;
			}
			break;
		case KEYMODE_MONO_UNISON_4:
			voice_count = 4;
			vnum[part_num] = 0;
			break;
		case KEYMODE_MONO_UNISON_6:
			voice_count = 6;
			vnum[part_num] = 0;
			break;
		case KEYMODE_MONO_UNISON_8:
			voice_count = 8;
			vnum[part_num] = 0;
			break;
		case KEYMODE_MONO_MULTIKEY:
			vnum[part_num] = 0;
			break;
		case KEYMODE_MONO_RETRIGGER:
			for (voice_num = 0; voice_num < setting_polyphony; voice_num++) {
				loop_voice = get_voice(part_num, voice_num);
				if (loop_voice->allocated) {
					loop_voice->keypressed = -1;
					loop_voice->cur_amp_interval = ENV_INTERVAL_RELEASE;
					loop_voice->cur_amp_sample = -1;
					old_voice = loop_voice;
					PHASEX_DEBUG(DEBUG_CLASS_MIDI_NOTE,
					             "voice %2d:  ^^^^^^^  Mono-Retrigger:  "
					             "Fading out voice.  (Note On)  ^^^^^^^\n",
					             (loop_voice->id + 1));
				}
			}
			vnum[part_num] = (vnum[part_num] + setting_polyphony - 1) % setting_polyphony;
			break;
		case KEYMODE_POLY:
			vnum[part_num] = 0;

			/* voice allocation with note stealing */
			oldest_age          = 0;
			free_voice          = -1;
			steal_voice         = setting_polyphony - 1;
			same_key            = -1;

			/* look through all the voices */
			for (voice_num = 0; voice_num < setting_polyphony; voice_num++) {
				loop_voice = get_voice(part_num, voice_num);

				/* priority 1: a free voice */
				if (loop_voice->allocated == 0) {
					free_voice = voice_num;
					vnum[part_num] = free_voice;
					voice_num = setting_polyphony;
					break;
				}
				else {
					if (loop_voice->midi_key == part->midi_key) {
						PHASEX_DEBUG(DEBUG_CLASS_MIDI_TIMING,
						             DEBUG_COLOR_RED "+++++++++++ "
						             DEBUG_COLOR_DEFAULT);
					}

					/* priority 2: find the absolute oldest in play */
					if ((same_key == -1) && (loop_voice->age > oldest_age)) {
						oldest_age = loop_voice->age;
						steal_voice = voice_num;
					}
				}
			}

			/* priorities 1 and 2 */
			if (free_voice >= 0) {
				vnum[part_num] = free_voice;
			}
			else {
				vnum[part_num] = steal_voice;
				PHASEX_DEBUG(DEBUG_CLASS_MIDI_NOTE,
				             "*** Part %d:  stealing voice %d!\n",
				             (part_num + 1), vnum[part_num]);
				PHASEX_DEBUG(DEBUG_CLASS_MIDI_TIMING,
				             DEBUG_COLOR_YELLOW "+++++++++++ "
				             DEBUG_COLOR_DEFAULT);
			}

			break;
		}

		/* keep pointer to current voice around */
		voice = get_voice(part_num, vnum[part_num]);
		/* assign midi note */
		voice->midi_key   = part->midi_key;
		voice->keypressed = part->midi_key;
		/* keep velocity for this note event */
		voice->velocity               = event->velocity;
		voice->velocity_target_linear = voice->velocity_coef_linear =
			part->velocity_target = part->velocity_coef = ((sample_t) event->velocity) * 0.01;
		voice->velocity_target_log    = voice->velocity_coef_log =
			velocity_gain_table[state->amp_velocity_cc][event->velocity];

		for (voice_num = 1; voice_num < voice_count; voice_num++) {
			if ( vnum[part_num] == voice_num ) continue;
			loop_voice = get_voice(part_num, voice_num);
			/* assign midi note */
			loop_voice->midi_key   = part->midi_key;
			loop_voice->keypressed = part->midi_key;
			/* keep velocity for this note event */
			loop_voice->velocity               = event->velocity;
			loop_voice->velocity_target_linear = loop_voice->velocity_coef_linear =
				part->velocity_target = part->velocity_coef = ((sample_t) event->velocity) * 0.01;
			loop_voice->velocity_target_log    = loop_voice->velocity_coef_log =
				velocity_gain_table[state->amp_velocity_cc][event->velocity];
		}

		if (event->velocity > 0) {
			part->velocity = event->velocity;
			PHASEX_DEBUG(DEBUG_CLASS_MIDI_NOTE,
			             "voice %2d:  Event Note On:   part=%d  "
			             "voice=%2d  note=%3d  velocity=%3d  keylist=:",
			             (vnum[part_num] + 1),
			             (part_num + 1),
			             (vnum[part_num] + 1),
			             event->note,
			             event->velocity);
			PHASEX_DEBUG(DEBUG_CLASS_MIDI_TIMING,
			             DEBUG_COLOR_RED "!!!!!!! %d !!!!!!! "
			             DEBUG_COLOR_DEFAULT,
			             event->note);
		}

		/* staccato, or no previous notes in play */
		if ((part->prev_key == -1) || (part->head == NULL)) {
			old_voice = NULL;

			/* put this key at the start of the list */
			part->head = & (part->keylist[part->midi_key]);
			part->head->next = NULL;
		}

		/* legato, or previous notes still in play */
		else {
			/* Link this key to the end of the list,
			   unlinking from the middle if necessary. */
			part->cur = part->head;
			part->prev = NULL;
			while (part->cur != NULL) {
				PHASEX_DEBUG(DEBUG_CLASS_MIDI_NOTE, "%d:", part->cur->midi_key);
				if (part->cur == &part->keylist[part->midi_key]) {
					if (part->prev != NULL) {
						part->prev->next = part->cur->next;
					}
				}
				part->prev = part->cur;
				part->cur = part->cur->next;
			}
			//PHASEX_DEBUG (DEBUG_CLASS_MIDI_NOTE, "\n");
			part->cur = & (part->keylist[part->midi_key]);

			/* if there is no end of the list, link it to the head */
			if (part->prev == NULL) {
				part->head = part->cur;
				PHASEX_WARN("*** process_note_on(): [part%d] found "
				            "previous key in play with no keylist!\n",
				            (part_num + 1));
			}
			else {
				part->prev->next = part->cur;
			}
			part->cur->next = NULL;
		}

		if (event->velocity > 0) {
			PHASEX_DEBUG(DEBUG_CLASS_MIDI_NOTE, "\n");
		}

		/* process parameters dependent on keytrigger events */
		process_keytrigger(event, old_voice, voice, part_num);
		for (voice_num = 0; voice_num < voice_count; voice_num++) {
			if ( vnum[part_num] == voice_num ) continue;
			loop_voice = get_voice(part_num, voice_num);
			process_keytrigger(event, old_voice, loop_voice, part_num);
		}
	}

	/* velocity 0 style note off */
	else {
		process_note_off(event, part_num);
	}
}
Exemplo n.º 10
0
/*****************************************************************************
 * process_keytrigger()
 *
 * Process voice/patch/param updates for keytrigger events.  This function
 * contains most of the logic for activating voices, and should be broken up
 * into its logical components.
 *****************************************************************************/
void
process_keytrigger(MIDI_EVENT   *UNUSED(event),
                   VOICE        *old_voice,
                   VOICE        *voice,
                   unsigned int part_num)
{
	VOICE           *loop_voice;
	PART            *part           = get_part(part_num);
	PATCH_STATE     *state          = get_active_state(part_num);
	int             osc;
	int             lfo;
	int             voice_num;
	int             staccato        = 1;
	int             env_trigger     = 0;
	sample_t        tmp;


	PHASEX_DEBUG(DEBUG_CLASS_MIDI_NOTE,
	             "voice %2d:  process_keytrigger():  old_voice=%2d  voice=%2d\n",
	             (voice->id + 1),
	             (old_voice == NULL ? 0 : (old_voice->id + 1)),
	             (voice->id + 1));

	/* check for notes currently in play */
	switch (state->keymode) {
	case KEYMODE_MONO_RETRIGGER:
		env_trigger = 1;
		/* intentional fall-through */
	case KEYMODE_MONO_UNISON_4:
	case KEYMODE_MONO_UNISON_6:
	case KEYMODE_MONO_UNISON_8:
	case KEYMODE_MONO_MULTIKEY:
	case KEYMODE_MONO_SMOOTH:
		if (voice->cur_amp_interval >= ENV_INTERVAL_RELEASE) {
			staccato = 1;
			env_trigger = 1;
		}
		else {
			staccato = 0;
		}
		break;
	case KEYMODE_POLY:
		staccato = 1;
		for (voice_num = 0; voice_num < setting_polyphony; voice_num++) {
			loop_voice = get_voice(part_num, voice_num);
			if (loop_voice->cur_amp_interval < ENV_INTERVAL_RELEASE) {
				staccato = 0;
				break;
			}
		}
		env_trigger = 1;
		break;
	}

	/* staccato, mono retrig, and poly get new envelopes and initphases */
	if (env_trigger) {

		/* start new amp and filter envelopes */
		voice->cur_amp_interval    = ENV_INTERVAL_ATTACK;
		voice->cur_filter_interval = ENV_INTERVAL_ATTACK;

		voice->cur_amp_sample    = voice->amp_env_dur[ENV_INTERVAL_ATTACK] =
			env_interval_dur[ENV_INTERVAL_ATTACK][state->amp_attack];
		voice->cur_filter_sample = voice->filter_env_dur[ENV_INTERVAL_ATTACK] =
			env_interval_dur[ENV_INTERVAL_ATTACK][state->filter_attack];

		/* TODO: test with hold pedal.                                */
		/* without hold pedal:                                        */
		/* voice->amp_env_delta[ENV_INTERVAL_ATTACK]    =             */
		/*      (1.0 - voice->amp_env_raw) /                          */
		/*      (sample_t)voice->amp_env_dur[ENV_INTERVAL_ATTACK];    */
		/* voice->filter_env_delta[ENV_INTERVAL_ATTACK] =             */
		/*      (1.0 - voice->filter_env_raw) /                       */
		/*      (sample_t)voice->filter_env_dur[ENV_INTERVAL_ATTACK]; */
		/* with hold pedal:  everything until next comment.           */
		voice->amp_env_raw = 0.0;
		voice->filter_env_raw = 0.0;

		if (state->amp_attack || state->amp_decay) {
			voice->amp_env_delta[ENV_INTERVAL_ATTACK]    =
				(1.0 - voice->amp_env_raw) /
				(sample_t) voice->amp_env_dur[ENV_INTERVAL_ATTACK];
		}
		else {
			voice->amp_env_delta[ENV_INTERVAL_ATTACK]    =
				(state->amp_sustain - voice->amp_env_raw) /
				(sample_t) voice->amp_env_dur[ENV_INTERVAL_ATTACK];
		}
		if (state->filter_attack || state->filter_decay) {
			voice->filter_env_delta[ENV_INTERVAL_ATTACK] =
				(1.0 - voice->filter_env_raw) /
				(sample_t) voice->filter_env_dur[ENV_INTERVAL_ATTACK];
		}
		else {
			voice->filter_env_delta[ENV_INTERVAL_ATTACK] =
				(state->filter_sustain - voice->filter_env_raw) /
				(sample_t) voice->filter_env_dur[ENV_INTERVAL_ATTACK];
		}
		/* end of hold pedal code changes */

		/* everything except mono multikey gets new init phases. */
		if (state->keymode != KEYMODE_MONO_MULTIKEY) {
			/* init phase for keytrig oscs */
			for (osc = 0; osc < NUM_OSCS; osc++) {
				/* init phase (unshifted by lfo) at note start */
				if ((state->osc_freq_base[osc] == FREQ_BASE_TEMPO_KEYTRIG) ||
				    (state->osc_freq_base[osc] == FREQ_BASE_MIDI_KEY)) {
					voice->index[osc] = part->osc_init_index[osc];
				}
			}
		}

		/* init phase for keytrig lfos if needed */
		/* TODO:  determine if including env retrigger is appropriate here */
		//if ((staccato) || (env_trigger)) {
		if (staccato) {
			for (lfo = 0; lfo < NUM_LFOS; lfo++) {
				switch (state->lfo_freq_base[lfo]) {
				case FREQ_BASE_MIDI_KEY:
				case FREQ_BASE_TEMPO_KEYTRIG:
					part->lfo_index[lfo] = part->lfo_init_index[lfo];
					/* intentional fallthrough */
				case FREQ_BASE_TEMPO:
					part->lfo_adjust[lfo] = part->lfo_freq[lfo] * wave_period;
					break;
				}
			}
		}
	}

	/* Both high key and low key are set to the last key and adjusted later
	   if necessary */
	part->high_key = part->low_key = part->last_key;

	/* set highest and lowest keys in play for things that need
	   keyfollow */
	part->cur = part->head;
	while (part->cur != NULL) {
		if (part->cur->midi_key < part->low_key) {
			part->low_key = part->cur->midi_key;
		}
		if (part->cur->midi_key > part->high_key) {
			part->high_key = part->cur->midi_key;
		}
		part->cur = part->cur->next;
	}

	/* volume keyfollow is set by last key for poly */
	if (state->keymode == KEYMODE_POLY) {
		voice->vol_key = part->last_key;
	}
	/* volume keyfollow is set by high key for mono */
	else {
		voice->vol_key = part->high_key;
	}

	/* set filter keyfollow key based on keyfollow mode */
	switch (state->filter_keyfollow) {
	case KEYFOLLOW_LAST:
		tmp = (sample_t)(part->last_key + state->transpose - 64);
		for (voice_num = 0; voice_num < setting_polyphony; voice_num++) {
			loop_voice = get_voice(part_num, voice_num);
			loop_voice->filter_key_adj = tmp;
		}
		break;
	case KEYFOLLOW_HIGH:
		tmp = (sample_t)(part->high_key + state->transpose - 64);
		for (voice_num = 0; voice_num < setting_polyphony; voice_num++) {
			loop_voice = get_voice(part_num, voice_num);
			loop_voice->filter_key_adj = tmp;
		}
		break;
	case KEYFOLLOW_LOW:
		tmp = (sample_t)(part->low_key + state->transpose - 64);
		for (voice_num = 0; voice_num < setting_polyphony; voice_num++) {
			loop_voice = get_voice(part_num, voice_num);
			loop_voice->filter_key_adj = tmp;
		}
		break;
	case KEYFOLLOW_MIDI:
		voice->filter_key_adj = (sample_t)(part->last_key + state->transpose - 64);
		break;
	case KEYFOLLOW_NONE:
		voice->filter_key_adj = 0.0;
		break;
	}

	/* start at beginning of list of keys in play */
	part->cur = part->head;

	/* Keytrigger volume only applicable to midi key based oscs portamento
	   applicable to midi key based oscs _and_ lfos. */

	/* handle per-osc portamento for the different keymodes */
	for (osc = 0; osc < NUM_OSCS; osc++) {

		/* portamento for midi key based main osc */
		if (state->osc_freq_base[osc] == FREQ_BASE_MIDI_KEY) {

			/* decide which key in play to assign to this oscillator */
			switch (state->keymode) {
			case KEYMODE_MONO_MULTIKEY:
				/* use notes in order in oscillators */
				if (part->cur != NULL) {
					voice->osc_key[osc] = part->cur->midi_key;
					if (part->cur->next != NULL) {
						part->cur = part->cur->next;
					}
					else {
						part->cur = part->head;
					}
				}
				else {
					voice->osc_key[osc] = part->last_key;
				}
				break;
			case KEYMODE_MONO_UNISON_4:
			case KEYMODE_MONO_UNISON_6:
			case KEYMODE_MONO_UNISON_8:
			case KEYMODE_MONO_SMOOTH:
			case KEYMODE_MONO_RETRIGGER:
				/* default mono -- use key just pressed */
				voice->osc_key[osc] = part->last_key;
				break;
			case KEYMODE_POLY:
				/* use midi key assigned to voice */
				voice->osc_key[osc] = voice->midi_key;
				break;
			}

			/* Set oscillator frequencies based on midi note, global transpose
			   value, and optional portamento.  state->osc_transpose[osc] is
			   taken into account every sample in the engine. */
			if ((state->portamento > 0)) {
				/* Portamento always starts from previous key hit, no matter
				   which voice.  Mono multikey always uses same voice. */
				if (state->keymode != KEYMODE_MONO_MULTIKEY) {
					if (part->prev_key == -1) {
						voice->osc_freq[osc] =
							freq_table[state->patch_tune_cc]
							[256 + part->last_key + state->transpose +
							 state->osc_transpose_cc[osc] - 64];
					}
					else {
						voice->osc_freq[osc] =
							freq_table[state->patch_tune_cc]
							[256 + part->prev_key + state->transpose +
							 state->osc_transpose_cc[osc] - 64];
					}
				}
				/* Portamento slide calculation works the same for all
				   keymodes.  Start portamento now that frequency adjustment
				   is known. */
				if ((old_voice == NULL) || (old_voice == voice)) {
					voice->osc_portamento[osc] = 4.0 *
						(freq_table[state->patch_tune_cc]
						 [256 + voice->osc_key[osc] + state->transpose +
						  state->osc_transpose_cc[osc] - 64]
						 - voice->osc_freq[osc]) /
						(sample_t)(voice->portamento_samples - 1);
					part->portamento_sample  = part->portamento_samples;
					voice->portamento_sample = voice->portamento_samples;
				}
				else {
					voice->osc_portamento[osc] = 4.0 *
						(freq_table[state->patch_tune_cc]
						 [256 + voice->osc_key[osc] + state->transpose +
						  state->osc_transpose_cc[osc] - 64]
						 - old_voice->osc_freq[osc]) /
						(sample_t)(voice->portamento_samples - 1);
					part->portamento_sample  = part->portamento_samples;
					voice->portamento_sample = voice->portamento_samples;
					/* Mono modes set portamento on voice just finishing to
					   match new voice. */
					if ((state->keymode == KEYMODE_MONO_SMOOTH) ||
					    (state->keymode == KEYMODE_MONO_RETRIGGER) ||
					    (state->keymode == KEYMODE_MONO_UNISON_4) ||
					    (state->keymode == KEYMODE_MONO_UNISON_6) ||
					    (state->keymode == KEYMODE_MONO_UNISON_8)) {
						old_voice->osc_portamento[osc] =
							voice->osc_portamento[osc];
						old_voice->portamento_sample   =
							voice->portamento_sample;
						old_voice->portamento_samples  =
							voice->portamento_samples;
					}
				}
			}

			/* If portamento is not needed, set the oscillator frequency
			   directly. */
			else {
				voice->osc_freq[osc] = freq_table[state->patch_tune_cc]
					[256 + voice->osc_key[osc] +
					 state->transpose + state->osc_transpose_cc[osc] - 64];
				voice->osc_portamento[osc] = 0.0;
				voice->portamento_sample   = 0;
				voice->portamento_samples  = 0;
			}
		}
	}

	/* portamento for midi key based lfo */
	for (lfo = 0; lfo < NUM_LFOS; lfo++) {

		if (state->lfo_freq_base[lfo] == FREQ_BASE_MIDI_KEY) {

			/* decide which key in play to assign to this lfo */
			switch (state->keymode) {
			case KEYMODE_MONO_MULTIKEY:
				/* use notes in order in lfos */
				if (part->cur != NULL) {
					part->lfo_key[lfo] = part->cur->midi_key;
					if (part->cur->next != NULL) {
						part->cur = part->cur->next;
					}
					else {
						part->cur = part->head;
					}
				}
				else {
					part->lfo_key[lfo] = part->last_key;
				}
				break;
			case KEYMODE_MONO_SMOOTH:
			case KEYMODE_MONO_RETRIGGER:
			case KEYMODE_MONO_UNISON_4:
			case KEYMODE_MONO_UNISON_6:
			case KEYMODE_MONO_UNISON_8:
				/* default mono -- use key just pressed */
				part->lfo_key[lfo] = part->last_key;
				break;
			case KEYMODE_POLY:
				/* use midi key assigned to allocated voice */
				part->lfo_key[lfo] = voice->midi_key;
				break;
			}

			/* Set lfo portamento frequencies based on
			   midi note and transpose value. */
			if ((state->portamento > 0) && (part->portamento_samples > 0)) {
				part->lfo_portamento[lfo] =
					(freq_table[state->patch_tune_cc]
					 [256 + part->lfo_key[lfo]] - part->lfo_freq[lfo]) /
					(sample_t) part->portamento_samples;
			}

			/* If portamento is not needed, set the lfo frequency directly. */
			else {
				part->lfo_portamento[lfo] = 0.0;
				part->lfo_freq[lfo] = freq_table[state->patch_tune_cc][256 + part->lfo_key[lfo]];
			}

		}
	}
	/* allocate voice (engine actually activates allocated voices) */
	voice->allocated = 1;
}
Exemplo n.º 11
0
/*****************************************************************************
 * process_note_off()
 *
 * Process a single note-off event (either a note-off message, or a note-on
 * message with velocity set to zero).  Select a voices to be turned on/off,
 * remove key from list, and call process_keytrigger() for any portamento,
 * envelope, osc and lfo init-phase, and filter-follow triggering actions for
 * note-off events that cause new notes to be triggered (mono modes).
 *****************************************************************************/
void
process_note_off(MIDI_EVENT *event, unsigned int part_num)
{
	VOICE           *voice;
	VOICE           *old_voice      = NULL;
	VOICE           *loop_voice;
	PART            *part           = get_part(part_num);
	PATCH_STATE     *state          = get_active_state(part_num);
	int             keytrigger      = 0;
	int             free_voice      = -1;
	int             voice_num;
	int             unlink;
	int 			voice_count = 0;

	switch (state->keymode) {
	case KEYMODE_POLY:
		/* find voice mapped to note being shut off */
		vnum[part_num] = -1;
		for (voice_num = 0; voice_num < setting_polyphony; voice_num++) {
			loop_voice = get_voice(part_num, voice_num);
			if (loop_voice->midi_key == event->note) {
				loop_voice->keypressed = -1;
				vnum[part_num] = voice_num;
			}
		}
		if (vnum[part_num] == -1) {
			vnum[part_num] = 0;
			keytrigger = 0;
		}
		break;

	case KEYMODE_MONO_SMOOTH:
		/* find voice mapped to note being shut off, if any */
		keytrigger = 0;
		for (voice_num = 0; voice_num < setting_polyphony; voice_num++) {
			loop_voice = get_voice(part_num, voice_num);
			if (loop_voice->keypressed == event->note) {
				loop_voice->keypressed = -1;
				if (event->note == part->midi_key) {
					old_voice = loop_voice;
				}
			}
		}
		break;

	case KEYMODE_MONO_RETRIGGER:
		/* find voice mapped to note being shut off, if any */
		keytrigger = 0;
		for (voice_num = 0; voice_num < setting_polyphony; voice_num++) {
			loop_voice = get_voice(part_num,
			                       ((voice_num + vnum[part_num] + 1) % setting_polyphony));
			if (loop_voice->allocated == 0) {
				free_voice = loop_voice->id;
			}
			else if (loop_voice->midi_key == event->note) {
				loop_voice->keypressed = -1;
				vnum[part_num] = (voice_num + 1) % setting_polyphony;
				if (event->note == part->midi_key) {
					old_voice = loop_voice;
				}
			}
		}
		if ((old_voice != NULL) && (free_voice > -1)) {
			vnum[part_num] = free_voice;
		}
		break;

	case KEYMODE_MONO_UNISON_4:
		voice_count = 4;
		vnum[part_num] = 0;
		if (part->midi_key == event->note) {
			keytrigger = 1;
			old_voice = get_voice(part_num, vnum[part_num]);
		}
		break;
	case KEYMODE_MONO_UNISON_6:
		voice_count = 6;
		vnum[part_num] = 0;
		if (part->midi_key == event->note) {
			keytrigger = 1;
			old_voice = get_voice(part_num, vnum[part_num]);
		}
		break;
	case KEYMODE_MONO_UNISON_8:
		voice_count = 8;
		vnum[part_num] = 0;
		if (part->midi_key == event->note) {
			keytrigger = 1;
			old_voice = get_voice(part_num, vnum[part_num]);
		}
		break;
	case KEYMODE_MONO_MULTIKEY:
		/* mono multikey needs keytrigger activities on note off for
		   resetting oscillator frequencies. */
		vnum[part_num] = 0;
		if (part->midi_key == event->note) {
			keytrigger = 1;
			old_voice = get_voice(part_num, vnum[part_num]);
		}
		break;
	}

	part->prev_key = part->midi_key;
	part->midi_key = event->note;

	PHASEX_DEBUG(DEBUG_CLASS_MIDI_NOTE, "voice %2d:  Event Note Off:  part=%d  "
	             "voice=%2d  note=%3d  velocity=%3d  keylist=:",
	             (vnum[part_num] + 1),
	             (part_num + 1),
	             (vnum[part_num] + 1),
	             event->note,
	             event->velocity);

	/* remove this key from the list and then find the last key */
	part->prev = NULL;
	part->cur = part->head;
	unlink = 0;
	while (part->cur != NULL) {

		/* if note is found, unlink it from the list */
		if (part->cur->midi_key == event->note) {
			PHASEX_DEBUG(DEBUG_CLASS_MIDI_NOTE, "-%d-:", part->cur->midi_key);
			unlink = 1;
			if (part->prev != NULL) {
				part->prev->next = part->cur->next;
				part->cur->next  = NULL;
				part->cur        = part->prev->next;
			}
			else {
				part->head       = part->cur->next;
				part->cur->next  = NULL;
				part->cur        = part->head;
			}
		}
		/* otherwise, on to the next key in the list */
		else {
			PHASEX_DEBUG(DEBUG_CLASS_MIDI_NOTE, "%d:", part->cur->midi_key);
			part->prev = part->cur;
			part->cur  = part->cur->next;
		}
	}

	PHASEX_DEBUG(DEBUG_CLASS_MIDI_NOTE, "\n");
	PHASEX_DEBUG(DEBUG_CLASS_MIDI_TIMING,
	             DEBUG_COLOR_BLUE "------- %d ------- " DEBUG_COLOR_DEFAULT,
	             event->note);

	if (!unlink) {
		/* Received note-off w/o corresponding note-on. */
		PHASEX_DEBUG(DEBUG_CLASS_MIDI_TIMING,
		             DEBUG_COLOR_RED "----------- " DEBUG_COLOR_DEFAULT);
	}

	/* keep pointer to current voice around */
	voice = get_voice(part_num, vnum[part_num]);

	/* ignore the note in the note off message if found in list */
	if ((part->prev != NULL) && (part->prev->midi_key == event->note)) {
		part->cur = part->head;
		while (part->cur != NULL) {
			if (part->cur->midi_key != event->note) {
				part->prev = part->cur;
			}
			part->cur  = part->cur->next;
		}
	}
	/* check for keys left on the list */
	if (part->prev != NULL) {
		/* set last and current keys in play respective of notes
		   still held */
		part->last_key = part->prev->midi_key;
		part->midi_key = part->prev->midi_key;
		part->prev->next = NULL;

		/* Retrigger and smooth modes need voice allocation with keys
		   still on list multikey always need osc remapping until all
		   keys are done. */
		switch (state->keymode) {
		case KEYMODE_MONO_RETRIGGER:
			if (old_voice == NULL) {
				keytrigger--;
				break;
			}
			old_voice->cur_amp_interval = ENV_INTERVAL_RELEASE;
			old_voice->cur_amp_sample = -1;
			/* intentional fall-through */
		case KEYMODE_MONO_SMOOTH:
			voice->midi_key   = part->midi_key;
			voice->keypressed = part->midi_key;

			/* use previous velocity for this generated note event */
			voice->velocity               = part->velocity;
			voice->velocity_target_linear = voice->velocity_coef_linear =
				part->velocity_target   = part->velocity_coef =
				((sample_t) part->velocity) * 0.01;
			voice->velocity_target_log    = voice->velocity_coef_log =
				velocity_gain_table[state->amp_velocity_cc][part->velocity];

			/* intentional fall-through */
		case KEYMODE_MONO_UNISON_4:
		case KEYMODE_MONO_UNISON_6:
		case KEYMODE_MONO_UNISON_8:
		case KEYMODE_MONO_MULTIKEY:
			keytrigger++;
			break;
		}
	}
	/* re-init list if no keys */
	else {
		voice->midi_key   = -1;
		voice->keypressed = -1;
		for (voice_num = 0; voice_num < voice_count; voice_num++) {
			if ( vnum[part_num] == voice_num ) continue;
			loop_voice = get_voice(part_num, voice_num);
			loop_voice->midi_key = -1;
			loop_voice->keypressed = -1;
		}
		part->head           = NULL;
		if (!part->hold_pedal) {
			part->midi_key       = -1;
		}
	}

	if (keytrigger > 0) {
		process_keytrigger(event, old_voice, voice, part_num);
		for (voice_num = 0; voice_num < voice_count; voice_num++) {
			if ( vnum[part_num] == voice_num ) continue;
			loop_voice = get_voice(part_num, voice_num);
			process_keytrigger(event, old_voice, loop_voice, part_num);
		}
	}
}
Exemplo n.º 12
0
/*****************************************************************************
 * process_midi_event()
 *
 * Perform complete processing for an event (straight from the queue).
 * All supported event types must be handled by this function.
 *****************************************************************************/
MIDI_EVENT *
process_midi_event(MIDI_EVENT *event, unsigned int part_num)
{
	MIDI_EVENT  *next;

	switch (event->type) {
	case MIDI_EVENT_NOTE_ON:
		process_note_on(event, part_num);
		break;
	case MIDI_EVENT_NOTE_OFF:
		process_note_off(event, part_num);
		break;
	case MIDI_EVENT_AFTERTOUCH:
		process_aftertouch(event, part_num);
		break;
	case MIDI_EVENT_STOP:
	case MIDI_EVENT_SYSTEM_RESET:
		process_all_notes_off(event, part_num);
		break;
	case MIDI_EVENT_PROGRAM_CHANGE:
		process_program_change(event, part_num);
		break;
	case MIDI_EVENT_POLYPRESSURE:
		process_polypressure(event, part_num);
		break;
	case MIDI_EVENT_CONTROLLER:
		process_controller(event, part_num);
		break;
	case MIDI_EVENT_PITCHBEND:
		process_pitchbend(event, part_num);
		break;
#ifdef MIDI_CLOCK_SYNC
	case MIDI_EVENT_CLOCK:
		break;
#endif /* MIDI_CLOCK_SYNC */
		/* The following are internal message types */
	case MIDI_EVENT_BPM_CHANGE:
		process_bpm_change(event, part_num);
		break;
	case MIDI_EVENT_PHASE_SYNC:
		process_phase_sync(event, part_num);
		break;
	default:
		PHASEX_DEBUG(DEBUG_CLASS_MIDI_EVENT,
		             "+++ process_midi_event():  part %d:  "
		             "received unhandled MIDI message type 0x%02x\n",
		             (part_num + 1), event->type);
		break;
	}

	/* keep track of pointers to bulk lists */
	next = event->next;

	/* Clear event. */
	event->type    = 0;
	event->channel = 0;
	event->byte2   = 0;
	event->byte3   = 0;
	event->next    = NULL;
	set_midi_event_state(event, EVENT_STATE_FREE);

	return next;
}
Exemplo n.º 13
0
/*****************************************************************************
 * process_bpm_change()
 *
 * Process a BPM change pseudo MIDI message.  Currently used when syncing
 * JACK Transport, this adjust BPM, independent of controller assignment.
 *
 * TODO:  Rework _all_ phasex BPM code, since this is almost identical to
 * update_bpm() in bpm.c.
 *****************************************************************************/
void
process_bpm_change(MIDI_EVENT *event, unsigned int part_num)
{
	PART        *part   = get_part(part_num);
	PATCH_STATE *state  = get_active_state(part_num);
	PARAM       *param  = get_param(part_num, PARAM_BPM);
	DELAY       *delay  = get_delay(part_num);
	CHORUS      *chorus = get_chorus(part_num);
	VOICE       *voice;
	int         int_val = (int)(event->float_value);
	int         cc_val  = int_val - 64;
	int         voice_num;
	int         lfo;
	int         osc;

	PHASEX_DEBUG(DEBUG_CLASS_MIDI_TIMING, "+++ Processing BPM change.  New BPM = %lf +++\n",
	             event->float_value);

	param->value.cc_val  = cc_val;
	param->value.int_val = int_val;

	/* For now, this is handled much like the normal param
	   callback for BPM, execpt that here we use floating point
	   values instead of integer. */

	global.bpm = event->float_value;
	global.bps = event->float_value / 60.0;

	if (param->value.cc_val != cc_val) {
		param->value.cc_prev = param->value.cc_val;
		param->value.cc_val  = cc_val;
		param->value.int_val = int_val;
		param->updated        = 1;
	}

	/* initialize all variables based on bpm */
	state->bpm     = event->float_value;
	state->bpm_cc  = (short)(param->value.cc_val & 0x7F);

	/* re-initialize delay size */
	delay->size   = state->delay_time * f_sample_rate / global.bps;
	delay->length = (int)(delay->size);

	/* re-initialize chorus lfos */
	chorus->lfo_freq     = global.bps * state->chorus_lfo_rate;
	chorus->lfo_adjust   = chorus->lfo_freq * wave_period;
	chorus->phase_freq   = global.bps * state->chorus_phase_rate;
	chorus->phase_adjust = chorus->phase_freq * wave_period;

	/* per-lfo setup */
	for (lfo = 0; lfo < NUM_LFOS; lfo++) {
		/* re-calculate frequency and corresponding index adjustment */
		if (state->lfo_freq_base[lfo] >= FREQ_BASE_TEMPO) {
			part->lfo_freq[lfo]    = global.bps * state->lfo_rate[lfo];
			part->lfo_adjust[lfo]  = part->lfo_freq[lfo] * wave_period;
		}
	}

	/* per-oscillator setup */
	for (osc = 0; osc < NUM_OSCS; osc++) {
		/* re-calculate tempo based osc freq */
		if (state->osc_freq_base[osc] >= FREQ_BASE_TEMPO) {
			for (voice_num = 0; voice_num < setting_polyphony; voice_num++) {
				voice = get_voice(part_num, voice_num);
				voice->osc_freq[osc] = global.bps * state->osc_rate[osc];
			}
		}
	}
}
Exemplo n.º 14
0
Arquivo: wave.c Projeto: EQ4/phasex
int
load_waveform_sample(int wavenum, int num_cycles, double octaves)
{
	float           *in_buf;
	float           *out_buf;
	char            filename[PATH_MAX];
	struct stat     statbuf;
	SRC_DATA        src_data;
	FILE            *rawfile;
	unsigned int    sample;
	unsigned int    input_len;
	float           pos_max;
	float           neg_max;
	float           offset;
	float           scalar;
	size_t          sample_t_size = sizeof(sample_t);

	if ((in_buf = malloc(2 * WAVEFORM_SIZE * sizeof(float))) == NULL) {
		phasex_shutdown("Out of Memory!\n");
	}
	if ((out_buf = malloc(WAVEFORM_SIZE * sizeof(float))) == NULL) {
		phasex_shutdown("Out of Memory!\n");
	}

	/* get file size */
	snprintf(filename, PATH_MAX, "%s/%s.raw", SAMPLE_DIR, wave_names[wavenum]);
	if (stat(filename, &statbuf) != 0) {
		PHASEX_ERROR("Unable to load raw sample file '%s'\n", filename);
	}
	input_len = (unsigned int)((unsigned int) statbuf.st_size / sizeof(float));
	PHASEX_DEBUG(DEBUG_CLASS_INIT, "Loading raw waveform '%s': %d samples\n",
	             filename, input_len);

	/* open raw sample file */
	if ((rawfile = fopen(filename, "rb")) != 0) {

		/* read sample data */
		if (fread(in_buf, sizeof(float), input_len, rawfile) == input_len) {
			fclose(rawfile);

			/* normalize sample to [-1,1] */
			pos_max = neg_max = 0;
			for (sample = 0; sample < input_len; sample++) {
				if (in_buf[sample] > pos_max) {
					pos_max = in_buf[sample];
				}
				if (in_buf[sample] < neg_max) {
					neg_max = in_buf[sample];
				}
			}
			offset = (pos_max + neg_max) / -2.0;
			scalar = 1.0 / (float)((pos_max - neg_max) / 2.0);
			for (sample = 0; sample < input_len; sample++) {
				in_buf[sample] = (in_buf[sample] + offset) * scalar;
			}

			/* resample to fit WAVEFORM_SIZE */
			src_data.input_frames  = (long int) input_len;
			src_data.output_frames = WAVEFORM_SIZE;
			src_data.src_ratio     = F_WAVEFORM_SIZE / (double) input_len;
			src_data.data_in       = in_buf;
			src_data.data_out      =
				(sample_t_size == 4) ? (float *) & (wave_table[wavenum][0]) : & (out_buf[0]);

			src_simple(&src_data, SRC_SINC_BEST_QUALITY, 1);

			if (sample_t_size != 4) {
				for (sample = 0; sample < input_len; sample++) {
					wave_table[wavenum][sample] = (sample_t)(out_buf[sample]);
				}
			}

			/* filter resampled data */
			filter_wave_table_24dB(wavenum, num_cycles, octaves);

			/* all done */
			return 0;
		}
		fclose(rawfile);
	}

	/* copy sine data on failure */
	PHASEX_ERROR("Error reading '%s'!\n", filename);
	for (sample = 0; sample < WAVEFORM_SIZE; sample++) {
		wave_table[wavenum][sample] = wave_table[WAVE_SINE][sample];
	}

	return -1;
}