/* created by DMH (damonhorowitz): write seq_type as standard midifile */
/***************************************************************************
*      Change Log
*  Date     | Change
*-----------+---------------------------------------------------------------
* 11-Mar-94 | Created Change Log
* 11-Mar-94 | PLu : Added private to function defs.
****************************************************************************/

#include "stdio.h"
#include "cext.h"
#include "userio.h"
#include "midicode.h"
#include "mfmidi.h"
#include "midifns.h"
#include "timebase.h"
#include "moxc.h"
#include "seq.h"
#include "seqread.h" /* to get scale() */
#include "seqmwrite.h"

long chunk_size_marker;
int seti_counter;
extern time_type a_start_time;

long last_event;                        /*time from last_clock_event to the last event*/
time_type last_clock_event;
time_type last_tick_size;       /* millisec per tick shifted 16 bits */

struct smf_write_seq {
    seq_type seq;
    int track;
    FILE *outfile;
    } smfw_seq;
extern seq_type sequence; /* this is a global to be accessed by 
			   * routines called from the sequence */
/* clock state: */
extern time_type clock_ticksize;  /* millisec per tick shifted 16 bits */
extern boolean clock_running;     /* true if clock is running */
extern boolean use_midi_clock;

private void smfw_bend();
private void smfw_cause_noteoff();
private void smfw_ctrl();
private void smfw_deltatime();
private void smfw_dotrack();
private void smfw_exclusive();
private void smfw_noteoff();
private void smfw_noteon();
private void smfw_process_event();
private void smfw_ramp_event(seq_type seq, event_type event, 
	unsigned int value, unsigned int to_value, int increment,
	time_type step, int n);
private void smfw_send_macro();
private void smfw_touch(seq_type seq, int voice, int value);
private void writevarlen();


/* smfw_bend -- write a pitch bend to a midi file */
/**/
private void smfw_bend(seq_type seq, int voice, int value)
{
    if(debug)   gprintf(TRANS, "smfw_bend %d\n", value);
    smfw_deltatime();
    putc(MIDI_BEND | (voice - 1), smfw_seq.outfile);
    putc(0xFF & ((value & 0x1) << 6) , smfw_seq.outfile);
    putc(0xFF & (value >> 1), smfw_seq.outfile);
}


/* smfw_cause_noteoff -- schedule a noteoff for midi file */
/*
 * NOTE: this is called by smfw_process_event when it handles a note
 * event node in a seq_type's event list.  The ordinary moxc scheduler
 * is used to "schedule" the noteoff in the future.  In reality, the
 * output is done as fast as possible (by attempting an infinite rate),
 * so no real timing delays occur.  The effect is to sort events by their
 * specified time.
 */
private void smfw_cause_noteoff(seq, delay, voice, pitch)
  seq_type seq;
  time_type delay;
  int voice;
  int pitch;
{
	if(debug)       gprintf(TRANS, "cause noteoff at %ld...", virttime + delay);
	pitch += seq->transpose;
	while (pitch <= 0) pitch += 12;
	while (pitch >= 127) pitch -= 12;
	seq->noteoff_count++;
	causepri((delay_type) delay, 10, seq->noteoff_fn,
		 seq, voice, pitch);
    
}

private void smfw_clock_event(old_ticksize, new_ticksize)
  time_type old_ticksize, new_ticksize;
{
	time_type temp_ticksize = new_ticksize;
	new_ticksize = scale(new_ticksize, 375L, 1024L);
/* (new_ticksize >> 16) * 24000 ms/clock becomes us/midiquarter */

	if(debug)       gprintf(TRANS, "smfw_clock: write %ld (time:%ld) ->->->tempo %ld\n", 
		new_ticksize, virttime, 2500L / (new_ticksize / 24000));

	/*use old ticksize to write the delta for the clock event*/
	last_tick_size = old_ticksize;
	smfw_deltatime();
	last_tick_size = temp_ticksize;/* reset to = new_tick_size */
	   putc(0xFF, smfw_seq.outfile);
	putc(0x51, smfw_seq.outfile);
	putc(0x03, smfw_seq.outfile);
	putc((int) ((new_ticksize >> 16) & 0xFF), smfw_seq.outfile);
	putc((int) ((new_ticksize >> 8) & 0xFF), smfw_seq.outfile);
	putc((int) (new_ticksize & 0xFF), smfw_seq.outfile);

	last_clock_event = virttime;
	last_event = 0L;
		/*no time expired between last clockevent and last event(they are the same).*/
		/*next clock event will be exactly the next this_event from last_clock_event*/
}


/* smfw_ctrl -- write a control change to a midi file */
/**/
private void smfw_ctrl(seq_type seq, int voice, int ctrl_name, int value)
{
    if(debug)   gprintf(TRANS, "smfw_ctrl %d: %d\n", ctrl_name, value); 
    smfw_deltatime();
    putc(MIDI_CTRL | (voice - 1), smfw_seq.outfile);
    putc(ctrl_name, smfw_seq.outfile);
    putc(value, smfw_seq.outfile);
}


/* smfw_deltatime -- write the time difference between now an previous event */
/**/
private void smfw_deltatime()
{
    /* if last_ and clock_ are different, use last_ for clock deltatime*/
    time_type use_ticksize = (clock_ticksize != last_tick_size) ?
				last_tick_size : clock_ticksize;
    time_type this_event = virttime - last_clock_event;
    if(debug)   gprintf(TRANS, "delta! ticksize: %lu Lastev: %ld ThisevScaled: %lu Thisev: %lu ", 
	    clock_ticksize, last_event,  (this_event * ((2500L << 16) / use_ticksize)) / 100,
	     this_event);
    
    this_event = ((virttime - last_clock_event) * ((2500L << 16) / use_ticksize)) / 100;

    if(debug)   gprintf(TRANS, "--- deltatime: %lu\n", this_event - last_event);        
    writevarlen((long) (this_event - last_event));

    last_event = this_event; 
}


/* smfw_dotrack -- write the remainder of a track  */
private void smfw_dotrack(seq)
  seq_type seq;
{
    long end_marker;
    timebase_type old_timebase = timebase;
    unsigned long chunk_size;

    if (seq->runflag) {
		if ((seq->timebase->virt_base == 0) &&
	      (seq->timebase->rate == STOPRATE)) 
		  /*we just set these last time through... do nothing*/;
		seq_stop(seq);
    }
    timebase_use(seq->timebase);
    set_rate(seq->timebase, STOPRATE);
    set_virttime(seq->timebase, 0L);
    seq->current = seq_events(seq);
    seq->noteoff_count = 0L;
    seq->runflag = true;
    seq->paused = true;
    last_clock_event = 0L;
    last_event = 0L;
    if(debug)   gprintf(TRANS, "dotrack (reset) %d %ld (%lu) \n", 
	    smfw_seq.track, last_event, virttime);

    if (seq->current)   
	cause((delay_type)(seq->current->ntime - virttime), smfw_process_event,
		 seq);
    set_virttime(timebase, MAXTIME);
    catchup();

    putc(0x00, smfw_seq.outfile);
    putc(0xFF, smfw_seq.outfile);/*end of track chunk*/
    putc(0x2F, smfw_seq.outfile);
    putc(0x00, smfw_seq.outfile);
    end_marker = ftell(smfw_seq.outfile);
    fseek(smfw_seq.outfile, chunk_size_marker, 0);/*go back to enter chunksize*/
    chunk_size = (end_marker - chunk_size_marker) - 4;/* - 4 for 4 size bytes*/ 
    if(debug)   gprintf(TRANS, "bytes written in previous track: %ld \n\n", chunk_size);
    putc((int) ((0xFF & (chunk_size >> 24))), smfw_seq.outfile);
    putc((int) ((0xFF & (chunk_size >> 16))), smfw_seq.outfile);
    putc((int) ((0xFF & (chunk_size >> 8))), smfw_seq.outfile);
    putc((int) ((0xFF & chunk_size)), smfw_seq.outfile);
    fseek(smfw_seq.outfile, end_marker, 0);/*return file pointer to end of track*/
    timebase_use(old_timebase);
}


/* smfw_exclusive -- write a system excl. msg to midi file */
private void smfw_exclusive(length, msg)
int length;
unsigned char *msg; 
{
    int length_count = 0;

    if(debug)   gprintf(TRANS, "SYSEX (time:%ld)\n", virttime);

    smfw_deltatime();
   
    while (length > length_count){ /* *(msg-1) != MIDI_EOX) { */
	    putc(*msg++, smfw_seq.outfile); 
		length_count++;
    }
    if(*(--msg) != MIDI_EOX) gprintf(TRANS, "ERROR: no end of sysex\n");
}

private void smfw_msg_write(n,c1,c2,c3)
  int n;
  unsigned char c1,c2,c3;
{
    if(debug)   gprintf(TRANS, "MSGWRITE %d bytes (time:%ld)\n", n, virttime);
    smfw_deltatime();
    switch(n) {
	case 1: putc(c1, smfw_seq.outfile);
		break;
	case 2: putc(c1, smfw_seq.outfile);
		putc(c2, smfw_seq.outfile);
		break;
	case 3: putc(c1, smfw_seq.outfile);
		putc(c2, smfw_seq.outfile);
		putc(c3, smfw_seq.outfile);
		break;
	}
}


/* smfw_noteoff -- write noteoff to midi file */
/**/
private void smfw_noteoff(seq_type seq, int voice, int pitch)
{
	if(debug)       gprintf(TRANS, "smfw_noteoff %d: %d (time:%ld)\n", voice, pitch, virttime);
    smfw_deltatime();
    putc(NOTEOFF | (voice - 1), smfw_seq.outfile);
    putc(pitch, smfw_seq.outfile);
    putc(0x40, smfw_seq.outfile);
} 


/* smfw_noteon -- write noteon to midi file */
/*
 * NOTE: the seq parameter is not used here, but is passed in by the
 * seq_noteon macro, so we have to have a placeholder for it.
 */
private void smfw_noteon(seq, voice, pitch, vel)
  seq_type seq;
  int voice, pitch, vel;
{
    if(debug)   gprintf(TRANS, "smfw_noteon %d: %d %d(time:%ld)\n", voice, pitch, vel, virttime);
    smfw_deltatime();
    putc(NOTEON | (voice - 1), smfw_seq.outfile);
    putc(pitch, smfw_seq.outfile);
    putc(vel, smfw_seq.outfile);
}


/* smfw_process_event -- write a seq event to a midi file */
/**/
private void smfw_process_event(seq)
  seq_type seq;
{
    register event_type event;
    if (!seq->runflag) return;
    while ((event = seq->current) && (event->ntime <= virttime)) {
	unsigned int voice;
	if ((vc_voice(event->nvoice) == smfw_seq.track) ||       /*if on current track*/
	    (((vc_voice(event->nvoice) - 16) == smfw_seq.track) 
			&& (smfw_seq.track > 0)) ||
		/* acknowledge clock change on all tracks*/
	    (event->value == CLOCK_VALUE)) {

	    /* process all current (and earlier) events */
	    if (is_note(event)) {   /*** play a note or rest ***/
		/* if this note is not a rest, play it and schedule an off event */
		if (event->value != NO_PITCH &&
		      (seq_channel_mask(seq) &
		       (1 << ((voice = vc_voice(event->nvoice)) - 1)))) {
		    seq_noteon(seq, voice, (0xFF & event->value), 
			(int) (event->u.note.ndur & 0xFF));
		
		    seq_cause_noteoff(seq, (event->u.note.ndur) >> 8, 
			  voice, (0xFF & event->value)); 
		}
	    } else {                    /*** send a control command ***/
		int n;
		time_type step;
		int delta;
		int increment;
		int voice = vc_voice(event->nvoice);
		ulong enabled = seq_channel_mask(seq) & (1 << (voice - 1));

		switch (vc_ctrl(event->nvoice)) {
		  case PSWITCH_CTRL:
		    if (!enabled) break;
		    if(debug)    gprintf(TRANS, "porta %d (time:%ld)... ", event->value, virttime);
		    seq_midi_ctrl(seq, voice, PORTASWITCH, 0xFF & event->value);
		    break;
		  case MODWHEEL_CTRL:
		    if (!enabled) break;
		    if(debug)    gprintf(TRANS, "modw %d (time:%ld)...", event->value, virttime);
		    seq_midi_ctrl(seq, voice, MODWHEEL, 0xFF & event->value);
		    break;
		  case TOUCH_CTRL:
		    if (!enabled) break;
		    if(debug)    gprintf(TRANS, "touch %d (time:%ld)... ", event->value, virttime);
		    seq_midi_touch(seq, voice, 0xFF & event->value);
		    break;
		  case VOLUME_CTRL:
		    if (!enabled) break;
		    if(debug)    gprintf(TRANS, "ftvol %d (time:%ld)...", event->value, virttime);
		    seq_midi_ctrl(seq, voice, VOLUME, 0xFF & event->value);
		    break;
		  case BEND_CTRL:
		    if (!enabled) break;
		    if(debug)    gprintf(TRANS, "bend %d (time:%ld)... ", event->value, virttime);
		    seq_midi_bend(seq, voice, event->value);
		    break;
		  case PROGRAM_CTRL:
		    if (!enabled) break;
		    if(debug)    gprintf(TRANS, "prog %d (time:%ld)\n", event->value, virttime);
		    smfw_deltatime();
		    putc(MIDI_CH_PROGRAM | (voice - 1), smfw_seq.outfile);
		    putc(0xFF & event->value, smfw_seq.outfile);
		    break;
		  case ESC_CTRL:
		    switch (event->value) {
		      time_type this_event;
		      case CALL_VALUE:       /*called routine will write to midifile in execution */
			sequence = seq;
			(*(event->u.call.routine))(event->u.call.args);
			break;
		      case CLOCK_VALUE:
			clock_ticksize = event->u.clock.ticksize;
			if(debug)    gprintf(TRANS, "clockevent! ticksize: %lu (time:%ld)\n",
				clock_ticksize, virttime);
    
			if (virttime > 0) {  /* any clock before this is already recorded in the header */
			    if (smfw_seq.track == 0) {             /* record clock event on tempo track = 0 */
				/* cause clock write in half a newtick, because it was written .5 tick early*/
				cause((delay_type) (clock_ticksize >> 17), smfw_clock_event, 
				      last_tick_size, clock_ticksize);
				last_tick_size = clock_ticksize; /*set new ticksize*/
			    } else { /*not on tempo track*/
				this_event = ((virttime - last_clock_event) *
					    ((2500L << 16) / last_tick_size)) / 100;
				if(debug)   gprintf(TRANS, "track != 0: Lastev: %ld Thisev: %ld NewLast: %ld\n", 
				last_event, this_event, this_event - last_event);
				last_event = 0L - (this_event - last_event);
				    last_clock_event = virttime;
			    /*last_event is negative, so will be ADDED to next this_event*/
    
				last_tick_size = clock_ticksize;
			    }               
			} else if (debug) gprintf(TRANS, "IGNORED\n");/* if virttime <= 0 */
			break;
		      case MACCTRL_VALUE:
			if (!enabled) break;
			if (debug) gprintf(TRANS, "MACCTRL %d: %d (time:%ld)\n", 
				    event->u.macctrl.ctrl_number, event->u.macctrl.value, virttime);
			smfw_deltatime();
			putc(MIDI_CTRL | (voice - 1), smfw_seq.outfile);
			putc(0xFF & event->u.macctrl.ctrl_number, smfw_seq.outfile);
			putc(0xFF & event->u.macctrl.value, smfw_seq.outfile);
			break;
		      case MACRO_VALUE:
			if (!enabled) break;
			if (debug) gprintf(TRANS, "MACRO sent to...\n");
			smfw_send_macro(event->u.macro.definition,
			  voice, event->u.macro.parameter, -1, 0);
			break;
		      case CTRLRAMP_VALUE:
		      case DEFRAMP_VALUE: {
			int from, to;
			if (!enabled) break;
			step = event->u.ramp.step;
			if (event->value == CTRLRAMP_VALUE) {
			if(debug)   gprintf(TRANS, "CTRLRAMP (time:%ld)...", virttime);
			    from = event->u.ramp.u.ctrl.from_value;
			    to = event->u.ramp.u.ctrl.to_value;
			} else {
			    if (debug) gprintf(TRANS, "DEFRAMP (time:%ld)...", virttime);
			    from = event->u.ramp.u.def.parameter[
					event->u.ramp.u.def.parm_num];
			    to = event->u.ramp.u.def.to_value;
			}
			delta = to - from;
			increment = delta;
			if (delta < 0) delta = -delta;
			/* RBD - Note: Step is always non-zero */
			n = event->u.ramp.dur / step;
			increment = (increment << 8) / n;
			smfw_ramp_event(seq, event, from << 8, to << 8, 
				   increment, step, n);
			seq->noteoff_count++;
			break;
		      }
		      case SETI_VALUE:
			seti_counter++; /*will be printed after writing is completed*/
			*(event->u.seti.int_to_set) = event->u.seti.value;
			break;
		      default:
			gprintf(TRANS, "unexpected ESC_CTRL value\n");
			break;
		    }
		    break;
		  default:
		    gprintf(TRANS, "unexpected seq data\n");
		    break;
		}
	    }
	}
	seq->current = event->next;
    }
    if (seq->current) { /* if there is an event: delay, and then process again */
	cause((delay_type)(event->ntime - virttime), smfw_process_event, seq);
    }
}

/* smfw_ramp_event -- generate a ramp to write*/
private void smfw_ramp_event(seq, event, value, to_value, increment, step, n)
  seq_type seq;
  register event_type event;
  unsigned int value;
  unsigned int to_value;
  int increment;
  time_type step;
  int n;
{
    if(debug)   gprintf(TRANS, "ramp of %d: %d to %d\n", event->u.ramp.ctrl, value >> 8,
	    to_value >> 8);     
    if (seq->runflag) {
	int voice = vc_voice(event->nvoice);
	if (n == 0) value = to_value;
	else cause((delay_type)step, smfw_ramp_event, seq, event, value + increment,
		   to_value, increment, step, n - 1);
	if (event->value == CTRLRAMP_VALUE) {
	    int ctrl = event->u.ramp.ctrl;
	    if (ctrl == -TOUCH_CTRL) smfw_touch(seq, voice, value >> 8);
	    else if (ctrl == -BEND_CTRL) smfw_bend(seq, voice, value >> 8);
	    else smfw_ctrl(seq, voice, ctrl, value >> 8);
	} else { /* must be DEFRAMP_VALUE */
	    smfw_send_macro(event->u.ramp.u.def.definition,
		vc_voice(event->nvoice),
		event->u.ramp.u.def.parameter,
		event->u.ramp.u.def.parm_num, value >> 8);
	}
	if (n == 0) seq_end_event(seq);
    }
}


/* smfw_send_macro -- write msg to midi file from a seq "macro" event */
/**/
private void smfw_send_macro(ptr, voice, parameter, parm_num, value)
  register unsigned char *ptr;
  int voice;
  short parameter[];
  int parm_num;
  int value;
{
    register unsigned char code, *loc;
    while (code = *ptr++) {
	loc = ptr + *ptr;
	ptr++;
	if (code <= nmacroparms) {
	    code--;
	    *loc = (code == parm_num ? value : parameter[code]) & 0x7f;
	} else if (code == nmacroparms + 1) {
	    *loc = ((voice - 1) & 0xF) | *loc;
	} else {
	    code -= (nmacroparms + 2);
	    *loc = ((code == parm_num ? value : parameter[code]) >> 7) & 0x7F;
	}
    }
    if (ptr[1] == MIDI_SYSEX) smfw_exclusive(*ptr, ptr + 1);
    else smfw_msg_write(*ptr, ptr[1], ptr[2], ptr[3]);
}


/* smfw_touch -- write aftertouch msg to midi file */
/**/
private void smfw_touch(seq_type seq, int voice, int value)
{
    if(debug)   gprintf(TRANS, "smfw_touch %d\n", value);
    smfw_deltatime();
    putc(MIDI_TOUCH | (voice - 1), smfw_seq.outfile);
    putc(value, smfw_seq.outfile);
}


void seq_write_smf(seq, outfile)
  seq_type seq;
  FILE *outfile;
{
    time_type put_tick_size;
    int i;
    time_type starting_ticksize = 1638400L;/*default midifile tempo 100*/
    int track_count = 0;
    long track_count_marker;
    register event_type event;

    seti_counter = 0;
    
	/*initialize the smfw_seq struct*/
    smfw_seq.outfile = outfile;
    smfw_seq.seq = seq_copy(seq);

    smfw_seq.seq->cause_noteoff_fn = smfw_cause_noteoff;
    smfw_seq.seq->midi_bend_fn    = smfw_bend;
    smfw_seq.seq->midi_ctrl_fn    = smfw_ctrl;
    smfw_seq.seq->midi_touch_fn   = smfw_touch;
    smfw_seq.seq->noteoff_fn      = smfw_noteoff;
    smfw_seq.seq->noteon_fn       = smfw_noteon;

    event = seq_events(smfw_seq.seq);

    /*search for clock events up till start of score*/
    while(event->ntime <= 0){
    if(debug)   gprintf(TRANS, "event (time:%ld)\n", event->ntime); 
	if(event->value == CLOCK_VALUE) {
	    if(debug)   gprintf(TRANS, "clock %lu at 0\n", event->u.clock.ticksize);
	    starting_ticksize = event->u.clock.ticksize;
	    break;
	    }
	event = event->next;
	}

    putc(0x4D, smfw_seq.outfile); /*header:  MThd*/
    putc(0x54, smfw_seq.outfile);
    putc(0x68, smfw_seq.outfile);
    putc(0x64, smfw_seq.outfile);
    putc(0x00, smfw_seq.outfile);
    putc(0x00, smfw_seq.outfile);
    putc(0x00, smfw_seq.outfile);
    putc(0x06, smfw_seq.outfile);
    putc(0x00, smfw_seq.outfile);
    putc(0x01, smfw_seq.outfile);       /*format 1 */
    putc(0x00, smfw_seq.outfile);

    track_count_marker = ftell(smfw_seq.outfile);   /*number of tracks will be written later*/
    putc(0x00, smfw_seq.outfile);                                       /*will be filled by track_count_marker*/

    putc(0x02, smfw_seq.outfile);/*division resolution of 600*/
    putc(0x58, smfw_seq.outfile);

    for(i = 0; i < 17; i++){/*for each track..*/
	    if(((seq_used_mask(smfw_seq.seq) >> (i - 1)) & 0x1) || (i == 0)){
	    if(debug) gprintf(TRANS, "write track %d \n", i);
	    track_count++;
	    clock_ticksize = starting_ticksize;
	    last_tick_size = starting_ticksize;
	    putc(0x4D, smfw_seq.outfile);/*track header: MTrk*/
	    putc(0x54, smfw_seq.outfile);
	    putc(0x72, smfw_seq.outfile);
	    putc(0x6B, smfw_seq.outfile);
	   
	    chunk_size_marker = ftell(smfw_seq.outfile);/*size of chunk will be written later*/
	    putc(0x00, smfw_seq.outfile);                               /*will be filled by chunk_size_marker*/
	    putc(0x00, smfw_seq.outfile);
	    putc(0x00, smfw_seq.outfile);
	    putc(0x00, smfw_seq.outfile);

	if(i == 0) { /*tempo and time signature track*/
	    putc(0x00, smfw_seq.outfile);/* default time sig stuff*/
	    putc(0xFF, smfw_seq.outfile);
	    putc(0x58, smfw_seq.outfile);
	    putc(0x04, smfw_seq.outfile);
	    putc(0x04, smfw_seq.outfile);
	    putc(0x02, smfw_seq.outfile);
	    putc(0x18, smfw_seq.outfile);
	    putc(0x08, smfw_seq.outfile);
	    putc(0x00, smfw_seq.outfile);
			
	    putc(0xFF, smfw_seq.outfile);/*TEMPO: inserted here in case default is used*/
	    putc(0x51, smfw_seq.outfile);
	    putc(0x03, smfw_seq.outfile);
	    put_tick_size = scale(clock_ticksize, 375L, 1024L);
	    putc((int) ((put_tick_size >> 16) & 0xFF), smfw_seq.outfile);
	    putc((int) ((put_tick_size >> 8) & 0xFF), smfw_seq.outfile);
	    putc((int) (put_tick_size & 0xFF), smfw_seq.outfile);
	    }
	    smfw_seq.track = i;
	    smfw_dotrack(smfw_seq.seq);
	  }
    }
    if(seti_counter) gprintf(TRANS, "%d SETI events IGNORED!\n", seti_counter);
    seq_stop(smfw_seq.seq);
    fseek(smfw_seq.outfile, track_count_marker, 0);/*go back and insert number of tracks*/
    putc(0xFF & track_count, smfw_seq.outfile);
    fclose(smfw_seq.outfile);
}


/* writevarlen -- write a variable length integer to midi file */
/**/
private void writevarlen(value)
  register long value;
{       
    register ulong buffer;

	if(debug) gprintf(TRANS, "variable length quantity...");

    buffer = value & 0x7f;

    while((value >>= 7) > 0) {
	buffer <<= 8;
	buffer |= 0x80;
	buffer += (value & 0x7f);
    }

    for(;;) {
	if(debug) gprintf(TRANS, " byte ");
	putc((int) (buffer & 0xFF), smfw_seq.outfile);
	if (buffer & 0x80)	buffer >>= 8;
	else break;
    }
	if(debug) gprintf(TRANS, "written!\n");
}
