246 lines
6.7 KiB
C
246 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->osc.phase = 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;
|
|
}
|