/* 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.
* 28-Apr-03 |  DM : Change #include's for portability
****************************************************************************/

#include "switches.h"

#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");
}
