Beispiel #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;
	}
}
/***********
 * returns JB_OK if a frame is available and *data points to the packet
 * returns JB_NOFRAME if it's no time to play voice and or no frame available
 * returns JB_INTERP if interpolating is required
 * returns JB_EMPTY if no voice frame is in the jitterbuffer (only during silence)
 * 
 * if the next frame is a silence frame we will go in silence-mode
 * each new instance of the jitterbuffer will start in silence mode
 * in silence mode we will set the jitterbuffer to the size we want
 * when we are not in silence mode get_voicecase will handle the rest. 
 */
static int get_voice(jitterbuffer *jb, void **data, long now, long interpl) 
{
  jb_frame *frame;
  long diff;
  int result;
  
  diff = jb->target - jb->current;
  
  //if the next frame is a silence frame, go in silence mode...
  if((get_next_frametype(jb, now - jb->current) == JB_TYPE_SILENCE) ) {
    jb_dbg("gs");
    frame = get_frame(jb, now - jb->current);
    *data = frame->data;
    frame->data = NULL;
    jb->info.silence =1;
    jb->silence_begin_ts = frame->ts;
    frame_free(frame);
    result = JB_OK;
  } else {  
    if(jb->info.silence) { // we are in silence
      /*
       * During silence we can set the jitterbuffer size to the size
       * we want...
       */
      if (diff) {
        jb->current = jb->target;
      }
      frame = get_frame(jb, now - jb->current);
      if (frame) {
        if (jb->silence_begin_ts && frame->ts < jb->silence_begin_ts) {
          jb_dbg("gL");
          /* voice frame is late, next!*/
          jb->info.frames_late++;
          frame_free(frame);
          result = get_voice(jb, data, now, interpl);
        } else {
          jb_dbg("gP"); 
          /* voice frame */
          jb->info.silence = 0;
          jb->silence_begin_ts = 0;
          jb->next_voice_time = frame->ts + frame->ms;
          jb->info.last_voice_ms = frame->ms;
          *data = frame->data;
          frame->data = NULL;
          frame_free(frame);
          result = JB_OK;
        }
      } else {    //no frame 
        jb_dbg("gS");
        result = JB_EMPTY;
      }
    } else { //voice case
      result = get_voicecase(jb,data,now,interpl,diff);
    }
  }
  return result;
}
Beispiel #3
0
void SOUNDCLIP::resume() {
    if (state_ != SoundClipPaused) { return; }

    int voice = get_voice();
    if (voice >= 0) {
        voice_start(voice);
        state_ = SoundClipPlaying;
    }
}
Beispiel #4
0
void SOUNDCLIP::pause() {
    if (state_ != SoundClipPlaying) { return; }

    int voice = get_voice();
    if (voice >= 0) {
        voice_stop(voice);
        state_ = SoundClipPaused;
    }
}
Beispiel #5
0
void SOUNDCLIP::set_panning(int newPanning) {
    if (!is_playing()) { return; }
    
    int voice = get_voice();
    if (voice >= 0) {
        voice_set_pan(voice, newPanning);
        panning = newPanning;
    }
}
/***********
 * control frames have a higher priority then voice frames
 * returns JB_OK if a frame is available and *data points to the packet
 * returns JB_NOFRAME if it's no time to play voice and no control available
 * returns JB_INTERP if interpolating is required
 * returns JB_EMPTY if no voice frame is in the jitterbuffer (only during silence)
 */
int jb_get(jitterbuffer *jb, void **data, long now, long interpl) 
{
  int result;
  
  jb_dbg("A");
  if (jb == NULL) {
    jb_err("no jitterbuffer in jb_get()\n");
    return JB_NOJB;
  }
  
  result = get_control(jb, data);
  if (result != JB_OK ) { //no control message available maybe there is voice...
    result = get_voice(jb, data, now, interpl);
  }
  return result;
}
Beispiel #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];
		}
	}
}
Beispiel #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];
		}
	}
}
/***********
 * The voicecase has four 'options'
 * - difference is way off, reset
 * - diff > 0, we may need to grow
 * - diff < 0, we may need to shrink
 * - everything else
 */
static int get_voicecase(jitterbuffer *jb, void **data, long now, long interpl, long diff) 
{
  jb_frame *frame;
  int result;
  
   // * - difference is way off, reset
  if (diff > jb->settings.max_diff || -diff > jb->settings.max_diff) {
    jb_err("wakko diff in get_voicecase\n");
    reset(jb); //reset hist because the timestamps are wakko. 
    result = JB_NOFRAME;
  //- diff > 0, we may need to grow
  } else if ((diff > 0) && 
                   (now > (jb->last_adjustment + jb->settings.wait_grow) 
                    || (now + jb->current + interpl) < get_next_framets(jb) ) ) { //grow
    /* first try to grow */
    if (diff<interpl/2) {
      jb_dbg("ag");
      jb->current +=diff;
    } else {
      jb_dbg("aG");
      /* grow by interp frame len */
      jb->current += interpl;
    }
    jb->last_adjustment = now;
    result = get_voice(jb, data, now, interpl);
  //- diff < 0, we may need to shrink
  } else if ( (diff < 0) 
                && (now > (jb->last_adjustment + jb->settings.wait_shrink)) 
                && ((-diff) > jb->settings.extra_delay) ) {
    /* now try to shrink
     * if there is a frame shrink by frame length
     * otherwise shrink by interpl
     */
    jb->last_adjustment = now;
    
    frame = get_frame(jb, now - jb->current);
    if(frame) {
      jb_dbg("as");
      /* shrink by frame size we're throwing out */
      jb->info.frames_dropped++;
      jb->current -= frame->ms;
      frame_free(frame);
    } else {
      jb_dbg("aS");
      /* shrink by interpl */
      jb->current -= interpl;
    }
    result = get_voice(jb, data, now, interpl);
  } else  { 
    /* if it is not the time to play a result = JB_NOFRAME
     * else We try to play a frame if a frame is available
     * and not late it is played otherwise 
     * if available it is dropped and the next is tried
     * last option is interpolating
     */
    if (now - jb->current < jb->next_voice_time) {
      jb_dbg("aN");
      result = JB_NOFRAME;
    } else {
      frame = get_frame(jb, now - jb->current);
      if (frame) { //there is a frame
        /* voice frame is late */
        if(frame->ts < jb->next_voice_time) {   //late
          jb_dbg("aL");
          jb->info.frames_late++;
          frame_free(frame);
          result = get_voice(jb, data, now, interpl);
        } else {
          jb_dbg("aP");
          /* normal case; return the frame, increment stuff */
          *data = frame->data;
          frame->data = NULL;
          jb->next_voice_time = frame->ts + frame->ms;
          jb->cnt_successive_interp = 0;
          frame_free(frame);
          result = JB_OK;
        }
      } else { // no frame, thus interpolate
        jb->cnt_successive_interp++;
        /* assume silence instead of continuing to interpolate */
        if (jb->settings.max_successive_interp && jb->cnt_successive_interp >= jb->settings.max_successive_interp) {
          jb->info.silence = 1;
          jb->silence_begin_ts = jb->next_voice_time;
        }
        jb_dbg("aI");
        jb->next_voice_time += interpl;
        result = JB_INTERP;
      }
    }
  }
  return result;

}
Beispiel #10
0
static void stop_note(struct SoundPlugin *plugin, int64_t time, float note_num, int64_t note_id){
  Data *data = (Data*)plugin->data;
  Voice *voice = get_voice(data);
  if(voice->delta_pos_at_end == -1)
    voice->delta_pos_at_end = time;
}
Beispiel #11
0
static void set_note_volume(struct SoundPlugin *plugin, int64_t time, float note_num, int64_t note_id, float volume){
  Data *data = (Data*)plugin->data;
  Voice *voice = get_voice(data);
  voice->velocity = volume;
}
Beispiel #12
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);
	}
}
Beispiel #13
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;
}
Beispiel #14
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);
		}
	}
}
Beispiel #15
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];
			}
		}
	}
}
Beispiel #16
0
/*****************************************************************************
 * process_phase_sync()
 *
 * Process a phase sync internal MIDI message.  Currently used for syncing
 * JACK Transport, this function performs phase correction for a given voice.
 *****************************************************************************/
void
process_phase_sync(MIDI_EVENT *event, unsigned int part_num)
{
	PART            *part              = get_part(part_num);
	PATCH_STATE     *state             = get_active_state(part_num);
	DELAY           *delay             = get_delay(part_num);
	CHORUS          *chorus            = get_chorus(part_num);
	VOICE           *voice;
	int             voice_num;
	int             osc;
	int             lfo;
	int             phase_correction   = event->value;
	sample_t        f_phase_correction = (sample_t) phase_correction;
	sample_t        tmp_1;

	delay->write_index += phase_correction;
	while (delay->write_index < 0.0) {
		delay->write_index += delay->bufsize;
	}
	while (delay->write_index >= delay->bufsize) {
		delay->write_index -= delay->bufsize;
	}

	chorus->lfo_index_a += f_phase_correction * chorus->lfo_adjust;
	while (chorus->lfo_index_a < 0.0) {
		chorus->lfo_index_a += F_WAVEFORM_SIZE;
	}
	while (chorus->lfo_index_a >= F_WAVEFORM_SIZE) {
		chorus->lfo_index_a -= F_WAVEFORM_SIZE;
	}

	chorus->lfo_index_b = chorus->lfo_index_a + (F_WAVEFORM_SIZE * 0.25);
	while (chorus->lfo_index_b < 0.0) {
		chorus->lfo_index_b += F_WAVEFORM_SIZE;
	}
	while (chorus->lfo_index_b >= F_WAVEFORM_SIZE) {
		chorus->lfo_index_b -= F_WAVEFORM_SIZE;
	}

	chorus->lfo_index_c = chorus->lfo_index_a + (F_WAVEFORM_SIZE * 0.5);
	while (chorus->lfo_index_c < 0.0) {
		chorus->lfo_index_c += F_WAVEFORM_SIZE;
	}
	while (chorus->lfo_index_c >= F_WAVEFORM_SIZE) {
		chorus->lfo_index_c -= F_WAVEFORM_SIZE;
	}

	chorus->lfo_index_d = chorus->lfo_index_a + (F_WAVEFORM_SIZE * 0.75);
	while (chorus->lfo_index_d < 0.0) {
		chorus->lfo_index_d += F_WAVEFORM_SIZE;
	}
	while (chorus->lfo_index_d >= F_WAVEFORM_SIZE) {
		chorus->lfo_index_d -= F_WAVEFORM_SIZE;
	}

	for (voice_num = 0; voice_num < setting_polyphony; voice_num++) {
		voice = get_voice(part_num, voice_num);
		for (osc = 0; osc < NUM_OSCS; osc++) {
			if (state->osc_freq_base[osc] >= FREQ_BASE_TEMPO) {
				switch (state->freq_mod_type[osc]) {
				case MOD_TYPE_LFO:
					tmp_1 = part->lfo_out[state->freq_lfo[osc]];
					break;
				case MOD_TYPE_OSC:
					tmp_1 = (voice->osc_out1[part->osc_freq_mod[osc]] +
					         voice->osc_out2[part->osc_freq_mod[osc]]) * 0.5;
					break;
				case MOD_TYPE_VELOCITY:
					tmp_1 = voice->velocity_coef_linear;
					break;
				default:
					tmp_1 = 0.0;
					break;
				}

				voice->index[osc] +=
					f_phase_correction *
					halfsteps_to_freq_mult((tmp_1 *
					                        state->freq_lfo_amount[osc]) +
					                       part->osc_pitch_bend[osc] +
					                       state->osc_transpose[osc] +
					                       state->voice_osc_tune[voice->id] ) *
					voice->osc_freq[osc] * wave_period;

				while (voice->index[osc] < 0.0) {
					voice->index[osc] += F_WAVEFORM_SIZE;
				}
				while (voice->index[osc] >= F_WAVEFORM_SIZE) {
					voice->index[osc] -= F_WAVEFORM_SIZE;
				}
			}
		}
	}
	for (lfo = 0; lfo < NUM_LFOS; lfo++) {
		if (state->lfo_freq_base[lfo] >= FREQ_BASE_TEMPO) {
			part->lfo_index[lfo] +=
				f_phase_correction *
				part->lfo_freq[lfo] *
				halfsteps_to_freq_mult(state->lfo_transpose[lfo] + part->lfo_pitch_bend[lfo]) *
				wave_period;

			while (part->lfo_index[lfo] < 0.0) {
				part->lfo_index[lfo] += F_WAVEFORM_SIZE;
			}
			while (part->lfo_index[lfo] >= F_WAVEFORM_SIZE) {
				part->lfo_index[lfo] -= F_WAVEFORM_SIZE;
			}
		}
	}
}