/*
(c) Copyright 1988-1994 Microsoft Corporation.

Microsoft Bars&Pipes Professional Source Code License

This License governs use of the accompanying Software.  
Microsoft hopes you find this Software useful.

You are licensed to do anything you want with the Software. 

In return, we simply require that you agree:

1.      Not to remove any copyright notices from the Software.

2.      That the Software comes "as is", with no warranties.  
        None whatsoever. This means no implied warranty of merchantability or 
        fitness for a particular purpose or any warranty of non-infringement.  
        Also, you must pass this disclaimer on whenever you distribute the Software.

3.      That we will not be liable for any of those types of damages known as indirect, 
        special, consequential, or incidental related to the Software or this License, 
        to the maximum extent the law permits. Also, you must pass this limitation of 
        liability on whenever you distribute the Software.

4.      That if you sue anyone over patents that you think may apply to the Software 
        for that person’s use of the Software, your license to the Software ends automatically.

5.      That the patent rights Microsoft is licensing only apply to the Software, 
        not to any derivatives you make.

6.      That your rights under the License end automatically if you breach this in any way.
*/

#include "/CompilerSpecific.h"
#include <intuition/intuition.h>
#include <exec/memory.h>
#include <graphics/gfxmacros.h>
#include "tools.h"
#include <proto/exec.h>
#include <proto/dos.h>
#include <proto/graphics.h>
#include <proto/intuition.h>
#include <proto/layers.h>
#include <string.h>
#include <stdio.h>
#include "all.h"
#include "edit.h"
#include "notate.h"
#include "noteimage.h"

#define SETDRAWN(a) ((a)->mark |= NM_DRAWN)
#define STEM_UP 1
#define STEM_DOWN 0

extern struct Functions functions;
extern char blowup;

long getstem(long notedata)
{
    if (notedata & N_STEMUP) return(N_STEMUP);
    else return(0);
}

void setstem(struct NotateEvent *note, long stem)
{
    if (note->mark & NM_KEEPSTEM) return;
    if (stem) note->notate |= N_STEMUP;
    else note->notate &= ~N_STEMUP;
}

short isathree(struct NotateEvent *note)
{
    if (!note) return(0);
    if (note->status != MIDI_NOTEOFF) return(0);
    if (note->velocity != NE_THREE) return(0);
    return(1);
}

short isarest(struct NotateEvent *note)
/* returns 0 if not a rest, 1 if is a rest */
{
    if (!note) return(0);
    if (note->status != MIDI_NOTEOFF) return(0);
    if (note->velocity != NE_REST) return(0);
    return(1);
}

short isarealnote(struct NotateEvent *note)
/* returns 1 if a note */
{
    if (!note) return(0);
    if (note->status == MIDI_NOTEON) return(1);
    return(0);
}

short isanote(struct NotateEvent *note)
/* returns 0 if not a note, 1 if is a note or tie */
{
    if (!note) return(0);
    if (note->status == MIDI_NOTEON) return(1);
    if ((note->status == MIDI_NOTEOFF) && (note->velocity ==
        NE_TIE)) return(1);
    return(0);
}

short isatie(struct NotateEvent *note)
/* returns 0 if not a tied note, 1 if it is a tied note */
{
    if (!note) return(0);
    if (isanote(note) && (note->notate & N_TNOTE)) return(1);
    else return(0);
}

static short isatriplet(struct NotateEvent *note)
/* returns 0 if not a triplet note, 1 if is a triplet note */
{
    if (!note) return(0);
    if (!(note->notate & N_TRIPLET)) return(0);
    if (note->status == MIDI_NOTEON) return(1);
    if ((note->status == MIDI_NOTEOFF) && (note->velocity ==
        NE_TIE)) return(1);
    return(0);
}

static struct NotateEvent *existsrest(struct NotateEvent *note)

{
    for (;note;note = note->next)
    {
        if (isarest(note))
            return(note);
    }
    return(NULL);
}

static struct NotateEvent *existstriplet(struct NotateEvent *note)

{
    for (;note;note = note->next)
    {
        if (isatriplet(note))
            return(note);
    }
    return(NULL);
}

static struct NotateEvent *existsrealnote(struct NotateEvent *note)
{
    for (;note;note = note->next)
    {
        if (isarealnote(note)) return(note);
    }
    return(NULL);
}

static struct NotateEvent *existsnote(struct NotateEvent *note)
{
    for (;note;note = note->next)
    {
        if (isanote(note)) return(note);
    }
    return(NULL);
}

char notatefull(struct NotateEvent *note)
{
    if (note->notate & N_DONTPLOT) return(0);
    else return(1);
}

void cleardrawnbit(struct NotateEvent *note)
{
    if (note) note->mark &= ~(NM_DRAWN);
}

void clearnote(struct NotateEvent *note, long endtime)
/* clear NM_DRAWN bit on notes from note until endtime */
{
    for (;note;note = note->next)
    {
        if (note->time > endtime) break;
        if ((note->status == MIDI_NOTEON) || (note->status == MIDI_NOTEOFF))
            note->mark &= ~(NM_DRAWN);
    }
}

static resolvetime(struct Edit *edit,long time,short notate)

{
    short quant;
    short mult;
    short notatequant = edit->notatequant;

    if (notate & N_TRIPLET) {
        quant = notatequant << 1;
        mult = 2;
    }
    else {
        quant = notatequant * 3;
        mult = 3;
    }
    time = (time + (quant >> 1)) / quant;
    return(time*mult);
}

quantizetime(struct Edit *edit,long time,short notate)

{
    return(resolvetime(edit,time,notate)*edit->notatequant);
}

short getnoteres(struct NotateEvent *note)
{
    return(short)((note->notate & N_RES) >> N_SHIFTRES);
}

static long finishresolvenotetime(struct Edit *edit,struct NotateEvent *note)

{
    long quant;
    long time = note->time;
    short notate = note->notate;
    short notatequant, notateres;
    notateres = (notate & N_RES) >> N_SHIFTRES;
    notatequant = (192 >> notateres) / 3;
    if (notate & N_RESTRIP) notateres |= 0x80;

    quant = (time + (notatequant >> 1))/ notatequant;
    if (((quant % 2) && (quant % 3)) || (!(notateres & 0x80) &&
        (quant % 3)) || ((notate & N_TRIPLET) && (quant % 2)))
    {
    /* move it to a 2 boundary if it is a triplet */
        if (((notateres & 0x80) && !(notate & N_NOTE)) ||
                                             (notate & N_TRIPLET)) {
            quant = (quant / 2) * 2;
        }
    /* move it to a 3 boundary if it is not a triplet */
        else {
            quant = (quant / 3) * 3;
        }
    }
    quant *= notatequant;
    return(quant);
}

static long resolvenotetime(struct Edit *edit,struct NotateEvent *note)

{
    long quant;
    quant = finishresolvenotetime(edit,note) / edit->notatequant;
    return(quant);
}

long quantizenotetime(struct Edit *edit,struct NotateEvent *note)

{
    return(finishresolvenotetime(edit,note));
}

static void notesetresolution(struct Edit *edit, struct NotateEvent *note)
{
    note->notate &= ~N_RES;
    note->notate |= ((edit->notateres & 3) << N_SHIFTRES);
    if (edit->notateres & 0x80) note->notate |= N_RESTRIP;
    else note->notate &= ~N_RESTRIP;
}

static short typetolength(struct Edit *edit, short data)
/* data is struct NotateEvent->notate.  In other words, the notation
bits
        1536 = 11000000000
*/

  {
    /* create temp note structure to send to quantizenotetime */
    struct NotateEvent typenote;
    struct NotateEvent *note = &typenote;
    short length;
    if (!(data & N_NOTEVAL)) data |= N_1;
    length = 1536 >> (data & N_NOTEVAL);
    length = (data & N_DOTTED) ? (length * 3) >> 1 : length;
    length = (data & N_TRIPLET) ? (length << 1) / 3 : length;
    typenote.status = MIDI_NOTEON;
    typenote.time = length;
    typenote.notate = data;
    length = quantizenotetime(edit, note);
    return(length);
}

static short drawtypetolength(struct Edit *edit, short data)
/* data is struct NotateEvent->notate.  In other words, the notation
bits
        1536 = 11000000000
*/

  {
    /* create temp note structure to send to quantizenotetime */
    struct NotateEvent typenote;
    struct NotateEvent *note = &typenote;
    short length;
    if (!(data & N_NOTEVAL)) data |= N_1;
    length = 1536 >> (data & N_NOTEVAL);
    length = (data & N_DOTTED) ? (length * 3) >> 1 : length;
    length = (data & N_TRIPLET) ? (length << 1) / 3 : length;
    typenote.status = MIDI_NOTEON;
    typenote.time = length;
    typenote.notate = data;
    typenote.notate |= N_RES;
    length = quantizenotetime(edit, note);
    return(length);
}

static void clipline(struct Edit *edit,short l,short t,
        short r,short b)
/* draws a line from left, top to right, bottom, unless both left
and right are off screen, or top and bottom are off screen.  If only
one is off screen, it is set to be on the screen boundary. */

{
    if (t < edit->topedge) t = edit->topedge;
    else if (t > edit->bottomedge) t = edit->bottomedge;
    if (b < edit->topedge) b = edit->topedge;
    else if (b > edit->bottomedge) b = edit->bottomedge;
    if (l < edit->leftedge) l = edit->leftedge;
    else if (l > edit->rightedge) l = edit->rightedge;
    if (r < edit->leftedge) r = edit->leftedge;
    else if (r > edit->rightedge) r = edit->rightedge;
    printMove(edit->rp,l,t);
    printDraw(edit->rp,r,b);
    if (blowup) {
      if (l == r) {
        Move(edit->rp,PRINTCONVERTX(l)+1,(PRINTCONVERTY(t)));
        Draw(edit->rp,PRINTCONVERTX(r)+1,PRINTCONVERTY(b));
      }
      else {
        Move(edit->rp,PRINTCONVERTX(l),PRINTCONVERTY(t)+1);
        Draw(edit->rp,PRINTCONVERTX(r),PRINTCONVERTY(b)+1);
      }
    }
}

static void drawpixel(struct Edit *edit, short x, short y)
/* plots a pixel as long as it is within the window boundary */

{
    if (blowup) {
      WritePixel(edit->rp,x,y);
    }
    else {
      if ((x >= edit->leftedge) && (x <= edit->rightedge) &&
        (y >= edit->topedge) && (y <= edit->bottomedge))
        WritePixel(edit->rp,x,y);
    }
}

static void drawledgerlines(struct Edit *edit,short x,
        short y,short stemup)
/* only called once from within notate.c, this draws the little
pieces of ledger that are on notes above or below the staff */

{
    short index;
    short x2, x8;
    x2 = x-2;   /* used to shorten number of computations */
    x8 = x+8;
    if (stemup) {
        if (y > edit->bassbottom) {
            for (index = edit->bassbottom + 6;index <= y;index += 6) {
                clipline(edit,x2,index,x8,index);
            }
        }
        else if ((y > edit->treblebottom) && (y < edit->basstop)) {
            for (index = edit->treblebottom + 6;index <= y;index += 6) {
                clipline(edit,x2,index,x8,index);
            }
        }
        if (y < edit->trebletop) {
            for (index = edit->trebletop - 6;index >= y;index -= 6) {
                clipline(edit,x2,index,x8,index);
            }
        }
    }
    else {
        if (y > edit->bassbottom) {
            for (index = edit->bassbottom + 6;index <= y;index += 6) {
                clipline(edit,x2,index,x8,index);
            }
        }
        else if (y < edit->trebletop) {
            for (index = edit->trebletop - 6;index >= y;index -= 6) {
                clipline(edit,x2,index,x8,index);
            }
        }
        else if ((y < edit->basstop) && (y > edit->treblebottom)) {
            for (index = edit->basstop - 6;index >= y;index -= 6) {
                clipline(edit,x2,index,x8,index);
            }
        }
    }
}

static void clipimagemask(struct Edit *edit,struct Image *image,
        short x,short y,short color)

{
    if ((x > (edit->leftedge-20)) &&
        (x < edit->rightedge - image->Width) &&
        (y > edit->topedge) &&
        (y < edit->bottomedge - image->Height)) {
        x = PRINTCONVERTX(x);
        y = PRINTCONVERTY(y);
            if (color > 100) newdrawimagemask(edit->rp,image,x,y,color,D_COMPLEMENT);
            else drawimagemask(edit->rp,image,x,y,color);
    }
}

long getnotetime(struct Edit *edit, struct NotateEvent *note)
{
    short leftoff = edit->notatequant >> (edit->shift + 1);
    long time;

    time = quantizenotetime(edit,note);
    /* subtract the left edge of the note display */
    time -= edit->leftstart;

    /* take into account the zoom factor */
    time = time >> edit->shift;

    /* add the distance from the window's edge to the beginning of the plotted data */
    time += edit->leftedge;

    /* add an offset, which is determined by the quantization
     * resolution diveded by the zoom factor plus one
     */
    time += leftoff;
    return(time);
}

static void beamcoords(struct Edit *edit,struct NotateEvent *note,
        short *xx,short *yy)
/* returns beamcoords through xx and yy pointers.  Returns x = 6
   if stem is up, x = 0 if stem is down.   determines if the stem
comes out of the right side of the note (stem up) or the left side
(stem down.)
*/

{
    short x,y;
    short notatebits = edit->notatebits & NB_THINKBITS;
    y = edit->notationbase - edit->topstart + TOPDATASTART + 17;
    x = getnotetime(edit,note);
    if (getstem(note->notate)) x += 6;
    if (notatebits & NB_THINKTREBLE) {
        y -= 36;
    }
//    else if (note->value >= edit->transcenter) {
    else if (note->mark & NM_STAFF)
    {
        y -= 36;
    }
    y -= 3 * (BEAMTOINT(note->mark));
    *yy = y;
    *xx = x;
}

short gett(struct Edit *edit, struct NotateEvent *note)
{
    short t2;
    t2 = displaytwelvetoscale(&edit->clip,note->time,note->value -
            edit->transcenter + 60,0);
    t2 = t2 - 21;
    t2 = IMulS(t2,3);
    t2 += 11;
    t2 = edit->notationbase - t2;
    t2 -= edit->topstart;
    t2 += TOPDATASTART;
    if (getstem(note->notate)) t2 += 1;
    return(t2);
}

static short getintersection(short x1, short y1, short x2, short y2,
    short x)

{
    short dy, dx, ady, adx, r, c, f, inc1, inc2, g;
    char pos_slope;

        dx = x2-x1;
        dy = y2-y1;
        adx = abs(dx);
        ady = abs(dy);
        pos_slope=(dx>0);
        if (dy<0) pos_slope=!pos_slope;
        if (dx>0) { c=x1; r=y1; f=x2; }
        else { c=x2; r=y2; f=x1; }
        inc1=ady<<1;
        g=inc1-adx;
        inc2=(ady-adx)<<1;
        if (pos_slope)
        {
            while (c<=f)
            {
                if (c==x)
                {
                    return(r);
                }
                ++c;
                if (g>=0)
                {
                    ++r;
                    g+=inc2;
                }
                else g+=inc1;
            }
        }
        else
        {
            while (c<=f)
            {
                if (c==x)
                {
                    return(r);
                }
                ++c;
                if (g>0)
                {
                    --r;
                    g+=inc2;
                }
                else g+=inc1;
            }
        }
}

static void drawbeamline(struct Edit *edit, short x1, short y1, short x2,
    short y2, short xbegin, short xend, short ydiff)

{
    short dy, dx, ady, adx, r, c, f, inc1, inc2, g;
    char pos_slope;

    dx = x2-x1;
    dy = y2-y1;
    adx = abs(dx);
    ady = abs(dy);
    pos_slope=(dx>0);
    if (dy<0) pos_slope = !pos_slope;
    if (dx>0) { c=x1; r=y1+ydiff; f=x2; }
    else { c=x2; r=y2+ydiff; f=x1; }
    inc1=ady<<1;
    g=inc1-adx;
    inc2=(ady-adx)<<1;
    if (pos_slope)
    {
        while (c<=f)
        {
            if ((c>=xbegin) && (c<=xend))
            {
              drawpixel(edit,c,r);
              drawpixel(edit,c,r+1);
              if (blowup)
              {
                drawpixel(edit,c,r+2);
              }
            }
            ++c;
            if (g>=0)
            {
              ++r;
              g+=inc2;
            }
            else g+=inc1;
        }
    }
    else
    {
        while (c<=f)
        {
          if ((c>=xbegin) && (c<=xend))
          {
            drawpixel(edit,c,r);
            drawpixel(edit,c,r+1);
            if (blowup)
            {
                drawpixel(edit,c,r+2);
            }
          }
          ++c;
          if (g>0)
          {
            --r;
            g+=inc2;
          }
          else g+=inc1;
        }
    }
}

static void drawlongbeam(struct Edit *edit,struct NotateEvent *note1,
        short t1,struct NotateEvent *note2,short t2)
/* draws the beams over or under groups of notes */
{
    short y1, x1, y2, x2;
    short notedata1 = note1->notate;
    beamcoords(edit,note1,&x1,&y1);
    beamcoords(edit,note2,&x2,&y2);
    if (notedata1 & N_FLAG) {
      x1 = PRINTCONVERTX(x1);
      x2 = PRINTCONVERTX(x2);
      y1 = PRINTCONVERTY(y1);
      y2 = PRINTCONVERTY(y2);
      drawbeamline(edit, x1, y1, x2, y2, x1, x2, 0);
    }
}

static void drawthree(struct Edit *edit,struct NotateEvent *note, short
    color)

{
    struct RastPort *rp = edit->rp;
    short y, x1, x2;
    short notedata = note->notate;
    short tips;
    long time = getnotetime(edit, note);
    long endtime, middletime;
    SetAPen(rp,color);
    beamcoords(edit,note,&x1,&y);
    if (getstem(note->notate))
    {
        x1 = 0;
        x2 = 8;
        if ((y>62) && (y<74)) y = 62;
        else if ((y>98) && (y<110)) y = 98;
        y -= 5;
    }
    else
    {
        x1 = 0;
        x2 = 6;
        if ((y>62) && (y<74)) y = 74;
        else if ((y>98) && (y<110)) y = 110;
        y += 2;
    }
    middletime = note->time + note->duration;
    endtime = middletime + note->duration;
    endtime -= edit->leftstart;
    endtime = endtime >> edit->shift;
    endtime += edit->leftedge;
    endtime += (edit->notatequant >> (edit->shift + 1));

    middletime -= edit->leftstart;
    middletime = middletime >> edit->shift;
    middletime += edit->leftedge;
    middletime += (edit->notatequant >> (edit->shift + 1));

    clipimagemask(edit,(struct Image *)getimage(IMAGE_3),middletime,y,color);     /* Draw the 3. */

    y += 2;
    clipline(edit,time+x1,y,middletime - 2,y);           /* The lines on each side. */
    clipline(edit,middletime+8,y,endtime + x2,y);

    if (getstem(notedata)) tips = y + 1;
    else tips = y - 1;

    clipline(edit,time + x1,y,time + x1,tips);            /* The brace ends. */
    clipline(edit,endtime + x2,y,endtime + x2,tips);
}

void drawrest(struct Edit *edit,struct NotateEvent *note, short color)

{
    struct RastPort *rp = edit->rp;
    short notedata = note->notate;
    short notetype = notedata & N_NOTEVAL;
    short leftoff = edit->notatequant >> (edit->shift + 1);
    long time = getnotetime(edit,note);
    short y;
    char staff=0;
    if (note->mark & NM_STAFF) staff=1;
    SetAPen(rp,color);
    /* plot rests */
    switch (notetype) {
            case N_1 :
                if (staff) y=77;
                else y=41;
                break;
            case N_2 :
            case N_4 :
                if (staff) y=74;
                else y=38;
                break;
            case N_8 :
            case N_16 :
            case N_32 :
                if (staff) y=71;
                else y=35;
                break;
    }
    y = edit->notationbase - y;
    y += TOPDATASTART - edit->topstart + 2;
    switch (notetype) {
            case N_1 :
                y -= 1;
                time -= leftoff;
                time += (348 >> edit->shift);
                clipimagemask(edit,(struct Image *)getimage(IMAGE_1R),time,y,color);
                break;
            case N_2 :
                time -= leftoff;
                clipimagemask(edit,(struct Image *)getimage(IMAGE_2R),time+2,y,color);
                break;
            case N_4 :
                y -= 6;
                time -= leftoff;
                clipimagemask(edit,(struct Image *)getimage(IMAGE_4R),time+2,y,color);
                break;
            case N_8 :
                y -= 4;
                clipimagemask(edit,(struct Image *)getimage(IMAGE_8R),time,y,color);
                break;
            case N_16 :
                y -= 4;
                clipimagemask(edit,(struct Image *)getimage(IMAGE_16R),time-2,y,color);
                break;
            case N_32 :
                y -= 4;
                clipimagemask(edit,(struct Image *)getimage(IMAGE_32R),time,y,color);
                break;
    }
    if (notedata & N_DOTTED) clipline(edit,time+13,y+2,time+15,y+2);
}

char getnoteoffset(struct NotateEvent *note)

{
    if ((note->mark & NM_SIGN1) && (note->mark & NM_SIGN2)) return(4);
    if (note->mark & NM_SIGN1) return(1);
    if (note->mark & NM_SIGN2) return(-1);
    return(0);
}

void drawnote(struct Edit *edit,struct NotateEvent *note,short color)
/* edit = Edit structure, note = Note structure,
   t determines vertical value of note
   offset determines whether to plot a natural, sharp, or flat sign
*/

{
  struct RastPort *rp = edit->rp;
  short notedata = note->notate;
  short notetype = notedata & N_NOTEVAL;
  long time;
  long endtime;
  short t;
  char offset, drawheight;
  if (!(notedata & N_NOTE)) return;
  t = displaytwelvetoscale(&edit->clip,note->time,note->value -
          edit->transcenter + 60,&offset);
  offset = getnoteoffset(note);
  t = t - 21;
  t = IMulS(t,3);
  t += 11;
  t = edit->notationbase - t;
  t -= edit->topstart;
  t += TOPDATASTART;
  if (((t+2) >= edit->bottomedge) || (t < TOPDATASTART)) return;
  time = getnotetime(edit,note);
  if (time < edit->leftedge) return;
  if (notedata & N_ADJACENT)
  {
    if (getstem(notedata)) time += 6;
    else time -= 6;
  }
  /* plot natural, sharp, or flat sign */
  SetAPen(rp,color);
  if (blowup) time+=3;
  if (offset == 4)
  {
    if (blowup) t-=1;
    clipimagemask(edit,(struct Image *)getimage(IMAGE_NATURAL),time-10,t-2,color);
    if (blowup) t+=1;
  }
  else if (offset > 0)
    clipimagemask(edit,(struct Image *)getimage(IMAGE_SHARP),time-10,t-2,color);
  else if (offset < 0)
  {
    if (blowup) t-=2;
    clipimagemask(edit,(struct Image *)getimage(IMAGE_FLAT),time-10,t-2,color);
    if (blowup) t+=2;
  }
  if (blowup) time-=3;
  if ((notetype < N_8) || !(notedata & N_FLAG) || (notedata & N_ADJACENT)
    || (notedata & N_BEAM))
  {
    if (notetype < N_4)
    {
      clipimagemask(edit,(struct Image *)getimage(IMAGE_1),time,t-1,color);
    }
    else
    {
      clipimagemask(edit,(struct Image *)getimage(IMAGE_4),time,t-1,color);
    }
  }
  if (notedata & N_DOTTED)
  {
    clipline(edit,time+8,t+2,time+10,t+2);
  }
  if (notedata & N_ADJACENT)
  {
    if (getstem(notedata)) time -= 6;
    else time += 6;
  }
  drawledgerlines(edit,time,t+1,getstem(notedata));

  if (notetype >= N_8)
  {
    if (notedata & N_FLAG)
    {
      if (!(notedata & N_BEAM) && !(notedata & N_ADJACENT))
      {
        if (notetype == N_8)
        {
          if (getstem(notedata))
          {
            clipimagemask(edit,(struct Image *)getimage(IMAGE_8U),time,t-13,color);
          }
          else
          {
            clipimagemask(edit,(struct Image *)getimage(IMAGE_8D),time,t-1,color);
          }
        }
        else if (notetype == N_16)
        {
          if (getstem(notedata))
          {
            clipimagemask(edit,(struct Image *)getimage(IMAGE_16U),time,t-13,color);
          }
          else
          {
            clipimagemask(edit,(struct Image *)getimage(IMAGE_16D),time,t-1,color);
          }
        }
        else if (notetype == N_32)
        {
          if (getstem(notedata))
          {
            clipimagemask(edit,(struct Image *)getimage(IMAGE_32U),time,t-13,color);
          }
          else
          {
            clipimagemask(edit,(struct Image *)getimage(IMAGE_32D),time,t-1,color);
          }
        }
        else if (notetype == N_64)
        {
          if (getstem(notedata))
          {
            clipimagemask(edit,(struct Image *)getimage(IMAGE_64U),time,t-13,color);
          }
          else
          {
            clipimagemask(edit,(struct Image *)getimage(IMAGE_64D),time,t-1,color);
          }
        }
      }
    }
    /* Flag not set, draw little stem to connect with other notes */
    else
    {
      if (!(notedata & N_BEAM))
      {
        if (getstem(notedata))
        {
          clipline(edit,time+6,t,time+6,t-BEAMTOINT(note->mark)*3);
        }
        else clipline(edit,time,t+2,time,t+BEAMTOINT(note->mark)*3+2);
      }
    }
  }
  else if (notetype > N_1)
  {
    if (notetype < N_8)
    {
      if (getstem(notedata))
      {
        clipline(edit,time+6,t,time+6,t-21);
      }
      else
      {
        clipline(edit,time,t+3,time,t+21);
      }
    }
  }
  if ((color == 6) || (color == 1) || (color == 200)) return;

  offset = 4;
  if (notedata & N_TNOTE)
  {
    /* need endtime to determine how long to draw the "arc" for a tied note */
    endtime = time + (drawtypetolength(edit,note->notate) >> edit->shift);
    #define LEFTOFFSET      6
    #define RIGHTOFFSET     -1
    #define TOPOFFSET       4
    #define DRAWWIDTH       2
    if (getstem(note->notate))
    {
      offset = 4;
      drawheight = 2;
    }
    else
    {
      offset = -3;
      drawheight = -2;
    }
    /* draw the \_ after the note, for a tie */
    clipline(edit,time+LEFTOFFSET,t+offset,
      time+LEFTOFFSET+DRAWWIDTH,t+offset+drawheight);
    clipline(edit,time+LEFTOFFSET+DRAWWIDTH,t+offset+drawheight,
      endtime + RIGHTOFFSET - DRAWWIDTH,t + offset + drawheight);
    /* draw the / before a note, to finish the \_/ tie */
    clipline(edit,endtime+RIGHTOFFSET-DRAWWIDTH,t+offset+drawheight,
      endtime + RIGHTOFFSET,t + offset);
  }
}

void drawstem(struct Edit *edit,struct NotateEvent *note,
    struct NotateEvent *firstnote, struct NotateEvent *lastnote)
{
    short xfirst, yfirst, xlast, ylast, x, y, t, ydiff, beam, xbegin, xend;
    char width;
    short notedata = note->notate;
    short notetype = notedata & N_NOTEVAL;
    beamcoords(edit,firstnote,&xfirst,&yfirst);
    beamcoords(edit,lastnote,&xlast,&ylast);
    if (xlast == xfirst) return;
    x = getnotetime(edit,note);
    if (getstem(note->notate))
    {
      x += 6;
    }
    y = getintersection(xfirst, yfirst, xlast, ylast, x);
    if (notetype > N_8)
    {
      if (notedata & N_TRIPLET) width = (16 / (notetype - N_8)) >> edit->shift;
      else width = (24 / (notetype - N_8)) >> edit->shift;
    }
    else width = 0;
    if (notedata & N_LEFTBEAM) xbegin = x - width;
    else xbegin = x;
    if (notedata & N_RIGHTBEAM) xend = x + width;
    else xend = x;
    t = gett(edit,note);
    if (!getstem(note->notate)) clipline(edit,x,t+2,x,y);
    else clipline(edit,x,t,x,y);
    /* draw correct number of beams for Noteval */
    if (width && (notedata & N_BEAM))
    {
      beam = notetype - N_8;
      if (blowup)
      {
        xfirst = PRINTCONVERTX(xfirst);
        yfirst = PRINTCONVERTY(yfirst);
        xlast = PRINTCONVERTX(xlast);
        ylast = PRINTCONVERTY(ylast);
        xend = PRINTCONVERTX(xend);
        xbegin = PRINTCONVERTX(xbegin);
      }
      ydiff = 0;
      while (beam)
      {
        beam--;
        if (getstem(notedata))
        {
          ydiff += 3;
        }
        else
        {
          ydiff -= 3;
        }
        ydiff = PRINTCONVERTY(ydiff);
        drawbeamline(edit, xfirst, yfirst, xlast, ylast,
          xbegin, xend, ydiff);
      }
    }
}

void drawphrase(struct Edit *edit,struct NotateEvent *note,short color)
/* edit = Edit structure, note = Note structure,
*/

{
  struct NotateEvent *veryfirstnote, *firstnote, *lastnote, *finalnote;
  short stem, t1, t2;
  char staff = note->mark & NM_STAFF;
  long nextmeasuretime = nextmeasure(&edit->clip,
    quantizenotetime(edit,note),1);
  long firstnotetime, lastnotetime;

  if ((note->status != MIDI_NOTEON) && (note->status != MIDI_NOTEOFF))
    return;
  if (color == 4) color = 0;

  /* only plot one deleted or highlighted note or complemented */
  if ((color == 6) || (color == 1) || (color >= 200))
  {
    if (color == 201) color = 0;
    if (edit->lastselectnote)
      cleardrawnbit((struct NotateEvent *)edit->lastselectnote);
    if (edit->selectnote)
      cleardrawnbit((struct NotateEvent *)edit->selectnote);
    if (note->mark & NM_DRAWN) return;  /* note is already drawn */
    if (note->notate & N_DONTPLOT) return;
    if ((edit->notatebits & NB_THINKTREBLE) && !staff) return;
    if ((edit->notatebits & NB_THINKBASS) && staff) return;
    if (note->status == MIDI_NOTEOFF)
    {
      if (note->velocity == NE_REST)
      {
        drawrest(edit,note,color);
      }
      if (note->velocity == NE_THREE)
      {
        drawthree(edit,note,color);
      }
      if (note->velocity == NE_TIE)
      {
        drawnote(edit,note,color);
      }
    }
    else
    {
      drawnote(edit,note,color);
    }
    return;
  }
  if (note->mark & NM_DRAWN) return;  /* note is already drawn */
  if ((edit->notatebits & NB_THINKTREBLE) && !staff) return;
  if ((edit->notatebits & NB_THINKBASS) && staff) return;
  if (note->status == MIDI_NOTEOFF)
  {
      if (note->velocity == NE_REST)
      {
          drawrest(edit,note,color);
          SETDRAWN(note);
          return;
      }
      if (note->velocity == NE_THREE)
      {
          drawthree(edit,note,color);
          SETDRAWN(note);
          return;
      }
  }
  stem = getstem(note->notate);
  /* time to find beam info */
  firstnote = 0; lastnote = 0;
  for (;(note && (quantizenotetime(edit,note) < nextmeasuretime));
      note =note->next)
  {
    if (isanote(note) && !(note->mark & NM_DRAWN) &&
          !(note->notate & N_DONTPLOT))
    {
      if ((note->mark & NM_STAFF) != staff) continue;
      if ((getstem(note->notate)) != stem) continue;
      if (!firstnote)
      {
        firstnote = note;
        veryfirstnote = note;
      }
      else if (quantizenotetime(edit,note) <
        quantizenotetime(edit,firstnote)) firstnote = note;
      if ((!(note->notate & N_FLAG))
        || ((note->notate & N_FLAG) && !(note->notate & N_BEAM)))
      {
        if (lastnote)
        {
          if (quantizenotetime(edit,note) !=
            quantizenotetime(edit,lastnote)) break;
        }
        lastnote = note;
      }
      finalnote = note;
    }
  }
  if (!firstnote) return;
  if (!lastnote) lastnote = firstnote;
  nextmeasuretime = quantizenotetime(edit, lastnote);
  t1 = gett(edit, firstnote);
  t2 = gett(edit, lastnote);
  firstnotetime = getnotetime(edit,firstnote);
  lastnotetime = getnotetime(edit,lastnote);
  SetAPen(edit->rp, 0);
  if ((firstnotetime != lastnotetime) &&
    ((firstnote->notate & N_NOTEVAL) >= N_8))
  {
    drawlongbeam(edit,firstnote,t1,lastnote,t2);
  }
  /* time to plot notes */
  note = veryfirstnote;
  for (;note;note = note->next)
  {
    /* plot if it is a note or a tie, is in the same staff, and hasn't been
    * drawn yet
    */
    if (quantizenotetime(edit,note) > nextmeasuretime) continue;
    if (((note->status == MIDI_NOTEON)
      || ((note->status == MIDI_NOTEOFF) && (note->velocity ==
      NE_TIE))) && !(note->mark & NM_DRAWN))
    {
      if ((note->mark & NM_STAFF) != staff) continue;
      if ((getstem(note->notate)) != stem) continue;
      if (note->notate & N_DONTPLOT) continue;
      drawnote(edit,note,color);
      if ((note->notate & N_NOTEVAL) > N_4)
      drawstem(edit,note,firstnote,lastnote);
      SETDRAWN(note);
    }
    if (note == finalnote) break;
  }
}

#ifdef GERMAN
static struct IntuiText waitIText2 = {
        0,2,JAM2,133,17,NULL,"",NULL
};

static struct IntuiText waitIText1 = {
        3,0,JAM1,22,17,NULL,"Notation Takt",&waitIText2
};

static struct NewWindow waitNewWindowStructure1 = {
        188,52,183,31,0,4,
        GADGETDOWN+GADGETUP,
        ACTIVATE+NOCAREREFRESH,
        NULL,NULL,NULL,NULL,NULL,5,5,-1,-1,
        CUSTOMSCREEN
};
#else
static struct IntuiText waitIText2 = {
        0,2,JAM2,157,17,NULL,"",NULL
};

static struct IntuiText waitIText1 = {
        3,0,JAM1,22,17,NULL,"Notating Measure",&waitIText2
};

static struct NewWindow waitNewWindowStructure1 = {
        188,52,207,31,0,4,
        GADGETDOWN+GADGETUP,
        ACTIVATE+NOCAREREFRESH,
        NULL,NULL,NULL,NULL,NULL,5,5,-1,-1,
        CUSTOMSCREEN
};
#endif
static struct Window *waitwindow = 0;
extern short dontcolorpointer;
static char printing = 0;

void setprinting(char pflag)

{
    printing = pflag;
}

static void notateopenwait()

{
    preparerequester(&waitNewWindowStructure1);
    if (printing) {
    waitNewWindowStructure1.LeftEdge = 20;
    waitNewWindowStructure1.TopEdge = 10;
    }
    waitwindow = (struct Window *) OpenWindow(&waitNewWindowStructure1);
    if (waitwindow) {
        dontcolorpointer = 1;
#ifdef GERMAN
        EmbossRequestOn(waitwindow,"Warte");
#else
        EmbossRequestOn(waitwindow,"Wait");
#endif
        dontcolorpointer = 0;
    }
}

static void postmeasure(short measure)

{
    char text[20];
    sprintf(text,"%ld    ",measure);
    text[5] = 0;
    waitIText2.IText = text;
    PrintIText(waitwindow->RPort,&waitIText1,0,0);
}

static void notateclosewait(void)

{
    if (waitwindow) {
        CloseWindow(waitwindow);
        waitwindow = 0;
    }
}

static short durationtonotation(struct Edit *edit,short len)

{
    short result = 0;
    short index = 0;

    if (!(len % 9)) {
        result = N_DOTTED;
        len = (len << 1) / 3;
    }
    else if (len % 3) {
        result = N_TRIPLET;
        len = (len * 3) >> 1;
    }
    len *= edit->notatequant;
    for (index = 1;index <= N_64;index++) {
        if ((768 >> (index - 1)) <= len) break;
    }
    return(short)(index | result);
}

static short newdurationtonotation(struct Edit *edit,short len)
/* find the note->notate duration from the note->duration of a note.
 * return this value
 */
{

    short type, length, index = 0;
    short lowest = 6;
    char tripleton;
    tripleton = (edit->notateres & 0x80) ? 1 : 0;
    for (type = NT_DOTTED; type <= NT_NORMAL; type++)
    {
        for (length = 0; length < NL_LEN; length ++)
        {
            if ((len >= edit->noteconvert[type][length][NR_LOW]) &&
                (len <= edit->noteconvert[type][length][NR_HIGH]))
            {
                index = length + 1;
                if (index > lowest) index = lowest;
                else if ((type == NT_TRIPLET) &&
                    (edit->notateres & 0x80))
                {
                    index |= N_TRIPLET;
                }
                else if (type == NT_DOTTED) index |= N_DOTTED;
                /* if triplet resolution is not selected, return
                 * immediately.  Otherwise, wait until this routine
                 * has a chance to check the length against the
                 * N_TRIPLET
                 */
            }
        }
    }
    if ((index & N_TRIPLET) && (index & N_DOTTED))
    {
        index &= ~N_DOTTED;
    }
    return(index);
}

static short nontriplettonotation(struct Edit *edit,short len)
/* find the note->notate duration from the note->duration of a note.
 * return this value, which may only be as small as the smallest note
 * in the resolution.
 */
{

    short type, length, index = 0;
    short lowest = 6;
    for (type = NT_NORMAL; type > NT_TRIPLET; type --)
    {
        for (length = 0; length < NL_LEN; length ++)
        {
            if ((len >= edit->noteconvert[type][length][NR_LOW]) &&
                (len <= edit->noteconvert[type][length][NR_HIGH]))
            {
                index = length + 1;
                if (index > lowest) index = lowest;
                else if (type == NT_DOTTED) index |= N_DOTTED;
            }
        }
    }
    return(index);
}

static short findtripletnotation(struct Edit *edit,short len)
/* find the note->notate duration from the note->duration of a note.
 * return this value, which may only be as small as the smallest note
 * in the resolution.
 */
{

    short length, index = 0;
    short lowest = (edit->notateres & 7) + 3;
    {
        for (length = 0; length < NL_LEN; length ++)
        {
            if ((len >= edit->noteconvert[NT_TRIPLET][length][NR_LOW]) &&
                (len <= edit->noteconvert[NT_TRIPLET][length][NR_HIGH]))
            {
                index = length + 1;
            }
        }
    }
    if (index > lowest) index = lowest;
    if (!index) index = N_2;
    return(short)(index | N_TRIPLET);
}

void changeduration(struct Edit *edit,struct NotateEvent *note)

{
    short length;
     if (edit && note) {
    note->notate &= ~N_NOTE;
    note->notate &= ~N_TNOTE;
    length = newdurationtonotation(edit,note->duration);
    if (length & N_TRIPLET)
            length = findtripletnotation(edit,note->duration);
    note->notate |= length;
    if (!(edit->notateres & 0x80)) note->notate &= ~N_TRIPLET;
    }
}

static struct NotateEvent *sortchord(struct NotateEvent *list)

{
    struct NotateEvent *temp;
    struct NotateEvent *array[41];
    short i,j;
    short count = 0;
    temp = list;
    for (i=0;temp;temp = temp->next) {
        array[i] = temp;
        i++;
        if (i >= 40) return(list);
    }
    count = i;
    for (i=0;i<count;i++) {
        for (j=i+1;j<count;j++) {
            if (array[i]->value > array[j]->value) {
                temp = array[i];
                array[i] = array[j];
                array[j] = temp;
            }
            /* if values are the same, put the note with the greatest
             * duration first.  This is important for the removeduplicate
             * routine.
             * Also, ties are given first priority.
             */
            else if (array[i]->value == array[j]->value)
            {
                if ((array[j]->status == MIDI_NOTEON) &&
                    (array[i]->duration < array[j]->duration))
                {
                    temp = array[i];
                    array[i] = array[j];
                    array[j] = temp;
                }
                else if (isatie(array[j]) && !isatie(array[i]))
                {
                    temp = array[i];
                    array[i] = array[j];
                    array[j] = temp;
                }
            }
        }
    }
    array[count] = 0;
    list = array[0];
    temp = list;
    for (i=1;temp && (i < 40);i++) {
        temp->next = array[i];
        temp = temp->next;
    }
    return(list);
}

static struct NotateEvent *revsortchord(struct NotateEvent *list)

{
    struct NotateEvent *temp;
    struct NotateEvent *array[41];
    short i,j;
    short count = 0;
    temp = list;
    for (i=0;temp;temp = temp->next) {
        array[i] = temp;
        i++;
        if (i >= 40) return(list);
    }
    count = i;
    for (i=0;i<count;i++) {
        for (j=i+1;j<count;j++) {
            if (array[i]->value < array[j]->value) {
                temp = array[i];
                array[i] = array[j];
                array[j] = temp;
            }
        }
    }
    array[count] = 0;
    list = array[0];
    temp = list;
    for (i=1;temp && (i < 40);i++) {
        temp->next = array[i];
        temp = temp->next;
    }
    return(list);
}

static short findbeam(struct Edit *edit,short highest,
        short lowest,unsigned long time,short stem)

{
    short upperd;
    short lowerd;
    short notate = 0;
    short center, transcenter;
    transcenter =
        displaytwelvetoscale(&edit->clip,time,edit->transcenter,0);
    center = displaytwelvetoscale(&edit->clip,time,edit->centerrange,0);
    upperd = highest - center;
    lowerd = lowest - center;
    if (edit->notatebits & NB_THINKBOTH) {
        if (transcenter > highest) { /* notes are in bass clef */
            if (stem) {
                notate = upperd + 23;
            }
            else
            {
                notate = lowerd + 11;
            }
        }
        else {
            if (!stem) {
                notate = lowerd + 11;
            }
            else
            {
                notate = upperd + 23;
            }
        }
    }
    else if (stem) {
        notate = upperd + 23;
    }
    else notate = upperd + 11;
    return(notate);
}

static void clearbadties(struct Edit *edit)

{
    struct NotateEvent *note = (struct NotateEvent *) edit->clip.events.first;
    struct NotateEvent *keep = 0;
    struct NotateEvent *next;
    unsigned short index;
    long times[128];
    struct NotateEvent *list[128];
    short notelength, value;
    for (index = 0;index < 128;index++) {
        times[index] = 0;
        list[index] = 0;
    }
    for (;note;) {
        next = note->next;
        if ((note->status == MIDI_NOTEOFF) && (note->velocity == NE_TIE)) {
            value = note->value;
            if (quantizenotetime(edit,note) > times[value]) {
                changeduration(edit,list[value]);
                freeevent(note);
                note = next;
                continue;
            }
            else if (note->notate & N_TNOTE) {
                notelength = typetolength(edit, note->notate);
                times[note->value] = notelength + quantizenotetime(edit,note);
            }
            else {
                times[note->value] = 0;
                list[note->value] = 0;
            }
        }
        else {
            if (isanote(note) && (note->notate & N_TNOTE)) {
        value = note->value;
        changeduration(edit,list[value]);
                notelength = typetolength(edit,note->notate);
                list[value] = note;
                times[value] = notelength + quantizenotetime(edit,note);
            }
        }
        note->next = keep;
        keep = note;
        note = next;
    }
    for (value = 0;value < 128;value++) {
        if (list[value]) {
            changeduration(edit,list[value]);
        }
    }
    edit->clip.events.first = (struct Event *) keep;
}

void setstaff(struct Edit *edit, struct NotateEvent *note)

{
        long value = edit->transcenter;
        /* only change staff of notes, not rests */
        if (note->status == MIDI_NOTEON) value += edit->ledger_lines;
        if (note->value >= value)
            note->mark |= NM_STAFF;
        else
            note->mark &= ~NM_STAFF;
}

static struct NBeat *getbeat(struct NMeasure *measure,short index)

{
    struct NBeat *beat = measure->beats;
    for (;beat && ((beat->index + beat->length) <= index);beat = beat->next);
    return(beat);
}

static short notationtoindexln(struct Edit *edit, struct NotateEvent *note)
/* convert note->notate into a measure index length */
{
    short factor, indexln;
    if (!(note->notate & N_NOTEVAL)) return(99);
    factor = 6 - (note->notate & N_NOTEVAL);
    if (note->notate & N_TRIPLET) indexln = 2<<factor;
    else indexln = 3<<factor;
    if (note->notate & N_DOTTED) indexln = (3*indexln)/2;
    return(indexln);
}

static void setnotationfromindexln(struct Edit *edit,
    struct NotateEvent *note, short indexln)
/* sets note->notate according to indexln */
{
    short newnotate = 0;
    char triplet = 0;
    if (!(indexln%3) && !(note->notate & N_TRIPLET)) indexln /= 3;
    else if (!(indexln % 2) || (note->notate & N_TRIPLET))
    {
        indexln /= 2;
        triplet = 1;
    }
    else indexln /= 3;
    switch (indexln)
    {
        case 1 :
            newnotate = 6;
            break;
        case 2 :
            newnotate = 6-1;
            break;
        case 3 :
            newnotate = (6-1)|N_DOTTED;
            break;
        case 4 :
            newnotate = 6-2;
            break;
        case 5 :
        case 6 :
            newnotate = (6-2)|N_DOTTED;
            break;
        case 7 :
        case 8 :
            newnotate = 6-3;
            break;
        case 9 :
        case 10 :
        case 11 :
        case 12 :
            newnotate = (6-3)|N_DOTTED;
            break;
        case 13 :
        case 14 :
        case 15 :
        case 16 :
            newnotate = 6-4;
            break;
        case 17 :
        case 18 :
        case 19 :
        case 20 :
        case 21 :
        case 22 :
        case 23 :
        case 24 :
            newnotate = (6-4)|N_DOTTED;
            break;
        default :
            if (indexln < 40)
            {
                newnotate = 6-5;
            }
            else return;
    }
    note->notate &= ~N_NOTE;
    note->notate |= newnotate;
    if (triplet) note->notate |= N_TRIPLET;
}

static void inserttie(struct NotateEvent *original,
        struct Edit *edit,struct NMeasure *measure,
        short start,short end,short duration,short value,char flag,
        short triplet)

/*      Create an imaginary tied note.  First, make sure that there
        is no conflicting tied note already in the measure.
        Then, create the new tied note and place it in the
        measure.
        The original note is sent so that the new tied note's
        ->mark bits can equal the original's.
        start = measure click time of original note.
        end = measure click time of new note.
        duration = note->duration of new note.
*/

{
    struct NotateEvent *note = (struct NotateEvent *) allocevent();
    struct NotateEvent *scan;
    struct NBeat *beat;
    short index, newlength;
    for (index = start + 1;index <= measure->size;index++) {
        if (index > end) break;
        scan = measure->array[index];
        for (;scan;scan = scan->next) {
        if (scan == original) continue;
            if (scan->status == MIDI_NOTEOFF) {
                if (scan->value == value) {
                    if (scan->velocity == NE_TIE) {
                        measure->array[index] = (struct NotateEvent *)
                            List_Remove((struct ListItem *)measure->array[index],(struct ListItem *)scan);
                        freeevent(scan);
                        break;
                    }
                }
            }
        }
    }
    if (note) {
        note->notate = 0;
        note->mark = 0;
        beat = getbeat(measure, end);
        if ((!triplet) && beat) triplet = beat->triplet;
        else triplet = 0;
        if (triplet) note->notate |= N_TRIPLET;
        note->time = measure->time + (end * edit->notatequant);
        notesetresolution(edit,note);
        newlength = notationtoindexln(edit,original)-(end-start);
        note->duration = original->duration - note->time +
            original->time;
        if (!(original->notate & N_NOTEVAL))
        {
            newlength = newdurationtonotation(edit, note->duration);
            if (newlength & N_TRIPLET)
                newlength = findtripletnotation(edit, note->duration);
            note->notate |= newlength & (N_TRIPLET|N_DOTTED);
            newlength = newlength & N_NOTEVAL;
            if (newlength > (edit->notateres & 3) + 3)
                newlength = (edit->notateres & 3) + 3;
            note->notate |= newlength;
        }
        else
        {
            setnotationfromindexln(edit,note,newlength);
            note->duration = typetolength(edit,note->notate);
        }
        note->status = MIDI_NOTEOFF;
        note->velocity = NE_TIE;
        note->value = value;
        if (end > measure->size) end = measure->size;
        note->next = measure->array[end];
        note->notate |= N_RES;
        if (getstem(original->notate)) setstem(note, STEM_UP);
        note->notelength = note->duration;
        note->length = notationtoindexln(edit,note);
        if (!note->length) note->length = 1;
        note->mark = original->mark;
        note->mark &= ~NM_SIGN;
        measure->array[end] = note;
        if (flag)
        {
            note->notate |= N_TNOTE;
        }
        setstaff(edit,note);
    }
}

void tienotes(struct Edit *edit,
    struct NotateEvent *first, struct NotateEvent *second)
/* turn second into a MIDI_NOTEOFF tie, and the first into a note
 * equaling the length of the first and the second.  Also, quantize
 * the two notes to the correct notated lengths.
 */
{
    second->status = MIDI_NOTEOFF;
    second->velocity = NE_TIE;
    second->mark &= ~NM_DRAWN;
    if (!(first->notate & N_NOTE)) changeduration(edit,first);
    if ((quantizenotetime(edit,first) + typetolength(edit, first->notate))
         != quantizenotetime(edit,second))
    {
        /* if the first note's length doesn't make it to the
         * beginning of the second note, free the second note
         * and just notate the new, longer, single note
         */
        first->duration = ((second->time + second->duration) - first->time);
        first->notelength = first->duration;
        second->velocity = NE_DONTSHOW;
        changeduration(edit,first);
        return;
    }
    first->notate |= N_TNOTE;
    first->duration = ((second->time + second->duration) - first->time);
    first->mark &= ~NM_DRAWN;
}

static void removerests(struct Edit *edit,long start,long end)

{
    struct NotateEvent *note = (struct NotateEvent *) edit->clip.events.first;
    struct NotateEvent *next;
    struct NotateEvent *keep = 0;
    for (;note;) {
        next = note->next;
        if ((note->time >= start) && (note->time < end)) {
            if ((note->status == MIDI_NOTEOFF) &&
                ((note->velocity == NE_REST) || (note->velocity == NE_DONTSHOW))){
                freeevent(note);
                note = next;
                continue;
            }
        }
        note->next = keep;
        keep = note;
        note = next;
    }
    edit->clip.events.first = (struct Event *) sorteventlist((struct Event *)keep);
}

static void stripties(struct Edit *edit,long start,long end)

{
    struct NotateEvent *note = (struct NotateEvent *) edit->clip.events.first;
    struct NotateEvent *next;
    struct NotateEvent *keep = 0;
    for (;note;) {
        next = note->next;
        if ((note->time >= start) && (note->time < end)) {
            if ((note->status == MIDI_NOTEOFF) && (note->velocity == NE_TIE)){
                freeevent(note);
                note = next;
                continue;
            }
            else if (isanote(note) && (note->notate & N_TNOTE))
            {
                changeduration(edit,note);
            }
        }
        note->next = keep;
        keep = note;
        note = next;
    }
    edit->clip.events.first = (struct Event *) sorteventlist((struct Event *)keep);
}

static void removethrees(struct Edit *edit,long start,long end)

{
    struct NotateEvent *note = (struct NotateEvent *) edit->clip.events.first;
    struct NotateEvent *next;
    struct NotateEvent *keep = 0;
    for (;note;) {
        next = note->next;
        if ((note->time >= start) && (note->time < end)) {
            if ((note->status == MIDI_NOTEOFF) && (note->velocity == NE_THREE)){
                freeevent(note);
                note = next;
                continue;
            }
        }
        note->next = keep;
        keep = note;
        note = next;
    }
    edit->clip.events.first = (struct Event *) sorteventlist((struct Event *)keep);
}

static void highandlow(struct Edit *edit,
        struct NotateEvent *list,short *highest,
        short *lowest)

{
    short value;
    for (;list;list = list->next) {
        if (isanote(list))
        {
            if (list->value < *lowest) *lowest = list->value;
            if (list->value > *highest) *highest = list->value;
        }
        if (isarest(list))
        {
            if (list->value >= edit->transcenter)
                value = list->value;
            else value = list->value;
            if (value < *lowest) *lowest = value;
            if (value > *highest) *highest = value;
        }
    }
}

static void stemhighandlow(struct Edit *edit,
        struct NotateEvent *list,short *highest,
        short *lowest, short stem)

{
    short value;
    for (;list;list = list->next) {
        if ((isanote(list) && (getstem(list->notate) == stem)))
        {
            if (list->value < *lowest) *lowest = list->value;
            if (list->value > *highest) *highest = list->value;
        }
        if (isarest(list))
        {
            if (list->value >= edit->transcenter)
                value = list->value;
            else value = list->value;
            if (value < *lowest) *lowest = value;
            if (value > *highest) *highest = value;
        }
    }
}

static void cleanupbeam(struct Edit *edit,struct NMeasure *measure,
        short start,short beamend,short stem)

{
    unsigned long time;
    short index;
    char donotslant;
    short highest = 0;
    short lowest = 300;
    short firsthigh, lasthigh, firstlow, lastlow;
    short testhigh,testlow;
    short beam, firstbeam, lastbeam, notelength;
    struct NotateEvent *note, *temp;
    short begin,end, diff;
    end = beamend;
    begin = -1;
    firsthigh = 0; lasthigh = 0;
    firstlow = 300; lastlow = 300;
    for (index = start;index <= beamend;index++)
    {
        if (existsnote(measure->array[index]))
            end = index;
    }
    for (index = start;index <= end;index++) {
        note = measure->array[index];
        if (note)
        {
            testhigh = 0; testlow = 300;
            stemhighandlow(edit,note,&testhigh,&testlow,stem);
            if (testhigh)
            {
                if (begin < 0)
                {
                    begin = index;
                    firsthigh = testhigh;
                    firstlow = testlow;
                    stemhighandlow(edit,note,&firsthigh,&firstlow,stem);
                }
                lasthigh = testhigh;
                lastlow = testlow;
                if (highest < testhigh) highest = testhigh;
                if (lowest > testlow) lowest = testlow;
            }
        }
    }
    time = measure->time + start*edit->notatequant;
    testhigh = highest;
    testlow = lowest;
    highest = displaytwelvetoscale(&edit->clip,time,highest,0);
    lowest = displaytwelvetoscale(&edit->clip,time,lowest,0);
    if (begin == end) {
        for (note = measure->array[start];note;note = note->next) {
            if (!isanote(note)) continue;
            if ((getstem(note->notate)) != stem) continue;
            CLEARBEAMBITS(note->mark);
            if ((note->value == testhigh) || (note->value == testlow))
            {
                note->mark |= INTTOBEAM(highest-lowest);
            }
        }
        return;
    }
    firsthigh = displaytwelvetoscale(&edit->clip,time,firsthigh,0);
    firstlow = displaytwelvetoscale(&edit->clip,time,firstlow,0);
    lasthigh = displaytwelvetoscale(&edit->clip,time,lasthigh,0);
    lastlow = displaytwelvetoscale(&edit->clip,time,lastlow,0);
    firstbeam = lastbeam = beam = findbeam(edit,highest,lowest,
        time,stem);
    donotslant = 0;
    for (note = measure->array[start];note;note = note->next)
    {
        for (temp = measure->array[end];temp;temp = temp->next)
        {
            if (note->value == temp->value)
            {
                donotslant = 1;
                break;
            }
        }
    }
    if (!donotslant)
    {
        if (stem)
        {
            diff = abs(firsthigh - lasthigh);
            if (diff > 4) diff = 0;
            if ((firsthigh > lasthigh))
            {
                lastbeam -= diff;
            }
            else if ((lasthigh > firsthigh))
            {
                firstbeam -= diff;
            }
        }
        else
        {
            diff = abs(firstlow - lastlow);
            if (diff > 4) diff = 0;
            if ((firstlow < lastlow))
            {
                lastbeam += diff;
            }
            else if ((lastlow < firstlow))
            {
                firstbeam += diff;
            }
        }
    }
    /* limit beam height */
    if (firstbeam > 30) firstbeam = 30;
    if (lastbeam > 30) lastbeam = 30;
    if (firstbeam < 0) firstbeam = 0;
    if (lastbeam < 0) lastbeam = 0;

    /* here is where LEFTBEAM and RIGHTBEAM are set according to the rhythm of
     * the phrase.
     */
    {
        /* first note always has RIGHTBEAM set and LEFTBEAM unset */
        for (note = measure->array[start];note;note = note->next)
        {
            if (!isanote(note)) continue;
            if ((getstem(note->notate)) != stem) continue;
            note->notate &= ~ N_LEFTBEAM;
            CLEARBEAMBITS(note->mark);
            note->notate |= (N_FLAG | N_BEAM | N_RIGHTBEAM);
            note->mark |= INTTOBEAM(firstbeam);
        }

        /* middle notes have various combos of RIGHTBEAM and LEFTBEAM */
        for (index = start + 1;index < end;index++)
        {
            for (note = measure->array[index];note;note = note->next)
            {
                if (!isanote(note)) continue;
                if ((getstem(note->notate)) != stem) continue;
                note->notate &= ~(N_LEFTBEAM | N_RIGHTBEAM);
                CLEARBEAMBITS(note->mark);
                note->notate |= (N_BEAM | N_FLAG);
                note->mark |= INTTOBEAM(beam);
                notelength = typetolength(edit,note->notate) /
                    edit->notatequant;
                /* LEFT is set if note to the left is there, and is same length as
                 * this note.
                 */
                if (notelength && (index-notelength >= start))
                {
                    if (temp = measure->array[index-notelength])
                    {
                        for (;temp;temp = temp->next)
                        {
                            if (isanote(temp) && ((getstem(temp->notate))
                                 == stem)) break;
                        }
                        if (temp)
                        {
                            if ((temp->notate & N_NOTEVAL) ==
                                (note->notate & N_NOTEVAL))
                            {
                                note->notate |= N_LEFTBEAM;
                            }
                        }
                    }
                }
                if (!(note->notate & N_LEFTBEAM)) note->notate |= N_RIGHTBEAM;
                else if (notelength && (index+notelength <= end))
                {
                    if (temp = measure->array[index+notelength])
                    {
                        for (;temp;temp = temp->next)
                        {
                            if (isanote(temp) && ((getstem(temp->notate))
                                == stem)) break;
                        }
                        if (temp)
                        {
                            if ((temp->notate & N_NOTEVAL) ==
                                (note->notate & N_NOTEVAL))
                            {
                                note->notate |= N_RIGHTBEAM;
                            }
                        }
                    }
                }
            }
        }
        /* only the last note doesn't have N_BEAM set. */
        /* all last notes have LEFTBEAM set and RIGHTBEAM unset */
        for (note = measure->array[end];note;note = note->next) {
            if (!isanote(note)) continue;
            if ((getstem(note->notate)) != stem) continue;
            note->notate &= ~(N_FLAG | N_RIGHTBEAM);
            CLEARBEAMBITS(note->mark);
            note->notate |= (N_LEFTBEAM | N_BEAM);
            note->mark |= INTTOBEAM(lastbeam);
        }
    }
}

static void beambeat(struct Edit *edit,struct NMeasure *measure,
        struct NBeat *beat)

{
    struct NotateEvent *note;
    short start;
    short count, stem;
    short startdata;
    short startbeam;
    short end;
for (stem = 0;stem <= N_STEMUP;stem += N_STEMUP)
{
    start = beat->index;
    end = start + beat->length;
    count = 0;
    startbeam = start;
    startdata = 0;
    for (;start < end;start++) {
        for (note = measure->array[start];note;note = note->next) {
            if ((getstem(note->notate)) != stem) continue;
            if (!isanote(note)) continue;
            note->notate &= ~N_BEAM;
            if (count) {
                if ((note->notate & N_NOTEVAL) < N_8) {
                    if (start > startbeam)
                        cleanupbeam(edit,measure,startbeam,start-1,stem);
                    startdata = note->notate & N_NOTEVAL;
                    if (startdata >= N_8) {
                        count = 1;
                        startbeam = start;
                    }
                    else count = 0;
                }
            }
            else {
                startdata = note->notate & N_NOTEVAL;
                if (startdata >= N_8) {
                    count = 1;
                    startbeam = start;
                }
                else count = 0;
            }
        }
    }
    if (count && (start > startbeam))
        cleanupbeam(edit,measure,startbeam,start-1,stem);
}
}

static void beammeasure(struct Edit *edit,struct NMeasure *measure)

{
    struct NBeat *beat = measure->beats;
    for (;beat;beat = beat->next) {
        beambeat(edit,measure,beat);
    }
}

static void insertbeamandstem(struct NotateEvent *list,short stem,long beam)

{
    struct NotateEvent *note;
    if (!stem)
    {
        for (;list;list = list->next)
        {
            if (isanote(list) && getstem(list->notate))
            {
                CLEARBEAMBITS(list->mark);
                list->mark |= beam;
                for (note = list->next;note;note = note->next)
                {
                    if (isanote(note) && getstem(note->notate))
                    {
                        CLEARBEAMBITS(note->mark);
                        note->mark |= INTTOBEAM(abs(list->value - note->value));
                    }
                }
                return;
            }
        }
    }
    else
    {
        note = 0;
        for (;list;list = list->next)
        {
            if (isanote(list) && !getstem(list->notate))
            {
                if (note)
                {
                    CLEARBEAMBITS(note->mark);
                    note->mark |= INTTOBEAM(abs(list->value-note->value));
                }
                note = list;
            }
        }
        if (note)
        {
            CLEARBEAMBITS(note->mark);
            note->mark |= beam;
        }
    }
}

static short tripletinterval(struct Edit *edit,
        struct NMeasure *measure,short start)

/* Given: First position of a beat boundary.
 * Limitation: half note triplets are the greatest supported.
 * Go through intervals of 2,4,8,16... where 2 is the finest
 * resolution.  E.g. In 1/4th note resolution, 2 represents quarter
 * note triplets, 4 represents half note triplets.
 * Returns: "interval" if 1. there is a note of proper length
 * in the 1/3 or 2/3
 * boundary, or 2. there is a triplet note in the 0/3 boundary
 */
{
    struct NotateEvent *note, *two;
    short index;
    short smallest, count;

    /* find smallest triplet note length */
    smallest = 6|N_TRIPLET;

    /* see if the first note is a triplet */
    if ((start <= measure->size) && (note = existstriplet(measure->array[start])))
    {
        {
            if ((note->notate & N_NOTE) == smallest) return(2);
            for (count = 1;count < 4;count++)
            {
                if (((note->notate & N_NOTE) == (smallest - count))
                    && ((start + (2<<count)) <= measure->size))
                {
                    if (two = existstriplet(measure->array[start + 4*count]))
                    {
                        if ((two->notate & N_NOTE) ==
                            (smallest - (count-1))) return(short)(1<<count);
                    }
                    return(short)(2<<count);
                }
            }
        }
    }

    for (index = start; index < measure->size; index += 2)
    {
        if (note = existstriplet(measure->array[index]))
        {
            if (index > start + 32) return(0);
            if (index == start + 2) return(2);
            if (index == start + 4)
            {
                if ((note->notate & N_NOTEVAL) == N_8) return(4);
                else if ((note->notate & N_NOTEVAL) == N_16)
                {
                    return(4);
                }
                else return(2);
            }
            if (index == start + 6) return(0);
            if (index == start + 8)
            {
                if ((note->notate & N_NOTE) == (N_4+N_TRIPLET)) return(8);
                else if ((note->notate & N_NOTE) == (N_8|N_TRIPLET))
                {
                    return(8);
                }
                else if ((note->notate & N_NOTE) == (N_16|N_TRIPLET))
                    return(4);
            }
            if ((index == start + 10) || (index == start + 12) ||
                (index == start + 14)) return(0);
            if (index == start + 16)
            {
                if ((note->notate & N_NOTEVAL) == N_2) return(16);
                if ((note->notate & N_NOTE) == (N_4|N_TRIPLET))
                {
                    return(16);
                }
                else if ((note->notate & N_NOTE) == (N_8|N_TRIPLET)) return(8);
            }
            if (index == start + 32)
            {
                if ((note->notate & N_NOTE) == (N_2|N_TRIPLET))
                {
                    return(32);
                }
                else if ((note->notate & N_NOTE) == (N_4|N_TRIPLET)) return(16);
            }
        }
    }

    return(0);
}

static void setalltriplets(struct NotateEvent *note, short setflags,
    short unsetflags)
/* functions takes: note, flags to be set, flags to be unset */
{
    for (;note;note = note->next)
    {
        if (isatriplet(note))
        {
            note->notate |= setflags;
            note->notate &= ~unsetflags;
        }
    }
}

static void fixflags(struct Edit *edit, struct NotateEvent *note)

{
    struct NotateEvent *temp, *first = note;
    short origvalue, diff;
    if (note)
    {
        for (;note;note = note->next)
        {
            if (!isanote(note)) continue;
            if (getstem(note->notate))
            {
                /* get origvalue for last note in list */
                for (temp = note;temp;temp = temp->next)
                {
                    if (isanote(temp) && getstem(note->notate))
                    {
                        temp->notate |= N_FLAG;
                        origvalue = gett(edit,temp);
                    }
                }
                for (;note->next;note = note->next)
                {
                    if ((!isanote(note)) || !(getstem(note->notate))) continue;
                    note->notate &= ~N_FLAG;
                    diff = abs(origvalue - gett(edit,note))/3 + 1;
                    if (diff > 31) diff = 31;
                    CLEARBEAMBITS(note->mark);
                    note->mark |= INTTOBEAM(diff);
                }
                break;
            }
        }
        for (note = first;note;note = note->next)
        {
            if (!isanote(note)) continue;
            if (!(getstem(note->notate)))
            {
                note->notate |= N_FLAG;
                origvalue = gett(edit,note);
                for (note = note->next;note;note = note->next)
                {
                    if ((!isanote(note)) || (getstem(note->notate))) continue;
                    note->notate &= ~N_FLAG;
                    diff = abs(gett(edit,note) - origvalue)/3 + 1;
                    if (diff > 31) diff = 31;
                    CLEARBEAMBITS(note->mark);
                    note->mark |= INTTOBEAM(diff);
                }
                break;
            }
        }
    }
}

static void insertthrees(struct Edit *edit,struct NMeasure *measure)

{
    struct NotateEvent *note, *new, *middle, *last;
    struct NBeat *beat;
    short index;
    short interval = 0;
    short highest, lowest;
    short stem;
    long beam;
    for (index = 0;index < measure->size;)
    {
        interval = tripletinterval(edit,measure,index);
        if (interval) {
            beat = getbeat(measure, index);
            if ((index + interval*3) > (beat->index + beat->length))
                interval = interval / 2;
            highest = 0;
            lowest = 128;
            note = existstriplet(measure->array[index]);
            if ((index+interval) <= measure->size)
                middle = existstriplet(measure->array[index + interval]);
            if ((index+interval+interval) <= measure->size)
                last = existstriplet(measure->array[index + interval +
                interval]);
            if (!(note || middle || last))
            {
                index += (6 << (3-(edit->notateres & 3)));
                continue;
            }
            if (!note && middle && !last)
            {
                setalltriplets(middle, 0, N_BEAM|N_LEFTBEAM|N_RIGHTBEAM);
                fixflags(edit,middle);
            }
            else if (note && !middle && !last)
            {
                setalltriplets(note, 0, N_BEAM|N_LEFTBEAM|N_RIGHTBEAM);
                fixflags(edit,note);
            }
            if (note && middle && last)
                setalltriplets(middle, N_LEFTBEAM, 0);
            highandlow(edit,note,&highest,&lowest);
            highandlow(edit,middle,&highest,&lowest);
            highandlow(edit,last,&highest,&lowest);
            if (!middle)
            {
                if (middle = existsrest(measure->array[index+interval]))
                {
                    highandlow(edit,middle,&highest,&lowest);
                    middle = 0;
                }
            }
            if (!note)
            {
                note = middle;
                middle = 0;
            }
            if (!note)
            {
                note = last;
                last = 0;
            }
            if (!note)
            {
                index += (6 << (3-(edit->notateres & 3)));
                continue;
            }
            stem = getstem(note->notate);
            beam = findbeam(
                edit,displaytwelvetoscale(&edit->clip,note->time,highest,0),
                displaytwelvetoscale(&edit->clip,note->time,lowest,0),
                note->time,stem);
            beam = INTTOBEAM(beam);
            insertbeamandstem(note,stem,beam);
            insertbeamandstem(middle,stem,beam);
            insertbeamandstem(last,stem,beam);
            new = (struct NotateEvent *) allocevent();
            if (new) {
                new->status = MIDI_NOTEOFF;
                new->time = (index * edit->notatequant) + measure->time;
                new->duration = interval * edit->notatequant;
                new->notate = note->notate;
                new->mark = note->mark;
                if (last && (BEAMTOINT(last->mark) > BEAMTOINT(new->mark)))
                    new->mark = last->mark;
                if (middle && (BEAMTOINT(middle->mark)>BEAMTOINT(new->mark)))
                    new->mark = middle->mark;
                /* make sure that beam doesn't make it be on top
                 * of a rest or something
                 */
                beam = BEAMTOINT(beam);
                if ((beam > 15) && (beam < 19))
                {
                    if (getstem(new->notate)) beam = 19;
                    else beam = 15;
                }
                beam = INTTOBEAM(beam);
                CLEARBEAMBITS(new->mark);
                new->mark |= beam;
                new->value = (highest + lowest) >> 1;
                new->velocity = NE_THREE;
                new->next = measure->array[index];
                measure->array[index] = new;
                setstaff(edit,new);
            }
            index += 3*interval;
            continue;
        }
        index += (6 << (3-(edit->notateres & 3)));
    }
}

static void insertrest(struct Edit *edit,struct NMeasure *measure,
        short index,short value,short rest)

{
    struct NBeat *beat = getbeat(measure,index);
    struct NotateEvent *note;
    short length;
    short noteres = (edit->notateres & 7);
    while (rest > 0) {
        if (noteres >= 3)   /* notate res. is 1/32 or higher */
        {
            if ((rest/beat->grain == 7) || (rest/beat->grain == 5))
            {
                length = beat->grain;
            }
            else length = rest;
        }
        else length = rest;
        if (index > measure->size) index = measure->size;
        note = (struct NotateEvent *) allocevent();
        if (note) {
            note->status = MIDI_NOTEOFF;
            note->value = value;
            note->duration = length * edit->notatequant;
            note->velocity = NE_REST;
            note->time = measure->time + (index * edit->notatequant);
            {
                note->notate = durationtonotation(edit,length);
            }
            note->notate |= N_RES;
            if (beat->triplet) note->notate |= N_TRIPLET;
            note->length = notationtoindexln(edit,note);
            note->next = measure->array[index];
            measure->array[index] = note;

            setstaff(edit,note);
            switch (note->notate & N_NOTEVAL) {
                case N_1 :
                    note->value += 4;
                    break;
                case N_2 :
                case N_4 :
                    note->value += 2;
                    break;
                case N_8 :
                case N_16 :
                case N_32 :
                    note->value += 1;
                    break;
            }
        }
        index += length;
        rest -= length;
    }
}

static void insertrests(struct Edit *edit,struct NMeasure *measure)

{
    short start;
    struct NotateEvent *note, *thenote;
    struct NBeat *beat;
    short notelen;
    short value;
    short bottom,top;
    short index;
    bottom = edit->bottomrange;
    top = edit->toprange;
    if (edit->notatebits & NB_THINKTREBLE) value =  edit->transcenter + 10;
    else if (edit->notatebits & NB_THINKBASS) value = edit->transcenter - 10;
    else if (edit->centerrange > edit->transcenter)
      value = edit->transcenter + 10;
    else value = edit->transcenter - 10;
    if ((value > 120) || (value < 10)) return;
    start = 0;
    for (beat = measure->beats;beat;beat = beat->next) {
        if (start < beat->index) start = beat->index;
        for (index = beat->index;index < beat->index + beat->length;index++) {
            /* find greatest note value */
            notelen = 0;
            thenote = 0;
            for (note = measure->array[index];note;note = note->next) {
                if (isanote(note) || isarest(note))
                {
                    if (notationtoindexln(edit,note) > notelen)
                    {
                        notelen = note->length;
                        thenote = note;
                    }
                }
            }
            if (thenote)
            {
                notelen = thenote->notate & N_NOTE;
                if (thenote->length > measure->size) notelen = N_1;
                if (!notelen) notelen = N_1;
            }
            /* make sure notelength is within bounds of notate resolution */
            if (notelen)
            {
                notelen = typetolength(edit, notelen |
                    (thenote->notate | N_RES)) / edit->notatequant;
                if (start < index)
                {
                    insertrest(edit,measure,start,
                        value, index - start);
                }
                start = index + notelen;
            }
        }
        if (start < (beat->index + beat->length))
        {
            insertrest(edit,measure,start,value,
                beat->index+beat->length-start);
        }
    }
}

static void extendnotes(struct Edit *edit, struct NMeasure *measure,
    short start)
/* lengthen notes to the next beat boundary or note, whichever comes first */
{
    short noteendindex, nextindex, nextbeat;
    struct NotateEvent *note;
    struct NBeat *beat;
    for (note = measure->array[start];note;note = note->next)
    {
        noteendindex = notationtoindexln(edit,note) + start;
        if (beat = getbeat(measure,noteendindex))
        {
            nextbeat = beat->index;
            while (nextbeat < noteendindex)
            {
            /* if it's a real note, wait for it to be split up */
                if (isarealnote(note) &&
                    ((note->notate & N_NOTEVAL) <= N_4)) return;
                else
                    nextbeat += beat->length;
            }
            for (nextindex = start + 1;nextindex < measure->size;nextindex++)
                if (existsrealnote(measure->array[nextindex])) break;
            if (nextindex < nextbeat) nextbeat = nextindex;
            if (noteendindex < nextbeat)
            {
                nextbeat -= start;
                setnotationfromindexln(edit,note,nextbeat);
            }
        }
    }
}

static void removeoverlap(struct Edit *edit, struct NMeasure *measure,
    short start)
/* if a note extends past another note, instead of creating a tie, shorten
    the note.
*/
{
    short noteendindex, nextnoteindex;
    struct NotateEvent *note;
    for (note = measure->array[start];note;note = note->next)
    {
        noteendindex = notationtoindexln(edit,note) + start;
        for (nextnoteindex = start+1;nextnoteindex < measure->size;
            nextnoteindex++)
            if (existsrealnote(measure->array[nextnoteindex]))
            {
                if (nextnoteindex < noteendindex)
                {
                    nextnoteindex -= start;
                    setnotationfromindexln(edit,note,nextnoteindex);
                }
                break;
            }
    }
}


static void shortenchord(struct NotateEvent *note)
/* make the lengths of all notes the shortest note in the chord */
{
    short notelength = 0;
    struct NotateEvent *first = note;
    short stem;
for (stem = 0; stem <= N_STEMUP; stem += N_STEMUP)
{
    for (note = first;note;note = note->next)
    {
        if ((getstem(note->notate)) != stem) continue;
        if ((note->notate & N_NOTEVAL) > notelength) /* notes with shorter lengths have
                                                   * larger notelength */
            notelength = note->notate & N_NOTEVAL;
    }
    for (note = first;note;note = note->next)
    {
        if ((getstem(note->notate)) != stem) continue;
        note->notate &= ~N_NOTEVAL;
        note->notate |= notelength;
    }
}
}

static void lengthenchord(struct NotateEvent *note)
/* make the lengths of all notes the longest note in the chord */
{
    struct NotateEvent *first = note;
    short notelength = 100;
    short stem;
for (stem = 0; stem <= N_STEMUP; stem += N_STEMUP)
{
    for (note = first;note;note = note->next)
    {
        if ((getstem(note->notate)) != stem) continue;
        if ((note->notate & N_NOTEVAL) &&
            ((note->notate & N_NOTEVAL) < notelength))
            notelength = note->notate & N_NOTEVAL;
    }
    for (note = first;note;note = note->next)
    {
        if ((getstem(note->notate)) != stem) continue;
        note->notate &= ~N_NOTEVAL;
        note->notate |= notelength;
    }
}
}

static void splitnotes(struct Edit *edit, struct NMeasure *measure,
    short start, short length, short stem)
{
    struct NotateEvent *note;
    char x;

    for (note = measure->array[start];note;note = note->next)
    {
        if (!isanote(note)) continue;
        if ((getstem(note->notate)) != stem) continue;
        if (notationtoindexln(edit,note) > length)
        {
            if (isatie(note) && !isarealnote(note)) x = 1;
            else x = 0;
            if ((start + length) == measure->size) x = 0;
            inserttie(note,edit,measure,start,start+length,
                    typetolength(edit,length|N_RES),
                    note->value,x,(note->notate) & N_TRIPLET);
            note->notate |= N_TNOTE;
            setnotationfromindexln(edit,note,length);
            note->notelength = typetolength(edit, note->notate|N_RES);
            note->length = note->notelength / edit->notatequant;
        }
    }
}

static void autotiechord(struct Edit *edit, struct NMeasure *measure, short start)

{
    struct NotateEvent *note = measure->array[start];
    struct NotateEvent *first = note;
    short length;
    short noteval, count;
    short stem;
    /* find shortest note length */
    for (stem = 0;stem <= N_STEMUP; stem += N_STEMUP)
    {
        count = 0;
        length = 0;
        for (note = first;note;note = note->next)
        {
            if (!isanote(note)) continue;
            if ((getstem(note->notate)) != stem) continue;
            noteval = notationtoindexln(edit,note);
            if ((noteval < length) || (!count))
            {
                length = noteval;
                count++;
            }
            else if (noteval > length)
            {
                count++;
            }
        }
        if ((count > 1) && (length < 24))
        {
            splitnotes(edit,measure,start,length,stem);
        }
    }
}

static void splitupnotes(struct Edit *edit, struct NMeasure *measure, short index)
/* if a note extends past another note, or past the measure boundary, it needs
 * to be split up
 */
{
    struct NotateEvent *note, *temp;
    struct NBeat *beat;
    short tempindex,length,newlength;
    short stem;
    char flag;
    if (index > measure->size) return;
    for (stem = 0;stem <= N_STEMUP;stem += N_STEMUP)
    {
        for (note = measure->array[index];note;note = note->next)
        {
            flag = 0;
            if (!isanote(note)) continue;
            if ((getstem(note->notate)) != stem) continue;
            /* see if note illegally crosses beat boundary.  This occurs
             * when a note such as a quarter note does not begin on
             * a beat boundary, and passes another.
             */
            length = notationtoindexln(edit,note);
            beat = getbeat(measure, index);
            for (tempindex = index+1;(tempindex < (index+length))
                && (tempindex < measure->size);tempindex++)
            {
                if (temp = existsrealnote(measure->array[tempindex]))
                {
                    flag = 1;
                    break;
                }
            }
            if (beat && (flag || (index != beat->index)))
            {
                for (tempindex=index+1;(tempindex<(index+length))
                    && (tempindex<measure->size);tempindex++)
                    {
                    if (tempindex > (beat->length + beat->index))
                    {
                        newlength = beat->length + beat->index - index;
                        splitnotes(edit,measure,index,newlength,stem);
                        break;
                    }
                }
            }
            for (tempindex = index+1;(tempindex < (index+length))
                && (tempindex < measure->size);tempindex++)
            {
                if (temp = existsrealnote(measure->array[tempindex]))
                {
                    newlength = tempindex - index;
                    splitnotes(edit,measure,index,newlength,stem);
                    break;
                }
            }
            /* check to make sure note doesn't extend past measure
             * boundary.
             */
            /* this value could change from before! */

            length = notationtoindexln(edit,note);
            if ((index + length) > measure->size)
            {
                newlength = measure->size - index;
                splitnotes(edit,measure,index,newlength,stem);
            }
        }
    }
}

static void halfnote(struct NotateEvent *note, struct Edit *edit,
    struct NMeasure *measure,
    short start, short end)
/* halves the note, creating a tie if the beginning of the tie is before the
end.
*/
{
    struct NotateEvent *tie;
    short length,newlength;
    newlength = length = notationtoindexln(edit,note);
    switch ((end-start)/3)
    {
        case 5 :
        case 7 :
            length = 3;
            break;
        default :
            length /= 2;
    }
    setnotationfromindexln(edit,note,length);
    start += length;
    newlength = end-start;
    for (tie=measure->array[start];tie;tie=tie->next)
        if (isatie(tie) && (tie->value == note->value)) return;
    if (start < end)
    {
        tie = (struct NotateEvent *)allocevent();
        tie->time = measure->time + (start * edit->notatequant);
        tie->value = note->value;
        tie->notate = note->notate;
        tie->mark = note->mark;
        setnotationfromindexln(edit,tie,newlength);
        tie->duration = typetolength(edit, tie->notate);
        tie->status = MIDI_NOTEOFF;
        tie->velocity = NE_TIE;
        tie->next = measure->array[start];
        tie->notate |= N_RES;
        tie->notelength = tie->duration;
        tie->length = tie->notelength / edit->notatequant;
        tie->mark &= ~NM_SIGN;
        tie->notate |= N_TNOTE;
        measure->array[start] = tie;
        setstaff(edit,tie);
    }
}

static void cleanupties(struct Edit *edit, struct NMeasure *measure,
    short start)
/* sometimes, ties are created that extend past their own tied note. This
routine fixes this problem by searching for such a note, and subdividing it
in half until it fits correctly.
*/
{
    struct NotateEvent *note, *test;
    short index, length;
    char flag;
    for (note=measure->array[start];note;note=note->next)
    {
        flag = 0;
        if (isatie(note) && isarealnote(note))
        {
            length = notationtoindexln(edit,note);
            for (index=start+2;((index<start+length)&&(index<measure->size))
                ;index++)
            {
                for (test=measure->array[index];test;test=test->next)
                {
                    if (isatie(note) && (test->value == note->value))
                    {
                        halfnote(note,edit,measure,start,index);
                        flag = 1;
                        break;
                    }
                }
                if (flag) break;
            }
        }
    }
}

static short stemdirection(struct Edit *edit,short value)

{
    short stemup = STEM_DOWN;
    if (edit->centerrange > edit->transcenter) /* treble cleff */
    {
      if (value < (edit->centerrange+1)) stemup = STEM_UP;
    }
    else /* bass clef */
    {
      if (value < (edit->centerrange-2)) stemup = STEM_UP;
    }
    return(stemup);
}

static short findbeatstem(struct Edit *edit, struct NMeasure
    *measure, short start, short end)
{
    struct NotateEvent *note;
    short stem;
    char treble;
    treble = (edit->centerrange > edit->transcenter);
    if (treble) stem = STEM_DOWN;
    else stem = STEM_UP;
    for (;start<end;start++)
    {
        if (note = measure->array[start])
        {
          stem = stemdirection(edit,note->value);
          if (treble)
          {
           if (stem == STEM_UP) return(stem);
          }
          else
          {
            if (stem == STEM_DOWN) return(stem);
          }
        }
    }
    return(stem);
}

void removeduplicates(struct Edit *edit,struct NMeasure *measure, short index)
/* after the sortchord call, the notes are in order according to
   note->value.  This routine goes through and puts duplicate valued
   notes at the end of the measure, and sets them up to be not printed,
   by setting note->notate |= N_DONTPLOT.
   Also, ties are given precedence over real notes.
*/
{
    struct NotateEvent *note, *temp;
    short end = measure->size;
    for (note = measure->array[index];note;note = note->next)
    {
        for (;note->next &&
            (displaytwelvetoscale(&edit->clip,note->next->time,note->next->value,0) ==
             displaytwelvetoscale(&edit->clip,note->time,note->value,0));)
        {
            temp = note->next->next;
            note->next->next = measure->array[end];
            note->next->notate |= N_DONTPLOT;
            measure->array[end] = note->next;
            note->next = temp;
        }
    }
}

char adjacentbitset(struct NotateEvent *note)
{
    if (note->notate & N_ADJACENT) return(1);
    else return(0);
}

static transcribing = 0; /* set in guessdurations */

static void newnotatemeasure(struct Edit *edit,struct NMeasure *
        measure)

{
    short beatend = 0;
    short start,value,prevnotevalue,notetype,stem;
    struct NBeat *beat;
    struct NotateEvent *note, *temp;
    char flag;

    beat = measure->beats;
    start = 0;
    for (;beat;beat = beat->next) {
        beatend = beat->index + beat->length;
        flag = 0;
        /* sort chords */
        for (start = beat->index;start < beatend;start++)
        {
            if (measure->array[start])
            {
                measure->array[start] = sortchord(measure->array[start]);
                removeduplicates(edit,measure,start);
                flag = 1;
            }
        }
        /* used to save computation time */
        if (!flag) continue;
        /* find type of note which has stems up if user wants to have
         * opposed stems.  (Find lowest note in beat)
         */
        prevnotevalue = 128;
        for (start = beat->index;start < beatend;start++)
        {
            for (note = measure->array[start];note;note = note->next)
            {
                if (isanote(note) && (note->value < prevnotevalue))
                {
                    notetype = note->notate & N_NOTE;
                    prevnotevalue = note->value;
                    break;
                }
            }
        }
        /* go through and set stems up or down, unless note has been
         * touched.
         */
        start = beat->index;
        stem = -1;
        for (;start < beatend; start++)
        {
            note = measure->array[start];
        if (note)
        {
            for (;note;note = note->next)
            {
                if (!isanote(note)) continue;
                CLEARBEAMBITS(note->mark);
                if (stem < 0)
                    stem = findbeatstem(edit,measure,beat->index,beatend);
                {
                    /* oppose stems with different rhythms */
                    if (edit->ntbits & NT_OPPOSESTEM)
                    {
                        if ((note->notate & N_NOTE) ==
                            notetype)
                        {
                            setstem(note, STEM_DOWN);
                        }
                        else
                        {
                            setstem(note, STEM_UP);
                        }
                    }
                    /* user wants all stems up */
                    else if (edit->ntbits & NT_STEMUP)
                    {
                        setstem(note, STEM_UP);
                    }
                    /* user wants all stems down */
                    else if (edit->ntbits & NT_STEMDOWN)
                    {
                        setstem(note, STEM_DOWN);
                    }
                    /* autostem */
                    else
                    {
                        setstem(note, stem);
                    }
                }
            }
            if (edit->ntbits & NT_SHORTEN)
                shortenchord(measure->array[start]);
            else if (edit->ntbits & NT_EXTEND)
                lengthenchord(measure->array[start]);
            if ((edit->trbits & TR_EXTEND) && transcribing)
                extendnotes(edit,measure,start);
            if (!(edit->trbits & TR_OVERLAP) && transcribing)
                removeoverlap(edit,measure,start);
            if (edit->ntbits & NT_AUTOTIE)
            {
                autotiechord(edit,measure,start);
                splitupnotes(edit,measure,start);
            }
            cleanupties(edit,measure,start);
            fixflags(edit,measure->array[start]);
        }
        }
    }
    /* fix adjacent bit */
    for (start = 0;start < measure->size;start++)
    {
        if (measure->array[start])
        {
            prevnotevalue = 128;
            measure->array[start] = revsortchord(measure->array[start]);
            temp = note = measure->array[start];
            for (;note;note = note->next)
            {
                if (!isanote(note) || getstem(note->notate)) continue;
                note->notate &= ~N_ADJACENT;
                /* adjacent notes can't plot flags, move flag to next note*/
                if ((note->notate & N_FLAG) && (note->next))
                    note->next->notate |= N_FLAG;
                value = twelvetoscale(&edit->clip,note->time,note->value,0);
                if (((prevnotevalue - value) < 2) &&
                    (value != prevnotevalue))
                {
                    if (!(temp->notate & N_ADJACENT))
                    {
                        note->notate |= N_ADJACENT;
                        if (note->notate & N_FLAG)
                        {
                            note->notate &= ~N_FLAG;
                            temp->notate |= N_FLAG;
                        }
                    }
                }
                temp = note;
                prevnotevalue = value;
            }
            prevnotevalue = 0;
            measure->array[start] = sortchord(measure->array[start]);
            temp = note = measure->array[start];
            for (;note;note = note->next)
            {
                if (!isanote(note) || !getstem(note->notate)) continue;
                note->notate &= ~N_ADJACENT;
                value = twelvetoscale(&edit->clip,note->time,note->value,0);
                if (((value - prevnotevalue) < 2) &&
                    (value != prevnotevalue))
                {
                    if (!(temp->notate & N_ADJACENT))
                    {
                        note->notate |= N_ADJACENT;
                        if (note->notate & N_FLAG)
                        {
                            note->notate &= ~N_FLAG;
                            temp->notate |= N_FLAG;
                        }
                    }
                }
                temp = note;
                prevnotevalue = value;
            }
        }
    }
}

static short findsmallesttriplet(struct Edit *edit,
        struct NMeasure *measure,short start,short length)

/*      Scan through the section, looking for the smallest
        triplet subdivision that satisfies the following:
        The start time of at least one note can not be divided by
        6 or double the division, or
        The duration of at least one note can not be divided by 6
        or double the division, or
        The end time of a note that ends in this section
        can not be divided by 6 or double the division.
*/

{
    short smallest, realsmall = 100;
    short index;
    short end = start + length;
    struct NotateEvent *note = 0;
    for (index = start;index < end;index += 2) {
        for (note = measure->array[index];note;note = note->next) {
            if (note->notate & N_TRIPLET) {
                smallest =
                typetolength(edit,note->notate|N_RES)/edit->notatequant;
                if (smallest < 2) smallest = 2;
                if (smallest < realsmall) realsmall = smallest;
            }
        }
    }
    if (realsmall == 100) realsmall = 1;
    return(realsmall);
}

static short emptybeat(struct Edit *edit, struct NMeasure *measure,
        short start,
        short end)

{
    struct NotateEvent *note;
    short index;
    short endtime;
    for (index = start + 1;index < end;index++) {
        for (note = measure->array[index]; note; note = note->next)
        {
            if (isanote(note)) return(0);
        }
    }
    for (note = measure->array[start];note;note = note->next) {
        if (!isanote(note)) continue;
        endtime = typetolength(edit, note->notate) / edit->notatequant;
        if (endtime != (end - start)) return(0);
    }
    for (index = 0;index < start;index++) {
        for (note = measure->array[index];note;note = note->next) {
            if (!isanote(note)) continue;
            endtime = index + (typetolength(edit,note->notate)
                / edit->notatequant);
            if ((endtime > start) && (endtime < end)) return(0);
        }
    }
    index = 0;
    end -= start;
    end /= 3;
    for (;end;end = end >> 1) index += (end & 1);
    return (short)(index == 1);
}

static short newgrainsize(struct NMeasure *measure,short start,
        short end)

{
    struct NotateEvent *note;
    short index, endpoint;
    short grain = measure->beatlen;
    for (;grain > 3;grain = grain >> 1) {
        for (index = 0;index < end;index += 3) {
            if (note = measure->array[index]) {
                if (index > start) {
                    if ((index - start) % grain) break;
                }
                for (;note;note = note->next) {
                    endpoint = note->length + index;
                    if (endpoint > start) {
                        if ((endpoint - start) % grain) break;
                    }
                    if (index >= start) {
                        if (note->length % grain) break;
                    }
                }
                if (note) break;
            }
        }
        if (index >= end) break;
    }
    return(grain);
}

static void makealltriplets(struct Edit *edit, struct NMeasure *measure,short start,
        short end,short smallest)

{
    short index;
    struct NotateEvent *note, *hold, *next;
    short place;
    long measurestart = measure->time / edit->notatequant;
    hold = NULL;
    for (index = start;index <end;index++) {
        if (note = measure->array[index])
        {
            for (;note;)
            {
                next = note->next;
                if (isanote(note) && transcribing)
                {
                    note->notate &= ~N_NOTE;
                    note->notate |= findtripletnotation(edit,
                        note->duration);
                    note->notelength = typetolength(edit,note->notate);
                    note->length = notationtoindexln(edit,note);
                    note->mark &= ~NM_NOTATED;
                }
                place = resolvenotetime(edit,note) - measurestart;
                if ((place >= 0) && (place <= measure->size)
                    && (place != index))
                {
                    note->next = measure->array[place];
                    measure->array[place] = note;
                }
                else
                {
                    note->next = hold;
                    hold = note;
                }
                note = next;
            }
            measure->array[index] = hold;
            hold = NULL;
        }
    }
}

static void dividebeat(struct Edit *edit,struct NMeasure *measure,
        short start,short end)

/*
Test to subdivide a beat.  If successful, call this routine on the
two parts.  The test is as follows:

If the beat is empty or all notes start at the
top of the beat, no more recursion.

If we are beat size or smaller and no triplets are found within,
no more recursion.

If subdividing splits the smallest triplet note, no more recursion.
*/

{
    short length = end - start;
    short smallest = 1;
    short empty = emptybeat(edit,measure,start,end);
    short norecur;
    short splitpoint;
    struct NBeat *beat;

    if (!empty)
    {
        smallest = findsmallesttriplet(edit,measure,
                                        start,end - start);
        norecur = ((length <= measure->beatlen) && (smallest == 1));
        if (!norecur) {
            if (length <= measure->beatlen) {
                                        /* Smaller than the beat. */
                splitpoint = length >> 1;
            }
            else {
                splitpoint = measure->beatlen;
                for (;splitpoint < length;splitpoint =
                                                splitpoint << 1);
                splitpoint = splitpoint >> 1;
            }
            if (!splitpoint) return;
            norecur = (splitpoint % smallest);
            if (!norecur) {
                dividebeat(edit,measure,start,start+splitpoint);
                dividebeat(edit,measure,start+splitpoint,end);
                return;
            }
        }
    }
    beat = (struct NBeat *) allocevent();
    if (beat) {
        beat->time = measure->time + start * edit->notatequant;
        beat->downbeat =
                ((length >= measure->beatlen) && !((start /
                                        measure->beatlen) & 1));
        beat->index = start;
        beat->length = length;
        if (smallest > 1) {
            beat->grain = smallest;
            beat->triplet = 1;
            if (transcribing)
                makealltriplets(edit,measure,start,end,smallest);
        }
        else if (empty) {
            beat->empty = !measure->array[start];
            beat->grain = length;
        }
        else beat->grain = newgrainsize(measure,start,end);
        measure->beats = (struct NBeat *) List_Cat((struct ListItem *)measure->beats,(struct ListItem *)beat);
    }
}

static void putnoteinmeasure(struct Edit *edit, struct NotateEvent *note,
    struct NMeasure *measure, long time)

{
    if (time > measure->size) time = measure->size;
    note->next = measure->array[time];
    measure->array[time] = note;
    note->notate &= ~N_DONTPLOT;
   if (!(note->mark & NM_NOTATED) && transcribing)
   {
    if ((time % 3))
    {
        note->notate &= ~N_NOTE;
        note->notate |= findtripletnotation(edit,note->duration);
        if (note->notate & N_DOTTED)
        {
            note->notate &= ~N_DOTTED;
            if ((note->notate & N_NOTEVAL) > 1)
                note->notate--;
        }
    }
    if ((time % 2)) note->notate &= ~N_TRIPLET;
    if (note->duration > 768) note->notelength = note->duration;
    else note->notelength = typetolength(edit,note->notate);
    note->length = note->notelength / edit->notatequant;
    note->notate &= ~N_DONTPLOT;
    if (!note->length) note->length = 1;
    setstaff(edit,note);
    note->mark |= NM_NOTATED;
   }
}

static void grabmeasure(struct Edit *edit,struct NMeasure *measure,
        long start,long end)

{
    struct NotateEvent *note = (struct NotateEvent *)
                                        edit->clip.events.first;
    long time;
    short bottom = edit->bottomrange;
    short top = edit->toprange;
    struct NotateEvent *next;

    start /= edit->notatequant;
    end /= edit->notatequant;
    for (;note;) {
        next = note->next;
        time = resolvenotetime(edit,note);
        if (time >= start) break;
        note->next = (struct NotateEvent *) edit->fillsequence;
        edit->fillsequence = (struct NoteEvent *) note;
        note = next;
    }
    for (;note;) {
        next = note->next;
        time = resolvenotetime(edit,note);
        if (time > end) break;
        if (time < start)
        {
            note->next = (struct NotateEvent *) edit->fillsequence;
            edit->fillsequence = (struct NoteEvent *) note;
            note = next;
            continue;
        }
        /* make sure that the note is one which needs to be
                displayed */
        if ((note->status == MIDI_NOTEON) ||
                                 (note->status == MIDI_NOTEOFF)) {
            /* see if note is within the visible boundaries */
            if ((note->value < top) && (note->value >= bottom)) {
                time -= start;
                putnoteinmeasure(edit,note,measure,time);
            }
            else {
                note->next = measure->others;
                measure->others = note;
            }
        }
        else {
            note->next = (struct NotateEvent *) edit->fillsequence;
            edit->fillsequence = (struct NoteEvent *) note;
        }
        note = next;
    }
    edit->clip.events.first = (struct Event *) note;
}

static void grabothers(struct Edit *edit,struct NMeasure *measure)
/* others are events which are in the measure, but not on bass clef
*/

{
    struct NotateEvent *note = measure->others;
    long time;
    long start = measure->time / edit->notatequant;
    short bottom = edit->bottomrange;
    short top = edit->toprange;
    struct NotateEvent *next;
    for (;note;) {
        next = note->next;
        time = resolvenotetime(edit,note);
        if ((note->value < top) && (note->value >= bottom)) {
            time -= start;
            putnoteinmeasure(edit,note,measure,time);
        }
        else {
            /* don't plot these notes, out of bounds */
            note->notate |= N_DONTPLOT;
            note->mark |= NM_NOTATED;
            note->next = (struct NotateEvent *) edit->fillsequence;
            edit->fillsequence = (struct NoteEvent *) note;
        }
        note = next;
    }
    measure->others = 0;
}

static void putmeasure(struct Edit *edit,struct NMeasure *measure)

{
    struct NotateEvent *top = 0;
    short index;
    for (index = 0;index < measure->size;index++) {
        if (measure->array[index]) {
            top = (struct NotateEvent *) List_Cat((struct ListItem *)top,(struct ListItem *)measure->array[index]);
            measure->array[index] = 0;
        }
    }
    if (measure->array[measure->size]) {
        edit->clip.events.first = (struct Event *)
            List_Cat((struct ListItem *)measure->array[measure->size],(struct ListItem *)edit->clip.events.first);
        measure->array[measure->size] = 0;
    }
    edit->fillsequence = (struct NoteEvent *) List_Cat((struct ListItem *)top,(struct ListItem *)edit->fillsequence);
}

static void fixnoteoffsets(struct Edit *edit, struct NMeasure *measure)
{
    short t,index, notatequant = edit->notatequant;
    char offset;
    long quanttime, start = measure->time;
    struct NotateEvent *note;
    /* clear filteroffset */
    filteroffset(edit, -1, 0, 0);
    for (index = 0;index < measure->size;index++)
    {
        for (note = measure->array[index];note;note = note->next)
        {
            if (isanote(note))
            {
                quanttime = start + (index * notatequant);
                t = displaytwelvetoscale(&edit->clip,
                    quanttime,note->value -
                    edit->transcenter + 60,&offset);

                offset = filteroffset(edit, quanttime, t, offset);
                note->mark &= ~NM_SIGN;
                if (offset == 4) note->mark |= NM_SIGN;
                else if (offset > 0) note->mark |= NM_SIGN1;
                else if (offset < 0) note->mark |= NM_SIGN2;
            }
        }
    }
}

static void finishmeasure(struct Edit *edit,struct NMeasure *measure)
{
//short index;
//struct NotateEvent *note;
    dividebeat(edit,measure,0,measure->size);
    newnotatemeasure(edit,measure);
/*  for (index=0;index < measure->size;index+=2)
  {
   if (note=measure->array[index])
   {
     if (getstem(note->notate)) kprintf("U");
     else kprintf("d");
   }
   else kprintf(".");
  }
  kprintf("\n\r");
*/
    if ((edit->ntbits & NT_AUTOREST) && (edit->notatebits & (NB_THINKBASS |
        NB_THINKBOTH)))
    {
//        kprintf("from finishmeasure ");
        insertrests(edit,measure);
    }
    beammeasure(edit,measure);
    insertthrees(edit,measure);
    fixnoteoffsets(edit,measure);
    putmeasure(edit,measure);
}

#define NMEASURESIZE    (sizeof(struct NMeasure)<<2)

static struct NMeasure *
    preparenextmeasure1(struct Edit *edit,struct NMeasure *measure,
        long start)
/* computes resolution size from the length of the measure and the
quantization size, then calls putmeasure, grabothers, and dividebeat
 */

{
    long next = nextmeasure(&edit->clip,start,1);
    long length = next - start;         /* length of measure */
    long size = length / edit->notatequant;
    if (measure) {
        if ((measure->size != size) || !size) {
            freelist((struct Event *)measure->beats);
            FreeMem((char *)measure,(measure->size << 2) + NMEASURESIZE);
            measure = 0;
        }
    }
    if (!size) return(0);
    if (!measure) {
        measure = (struct NMeasure *) AllocMem((size << 2) + NMEASURESIZE,MEMF_PUBLIC);
    }
    if (!measure)
    {
        /*** should be a warning message here */
        return(0);
    }
    memset((char *)measure,0,(size << 2) + NMEASURESIZE);
    measure->size = size;
    measure->time = start;
    measure->endtime = next;
    measure->beatlen = beatlength(&edit->clip,start) / edit->notatequant;
    if (!measure->beatlen) measure->beatlen = size;
    measure->beatcount = measure->size / measure->beatlen;
    /* check for time sigs with half note receiving beat, or whole note */
    if (measure->beatlen == 48) /* half note */
    {
        measure->beatlen = measure->beatlen >> 1; /* divide beatlen by 2 */
        measure->beatcount = measure->beatcount << 1; /* mult. beatcount by 2 */
    }
    else if (measure->beatlen == 96) /* whole note */
    {
        measure->beatlen = measure->beatlen >> 2; /* divide beatlen by 4 */
        measure->beatcount = measure->beatcount << 2; /* mult. beatcount by 4 */
    }
    if ((measure->beatlen * measure->beatcount) != measure->size)
    {
        freelist((struct Event *)measure->beats);
        FreeMem((char *)measure,(measure->size << 2) + NMEASURESIZE);
        measure = 0;
        return(0);
    }
    grabmeasure(edit,measure,start,next);
    return(measure);
}

static struct NMeasure *
    preparenextmeasure2(struct Edit *edit,struct NMeasure *measure,
        long start)
/* computes resolution size from the length of the measure and the
quantization size, then calls putmeasure, grabothers, and dividebeat
 */

{
    if (measure->beats) freelist((struct Event *)measure->beats);
    measure->beats = 0;
    grabothers(edit,measure);
    return(measure);
}

void notation(struct Edit *edit,long start,long end)

{
    short bottom, top;
    long begin;
    short measurecount;
    struct NMeasure *measure;
    if (edit->notatebits & NB_TRANSPOSE) transkeyon(edit);
    edit->notatequant = 8;
    begin = start;
    measurecount = timetomeasure(&edit->clip,start);
    if (!edit->notatequant) edit->notatequant = 32;
    bottom = edit->transcenter - DISPLAYRANGE;
    if (bottom < 1) bottom = 1;
    top = edit->transcenter + DISPLAYRANGE;
    if (top > 127) top = 127;
    if (timetomeasure(&edit->clip,end - start) > 5) {
        notateopenwait();
    }
    edit->fillsequence = 0;
    measure = 0;
    for (;start < end;) {
        measurecount++;
        if (waitwindow) postmeasure(measurecount);
        if (edit->notatebits & NB_THINKBOTH) {
                        /* Both Cleff */
            edit->bottomrange = bottom;
            edit->toprange = edit->transcenter+edit->ledger_lines;
//            if (!(edit->notatebits & NB_PRINTTREBLE))
//              edit->toprange += 3;
//            else if (!(edit->notatebits & NB_PRINTBASS))
//              edit->toprange -= 3;
            edit->centerrange = edit->transcenter - 10;
        }
        else if (edit->notatebits & NB_THINKBASS) {
            edit->bottomrange = 1;
            edit->toprange = 127;
            edit->centerrange = edit->transcenter - 10;
        }
        else {
                        /* Just Treble */
            edit->bottomrange = 1;
            edit->toprange = 1;
            edit->centerrange = 1;
        }
        measure = preparenextmeasure1(edit,measure,start);
        if (!measure) break;
        finishmeasure(edit,measure);
        if (edit->notatebits & NB_THINKBOTH) {
                        /* Both Cleff */
            edit->bottomrange = edit->transcenter+edit->ledger_lines;
            edit->toprange = top;
//            if (!(edit->notatebits & NB_PRINTBASS))
//              edit->bottomrange -= 3;
//            else if (!(edit->notatebits & NB_PRINTTREBLE))
//              edit->bottomrange += 3;
            edit->centerrange = edit->transcenter + 11;
        }
        else if (edit->notatebits & NB_THINKBASS) {
                        /* Just Bass */
            edit->bottomrange = 127;
            edit->toprange = 127;
            edit->centerrange = 127;
        }
        else {
                        /* Just Treble */
            edit->bottomrange = 1;
            edit->toprange = 127;
            edit->centerrange = edit->transcenter + 11;
        }
        measure = preparenextmeasure2(edit,measure,start);
        if (!measure) break;
        finishmeasure(edit,measure);
        start += (measure->size * edit->notatequant);
    }
    if (measure) {
        freelist((struct Event *)measure->beats);
        FreeMem((char *)measure,(measure->size << 2) + NMEASURESIZE);
    }
    edit->clip.events.first = (struct Event *) List_Cat((struct ListItem *)edit->fillsequence,
        (struct ListItem *)edit->clip.events.first);
    edit->clip.events.first = (struct Event *) sorteventlist((struct Event *)edit->clip.events.first);
    if (waitwindow) notateclosewait();
    edit->clip.events.point = 0;
    edit->displaynote = (struct NoteEvent *) edit->clip.events.first;
    if (edit->notatebits & NB_TRANSPOSE) transkeyoff(edit);
}

void preparenotation(struct Edit *edit,long start,long end)

{
    short measurecount;
    measurecount = timetomeasure(&edit->clip,start);
    start = measuretotime(&edit->clip,measurecount);
    end = nextmeasure(&edit->clip,end,1);
    clearbadties(edit);
    removethrees(edit,start,end);
    if (edit->ntbits & NT_AUTOREST) removerests(edit,start,end);
    notation(edit,start,end);
}

void refreshnotation(struct Edit *edit)

{
    transcribing = 1;
    if (edit->refreshend >= edit->refreshstart)
    {
        if (edit->showbits & SB_NOTATION)
            preparenotation(edit,edit->refreshstart,edit->refreshend);
    }
    edit->refreshstart = 0x40000000;
    edit->refreshend = 0;
    transcribing = 0;
}

void guessdurations(struct Edit *edit, long start, long end)

{
    short length, noteval;
    short smallest = (edit->notateres & 3) + 3;
    struct NotateEvent *note;
    stripties(edit,start,end);
    removerests(edit, start, end);
    transcribing = 1;
    for (note = (struct NotateEvent *)edit->clip.events.first
        ;note;note = note->next)
    {
        if ((isanote(note)) && ((note->time >= start) && (note->time < end)))
        {
            note->notate = 0;
        notesetresolution(edit,note);
            length = newdurationtonotation(edit, note->duration);
            if (length & N_TRIPLET)
            length = findtripletnotation(edit, note->duration);
            noteval = length & N_NOTEVAL;
        if (noteval > smallest) noteval = smallest;
        note->notate |= length & (N_TRIPLET|N_DOTTED);
        note->notate |= noteval;
            note->mark &= NM_STRING|NM_TABSET;
            if (note->notate & N_NOTEVAL)
            {
            note->notelength = typetolength(edit, note->notate);
            if (note->notelength > note->duration)
                note->notelength = note->duration;
            }
            else note->notelength = note->duration;
        }
    }
    if (edit->refreshstart > start) edit->refreshstart = start;
    if (edit->refreshend < end) edit->refreshend = end;
    refreshnotation(edit);
    transcribing = 0;
}

void guessnewdurations(struct Edit *edit)

{
    guessdurations(edit,edit->refreshstart,edit->refreshend);
}

/*
void onlyinsertrests(struct Edit *edit)

{
    long start,end;
    short bottom, top;
    long begin;
    short measurecount;
    struct NMeasure *measure;
    start = 0;
    end = edit->datawidth;
    edit->notatequant = 8;
    begin = start;
    measurecount = timetomeasure(&edit->clip,start);
    if (!edit->notatequant) edit->notatequant = 32;
    bottom = edit->transcenter - DISPLAYRANGE;
    if (bottom < 1) bottom = 1;
    top = edit->transcenter + DISPLAYRANGE;
    if (top > 127) top = 127;
    edit->fillsequence = 0;
    measure = 0;
    for (;start < end;) {
        measurecount++;
        if (edit->notatebits & NB_THINKBOTH) {
            edit->bottomrange = bottom;
            edit->toprange = edit->transcenter + edit->ledger_lines;
            edit->centerrange = edit->transcenter - 10;
        }
        else if (edit->notatebits & NB_THINKBASS) {
            edit->bottomrange = 1;
            edit->toprange = 127;
            edit->centerrange = edit->transcenter - 10;
        }
        else {
            edit->bottomrange = 1;
            edit->toprange = 1;
            edit->centerrange = 1;
        }
            measure = preparenextmeasure1(edit,measure,start);
            if (!measure) break;
        if (!(edit->notatebits & NB_THINKTREBLE))
        {
            dividebeat(edit,measure,0,measure->size);
            insertrests(edit,measure);
        }
            putmeasure(edit,measure);
        if (edit->notatebits & NB_THINKBOTH) {
            edit->bottomrange = edit->transcenter + edit->ledger_lines;
            edit->toprange = top;
            edit->centerrange = edit->transcenter + 11;
        }
        else if (edit->notatebits & NB_THINKBASS) {
            edit->bottomrange = 127;
            edit->toprange = 127;
            edit->centerrange = 127;
        }
        else {
            edit->bottomrange = 1;
            edit->toprange = 127;
            edit->centerrange = edit->transcenter + 11;
        }
            measure = preparenextmeasure2(edit,measure,start);
            if (!measure) break;
        if (!(edit->notatebits & NB_THINKBASS))
        {
            dividebeat(edit,measure,0,measure->size);
            insertrests(edit,measure);
        }
            putmeasure(edit,measure);
        start += (measure->size * edit->notatequant);
    }
    if (measure) {
        freelist((struct Event *)measure->beats);
        FreeMem((char *)measure,(measure->size << 2) + NMEASURESIZE);
    }
    edit->clip.events.first = (struct Event *) List_Cat(edit->fillsequence,
        edit->clip.events.first);
    edit->clip.events.first = (struct Event *) sorteventlist(edit->clip.events.first);
    if (waitwindow) notateclosewait();
    edit->clip.events.point = 0;
    edit->displaynote = (struct NoteEvent *) edit->clip.events.first;
}
*/

void checknotation(struct Edit *edit)

{
    unsigned long start, end;
    struct NotateEvent *note;
    start = 0x7FFFFFFF;
    end = 0;
    for (note = (struct NotateEvent *)edit->clip.events.first
        ;note;note = note->next)
    {
        if ((isanote(note)) && ((note->mark == 0) || (note->notate == 0)
            || (note->mark & NM_CLEARED)))
        {
            note->mark &= ~NM_CLEARED;
            if (note->time < start) start = note->time;
            if (note->time > end) end = note->time;
        }
    }
    end++;
    if (start <= end)
    {
//      if (edit->ntbits & NT_AUTOREST) onlyinsertrests(edit);
//      else
      guessdurations(edit,start,end+700);
    }
}

void tagrefresh(struct Edit *edit,long time)

{
    if (time < edit->refreshstart)
    {
        edit->refreshstart = nextmeasure(&edit->clip,time,0);
    }
    if (time > edit->refreshend)
    {
        edit->refreshend = nextmeasure(&edit->clip,time,1);
    }
}

void clearmarkbits(struct NotateEvent *note)

{
    if (!(note->mark & NM_DONTCLEAR)) note->mark |= NM_CLEARED;
    else note->mark &= ~NM_DONTCLEAR;
}

void tagnote(struct Edit *edit,struct NotateEvent *note)

{
    tagrefresh(edit,note->time);
    tagrefresh(edit,note->time + note->duration +1);
}

void initnote(struct Edit *edit,struct NotateEvent *note,char new)

{
    char offset;
    short t;

    if (note->type == EVENT_VOICE) {
        if (note->notate & N_TNOTE) {
            note->notate &= ~N_NOTE;
            note->notate |= newdurationtonotation(edit,note->duration);
            note->notate &= ~N_TNOTE;
        }
        /* new == 1 from inter.c/alternote() */
        if (new) {
            note->mark &= ~(NM_NOTATED);
            note->duration = edit->insertduration;
            note->notate &= ~(N_NOTE | N_TNOTE);
            note->notate |= (1 + edit->inserttype);
            if (edit->insertalter == 2) note->notate |= N_DOTTED;
            else if (!edit->insertalter) note->notate |= N_TRIPLET;
            note->notelength = typetolength(edit,note->notate);
        }
        /* new == 2 from inter.c/fillnote() */
        if (new == 2) {
            note->notate |= N_FLAG;
            note->notate &= ~(N_BEAM | N_ADJACENT);
            setstem(note, STEM_DOWN);
            if (edit->ntbits & NT_AUTOSTEM)
                setstem(note, stemdirection(edit, note->value));
            else if (edit->ntbits & NT_STEMUP)
                setstem(note, STEM_UP);
            else setstem(note, STEM_DOWN);
            notesetresolution(edit,note);
        }
        if (isanote(note))
        {
            t = displaytwelvetoscale(&edit->clip,note->time,note->value -
                edit->transcenter + 60,&offset);
            note->mark &= ~NM_SIGN;
            if (offset == 1) note->mark |= NM_SIGN1;
            else if (offset == -1) note->mark |= NM_SIGN2;
            else if (offset == 4) note->mark |= NM_SIGN;
            note->notate &= ~(N_BEAM | N_ADJACENT);
            note->notate |= N_FLAG;
        }
        note->mark &= ~NM_DRAWN;
    }
}

void striprests(struct Edit *edit, long start, long end)

{
    struct Clip *clip = &edit->clip;
    struct NotateEvent *toss = 0;
    struct NotateEvent *keep = 0;
    struct NotateEvent *event = (struct NotateEvent *) clip->events.first;
    struct NotateEvent *next;
    for (;event;) {
        if ((event->time < start) || (event->time > end)) continue;

        next = event->next;
        if (isarest(event)) {
            event->next = toss;
            toss = event;
        }
        else {
            if (event->status == MIDI_NOTEON) {
                if (event->notate & N_TNOTE) {
                    event->notate &= ~N_NOTE;
                    event->notate |= newdurationtonotation(edit,
                        event->duration);
                    event->notate &= ~N_TNOTE;
                }
            }
            event->next = keep;
            keep = event;
        }
        event = next;
    }
    freelist((struct Event *)toss);
    clip->events.first = (struct Event *) sorteventlist((struct Event *)keep);
    clip->events.point = clip->events.first;
}
