nekobi-reworked/plugins/Nekobi/nekobee-src/nekobee_voice.c

247 lines
6.7 KiB
C

/* nekobee DSSI software synthesizer plugin
*
* Copyright (C) 2004 Sean Bolton and others.
*
* Portions of this file may have come from Steve Brookes'
* nekobee, copyright (C) 1999 S. J. Brookes.
* Portions of this file may have come from Peter Hanappe's
* Fluidsynth, copyright (C) 2003 Peter Hanappe and others.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program; if not, write to the Free
* Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307, USA.
*/
#define _BSD_SOURCE 1
#define _SVID_SOURCE 1
#define _ISOC99_SOURCE 1
#include <stdlib.h>
#include "nekobee_types.h"
#include "nekobee_synth.h"
#include "nekobee_voice.h"
/*
* nekobee_voice_new
*/
nekobee_voice_t *
nekobee_voice_new()
{
nekobee_voice_t *voice;
voice = (nekobee_voice_t *)calloc(sizeof(nekobee_voice_t), 1);
if (voice) {
voice->status = XSYNTH_VOICE_OFF;
}
return voice;
}
/*
* nekobee_voice_note_on
*/
void
nekobee_voice_note_on(nekobee_synth_t *synth, nekobee_voice_t *voice,
unsigned char key, unsigned char velocity)
{
int i;
voice->key = key;
voice->velocity = velocity;
if (!synth->monophonic || !(_ON(voice) || _SUSTAINED(voice))) {
// brand-new voice, or monophonic voice in release phase; set everything up
voice->target_pitch = nekobee_pitch[key];
if (synth->held_keys[0] >= 0) {
voice->prev_pitch = nekobee_pitch[synth->held_keys[0]];
} else {
voice->prev_pitch = voice->target_pitch;
}
if (!_PLAYING(voice)) {
voice->lfo_pos = 0.0f;
voice->vca_eg = 0.0f;
voice->vcf_eg = 0.0f;
voice->delay1 = 0.0f;
voice->delay2 = 0.0f;
voice->delay3 = 0.0f;
voice->delay4 = 0.0f;
voice->c5 = 0.0f;
voice->osc_index = 0;
voice->osc1.last_waveform = -1;
voice->osc1.pos = 0.0f;
}
voice->vca_eg_phase = 0;
voice->vcf_eg_phase = 0;
// nekobee_voice_update_pressure_mod(synth, voice);
} else {
/* synth is monophonic, and we're modifying a playing voice */
/* set new pitch */
voice->target_pitch = nekobee_pitch[key];
if (synth->glide == XSYNTH_GLIDE_MODE_INITIAL ||
synth->glide == XSYNTH_GLIDE_MODE_OFF)
voice->prev_pitch = voice->target_pitch;
/* if in 'on' or 'both' modes, and key has changed, then re-trigger EGs */
if ((synth->monophonic == XSYNTH_MONO_MODE_ON ||
synth->monophonic == XSYNTH_MONO_MODE_BOTH) &&
(synth->held_keys[0] < 0 || synth->held_keys[0] != key)) {
voice->vca_eg_phase = 0;
voice->vcf_eg_phase = 0;
}
/* all other variables stay what they are */
}
synth->last_noteon_pitch = voice->target_pitch;
/* add new key to the list of held keys */
/* check if new key is already in the list; if so, move it to the
* top of the list, otherwise shift the other keys down and add it
* to the top of the list. */
for (i = 0; i < 7; i++) {
if (synth->held_keys[i] == key)
break;
}
for (; i > 0; i--) {
synth->held_keys[i] = synth->held_keys[i - 1];
}
synth->held_keys[0] = key;
if (!_PLAYING(voice)) {
nekobee_voice_start_voice(voice);
} else if (!_ON(voice)) { /* must be XSYNTH_VOICE_SUSTAINED or XSYNTH_VOICE_RELEASED */
voice->status = XSYNTH_VOICE_ON;
}
}
/*
* nekobee_voice_set_release_phase
*/
static inline void
nekobee_voice_set_release_phase(nekobee_voice_t *voice)
{
voice->vca_eg_phase = 2;
voice->vcf_eg_phase = 2;
}
/*
* nekobee_voice_remove_held_key
*/
inline void
nekobee_voice_remove_held_key(nekobee_synth_t *synth, unsigned char key)
{
int i;
/* check if this key is in list of held keys; if so, remove it and
* shift the other keys up */
for (i = 7; i >= 0; i--) {
if (synth->held_keys[i] == key)
break;
}
if (i >= 0) {
for (; i < 7; i++) {
synth->held_keys[i] = synth->held_keys[i + 1];
}
synth->held_keys[7] = -1;
}
}
/*
* nekobee_voice_note_off
*/
void
nekobee_voice_note_off(nekobee_synth_t *synth, nekobee_voice_t *voice,
unsigned char key, unsigned char rvelocity)
{
unsigned char previous_top_key;
/* save release velocity */
voice->velocity = rvelocity;
previous_top_key = synth->held_keys[0];
/* remove this key from list of held keys */
nekobee_voice_remove_held_key(synth, key);
if (synth->held_keys[0] >= 0) {
/* still some keys held */
if (synth->held_keys[0] != previous_top_key) {
/* most-recently-played key has changed */
voice->key = synth->held_keys[0];
voice->target_pitch = nekobee_pitch[voice->key];
if (synth->glide == XSYNTH_GLIDE_MODE_INITIAL ||
synth->glide == XSYNTH_GLIDE_MODE_OFF)
voice->prev_pitch = voice->target_pitch;
/* if mono mode is 'both', re-trigger EGs */
if (synth->monophonic == XSYNTH_MONO_MODE_BOTH && !_RELEASED(voice)) {
voice->vca_eg_phase = 0;
voice->vcf_eg_phase = 0;
}
}
} else { /* no keys still held */
if (XSYNTH_SYNTH_SUSTAINED(synth)) {
/* no more keys in list, but we're sustained */
if (!_RELEASED(voice))
voice->status = XSYNTH_VOICE_SUSTAINED;
} else { /* not sustained */
/* no more keys in list, so turn off note */
nekobee_voice_set_release_phase(voice);
voice->status = XSYNTH_VOICE_RELEASED;
}
}
}
/*
* nekobee_voice_release_note
*/
void
nekobee_voice_release_note(nekobee_synth_t *synth, nekobee_voice_t *voice)
{
if (_ON(voice)) {
/* dummy up a release velocity */
voice->rvelocity = 64;
}
nekobee_voice_set_release_phase(voice);
voice->status = XSYNTH_VOICE_RELEASED;
return;
(void)synth;
}