/*
	$Id: playmidi.cpp,v 1.17 2000/07/16 19:17:06 greglee Exp $

    TiMidity -- Experimental MIDI to WAVE converter
    Copyright (C) 1995 Tuukka Toivonen <toivonen@clinet.fi>

    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., 675 Mass Ave, Cambridge, MA 02139, USA.

    playmidi.c -- random stuff in need of rearrangement

*/

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>

#ifndef NO_STRING_H
#    include <string.h>
#else
#    include <strings.h>
#endif

#include "gtim.h"
#include "common.h"
#include "instrum.h"
#include "playmidi.h"
#include "readmidi.h"
#include <sys/time.h>
#include "output.h"
#include "mix.h"
#include "controls.h"
#include "resample.h"

#include "tables.h"
#include "effects.h"

/* #define WATCH_SQUARE */
#define ADHOC_LEGATO

#ifdef tplus
#    define PORTAMENTO_TIME_TUNING		(1.0 / 5000.0)
#    define PORTAMENTO_CONTROL_RATIO	256	/* controls per sec */
#endif

#ifdef tplus
int     dont_cspline = 0;
#endif
int     opt_dry = 0;
int     opt_expression_curve = 0;
int     opt_volume_curve = 0;
int     opt_stereo_surround = 0;
int     dont_chorus = 0;
int     dont_reverb = 0;
int     current_interpolation = INTERPOLATION_CSPLINE|INTERPOLATION_BUTTERWORTH;
int     dont_keep_looping = 0;
int	voices_ceiling = 192;

int opt_center_position = 64;
int opt_left_position = 32;
int opt_right_position = 95;
int opt_rear_left_position = 0;
int opt_rear_right_position = 127;
int opt_bank = 0;

static int voice_reserve = 0;

Channel channel[MAXCHAN];
signed char drumvolume[MAXCHAN][MAXNOTE];
signed char drumpanpot[MAXCHAN][MAXNOTE];
signed char drumreverberation[MAXCHAN][MAXNOTE];
signed char drumchorusdepth[MAXCHAN][MAXNOTE];
signed char drumattack[MAXCHAN][MAXNOTE];
signed char drumdecay[MAXCHAN][MAXNOTE];
signed char drumpitch[MAXCHAN][MAXNOTE];
signed char drumcutoff[MAXCHAN][MAXNOTE];
signed char drumresonance[MAXCHAN][MAXNOTE];
signed char drumvariationsend[MAXCHAN][MAXNOTE];

Voice   voice[MAX_VOICES];

//int voices = DEFAULT_VOICES;

int32 control_ratio = 0, amplification = DEFAULT_AMPLIFICATION;

FLOAT_T master_volume;

int32   drumchannels = DEFAULT_DRUMCHANNELS;
int     adjust_panning_immediately = 1;
int     wide_panning = -1;

int     GM_System_On = 0;
int     XG_System_On = 0;
int     GS_System_On = 0;

int     XG_System_reverb_type;
int     XG_System_chorus_type;
int     XG_System_variation_type;
int	XG_Variation_Feedback;
int	XG_Variation_Drylevel;
int     XG_insertion1_type;
int     XG_insertion2_type;

static int32 lost_notes, cut_notes, played_notes;
static int32 common_buffer[AUDIO_BUFFER_SIZE * MAX_OUT_CHANNELS],	/* surround samples */
       *buffer_pointer;
static uint32 buffered_count;

static MidiEvent *event_list;
MidiEvent *current_event;
static uint32 sample_count, current_sample, midi_restart_time = 0;

#ifdef tplus
static void update_portamento_controls (int ch);

static int current_keysig = -1;
static int current_play_tempo = -1;
static int play_pause_flag = 0;
#endif

static int kill_note (int i);

static void
adjust_amplification (void)
{
    master_volume = (FLOAT_T) (amplification) / (FLOAT_T) 100.0;
    /*master_volume /= 4; */
    master_volume /= 2;
    ctl->master_volume ((int)(master_volume * 200));
}

static void
adjust_master_volume (int32 vol)
{
    master_volume = (double) (vol * amplification) / 1638400.0L;
    /* master_volume /= 4; */
    master_volume /= 2;
    ctl->master_volume ((int)(master_volume * 200));
}


static void
reset_voices (void)
{
    int     i;
    for (i = 0; i < MAX_VOICES; i++)
	voice[i].status = VOICE_FREE;
    danger = 0;
}

/* Process the Reset All Controllers event */
static void
reset_controllers (int c)
{
    channel[c].volume = 90;	/* Some standard says, although the SCC docs say 0. */
    channel[c].expression = 127;	/* SCC-1 does this. */
    channel[c].sustain = 0;
    channel[c].pitchbend = 0x2000;
    channel[c].pitchfactor = 0;	/* to be computed */
    channel[c].reverberation = 0x28;
    channel[c].chorusdepth = 0;
    channel[c].tremolo = 64;
#ifdef tplus
    channel[c].modulation_wheel = 0;
    channel[c].mw_pmod = 10;
    channel[c].mw_fmod = 0;
    channel[c].mw_amod = 0;
    channel[c].portamento_time_lsb = 0;
    channel[c].portamento_time_msb = 0;
    channel[c].tuning_lsb = 64;
    channel[c].tuning_msb = 64;
    channel[c].porta_control_ratio = 0;
    channel[c].portamento = 0;
    channel[c].last_note_fine = -1;

    channel[c].vibrato_ratio = 0;
    channel[c].vibrato_depth = 0;
    channel[c].vibrato_delay = 0;
    channel[c].variation_depth = 0;
    channel[c].sostenuto = 0;
    channel[c].harmoniccontent = 64;
    channel[c].releasetime = 64;
    channel[c].attacktime = 64;
    channel[c].decaytime = 64;
    channel[c].brightness = 64;
/*
  memset(channel[c].envelope_rate, 0, sizeof(channel[c].envelope_rate));
*/
    update_portamento_controls (c);
#endif
}

static void
redraw_controllers (int c)
{
    ctl->volume (c, channel[c].volume);
    ctl->expression (c, channel[c].expression);
    ctl->sustain (c, channel[c].sustain, 'S');
    ctl->pitch_bend (c, channel[c].pitchbend, channel[c].modulation_wheel);
}

static void
reset_midi (void)
{
    int     i;
    for (i = 0; i < MAXCHAN; i++) {
	reset_controllers (i);
	/* The rest of these are unaffected by the Reset All Controllers event */
	channel[i].program = default_program;
	channel[i].panning = NO_PANNING;
	channel[i].pitchsens = 2;
	channel[i].bank = 0;	/* tone bank or drum set */
	/*channel[i].kit=0; */
	channel[i].xg = 0;
	channel[i].effect = 0;
	channel[i].mono = -1;
	if (ISDRUMCHANNEL (i)) channel[i].kit = 127;
	else channel[i].kit = 0;
	/* channel[i].transpose, .name, are initialized in readmidi.c */
	if (channel[i].futurekit) channel[i].kit = channel[i].futurekit;
	channel[i].variationbank = 0;
	channel[i].receive = -1;
	channel[i].drylevel = 127;
	channel[i].velocity_sense_depth = 64;
	channel[i].velocity_sense_offset = 64;
    }
    reset_voices ();
}


static int
check_switches (int i, Sample *sp)
{
    int     j = voices, fc;
    FLOAT_T r;

    if (sp->hirand < 1.0 || sp->lorand > 0) {
	    r = 1.0 * rand() / (RAND_MAX);
	    if (r < sp->lorand || r >= sp->hirand) return 0;
    }

    if (sp->sw_hikey < 0) return 1;
    if (sp->sw_lokey < 0) return 1;
    if (sp->sw_up < 0 && sp->sw_down < 0) return 1;

    while (j--) {
	if (voice[j].status & (VOICE_FREE | VOICE_OFF | VOICE_DIE))
	    continue;
	if ( (voice[j].clone_type & IS_CLONE) )
	    continue;
	if (i == j)
	    continue;
	if (voice[i].channel != voice[j].channel)
	    continue;
	fc = voice[j].sample->freq_center;
	if (fc > sp->sw_hikey)
	    continue;
	if (fc < sp->sw_lokey)
	    continue;
	if (fc == sp->sw_down) return 1;
	if (fc == sp->sw_up) return 0;
    }
    if (sp->sw_up >= 0) return 1;
    if (sp->sw_down >= 0) return 0;
    return 1;
}



static void
select_sample (int v, Instrument * ip, int trigger)
{
    int32   f, cdiff, diff, midfreq;
    int     s, i, first_trigger;
    Sample *sp, *closest;

    s = ip->samples;
    sp = ip->sample;

    if (s == 1) {
	voice[v].sample = sp;
	return;
    }

    f = voice[v].orig_frequency;
#if 0
/*
    Even if in range, a later patch may be closer. */

    for (i = 0; i < s; i++) {
	if (sp->low_freq <= f && sp->high_freq >= f) {
	    voice[v].sample = sp;
	    return;
	}
	sp++;
    }
#endif
    /* 
       No suitable sample found! We'll select the sample whose root
       frequency is closest to the one we want. (Actually we should
       probably convert the low, high, and root frequencies to MIDI note
       values and compare those.) */

    cdiff = 0x7FFFFFFF;
    closest = sp = ip->sample;
    midfreq = (sp->low_freq + sp->high_freq) / 2;
    for (i = 0; i < s; i++) {
	diff = sp->root_freq - f;
	if (trigger == TRIGGER_NONE) first_trigger = 0;
	else first_trigger = (trigger == sp->trigger);
	/*  But the root freq. can perfectly well lie outside the keyrange
	 *  frequencies, so let's try:
	 */
	/* diff=midfreq - f; */
	if (diff < 0)
	    diff = -diff;
	if (diff < cdiff) {
	    cdiff = diff;
	    closest = sp;
	}
	else if (diff == cdiff && first_trigger) {
	    cdiff = diff;
	    closest = sp;
	}
	else if (diff == cdiff && check_switches(v, sp)) {
	    cdiff = diff;
	    closest = sp;
	}
	sp++;
    }
    voice[v].sample = closest;
    return;
}

static void
select_stereo_samples (int v, InstrumentLayer * lp, int trigger)
{
    Instrument *ip;
    InstrumentLayer *nlp, *bestvel;
    Sample *left_sample;
    int     diffvel, midvel, mindiff;

/* select closest velocity */
    bestvel = lp;
    mindiff = 500;
    for (nlp = lp; nlp; nlp = nlp->next) {
	midvel = (nlp->hi + nlp->lo) / 2;
	if (!midvel)
	    diffvel = 127;
	else if (voice[v].velocity < nlp->lo || voice[v].velocity > nlp->hi)
	    diffvel = 200;
	else
	    diffvel = voice[v].velocity - midvel;
	if (diffvel < 0)
	    diffvel = -diffvel;
	if (diffvel < mindiff) {
	    mindiff = diffvel;
	    bestvel = nlp;
	}
    }
    ip = bestvel->instrument;

    ip->sample = ip->left_sample;
    ip->samples = ip->left_samples;
    select_sample (v, ip, trigger);
    left_sample = voice[v].sample;

    if (ip->right_sample) {
	ip->sample = ip->right_sample;
	ip->samples = ip->right_samples;
	if (!(voice[v].sample->stereo_mode & MONO_SAMPLE))
		select_sample (v, ip, trigger);
	voice[v].right_sample = voice[v].sample;
        ip->sample = ip->left_sample;
        ip->samples = ip->left_samples;
    }
    else
	voice[v].right_sample = 0;

    voice[v].sample = left_sample;
}

#ifndef tplus
static
#endif
    void
recompute_freq (int v)
{
    int
            sign = (voice[v].sample_increment < 0),	/* for bidirectional loops */
	pb = channel[voice[v].channel].pitchbend;
    double  a;
    int32   tuning = 0;

    if (!voice[v].sample->sample_rate)
	return;

#ifdef tplus
#    if 0
    if (!opt_modulation_wheel)
	voice[v].modulation_wheel = 0;
    if (!opt_portamento)
	voice[v].porta_control_ratio = 0;
#    endif
    voice[v].vibrato_control_ratio = voice[v].orig_vibrato_control_ratio;

    if (voice[v].modulation_wheel > 0) {
	voice[v].vibrato_control_ratio =
	    (int32) (play_mode->rate * MODULATION_WHEEL_RATE
		     / (2.0 * VIBRATO_SAMPLE_INCREMENTS));
	voice[v].vibrato_delay = 0;
    }
#endif

#ifdef tplus
    if (voice[v].vibrato_control_ratio || voice[v].modulation_wheel > 0)
#else
    if (voice[v].vibrato_control_ratio)
#endif
    {
	/* This instrument has vibrato. Invalidate any precomputed
	   sample_increments. */

	int     i = VIBRATO_SAMPLE_INCREMENTS;
	while (i--)
	    voice[v].vibrato_sample_increment[i] = 0;
#ifdef tplus29
	if (voice[v].modulation_wheel > 0) {
	    voice[v].vibrato_control_ratio =
		(int32) (play_mode->rate * MODULATION_WHEEL_RATE
			 / (2.0 * VIBRATO_SAMPLE_INCREMENTS));
	    voice[v].vibrato_delay = 0;
	}
#endif
    }


#ifdef tplus
    /* fine: [0..128] => [-256..256]
     * 1 coarse = 256 fine (= 1 note)
     * 1 fine = 2^5 tuning
     */
    tuning = (((int32) channel[voice[v].channel].tuning_lsb - 0x40)
	      + 64 * ((int32) channel[voice[v].channel].tuning_msb -
		      0x40)) << 7;
#endif

#ifdef tplus
    if (!voice[v].porta_control_ratio) {
#endif
#ifdef tplus29
	if (tuning == 0 && pb == 0x2000)
#else
	if (pb == 0x2000 || pb < 0 || pb > 0x3FFF)
#endif
	    voice[v].frequency = voice[v].orig_frequency;
	else {
	    pb -= 0x2000;
	    if (!(channel[voice[v].channel].pitchfactor)) {
		/* Damn. Somebody bent the pitch. */
		int32   i = pb * channel[voice[v].channel].pitchsens + tuning;
#ifdef tplus29
		tuning;
		if (i >= 0)
		    channel[ch].pitchfactor =
			bend_fine[(i >> 5) & 0xFF] *
			bend_coarse[(i >> 13) & 0x7F];
		else {
		    i = -i;
		    channel[ch].pitchfactor = 1.0 /
			(bend_fine[(i >> 5) & 0xFF] *
			 bend_coarse[(i >> 13) & 0x7F]);
		}
#else
		if (pb < 0)
		    i = -i;
		channel[voice[v].channel].pitchfactor =
		    bend_fine[(i >> 5) & 0xFF] * bend_coarse[i >> 13];
#endif
	    }
#ifndef tplus29
	    if (pb > 0)
#endif
		voice[v].frequency =
		    (int32) (channel[voice[v].channel].pitchfactor *
			     (double) (voice[v].orig_frequency));
#ifndef tplus29
	    else
		voice[v].frequency =
		    (int32) ((double) (voice[v].orig_frequency) /
			     channel[voice[v].channel].pitchfactor);
#endif
	}
#ifdef tplus
    }
    else {			/* Portament */

	int32   i;
	FLOAT_T pf;

	pb -= 0x2000;

	i = pb * channel[voice[v].channel].pitchsens +
	    (voice[v].porta_pb << 5) + tuning;

	if (i >= 0)
	    pf = bend_fine[(i >> 5) & 0xFF] * bend_coarse[(i >> 13) & 0x7F];
	else {
	    i = -i;
	    pf = 1.0 / (bend_fine[(i >> 5) & 0xFF] *
			bend_coarse[(i >> 13) & 0x7F]);
	}
	voice[v].frequency =
	    (int32) ((double) (voice[v].orig_frequency) * pf);
	/*voice[v].cache = NULL; */
    }
#endif

    a = FRSCALE (((double) (voice[v].sample->sample_rate) *
		  (double) (voice[v].frequency)) /
		 ((double) (voice[v].sample->root_freq) *
		  (double) (play_mode->rate)), FRACTION_BITS);

    /* what to do if incr is 0? --gl */
    /* if (!a) a++; */
    a += 0.5;
    if ((int32) a < 1)
	a = 1;

    if (sign)
	a = -a;			/* need to preserve the loop direction */

    voice[v].sample_increment = (int32) (a);
}

/*
 * "pan" is midi pan, 0 (left) to 127 (right)
 * "speaker" is 0 (left surround), 32 (left front),
 * 	64 (center), 95 (right front), 128 (right surround)
 * "separation" is 95 for 4-channel surround (left
 * front and right front taper down to 0 amplitude
 * at right pan=127 and left pan=0, respectively).
 * and is 64 for 6-channel surround (center tapers
 * down to 0 amplitude at left and right).
 *
 * Returns amplitude 0-127 for requested speaker.
 */
static int expr_curve[128] = {
    0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 10, 10, 10, 10, 11, 
    11, 11, 11, 12, 12, 12, 12, 13, 13, 13, 14, 14, 14, 14, 15, 15, 
    15, 16, 16, 17, 17, 17, 18, 18, 19, 19, 19, 20, 20, 21, 21, 22, 
    22, 23, 23, 24, 24, 25, 25, 26, 26, 27, 28, 28, 29, 30, 30, 31, 
    32, 32, 33, 34, 35, 35, 36, 37, 38, 39, 39, 40, 41, 42, 43, 44, 
    45, 46, 47, 48, 49, 50, 51, 53, 54, 55, 56, 57, 59, 60, 61, 63, 
    64, 65, 67, 68, 70, 71, 73, 75, 76, 78, 80, 82, 83, 85, 87, 89, 
    91, 93, 95, 97, 99, 102, 104, 106, 109, 111, 113, 116, 118, 121,
    124, 127 
};

static int panf(int pan, int speaker, int separation)
{
    int val;

    val = abs(pan - speaker);
    val = (val * 127) / separation;
    val = 127 - val;
    if (val < 0) val = 0;
    if (val > 127) val = 127;
#ifdef NEW_PANNER
    return expr_curve[val];
#else
    return val;
#endif
}

#if 0
static int vcurve[128] = {
    0, 0, 18, 29, 36, 42, 47, 51, 55, 58,
    60, 63, 65, 67, 69, 71, 73, 74, 76, 77,
    79, 80, 81, 82, 83, 84, 85, 86, 87, 88,
    89, 90, 91, 92, 92, 93, 94, 95, 95, 96,
    97, 97, 98, 99, 99, 100, 100, 101, 101, 102,
    103, 103, 104, 104, 105, 105, 106, 106, 106, 107,
    107, 108, 108, 109, 109, 109, 110, 110, 111, 111,
    111, 112, 112, 112, 113, 113, 114, 114, 114, 115,
    115, 115, 116, 116, 116, 116, 117, 117, 117, 118,
    118, 118, 119, 119, 119, 119, 120, 120, 120, 120,
    121, 121, 121, 122, 122, 122, 122, 123, 123, 123,
    123, 123, 124, 124, 124, 124, 125, 125, 125, 125,
    126, 126, 126, 126, 126, 127, 127, 127
};
#endif

#ifdef tplus
/* measured value from SC-88STPro.
   approximate expression: y = (-1.5374x6 + 4.4002x5 - 4.8309x4 + 2.572x3 + 0.1487x2 + 0.2412x + 0.0044) * 127 */
/* integer part only: */
static int sc_vel_table[128] = {
	0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 4, 4, 4, 
	5, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 
	12, 13, 13, 14, 15, 15, 16, 17, 17, 18, 19, 19, 20, 21, 22, 22, 
	23, 24, 25, 26, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 
	37, 38, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 52, 53, 54, 
	55, 56, 58, 59, 60, 61, 63, 64, 65, 67, 68, 69, 71, 72, 73, 75, 
	76, 78, 79, 81, 82, 84, 85, 87, 88, 90, 91, 93, 94, 96, 98, 99, 
	101, 103, 104, 106, 108, 109, 111, 113, 114, 116, 118, 119, 121, 123, 125, 127
};


static int32 calc_velocity(int32 ch,int32 vel)
{
    int32 velocity;
    velocity = channel[ch].velocity_sense_depth * vel / 64 + (channel[ch].velocity_sense_offset - 64) * 2;
    if (velocity > 127) {velocity = 127;}
    switch (opt_volume_curve) {
    case 5:
	return (int32)(127.0 * xg_vol_table[velocity]);
    case 4:
	return (int32)(127.0 * gs_vol_table[velocity]);
    case 3:
	return (int32)(127.0 * def_vol_table[velocity]);
    case 2:
	return (int32)(127.0 * vol_table[velocity]);
    case 1:
	return sc_vel_table[velocity];
    default:
    case 0:
	return velocity;
    }
    return velocity;
}
#endif

static void
recompute_amp (int v)
{
    int32   tempamp;
    int     chan = voice[v].channel;
    int     panning = voice[v].panning;
    int     vol = channel[chan].volume;
    int     expr = channel[chan].expression;
    int     vel = calc_velocity(chan, voice[v].velocity);
    FLOAT_T curved_expression, curved_volume;

    /* TODO: use fscale */

    if (channel[chan].kit) {
	int     note = voice[v].sample->note_to_use;
	if (note > 0 && drumvolume[chan][note] >= 0)
	    vol = drumvolume[chan][note];
    }

    switch (opt_expression_curve) {
    case 5:
	curved_expression = 127.0 * xg_vol_table[expr];
	break;
    case 4:
	curved_expression = 127.0 * gs_vol_table[expr];
	break;
    case 3:
	curved_expression = 127.0 * def_vol_table[expr];
	break;
    case 2:
	curved_expression = 127.0 * vol_table[expr];
	break;
    default:
    case 1:
	curved_expression = expr_curve[expr];
	break;
    case 0:
	curved_expression = (FLOAT_T) expr;
	break;
    }
    switch (opt_volume_curve) {
    case 5:
	curved_volume = 127.0 * xg_vol_table[vol];
	break;
    case 4:
	curved_volume = 127.0 * gs_vol_table[vol];
	break;
    case 3:
	curved_volume = 127.0 * def_vol_table[vol];
	break;
    case 2:
	curved_volume = 127.0 * vol_table[vol];
	break;
    default:
    case 1:
	curved_volume = expr_curve[vol];
	break;
    case 0:
	curved_volume = (FLOAT_T) vol;
	break;
    }

    //if (voice[v].clone_type == STEREO_CLONE) curved_volume *= 0.75;

    tempamp = (int32) ((FLOAT_T) vel * curved_volume * curved_expression);	/* 21 bits */
/*-------------
Use sep = 32 and map midi pan 0-127 to 16-112, reserving 0-15 and 113-127 for surround effects
	pan = 96 * mpan / 128 + 16
113-127=0-15  --> 64-96 using ce for lr and rf for rr ??
	i.e., 113-127 --> 64-80
	and     0- 15 --> 80-96 using rf to get the lr value and ce to get the rr value
Probably don't use expr_curve.
 * sep = 32
  0->BE : lr= 64, lf=  0, ce=  0, rf=  0, rr= 64 +180
  8-> 0 : lr=127, lf=  0, ce=  0, rf=  0, rr=  0 -135
pan  16 : lr= 64, lf= 64, ce=  0, rf=  0, rr=  0  -90
pan  32 : lr=  0, lf=127, ce=  0, rf=  0, rr=  0  -45
pan  48 : lr=  0, lf= 64, ce= 64, rf=  0, rr=  0  -22
pan  64 : lr=  0, lf=  0, ce=127, rf=  0, rr=  0    0
pan  80 : lr=  0, lf=  0, ce= 64, rf= 64, rr=  0  +22
pan  96 : lr=  0, lf=  0, ce=  0, rf=127, rr=  0  +45
pan 112 : lr=  0, lf=  0, ce=  0, rf= 64, rr= 64  +90
127->120: lr=  0, lf=  0, ce=  0, rf=  4, rr=124 +135
  0->BE : lr= 64, lf=  0, ce=  0, rf=  0, rr= 64 +180
-------------*/
#define CENTER_PAN_VALUE	64
#ifdef NEW_PANNER
#define LEFT_PAN_VALUE	16
#define RIGHT_PAN_VALUE	112
#else
#define LEFT_PAN_VALUE	0
#define RIGHT_PAN_VALUE	127
#endif

#ifdef WATCH_SQUARE
if (chan == 6) fprintf(stderr,"%2d - %d of %d\n", chan, panning, v);
#endif

/* #define ALL_A_MYSTERY */
    if (num_ochannels > 1) {
#ifdef ALL_A_MYSTERY
/* to test the setpan algorithm */
	panning = LEFT_PAN_VALUE + 6;
#endif
	if (panning > (CENTER_PAN_VALUE-2) && panning < (CENTER_PAN_VALUE+2)) {
	    voice[v].panned = PANNED_CENTER;

	    if (num_ochannels == 6) voice[v].left_amp =
		FRSCALENEG ((double) (tempamp) * voice[v].volume *
			    master_volume, 20 /* lower center to 21?? */);
	    else voice[v].left_amp =
		FRSCALENEG ((double) (tempamp) * voice[v].volume *
			    master_volume, 21);
	}
	else if (panning >= LEFT_PAN_VALUE && panning < (LEFT_PAN_VALUE+5)) {
	    voice[v].panned = PANNED_LEFT;

	    voice[v].left_amp =
		FRSCALENEG ((double) (tempamp) * voice[v].volume *
			    master_volume, 20);
	}
	else if (panning > (RIGHT_PAN_VALUE-4) && panning <= RIGHT_PAN_VALUE) {
	    voice[v].panned = PANNED_RIGHT;

	    voice[v].left_amp =	/* left_amp will be used */
		FRSCALENEG ((double) (tempamp) * voice[v].volume *
			    master_volume, 20);
	}
	else {
	    FLOAT_T refv = (double)(tempamp) * voice[v].volume * master_volume;
	    voice[v].panned = PANNED_MYSTERY;

#ifdef ALL_A_MYSTERY
	    panning = voice[v].panning;
#endif
		voice[v].lfe_amp = FRSCALENEG(refv * 64, 27);
		switch (num_ochannels)
		{
		    case 2:
		      voice[v].lr_amp = 0;
		      voice[v].left_amp = FRSCALENEG(refv * (128-panning), 27);
		      voice[v].ce_amp = 0;
		      voice[v].right_amp = FRSCALENEG(refv * panning, 27);
		      voice[v].rr_amp = 0;
		      break;
		    case 4:
		      voice[v].lr_amp = FRSCALENEG(refv * panf(panning, 0, wide_panning), 27);
		      voice[v].left_amp = FRSCALENEG(refv * panf(panning, 32, wide_panning), 27);
		      voice[v].ce_amp = 0;
		      voice[v].right_amp = FRSCALENEG(refv * panf(panning, 95, wide_panning), 27);
		      voice[v].rr_amp = FRSCALENEG(refv * panf(panning, 128, wide_panning), 27);
		      break;
		    case 6:
#ifdef NEW_PANNER
	   if (panning >= LEFT_PAN_VALUE && panning <= RIGHT_PAN_VALUE) {
#endif
		      voice[v].lr_amp = FRSCALENEG(refv * panf(panning, opt_rear_right_position, wide_panning), 27);
		      voice[v].left_amp = FRSCALENEG(refv * panf(panning, opt_left_position, wide_panning), 27);
		      voice[v].ce_amp = FRSCALENEG(refv * panf(panning, opt_center_position, wide_panning), 27 /*28?*/);
		      voice[v].right_amp = FRSCALENEG(refv * panf(panning, opt_right_position, wide_panning), 27);
		      voice[v].rr_amp = FRSCALENEG(refv * panf(panning, opt_rear_right_position, wide_panning), 27);
#ifdef NEW_PANNER
	   }
	   else {
		   if (panning < LEFT_PAN_VALUE) panning += 80;
		   else panning -= 112 + 64;
		      voice[v].lr_amp = FRSCALENEG(refv * panf(panning, opt_right_position, wide_panning), 27);
		      voice[v].left_amp = 0;
		      voice[v].ce_amp = 0;
		      voice[v].right_amp = 0;
		      voice[v].rr_amp = FRSCALENEG(refv * panf(panning, opt_center_position, wide_panning), 27);
	   }
#endif
		      break;
		}
	}
    }
    else {
	voice[v].panned = PANNED_CENTER;

	voice[v].left_amp =
	    FRSCALENEG ((double) (tempamp) * voice[v].volume * master_volume,
			21);
    }
}


static int current_polyphony = 0;


/* just a variant of note_on() */
static int
vc_alloc (int j)
{
    int     i = voices;
    int     cpoly = 0, vc_ret = -1;

    while (i--) {
	if (i == j)
	    continue;
	if (voice[i].status == VOICE_FREE) {
	    vc_ret = i;
	}
	else if (voice[i].status & ~VOICE_DIE) {
	    cpoly++;
	}
    }
    if (cpoly <= voices - voice_reserve - voices_ceiling/4)
	return vc_ret;
    return -1;
}

static int
kill_others (int i)
{
    int     j = voices, ret = TRIGGER_FIRST;
    int     mono = channel[voice[i].channel].mono;

    if (!mono) return 0;

//    if (!voice[i].sample->exclusiveClass)
//	return TRIGGER_NONE;

    while (j--) {
	if (voice[j].status & (VOICE_FREE | VOICE_OFF | VOICE_DIE))
	    continue;
	if ( (voice[j].clone_type & IS_CLONE) )
	    continue;
	if (i == j)
	    continue;
	if (voice[i].channel != voice[j].channel)
	    continue;
	ret = TRIGGER_LEGATO;
	if (!voice[i].sample->exclusiveClass)
	    continue;
	if (voice[j].sample->exclusiveClass !=
	    voice[i].sample->exclusiveClass && mono < 0)
	    continue;
/* This doesn't sound good at all -- maybe use finish_note ?? */
	kill_note (j);
    }
    return ret;
}

#define INSTRUMENT_SEPARATION ((RIGHT_PAN_VALUE-LEFT_PAN_VALUE)/4)
static void
recompute_stereo_panning (int v, int w, unsigned panrequest)
{
    int     left, right, leftpan, rightpan;

    if (voice[v].sample->panning > voice[w].sample->panning) {
	left = w;
	right = v;
    }
    else {
	left = v;
	right = w;
    }
    leftpan = panrequest - INSTRUMENT_SEPARATION / 2;
    if (leftpan < 0) leftpan = 0;
    rightpan = leftpan + INSTRUMENT_SEPARATION;
    if (leftpan < LEFT_PAN_VALUE) {
	leftpan = LEFT_PAN_VALUE / 2 + (LEFT_PAN_VALUE - leftpan) / 2;
	rightpan = leftpan + INSTRUMENT_SEPARATION;
    }
    if (rightpan > 127) rightpan = 127;
    if (rightpan > RIGHT_PAN_VALUE) {
	rightpan = RIGHT_PAN_VALUE + (rightpan - RIGHT_PAN_VALUE) / 2;
	leftpan = rightpan - INSTRUMENT_SEPARATION;
    }
    voice[left].panning = leftpan;
    voice[right].panning = rightpan;
}


static void
clone_tutti (InstrumentLayer *lp, int i, int variationbank)
{
    int v;
    float send = 0;

    if ((v = vc_alloc (i)) < 0)
	return;

    voice[v] = voice[i];

    voice[v].clone_voice_tutti = i;
    voice[i].clone_voice_tutti = v;
    voice[v].clone_type = TUTTI_CLONE;

    switch (variationbank) {
	    case 52:
	    case 53:
	    case 54:
	    case 40: send = 0.50; break;
	    case 41: send = 0.80; break;
	    case 42: send = 1.00; break;
	    case 43: send = 1.20; break;
	    case 44: if (voice[v].velocity < 120) send = 0.30;
		     else send = 1.00;
		     break;
	    case 45: send = (float)voice[v].velocity / 127.00;
		     break;
    }

    voice[v].volume *= send;

    select_stereo_samples (v, lp, 0);

    recompute_freq (v);
    recompute_amp (v);
    recompute_envelope (v);
    recompute_modulation (&voice[v]);
    apply_envelope_to_amp (v);
}

#define DEFAULT_VIBRATO_SWEEP 14

static int debug_report[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};

static int parmxg(int pnum, int chan, int clone_type) {
    int small_parm = 0, big_parm = 0, is_variation;
    int XG_clone_variation_type = 0;

    is_variation = 1;

    if (!xg_parameter[SYSTEM_VARIATION_CONNECTION]) {
        if (xg_parameter[VARIATION_PART] == chan) {
	    if (pnum < 11) return ( (xg_parameter[0x42 + 2*(pnum-1)] << 8) +
			    	     xg_parameter[0x42 + 2*(pnum-1)+1] );
	    return xg_parameter[pnum - 11 + 0x70];
	}
	if (xg_insertion1_parameter[INSERTION_PART] == chan) {
	    if (pnum < 11) {
		small_parm = xg_insertion1_parameter[pnum - 1 + 0x02];
		big_parm = (xg_insertion1_parameter[0x30 + 2*(pnum - 1)] << 8) +
				xg_insertion1_parameter[1 + 0x30 + 2*(pnum - 1)];
	    }
	    else small_parm = big_parm = xg_insertion1_parameter[pnum - 11 + 0x20];
	    XG_clone_variation_type = XG_insertion1_type;
	}
	else if (xg_insertion2_parameter[INSERTION_PART] == chan) {
	    if (pnum < 11) {
		small_parm = xg_insertion2_parameter[pnum - 1 + 0x02];
		big_parm = (xg_insertion2_parameter[0x30 + 2*(pnum - 1)] << 8) +
				xg_insertion2_parameter[1 + 0x30 + 2*(pnum - 1)];
	    }
	    else small_parm = big_parm = xg_insertion2_parameter[pnum - 11 + 0x20];
	    XG_clone_variation_type = XG_insertion2_type;
	}
	else is_variation = 0;

	if (is_variation) switch (XG_clone_variation_type) {
		case DELAYLCR:
		case DELAYLR:
		case ECHO:
		case CROSSDELAY:
			return big_parm;
		default:
			return small_parm;
	}
    }
    else if (channel[chan].variation_depth > 0 || channel[chan].drylevel < 127) {
	    if (pnum < 11) return ( (xg_parameter[0x42 + 2*(pnum-1)] << 8) +
			    	     xg_parameter[0x42 + 2*(pnum-1)+1] );
	    return xg_parameter[pnum - 11 + 0x70];
    }
    if ((clone_type & REVERB_CLONE)) {
	    if (pnum < 11) return xg_parameter[0x02 + pnum - 1];
	    return xg_parameter[0x10 + pnum - 11];
    }
    if (pnum < 11) return xg_parameter[0x22 + pnum - 1];
    return xg_parameter[0x30 + pnum - 11];

}

static void
clone_voice (Instrument * ip, int v, MidiEvent * e, int clone_type,
	     int variationbank)
{
    Voice   *vpw, *vp = &voice[v];
    int     w, k, played_note, chorus, reverb, milli;
    int     chan = voice[v].channel;
    int	    XG_clone_chorus_type = XG_System_chorus_type;
    int	    XG_clone_reverb_type = XG_System_reverb_type;
    int	    XG_clone_variation_type = XG_System_variation_type;
    int	    dry_level, wet_level, stereo = 0;
    int	    reverb_time, initial_delay, er_balance = 64;
    int	    lfo_frequency, lfo_depth, chorus_feedback;

#ifdef WATCH_SQUARESQUARE
    if (clone_type != CHORUS_CLONE) return;
#endif
    reverb_time = xg_parameter[REVERB_TIME];
    initial_delay = xg_parameter[INITIAL_DELAY];
    dry_level = xg_parameter[DRY_LEVEL];
    lfo_depth = xg_parameter[LFO_DEPTH];
    er_balance = xg_parameter[ER_BALANCE];

    if (!xg_parameter[SYSTEM_VARIATION_CONNECTION] && xg_insertion1_parameter[INSERTION_PART] == chan) {
	    dry_level = xg_insertion1_parameter[INSERTION_DRY_LEVEL]; /* dry/wet */
	    XG_clone_variation_type = XG_insertion1_type;
	    reverb_time = xg_insertion1_parameter[INSERTION_REVERB_TIME]; /* LSB version */
	    lfo_depth = xg_insertion1_parameter[INSERTION_LFO_DEPTH]; /* LSB version */
	    initial_delay = xg_insertion1_parameter[INSERTION_INITIAL_DELAY]; /* LSB version */
	    er_balance = xg_insertion1_parameter[INSERTION_ER_BALANCE]; /* LSB version */
    	    if (!debug_report[chan] && dry_level < 127) {
		ctl->cmsg(CMSG_TRACE,VERB_DEBUG, "ins 1, chan %d: wet=%d=%d", chan+1, 127-dry_level,
				127 - parmxg(10, chan, clone_type));
    	    }
    }
    else if (!xg_parameter[SYSTEM_VARIATION_CONNECTION] && xg_insertion2_parameter[INSERTION_PART] == chan) {
	    dry_level = xg_insertion2_parameter[INSERTION_DRY_LEVEL]; /* dry/wet */
	    XG_clone_variation_type = XG_insertion2_type;
	    reverb_time = xg_insertion2_parameter[INSERTION_REVERB_TIME]; /* LSB version */
	    lfo_depth = xg_insertion2_parameter[INSERTION_LFO_DEPTH]; /* LSB version */
	    initial_delay = xg_insertion2_parameter[INSERTION_INITIAL_DELAY]; /* LSB version */
	    er_balance = xg_insertion2_parameter[INSERTION_ER_BALANCE]; /* LSB version */
    	    if (!debug_report[chan] && dry_level < 127) {
		ctl->cmsg(CMSG_TRACE,VERB_DEBUG, "ins 2, chan %d: wet=%d=%d", chan+1, 127-dry_level,
				127 - parmxg(10, chan, clone_type));
    	    }
    }
    else if (!xg_parameter[SYSTEM_VARIATION_CONNECTION] && xg_parameter[VARIATION_PART] == chan) {
	    dry_level = (xg_parameter[VARIATION_DRY_LEVEL] << 8) + xg_parameter[VARIATION_DRY_LEVEL+1];
	    reverb_time = (xg_parameter[VARIATION_REVERB_TIME] << 8) + xg_parameter[VARIATION_REVERB_TIME+1];
	    lfo_depth = (xg_parameter[VARIATION_LFO_DEPTH] << 8) + xg_parameter[VARIATION_LFO_DEPTH+1];
	    initial_delay = (xg_parameter[VARIATION_INITIAL_DELAY] << 8) +
		    xg_parameter[VARIATION_INITIAL_DELAY+1];
	    er_balance = (xg_parameter[VARIATION_ER_BALANCE] << 8) +
		    xg_parameter[VARIATION_ER_BALANCE+1];
    	    if (!debug_report[chan] /*&& dry_level < 127*/) {
		ctl->cmsg(CMSG_TRACE,VERB_DEBUG, "ins var, chan %d: wet=%d=%d", chan+1, 127-dry_level,
				127 - parmxg(10, chan, clone_type));
    	    }
    }
    else if (xg_parameter[SYSTEM_VARIATION_CONNECTION]) {
	    dry_level = 127 - channel[chan].variation_depth;
	    if (channel[chan].kit && drumvariationsend[chan][e->a & 0x7f] > -1)
		    dry_level = 127 - drumvariationsend[chan][e->a & 0x7f];
	    if (channel[chan].drylevel < dry_level) dry_level = channel[chan].drylevel;
    	    if (!debug_report[chan] /*&& dry_level < 127*/) {
		ctl->cmsg(CMSG_TRACE,VERB_DEBUG, "sys var, chan %d: wet=%d=%d", chan+1, 127-dry_level,
				127 - parmxg(10, chan, clone_type));
    	    }
    }
    else dry_level = 127;

    if (initial_delay > 127) initial_delay = 127;
//reverb_time = parmxg(1, chan, clone_type);

    lfo_frequency = reverb_time;
    chorus_feedback = initial_delay;

    if (!debug_report[chan] && clone_type == REVERB_CLONE) {
	debug_report[chan] = 1;
	if (dry_level == 127)
	ctl->cmsg(CMSG_TRACE,VERB_DEBUG, "no var eff. chan %d", chan+1);
	ctl->cmsg(CMSG_TRACE,VERB_DEBUG, "r.t.=%d p1=%d chan %d",
		       reverb_time, parmxg(1, chan, REVERB_CLONE), chan+1);
	ctl->cmsg(CMSG_TRACE,VERB_DEBUG, "i.d.=%d p3=%d chan %d",
		       initial_delay, parmxg(3, chan, REVERB_CLONE), chan+1);
    }

    chorus = opt_dry? 0 : ip->sample->chorusdepth;
    reverb = opt_dry? 0 : ip->sample->reverberation;

    wet_level = 127 - dry_level;

    if (wet_level) {
	int     v_type = XG_clone_variation_type >> 4;

        if (v_type > 0 && v_type <= 20) {
	    reverb = wet_level;
	    XG_clone_reverb_type = XG_clone_variation_type;
        }
	else if (v_type > 0x40) {
	    chorus = wet_level;
	    if (wet_level > 64) stereo = 1;
	    XG_clone_chorus_type = XG_clone_variation_type;
	}
	if (clone_type == STEREO_CLONE) switch(XG_clone_variation_type) {
	    case DELAYLCR:
	    case DELAYLR:
	    case ECHO:
	    case CHORUS4:
	    case CELESTE4:
	    case SYMPHONIC:
		stereo = 1;
		break;
	}
    }

    if ( (clone_type & STEREO_CLONE) ) {
	if (!vp->right_sample && variationbank != 3 && !stereo)
	    return;
	if (variationbank == 6)
	    return;
    }

    if (channel[chan].kit) {
	if ((k = drumreverberation[chan][vp->note]) >= 0)
	    reverb = (reverb > k) ? reverb : k;
	if ((k = drumchorusdepth[chan][vp->note]) >= 0)
	    chorus = (chorus > k) ? chorus : k;
    }
    else {
	if ((k = channel[chan].chorusdepth) >= 0)
	    chorus = (chorus > k) ? chorus : k;
	if ((k = channel[chan].reverberation) >= 0)
	    reverb = (reverb > k) ? reverb : k;
    }

    if ( (clone_type & REVERB_CLONE) )
	chorus = 0;
    else if ( (clone_type & CHORUS_CLONE) )
	reverb = 0;
    else if ( (clone_type & STEREO_CLONE) )
	reverb = chorus = 0;

    if (clone_type == CHORUS_CLONE && channel[chan].effect && !XG_clone_chorus_type) {
	    int effect = channel[chan].effect >> 8;
	    int amount = channel[chan].effect & 0xff;

	    if (effect == ME_CELESTE_EFFECT && (reverb_options & OPT_CELESTE_VOICE)) {
	        chorus = amount;
		XG_clone_chorus_type = CELESTE1;
	    }
	    else if (effect == ME_PHASER_EFFECT) {
	        chorus = amount;
		XG_clone_chorus_type = PHASER;
	    }
    }

    if (reverb > 127)
	reverb = 127;
    if (chorus > 127)
	chorus = 127;

    if ( (clone_type & REVERB_CLONE) ) {
	if ((reverb_options & OPT_REVERB_EXTRA) && reverb < global_echo)
	    reverb = global_echo;
	if (e->b < 20) return;
	if (dont_reverb > 3) return;
	if (dont_reverb > 2 && e->b < 110) return;
	if (dont_reverb > 1 && e->b < 90) return;
	if (dont_reverb > 0 && e->b < 60) return;
    }
    if ( (clone_type & CHORUS_CLONE) ) {
	if (variationbank == 32) chorus = 30;
	else if (variationbank == 33) chorus = 60;
	else if (variationbank == 34) chorus = 90;
	else if (variationbank == 34) chorus = 120;
	if ((reverb_options & OPT_CHORUS_EXTRA) && chorus < global_detune)
	    chorus = global_detune;
	if (dont_chorus > 3) return;
	if (dont_chorus > 2 && e->b < 110) return;
	if (dont_chorus > 1 && e->b < 90) return;
	if (dont_chorus > 0 && e->b < 60) return;
    }

    if (!vp->right_sample) {
	vp->right_sample = vp->sample;
    }
    else if ( (clone_type & STEREO_CLONE) )
    /* don't try to fake a second patch if we have a real one */
	variationbank = 0;

    if (!reverb && !chorus && !(clone_type & STEREO_CLONE) ) return;

    if ((w = vc_alloc (v)) < 0) return;

    voice[w] = voice[v];
    vpw = &voice[w];

    vpw->reso_phase_increment = 0;

#ifdef WATCH_SQUARE
    if (chan == 6) {
        fprintf(stderr,"clone %d of %d: chorus %d reverb %d\n", w, v, chorus, reverb);
    }
#endif
    switch (clone_type) {
	    case STEREO_CLONE:
		    vp->clone_voice_stereo = w;
		    vpw->clone_voice_stereo = v;
		    break;
	    case REVERB_CLONE:
		    vp->clone_voice_reverb = w;
		    vpw->clone_voice_reverb = v;
		    break;
	    case CHORUS_CLONE:
		    vp->clone_voice_chorus = w;
		    vpw->clone_voice_chorus = v;
		    break;
    }
    vpw->clone_type = clone_type;
    if ( (clone_type & STEREO_CLONE) ) {
        vp->clone_type = HAS_CLONE;
    }

    vpw->sample = vp->right_sample;
#ifdef DUBIOUS_MANEUVER
    vpw->velocity = (e->b * (127 - vpw->sample->attenuation)) / 127;
#else
    vpw->velocity = e->b;
#endif
    vpw->current_x0 =
	vpw->current_x1 = vpw->current_y0 = vpw->current_y1 = vpw->current_y2 = 0;

    if (!channel[chan].mw_amod) {
    	vpw->tremolo_sweep = vpw->sample->tremolo_sweep_increment;
    	vpw->tremolo_depth = vpw->sample->tremolo_depth;
    	vpw->tremolo_phase_increment =
		vpw->sample->tremolo_phase_increment;
    }
#if 0
    vpw->lfo_sweep = vpw->sample->lfo_sweep_increment;
    vpw->lfo_phase_increment = vpw->sample->lfo_phase_increment;
    vpw->lfo_depth = vpw->sample->lfo_depth;
#endif 
#if 0
    /* put this back ? */
    vpw->modLfoToFilterFc = vpw->sample->modLfoToFilterFc;
    vpw->modEnvToFilterFc = vpw->sample->modEnvToFilterFc;
    vpw->modEnvToPitch = vpw->sample->modEnvToPitch;
#endif 

    if (!channel[chan].vibrato_ratio) {
        vpw->vibrato_sweep = vpw->sample->vibrato_sweep_increment;
        vpw->vibrato_depth = vpw->sample->vibrato_depth;
        vpw->vibrato_control_ratio = vpw->sample->vibrato_control_ratio;
    }

    if (vpw->right_sample)
	vpw->panning = vpw->right_sample->panning;
    else
	vpw->panning = RIGHT_PAN_VALUE;

    milli = play_mode->rate / 1000;

    if ( (clone_type & STEREO_CLONE) ) {
	if (variationbank == 3) {
	    vp->panning = LEFT_PAN_VALUE;
	    vpw->panning = RIGHT_PAN_VALUE;
	}
	else recompute_stereo_panning (v, w, vp->panning);
#ifdef DEBUG_CLONE_NOTES
	fprintf (stderr, "STEREO_CLONE v%d vol%f pan%d\n", w, vpw->volume,
		 vpw->panning);
#endif
    }

#ifdef tplus
    vpw->porta_control_ratio = vp->porta_control_ratio;
    vpw->porta_dpb = vp->porta_dpb;
    vpw->porta_pb = vp->porta_pb;
    /* ?? vpw->vibrato_delay = 0; */
    vpw->vibrato_delay = vpw->sample->vibrato_delay;
    vpw->modulation_delay = vpw->sample->modulation_rate[DELAY];
#endif
    vpw->volume = vpw->sample->volume;


    if (reverb) {

#if 1
	vpw->algorithm = INTERPOLATION_LINEAR;
#else
	vpw->algorithm = INTERPOLATION_LINEAR | INTERPOLATION_VSF;
	vpw->filter_type = FILTER_LOWPASS;
#endif
	if (opt_stereo_surround) {
	    if (vpw->panning > CENTER_PAN_VALUE)
		vpw->panning = RIGHT_PAN_VALUE;
	    else
		vpw->panning = LEFT_PAN_VALUE;
	}
	else {
	    if (vp->panning < CENTER_PAN_VALUE)
		vpw->panning = CENTER_PAN_VALUE + reverb / 2;
	    else
		vpw->panning = CENTER_PAN_VALUE - reverb / 2;
	}

#ifdef DEBUG_REVERBERATION
	printf ("r=%d vol %f", reverb, vpw->volume);
#endif

/* try 98->99 for melodic instruments ? (bit much for percussion) */

	//vpw->volume *= vol_table[(127 - initial_delay) / (8 + (er_balance-64)/10) + 98];
	//vpw->volume *= vol_table[(127 - initial_delay) / (8 + (er_balance-64)/10) + 97 + reverb/32];
 
#ifdef DEBUG_REVERBERATION
	printf (" -> vol %f", vpw->volume);

	printf (" delay %d", vpw->echo_delay);
#endif
	/*vpw->echo_delay += (reverb>>1) * milli; */
	//vpw->echo_delay += reverb * milli;
	//vpw->echo_delay = reverb_delay;
	//vpw->echo_delay = play_mode->rate * xg_10th_millisecond_delay[reverb_delay] / 10000;
#if 0
/* moved down */
	vpw->echo_delay = play_mode->rate * initial_delay / 1000;

	if (reverb_time < MAX_MILLI_DELAY)
	    vpw->reverb_time = play_mode->rate * xg_10th_millisecond_delay[reverb_time] / 10000;
	else
	    vpw->reverb_time = play_mode->rate * reverb_time / 10000;

#ifdef DEBUG_REVERBERATION
	printf (" -> delay %d\n", vpw->echo_delay);
#endif
#endif
	/* ?? */
	///if (channel[chan].brightness > 84)
	///	vpw->orig_frequency *= 2;
	//else if (channel[chan].brightness < 44)
	//	vpw->orig_frequency /= 2;

	vpw->envelope_rate[DECAY] *= 2;
	vpw->envelope_rate[RELEASE] /= 2;


	switch (XG_clone_reverb_type) {
	    case 0:		/* no effect */
		break;
	    case HALL1:
		break;
	    case HALL2:
		vpw->cutoff_freq *= 2;
		break;
	    case ROOM1:
		vpw->cutoff_freq /= 2;
	        if (vp->panning < CENTER_PAN_VALUE)
		    vpw->panning = CENTER_PAN_VALUE + reverb / 4;
	        else
		    vpw->panning = CENTER_PAN_VALUE - reverb / 4;
		break;
	    case ROOM2:
		vpw->cutoff_freq /= 3;
		break;
	    case ROOM3:
		vpw->cutoff_freq /= 4;
		break;
	    case STAGE1:
	    case STAGE2:
		vpw->velocity = vp->velocity;
		break;
	    case PLATE:		/* plate */
		vpw->panning = vp->panning;
		vpw->resonance = 10;
		break;
	    case DELAYLCR:		/* Delay L,C,R */
		break;
	    case DELAYLR:		/* Delay L,R */
		break;
	    case ECHO:		/* Echo */
		//vp->echo_delay = vpw->echo_delay / 2;
		vpw->resonance = 20;
		vpw->panning = 0; /* behind */
		break;
	    case CROSSDELAY:		/* Cross-delay */
		break;
	    case ER1:		/* Early Reflections */
	    case ER2:
		vpw->cutoff_freq *= 2;
		vpw->resonance = 5;
		break;
	    case GATEREVERB:		/* Gate Delay */
		break;
	    case REVERSEGATE:		/* Reverse Gate */
		break;
	    case WHITEROOM:		/* white room */
		vpw->orig_frequency *= 2;
		break;
	    case TUNNEL:		/* tunnel */
		vpw->velocity /= 2;
		vpw->resonance = 5;
		break;
	    case CANYON:		/* canyon */
		//vpw->orig_frequency /= 2;
		vpw->resonance = 10;
		/* pan to rears */
		if (vp->panning > CENTER_PAN_VALUE) vpw->panning = 8;
		else vpw->panning = 120;
		break;
	    case BASEMENT:		/* basement */
		vpw->velocity /= 2;
		break;
	    default:
		break;
	}


	vpw->volume *= vol_table[(127 - initial_delay) / (8 + (er_balance-64)/10) + 97 + reverb/32];

	vpw->echo_delay = play_mode->rate * initial_delay / 1000;

	if (reverb_time < MAX_MILLI_DELAY)
	    vpw->reverb_time = play_mode->rate * xg_10th_millisecond_delay[reverb_time] / 10000;
	else
	    vpw->reverb_time = play_mode->rate * reverb_time / 10000;

#ifdef DEBUG_CLONE_NOTES
	fprintf (stderr,
		 "REVERB_CLONE v%d vol=%f pan=%d reverb=%d delay=%dms\n", w,
		 vpw->volume, vpw->panning, reverb,
		 vpw->echo_delay / milli);
#endif
    } /* end if reverb */

    played_note = vpw->sample->note_to_use;
    if (!played_note) {
	played_note = e->a & 0x7f;
	if (variationbank == 35)
	    played_note += 12;
	else if (variationbank == 36)
	    played_note -= 12;
	else if (variationbank == 37)
	    played_note += 7;
	else if (variationbank == 38)
	    played_note -= 7;
    }
#if 0
/* There may be a bug here, probably in unsf.  Play it safe.*/
    played_note =
	((played_note -
	  vpw->sample->freq_center) * vpw->sample->freq_scale) /
	1024 + vpw->sample->freq_center;
#endif
    vpw->note = played_note;
    vpw->orig_frequency = freq_table[played_note];

#ifdef WATCH_SQUARE
    if (chorus) {
	/*vpw->orig_frequency += (vpw->orig_frequency/128) * chorus; */
/*fprintf(stderr, "voice %d v sweep from %ld (cr %d, depth %d)", w, vpw->vibrato_sweep,
	 vpw->vibrato_control_ratio, vpw->vibrato_depth);*/

	vpw->algorithm |= INTERPOLATION_LINEAR;

	if (opt_stereo_surround) {
	    if (vp->panning < CENTER_PAN_VALUE)
		vpw->panning = vp->panning + (RIGHT_PAN_VALUE - CENTER_PAN_VALUE)/2;
	    else
		vpw->panning = vp->panning - (CENTER_PAN_VALUE - LEFT_PAN_VALUE)/2;
	}

	if (!vpw->vibrato_control_ratio) {
	    vpw->vibrato_control_ratio = /* 100*/ chorus_feedback;
	    vpw->vibrato_depth = /*6*/ lfo_depth / 9;
	    vpw->vibrato_sweep = 74;
	}
	/*vpw->velocity = (vpw->velocity * chorus) / 128; */
#if 0
	vpw->velocity = (vpw->velocity * chorus) / (128 + 96);
	vp->velocity = vpw->velocity;
	vpw->volume = (vpw->volume * chorus) / (128 + 96);
	vp->volume = vpw->volume;
#endif
	/* vpw->volume *= 0.9; */

	//vpw->volume *= 0.40;
	//vp->volume = vpw->volume;
	//vpw->volume *= (double)chorus / 127.0;
#define UNWISE_CHORUS_VOLUME_ADJUST

	vpw->volume *= (double)chorus / 127.0;
#ifdef UNWISE_CHORUS_VOLUME_ADJUST
	vp->volume *= (double)(127 - chorus/2) / 127.0;

	recompute_amp (v);
	apply_envelope_to_amp (v);
#endif
	//vpw->volume *= 1.0 + (float)(channel[chan].brightness - 64) / 64.0;

	vpw->vibrato_sweep = lfo_frequency / 2;
	vpw->vibrato_depth /= 2;
	if (!vpw->vibrato_depth)
	    vpw->vibrato_depth = 2;
	vpw->vibrato_control_ratio /= 2;
	/*vpw->vibrato_control_ratio += chorus; */
/*fprintf(stderr, " to %ld (cr %d, depth %d).\n", vpw->vibrato_sweep,
	 vpw->vibrato_control_ratio, vpw->vibrato_depth);
	vpw->vibrato_phase = 20;*/

	/* vpw->echo_delay += 30 * milli; Makes note onsets squawk. */

	if (channel[chan].harmoniccontent > 84)
		vpw->orig_frequency = 3 * vpw->orig_frequency / 2;
	//else if (channel[chan].harmoniccontent < 44)
	//	vpw->orig_frequency = 2 * vpw->orig_frequency / 3;


	switch (XG_clone_chorus_type) {
	    case 0:		/* no effect */
		break;
#if 0
	    case CHORUS2:
	    case CHORUS3:
	    case CHORUS4:
		    vpw->vibrato_depth *= 2;
	    case CHORUS1:
		chorus /= 3;
		if (channel[vpw->channel].pitchbend + chorus < 0x2000)
		    vpw->orig_frequency =
			(uint32) ((FLOAT_T) vpw->orig_frequency *
				  bend_fine[chorus]);
		else
		    vpw->orig_frequency =
			(uint32) ((FLOAT_T) vpw->orig_frequency /
				  bend_fine[chorus]);
		break;
#endif
	    case CELESTE1:
	    case CELESTE2:
	    case CELESTE3:
	    case CELESTE4:
		/* "A 3-phase LFO is used to give modulation and
		 * spaciousness."
		 */
		vpw->orig_frequency +=
		    (vpw->orig_frequency / 2048) * (chorus/2);
		vpw->vibrato_control_ratio = 5;
		vpw->vibrato_sweep = 32;
		break;
	    case FLANGER1:
	    case FLANGER2:
	    case FLANGER3:
		/* "An effect reminiscent of a jet airplane taking off and landing." */
		vpw->vibrato_control_ratio = 10;
		vpw->vibrato_depth = 100;
		vpw->vibrato_sweep = 8;
		//vpw->echo_delay += 100 * milli;
		vpw->modEnvToPitch = 0.98;
		vpw->modulation_wheel = 10;
		break;
	    case SYMPHONIC: 	/* Symphonic : cf Children of the Night /128 bad, /1024 ok */
		/* "A multi-stage version of CELESTE modulation." */
		vpw->orig_frequency +=
		    (vpw->orig_frequency / 1024) * (chorus/2);
		vp->orig_frequency -=
		    (vp->orig_frequency / 1024) * (chorus/2);
		recompute_freq (v);
		break;
	    case ROTARYSPEAKER:
	    		/* Rotary Speaker: "AC1 can be used to control the
			 * rotation."
			 */
	    		/* 2way Rotary Speaker: "AC1 can be used to control the
			 * rotation."
			 */
		vpw->tremolo_depth = 10;
		vpw->tremolo_sweep = convert_tremolo_sweep(32);
		vpw->tremolo_phase_increment = convert_tremolo_rate(10);
		break;
	    case TREMOLO:	/* Tremolo: "...cyclically modulates volume." */
		vpw->tremolo_depth = 10;
		vpw->tremolo_sweep = convert_tremolo_sweep(32);
		vpw->tremolo_phase_increment = convert_tremolo_rate(100);
		break;
	    case PHASER:	/* Phaser: "Cyclically changes the phase to modulate.." */
	    case PHASER2:
		vpw->vibrato_control_ratio = 10;
		vpw->vibrato_depth = 100;
		vpw->vibrato_sweep = 8;
		vpw->modEnvToPitch = 0.97;
		break;

	    case AUTOPAN:	/* Auto Pan: "Cyclically moves the sound between
			 	 * left/right and front/back" */
	    case DISTORTION:	/* Distortion: "... with an edge to the sound." */
	    case OVERDRIVE:	/* Overdrive: "Adds mild distortion ..." */
	    case AMPSIMULATOR:	/* Amp Simulator */
	    case EQ3BAND:	/* 3Band EQ(Mono) */
	    case EQ2BAND:	/* 2Band EQ(Stereo) */
	    case AUTOWAH:	/* Auto Wah(LFO...) */
	    case TOUCHWAH:	/* Touch Wah */
	    case PITCHCHANGE:	/* Pitch Change */
	    case AURALEXCITER:	/* Aural Exciter: "... adds new overtones..." */
	    case COMPRESSOR:	/* Compressor: "Holds down the output when the input
	   		 	 * exceeds a specified level.  Can also be used to
			 	 * add a sense of attack."
				 */
	    case NOISEGATE:	/* Noise Gate */
	    case VOICECANCEL:	/* Voice Cancel */
#if 0
	    case ENSEMBLEDETUNE:	/* Ensemble detune: "Chorus effect without modulation,
					 * created by adding a slightly pitch-shifted sound."
			 		 */
	    case AMBIENCE:	/* Ambience: "An effect which adds spatial breadth
			 	 * by blurring the location of the sound."
			 	 */
		/* and 5D, 5E, 5F, 60, 61 */
#endif
	    case CHORUS2:
	    case CHORUS3:
	    case CHORUS4:
		    vpw->vibrato_depth *= 2;
	    case CHORUS1:
	    default:
		if (vpw->cutoff_freq > 8000) vpw->cutoff_freq -= 100;
		if (vpw->cutoff_freq > 3000) vpw->cutoff_freq -= 100;
	    	if (channel[vpw->channel].pitchbend + lfo_depth < 0x2000)
			vpw->orig_frequency =
		    	(uint32) ((FLOAT_T) vpw->orig_frequency *
			      	bend_fine[lfo_depth]);
	    	else
			vpw->orig_frequency =
		    	(uint32) ((FLOAT_T) vpw->orig_frequency /
			      	bend_fine[lfo_depth]);
		break;
	}

#ifdef DEBUG_CLONE_NOTES
	fprintf (stderr, "CHORUS_CLONE v%d vol%f pan%d chorus%d\n", w,
		 vpw->volume, vpw->panning, chorus);
#endif
    } /* end if chorus */

#endif /* no WATCH_SQUARE */

#ifdef ENABLE_XG_STEREO_EFFECT
    if (clone_type == STEREO_CLONE && stereo) {
	int lch_delay;

	switch(XG_clone_variation_type) {
	    case DELAYLCR:
	    case DELAYLR:
	    case ECHO:
		lch_delay = parmxg(1, chan, clone_type);
		vpw->volume *= (double)wet_level / 127.0;
		vpw->echo_delay = play_mode->rate * lch_delay / 1000;
	        vpw->reverb_time = vpw->echo_delay;
		vpw->panning = 0;
		break;
	    case CHORUS4:
	    case CELESTE4:
		break;
	    case SYMPHONIC: 	/* Symphonic : cf Children of the Night /128 bad, /1024 ok */
		/* "A multi-stage version of CELESTE modulation." */
		vpw->orig_frequency +=
		    (vpw->orig_frequency / 1024) * (64/2);
		break;
	}
    }

#endif /* no WATCH_SQUARE */


    vpw->loop_start = vpw->sample->loop_start;
    vpw->loop_end = vpw->sample->loop_end;
    vpw->echo_delay_count = vpw->echo_delay;
    //if (reverb)
    //	vpw->echo_delay *= 2;

    recompute_freq (w);
    recompute_amp (w);

    if ( (clone_type & STEREO_CLONE) ) {
	recompute_amp (v);
    }

    if (vpw->sample->modes & MODES_ENVELOPE) {
	/* Ramp up from 0 */
	vpw->envelope_stage = ATTACK;
	vpw->modulation_stage = ATTACK;
	vpw->envelope_volume = 0;
	vpw->modulation_volume = 0;
	vpw->control_counter = 0;
	vpw->modulation_counter = 0;
	recompute_envelope (w);
	if (vpw->cutoff_freq) {
	    vpw->bw_index = (vpw->cutoff_freq + 50) / 100;
	    if (vpw->bw_index < 1) vpw->bw_index = 1;
	    else if (vpw->bw_index >= MAX_BW_INDEX)
		    vpw->bw_index = MAX_BW_INDEX - 1;
	}
	else
	    vpw->bw_index = 0;
	recompute_modulation (vpw);
	apply_envelope_to_amp (w);
    }
    else {
	vpw->envelope_increment = 0;
	vpw->modulation_increment = 0;
	apply_envelope_to_amp (w);
    }
}

static void
xremap (int *banknumpt, int *this_notept, int this_kit)
{
    int     i, newmap;
    int     banknum = *banknumpt;
    int     this_note = *this_notept;
    int     newbank, newnote;

    if (!this_kit) {
	/* FIXME: Use the table. */
	if (banknum == SFXBANK && tonebank[SFXBANK])
	    return;
	if (banknum == SFXBANK && tonebank[120])
	    *banknumpt = 120;
	return;
    }

    if (this_kit == 125 || this_kit == 126) {
	    if (drumset[SFXDRUM2] && drumset[SFXDRUM2]->tone[*this_notept].layer) *banknumpt = SFXDRUM2;
	    else if (drumset[SFXDRUM1] && drumset[SFXDRUM1]->tone[*this_notept].layer) *banknumpt = SFXDRUM1;
	    else if (drumset[122] && drumset[122]->tone[*this_notept].layer) *banknumpt = 122;
	    else if (drumset[121] && drumset[121]->tone[*this_notept].layer) *banknumpt = 121;
	    return;
    }

    if (this_kit != 127 && this_kit != 126 && this_kit != 125)
	return;

    for (i = 0; i < XMAPMAX; i++) {
	newmap = xmap[i][0];
	if (!newmap)
	    return;
	if (this_kit == 127 && newmap != XGDRUM)
	    continue;
	if ( (this_kit == 126||this_kit == 125) && newmap != SFXDRUM1)
	    continue;
	if (xmap[i][1] != banknum)
	    continue;
	if (xmap[i][2] != this_note)
	    continue;
	newbank = xmap[i][3];
	newnote = xmap[i][4];
	if (newbank == banknum && newnote == this_note)
	    return;
	if (!drumset[newbank])
	    return;
	if (!drumset[newbank]->tone[newnote].layer)
	    return;
	if (drumset[newbank]->tone[newnote].layer == MAGIC_LOAD_INSTRUMENT)
	    return;
	*banknumpt = newbank;
	*this_notept = newnote;
	return;
    }
}

/* #define VSF_TEST */

#ifdef RESO_TEST
static int reso_test = 1;
#endif

static void
start_note (MidiEvent * e, int i)
{
    InstrumentLayer *lp;
    Instrument *ip;
    Voice   *vp = &voice[i];
    int     j, banknum, ch = e->channel;
    int     played_note, drumpan = NO_PANNING, drum_pitch = -1;
    int32   rt;
    int     attacktime, releasetime, decaytime;
    int     brightness = channel[ch].brightness;
    int     harmoniccontent = channel[ch].harmoniccontent;
    int     variationbank = channel[ch].variationbank;
    int     this_note = e->a & 0x7f;
    int     this_velocity = e->b;
    int     drumsflag = channel[ch].kit;
    int     this_prog = channel[ch].program;
    int     this_bank = channel[ch].bank;
    int     trigger;

    if (check_for_rc ())
	return;

    vp->time = e->time;
#ifdef VSF_TEST
    //vp->reso_max = 240;
    //vp->reso_max = 180;
    vp->reso_max = 80;
    vp->algorithm = INTERPOLATION_MOOG;
    //vp->algorithm = INTERPOLATION_BUTTERWORTH;
    vp->filter_type = FILTER_LOWPASS;
    vp->drive = 0;
#else
    //vp->reso_max = 100;
    //vp->reso_max = 120; /* reducing cutoff doesn't make much difference for this value */
    vp->reso_max = 80;
    vp->algorithm = current_interpolation;
    vp->filter_type = FILTER_LOWPASS;
    vp->drive = 0;
#endif

    if (drumsflag) banknum = this_bank;
    else if (channel[ch].sfx)
	banknum = channel[ch].sfx;
    else if (channel[ch].xg == 48 &&
	   tonebank[this_bank+variationbank+MU100BANK] &&
	   tonebank[this_bank+variationbank+MU100BANK]->tone[this_prog].layer)
	banknum = this_bank + variationbank+MU100BANK;
    else if (channel[ch].xg == 33 &&
	   tonebank[this_bank+variationbank+VLBANK] &&
	   tonebank[this_bank+variationbank+VLBANK]->tone[this_prog].layer)
	banknum = this_bank + variationbank+VLBANK;
    else if (XG_System_On &&
	   this_bank+variationbank > 0 &&
	   this_bank+variationbank < NUM_VARIATION_BANKS &&
	   tonebank[this_bank+variationbank+SFXBANK] &&
	   tonebank[this_bank+variationbank+SFXBANK]->tone[this_prog].layer)
	banknum = this_bank + variationbank+SFXBANK;
    else
	banknum = this_bank;

    if (opt_bank && !drumsflag && !banknum &&
	tonebank[opt_bank] && tonebank[opt_bank]->tone[this_prog].layer)
	banknum = opt_bank;
#if 0
if (ch == 6 && channel[ch].xg == 48) {
fprintf(stderr,"ch7 mu bank%d var%d prog%d bnum%d exists %s\n",
	       	this_bank, variationbank, this_prog, banknum,
		tonebank[banknum]->tone[this_prog].layer? "yes":"no");
}
#endif

    vp->velocity = this_velocity;

    if (XG_System_On)
	xremap (&banknum, &this_note, drumsflag);

    if (drumsflag) {
	if (!drumset[banknum] || !(lp = drumset[banknum]->tone[this_note].layer)) {
	    if (!(lp = drumset[0]->tone[this_note].layer))
		return;		/* No instrument? Then we can't play. */
	}
	ip = lp->instrument;
	if (ip->type == FONT_GUS && ip->samples != 1) {
	    ctl->cmsg (CMSG_WARNING, VERB_VERBOSE,
		       "Strange: percussion instrument with %d samples!",
		       ip->samples);
	    return;
	}

	drumpan = drumpanpot[ch][this_note];
	drum_pitch = drumpitch[ch][this_note];

	if (drum_pitch >= 0 && drum_pitch < 128) {
	    vp->orig_frequency = freq_table[drum_pitch];
	}
	else if (ip->sample->note_to_use && !channel[ch].transpose) {	/* Do we have a fixed pitch? */
	    vp->orig_frequency =
		freq_table[(int) (ip->sample->note_to_use)];
	}
	else
	    vp->orig_frequency = freq_table[this_note];
    }
    else {
	if (this_prog == SPECIAL_PROGRAM)
	    lp = default_instrument;
	else if (!tonebank[banknum] || !(lp = tonebank[banknum]->tone[this_prog].layer)) {
	    if (!(lp = tonebank[0]->tone[this_prog].layer))
		return;		/* No instrument? Then we can't play. */
	}
	ip = lp->instrument;

	if (ip->sample->note_to_use)	/* Fixed-pitch instrument? */
	    vp->orig_frequency =
		freq_table[(int) (ip->sample->note_to_use)];
	else
	    vp->orig_frequency = freq_table[e->a & 0x7F];
    }				/* not drum channel */

    vp->sample = ip->sample;

    trigger = kill_others (i);
    select_stereo_samples (i, lp, trigger);

    vp->initial_offset = 0;
#ifdef ADHOC_LEGATO
    if (!drumsflag && lp->font_type != FONT_SFZ && trigger == TRIGGER_LEGATO) {
    	uint32  samp_milli;
	samp_milli = vp->sample->sample_rate/1000;
	if ((vp->sample->loop_start>>FRACTION_BITS) > samp_milli*80)
	    vp->initial_offset = ((32*samp_milli)<<FRACTION_BITS);
    }
#endif

    vp->starttime = e->time;
    played_note = vp->sample->note_to_use;
    if (!played_note || !drumsflag)
	played_note = this_note & 0x7f;

#if 0
    played_note =
	((played_note -
	  vp->sample->freq_center) * vp->sample->freq_scale) /
	1024 + vp->sample->freq_center;
#endif
    vp->note = played_note;
    vp->orig_frequency = freq_table[played_note];

/* Necessary for ind34xg.mid, otherwise synthtom note sticks and grows. */

    vp->status = VOICE_ON;
    vp->channel = ch;
#ifdef OBVIATE_PREVIOUS_CODE
    vp->note = e->a;
#endif
#ifdef DUBIOUS_MANEUVER
    vp->velocity = (e->b * (127 - vp->sample->attenuation)) / 127;
#else
    vp->velocity = e->b;
#endif
    vp->sample_offset = 0;
    vp->sample_increment = 0;	/* make sure it isn't negative */
    /* why am I copying loop points? */
    vp->loop_start = vp->sample->loop_start;
    vp->loop_end = vp->sample->loop_end;
    vp->volume = vp->sample->volume;
    vp->cutoff_freq = vp->sample->cutoff_freq;
#if 0
/* this doesn't seem to be doing any good */
#define MIN_CUTOFF 1000
/* very low cutoff makes instruments inaudible -- probably the filter envelopes are wrong */
    if (vp->cutoff_freq < MIN_CUTOFF) vp->cutoff_freq = MIN_CUTOFF;
#endif

#ifdef VSF_TEST
#define MAX_CUTOFF 12000
    if (vp->cutoff_freq > MAX_CUTOFF) vp->cutoff_freq = MAX_CUTOFF;
#endif

    if (vp->sample->amp_random > 0.1) {
	    double ar = vp->sample->amp_random * rand() / (RAND_MAX);
#ifdef WATCH_RANDOM_AMP
fprintf(stderr,"amp_random=%f, rand ar=%f, vol=%f", vp->sample->amp_random, ar, vp->volume);
#endif
	    ar = pow(10.0, ar / 20.0);
	    vp->volume *= ar;
#ifdef WATCH_RANDOM_AMP
fprintf(stderr," linear ar=%f, new vol=%f\n", ar, vp->volume);
#endif
    }

    if (vp->cutoff_freq) {
	int cut_adjust = 127 - vp->velocity;
	if (vp->velocity < 64) cut_adjust = 127 - 64;
	cut_adjust *= 24;
	vp->cutoff_freq -= cut_adjust;
	if (vp->cutoff_freq < 100) vp->cutoff_freq = 100;
    }

	/* resonance maxes out too much */
    //vp->resonance = (vp->sample->resonance + 5)/10;
    //vp->resonance = vp->sample->resonance/2;
    vp->resonance = vp->sample->resonance/4;
    if (vp->resonance > vp->reso_max) vp->resonance = vp->reso_max;

    vp->current_x0 =
	vp->current_x1 = vp->current_y0 = vp->current_y1 = vp->current_y2 = 0;
#ifdef tplus
    vp->modulation_wheel = channel[ch].modulation_wheel;
#endif

    vp->tremolo_phase = 0;
    vp->tremolo_phase_increment =
	vp->sample->tremolo_phase_increment;
    vp->tremolo_sweep = vp->sample->tremolo_sweep_increment;
    vp->tremolo_depth = vp->sample->tremolo_depth;
    vp->tremolo_sweep_position = 0;

    if (vp->tremolo_depth < channel[ch].mw_amod)
	vp->tremolo_depth = channel[ch].mw_amod;
    if (vp->tremolo_depth) {
	if (!vp->tremolo_phase_increment) {
		int trate = 50;
		trate += channel[ch].tremolo - 64;
		if (trate < 1) trate = 1;
		vp->tremolo_phase_increment = convert_tremolo_rate(trate);
		vp->tremolo_sweep = convert_tremolo_sweep(trate/5);
	}
    }
    vp->lfo_phase = 0;
    vp->lfo_phase_increment = vp->sample->lfo_phase_increment;
    vp->lfo_sweep = vp->sample->lfo_sweep_increment;
    vp->lfo_depth = vp->sample->lfo_depth;
    vp->lfo_sweep_position = 0;

    vp->reso_phase = 0;
    vp->reso_phase_increment = 0;
    vp->reso_sweep = 0;
    vp->reso_depth = 0;
    vp->reso_sweep_position = -(1<<SWEEP_SHIFT);
    vp->reso_volume = 0;

#ifdef RESO_TEST
/* rate 10 is a bit faster than 1Hz */
/* rate 100 is a flutter sound */
/* rate 400 is a warbling distortion */
#define RESO_RATE 10
if (reso_test > 0) {
	//reso_test--;
    vp->reso_phase_increment = 1;
    vp->reso_depth = 100;
    vp->reso_sweep = convert_vibrato_sweep ((1<<SWEEP_SHIFT)/RESO_RATE, 8176);
    //fprintf(stderr,"test depth 100\n");
    vp->reso_max = 100;
}
#endif
    if ((int)channel[ch].mw_fmod > vp->lfo_depth) vp->lfo_depth = channel[ch].mw_fmod;

    if (vp->lfo_depth && !vp->lfo_sweep) {
	    int frate = 50;
	    vp->lfo_sweep = convert_vibrato_sweep ((1<<SWEEP_SHIFT)/frate, 8176);
    }
    if (vp->reso_depth && !vp->reso_sweep) {
	    vp->reso_sweep = convert_vibrato_sweep ((1<<SWEEP_SHIFT)/50, 8176);
    }

    vp->modLfoToFilterFc = vp->sample->modLfoToFilterFc;
    vp->modEnvToPitch = vp->sample->modEnvToPitch;
    vp->modEnvToFilterFc = vp->sample->modEnvToFilterFc;
    vp->modulation_delay = vp->sample->modulation_rate[DELAY];

    vp->vibrato_sweep = vp->sample->vibrato_sweep_increment;
    vp->vibrato_depth = vp->sample->vibrato_depth;
    vp->vibrato_sweep_position = 0;
    vp->vibrato_control_ratio = vp->sample->vibrato_control_ratio;
    vp->vibrato_delay = vp->sample->vibrato_delay;
#ifdef tplus
    if (channel[ch].vibrato_ratio /* && vp->vibrato_depth > 0*/) {
	vp->vibrato_control_ratio = channel[ch].vibrato_ratio;
	vp->vibrato_depth = channel[ch].vibrato_depth;
	vp->vibrato_delay = channel[ch].vibrato_delay;
	if (!vp->vibrato_sweep) vp->vibrato_sweep = DEFAULT_VIBRATO_SWEEP;
    }
#endif
    vp->vibrato_control_counter = vp->vibrato_phase = 0;
    for (j = 0; j < VIBRATO_SAMPLE_INCREMENTS; j++)
	vp->vibrato_sample_increment[j] = 0;


    attacktime = channel[ch].attacktime;
    releasetime = channel[ch].releasetime;
    decaytime = channel[ch].decaytime;

    if (channel[ch].kit) {
	if ((rt = drumattack[ch][played_note]) >= 0) attacktime = rt;
	if ((rt = drumdecay[ch][played_note]) >= 0) decaytime = rt;
	if ((rt = drumcutoff[ch][played_note]) >= 0) brightness = rt;
	if ((rt = drumresonance[ch][played_note]) >= 0) harmoniccontent = rt;
    }

    switch (variationbank) {
    case 4:
	vp->lfo_phase_increment = convert_vibrato_rate (10);
	vp->lfo_sweep = convert_vibrato_sweep ((1<<SWEEP_SHIFT)/10, 8176);
	vp->lfo_depth = 40;
	break;
    case 5:
	vp->lfo_phase_increment = 0;
	vp->lfo_sweep = 0;
	vp->lfo_depth = 0;
	break;
    case 8:
	attacktime = 64 + 32;
	break;
    case 12:
	decaytime = 64 - 32;
	break;
    case 16:
	brightness = 64 + 16;
	break;
    case 17:
	brightness = 64 + 32;
	break;
    case 18:
	brightness = 64 - 16;
	break;
    case 19:
	brightness = 64 - 32;
	break;
    case 20:
	harmoniccontent = 64 + 16;
	break;
    case 24:
	vp->modEnvToFilterFc = 2.0;
	vp->modEnvToPitch = 0.99;
	break;
    case 25:
	vp->modEnvToFilterFc = -2.0;
	vp->modEnvToPitch = 0.98;
	break;
    case 26: /*  sweep */
	vp->lfo_depth = 40;
	vp->modLfoToFilterFc = 2.0;
	vp->lfo_phase_increment = 109;
	vp->lfo_sweep = 122;
	break;
    case 27: /* reso sweep */
#define RESO_RATE 10
/* which is 1-2Hz */
	vp->reso_phase_increment = 1;
	vp->reso_depth = 100;
	vp->reso_sweep = convert_vibrato_sweep ((1<<SWEEP_SHIFT)/RESO_RATE, 8176);
	vp->reso_max = 100;
	break;
    case 28:  /* muted -- fix this */
	vp->modLfoToFilterFc = -2.0;
	vp->lfo_phase_increment = 109;
	vp->lfo_sweep = 122;
	break;
    default:
	break;
    }


#ifdef RATE_ADJUST_DEBUG
    {
	int     e_debug = 0, f_debug = 0;
	int32   r;
	if (releasetime != 64)
	    e_debug = 1;
	if (attacktime != 64)
	    f_debug = 1;
	if (e_debug)
	    printf ("ADJ release time by %d on %d\n", releasetime - 64, ch);
	if (f_debug)
	    printf ("ADJ attack time by %d on %d\n", attacktime - 64, ch);
#endif

	for (j = ATTACK; j < MAXPOINT; j++) {
	    vp->envelope_rate[j] = vp->sample->envelope_rate[j];
	    vp->envelope_offset[j] = vp->sample->envelope_offset[j];
#ifdef RATE_ADJUST_DEBUG
	    if (f_debug)
		printf ("\trate %d = %ld; offset = %ld\n", j,
			vp->envelope_rate[j],
			vp->envelope_offset[j]);
#endif
	}

/* Fluid Halopad has 255 for this -- probably a bogus value */
	if (vp->sample->keyToVolEnvHold) {
	    FLOAT_T rate_adjust;
	    rate_adjust =
		pow (2.0, (60 -
		      vp->note) * vp->sample->keyToVolEnvHold / 1200.0);
	    vp->envelope_rate[HOLD] =
		(uint32) ((FLOAT_T) vp->envelope_rate[HOLD] /
			  rate_adjust);
	}

	if (vp->sample->keyToVolEnvDecay) {
	    FLOAT_T rate_adjust;
	    rate_adjust =
		pow (2.0, (60 -
		      vp->note) * vp->sample->keyToVolEnvDecay / 1200.0);
	    vp->envelope_rate[DECAY] =
		(uint32) ((FLOAT_T) vp->envelope_rate[DECAY] /
			  rate_adjust);
	}

	vp->echo_delay = vp->envelope_rate[DELAY];
	vp->echo_delay_count = vp->echo_delay;
	vp->reverb_time = -1;

#ifdef RATE_ADJUST_DEBUG
	if (e_debug) {
	    printf ("(old rel time = %ld)\n",
		    (vp->envelope_offset[2] -
		     vp->envelope_offset[3]) /
		    vp->envelope_rate[3]);
	    r = vp->envelope_rate[3];
	    r = r + ((64 - releasetime) * r) / 100;
	    vp->envelope_rate[3] = r;
	    printf ("(new rel time = %ld)\n",
		    (vp->envelope_offset[2] -
		     vp->envelope_offset[3]) /
		    vp->envelope_rate[3]);
	}
    }
#endif

    if (attacktime != 64) {
	rt = vp->envelope_rate[ATTACK];
	rt = rt + ((64 - attacktime) * rt) / 100;
	if (rt > 1000)
	    vp->envelope_rate[ATTACK] = rt;
    }
    if (releasetime != 64) {
	rt = vp->envelope_rate[RELEASE];
	rt = rt + ((64 - releasetime) * rt) / 100;
	if (rt > 1000)
	    vp->envelope_rate[RELEASE] = rt;
    }
    if (decaytime != 64) {
	rt = vp->envelope_rate[DECAY];
	rt = rt + ((64 - decaytime) * rt) / 100;
	if (rt > 1000)
	    vp->envelope_rate[DECAY] = rt;
    }

    if (trigger == TRIGGER_LEGATO) {
        rt = vp->envelope_rate[ATTACK];
	rt /= 2;
	if (rt > 500)
	    vp->envelope_rate[ATTACK] = rt;
    }

    if (channel[ch].panning != NO_PANNING)
	vp->panning = channel[ch].panning;
    else
	vp->panning = vp->sample->panning;
    if (drumpan != NO_PANNING)
	vp->panning = drumpan;

#ifdef NEW_PANNER
    vp->panning = MIDIFY_PAN(vp->panning);
#endif

#ifdef WATCH_SQUARE
    if (vp->panning < LEFT_PAN_VALUE || vp->panning > RIGHT_PAN_VALUE)
	fprintf(stderr,"pan %d out of bounds\n", vp->panning);
#endif

#ifdef tplus
    vp->porta_control_counter = 0;
    if (channel[ch].portamento && !channel[ch].porta_control_ratio)
	update_portamento_controls (ch);
    if (channel[ch].porta_control_ratio) {
	if (channel[ch].last_note_fine == -1) {
	    /* first on */
	    channel[ch].last_note_fine = vp->note * 256;
	    channel[ch].porta_control_ratio = 0;
	}
	else {
	    vp->porta_control_ratio = channel[ch].porta_control_ratio;
	    vp->porta_dpb = channel[ch].porta_dpb;
	    vp->porta_pb = channel[ch].last_note_fine -
		vp->note * 256;
	    if (vp->porta_pb == 0)
		vp->porta_control_ratio = 0;
	}
    }

    /* What "cnt"? if(cnt == 0) 
       channel[ch].last_note_fine = vp->note * 256; */
#endif

/* This code is in, ah, transition. */


#define NEUTRAL_CUTOFF 6400
    if (vp->sample->sample_rate) {
	int32   hc = harmoniccontent - 64;
	int32   br = brightness - 64;
	int32   fq = vp->cutoff_freq, dq, reso = vp->resonance;

	if (!fq) fq = NEUTRAL_CUTOFF;

	if (br) {
	    dq = fq / 64;
	    if (dq < 10) dq = 10;
	    fq += br * dq;
	    if (fq < 200) fq = 200;
	    if (fq > (int)play_mode->rate/2) fq = play_mode->rate/2;
	}

	if (hc > 0) {
	    reso = hc * (vp->reso_max) / 64;
	}
	else if (hc < 0) {
	    reso += hc;
	    if (reso < 0) reso = 0;
	}

	vp->cutoff_freq = fq;
	vp->resonance = reso;

/* #define TUNING_TEST */
#ifdef TUNING_TEST
/* temporary for tuning */
    	vp->modEnvToFilterFc = 0;
	vp->modLfoToFilterFc = 0;
	//vp->resonance = 40;
	vp->resonance = 40;
	//vp->cutoff_freq = 24000;
	//vp->cutoff_freq = 4000;
	vp->cutoff_freq = 4000;
/*
 * BUTTERWORTH tests
 * 4000		120	aliasing
 * 2000		120	ok
 * 2000		240	strong aliasing
 * 1000		240	strong aliasing
 *  500		240	strong aliasing
 *  500		200	aliasing
 *  500		180	aliasing
 *  500		160	aliasing
 *  500		140	aliasing
 *  500		120	aliasing
 *  500		100	aliasing
 *  500		 80	some aliasing
 *  500		 60	slight aliasing (pad1newage is pretty bad)
 * 2000		 80	little aliasing (newage), slight effect
 * 1000		 80	some aliasing (newage)
 * 2000		 60	a little aliasing; a little effect
 * 1000		 60	some aliasing (fx3crystal is pretty bad)
 * 4000		 40	a little aliasing; a little effect
 * 1000		 40	slight aliasing (fx3crystal is pretty bad)
 * 1000		 30	slight aliasing (fx3crystal is some bad)
 * 1000		 20	slight aliasing (fx3crystal is a little bad)
 * 1500		 20	slight aliasing (fx3crystal is a little bad)
 * 2000		 20	very slight aliasing (fx3crystal is slightly bad)
 * ****************
 * MOOG tests
 * 8000		120	alias bowed
 * 8000		 80	ok, some resonanct effect
 * 4000		 80	some aliasing -- tolerable
 * 4000		 60	ok, but not much resonant effect
 * 2000		120	aliasing
 * 2000		 80	very slight aliasing
 * 2000		 20	ok
 * 1000		 80	ok, except piccolo largely inaudible
 * ****************
 * VSF tests
 * 8000		120	not bad, fx3crystal distorts -- little res. effect
 * 8000		 80	ok  -- little res. effect
 * 4000		 80	some aliasing -- tolerable
 * 2000		 80	some aliasing -- fx3crystal is bad
 * 2000		 60	a little aliasing for fx3crystal; some resonant effect
 * 1000		 60	bad aliasing for fx3crystal; some resonant effect
 * 1000		 40	serious aliasing for fx3crystal; some resonant effect
 * 1000		 30	some aliasing for fx3crystal
 */
#endif
    }

#ifdef RESO_TEST
    vp->resonance = 0;
    vp->cutoff_freq = 1200;
#endif
#ifdef VSF_TEST
    //vp->resonance = 1;
    //vp->cutoff_freq = 1200;
    //if (vp->cutoff_freq > 10000) vp->cutoff_freq = 10000;
    //if (vp->cutoff_freq > 16000) vp->cutoff_freq = 16000;
    //vp->modLfoToFilterFc = 0;
    //vp->modEnvToFilterFc = 0;
    //if (vp->modEnvToFilterFc > 20) vp->modEnvToFilterFc = 20;
#endif

    if (reverb_options & OPT_STEREO_EXTRA || variationbank == 1 || variationbank == 2) {
	int     pan = vp->panning;
	int     disturb = 0;
	/* If they're close up (no reverb) and you are behind the pianist,
	 * high notes come from the right, so we'll spread piano etc. notes
	 * out horizontally according to their pitches.
	 */
	if (channel[ch].program < 21) {
	    int     n = vp->velocity - 32;
	    if (n < 0)
		n = 0;
	    if (n > 64)
		n = 64;
	    pan = pan / 2 + n;
	}
	/* For other types of instruments, the music sounds more alive if
	 * notes come from slightly different directions.  However, instruments
	 * do drift around in a sometimes disconcerting way, so the following
	 * might not be such a good idea.
	 */
	else
	    disturb = (vp->velocity / 32 % 8) + (vp->note % 8);	/* /16? */

	if (pan < 64)
	    pan += disturb;
	else
	    pan -= disturb;
	if (pan < 0)
	    pan = 0;
	else if (pan > 127)
	    pan = 127;
	if (variationbank == 2) pan = 127 - pan;
	vp->panning = pan;
    }

    recompute_freq (i);
    recompute_amp (i);
    if (vp->sample->modes & MODES_ENVELOPE) {
	/* Ramp up from 0 */
	vp->envelope_stage = ATTACK;
	vp->envelope_volume = 0;
	vp->control_counter = 0;
	vp->modulation_stage = ATTACK;
	vp->modulation_volume = 0;
	vp->modulation_counter = 0;
	if (vp->cutoff_freq) {
	    vp->bw_index = (vp->cutoff_freq + 50) / 100;
	    if (vp->bw_index < 1) vp->bw_index = 1;
	    else if (vp->bw_index >= MAX_BW_INDEX)
		    vp->bw_index = MAX_BW_INDEX - 1;
	}
	else
	    vp->bw_index = 0;
	recompute_envelope (i);
	recompute_modulation (vp);
	apply_envelope_to_amp (i);
    }
    else {
	vp->envelope_increment = 0;
	apply_envelope_to_amp (i);
    }
    vp->clone_voice_reverb = -1;
    vp->clone_voice_chorus = -1;
    vp->clone_voice_stereo = -1;
    vp->clone_voice_tutti = -1;
    vp->clone_type = NOT_CLONE;
#ifdef DEBUG_CLONE_NOTES
    fprintf (stderr, "NOT_CLONE v%d vol%f pan%d\n", i, vp->volume,
	     vp->panning);
#endif

    if (reverb_options & OPT_STEREO_VOICE)
	clone_voice (ip, i, e, STEREO_CLONE, variationbank);
    if ( (reverb_options & OPT_CHORUS_VOICE)
	|| (XG_System_chorus_type >> 4) == 3 || channel[ch].effect ||
       	variationbank == 32 ||
       	variationbank == 33 ||
       	variationbank == 34 ||
       	variationbank == 39)
	clone_voice (ip, i, e, CHORUS_CLONE, variationbank);
    if (reverb_options & OPT_REVERB_VOICE)
	clone_voice (ip, i, e, REVERB_CLONE, variationbank);

    if (trigger != TRIGGER_LEGATO &&
	((variationbank >= 40 && variationbank <= 45) || (variationbank >= 52 && variationbank <= 54)) &&
	(lp = tonebank[0]->tone[115].layer)) {
	    clone_tutti (lp, i, variationbank);
    }

    ctl->note (i);
    played_notes++;
}


static int 
kill_note (int i)
{
    int the_clone, ret = 1;

    voice[i].status = VOICE_DIE;
    the_clone = voice[i].clone_voice_reverb;
    if (the_clone >= 0) {
	if (voice[the_clone].status != VOICE_FREE) {
	    voice[the_clone].status = VOICE_DIE;
	    ret++;
	}
	voice[i].clone_voice_reverb = -1;
    }
    the_clone = voice[i].clone_voice_chorus;
    if (the_clone >= 0) {
	if (voice[the_clone].status != VOICE_FREE) {
	    voice[the_clone].status = VOICE_DIE;
	    ret++;
	}
	voice[i].clone_voice_chorus = -1;
    }
    the_clone = voice[i].clone_voice_stereo;
    if (the_clone >= 0) {
	if (voice[the_clone].status != VOICE_FREE) {
	    voice[the_clone].status = VOICE_DIE;
	    ret++;
	}
	voice[i].clone_voice_stereo = -1;
    }
    the_clone = voice[i].clone_voice_tutti;
    if (the_clone >= 0) {
	if (voice[the_clone].status != VOICE_FREE) {
	    voice[the_clone].status = VOICE_DIE;
	    ret++;
	}
	voice[i].clone_voice_tutti = -1;
    }
    ctl->note (i);
    return ret;
}


static int
reduce_polyphony_by_some ()
{
    int     i = voices, lowest = -1;
    int32   lv = 0x7FFFFFFF, v;

    /* Look for the decaying note with the lowest volume */
    i = voices;
    while (i--) {
	if (voice[i].status == VOICE_FREE || (voice[i].clone_type & IS_CLONE))
	    continue;
	if (voice[i].status & ~(VOICE_ON | VOICE_DIE)) {
	    v = voice[i].left_mix;
	    if ((voice[i].panned == PANNED_MYSTERY)
		&& (voice[i].right_mix > v))
		v = voice[i].right_mix;
	    if (v < lv) {
		lv = v;
		lowest = i;
	    }
	}
    }

    if (lowest != -1) {
	return kill_note (lowest);
    }
    return 0;
}

static int
reduce_polyphony_by_percussion ()
{
    int     i = voices, lowest = -1;
    int32   lv = 0x7FFFFFFF, v;

    /* Look for the decaying note with the lowest volume */
    i = voices;
    while (i--) {
	if (voice[i].status == VOICE_FREE || (voice[i].clone_type & IS_CLONE))
	    continue;
	if (!channel[voice[i].channel].kit) continue;
	if (voice[i].status & ~(VOICE_DIE)) {
	    v = voice[i].left_mix;
	    if ((voice[i].panned == PANNED_MYSTERY)
		&& (voice[i].right_mix > v))
		v = voice[i].right_mix;
	    if (v < lv) {
		lv = v;
		lowest = i;
	    }
	}
    }

    if (lowest != -1) {
	return kill_note (lowest);
    }
    return 0;
}
static int
reduce_polyphony_by_desperation ()
{
    int     i = voices, lowest = -1;
    int32   lv = 0x7FFFFFFF, v;

    /* Look for the decaying note with the lowest volume */
    i = voices;
    while (i--) {
	if (voice[i].status == VOICE_FREE || (voice[i].clone_type & IS_CLONE))
	    continue;
	if (voice[i].status & ~(VOICE_DIE)) {
	    v = voice[i].left_mix;
	    if ((voice[i].panned == PANNED_MYSTERY)
		&& (voice[i].right_mix > v))
		v = voice[i].right_mix;
	    if (v < lv) {
		lv = v;
		lowest = i;
	    }
	}
    }

    if (lowest != -1) {
	return kill_note (lowest);
    }
    return 0;
}

static int
reduce_polyphony_by_reverb ()
{
    int     i = voices, lowest = -1, ref = -1;
    int32   lv = 0x7FFFFFFF, v;
    i = voices;

    while (i--) {
	int j;
	if (voice[i].status == VOICE_FREE || (voice[i].clone_type & IS_CLONE))
	    continue;
	if ( (j=voice[i].clone_voice_reverb) < 0) continue;
	if (voice[j].status & ~(VOICE_DIE)) {
	    v = voice[j].left_mix;
	    if ((voice[j].panned == PANNED_MYSTERY)
		&& (voice[j].right_mix > v))
		v = voice[j].right_mix;
	    if (v < lv) {
		lv = v;
		lowest = j;
		ref = i;
	    }
	}
    }
    if (lowest != -1) {
	voice[ref].clone_voice_reverb = -1;
	voice[lowest].status = VOICE_DIE;
        return 1;
    }
    return 0;
}

static int
reduce_polyphony_by_chorus ()
{
    int     i = voices, lowest = -1, ref = -1;
    int32   lv = 0x7FFFFFFF, v;
    i = voices;

    while (i--) {
	int j;
	if (voice[i].status == VOICE_FREE || (voice[i].clone_type & IS_CLONE))
	    continue;
	if ( (j=voice[i].clone_voice_chorus) < 0) continue;
	if (voice[j].status & ~(VOICE_DIE)) {
	    v = voice[j].left_mix;
	    if ((voice[j].panned == PANNED_MYSTERY)
		&& (voice[j].right_mix > v))
		v = voice[j].right_mix;
	    if (v < lv) {
		lv = v;
		lowest = j;
		ref = i;
	    }
	}
    }
    if (lowest != -1) {
	voice[ref].clone_voice_chorus = -1;
	voice[lowest].status = VOICE_DIE;
        return 1;
    }
    return 0;
}


static int
reduce_polyphony (int by)
{
    int ret = 0;

    while ( by>0 && (ret=reduce_polyphony_by_some ()) ) by -= ret;
    while ( by>0 && (ret=reduce_polyphony_by_reverb ()) ) by -= ret;
    while ( by>0 && (ret=reduce_polyphony_by_chorus ()) ) by -= ret;
    while ( by>0 && (ret=reduce_polyphony_by_percussion ()) ) by -= ret;
    while ( by>0 && (ret=reduce_polyphony_by_desperation ()) ) by -= ret;
    return 1;
}


static int obf_last = 0;

static int
check_quality ()
{
    int     obf = output_buffer_full, retvalue = 1;
    int     vcs = voices;
    int     cpoly = current_polyphony;
    int     rsv = 0, permitted, polyreduction;

    permitted = vcs - 16;
    if (permitted < 0)
	permitted = 0;
    if (permitted > voices_ceiling)
	permitted = voices_ceiling;
    permitted = permitted * obf / 100;
    //permitted += 16;
    if (permitted < 16) permitted = 16;
    rsv = vcs - permitted;

    voice_reserve = rsv;

    if (obf > 96) danger = 0;
    else if (obf < obf_last) {
	    if (obf < 88)
	    danger += (100 - obf) * (obf_last - obf);
	    //fprintf(stderr,"obf now = %d, danger %d, no rev=%d\n", obf, danger, dont_reverb);
    }
    else {
	    danger--;
	    if (obf > 90) danger--;
    }
    obf_last = obf;

    if (danger > 2000)
	dont_cspline = 1;
    else if (danger < 1000)
	dont_cspline = 0;

    if (danger > 3000)
	dont_reverb = 4;
    else if (danger > 2000)
	dont_reverb = 3;
    else if (danger > 1000)
	dont_reverb = 2;
    else if (danger < 1000)
	dont_reverb = 0;

    if (danger > 3000)
	dont_chorus = 4;
    else if (danger > 2000)
	dont_chorus = 3;
    else if (danger < 1000)
	dont_chorus = 0;

    if (opt_dry || danger > 2000)
	dont_keep_looping = 1;
    else if (danger < 500)
	dont_keep_looping = 0;

/* pool should be permitted/10
 * present pool is permitted - cpoly
 * reduction = permitted/10 - (permitted - cpoly)
 */

    polyreduction = permitted / 4 - (permitted - cpoly) + danger / 500;
/*
 * extra reduction if buffer is too low
 * (100 - obf)% of cpoly
 */

    if (polyreduction > 0)
	retvalue = reduce_polyphony (polyreduction);

    retvalue = 1;

    return retvalue;
}

#ifdef WATCH_OLD_NOTES
static int tock = 100;
#endif

static void finish_note (int i);

static void
note_on (MidiEvent * e)
{
    int     i = voices, lowest = -1;
    int32   lv = 0x7FFFFFFF, v;

#ifdef WATCH_OLD_NOTES
unsigned stuck = (unsigned)lv;
int istuck=0;
#endif

    current_polyphony = 0;

    while (i--) {
#ifdef WATCH_OLD_NOTES
if (voice[i].status != VOICE_FREE && voice[i].time < stuck) { stuck = voice[i].time; istuck = i; }
#endif
	if (voice[i].status == VOICE_FREE)
	    lowest = i;		/* Can't get a lower volume than silence */
	else if (voice[i].status & ~VOICE_DIE) {
	    current_polyphony++;
	}
    }

#ifdef WATCH_OLD_NOTES
if (--tock <= 0) {
fprintf(stderr,"stuck vc%d ch%d age=%d status%d clonetype%d clonevc %d %d %d\n", istuck,
	       voice[istuck].channel, current_event->time - stuck,
	       voice[istuck].status, voice[istuck].clone_type,
	       voice[istuck].clone_voice_reverb,
	       voice[istuck].clone_voice_chorus,
	       voice[istuck].clone_voice_stereo);
tock = 100;
}
#endif
    if (!check_quality ()) {
	lost_notes++;
	return;
    }


    if (lowest != -1) {
	/* Found a free voice. */
	start_note (e, lowest);
	return;
    }
#if 0
    /* Look for the decaying note with the lowest volume */
    i = voices;
    while (i--) {
	if (voice[i].status & ~(VOICE_ON | VOICE_DIE | VOICE_FREE)) {
	    v = voice[i].left_mix;
	    if ((voice[i].panned == PANNED_MYSTERY)
		&& (voice[i].right_mix > v))
		v = voice[i].right_mix;
	    if (v < lv) {
		lv = v;
		lowest = i;
	    }
	}
    }
#endif
    /* Look for the decaying note with the lowest volume */
    if (lowest == -1) {
	i = voices;
	while (i--) {
	    if ((voice[i].status & ~(VOICE_ON | VOICE_DIE | VOICE_FREE)) &&
		( !(voice[i].clone_type & IS_CLONE) )) {
		v = voice[i].left_mix;
		if ((voice[i].panned == PANNED_MYSTERY)
		    && (voice[i].right_mix > v))
		    v = voice[i].right_mix;
		if (v < lv) {
		    lv = v;
		    lowest = i;
		}
	    }
	}
    }

    if (lowest != -1) {
	int     cl;
	/* This can still cause a click, but if we had a free voice to
	   spare for ramping down this note, we wouldn't need to kill it
	   in the first place... Still, this needs to be fixed. Perhaps
	   we could use a reserve of voices to play dying notes only. */

	cut_notes++;
	voice[lowest].status = VOICE_FREE;
	if ( (cl=voice[lowest].clone_voice_reverb) >= 0) voice[cl].status = VOICE_FREE;
	if ( (cl=voice[lowest].clone_voice_chorus) >= 0) voice[cl].status = VOICE_FREE;
	if ( (cl=voice[lowest].clone_voice_stereo) >= 0) voice[cl].status = VOICE_FREE;
	if ( (cl=voice[lowest].clone_voice_tutti) >= 0) voice[cl].status = VOICE_FREE;
	ctl->note (lowest);
	start_note (e, lowest);
    }
    else
	lost_notes++;
}

static void
finish_note (int i)
{
    int     v;

    if (voice[i].status & (VOICE_FREE | VOICE_DIE | VOICE_OFF))
	return;
#ifdef WATCH_SQUARESQUARE
    if (voice[i].channel == 6)
    fprintf(stderr,"finish %d\n", i);
#endif
    if (voice[i].sample->modes & MODES_ENVELOPE) {
	/* We need to get the envelope out of Sustain stage */
	if (voice[i].envelope_stage < RELEASE)
	    voice[i].envelope_stage = RELEASE;
	voice[i].status = VOICE_OFF;
	recompute_envelope (i);
	apply_envelope_to_amp (i);
	ctl->note (i);
    }
    else {
	/* Set status to OFF so resample_voice() will let this voice out
	   of its loop, if any. In any case, this voice dies when it
	   hits the end of its data (ofs>=data_length). */
	voice[i].status = VOICE_OFF;
	ctl->note (i);
    }
 
    if ((v = voice[i].clone_voice_reverb) >= 0) {
	    voice[i].clone_voice_reverb = -1;
	    finish_note (v);
    }
    if ((v = voice[i].clone_voice_chorus) >= 0) {
	    voice[i].clone_voice_chorus = -1;
	    finish_note (v);
    }
    if ((v = voice[i].clone_voice_stereo) >= 0) {
	    voice[i].clone_voice_stereo = -1;
	    finish_note (v);
    }
    if ((v = voice[i].clone_voice_tutti) >= 0) {
	    voice[i].clone_voice_tutti = -1;
	    finish_note (v);
    }
}

static void
note_off (MidiEvent * e)
{
    int     i = voices, v;
    while (i--)
	if (voice[i].status == VOICE_ON &&
	    voice[i].channel == e->channel && voice[i].note == e->a) {
	    if (channel[e->channel].sustain) {
		voice[i].status = VOICE_SUSTAINED;
		ctl->note (i);
#if 0
		if ((v = voice[i].clone_voice_reverb) >= 0) {
		    if (voice[v].status == VOICE_ON)
			voice[v].status = VOICE_SUSTAINED;
		}
#endif
		if ((v = voice[i].clone_voice_chorus) >= 0) {
		    if (voice[v].status == VOICE_ON)
			voice[v].status = VOICE_SUSTAINED;
		}
		if ((v = voice[i].clone_voice_stereo) >= 0) {
		    if (voice[v].status == VOICE_ON)
			voice[v].status = VOICE_SUSTAINED;
		}
	    }
	    else
		finish_note (i);
	}
}

void send_note(int vel, MidiEvent *e)
{
    int i;
    int ch = e->channel;
    MidiEvent new_e = *e;

    for (i = 0; i < MAXCHAN; i++) {
	if (i == ch) continue;
	if (channel[i].receive == ch) {
		new_e.channel = i;
		if (vel) note_on(&new_e);
		else note_off(&new_e);
	}
    }
}

/* Process the All Notes Off event */
static void
all_notes_off (int c)
{
    int     i = voices;
    ctl->cmsg (CMSG_INFO, VERB_DEBUG, "All notes off on channel %d", c);
    while (i--)
	if (voice[i].status == VOICE_ON && voice[i].channel == c) {
	    if (channel[c].sustain) {
		voice[i].status = VOICE_SUSTAINED;
		ctl->note (i);
	    }
	    else
		finish_note (i);
	}
}

/* Process the All Sounds Off event */
static void
all_sounds_off (int c)
{
    int     i = voices;
    while (i--)
	if (voice[i].channel == c &&
	    voice[i].status != VOICE_FREE && voice[i].status != VOICE_DIE) {
	    kill_note (i);
	}
}

static void
adjust_pressure (MidiEvent * e)
{
    int     i = voices;
    while (i--)
	if (voice[i].status == VOICE_ON &&
	    voice[i].channel == e->channel && voice[i].note == e->a) {
	    voice[i].velocity = e->b;
	    recompute_amp (i);
	    apply_envelope_to_amp (i);
	}
}

#ifdef tplus
static void
adjust_channel_pressure (MidiEvent * e)
{
#    if 0
    if (opt_channel_pressure) {
#    endif
	int     i = voices;
	int     ch, pressure;

	ch = e->channel;
	pressure = e->a;
	while (i--)
	    if (voice[i].status == VOICE_ON && voice[i].channel == ch) {
		voice[i].velocity = pressure;
		recompute_amp (i);
		apply_envelope_to_amp (i);
	    }
#    if 0
    }
#    endif
}
#endif

static void
adjust_panning (int c)
{
    int     i = voices, w;
    while (i--)
	if ((voice[i].channel == c) &&
	    (voice[i].status & (VOICE_ON | VOICE_SUSTAINED))) {
	    /* if (voice[i].clone_voice >= 0) continue; */
/* FIXME */
	    if ( (voice[i].clone_type & REVERB_CLONE) )
		continue;
	    if ( (w = voice[i].clone_voice_stereo) >= 0) {
		    recompute_stereo_panning (i, w, (unsigned)MIDIFY_PAN(channel[c].panning));
		    recompute_amp (w);
		    apply_envelope_to_amp (w);
	    }
	    else voice[i].panning = MIDIFY_PAN(channel[c].panning);
	    recompute_amp (i);
	    apply_envelope_to_amp (i);
	}
}

static void
drop_sustain (int c)
{
    int     i = voices;
    while (i--)
	if ((voice[i].status & VOICE_SUSTAINED) && voice[i].channel == c)
	    finish_note (i);
}

static void
adjust_pitchbend (int c)
{
    int     i = voices;
    while (i--)
	if (voice[i].status != VOICE_FREE && voice[i].channel == c) {
	    recompute_freq (i);
	}
}

static void
adjust_volume (int c)
{
    int     i = voices;
    while (i--)
	if (voice[i].channel == c &&
	    (voice[i].status == VOICE_ON
	     || voice[i].status == VOICE_SUSTAINED)) {
	    recompute_amp (i);
	    apply_envelope_to_amp (i);
	    ctl->note (i);
	}
}

#ifdef tplus
static int32
midi_cnv_vib_rate (int rate)
{
    return (int32) ((double) play_mode->rate * MODULATION_WHEEL_RATE
		    / (midi_time_table[rate] *
		       2.0 * VIBRATO_SAMPLE_INCREMENTS));
}

static int
midi_cnv_vib_depth (int depth)
{
    return (int) (depth * VIBRATO_DEPTH_TUNING);
}

static int
calc_mw_depth (int ch, int depth)
{
    int pmod = (int)channel[ch].mw_pmod;

    if (!pmod) return 0;

    if (pmod != 10) {
	    pmod *= 10;
	    depth = (pmod*depth)/100;
	    if (depth > 200) depth = 200;
    }

    return (int) (depth * VIBRATO_DEPTH_TUNING);
}

static int32
midi_cnv_vib_delay (int delay)
{
    return (int32) (midi_time_table[delay]);
}
#endif

static int xmp_epoch = -1;
static unsigned xxmp_epoch = 0;
static unsigned time_expired = 0;
static unsigned last_time_expired = 0;
static struct timeval tv;
static struct timezone tz;
static void
time_sync (uint32 resync, int dosync)
{
    unsigned jiffies;

    if (dosync) {
	last_time_expired = resync;
	xmp_epoch = -1;
	xxmp_epoch = 0;
	time_expired = 0;
	/*return; */
    }
    gettimeofday (&tv, &tz);
    if (xmp_epoch < 0) {
	xxmp_epoch = tv.tv_sec;
	xmp_epoch = tv.tv_usec;
    }
    jiffies =
	(tv.tv_sec - xxmp_epoch) * 100 + (tv.tv_usec - xmp_epoch) / 10000;
    time_expired = (jiffies * play_mode->rate) / 100 + last_time_expired;
}

static int got_a_lyric = 0;

#define META_BUF_LEN 1024

static void
show_markers (uint32 until_time, int dosync)
{
    static struct meta_text_type *meta;
    char    buf[META_BUF_LEN];
    int     i, j, len, lyriclen;

    if (!meta_text_list)
	return;

    if (dosync) {
	time_sync (until_time, 1);
	for (meta = meta_text_list; meta && meta->time < until_time;
	     meta = meta->next);
	return;
    }

    if (!time_expired)
	meta = meta_text_list;

    time_sync (0, 0);

    buf[0] = '\0';
    len = 0;
    while (meta)
	if (meta->time <= time_expired) {
	    if (meta->type == 5)
		got_a_lyric = 1;
	    if (!got_a_lyric || meta->type == 5) {
		lyriclen = strlen (meta->text);
		if (len + lyriclen + 1 < META_BUF_LEN) {
		    len += lyriclen;
		    strcat (buf, meta->text);
		}
		if (!meta->next)
		    strcat (buf, " \n");
	    }
	    meta = meta->next;
	}
	else
	    break;
    len = strlen (buf);
    for (i = 0, j = 0; j < META_BUF_LEN && j < len; j++)
	if (buf[j] == '\n') {
	    buf[j] = '\0';
	    if (j - i > 0)
		ctl->cmsg (CMSG_LYRIC, VERB_ALWAYS, buf + i);
	    else
		ctl->cmsg (CMSG_LYRIC, VERB_ALWAYS, " ");
	    i = j + 1;
	}
    if (i < j)
	ctl->cmsg (CMSG_LYRIC, VERB_ALWAYS, "~%s", buf + i);
}

static void
seek_forward (uint32 until_time)
{
    reset_voices ();
    show_markers (until_time, 1);
    while (current_event->time < until_time) {
	int ch = current_event->channel;
	int a = current_event->a;
	int b = current_event->b;

	switch (current_event->type) {
	    /* All notes stay off. Just handle the parameter changes. */

	case ME_PITCH_SENS:
	    channel[ch].pitchsens = a;
	    channel[ch].pitchfactor = 0;
	    break;

	case ME_PITCHWHEEL:
	    channel[ch].pitchbend = a + b * 128;
	    channel[ch].pitchfactor = 0;
	    break;
#ifdef tplus
	case ME_MODULATION_WHEEL:
	    channel[ch].modulation_wheel =
		calc_mw_depth (ch, a);
	    break;
	case ME_MW_PMOD:
	    channel[ch].mw_pmod = a;
	    break;
	case ME_MW_FMOD:
	    channel[ch].mw_fmod = a;
	    break;
	case ME_MW_AMOD:
	    channel[ch].mw_amod = a;
	    break;

	case ME_PORTAMENTO_TIME_MSB:
	    channel[ch].portamento_time_msb = a;
	    break;

	case ME_PORTAMENTO_TIME_LSB:
	    channel[ch].portamento_time_lsb = a;
	    break;

	case ME_PORTAMENTO:
	    channel[ch].portamento = (a >= 64);
	    ctl->sustain (ch, a, 'P');
	    break;

	case ME_FINE_TUNING:
	    channel[ch].tuning_lsb = a;
	    break;

	case ME_COARSE_TUNING:
	    channel[ch].tuning_msb = a;
	    break;

	case ME_CHANNEL_PRESSURE:
	    /*adjust_channel_pressure(current_event); */
	    break;

	case ME_KEYSIG:
	    current_keysig = a + b * 16;
	    break;

	case ME_TIMESIG:
	    break;

	case ME_BREATH:
		break;
	case ME_FOOT:
		break;
	case ME_BALANCE:
		break;
	case ME_DATA_ENTRY_LSB:
		break;
	case ME_SOSTENUTO:
		channel[ch].sostenuto = (a >= 64);
		break;
	case ME_SOFT_PEDAL:
		break;
	case ME_LEGATO_FOOTSWITCH:
		break;
	case ME_HOLD2:
		break;
	case ME_PORTAMENTO_CONTROL:
		break;
	case ME_TREMOLO_EFFECT:
		break;
	case ME_CELESTE_EFFECT:
		if (XG_System_On) channel[ch].variation_depth = a;
		else if (a) {
			channel[ch].effect = (ME_CELESTE_EFFECT<<8) | a;
		}
		else channel[ch].effect = 0;
		break;
	case ME_PHASER_EFFECT:
		break;
	case ME_RPN_INC:
		break;
	case ME_RPN_DEC:
		break;
	case ME_MONO:
		channel[ch].mono = a;
		break;
	case ME_POLY:
		channel[ch].mono = 0;
		break;
#endif

	case ME_MAINVOLUME:
	    channel[ch].volume = a;
	    break;

	case ME_MASTERVOLUME:
	    adjust_master_volume (a + (b << 7));
	    break;

	case ME_PAN:
	    channel[ch].panning = a;
	    break;

	case ME_EXPRESSION:
	    channel[ch].expression = a;
	    break;

	case ME_PROGRAM:
	    if (channel[ch].kit)
		/* Change drum set */
		channel[ch].bank = a;
	    else
		channel[ch].program = a;
	    break;

	case ME_SUSTAIN:
	    channel[ch].sustain = a;
	    break;

	case ME_REVERBERATION:
	    if (global_reverb > a)
		break;
	    channel[ch].reverberation = a;
	    break;

	case ME_CHORUSDEPTH:
	    if (global_chorus > a)
		break;
	    channel[ch].chorusdepth = a;
	    break;

	case ME_HARMONICCONTENT:
	    channel[ch].harmoniccontent = a;
	    break;

	case ME_RELEASETIME:
	    channel[ch].releasetime = a;
	    break;

	case ME_ATTACKTIME:
	    channel[ch].attacktime = a;
	    break;

	case ME_DECAYTIME:
	    channel[ch].decaytime = a;
	    break;
#ifdef tplus
	case ME_VIBRATO_RATE:
	    channel[ch].vibrato_ratio =
		midi_cnv_vib_rate (a);
	    break;
	case ME_VIBRATO_DEPTH:
	    channel[ch].vibrato_depth =
		midi_cnv_vib_depth (a);
	    break;
	case ME_VIBRATO_DELAY:
	    channel[ch].vibrato_delay =
		midi_cnv_vib_delay (a);
	    break;
	case ME_TEMPO:
	    current_play_tempo = ch + b * 256 + a * 65536;
	    break;
#endif
	case ME_BRIGHTNESS:
	    channel[ch].brightness = a;
	    break;

	case ME_DRYLEVEL:
	    channel[ch].drylevel = a;
	    break;

	case ME_VELOCITY_SENSE_DEPTH:
	    channel[ch].velocity_sense_depth = a;
	    break;
	case ME_VELOCITY_SENSE_OFFSET:
	    channel[ch].velocity_sense_offset = a;
	    break;

	case ME_RESET_CONTROLLERS:
	    reset_controllers (ch);
	    break;

	case ME_TONE_BANK:
	    if (channel[ch].xg) {
			channel[ch].bank = a;
	    }
	    else if (!channel[ch].kit) {
		    if ( (XG_System_On && a >= 0 && a < NUM_VARIATION_BANKS) || !tonebank[a]) {
			channel[ch].variationbank = a;
		    	channel[ch].bank = 0;
		    }
		    else {
			channel[ch].bank = a;
		    }
	    }
	    break;

	case ME_TONE_KIT:
	    if (a == SFX_BANKTYPE) {
		channel[ch].sfx = SFXBANK;
		channel[ch].kit = 0;
	    }
	    else {
		    channel[ch].sfx = 0;
		    channel[ch].kit = a;
		    a = channel[ch].bank;
		    if (!channel[ch].kit) {
			if (a >= MAXPROG && !channel[ch].xg) a -= MAXPROG;
		        if ( (XG_System_On && a >= 0 && a < NUM_VARIATION_BANKS) || !tonebank[a]) {
			    channel[ch].variationbank = a;
		    	    channel[ch].bank = 0;
		        }
		        else {
			    channel[ch].bank = a;
		        }
		    }
	    }
	    break;

	case ME_EOT:
	    current_sample = current_event->time;
	    return;
	}
	current_event++;
    }
    /*current_sample=current_event->time; */
    if (current_event != event_list)
	current_event--;
    current_sample = until_time;
}

static void
skip_to (uint32 until_time)
{
    if (current_sample > until_time)
	current_sample = 0;

    reset_midi ();
    buffered_count = 0;
    buffer_pointer = common_buffer;
    current_event = event_list;

    if (until_time)
	seek_forward (until_time);
    else
	show_markers (until_time, 1);
    ctl->redo ();
}


static int
apply_controls (void)
{
    int     rc, i, did_skip = 0;
    int32   val;
    /* ASCII renditions of CD player pictograms indicate approximate effect */
    do {
	switch (rc = ctl->read (&val)) {
	case RC_QUIT:		/* [] */
	case RC_LOAD_FILE:
	case RC_NEXT:		/* >>| */
	case RC_REALLY_PREVIOUS:	/* |<< */
	case RC_PATCHCHANGE:
	case RC_CHANGE_VOICES:
	case RC_STOP:
	    play_mode->purge_output ();
	    return rc;

	case RC_CHANGE_VOLUME:
	    if (val > 0 || amplification > -val)
		amplification += val;
	    else
		amplification = 0;
	    if (amplification > MAX_AMPLIFICATION)
		amplification = MAX_AMPLIFICATION;
	    adjust_amplification ();
	    for (i = 0; i < voices; i++)
		if (voice[i].status != VOICE_FREE) {
		    recompute_amp (i);
		    apply_envelope_to_amp (i);
		}
	    break;

	case RC_PREVIOUS:	/* |<< */
	    play_mode->purge_output ();
	    if (current_sample < 2 * play_mode->rate)
		return RC_REALLY_PREVIOUS;
	    return RC_RESTART;

	case RC_RESTART:	/* |<< */
	    if(play_pause_flag)
	    {
		midi_restart_time = 0;
		continue;
	    }
	    skip_to (0);
	    play_mode->purge_output ();
	    did_skip = 1;
	    break;

	case RC_JUMP:
	    if(play_pause_flag)
	    {
		midi_restart_time = val;
		continue;
	    }
	    play_mode->purge_output ();
	    if (val >= (int32) sample_count)
		return RC_NEXT;
	    skip_to ((uint32) val);
	    return rc;

	case RC_FORWARD:	/* >> */
	    if(play_pause_flag)
	    {
		midi_restart_time += val;
		if(midi_restart_time > sample_count)
		    midi_restart_time = sample_count;
		continue;
	    }
	    /*play_mode->purge_output(); */
	    if (val + current_sample >= sample_count)
		return RC_NEXT;
	    skip_to (val + current_sample);
	    did_skip = 1;
	    break;

	case RC_BACK:		/* << */
	    if(play_pause_flag)
	    {
		if (val > 0 && midi_restart_time > (unsigned)val)
		    midi_restart_time -= val;
		else midi_restart_time = 0;
		continue;
	    }
	    /*play_mode->purge_output(); */
	    if (current_sample > (uint32) val)
		skip_to (current_sample - (uint32) val);
	    else
		skip_to (0);	/* We can't seek to end of previous song. */
	    did_skip = 1;
	    break;

	case RC_TOGGLE_PAUSE:
	    if(play_pause_flag)
	    {
		play_pause_flag = 0;
#ifndef HARDWARE_PAUSE
		skip_to(midi_restart_time);
#else
		play_mode->output_pause(0);
#endif
	    }
	    else
	    {
#ifndef HARDWARE_PAUSE
		midi_restart_time = current_sample;
		play_mode->flush_output();
#else
		play_mode->output_pause(1);
#endif
		play_pause_flag = 1;
	    }
#ifndef HARDWARE_PAUSE
	    did_skip = 1;
#endif
	    continue;

	}
	if(play_pause_flag) usleep(300000);

    } while (rc != RC_NONE || play_pause_flag);

    /* Advertise the skip so that we stop computing the audio buffer */
    if (did_skip)
	return RC_JUMP;
    else
	return rc;
}

static void
do_compute_data (uint32 count)
{
    int     i;
    if (!count)
	return;			/* (gl) */
    memset (buffer_pointer, 0, count * num_ochannels * 4);
    for (i = 0; i < voices; i++) {
	if (voice[i].status != VOICE_FREE) {
	    if (!voice[i].sample_offset && voice[i].echo_delay_count) {
		if (voice[i].echo_delay_count >= count)
		    voice[i].echo_delay_count -= count;
		else {
		    mix_voice (buffer_pointer + voice[i].echo_delay_count, i,
			       count - voice[i].echo_delay_count);
		    voice[i].echo_delay_count = 0;
		}
	    }
	    else
		mix_voice (buffer_pointer, i, count);
	}
    }
    current_sample += count;
}

/* count=0 means flush remaining buffered data to output device, then
   flush the device itself */
static int
compute_data (uint32 count)
{
    int     rc;

    num_ochannels_in_buf = num_ochannels;

    if (!count) {
	if (buffered_count)
	    play_mode->output_data (common_buffer, buffered_count);
	play_mode->flush_output ();
	buffer_pointer = common_buffer;
	buffered_count = 0;
	return RC_NONE;
    }

    while ((count + buffered_count) >= AUDIO_BUFFER_SIZE) {
	do_compute_data (AUDIO_BUFFER_SIZE - buffered_count);
	count -= AUDIO_BUFFER_SIZE - buffered_count;
	play_mode->output_data (common_buffer, AUDIO_BUFFER_SIZE);
	buffer_pointer = common_buffer;
	buffered_count = 0;

	ctl->current_time (current_sample);
	show_markers (0, 0);
	if ((rc = apply_controls ()) != RC_NONE)
	    return rc;
    }
    if (count > 0) {
	do_compute_data (count);
	buffered_count += count;
	buffer_pointer += count * num_ochannels;
    }
    return RC_NONE;
}

static void
update_tremolo_effect (int ch)
{
    int   i;
    int   depth = channel[ch].mw_amod;

    for (i = 0; i < voices; i++)
	if (voice[i].status != VOICE_FREE && voice[i].channel == ch &&
		voice[i].tremolo_phase_increment &&
	        voice[i].tremolo_depth != depth) {
	    /* Set/Reset mod-wheel */
	    voice[i].tremolo_depth = depth;
	    update_tremolo (i);
	}
}

#ifdef tplus
static void
update_modulation_wheel (int ch, uint32 val)
{
    int     i;
    for (i = 0; i < voices; i++)
	if (voice[i].status != VOICE_FREE && voice[i].channel == ch) {
	    /* Set/Reset mod-wheel */
	    if (channel[ch].mw_pmod && voice[i].modulation_wheel != val) {
	        voice[i].modulation_wheel = val;
	        voice[i].vibrato_delay = 0;
	        recompute_freq (i);
	    }
	    if (channel[ch].mw_amod && voice[i].tremolo_depth != val) {
	        voice[i].tremolo_depth = val;
	        update_tremolo (i);
	    }
	    if (channel[ch].mw_fmod && voice[i].lfo_depth != (int)val) {
	        voice[i].lfo_depth = val;
	    }
	}
}

static void
drop_portamento (int ch)
{
    int     i, uv = /*upper_ */ voices;

    channel[ch].porta_control_ratio = 0;
    for (i = 0; i < uv; i++)
	if (voice[i].status != VOICE_FREE &&
	    voice[i].channel == ch && voice[i].porta_control_ratio) {
	    voice[i].porta_control_ratio = 0;
	    recompute_freq (i);
	}
    channel[ch].last_note_fine = -1;
}

static void
update_portamento_controls (int ch)
{
    if (!channel[ch].portamento ||
	(channel[ch].portamento_time_msb | channel[ch].portamento_time_lsb)
	== 0)
	drop_portamento (ch);
    else {
	double  mt, dc;
	int     d;

	mt = midi_time_table[channel[ch].portamento_time_msb & 0x7F] *
	    midi_time_table2[channel[ch].portamento_time_lsb & 0x7F] *
	    PORTAMENTO_TIME_TUNING;
	dc = play_mode->rate * mt;
	d = (int) (1.0 / (mt * PORTAMENTO_CONTROL_RATIO));
	d++;
	channel[ch].porta_control_ratio = (int) (d * dc + 0.5);
	channel[ch].porta_dpb = d;
    }
}

static void
update_portamento_time (int ch)
{
    int     i, uv = /*upper_ */ voices;
    int     dpb;
    int32   ratio;

    update_portamento_controls (ch);
    dpb = channel[ch].porta_dpb;
    ratio = channel[ch].porta_control_ratio;

    for (i = 0; i < uv; i++) {
	if (voice[i].status != VOICE_FREE &&
	    voice[i].channel == ch && voice[i].porta_control_ratio) {
	    voice[i].porta_control_ratio = ratio;
	    voice[i].porta_dpb = dpb;
	    recompute_freq (i);
	}
    }
}

static void
update_channel_freq (int ch)
{
    int     i, uv = /*upper_ */ voices;
    for (i = 0; i < uv; i++)
	if (voice[i].status != VOICE_FREE && voice[i].channel == ch)
	    recompute_freq (i);
}

/*! sostenuto is now implemented as an instant sustain */
static void update_sostenuto_controls(int ch)
{
  int i;

  if (channel[ch].kit || channel[ch].sostenuto == 0) return;

  for(i = 0; i < voices; i++) {
	if ((voice[i].status & (VOICE_ON | VOICE_OFF))
			&& voice[i].channel == ch) {
		  voice[i].status = VOICE_SUSTAINED;
		  ctl->note(i);
		  voice[i].envelope_stage = RELEASE;
		  recompute_envelope(i);
	 }
  }
}

#endif

int
play_midi (MidiEvent * eventlist, uint32 samples)
{
    int     rc;
    int saved_kit[MAXCHAN];

    for (rc = 0; rc < MAXCHAN; rc++) saved_kit[rc] = 0;
    adjust_amplification ();

    sample_count = samples;
    event_list = eventlist;
    lost_notes = cut_notes = played_notes = output_clips = 0;

    skip_to (0);

    for (;;) {
	/* Handle all events that should happen at this time */
	while (current_event->time <= current_sample) {
	    int ch = current_event->channel;
	    int a = current_event->a;
	    int b = current_event->b;

	    switch (current_event->type) {

		/* Effects affecting a single note */

	    case ME_NOTEON:

#ifdef tplus
#    if 0
		if (channel[current_event->channel].portamento &&
		    current_event->b &&
		    (channel[current_event->channel].portamento_time_msb |
		     channel[current_event->channel].portamento_time_lsb))
		    break;
#    endif
#endif
		a += channel[ch].transpose;
		current_event->a = a;
		if (!b)	/* Velocity 0? */
		    note_off (current_event);
		else
		    note_on (current_event);
		send_note(b, current_event);
		break;

	    case ME_NOTEOFF:
		a += channel[ch].transpose;
		current_event->a = a;
		note_off (current_event);
		send_note(0, current_event);
		break;

	    case ME_KEYPRESSURE:
		adjust_pressure (current_event);
		ctl->misc_controller(ch, a, 3, 'K', 0);
		break;

		/* Effects affecting a single channel */

	    case ME_PITCH_SENS:
		channel[ch].pitchsens = a;
		channel[ch].pitchfactor = 0;
		break;

	    case ME_PITCHWHEEL:
		channel[ch].pitchbend = a + b * 128;
		channel[ch].pitchfactor = 0;
		/* Adjust pitch for notes already playing */
		adjust_pitchbend (ch);
		ctl->pitch_bend (ch, channel[ch].pitchbend, 0);
		break;
#ifdef tplus
	    case ME_MODULATION_WHEEL:
		channel[ch].modulation_wheel = calc_mw_depth (ch, a);
		update_modulation_wheel (ch, channel[ch].modulation_wheel);
		ctl->pitch_bend(ch, channel[ch].pitchbend, (unsigned)a);
		break;
	    case ME_MW_PMOD:
	        channel[ch].mw_pmod = a;
		break;
	    case ME_MW_FMOD:
	        channel[ch].mw_fmod = a;
		break;
	    case ME_MW_AMOD:
	        channel[ch].mw_amod = a;
		break;

	    case ME_PORTAMENTO_TIME_MSB:
		channel[ch].portamento_time_msb = a;
		update_portamento_time (ch);
		break;

	    case ME_PORTAMENTO_TIME_LSB:
		channel[ch].portamento_time_lsb = a;
		update_portamento_time (ch);
		break;

	    case ME_PORTAMENTO:
		channel[ch].portamento = (a >= 64);
		if (!channel[ch].portamento)
		    drop_portamento (ch);
		ctl->misc_controller(ch, a, 3, 'P', 0);
		break;

	    case ME_FINE_TUNING:
		channel[ch].tuning_lsb = a;
		break;

	    case ME_COARSE_TUNING:
		channel[ch].tuning_msb = a;
		break;

	    case ME_CHANNEL_PRESSURE:
		adjust_channel_pressure (current_event);
		ctl->misc_controller(ch, a, 3, 'p', 0);
		break;

	    case ME_KEYSIG:
		{   int re_sign = a;
		    if (re_sign > 127) re_sign -= 256;
	            current_keysig = re_sign + b * 16;
		}
		ctl->keysig (current_keysig, 0);
	        break;

	    case ME_TIMESIG:
		ctl->timesig (a & 0x0f, a >> 4, b & 0x0f, b >> 4);
	        break;

	    case ME_BREATH:
		ctl->cmsg (CMSG_INFO, VERB_NOISY, "Breath controller");
		ctl->misc_controller(ch, a, 3, 'B', 0);
		break;
	    case ME_FOOT:
		ctl->cmsg (CMSG_INFO, VERB_NOISY, "Foot controller");
		ctl->misc_controller(ch, a, 3, 'F', 0);
		break;
	    case ME_BALANCE:
		ctl->cmsg (CMSG_INFO, VERB_NOISY, "Balance controller");
		ctl->misc_controller(ch, a, 3, 'n', 0);
		break;
	    case ME_DATA_ENTRY_LSB:
		ctl->cmsg (CMSG_INFO, VERB_NOISY, "Data Entry LSB controller");
		break;
	    case ME_SOSTENUTO:
		channel[ch].sostenuto = (a >= 64);
		if (channel[ch].sustain == 0 && channel[ch].sostenuto == 0)
		    drop_sustain(ch);
		else update_sostenuto_controls(ch);
		ctl->cmsg (CMSG_INFO, VERB_NOISY, "Sostenuto controller %d chan %d", a+b, ch);
	        ctl->sustain (ch, a, 'O');
		break;
	    case ME_SOFT_PEDAL:
		ctl->cmsg (CMSG_INFO, VERB_NOISY, "Soft Pedal controller");
	        ctl->sustain (ch, a, 's');
		break;
	    case ME_LEGATO_FOOTSWITCH:
		ctl->cmsg (CMSG_INFO, VERB_NOISY, "Legato Footswitch controller");
	        ctl->sustain (ch, a, 'L');
		break;
	    case ME_HOLD2:
		channel[ch].sustain = a;
		if (channel[ch].sustain == 0 && channel[ch].sostenuto == 0)
		    drop_sustain(ch);
		else update_sostenuto_controls(ch);
		ctl->cmsg (CMSG_INFO, VERB_NOISY, "Hold2 controller");
		ctl->misc_controller(ch, a, 3, 'H', 0);
		break;
	    case ME_PORTAMENTO_CONTROL:
		ctl->cmsg (CMSG_INFO, VERB_NOISY, "Portamento Control controller");
		//ctl->misc_controller(ch, a, 3, 'P', 0);
		break;
	    case ME_TREMOLO_EFFECT:
		ctl->cmsg (CMSG_INFO, VERB_NOISY, "Tremolo Effect controller");
		//channel[ch].effect = (ME_TREMOLO_EFFECT<<8) | a;
		channel[ch].tremolo = a;
		update_tremolo_effect(ch);
		ctl->misc_controller(ch, a, 3, 'T', 0);
		break;
	    case ME_CELESTE_EFFECT:
		if (XG_System_On) channel[ch].variation_depth = a;
		else if (a) {
			ctl->cmsg (CMSG_INFO, VERB_NOISY, "Celeste Effect controller %d chan %d", a, ch);
			channel[ch].effect = (ME_CELESTE_EFFECT<<8) | a;
		}
		else channel[ch].effect = 0;
		ctl->misc_controller(ch, a, 2, XG_System_On? 'V' : 'c', 0);
		break;
	    case ME_PHASER_EFFECT:
		if (a) {
			ctl->cmsg (CMSG_INFO, VERB_NOISY, "Phaser Effect controller");
			channel[ch].effect = (ME_PHASER_EFFECT<<8) | a;
		}
		else channel[ch].effect = 0;
		ctl->misc_controller(ch, a, 3, 'p', 0);
		break;
	    case ME_RPN_INC:
		ctl->cmsg (CMSG_INFO, VERB_NOISY, "RPN Inc controller");
		break;
	    case ME_RPN_DEC:
		ctl->cmsg (CMSG_INFO, VERB_NOISY, "RPN Dec controller");
		break;
	    case ME_MONO:
		ctl->cmsg (CMSG_INFO, VERB_NOISY, "Mono controller %d chan %d", a, ch);
		channel[ch].mono = a;
		break;
	    case ME_POLY:
		ctl->cmsg (CMSG_INFO, VERB_NOISY, "Poly controller");
		channel[ch].mono = 0;
		break;

#endif
	    case ME_MAINVOLUME:
		channel[ch].volume = a;
		adjust_volume (ch);
		ctl->volume (ch, a);
		break;

	    case ME_MASTERVOLUME:
		adjust_master_volume (a + (b << 7));
		break;

	    case ME_REVERBERATION:
		channel[ch].reverberation = a;
		ctl->misc_controller(ch, a, 0, 'R', 0);
		break;

	    case ME_CHORUSDEPTH:
		channel[ch].chorusdepth = a;
		ctl->misc_controller(ch, a, 1, 'C', 0);
		break;

	    case ME_PAN:
		channel[ch].panning = a;
		if (adjust_panning_immediately) adjust_panning (ch);
		ctl->panning (ch, a);
		break;

#ifdef tplus
	    case ME_RANDOM_PAN:
		channel[ch].panning = int_rand(128);
		ctl->panning (ch, channel[ch].panning);
		break;
#endif

	    case ME_EXPRESSION:
		channel[ch].expression = a;
		adjust_volume (ch);
		ctl->expression (ch, a);
		break;

	    case ME_PROGRAM:
		saved_kit[ch] = 0;
		if (channel[ch].kit) {
		    if (channel[ch].kit == 126 || channel[ch].kit == 125) {
		        channel[ch].bank = a + SFXBANK;
			if (drumset[channel[ch].bank] && drumset[channel[ch].bank]->name)
		            ctl->bank (ch, a, 0,
				  drumset[channel[ch].bank]->name);
			else ctl->bank (ch, a, 0, "rhythm sfx");
		    }
		    else {
		        /* Change drum set */
		        channel[ch].bank = a;
			if (drumset[channel[ch].bank] && drumset[channel[ch].bank]->name)
		            ctl->bank (ch, a, 0,
				  drumset[channel[ch].bank]->name);
			else ctl->bank (ch, a, 0, "drums");
		    }
		}
#define WATCH_MU
		else {
		    int bo = 0;
		    channel[ch].program = a;
		    if (channel[ch].xg == 48) {
#ifdef WATCH_MU
			ctl->cmsg(CMSG_TRACE, VERB_VERBOSE,
				"check ch=%d MU100 patch [%d,%d]", ch+1, a, channel[ch].bank);
#endif
			if (tonebank[channel[ch].bank + MU100BANK] &&
			    tonebank[channel[ch].bank + MU100BANK]->tone[a].layer)
				bo = MU100BANK;

#ifdef WATCH_MU
			else ctl->cmsg(CMSG_TRACE, VERB_VERBOSE,
				"Chan %d, no MU100 patch [%d,%d]", ch+1, a, channel[ch].bank);
#endif
		    }
		    else if (channel[ch].xg == 33) {
#ifdef WATCH_MU
			ctl->cmsg(CMSG_TRACE, VERB_VERBOSE,
				"check chan %d VL patch [%d,%d]", ch+1, a, channel[ch].bank);
#endif
			if (tonebank[channel[ch].bank + VLBANK] &&
			    tonebank[channel[ch].bank + VLBANK]->tone[a].layer)
				bo = VLBANK;
#ifdef WATCH_MU
			else ctl->cmsg(CMSG_TRACE, VERB_VERBOSE,
				"Chan %d no VL patch [%d,%d]", ch+1, a, channel[ch].bank);
#endif
		    }
		    else if (XG_System_On && !channel[ch].bank && channel[ch].variationbank &&
			channel[ch].variationbank < NUM_VARIATION_BANKS &&
			tonebank[channel[ch].variationbank + SFXBANK] &&
			tonebank[channel[ch].variationbank + SFXBANK]->tone[a].layer) {
			    bo = channel[ch].variationbank + SFXBANK;
			    ctl->bank(ch, channel[ch].variationbank, 0, NULL);
		    }

		    if (!bo && !channel[ch].sfx)
		    if (!tonebank[channel[ch].bank] || !tonebank[channel[ch].bank]->tone[a].layer) {
			channel[ch].variationbank = channel[ch].bank;
			channel[ch].bank = 0;
			ctl->bank(ch, 0, channel[ch].variationbank, NULL);
		    }
		    if (channel[ch].sfx == SFXBANK && tonebank[SFXBANK]
				    && tonebank[SFXBANK]->tone[a].name)
		        ctl->program (ch, a, tonebank[SFXBANK]->tone[a].name);
		    else if (channel[ch].sfx == SFXBANK && tonebank[120]
				    && tonebank[120]->tone[a].name)
		        ctl->program (ch, a, tonebank[120]->tone[a].name);
		    else if (channel[ch].sfx == SFXBANK)
		        ctl->program (ch, a, "effect");
		    else if (opt_bank &&
				    channel[ch].bank+bo == 0 &&
				    tonebank[opt_bank] &&
				    tonebank[opt_bank]->tone[a].name)
		    	ctl->program (ch, a, tonebank[opt_bank]->tone[a].name);
		    else ctl->program (ch, a, tonebank[channel[ch].bank + bo]->tone[a].name);
		}
		break;

	    case ME_SUSTAIN:
		channel[ch].sustain = a;
		if (!a)
		    drop_sustain (ch);
		ctl->sustain (ch, a, 'S');
		break;

	    case ME_RESET_CONTROLLERS:
		reset_controllers (ch);
		redraw_controllers (ch);
		break;

	    case ME_ALL_NOTES_OFF:
		all_notes_off (ch);
		break;

	    case ME_ALL_SOUNDS_OFF:
		all_sounds_off (ch);
		break;

	    case ME_HARMONICCONTENT:
		channel[ch].harmoniccontent = a;
		ctl->misc_controller(ch, 2*(a-64), -1, 'h', 0);
		break;

	    case ME_RELEASETIME:
		channel[ch].releasetime = a;
		ctl->misc_controller(ch, 2*(a-64), 3, 'r', 0);
		break;

	    case ME_ATTACKTIME:
		channel[ch].attacktime = a;
		ctl->misc_controller(ch, 2*(a-64), 3, 'a', 0);
		break;

	    case ME_DECAYTIME:
		channel[ch].decaytime = a;
		ctl->misc_controller(ch, 2*(a-64), 3, 'd', 0);
		break;

	    case ME_AC1:
		ctl->cmsg(CMSG_TRACE, VERB_DEBUG, "AC1 ch%d val%d", ch, a);
		ctl->misc_controller(ch, a, 3, 'X', 0);
		break;

	    case ME_AC2:
		ctl->cmsg(CMSG_TRACE, VERB_DEBUG, "AC2 ch%d val%d", ch, a);
		ctl->misc_controller(ch, a, 3, 'Y', 0);
		break;
#ifdef tplus
	    case ME_VIBRATO_RATE:
		channel[ch].vibrato_ratio = midi_cnv_vib_rate (a);
		update_channel_freq (ch);
		ctl->misc_controller(ch, a, 3, 'v', 0);
		break;
	    case ME_VIBRATO_DEPTH:
		channel[ch].vibrato_depth = midi_cnv_vib_depth (a);
		update_channel_freq (ch);
		ctl->misc_controller(ch, a, 3, 'V', 0);
		break;
	    case ME_VIBRATO_DELAY:
		channel[ch].vibrato_delay = midi_cnv_vib_delay (a);
		update_channel_freq (ch);
		ctl->misc_controller(ch, a, 3, 'd', 0);
		break;
	    case ME_TEMPO:
	        current_play_tempo = ch + b * 256 + a * 65536;
		ctl->tempo (current_play_tempo, 100);
	        break;
#endif
	    case ME_RECEIVE_CHANNEL:
		ctl->cmsg (CMSG_INFO, VERB_NOISY,
			   "Set receive channel for channel %d to %d", ch, a);
		if (a == ch) break;
		channel[ch].receive = a;
		if (channel[ch].kit)
		        ctl->bank (ch, channel[ch].bank, 0, drumset[channel[ch].bank]->name);
#if 0
ctl->cmsg (CMSG_ERROR, VERB_NORMAL,
			   "Set receive channel for channel %d to %d, bank=%d name=%s", ch, a,
			   channel[ch].bank, drumset[channel[ch].bank]->name);
#endif
	        break;

	    case ME_BRIGHTNESS:
		channel[ch].brightness = a;
		ctl->misc_controller(ch, 2*(a-64), -2, 'b', 0);
		break;

	    case ME_DRYLEVEL:
	        channel[ch].drylevel = a;
		ctl->misc_controller(ch, a, 3, 'D', 0);
	        break;

	    case ME_VELOCITY_SENSE_DEPTH:
	        channel[ch].velocity_sense_depth = a;
	        break;
	    case ME_VELOCITY_SENSE_OFFSET:
	        channel[ch].velocity_sense_offset = a;
	        break;

	    case ME_TONE_BANK:
		if (saved_kit[ch] == SFX_BANKTYPE) {
		    channel[ch].sfx = SFXBANK;
		    channel[ch].kit = channel[ch].xg = 0;
		    ctl->bank(ch, 64, 0, "sfx");
		}
		else channel[ch].sfx = 0;
		saved_kit[ch] = 0;
		if (channel[ch].xg) {
			channel[ch].bank = a;
			ctl->bank(ch, a, 0, NULL);
#ifdef WATCH_MU
		ctl->cmsg(CMSG_TRACE, VERB_VERBOSE, "Chan %d bank=%d xg=%d", ch+1, a, channel[ch].xg);
#endif
		}
		else if (!channel[ch].kit && !channel[ch].sfx) {
		    if ( (XG_System_On && a >= 0 && a < NUM_VARIATION_BANKS) || !tonebank[a]) {
			channel[ch].variationbank = a;
		    	channel[ch].bank = 0;
			ctl->bank(ch, 0, a, NULL);
		    }
		    else {
			channel[ch].bank = a;
			ctl->bank(ch, a, 0, NULL);
		    }
		}
		break;

	    case ME_TONE_KIT:
		if (a == SFX_BANKTYPE) {
		    saved_kit[ch] = a;
		    //channel[ch].sfx = SFXBANK;
		    //channel[ch].kit = channel[ch].xg = 0;
		    //ctl->bank(ch, a, 0, "sfx");
		}
		else {
		    saved_kit[ch] = 0;
		    channel[ch].sfx = 0;
		    if (a == 48 || a == 33) {
		        channel[ch].kit = 0;
			channel[ch].xg = a;
#ifdef WATCH_MU
		ctl->cmsg(CMSG_TRACE, VERB_VERBOSE, "Chan %d xg=%d", ch+1, a);
#endif
		    }
		    else {
		        channel[ch].kit = a;
			channel[ch].xg = 0;
		        a = channel[ch].bank;
		        if (!channel[ch].kit) {
			    if (a >= MAXPROG) a -= MAXPROG;
		            if ( (XG_System_On && a >= 0 && a < NUM_VARIATION_BANKS) || !tonebank[a]) {
			        channel[ch].variationbank = a;
		    	        channel[ch].bank = 0;
			        ctl->bank(ch, 0, a, NULL);
		            }
		            else ctl->bank(ch, a, 0, NULL);
		        }
		        else ctl->bank(ch, a, 0, NULL);
		    }
		}
		break;

	    case ME_EOT:
		/* Give the last notes a couple of seconds to decay  */
		compute_data (play_mode->rate * 2);
		compute_data (0);	/* flush buffer to device */
		ctl->cmsg (CMSG_INFO, VERB_VERBOSE,
			   "Playing time: ~%d seconds",
			   current_sample / play_mode->rate + 2);
		ctl->cmsg (CMSG_INFO, VERB_VERBOSE,
			   "Notes played: %d", played_notes);
		ctl->cmsg (CMSG_INFO, VERB_VERBOSE,
			   "Samples clipped: %d", output_clips);
		ctl->cmsg (CMSG_INFO, VERB_VERBOSE,
			   "Notes cut: %d", cut_notes);
		ctl->cmsg (CMSG_INFO, VERB_VERBOSE,
			   "Notes lost totally: %d", lost_notes);
		ctl->cmsg (CMSG_INFO, VERB_VERBOSE,
			   "Current memory used: %d", current_patch_memory);
		return RC_TUNE_END;
	    }
	    current_event++;
	}

	rc = compute_data (current_event->time - current_sample);
	ctl->refresh ();
	if ((rc != RC_NONE) && (rc != RC_JUMP))
	    return rc;
    }
}



int
play_midi_file (const char *fn)
{
    MidiEvent *event;
    uint32  events, samples;
    int     rc;
    int32   val;
    FILE   *fp;

    ctl->cmsg (CMSG_INFO, VERB_VERBOSE, "MIDI file: %s", fn);

    if (!strcmp (fn, "-")) {
	fp = stdin;
	strcpy (current_filename, "(stdin)");
    }
    else if (!(fp = open_file (fn, 1, OF_VERBOSE, 0)))
	return RC_ERROR;

    ctl->file_name (current_filename);

    event = read_midi_file (fp, &events, &samples);

    if (fp != stdin)
	close_file (fp);

    if (!event || !events)
	return RC_ERROR;

    ctl->cmsg (CMSG_INFO, VERB_NOISY,
	       "%d supported events, %d samples", events, samples);

    ctl->total_time (samples);
    ctl->master_volume (amplification);

    load_missing_instruments ();
    if (check_for_rc ())
	return ctl->read (&val);
#ifdef tplus
    dont_cspline = 0;
#endif

    got_a_lyric = 0;
    rc = play_midi (event, samples);
    if (free_instruments_afterwards)
	free_instruments ();

    free (event);
    return rc;
}

void
dumb_pass_playing_list (int number_of_files, const char *list_of_files[])
{
    int     i = 0;

    if (number_of_files == 0)
	return;

    for (;;) {
	switch (play_midi_file (list_of_files[i])) {
	case RC_REALLY_PREVIOUS:
	    if (i > 0)
		i--;
	    break;

	case RC_PATCHCHANGE:
	    free_instruments ();
	    end_soundfont ();
	    clear_config ();
	    /* what if read_config fails?? */
	    if (read_config_file (current_config_file, 0))
		ctl->cmsg (CMSG_ERROR, VERB_NORMAL,
			   "Could not read patchset %d", cfg_select);
	    break;

	default:		/* An error or something */
	case RC_NEXT:
	    if (i < number_of_files - 1) {
		i++;
		ctl->reset ();
		break;
	    }
	    /* else fall through */

	case RC_QUIT:
	    play_mode->close_output ();
	    ctl->close ();
	    return;
	}
    }
}
