/branch/robo-ops/contrib/libmodplug/src/load_abc.cpp
C++ | 2649 lines | 2431 code | 110 blank | 108 comment | 614 complexity | a6147e7c023578ae49fe217a8371621b MD5 | raw file
Possible License(s): GPL-2.0
Large files files are truncated, but you can click here to view the full file
- /*
- MikMod Sound System
- By Jake Stine of Divine Entertainment (1996-2000)
- Support:
- If you find problems with this code, send mail to:
- air@divent.org
- Distribution / Code rights:
- Use this source code in any fashion you see fit. Giving me credit where
- credit is due is optional, depending on your own levels of integrity and
- honesty.
- -----------------------------------------
- Module: LOAD_ABC
- ABC module loader.
- by Peter Grootswagers (2006)
- <email:pgrootswagers@planet.nl>
- Portability:
- All systems - all compilers (hopefully)
- */
- #include <stdlib.h>
- #include <time.h>
- #include <string.h>
- #include <math.h>
- #include <ctype.h>
- #ifdef NEWMIKMOD
- #include "mikmod.h"
- #include "uniform.h"
- typedef UBYTE BYTE;
- typedef UWORD WORD;
- #else
- #include "stdafx.h"
- #include "sndfile.h"
- #endif
- #include "load_pat.h"
- #define MAXABCINCLUDES 8
- #define MAXCHORDNAMES 80
- #define ABC_ENV_DUMPTRACKS "MMABC_DUMPTRACKS"
- #define ABC_ENV_NORANDOMPICK "MMABC_NO_RANDOM_PICK"
- // gchords use tracks with vpos 1 thru 7
- // drums use track with vpos 8
- // voice chords use vpos 0 and vpos from 11 up
- #define GCHORDBPOS 1
- #define GCHORDFPOS 2
- #define GCHORDCPOS 3
- #define DRUMPOS 8
- #define DRONEPOS1 9
- #define DRONEPOS2 10
- // in the patterns a whole note at unmodified tempo is 16 rows
- #define ROWSPERNOTE 16
- // a 1/64-th note played in triool equals a 1/96-th note, to be able
- // to play them and also to play the 1/64-th we need a resolution of 192
- // because 2/192 = 1/96 and 3/192 = 1/64
- #define RESOLUTION 192
- #pragma pack(1)
- /**************************************************************************
- **************************************************************************/
- #ifdef NEWMIKMOD
- static char ABC_Version[] = "ABC+2.0 (draft IV)";
- #endif
- typedef enum {
- note,
- octave,
- smpno,
- volume,
- effect,
- effoper
- } ABCEVENT_X_NOTE;
- typedef enum {
- none,
- trill,
- bow,
- accent
- } ABCEVENT_X_EFFECT;
- typedef enum {
- cmdflag,
- command,
- chordnum,
- chordnote,
- chordbase,
- jumptype
- } ABCEVENT_X_CMD;
- typedef enum {
- cmdsegno = '$',
- cmdcapo = 'B',
- cmdchord = 'C',
- cmdfine = 'F',
- cmdhide = 'H',
- cmdjump = 'J',
- cmdloop = 'L',
- cmdcoda = 'O',
- cmdpartbrk = 'P',
- cmdsync = 'S',
- cmdtempo = 'T',
- cmdvariant = 'V',
- cmdtocoda = 'X'
- } ABCEVENT_CMD;
- typedef enum {
- jumpnormal,
- jumpfade,
- jumpdacapo,
- jumpdcfade,
- jumpdasegno,
- jumpdsfade,
- jumpfine,
- jumptocoda,
- jumpvariant,
- jumpnot
- } ABCEVENT_JUMPTYPE;
- typedef struct _ABCEVENT
- {
- struct _ABCEVENT *next;
- ULONG tracktick;
- union {
- BYTE par[6];
- struct {
- BYTE flg;
- BYTE cmd;
- ULONG lpar; // for variant selections, bit pattern
- };
- };
- BYTE part;
- BYTE tiednote;
- } ABCEVENT;
- typedef struct _ABCTRACK
- {
- struct _ABCTRACK *next;
- ABCEVENT *head;
- ABCEVENT *tail;
- ABCEVENT *capostart;
- ABCEVENT *tienote;
- int transpose;
- int octave_shift;
- ULONG slidevoltime; // for crescendo and diminuendo
- int slidevol; // -2:fade away, -1:diminuendo, 0:none, +1:crescendo
- BYTE vno; // 0 is track is free for use, from previous song in multi-songbook
- BYTE vpos; // 0 is main voice, other is subtrack for gchords, gchords or drumnotes
- BYTE tiedvpos;
- BYTE mute;
- BYTE chan; // 10 is percussion channel, any other is melodic channel
- BYTE volume;
- BYTE instr; // current instrument for this track
- BYTE legato;
- char v[22]; // first twenty characters are significant
- } ABCTRACK;
- typedef struct _ABCMACRO
- {
- struct _ABCMACRO *next;
- char *name;
- char *subst;
- char *n;
- } ABCMACRO;
- /**************************************************************************
- **************************************************************************/
- typedef struct _ABCHANDLE
- {
- #ifdef NEWMIKMOD
- MM_ALLOC *allochandle;
- MM_ALLOC *macrohandle;
- MM_ALLOC *trackhandle;
- MM_ALLOC *ho;
- #endif
- ABCMACRO *macro;
- ABCMACRO *umacro;
- ABCTRACK *track;
- long int pickrandom;
- unsigned int len;
- int speed;
- char *line;
- char *beatstring;
- BYTE beat[4]; // a:first note, b:strong notes, c:weak notes, n:strong note every n
- char gchord[80]; // last setting for gchord
- char drum[80]; // last setting for drum
- char drumins[80]; // last setting for drum
- char drumvol[80]; // last setting for drum
- ULONG barticks;
- // parse variables, declared here to avoid parameter pollution
- int abcchordvol, abcchordprog, abcbassvol, abcbassprog;
- int ktrans;
- int drumon, gchordon, droneon;
- int dronegm, dronepitch[2], dronevol[2];
- ABCTRACK *tp, *tpc, *tpr;
- ULONG tracktime;
- } ABCHANDLE;
- static int global_voiceno, global_octave_shift, global_tempo_factor, global_tempo_divider;
- static char global_part;
- static ULONG global_songstart;
- /* Named guitar chords */
- static char chordname[MAXCHORDNAMES][8];
- static int chordnotes[MAXCHORDNAMES][6];
- static int chordlen[MAXCHORDNAMES];
- static int chordsnamed = 0;
- static const char *sig[] = {
- " C D EF G A Bc d ef g a b", // 7 sharps C#
- " C D EF G AB c d ef g ab ", // 6 sharps F#
- " C DE F G AB c de f g ab ", // 5 sharps B
- " C DE F GA B c de f ga b ", // 4 sharps E
- " CD E F GA B cd e f ga b ", // 3 sharps A
- " CD E FG A B cd e fg a b ", // 2 sharps D
- " C D E FG A Bc d e fg a b", // 1 sharps G
- " C D EF G A Bc d ef g a b", // 0 sharps C
- " C D EF G AB c d ef g ab ", // 1 flats F
- " C DE F G AB c de f g ab ", // 2 flats Bb
- " C DE F GA B c de f ga b ", // 3 flats Eb
- " CD E F GA B cd e f ga b ", // 4 flats Ab
- " CD E FG A B cd e fg a b ", // 5 flats Db
- "C D E FG A Bc d e fg a b ", // 6 flats Gb
- "C D EF G A Bc d ef g a b ", // 7 flats Cb
- // 0123456789012345678901234
- };
- static const char *keySigs[] = {
- /* 0....:....1....:....2....:....3....:....4....:....5. */
- "7 sharps: C# A#m G#Mix D#Dor E#Phr F#Lyd B#Loc ",
- "6 sharps: F# D#m C#Mix G#Dor A#Phr BLyd E#Loc ",
- "5 sharps: B G#m F#Mix C#Dor D#Phr ELyd A#Loc ",
- "4 sharps: E C#m BMix F#Dor G#Phr ALyd D#Loc ",
- "3 sharps: A F#m EMix BDor C#Phr DLyd G#Loc ",
- "2 sharps: D Bm AMix EDor F#Phr GLyd C#Loc ",
- "1 sharp : G Em DMix ADor BPhr CLyd F#Loc ",
- "0 sharps: C Am GMix DDor EPhr FLyd BLoc ",
- "1 flat : F Dm CMix GDor APhr BbLyd ELoc ",
- "2 flats : Bb Gm FMix CDor DPhr EbLyd ALoc ",
- "3 flats : Eb Cm BbMix FDor GPhr AbLyd DLoc ",
- "4 flats : Ab Fm EbMix BbDor CPhr DbLyd GLoc ",
- "5 flats : Db Bbm AbMix EbDor FPhr GbLyd CLoc ",
- "6 flats : Gb Ebm DbMix AbDor BbPhr CbLyd FLoc ",
- "7 flats : Cb Abm GbMix DbDor EbPhr FbLyd BbLoc ",
- 0
- };
- // local prototypes
- static int abc_getnumber(const char *p, int *number);
- static ABCTRACK *abc_locate_track(ABCHANDLE *h, const char *voice, int pos);
- static void abc_add_event(ABCHANDLE *h, ABCTRACK *tp, ABCEVENT *e);
- static void abc_add_setloop(ABCHANDLE *h, ABCTRACK *tp, ULONG tracktime);
- static void abc_add_setjumploop(ABCHANDLE *h, ABCTRACK *tp, ULONG tracktime, ABCEVENT_JUMPTYPE j);
- static ULONG abc_pattracktime(ABCHANDLE *h, ULONG tracktime);
- static int abc_patno(ABCHANDLE *h, ULONG tracktime);
- static void abc_message(const char *s1, const char *s2)
- {
- char txt[256];
- if( strlen(s1) + strlen(s2) > 255 ) return;
- sprintf(txt, s1, s2);
- #ifdef NEWMIKMOD
- _mmlog(txt);
- #else
- fprintf(stderr, "load_abc > %s\n", txt);
- #endif
- }
- static ULONG modticks(ULONG abcticks)
- {
- return abcticks / RESOLUTION;
- }
- static ULONG abcticks(ULONG modticks)
- {
- return modticks * RESOLUTION;
- }
- static ULONG notelen_notediv_to_ticks(int speed, int len, int div)
- {
- ULONG u;
- u = (ROWSPERNOTE * RESOLUTION * speed * len * global_tempo_factor) / (div * global_tempo_divider);
- return u;
- }
- static void abc_dumptracks(ABCHANDLE *h, const char *p)
- {
- ABCTRACK *t;
- ABCEVENT *e;
- int n,pat,row,tck;
- char nn[3];
- if( !h ) return;
- for( t=h->track; t; t=t->next ) {
- printf("track %d.%d chan=%d %s\n", (int)(t->vno), (int)(t->vpos),
- (int)(t->chan), (char *)(t->v));
- if( strcmp(p,"nonotes") )
- n = 1;
- else
- n = 0;
- for( e=t->head; e; e=e->next ) {
- tck = modticks(e->tracktick);
- row = tck / h->speed;
- pat = row / 64;
- tck = tck % h->speed;
- row = row % 64;
- nn[0] = ( e->tracktick % abcticks(h->speed * 64) ) ? ' ': '-';
- if( e->flg == 1 ) {
- printf(" %6d.%02d.%d%c%c %d.%d %s ",
- pat, row, tck, nn[0], (int)(e->part), (int)(t->vno),
- (int)(t->vpos), (char *)(t->v));
- if( e->cmd == cmdchord ) {
- nn[0] = "CCCDDEFFGGAABccddeffggaabb"[e->par[chordnote]];
- nn[1] = "b # # # # # # # # # # #"[e->par[chordnote]];
- nn[2] = '\0';
- if( isspace(nn[1]) ) nn[1] = '\0';
- printf("CMD %c: gchord %s%s",
- (char)(e->cmd), nn, chordname[e->par[chordnum]]);
- if( e->par[chordbase] != e->par[chordnote] ) {
- nn[0] = "CCCDDEFFGGAABccddeffggaabb"[e->par[chordbase]];
- nn[1] = "b # # # # # # # # # # #"[e->par[chordbase]];
- nn[2] = '\0';
- printf("/%s", nn);
- }
- printf("\n");
- }
- else
- printf("CMD %c @%p 0x%08lX\n",
- (char)(e->cmd), e,
- (unsigned long)(e->lpar));
- if( strcmp(p,"nonotes") )
- n = 1;
- else
- n = 0;
- }
- else if( n ) {
- printf(" %6d.%02d.%d%c%c %d.%d %s ", pat, row, tck, nn[0], e->part, t->vno, t->vpos, t->v);
- if( e->par[note] ) {
- nn[0] = "CCCDDEFFGGAABccddeffggaabb"[e->par[note]-23];
- nn[1] = "b # # # # # # # # # # #"[e->par[note]-23];
- nn[2] = '\0';
- }
- else strcpy(nn,"--");
- printf("NOTE %s octave %d inst %s vol %03d\n",
- nn, e->par[octave], pat_gm_name(pat_smptogm(e->par[smpno])),e->par[volume]);
- if( strcmp(p,"all") )
- n = 0;
- }
- }
- }
- }
- #ifdef NEWMIKMOD
- #define MMFILE MMSTREAM
- #define mmfgetc(x) _mm_read_SBYTE(x)
- #define mmfeof(x) _mm_feof(x)
- #define mmfgets(buf,sz,f) _mm_fgets(f,buf,sz)
- #define mmftell(x) _mm_ftell(x)
- #define mmfseek(f,p,w) _mm_fseek(f,p,w)
- #define mmfopen(s,m) _mm_fopen(s,m)
- #define mmfclose(f) _mm_fclose(f)
- #else
- #define MMSTREAM FILE
- #define _mm_fopen(name,mode) fopen(name,mode)
- #define _mm_fgets(f,buf,sz) fgets(buf,sz,f)
- #define _mm_fseek(f,pos,whence) fseek(f,pos,whence)
- #define _mm_ftell(f) ftell(f)
- #define _mm_read_UBYTES(buf,sz,f) fread(buf,sz,1,f)
- #define _mm_read_SBYTES(buf,sz,f) fread(buf,sz,1,f)
- #define _mm_feof(f) feof(f)
- #define _mm_fclose(f) fclose(f)
- #define DupStr(h,buf,sz) strdup(buf)
- #define _mm_calloc(h,n,sz) calloc(n,sz)
- #define _mm_recalloc(h,buf,sz,elsz) realloc(buf,sz)
- #define _mm_free(h,p) free(p)
- typedef struct {
- char *mm;
- int sz;
- int pos;
- } MMFILE;
- static MMFILE *mmfopen(const char *name, const char *mode)
- {
- FILE *fp;
- MMFILE *mmfile;
- long len;
- if( *mode != 'r' ) return NULL;
- fp = fopen(name, mode);
- if( !fp ) return NULL;
- fseek(fp, 0, SEEK_END);
- len = ftell(fp);
- mmfile = (MMFILE *)malloc(len+sizeof(MMFILE));
- if( !mmfile ) return NULL;
- fseek(fp, 0, SEEK_SET);
- fread(&mmfile[1],1,len,fp);
- fclose(fp);
- mmfile->mm = (char *)&mmfile[1];
- mmfile->sz = len;
- mmfile->pos = 0;
- return mmfile;
- }
- static void mmfclose(MMFILE *mmfile)
- {
- free(mmfile);
- }
- static bool mmfeof(MMFILE *mmfile)
- {
- if( mmfile->pos < 0 ) return TRUE;
- if( mmfile->pos < mmfile->sz ) return FALSE;
- return TRUE;
- }
- static int mmfgetc(MMFILE *mmfile)
- {
- int b;
- if( mmfeof(mmfile) ) return EOF;
- b = mmfile->mm[mmfile->pos];
- mmfile->pos++;
- if( b=='\r' && mmfile->mm[mmfile->pos] == '\n' ) {
- b = '\n';
- mmfile->pos++;
- }
- return b;
- }
- static void mmfgets(char buf[], unsigned int bufsz, MMFILE *mmfile)
- {
- int i,b;
- for( i=0; i<(int)bufsz-1; i++ ) {
- b = mmfgetc(mmfile);
- if( b==EOF ) break;
- buf[i] = b;
- if( b == '\n' ) break;
- }
- buf[i] = '\0';
- }
- static long mmftell(MMFILE *mmfile)
- {
- return mmfile->pos;
- }
- static void mmfseek(MMFILE *mmfile, long p, int whence)
- {
- switch(whence) {
- case SEEK_SET:
- mmfile->pos = p;
- break;
- case SEEK_CUR:
- mmfile->pos += p;
- break;
- case SEEK_END:
- mmfile->pos = mmfile->sz + p;
- break;
- }
- }
- #endif
- // =====================================================================================
- static ABCEVENT *abc_new_event(ABCHANDLE *h, ULONG abctick, const char data[])
- // =====================================================================================
- {
- ABCEVENT *retval;
- int i;
- retval = (ABCEVENT *)_mm_calloc(h->trackhandle, 1,sizeof(ABCEVENT));
- retval->next = NULL;
- retval->tracktick = abctick;
- for( i=0; i<6; i++ )
- retval->par[i] = data[i];
- retval->part = global_part;
- retval->tiednote = 0;
- return retval;
- }
- // =============================================================================
- static ABCEVENT *abc_copy_event(ABCHANDLE *h, ABCEVENT *se)
- // =============================================================================
- {
- ABCEVENT *e;
- e = (ABCEVENT *)_mm_calloc(h->trackhandle, 1,sizeof(ABCEVENT));
- e->next = NULL;
- e->tracktick = se->tracktick;
- e->flg = se->flg;
- e->cmd = se->cmd;
- e->lpar = se->lpar;
- e->part = se->part;
- return e;
- }
- // =============================================================================
- static void abc_new_macro(ABCHANDLE *h, const char *m)
- // =============================================================================
- {
- ABCMACRO *retval;
- const char *p;
- char buf[256],*q;
- for( p=m; *p && isspace(*p); p++ ) ;
- for( q=buf; *p && *p != '='; p++ )
- *q++ = *p;
- if( q != buf )
- while( isspace(q[-1]) ) q--;
- *q = '\0';
- retval = (ABCMACRO *)_mm_calloc(h->macrohandle, 1,sizeof(ABCTRACK));
- retval->name = DupStr(h->macrohandle, buf,strlen(buf));
- retval->n = strrchr(retval->name, 'n'); // for transposing macro's
- for( p++; *p && isspace(*p); p++ ) ;
- strncpy(buf,p,200);
- for( q=&buf[strlen(buf)-1]; q!=buf && isspace(*q); q-- ) *q = '\0';
- retval->subst = DupStr(h->macrohandle, buf, strlen(buf));
- retval->next = h->macro;
- h->macro = retval;
- }
- // =============================================================================
- static void abc_new_umacro(ABCHANDLE *h, const char *m)
- // =============================================================================
- {
- ABCMACRO *retval, *mp;
- const char *p;
- char buf[256], let[2], *q;
- for( p=m; *p && isspace(*p); p++ ) ;
- for( q=buf; *p && *p != '='; p++ )
- *q++ = *p;
- if( q != buf )
- while( isspace(q[-1]) ) q--;
- *q = '\0';
- if( strlen(buf) > 1 || strchr("~HIJKLMNOPQRSTUVWXY",toupper(buf[0])) == 0 || strchr("xy",buf[0]) ) return;
- strcpy(let,buf);
- for( p++; *p && isspace(*p); p++ ) ;
- strncpy(buf,p,200);
- for( q=&buf[strlen(buf)-1]; q!=buf && isspace(*q); q-- ) *q = '\0';
- for( q=buf; *q; q++ ) if( *q == '!' ) *q = '+'; // translate oldstyle to newstyle
- if( !strcmp(buf,"+nil+") ) { // delete a macro
- mp = NULL;
- for( retval=h->umacro; retval; retval = retval->next ) {
- if( retval->name[0] == let[0] ) { // delete this one
- if( mp ) mp->next = retval->next;
- else h->umacro = retval->next;
- _mm_free(h->macrohandle, retval);
- return;
- }
- mp = retval;
- }
- return;
- }
- retval = (ABCMACRO *)_mm_calloc(h->macrohandle, 1,sizeof(ABCTRACK));
- retval->name = DupStr(h->macrohandle, let,1);
- retval->subst = DupStr(h->macrohandle, buf, strlen(buf));
- retval->n = 0;
- retval->next = h->umacro; // by placing it up front we mask out the old macro until we +nil+ it
- h->umacro = retval;
- }
- // =============================================================================
- static ABCTRACK *abc_new_track(ABCHANDLE *h, const char *voice, int pos)
- // =============================================================================
- {
- ABCTRACK *retval;
- if( !pos ) global_voiceno++;
- retval = (ABCTRACK *)_mm_calloc(h->trackhandle, 1,sizeof(ABCTRACK));
- retval->next = NULL;
- retval->vno = global_voiceno;
- retval->vpos = pos;
- retval->tiedvpos = pos;
- retval->instr = 1;
- strncpy(retval->v, voice, 20);
- retval->v[20] = '\0';
- retval->head = NULL;
- retval->tail = NULL;
- retval->capostart = NULL;
- retval->tienote = NULL;
- retval->mute = 0;
- retval->chan = 0;
- retval->transpose = 0;
- retval->volume = h->track? h->track->volume: 120;
- retval->slidevoltime = 0;
- retval->slidevol = 0;
- retval->legato = 0;
- return retval;
- }
- static int abc_numtracks(ABCHANDLE *h)
- {
- int n;
- ABCTRACK *t;
- n=0;
- for( t = h->track; t; t=t->next )
- n++;
- return n;
- }
- static int abc_interval(const char *s, const char *d)
- {
- const char *p;
- int i,j,k;
- int n,oct,m[2];
- for( j=0; j<2; j++ ) {
- if( j ) p = d;
- else p = s;
- switch(p[0]) {
- case '^':
- n = p[1];
- i = 2;
- break;
- case '_':
- n = p[1];
- i = 2;
- break;
- case '=':
- n = p[1];
- i = 2;
- break;
- default:
- n = p[0];
- i = 1;
- break;
- }
- for( k=0; k<25; k++ )
- if( n == sig[7][k] )
- break;
- oct = 4; // ABC note pitch C is C4 and pitch c is C5
- if( k > 12 ) {
- oct++;
- k -= 12;
- }
- while( p[i] == ',' || p[i] == '\'' ) {
- if( p[i] == ',' )
- oct--;
- else
- oct++;
- i++;
- }
- m[j] = k + 12 * oct;
- }
- return m[0] - m[1];
- }
- static int abc_transpose(const char *v)
- {
- int i,j,t;
- const char *m = "B", *mv = "";
- t = 0;
- global_octave_shift = 99;
- for( ; *v && *v != ']'; v++ ) {
- if( !strncasecmp(v,"t=",2) ) {
- v+=2;
- if( *v=='-' ) {
- j = -1;
- v++;
- }
- else j = 1;
- v+=abc_getnumber(v,&i);
- t += i * j;
- global_octave_shift = 0;
- }
- if( !strncasecmp(v,"octave=",7) ) {
- v+=7;
- if( *v=='-' ) {
- j = -1;
- v++;
- }
- else j = 1;
- v+=abc_getnumber(v,&i);
- t += i * j * 12;
- global_octave_shift = 0;
- }
- if( !strncasecmp(v,"transpose=",10) ) {
- v+=10;
- if( *v=='-' ) {
- j = -1;
- v++;
- }
- else j = 1;
- v+=abc_getnumber(v,&i);
- t += i * j;
- global_octave_shift = 0;
- }
- if( !strncasecmp(v,"octave=",7) ) { // used in kv304*.abc
- v+=7;
- if( *v=='-' ) {
- j = -1;
- v++;
- }
- else j = 1;
- v+=abc_getnumber(v,&i);
- t += i * j * 12;
- global_octave_shift = 0;
- }
- if( !strncasecmp(v,"m=",2) ) {
- v += 2;
- mv = v; // get the pitch for the middle staff line
- while( *v && *v != ' ' && *v != ']' ) v++;
- global_octave_shift = 0;
- }
- if( !strncasecmp(v,"middle=",7) ) {
- v += 7;
- mv = v; // get the pitch for the middle staff line
- while( *v && *v != ' ' && *v != ']' ) v++;
- global_octave_shift = 0;
- }
- if( !strncasecmp(v,"clef=",5) )
- v += 5;
- j = 1;
- if( !strncasecmp(v,"treble",6) ) {
- j = 0;
- v += 6;
- switch( *v ) {
- case '1': v++; m = "d"; break;
- case '2': v++;
- default: m = "B"; break;
- case '3': v++; m = "G"; break;
- case '4': v++; m = "E"; break;
- case '5': v++; m = "C"; break;
- }
- global_octave_shift = 0;
- }
- if( j && !strncasecmp(v,"bass",4) ) {
- m = "D,";
- j = 0;
- v += 4;
- switch( *v ) {
- case '1': v++; m = "C"; break;
- case '2': v++; m = "A,"; break;
- case '3': v++; m = "F,"; break;
- case '4': v++;
- default: m = "D,"; break;
- case '5': v++; m = "B,,"; break;
- }
- if( global_octave_shift == 99 )
- global_octave_shift = -2;
- }
- if( j && !strncasecmp(v,"tenor",5) ) {
- j = 0;
- v += 5;
- switch( *v ) {
- case '1': v++; m = "G"; break;
- case '2': v++; m = "E"; break;
- case '3': v++; m = "C"; break;
- case '4': v++;
- default: m = "A,"; break;
- case '5': v++; m = "F,"; break;
- }
- if( global_octave_shift == 99 )
- global_octave_shift = 1;
- }
- if( j && !strncasecmp(v,"alto",4) ) {
- j = 0;
- v += 4;
- switch( *v ) {
- case '1': v++; m = "G"; break;
- case '2': v++; m = "E"; break;
- case '3': v++;
- default: m = "C"; break;
- case '4': v++; m = "A,"; break;
- case '5': v++; m = "F,"; break;
- }
- if( global_octave_shift == 99 )
- global_octave_shift = 1;
- }
- if( j && strchr("+-",*v) && *v && v[1]=='8' ) {
- switch(*v) {
- case '+':
- t += 12;
- break;
- case '-':
- t -= 12;
- break;
- }
- v += 2;
- if( !strncasecmp(v,"va",2) ) v += 2;
- global_octave_shift = 0;
- j = 0;
- }
- if( j ) {
- while( *v && *v != ' ' && *v != ']' ) v++;
- }
- }
- if( strlen(mv) > 0 ) // someone set the middle note
- t += abc_interval(mv, m);
- if( global_octave_shift == 99 )
- global_octave_shift = 0;
- return t;
- }
- // =============================================================================
- static ABCTRACK *abc_locate_track(ABCHANDLE *h, const char *voice, int pos)
- // =============================================================================
- {
- ABCTRACK *tr, *prev, *trunused;
- char vc[21];
- int i, trans=0, voiceno=0, instrno = 1, channo = 0;
- for( ; *voice == ' '; voice++ ) ; // skip leading spaces
- for( i=0; *voice && *voice != ']' && *voice != '%' && !isspace(*voice); voice++ ) // can work with inline voice instructions
- vc[i++] = *voice;
- vc[i] = '\0';
- prev = NULL;
- trunused = NULL;
- if( !pos ) trans = abc_transpose(voice);
- for( tr=h->track; tr; tr=tr->next ) {
- if( tr->vno == 0 ) {
- if( !trunused ) trunused = tr; // must reuse mastertrack (h->track) as first
- }
- else {
- if( !strncasecmp(tr->v, vc, 20) ) {
- if( tr->vpos == pos )
- return tr;
- trans = tr->transpose;
- global_octave_shift = tr->octave_shift;
- voiceno = tr->vno;
- instrno = tr->instr;
- channo = tr->chan;
- }
- }
- prev = tr;
- }
- if( trunused ) {
- tr = trunused;
- if( pos ) {
- tr->vno = voiceno;
- tr->instr = instrno;
- tr->chan = channo;
- }
- else {
- global_voiceno++;
- tr->vno = global_voiceno;
- tr->instr = 1;
- tr->chan = 0;
- }
- tr->vpos = pos;
- tr->tiedvpos = pos;
- strncpy(tr->v, vc, 20);
- tr->v[20] = '\0';
- tr->mute = 0;
- tr->transpose = trans;
- tr->octave_shift = global_octave_shift;
- tr->volume = h->track->volume;
- tr->tienote = NULL;
- tr->legato = 0;
- return tr;
- }
- tr = abc_new_track(h, vc, pos);
- if( pos ) {
- tr->vno = voiceno;
- tr->instr = instrno;
- tr->chan = channo;
- }
- tr->transpose = trans;
- tr->octave_shift = global_octave_shift;
- if( prev ) prev->next = tr;
- else h->track = tr;
- return tr;
- }
- // =============================================================================
- static ABCTRACK *abc_check_track(ABCHANDLE *h, ABCTRACK *tp)
- // =============================================================================
- {
- if( !tp ) {
- tp = abc_locate_track(h, "", 0); // must work for voiceless abc too...
- tp->transpose = h->ktrans;
- }
- return tp;
- }
- static void abc_add_capo(ABCHANDLE *h, ABCTRACK *tp, ULONG tracktime)
- {
- ABCEVENT *e;
- char d[6];
- d[0] = d[1] = d[2] = d[3] = d[4] = d[5] = 0;
- d[cmdflag] = 1;
- d[command] = cmdcapo;
- e = abc_new_event(h, tracktime, d);
- tp->capostart = e;
- abc_add_event(h, tp, e); // do this last (recursion danger)
- }
- static void abc_add_segno(ABCHANDLE *h, ABCTRACK *tp, ULONG tracktime)
- {
- ABCEVENT *e;
- char d[6];
- d[0] = d[1] = d[2] = d[3] = d[4] = d[5] = 0;
- d[cmdflag] = 1;
- d[command] = cmdsegno;
- e = abc_new_event(h, tracktime, d);
- abc_add_event(h, tp, e);
- }
- static void abc_add_coda(ABCHANDLE *h, ABCTRACK *tp, ULONG tracktime)
- {
- ABCEVENT *e;
- char d[6];
- d[0] = d[1] = d[2] = d[3] = d[4] = d[5] = 0;
- d[cmdflag] = 1;
- d[command] = cmdcoda;
- e = abc_new_event(h, tracktime, d);
- abc_add_event(h, tp, e);
- }
- static void abc_add_fine(ABCHANDLE *h, ABCTRACK *tp, ULONG tracktime)
- {
- ABCEVENT *e;
- char d[6];
- d[0] = d[1] = d[2] = d[3] = d[4] = d[5] = 0;
- d[cmdflag] = 1;
- d[command] = cmdfine;
- e = abc_new_event(h, tracktime, d);
- abc_add_event(h, tp, e);
- }
- static void abc_add_tocoda(ABCHANDLE *h, ABCTRACK *tp, ULONG tracktime)
- {
- ABCEVENT *e;
- char d[6];
- d[0] = d[1] = d[2] = d[3] = d[4] = d[5] = 0;
- d[cmdflag] = 1;
- d[command] = cmdtocoda;
- e = abc_new_event(h, tracktime, d);
- abc_add_event(h, tp, e);
- }
- // first track is dirigent, remove all control events from other tracks
- // to keep the information where the events should be relative to note events
- // in the same tick the ticks are octated and four added for note events
- // the control events that come before the note events get a decremented tick,
- // those that come after get an incremented tick, for example:
- // ctrl ctrl note ctrl ctrl note
- // original: t t t t t+1 t+1
- // recoded: 8t+1 8t+2 8t+4 8t+5 8t+11 8t+12
- static void abc_remove_unnecessary_events(ABCHANDLE *h)
- {
- ABCTRACK *tp,*ptp;
- ABCEVENT *ep, *el;
- ULONG ct, et;
- int d;
- ptp = NULL;
- for( tp=h->track; tp; tp=tp->next ) {
- el = NULL;
- ep = tp->head;
- ct = 0;
- d = -3;
- while( ep ) {
- et = ep->tracktick;
- ep->tracktick <<= 3;
- ep->tracktick += 4;
- if( ep->flg == 1 ) {
- ep->tracktick += d;
- d++;
- if( d == 0 ) d = -1;
- if( d == 4 ) d = 3;
- if( tp!=h->track ) ep->cmd = cmdhide;
- switch( ep->cmd ) {
- case cmdhide:
- case cmdsync:
- if( el ) {
- el->next = ep->next;
- _mm_free(h->trackhandle,ep);
- ep = el->next;
- }
- else {
- tp->head = ep->next;
- _mm_free(h->trackhandle,ep);
- ep = tp->head;
- }
- break;
- default:
- el = ep;
- ep = ep->next;
- break;
- }
- }
- else {
- el = ep;
- ep = ep->next;
- d = 1;
- }
- if( et > ct )
- d = -3;
- ct = et;
- }
- if( !tp->head ) { // no need to keep empty tracks...
- if( ptp ) {
- ptp->next = tp->next;
- _mm_free(h->trackhandle,tp);
- tp = ptp;
- }
- else {
- h->track = tp->next;
- _mm_free(h->trackhandle,tp);
- tp = h->track;
- }
- }
- ptp = tp; // remember previous track
- }
- }
- // set ticks back, and handle partbreaks
- static void abc_retick_events(ABCHANDLE *h)
- {
- ABCTRACK *tp;
- ABCEVENT *ep;
- ULONG et, tt=0, at = abcticks(64 * h->speed);
- for( tp=h->track; tp; tp=tp->next ) {
- // make ticks relative
- tt = 0;
- for( ep=tp->head; ep; ep=ep->next ) {
- et = ep->tracktick >> 3;
- ep->tracktick = et - tt;
- tt = et;
- }
- // make ticks absolute again, skipping no-op partbreaks
- tt = 0;
- for( ep=tp->head; ep; ep=ep->next ) {
- ep->tracktick += tt;
- tt = ep->tracktick;
- if( ep->flg == 1 && ep->cmd == cmdpartbrk ) {
- if( tt % at ) {
- tt += at;
- tt /= at;
- tt *= at;
- ep->tracktick -= abcticks(h->speed); // break plays current row
- }
- else ep->cmd = cmdhide;
- }
- }
- }
- }
- // make sure every track has the control events it needs, this way it is not
- // necessary to have redundant +segno+ +D.C.+ etc in the voices, the first voice
- // is the master, it is pointed to by the member 'track' in the ABCHANDLE
- static void abc_synchronise_tracks(ABCHANDLE *h)
- {
- ABCTRACK *tp;
- ULONG tm; // tracktime in master
- ABCEVENT *em, *es, *et, *ec; // events in master, slave, slave temporary and copied event
- if( !h || !h->track ) return;
- abc_remove_unnecessary_events(h);
- for( tp = h->track->next; tp; tp = tp->next ) {
- for( em=h->track->head; em; em=em->next ) {
- if( em->flg == 1 ) { // some kind of control event
- switch( em->cmd ) {
- case cmdchord:
- case cmdhide:
- case cmdtempo:
- case cmdsync:
- break;
- default: // check to see if copy is necessary
- ec = abc_copy_event(h, em);
- tm = em->tracktick;
- es = tp->head; // allways search from the begin...
- for( et=es; et && et->tracktick <= tm; et=et->next )
- es = et;
- if( es == NULL || es->tracktick > tm ) { // special case: head of track
- ec->next = es;
- tp->head = ec;
- }
- else {
- ec->next = es->next;
- es->next = ec;
- }
- break;
- }
- }
- }
- }
- abc_retick_events(h);
- }
- static void abc_add_event(ABCHANDLE *h, ABCTRACK *tp, ABCEVENT *e)
- {
- if( !tp->capostart ) abc_add_capo(h, tp, global_songstart);
- if( tp->tail ) {
- tp->tail->next = e;
- tp->tail = e;
- }
- else {
- tp->head = e;
- tp->tail = e;
- }
- }
- static void abc_add_partbreak(ABCHANDLE *h, ABCTRACK *tp, ULONG tracktime)
- {
- ABCEVENT *e;
- char d[6];
- d[0] = d[1] = d[2] = d[3] = d[4] = d[5] = 0;
- d[cmdflag] = 1;
- d[command] = cmdpartbrk;
- e = abc_new_event(h, tracktime, d);
- abc_add_event(h, tp, e);
- }
- static void abc_add_tempo_event(ABCHANDLE *h, ABCTRACK *tp, ULONG tracktime, int tempo)
- {
- ABCEVENT *e;
- char d[6];
- d[0] = d[1] = d[2] = d[3] = d[4] = d[5] = 0;
- d[cmdflag] = 1;
- d[command] = cmdtempo;
- e = abc_new_event(h, tracktime, d);
- e->lpar = tempo;
- abc_add_event(h, tp, e);
- }
- static void abc_add_noteoff(ABCHANDLE *h, ABCTRACK *tp, ULONG tracktime)
- {
- ABCEVENT *e;
- char d[6];
- d[note] = 0;
- d[octave] = 0;
- d[smpno] = pat_gmtosmp(tp->instr);
- d[volume] = 0;
- d[effect] = 0;
- d[effoper] = 0;
- e = abc_new_event(h, tracktime, d);
- abc_add_event(h, tp, e);
- }
- static int abc_dynamic_volume(ABCTRACK *tp, ULONG tracktime, int vol)
- {
- ULONG slidetime;
- int voldelta;
- if( tp->mute ) return 0;
- if( tp->slidevol == 0 ) return vol;
- if( tracktime < tp->slidevoltime ) return vol;
- slidetime = modticks(tracktime - tp->slidevoltime);
- voldelta = (slidetime * 15) / 64 / 6; // slide from say mf up to f in one pattern's time
- if( tp->slidevol > -2 && voldelta > 15 ) voldelta = 15; // never to much dynamics
- if( tp->slidevol > 0 ) vol += voldelta;
- else vol -= voldelta;
- if( vol < 2 ) vol = 2; // xmms divides this by 2....
- if( vol > 127 ) vol = 127;
- return vol;
- }
- static void abc_track_untie_short_chordnotes(ABCHANDLE *h)
- {
- ABCTRACK *tp;
- int vn;
- tp = h->tp;
- vn = tp->vno;
- for( tp = h->track; tp; tp = tp->next )
- if( tp != h->tp && tp->vno == vn && tp->tienote ) {
- abc_message("short notes in chord can not be tied:\n%s", h->line);
- tp->tienote = 0;
- }
- }
- static void abc_track_clear_tiednote(ABCHANDLE *h)
- {
- ABCTRACK *tp;
- int vn;
- tp = h->tp;
- vn = tp->vno;
- for( tp = h->track; tp; tp = tp->next )
- if( tp->vno == vn ) tp->tienote = 0;
- }
- static void abc_track_clear_tiedvpos(ABCHANDLE *h)
- {
- ABCTRACK *tp;
- int vn;
- tp = h->tp;
- vn = tp->vno;
- for( tp = h->track; tp; tp = tp->next )
- if( tp->vno == vn ) tp->tiedvpos = tp->vpos;
- }
- static ABCTRACK *abc_track_with_note_tied(ABCHANDLE *h, ULONG tracktime, int n, int oct)
- {
- int vn, vp;
- ABCTRACK *tp;
- ABCEVENT *e;
- tp = h->tp;
- vn = tp->vno;
- vp = tp->vpos;
- for( tp = h->track; tp; tp = tp->next ) {
- if( tp->vno == vn ) {
- e = tp->tienote;
- if( e && e->tracktick < tracktime
- && e->par[octave] == oct && abs(e->par[note] - n) < 3 ) {
- if( tp->vpos != vp ) tp->tiedvpos = vp;
- h->tp = tp;
- return tp;
- }
- }
- }
- tp = h->tp;
- vp = tp->tiedvpos;
- if( tp->vpos != vp ) {
- // chord note track allready returned in previous call
- for( tp = h->track; tp; tp = tp->next ) {
- if( tp->vno == vn && tp->vpos == vp ) {
- tp->tiedvpos = h->tp->vpos;
- h->tp = tp;
- return tp;
- }
- }
- }
- return h->tp;
- }
- static int abc_add_noteon(ABCHANDLE *h, int ch, const char *p, ULONG tracktime, char *barkey, int vol, ABCEVENT_X_EFFECT fx, int fxop)
- {
- ABCEVENT *e;
- ABCTRACK *tp;
- int i,j,k;
- int n,oct;
- char d[6];
- tp = h->tp;
- switch(ch) {
- case '^':
- if( p[0] == '^' ) {
- n = p[1];
- i = 2;
- ch = 'x';
- }
- else {
- n = p[0];
- i = 1;
- }
- break;
- case '_':
- if( p[0] == '_' ) {
- n = p[1];
- i = 2;
- ch = 'b';
- }
- else {
- n = p[0];
- i = 1;
- }
- break;
- case '=':
- n = p[0];
- i = 1;
- break;
- default:
- n = ch;
- i = 0;
- break;
- }
- for( k=0; k<51; k++ ) {
- if( n == barkey[k] )
- break;
- }
- j = k;
- if( k > 24 )
- k -= 25; // had something like A# over Bb key F signature....
- if( i ) {
- // propagate accidentals if necessary
- // DON'T do redundant accidentals they're always relative to C-scale
- for( k=0; k<25; k++ ) {
- if( n == sig[7][k] )
- break;
- }
- if( k < 25 ) { // only do real notes...
- switch(ch) {
- case 'x':
- k++;
- case '^':
- k++;
- break;
- case 'b':
- k--;
- case '_':
- k--;
- break;
- case '=':
- break;
- }
- if( j < 25 ) // was it not A# over Bb?
- barkey[j] = ' ';
- barkey[k] = n;
- }
- }
- oct = 3; // ABC note pitch C is C4 and pitch c is C5
- if( k < 25 ) {
- k += tp->transpose;
- while( k > 12 ) {
- oct++;
- k -= 12;
- }
- while( k < 0 ) {
- oct--;
- k += 12;
- }
- d[note] = 23 + k; // C0 is midi notenumber 24
- }
- else
- d[note] = 0; // someone has doen ^X3 or something like it...
- while( p[i] && strchr(",'",p[i]) ) {
- if( p[i]==',' ) oct--;
- else oct++;
- i++;
- tp->octave_shift = 0; // forget we ever had to look at it
- }
- if( tp->octave_shift )
- tp->transpose += 12 * tp->octave_shift;
- oct += tp->octave_shift;
- tp->octave_shift = 0; // after the first note we never have to look at it again
- if( oct < 0 ) oct = 0;
- if( oct > 9 ) oct = 9;
- d[octave] = oct;
- d[smpno] = pat_gmtosmp(tp->instr);
- d[volume] = abc_dynamic_volume(tp, tracktime, vol);
- d[effect] = fx; // effect
- d[effoper] = fxop;
- tp = abc_track_with_note_tied(h, tracktime, d[note], oct);
- if( tp->tienote ) {
- if( tp->tienote->par[note] != d[note] ) {
- if( abs(tp->tienote->par[note] - d[note]) < 3 ) {
- // may be tied over bar symbol, recover local accidental to barkey
- k = tp->tienote->par[note] - 23 - tp->transpose;
- while( k < 0 ) k += 12;
- while( k > 12 ) k -= 12;
- if( (isupper(n) && barkey[k+12] == ' ') || (islower(n) && barkey[k] == ' ') ) {
- barkey[j] = ' ';
- if( isupper(n) )
- barkey[k] = n;
- else
- barkey[k+12] = n;
- d[note] = tp->tienote->par[note];
- d[octave] = tp->tienote->par[octave];
- }
- }
- }
- }
- if( tp->tienote
- && tp->tienote->par[note] == d[note]
- && tp->tienote->par[octave] == d[octave] ) {
- for( e = tp->tienote; e; e = e->next ) {
- if( e->par[note] == 0 && e->par[octave] == 0 ) { // undo noteoff
- e->flg = 1;
- e->cmd = cmdhide;
- e->lpar = 0;
- break;
- }
- }
- tp->tienote->tiednote = 1; // mark him for the pattern writers
- for( j=i; isdigit(p[j]) || p[j]=='/'; j++ ) ; // look ahead to see if this one is tied too
- if( p[j] != '-' ) // is this note tied too?
- tp->tienote = NULL; // if not the tie ends here...
- return i;
- }
- tp->tienote = NULL;
- if( tp->tail
- && tp->tail->tracktick == tracktime
- && tp->tail->par[note] == 0
- && tp->tail->par[octave] == 0 ) {
- for( j=0; j<6; j++ )
- tp->tail->par[j] = d[j];
- }
- else {
- e = abc_new_event(h, tracktime, d);
- abc_add_event(h, tp, e);
- }
- if( i > 0 && p[i-1] == '"' ) {
- i--; // someone coded a weird note like ^"E"
- abc_message("strange note encountered scanning %s", h->line);
- }
- return i;
- }
- static void abc_add_dronenote(ABCHANDLE *h, ABCTRACK *tp, ULONG tracktime, int nnum, int vol)
- {
- ABCEVENT *e;
- int j,k;
- int oct;
- char d[6];
- oct = -1; // ABC note pitch C is C4 and pitch c is C5
- k = nnum + 1;
- while( k > 12 ) {
- oct++;
- k -= 12;
- }
- while( k < 0 ) {
- oct--;
- k += 12;
- }
- if( oct < 0 ) oct = 0;
- d[note] = 23 + k; // C0 is midi notenumber 24
- d[octave] = oct;
- d[smpno] = pat_gmtosmp(tp->instr);
- d[volume] = abc_dynamic_volume(tp, tracktime, vol);
- d[effect] = 0; // effect
- d[effoper] = 0;
- if( tp->tail
- && tp->tail->tracktick == tracktime
- && tp->tail->par[note] == 0
- && tp->tail->par[octave] == 0 ) {
- for( j=0; j<6; j++ )
- tp->tail->par[j] = d[j];
- }
- else {
- e = abc_new_event(h, tracktime, d);
- abc_add_event(h, tp, e);
- }
- }
- static void abc_add_chordnote(ABCHANDLE *h, ABCTRACK *tp, ULONG tracktime, int nnum, int vol)
- {
- abc_add_dronenote(h, tp, tracktime, nnum + 23, tp->mute? 0: vol);
- }
- static void abc_add_drumnote(ABCHANDLE *h, ABCTRACK *tp, ULONG tracktime, int nnum, int vol)
- {
- abc_add_dronenote(h, tp, tracktime, nnum, tp->mute? 0: vol);
- }
- static void abc_add_variant_start(ABCHANDLE *h, ABCTRACK *tp, ULONG tracktime, int n)
- {
- ABCEVENT *e;
- char d[6];
- d[0] = d[1] = d[2] = d[3] = d[4] = d[5] = 0;
- d[cmdflag] = 1;
- d[command] = cmdvariant;
- e = abc_new_event(h, tracktime, d);
- e->lpar = 1<<n;
- abc_add_event(h, tp, e);
- }
- static void abc_add_variant_choise(ABCTRACK *tp, int n)
- {
- tp->tail->lpar |= 1<<n;
- }
- static void abc_add_chord(const char *p, ABCHANDLE *h, ABCTRACK *tp, ULONG tracktime)
- {
- ABCEVENT *e;
- char d[6];
- char s[8];
- int i;
- const char *n = " C D EF G A Bc d ef g a b";
- d[0] = d[1] = d[2] = d[3] = d[4] = d[5] = 0;
- d[cmdflag] = 1;
- d[command] = cmdchord;
- if( p[0] == '(' ) p++; // chord between parens like: (C)
- for( i=0; n[i]; i++ )
- if( *p == n[i] ) {
- d[chordnote] = i;
- break;
- }
- p++;
- switch(*p) {
- case 'b':
- d[chordnote]--;
- p++;
- break;
- case '#':
- d[chordnote]++;
- p++;
- break;
- }
- d[chordbase] = d[chordnote];
- for( i=0; p[i] && p[i] != '"' && p[i] != '/' && p[i] != '(' && p[i] != ')' && p[i] != ' '; i++ ) s[i] = p[i];
- s[i] = '\0';
- p = &p[i];
- if( *p=='/' ) {
- p++;
- for( i=0; n[i]; i++ )
- if( *p == n[i] ) {
- d[chordbase] = i;
- break;
- }
- p++;
- switch(*p) {
- case 'b':
- d[chordbase]--;
- p++;
- break;
- case '#':
- d[chordbase]++;
- p++;
- break;
- }
- }
- for( i=0; i<chordsnamed; i++ )
- if( !strcmp(s, chordname[i]) ) {
- d[chordnum] = i;
- break;
- }
- if( i==chordsnamed ) {
- abc_message("Failure: unrecognized chordname %s",s);
- return;
- }
- e = abc_new_event(h, tracktime, d);
- abc_add_event(h, tp, e);
- }
- static void abc_add_setloop(ABCHANDLE *h, ABCTRACK *tp, ULONG tracktime)
- {
- ABCEVENT *e;
- char d[6];
- d[0] = d[1] = d[2] = d[3] = d[4] = d[5] = 0;
- d[cmdflag] = 1;
- d[command] = cmdloop;
- e = abc_new_event(h, tracktime, d);
- abc_add_event(h, tp, e);
- }
- static void abc_fade_track(ABCTRACK *tp, ABCEVENT *e)
- {
- while(e) {
- if( e->flg != 1 && e->par[note] != 0 )
- e->par[volume] = abc_dynamic_volume(tp, e->tracktick, e->par[volume]);
- e = e->next;
- }
- }
- static void abc_add_setjumploop(ABCHANDLE *h, ABCTRACK *tp, ULONG tracktime, ABCEVENT_JUMPTYPE j)
- {
- ABCEVENT *e;
- char d[8];
- d[0] = d[1] = d[2] = d[3] = d[4] = d[5] = 0;
- d[cmdflag] = 1;
- d[command] = cmdjump;
- d[jumptype] = j;
- e = abc_new_event(h, tracktime, d);
- abc_add_event(h, tp, e);
- }
- static void abc_add_sync(ABCHANDLE *h, ABCTRACK *tp, ULONG tracktime)
- {
- ABCEVENT *e;
- char d[6];
- e = tp->tail;
- if( e && e->tracktick == tracktime ) return;
- if( e && e->flg == 1 && e->cmd == cmdsync ) {
- e->tracktick = tracktime;
- return;
- }
- d[0] = d[1] = d[2] = d[3] = d[4] = d[5] = 0;
- d[cmdflag] = 1;
- d[command] = cmdsync;
- e = abc_new_event(h, tracktime, d);
- abc_add_event(h, tp, e);
- }
- static void abc_add_gchord_syncs(ABCHANDLE *h, ABCTRACK *tpc, ULONG tracktime)
- {
- ABCTRACK *tp;
- int i;
- for( i = GCHORDBPOS; i < DRUMPOS; i++ ) {
- tp = abc_locate_track(h, tpc->v, i);
- abc_add_sync(h,tp,tracktime);
- }
- }
- static void abc_add_drum_sync(ABCHANDLE *h, ABCTRACK *tpr, ULONG tracktime)
- {
- ABCTRACK *tp;
- tp = abc_locate_track(h, tpr->v, DRUMPOS);
- abc_add_sync(h,tp,tracktime);
- }
- static int abc_getnumber(const char *p, int *number)
- {
- int i,h;
- i = 0;
- h = 0;
- while( isdigit(p[i]) ) {
- h = 10 * h + p[i] - '0';
- i++;
- }
- if( i==0 )
- *number = 1;
- else
- *number = h;
- return i;
- }
- static int abc_getexpr(const char *p, int *number)
- {
- int i, term, total;
- i = 0;
- while( isspace(p[i]) )
- i++;
- if( p[i] == '(' ) {
- i += abc_getexpr(p+i+1, number);
- while( p[i] && (p[i] != ')') )
- i++;
- return i;
- }
- i += abc_getnumber(p+i, &total);
- while( isspace(p[i]) )
- i++;
- while( p[i] == '+' ) {
- i += abc_getexpr(p+i+1, &term);
- total += term;
- while( isspace(p[i]) )
- i++;
- }
- *number = total;
- return i;
- }
- static int abc_notelen(const char *p, int *len, int *div)
- {
- int i,h,k;
- i = abc_getnumber(p,len);
- h = 1;
- while( p[i] == '/' ) {
- h *= 2;
- i++;
- }
- if( isdigit(p[i]) ) {
- h /= 2;
- i += abc_getnumber(p+i,&k);
- }
- else k = 1;
- *div = h * k;
- return i;
- }
- static int abc_brokenrithm(const char *p, int *nl, int *nd, int *b, int hornpipe)
- {
- switch( *b ) {
- case '<':
- *nl *= 3;
- *nd *= 2;
- hornpipe = 0;
- break;
- case '>':
- *nd *= 2;
- hornpipe = 0;
- break;
- }
- *b = *p;
- switch( *b ) {
- case '>':
- *nl *= 3;
- *nd *= 2;
- return 1;
- case '<':
- *nd *= 2;
- return 1;
- default:
- *b = 0;
- break;
- }
- if( hornpipe ) { // still true then make 1/8 notes broken rithme
- if( *nl == 1 && *nd == 1 ) {
- *b = '>';
- *nl = 3;
- *nd = 2;
- }
- }
- return 0;
- }
- // put p notes in the time q for the next r notes
- static int abc_tuplet(int *nl, int *nd, int p, int q, int r)
- {
- if( !r ) return 0;
- *nl *= q;
- *nd *= p;
- return r - 1;
- }
- // evaluate [Q:"string" n1/m1 n2/m2 n3/m3 n4/m4=bpm "string"]
- // minimal form [Q:"string"]
- // most used form [Q: 1/4=120]
- static int abc_extract_tempo(const char *p, int invoice)
- {
- int nl, nd, ns, in, tempo;
- int nl1=0, nd1, notes, state;
- const char *q;
- in = 0;
- nl = 0;
- nd = 1;
- ns = 120;
- notes = 0;
- state = 0;
- for( q=p; *q; q++ ) {
- if( in ) {
- if( *q=='"' )
- in = 0;
- }
- else {
- if( *q == ']' ) break;
- switch( *q ) {
- case '"':
- in = 1;
- break;
- case '/':
- notes++;
- state = 1;
- nl1 = ns;
- break;
- case '=':
- break;
- default:
- if( isdigit(*q) ) {
- if( state ) {
- q+=abc_getnumber(q,&nd1)-1;
- state = 0;
- nl = nl * nd1 + nl1 * nd;
- nd = nd * nd1;
- }
- else
- q+=abc_getnumber(q,&ns)-1;
- }
- break;
- }
- }
- }
- if( !notes ) {
- nl = 1;
- nd = 4;
- }
- if( !nd ) tempo = 120;
- else tempo = ns * nl * 4 / nd; // mod tempo is really BPM where one B is equal to a quartnote
- if( invoice ) {
- nl = global_tempo_factor;
- nd = global_tempo_divider;
- }
- global_tempo_factor = 1;
- global_tempo_divider = 1;
- while( tempo/global_tempo_divider > 255 )
- global_tempo_divider++;
- tempo /= global_tempo_divider;
- while( tempo * global_tempo_factor < 256 )
- global_tempo_factor++;
- global_tempo_factor--;
- tempo *= global_tempo_factor;
- if( tempo * 3 < 512 ) {
- global_tempo_factor *= 3;
- global_tempo_divider *= 2;
- tempo = (tempo * 3) / 2;
- }
- if( invoice ) {
- if( nl != global_tempo_factor || nd != global_tempo_divider ) {
- ns = (tempo * nl * global_tempo_divider) / (nd * global_tempo_factor);
- if( ns > 31 && ns < 256 ) {
- tempo = ns;
- global_tempo_factor = nl;
- global_tempo_divider = nd;
- }
- else
- abc_message("Failure: inconvenient tempo change in middle of voice (%s)", p);
- }
- }
- return tempo;
- }
- static void abc_set_parts(char **d, char *p)
- {
- int i,j,k,m,n;
- char *q;
- #ifdef NEWMIKMOD
- static MM_ALLOC *h;
- if( *d ) _mmalloc_close(h);
- #else
- if( *d ) free(*d);
- #endif
- *d = 0;
- if( !p ) return;
- for( i=0; p[i] && p[i] != '%'; i++ ) {
- if( !strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZ().0123456789 ",p[i]) ) {
- abc_message("invalid characters in part string scanning P:%s", p);
- return;
- }
- }
- #ifdef NEWMIKMOD
- h = _mmalloc_create("Load_ABC_parts", NULL);
- #endif
- // decode constructs like "((AB)2.(CD)2)3.(AB)E2" to "ABABCDCDABABCDCDABABCDCDABEE"
- // first compute needed storage...
- j=0;
- k=0;
- for( i=0; p[i] && p[i] != '%'; i++ ) {
- if( isupper(p[i]) ) {
- j++;
- }
- if( isdigit(p[i]) ) {
- n=abc_getnumber(p+i,&k);
- if( p[i-1] == ')' )
- j *= k; // never mind multiple parens, just take the worst case
- else
- j += k-1;
- i += n-1;
- }
- }
- q = (char *)_mm_calloc(h, j+1, sizeof(char)); // enough storage for the worst case
- // now copy bytes from p to *d, taking parens and digits in account
- j = 0;
- for( i=0; p[i] && p[i] != '%'; i++ ) {
- if( isdigit(p[i]) || isupper(p[i]) || p[i] == '(' || p[i] == ')' ) {
- if( p[i] == ')' ) {
- for( n=j; n > 0 && q[n-1] != '('; n-- ) ; // find open paren in q
- // q[n+1] to q[j] contains the substring that must be repeated
- if( n > 0 ) {
- for( k = n; k<j; k++ ) q[k-1] = q[k]; // shift to the left...
- j--;
- }
- else
- abc_message("Warning: Unbalanced right parens in P: definition %s",p);
- n = j - n + 1; // number of repeatable characters
- i += abc_getnumber(p+i+1,&k);
- while( k-- > 1 ) {
- for( m=0; m<n; m++ ) {
- q[j] = q[j-n];
- j++;
- }
- }
- continue;
- }
- if( isdigit(p[i]) ) {
- n = abc_getnumber(p+i,&k);
- i += n - 1;
- while( k-- > 1 ) {
- q[j] = q[j-1];
- j++;
- }
- continue;
- }
- q[j] = p[i];
- j++;
- }
- }
- q[j] = '\0';
- // remove any left over parens
- for( i=0; i<j; i++ ) {
- if( q[i] == '(' ) {
- abc_message("Warning: Unbalanced left parens in P: definition %s",p);
- for( k=i; k<j; k++ ) q[k] = q[k+1];
- j--;
- }
- }
- *d = q;
- }
- static void abc_appendpart(ABCHANDLE *h, ABCTRACK *tp, ULONG pt1, ULONG pt2)
- {
- ABCEVENT *e, *ec;
- ULONG dt;
- dt = tp->tail->tracktick - pt1;
- for( e=tp->head; e && e->tracktick <= pt2; e=e->next ) {
- if( e->tracktick >= pt1 ) {
- if( e->flg != 1 || e->cmd == cmdsync || e->cmd == cmdchord ) {
- if( e != tp->tail ) {
- // copy this event at tail
- ec = abc_copy_event(h,e);
- ec->tracktick += dt;
- ec->part = '*';
- tp->tail->next = ec;
- tp->tail = ec;
- }
- }
- }
- }
- abc_add_sync(h, tp, pt2 + dt); // make sure there is progression...
- }
- static ULONG abc_pattracktime(ABCHANDLE *h, ULONG tracktime)
- {
- ABCEVENT *e;
- ULONG dt,et,pt=abcticks(64 * h->speed);
- if(!h || !h->track || !h->track->head ) return 0;
- dt = 0;
- for( e=h->track->head; e && e->tracktick <= tracktime; e=e->next ) {
- if( e->flg == 1 && e->cmd == cmdpartbrk ) {
- et = e->tracktick + dt;
- if( et % pt ) {
- et += pt;
- et /= pt;
- et *= pt;
- dt = et - e->tracktick;
- }
- }
- }
- return (tracktime + dt);
- }
- static int abc_patno(ABCHANDLE *h, ULONG tracktime)
- {
- return modticks(abc_pattracktime(h, tracktime)) / 64 / h->speed;
- }
- static void abc_stripoff(ABCHANDLE *h, ABCTRACK *tp, ULONG tt)
- {
- ABCEVENT *e1, *e2;
- e2 = NULL;
- for( e1 = tp->head; e1 && e1->tracktick <= tt; e1=e1->next )
- e2 = e1;
- if( e2 ) {
- e1 = e2->next;
- tp->tail = e2;
- e2->next = NULL;
- }
- else {
- e1 = tp->tail;
- tp->head = NULL;
- tp->tail = NULL;
- }
- while( e1 ) {
- e2 = e1->next;
- _mm_free(h->trackhandle,e1);
- e1 = e2;
- }
- }
- static void abc_keeptiednotes(ABCHANDLE *h, ULONG fromtime, ULONG totime) {
- ABCTRACK *tp;
- ABCEVENT *e,*n,*f;
- if( totime <= fromtime ) return;
- for( tp=h->track; tp; tp=tp->next ) {
- if( tp->vno ) { // if track is in use...
- n = NULL;
- for( e=tp->head; e && e->tracktick < fromtime; e = e->next )
- if( e->flg != 1 ) n = e; // remember it when it is a note event
- if( n && n->tiednote ) { // we've a candidate to tie over the break
- while( e && e->tracktick < totime ) e=e->next; // skip to other part
- if( e && e->tracktick == totime ) { // if this is on begin row of this part
- f = NULL;
- while( !f && e && e->tracktick == totime ) {
- if( e->flg != 1 ) f = e;
- e = e->next;
- }
- if( f && f->par[note] ) { // pfoeie, we've found a candidate
- if( abs(n->par[note] - f->par[note]) < 3 ) { // undo the note on
- f->flg = 1;
- f->cmd = cmdhide;
- f->lpar = 0;
- }
- }
- }
- }
- }
- }
- }
- static ULONG abc_fade_tracks(ABCHANDLE *h, char *abcparts, ULONG ptt[27])
- {
- ABCTRACK *tp;
- ABCEVENT *e0;
- char *p;
- int vol;
- ULONG pt1,pt2;
- ULONG tt;
- tt = h->track->tail->tracktick;
- for( tp=h->track->next; tp; tp=tp->next ) {
- if( !tp->tail ) abc_add_sync(h, tp, tt); // no empty tracks please...
- if( tp->tail->tracktick > tt ) abc_stripoff(h, tp, tt); // should not happen....
- if( tp->tail->tracktick < tt ) abc_add_sync(h, tp, tt);
- }
- for( tp=h->track; tp; tp=tp->next ) {
- vol = 127;
- e0 = tp->tail;
- if( tp->slidevol != -2 ) {
- tp->slidevol = -2;
- tp->slidevoltime = e0->tracktick;
- }
- tp->mute = 0; // unmute track for safety, notes in a muted track already have zero volume...
- while( vol > 5 ) {
- for( p=abcparts; *p && vol > 5; p++ ) {
- pt1 = ptt[*p-'A'];
- pt2 = ptt[*p-'A'+1];
- abc_appendpart(h, tp, pt1, pt2);
- vol = abc_dynamic_volume(tp, tp->tail->tracktick, 127);
- }
- }
- abc_fade_track(tp,e0);
- }
- return h->track->tail->tracktick;
- }
- static void abc_song_to_parts(ABCHANDLE *h, char **abcparts, BYTE partp[27][2])
- {
- ULONG starttick;
- ABCEVENT *e;
- int i, fading, loop, normal, partno, partsegno, partloop, partcoda, parttocoda, partfine, skip, x, y;
- int vmask[27],nextp[27];
- ULONG ptt[27];
- char buf[256]; // must be enough, mod's cannot handle more than 240 patterns
- char *pfade;
- if( !h || !h->track || !h->track->capostart ) return;
- strcpy(buf,"A"); // initialize our temporary array
- i = 1;
- loop = 1;
- partno = 0;
- partsegno = 0;
- partloop = 0;
- partcoda = -1;
- parttocoda = -1;
- partfine = -1;
- starttick = h->track->capostart->tracktick;
- ptt[0] = starttick;
- vmask[0] = -1;
- nextp[0] = 1;
- for( e=h->track->capostart; e; e=e->next ) {
- if( e->flg == 1 ) {
- switch( e->cmd ) {
- case cmdpartbrk:
- if( e->tracktick > starttick) {
- starttick = e->tracktick; // do not make empty parts
- if( partno < 26 ) {
- partno++;
- ptt[partno] = starttick;
- }
- if( i < 255 ) buf[i++] = partno+'A';
- vmask[partno] = -1;
- nextp[partno] = partno+1;
- }
- break;
- case cmdloop:
- partloop = partno;
- loop = 1; // start counting anew...
- break;
- case cmdvariant:
- vmask[partno] = e->lpar;
- break;
- case cmdjump:
- x = 0;
- fading = 0;
- normal = 0;
- skip = 0;
- pfade = &buf[i];
- switch( e->par[jumptype] ) {
- case jumpfade:
- fading = 1;
- case jumpnormal:
- normal = 1;
- x = partloop;
- loop++;
- break;
- case jumpdsfade:
- fading = 1;
- case jumpdasegno:
- x = partsegno;
- break;
- case jumpdcfade:
- fading = 1;
- case jumpdacapo:
- x = 0;
- break;
- default:
- x = 0;
- break;
- }
- if( vmask[partno] != -1 ) nextp[partno] = x;
- if( partno < 26 ) ptt[partno+1] = e->tracktick; // for handling ties over breaks
- while( x <= partno ) {
- if( skip == 1 && x == partcoda ) skip = 0;
- y = !skip;
- if( y ) {
- if( !normal ) {
- if( x == partfine ) skip = 2;
- if( x == parttocoda ) skip = 1;
- y = !skip;
- }
- if( !(vmask[x] & (1<<loop)) ) y = 0;
- }
- if( y ) {
- if( i < 255 ) buf[i++] = x+'A';
- if( nextp[x] != x + 1 ) loop++;
- x = nextp[x];
- }
- else
- x++;
- }
- if( fading && partno < 26 && i < 255 ) { // add single part with fading tracks
- partno++;
- ptt[partno] = e->tracktick;
- buf[i] = '\0'; // close up pfade with zero byte
- starttick = abc_fade_tracks(h, pfade, ptt);
- buf[i++] = partno+'A';
- partno++;
- ptt[…
Large files files are truncated, but you can click here to view the full file