diff options
author | Rainer Hochecker <fernetmenta@online.de> | 2015-01-07 11:31:14 +0100 |
---|---|---|
committer | Rainer Hochecker <fernetmenta@online.de> | 2015-03-19 16:04:23 +0100 |
commit | 0f6a8829e0894a145362ca9c2bc90ddf9781577a (patch) | |
tree | 524a796c4f570d330e5e0895276db23bc9ebc36a /lib/libmodplug/src/load_abc.cpp | |
parent | 0333bf47a7fb9160a598c8ea32afd21f1947d6d9 (diff) |
paplayer: drop obsolete codecs from lib
Diffstat (limited to 'lib/libmodplug/src/load_abc.cpp')
-rw-r--r-- | lib/libmodplug/src/load_abc.cpp | 5142 |
1 files changed, 0 insertions, 5142 deletions
diff --git a/lib/libmodplug/src/load_abc.cpp b/lib/libmodplug/src/load_abc.cpp deleted file mode 100644 index fd708578bb..0000000000 --- a/lib/libmodplug/src/load_abc.cpp +++ /dev/null @@ -1,5142 +0,0 @@ -/* - - 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> -#include "stdafx.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; - uint32_t tracktick; - union { - uint8_t par[6]; - struct { - uint8_t flg; - uint8_t cmd; - uint32_t lpar; // for variant selections, bit pattern - }; - }; - uint8_t part; - uint8_t tiednote; -} ABCEVENT; - -typedef struct _ABCTRACK -{ - struct _ABCTRACK *next; - ABCEVENT *head; - ABCEVENT *tail; - ABCEVENT *capostart; - ABCEVENT *tienote; - int transpose; - int octave_shift; - uint32_t slidevoltime; // for crescendo and diminuendo - int slidevol; // -2:fade away, -1:diminuendo, 0:none, +1:crescendo - uint8_t vno; // 0 is track is free for use, from previous song in multi-songbook - uint8_t vpos; // 0 is main voice, other is subtrack for gchords, gchords or drumnotes - uint8_t tiedvpos; - uint8_t mute; - uint8_t chan; // 10 is percussion channel, any other is melodic channel - uint8_t volume; - uint8_t instr; // current instrument for this track - uint8_t 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; - uint8_t 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 - uint32_t 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; - uint32_t tracktime; -} ABCHANDLE; - -static int global_voiceno, global_octave_shift, global_tempo_factor, global_tempo_divider; -static char global_part; -static uint32_t 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, uint32_t tracktime); -static void abc_add_setjumploop(ABCHANDLE *h, ABCTRACK *tp, uint32_t tracktime, ABCEVENT_JUMPTYPE j); -static uint32_t abc_pattracktime(ABCHANDLE *h, uint32_t tracktime); -static int abc_patno(ABCHANDLE *h, uint32_t tracktime); - -#ifndef HAVE_SETENV -static void setenv(const char *name, const char *value, int overwrite) -{ - int len = strlen(name)+1+strlen(value)+1; - char *str = (char *)alloca(len); - sprintf(str, "%s=%s", name, value); - putenv(str); -} -#endif - - -static int abc_isvalidchar(unsigned char c) { - return(isalpha(c) || isdigit(c) || isspace(c) || c == '%' || c == ':'); -} - - -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 uint32_t modticks(uint32_t abcticks) -{ - return abcticks / RESOLUTION; -} - -static uint32_t abcticks(uint32_t modticks) -{ - return modticks * RESOLUTION; -} - -static uint32_t notelen_notediv_to_ticks(int speed, int len, int div) -{ - uint32_t 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) -#undef _mm_free -#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, uint32_t 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, uint32_t 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, uint32_t 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, uint32_t 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, uint32_t 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, uint32_t 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; - uint32_t 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; - uint32_t 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; - uint32_t 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, uint32_t 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, uint32_t 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, uint32_t 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, uint32_t tracktime, int vol) -{ - uint32_t 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, uint32_t 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, uint32_t 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, uint32_t 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, uint32_t 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, uint32_t 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, uint32_t 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, uint32_t 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, uint32_t 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, uint32_t 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, uint32_t 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, uint32_t 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, uint32_t 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, uint32_t pt1, uint32_t pt2) -{ - ABCEVENT *e, *ec; - uint32_t 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 uint32_t abc_pattracktime(ABCHANDLE *h, uint32_t tracktime) -{ - ABCEVENT *e; - uint32_t 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, uint32_t tracktime) -{ - return modticks(abc_pattracktime(h, tracktime)) / 64 / h->speed; -} - -static void abc_stripoff(ABCHANDLE *h, ABCTRACK *tp, uint32_t 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, uint32_t fromtime, uint32_t 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 uint32_t abc_fade_tracks(ABCHANDLE *h, char *abcparts, uint32_t ptt[27]) -{ - ABCTRACK *tp; - ABCEVENT *e0; - char *p; - int vol; - uint32_t pt1, pt2; - uint32_t 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]) -{ - uint32_t starttick; - ABCEVENT *e; - int i, fading, loop, normal, partno, partsegno, partloop, partcoda, parttocoda, partfine, skip, x, y; - int vmask[27],nextp[27]; - uint32_t 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[partno] = starttick; - buf[i++] = partno+'A'; // one extra to throw away... - e = h->track->tail; // this is the edge of the world captain... - } - break; - case cmdtocoda: - parttocoda = partno; - break; - case cmdcoda: - partcoda = partno; - break; - case cmdfine: - partfine = partno; - break; - case cmdsegno: - partsegno = partno; - break; - } - } - e->part = partno+'a'; // small caps for generated parts... - } - i--; // strip off last partno - if( partno > 0 ) partno--; - buf[i] = '\0'; - if( i > 1 ) { - for( i=1; buf[i]; i++ ) { - if( buf[i] != buf[i-1] + 1 ) { - x = buf[i-1] - 'A'; - y = buf[i] - 'A'; - abc_keeptiednotes(h, ptt[x+1], ptt[y]); - } - } - } - starttick = h->track->tail->tracktick; - ptt[partno+1] = starttick; - for( i=0; i<=partno; i++ ) { - partp[i][0] = abc_patno(h, ptt[i]); - partp[i][1] = abc_patno(h, ptt[i+1]); - } - // calculate end point of last part - starttick = abc_pattracktime(h, starttick); - if( starttick % abcticks(64 * h->speed) ) - partp[partno][1]++; - abc_set_parts(abcparts, buf); -} - -// ===================================================================================== -static char *abc_fgets(MMFILE *mmfile, char buf[], unsigned int bufsz) -// ===================================================================================== -{ - if( mmfeof(mmfile) ) return NULL; - mmfgets(buf,bufsz,mmfile); - return buf; -} - -// ===================================================================================== -static char *abc_fgetbytes(MMFILE *mmfile, char buf[], unsigned int bufsz) -// ===================================================================================== -{ - unsigned int i; - long pos; - if( mmfeof(mmfile) ) return NULL; - for( i=0; i<bufsz-2; i++ ) { - buf[i] = (char)mmfgetc(mmfile); - if( buf[i] == '\n' ) break; - if( buf[i] == '\r' ) { - pos = mmftell(mmfile); - if( mmfgetc(mmfile) != '\n' ) mmfseek(mmfile, pos, SEEK_SET); - buf[i] = '\n'; - break; - } - } - if( buf[i] == '\n' ) i++; - buf[i] = '\0'; - return buf; -} - -static void abc_substitute(ABCHANDLE *h, char *target, char *s) -{ - char *p, *q; - int i; - int l = strlen(target); - int n = strlen(s); - while( (p=strstr(h->line, target)) ) { - if( (i=strlen(h->line)) + n - l >= (int)h->len ) { - h->line = (char *)_mm_recalloc(h->allochandle, h->line, h->len<<1, sizeof(char)); - h->len <<= 1; - p=strstr(h->line, target); - } - if( n > l ) { - for( q=&h->line[i]; q>p; q-- ) q[n-l] = q[0]; - for( q=s; *q; q++ ) *p++ = *q; - } - else { - strcpy(p,s); - strcat(p,p+l); - } - } -} - -static void abc_preprocess(ABCHANDLE *h, ABCMACRO *m) -{ - int i, j, k, l, a, b; - char t[32]; - char s[200],*p; - if( m->n ) { - k = m->n - m->name; - for( i=0; i<14; i++ ) { - strncpy(t, m->name, 32); - t[k] = "CDEFGABcdefgab"[i]; - l = strlen(m->subst); - p = s; - for( j=0; j<l; j++ ) { - a = m->subst[j]; - if( a > 'g' && islower(a) ) { - b = a - 'n'; - a = "CDEFGABCDEFGABcdefgabcdefgab"[i+b+7]; - *p++ = a; - if( i+b < 0 ) - *p++ = ','; - if( i+b > 13 ) - *p++ = '\''; - } - else *p++ = a; - } - *p = '\0'; - abc_substitute(h, t, s); - } - } - else - abc_substitute(h, m->name, m->subst); -} - -static char *abc_gets(ABCHANDLE *h, MMFILE *mmfile) -{ - int i; - ABCMACRO *mp; - if( !h->len ) { - h->len = 64; // initial line size, adequate for most abc's - h->line = (char *)_mm_calloc(h->allochandle, h->len, sizeof(char)); - } - if( abc_fgetbytes(mmfile, h->line, h->len) ) { - while( (i=strlen(h->line)) > (int)(h->len - 3) ) { - // line too short, double it - h->line = (char *)_mm_recalloc(h->allochandle, h->line, h->len<<1, sizeof(char)); - if( h->line[i-1] != '\n' ) - abc_fgetbytes(mmfile, &h->line[i], h->len); - h->len <<= 1; - } - h->line[i-1] = '\0'; // strip off newline - for( mp=h->macro; mp; mp=mp->next ) - abc_preprocess(h,mp); - return h->line; - } - return NULL; -} - -static int abc_parse_decorations(ABCHANDLE *h, ABCTRACK *tp, const char *p) -{ - int vol=0; - if( !strncmp(p,"mp",2) ) vol = 75; - if( !strncmp(p,"mf",2) ) vol = 90; - if( !strncmp(p,"sfz",3) ) vol = 100; - if( *p == 'p' ) { - vol = 60; - while( *p++ == 'p' ) vol -= 15; - if( vol < 1 ) vol = 1; - } - if( *p == 'f' ) { - vol = 105; - while( *p++ == 'f' ) vol += 15; - if( vol > 135 ) vol = 127; // ffff - if( vol > 127 ) vol = 125; // fff - } - if( vol ) { - tp->volume = vol; - if( tp == h->track ) { // copy volume over to all voice tracks - for( ; tp; tp=tp->next ) { - if( tp->vpos == 0 || tp->vpos > DRONEPOS2 ) tp->volume = vol; - } - tp = h->track; - } - } - return tp->volume; -} - -// ===================================================================================== -#ifdef NEWMIKMOD -BOOL ABC_Test(MMSTREAM *mmfile) -#else -BOOL CSoundFile::TestABC(const BYTE *lpStream, DWORD dwMemLength) -#endif -// ===================================================================================== -{ - char id[128]; - bool hasK = false, hasX = false; - // scan file for first K: line (last in header) -#ifdef NEWMIKMOD - _mm_fseek(mmfile,0,SEEK_SET); - while(abc_fgets(mmfile,id,128)) { -#else - MMFILE mmfile; - mmfile.mm = (char *)lpStream; - mmfile.sz = dwMemLength; - mmfseek(&mmfile,0,SEEK_SET); - while(abc_fgets(&mmfile,id,128)) { -#endif - if (id[0] == 0) continue; // blank line. - if (id[0] == '%' && id[1] != '%') continue; // comment line. - - if (!abc_isvalidchar(id[0]) || !abc_isvalidchar(id[1])) { - return(0); // probably not an ABC. - } - if(id[0]=='K' - && id[1]==':' - && (isalpha(id[2]) || isspace(id[2])) ) hasK = true; - if (id[0]=='X' - && id[1]== ':' - && (abc_isvalidchar(id[2])) ) hasX = true; - if (hasK && hasX) { return 1; printf("valid\n"); } - } - return 0; -} - -// ===================================================================================== -static ABCHANDLE *ABC_Init(void) -{ - ABCHANDLE *retval; - char *p; - char buf[10]; -#ifdef NEWMIKMOD - MM_ALLOC *allochandle; - - allochandle = _mmalloc_create("Load_ABC", NULL); - retval = (ABCHANDLE *)_mm_calloc(allochandle, 1,sizeof(ABCHANDLE)); - if( !retval ) return NULL; - retval->allochandle = allochandle; - allochandle = _mmalloc_create("Load_ABC_macros", NULL); - retval->macrohandle = allochandle; - allochandle = _mmalloc_create("Load_ABC_tracks", NULL); - retval->trackhandle = allochandle; -#else - retval = (ABCHANDLE *)calloc(1,sizeof(ABCHANDLE)); - if( !retval ) return NULL; -#endif - retval->track = NULL; - retval->macro = NULL; - retval->umacro = NULL; - retval->beatstring = NULL; - retval->pickrandom = 0; - retval->len = 0; - retval->line = NULL; - strcpy(retval->gchord, ""); - retval->barticks = 0; - p = getenv(ABC_ENV_NORANDOMPICK); - if( p ) { - if( isdigit(*p) ) - retval->pickrandom = atoi(p); - if( *p == '-' ) { -#ifdef NEWMIKMOD - retval->pickrandom = atoi(p+1); - sprintf(buf,"-%ld",retval->pickrandom+1); -#else - retval->pickrandom = atoi(p+1)-1; // xmms preloads the file - sprintf(buf,"-%ld",retval->pickrandom+2); -#endif - setenv(ABC_ENV_NORANDOMPICK, buf, 1); - } - } - else { - srandom((unsigned int)time(0)); // initialize random generator with seed - retval->pickrandom = 1+(int)(10000.0*random()/(RAND_MAX+1.0)); - // can handle pickin' from songbooks with 10.000 songs -#ifdef NEWMIKMOD - sprintf(buf,"-%ld",retval->pickrandom+1); // next in sequence -#else - sprintf(buf,"-%ld",retval->pickrandom); // xmms preloads the file -#endif - setenv(ABC_ENV_NORANDOMPICK, buf, 1); - } - return retval; -} - -#ifndef NEWMIKMOD -static void ABC_CleanupTrack(ABCTRACK *tp) -{ - ABCEVENT *ep, *en; - if( tp ) { - for( ep=tp->head; ep; ep = en ) { - en=ep->next; - free(ep); - } - tp->head = NULL; - } -} - -static void ABC_CleanupMacro(ABCMACRO *m) -{ - if( m->name ) - free(m->name); - if( m->subst ) - free(m->subst); - free(m); -} -#endif - -// ===================================================================================== -static void ABC_CleanupTracks(ABCHANDLE *handle) -// ===================================================================================== -{ -#ifdef NEWMIKMOD - if(handle && handle->trackhandle) { - _mmalloc_close(handle->trackhandle); - handle->trackhandle = 0; - } -#else - ABCTRACK *tp, *tn; - if(handle) { - for( tp=handle->track; tp; tp = tn ) { - tn=tp->next; - ABC_CleanupTrack(tp); - } - handle->track = NULL; - } -#endif -} - -// ===================================================================================== -static void ABC_CleanupMacros(ABCHANDLE *handle) -// ===================================================================================== -{ -#ifdef NEWMIKMOD - if(handle && handle->macrohandle) { - _mmalloc_close(handle->macrohandle); - handle->macrohandle = 0; - } -#else - ABCMACRO *mp, *mn; - if(handle) { - for( mp=handle->macro; mp; mp = mn ) { - mn=mp->next; - ABC_CleanupMacro(mp); - } - for( mp=handle->umacro; mp; mp = mn ) { - mn=mp->next; - ABC_CleanupMacro(mp); - } - handle->macro = NULL; - handle->umacro = NULL; - } -#endif -} - -// ===================================================================================== -static void ABC_Cleanup(ABCHANDLE *handle) -// ===================================================================================== -{ -#ifdef NEWMIKMOD - if(handle && handle->allochandle) { -#else - if(handle) { -#endif - ABC_CleanupMacros(handle); - ABC_CleanupTracks(handle); -#ifdef NEWMIKMOD - _mmalloc_close(handle->allochandle); - handle->allochandle = 0; - handle->len = 0; -#else - if( handle->line ) - free(handle->line); - if( handle->beatstring ) - free(handle->beatstring); - free(handle); -#endif - } -} - -static int abc_is_global_event(ABCEVENT *e) -{ - return e->flg == 1 && (e->cmd == cmdtempo || e->cmd == cmdpartbrk); -} - -static ABCEVENT *abc_next_global(ABCEVENT *e) -{ - for( ; e && !abc_is_global_event(e); e=e->next ) ; - return e; -} - -static ABCEVENT *abc_next_note(ABCEVENT *e) -{ - for( ; e && e->flg == 1; e=e->next ) ; - return e; -} - -// ============================================================================= -#ifdef NEWMIKMOD -static void ABC_ReadPatterns(UNIMOD *of, ABCHANDLE *h, int numpat) -// ============================================================================= -{ - int pat,row,i,ch,trillbits; - BYTE n,ins,vol; - ABCTRACK *t; - ABCEVENT *e, *en, *ef, *el; - uint32_t tt1, tt2; - UNITRK_EFFECT eff; - - // initialize start points of event list in tracks - for( t = h->track; t; t = t->next ) t->capostart = t->head; - trillbits = 0; // trill effect admininstration: one bit per channel, max 32 channnels - for( pat = 0; pat < numpat; pat++ ) { - utrk_reset(of->ut); - for( row = 0; row < 64; row++ ) { - tt1 = abcticks((pat * 64 + row ) * h->speed); - tt2 = tt1 + abcticks(h->speed); - ch = 0; - for( e=abc_next_global(h->track->capostart); e && e->tracktick < tt2; e=abc_next_global(e->next) ) { - if( e && e->tracktick >= tt1 ) { // we have a tempo event in this row - switch( e->cmd ) { - case cmdtempo: - eff.effect = UNI_GLOB_TEMPO; - eff.param.u = e->lpar; - eff.framedly = UFD_RUNONCE; - utrk_write_global(of->ut, &eff, PTMEM_TEMPO); - break; - case cmdpartbrk: - eff.effect = UNI_GLOB_PATBREAK; - eff.param.u = 0; - eff.framedly = UFD_RUNONCE; - utrk_write_global(of->ut, &eff, UNIMEM_NONE); - break; - } - } - } - for( t = h->track; t; t = t->next ) { - for( e=abc_next_note(t->capostart); e && e->tracktick < tt1; e=abc_next_note(e->next) ) - t->capostart = e; - i = 0; - ef = NULL; - en = e; - el = e; - for( ; e && e->tracktick < tt2; e=abc_next_note(e->next) ) { // we have a note event in this row - t->capostart = e; - i++; - if( e->par[volume] ) { - if( !ef ) ef = e; - el = e; - } - } - if( i ) { - trillbits &= ~(1<<ch); - utrk_settrack(of->ut, ch); - if( i == 1 || ef == el || !ef ) { // only one event in this row - if( ef ) e = ef; - else e = en; - el = t->capostart; - i = e->par[note] + ((e->par[octave])*12); - if( t->chan == 10 ) { - n = pat_gm_drumnote(i) + 23; - ins = pat_gmtosmp(pat_gm_drumnr(i)); - } - else { - n = pat_modnote(i); - ins = e->par[smpno]; - } - eff.framedly = modticks(e->tracktick - tt1); - vol = e->par[volume]; - if( e->par[effect] == accent ) { - vol += vol / 10; - if( vol > 127 ) vol = 127; - } - if (vol <= 0) {} - else if( el->par[volume] == 0 ) { - eff.framedly = modticks(el->tracktick - tt1); - eff.param.u = 0; - eff.param.byte_a = n; - eff.param.byte_b = ins; - eff.effect = UNI_NOTEKILL; - utrk_write_local(of->ut, &eff, UNIMEM_NONE); - } - else { - switch( e->par[effect] ) { - case trill: - eff.effect = UNI_VIBRATO_DEPTH; - eff.param.u = 12; // depth 1.5 - utrk_write_local(of->ut, &eff, PTMEM_VIBRATO_DEPTH); - eff.effect = UNI_VIBRATO_SPEED; - eff.param.u = 48; // speed 12 - utrk_write_local(of->ut, &eff, PTMEM_VIBRATO_SPEED); - trillbits |= (1<<ch); - break; - case bow: - eff.effect = UNI_PITCHSLIDE; - eff.framedly = (h->speed/2)|UFD_RUNONCE; - eff.param.s = 2; - utrk_write_local(of->ut, &eff, (e->par[effoper])? PTMEM_PITCHSLIDEUP: PTMEM_PITCHSLIDEDN); - break; - default: - break; - } - if( eff.framedly ) { - eff.param.u = 0; - eff.param.byte_a = n; - eff.param.byte_b = ins; - eff.effect = UNI_NOTEDELAY; - utrk_write_local(of->ut, &eff, UNIMEM_NONE); - } - } - utrk_write_inst(of->ut, ins); - utrk_write_note(of->ut, n); // <- normal note - pt_write_effect(of->ut, 0xc, vol); - } - else { - // two notes in one row, use FINEPITCHSLIDE runonce effect - // start first note on first tick and framedly runonce on seconds note tick - // use volume and instrument of last note - if( t->chan == 10 ) { - i = el->par[note] + ((el->par[octave])*12); - n = pat_gm_drumnote(i) + 23; - ins = pat_gmtosmp(pat_gm_drumnr(i)); - i = n; // cannot change instrument here.. - } - else { - i = ef->par[note] + ((ef->par[octave])*12); - n = pat_modnote(i); - ins = el->par[smpno]; - i = pat_modnote(el->par[note] + ((el->par[octave])*12)); - } - vol = el->par[volume]; - eff.effect = UNI_PITCHSLIDE; - eff.framedly = modticks(el->tracktick - tt1)|UFD_RUNONCE; - eff.param.s = ((i > n)?i-n:n-i); - utrk_write_inst(of->ut, ins); - utrk_write_note(of->ut, n); // <- normal note - pt_write_effect(of->ut, 0xc, vol); - utrk_write_local(of->ut, &eff, (i > n)? PTMEM_PITCHSLIDEUP: PTMEM_PITCHSLIDEDN); - } - } - else { // no new notes, keep on trilling... - if( trillbits & (1<<ch) ) { - utrk_settrack(of->ut, ch); - eff.effect = UNI_VIBRATO_DEPTH; - eff.param.u = 12; // depth 1.5 - utrk_write_local(of->ut, &eff, PTMEM_VIBRATO_DEPTH); - eff.effect = UNI_VIBRATO_SPEED; - eff.param.u = 60; // speed 15 - utrk_write_local(of->ut, &eff, PTMEM_VIBRATO_SPEED); - } - } - ch++; - } - utrk_newline(of->ut); - } - if(!utrk_dup_pattern(of->ut,of)) return; - } -} - -#else - -static int ABC_ReadPatterns(MODCOMMAND *pattern[], WORD psize[], ABCHANDLE *h, int numpat, int channels) -// ===================================================================================== -{ - int pat,row,i,ch,trillbits; - BYTE n,ins,vol; - ABCTRACK *t; - ABCEVENT *e, *en, *ef, *el; - uint32_t tt1, tt2; - MODCOMMAND *m; - int patbrk, tempo; - if( numpat > MAX_PATTERNS ) numpat = MAX_PATTERNS; - - // initialize start points of event list in tracks - for( t = h->track; t; t = t->next ) t->capostart = t->head; - trillbits = 0; // trill effect admininstration: one bit per channel, max 32 channnels - for( pat = 0; pat < numpat; pat++ ) { - pattern[pat] = CSoundFile::AllocatePattern(64, channels); - if( !pattern[pat] ) return 0; - psize[pat] = 64; - for( row = 0; row < 64; row++ ) { - tt1 = abcticks((pat * 64 + row ) * h->speed); - tt2 = tt1 + abcticks(h->speed); - ch = 0; - tempo = 0; - patbrk = 0; - for( e=abc_next_global(h->track->capostart); e && e->tracktick < tt2; e=abc_next_global(e->next) ) { - if( e && e->tracktick >= tt1 ) { // we have a tempo event in this row - switch( e->cmd ) { - case cmdtempo: - tempo = e->lpar; - break; - case cmdpartbrk: - patbrk = 1; - break; - } - } - } - for( t = h->track; t; t = t->next ) { - for( e=abc_next_note(t->capostart); e && e->tracktick < tt1; e=abc_next_note(e->next) ) ; - i = 0; - ef = NULL; - en = e; - el = e; - for( ; e && e->tracktick < tt2; e=abc_next_note(e->next) ) { // we have a note event in this row - t->capostart = e; - i++; - if( e->par[volume] ) { - if( !ef ) ef = e; - el = e; - } - } - m = &pattern[pat][row * channels + ch]; - m->param = 0; - m->command = CMD_NONE; - if( i ) { - trillbits &= ~(1<<ch); - if( i == 1 || ef == el || !ef ) { // only one event in this row - if( ef ) e = ef; - else e = en; - el = t->capostart; - i = e->par[note] + ((e->par[octave])*12); - if( t->chan == 10 ) { - n = pat_gm_drumnote(i) + 23; - ins = pat_gmtosmp(pat_gm_drumnr(i)); - } - else { - n = pat_modnote(i); - ins = e->par[smpno]; - } - vol = e->par[volume]/2; - if( e->par[volume] > 0 ) { - if( e->par[effect] == accent ) vol += vol / 20; - if( vol > 64 ) vol = 64; - if( el->par[volume] == 0 ) { // note cut - m->param = el->tracktick - tt1; - m->command = CMD_S3MCMDEX; - m->param |= 0xC0; - } - else { - switch( e->par[effect] ) { - case trill: - m->command = CMD_VIBRATO; - m->param = 0xC2; // speed 12 depth 2 - trillbits |= (1<<ch); - break; - case bow: - m->command = CMD_XFINEPORTAUPDOWN; - m->param |= (e->par[effoper])? 0x12: 0x22; - break; - default: - m->param = modticks(e->tracktick - tt1); - if( m->param ) { // note delay - m->command = CMD_S3MCMDEX; - m->param |= 0xD0; - } - break; - } - } - } - m->instr = ins; - m->note = n; // <- normal note - m->volcmd = VOLCMD_VOLUME; - m->vol = vol; - } - else { - // two notes in one row, use FINEPITCHSLIDE runonce effect - // start first note on first tick and framedly runonce on seconds note tick - // use volume and instrument of last note - if( t->chan == 10 ) { - i = el->par[note] + ((el->par[octave])*12); - n = pat_gm_drumnote(i) + 23; - ins = pat_gmtosmp(pat_gm_drumnr(i)); - i = n; // cannot change instrument here.. - } - else { - i = ef->par[note] + ((ef->par[octave])*12); - n = pat_modnote(i); - ins = el->par[smpno]; - i = pat_modnote(el->par[note] + ((el->par[octave])*12)); - } - vol = el->par[volume]/2; - if( vol > 64 ) vol = 64; - m->instr = ins; - m->note = n; // <- normal note - m->volcmd = VOLCMD_VOLUME; - m->vol = vol; - m->param = ((i > n)?i-n:n-i); - if( m->param < 16 ) { - if( m->param ) { - m->command = CMD_XFINEPORTAUPDOWN; - m->param |= (i > n)? 0x10: 0x20; - } - else { // retrigger same note... - m->command = CMD_RETRIG; - m->param = modticks(el->tracktick - tt1); - } - } - else - m->command = (i > n)? CMD_PORTAMENTOUP: CMD_PORTAMENTODOWN; - } - } - else { // no new notes, keep on trilling... - if( trillbits & (1<<ch) ) { - m = &pattern[pat][row * channels + ch]; - m->command = CMD_VIBRATO; - m->param = 0; // inherited from first effect - m->instr = 0; - m->note = 0; - m->volcmd = 0; - m->vol = 0; - } - } - if( m->param == 0 && m->command == CMD_NONE ) { - if( tempo ) { - m->command = CMD_TEMPO; - m->param = tempo; - tempo = 0; - } - else { - if( patbrk ) { - m->command = CMD_PATTERNBREAK; - patbrk = 0; - } - } - } - ch++; - } - if( tempo || patbrk ) return 1; - } - } - return 0; -} - -#endif - -static int ABC_Key(const char *p) -{ - int i,j; - char c[8]; - const char *q; - while( isspace(*p) ) p++; - i = 0; - q = p; - for( i=0; i<8 && *p && *p != ']'; p++ ) { - if( isspace(*p) ) { - while( isspace(*p) ) p++; - if( strncasecmp(p, "min", 3) && strncasecmp(p, "maj", 3) ) - break; - } - c[i] = *p; - i++; - } - c[i] = '\0'; - if( !strcmp(c,"Hp") || !strcmp(c,"HP") ) // highland pipes - strcpy(c,"Bm"); // two sharps at c and f - if( !strcasecmp(c+1, "minor") ) i=2; - if( !strcasecmp(c+2, "minor") ) i=3; - if( !strcasecmp(c+1, "major") ) i=1; - if( !strcasecmp(c+2, "major") ) i=2; - if( !strcasecmp(c+1, "min") ) i=2; - if( !strcasecmp(c+2, "min") ) i=3; - if( !strcasecmp(c+1, "maj") ) i=1; - if( !strcasecmp(c+2, "maj") ) i=2; - for( ; i<6; i++ ) - c[i] = ' '; - c[i] = '\0'; - for( i=0; keySigs[i]; i++ ) { - for( j=10; j<46; j+=6 ) - if( !strncasecmp(keySigs[i]+j, c, 6) ) - return i; - } - abc_message("Failure: Unrecognised K: field %s", q); - return 7; -} - -static char *abc_skip_word(char *p) -{ - while( isspace(*p) ) p++; - while( *p && !isspace(*p) && *p != ']') p++; - while( isspace(*p) ) p++; - return p; -} - -static uint32_t abc_tracktime(ABCTRACK *tp) -{ - uint32_t tracktime; - if( tp->tail ) tracktime = tp->tail->tracktick; - else tracktime = 0; - if( tracktime < global_songstart ) - tracktime = global_songstart; - return tracktime; -} - -static void abc_addchordname(const char *s, int len, const int *notes) -// adds chord name and note set to list of known chords -{ - int i, j; - if(strlen(s) > 7) { - abc_message("Failure: Chord name cannot exceed 7 characters, %s", s); - return; - } - if(len > 6) { - abc_message("Failure: Named chord cannot have more than 6 notes, %s", s); - return; - } - for( i=0; i < chordsnamed; i++ ) { - if(strcmp(s, chordname[i]) == 0) { - /* change chord */ - chordlen[i] = len; - for(j = 0; j < len; j++) chordnotes[i][j] = notes[j]; - return; - } - } - if(chordsnamed > MAXCHORDNAMES - 1) - abc_message("Failure: Too many Guitar Chord Names used, %s", s); - else { - strcpy(chordname[chordsnamed], s); - chordlen[chordsnamed] = len; - for(j = 0; j < len; j++) chordnotes[chordsnamed][j] = notes[j]; - chordsnamed++; - } -} - -static void abc_setup_chordnames() -// set up named guitar chords -{ - static const int list_Maj[3] = { 0, 4, 7 }; - static const int list_m[3] = { 0, 3, 7 }; - static const int list_7[4] = { 0, 4, 7, 10 }; - static const int list_m7[4] = { 0, 3, 7, 10 }; - static const int list_maj7[4] = { 0, 4, 7, 11 }; - static const int list_M7[4] = { 0, 4, 7, 11 }; - static const int list_6[4] = { 0, 4, 7, 9 }; - static const int list_m6[4] = { 0, 3, 7, 9 }; - static const int list_aug[3] = { 0, 4, 8 }; - static const int list_plus[3] = { 0, 4, 8 }; - static const int list_aug7[4] = { 0, 4, 8, 10 }; - static const int list_dim[3] = { 0, 3, 6 }; - static const int list_dim7[4] = { 0, 3, 6, 9 }; - static const int list_9[5] = { 0, 4, 7, 10, 2 }; - static const int list_m9[5] = { 0, 3, 7, 10, 2 }; - static const int list_maj9[5] = { 0, 4, 7, 11, 2 }; - static const int list_M9[5] = { 0, 4, 7, 11, 2 }; - static const int list_11[6] = { 0, 4, 7, 10, 2, 5 }; - static const int list_dim9[5] = { 0, 4, 7, 10, 13 }; - static const int list_sus[3] = { 0, 5, 7 }; - static const int list_sus9[3] = { 0, 2, 7 }; - static const int list_7sus[4] = { 0, 5, 7, 10 }; - static const int list_7sus4[4] = { 0, 5, 7, 10 }; - static const int list_7sus9[4] = { 0, 2, 7, 10 }; - static const int list_9sus4[5] = { 0, 5, 10, 14, 19 }; - static const int list_5[2] = { 0, 7 }; - static const int list_13[6] = { 0, 4, 7, 10, 16, 21 }; - - chordsnamed = 0; - abc_addchordname("", 3, list_Maj); - abc_addchordname("m", 3, list_m); - abc_addchordname("7", 4, list_7); - abc_addchordname("m7", 4, list_m7); - abc_addchordname("maj7", 4, list_maj7); - abc_addchordname("M7", 4, list_M7); - abc_addchordname("6", 4, list_6); - abc_addchordname("m6", 4, list_m6); - abc_addchordname("aug", 3, list_aug); - abc_addchordname("+", 3, list_plus); - abc_addchordname("aug7", 4, list_aug7); - abc_addchordname("7+", 4, list_aug7); - abc_addchordname("dim", 3, list_dim); - abc_addchordname("dim7", 4, list_dim7); - abc_addchordname("9", 5, list_9); - abc_addchordname("m9", 5, list_m9); - abc_addchordname("maj9", 5, list_maj9); - abc_addchordname("M9", 5, list_M9); - abc_addchordname("11", 6, list_11); - abc_addchordname("dim9", 5, list_dim9); - abc_addchordname("sus", 3, list_sus); - abc_addchordname("sus9", 3, list_sus9); - abc_addchordname("7sus", 4, list_7sus); - abc_addchordname("7sus4", 4, list_7sus4); - abc_addchordname("7sus9", 4, list_7sus9); - abc_addchordname("9sus4", 5, list_9sus4); - abc_addchordname("5", 2, list_5); - abc_addchordname("13", 6, list_13); -} - -static int abc_MIDI_getnumber(const char *p) -{ - int n; - while( isspace(*p) ) p++; - abc_getnumber(p, &n); - if( n < 0 ) n = 0; - if( n > 127 ) n = 127; - return n; -} - -static int abc_MIDI_getprog(const char *p) -{ - int n; - while( isspace(*p) ) p++; - abc_getnumber(p, &n); - if( n < 1 ) n = 1; - if( n > 128 ) n = 128; - return n; -} - -// MIDI drone <instr0> <pitch1> <pitch2> <vel1> <vel2> -static void abc_MIDI_drone(const char *p, int *gm, int *ptch, int *vol) -{ - int i; - while( isspace(*p) ) p++; - p += abc_getnumber(p, &i); - i++; // adjust for 1..128 - if( i>0 && i < 129 ) - *gm = i; - else - *gm = 71; // bassoon - while( isspace(*p) ) p++; - p += abc_getnumber(p, &i); - if( i>0 && i < 127 ) - ptch[0] = i; - else - ptch[0] = 45; - while( isspace(*p) ) p++; - p += abc_getnumber(p, &i); - if( i>0 && i < 127 ) - ptch[1] = i; - else - ptch[1] = 33; - while( isspace(*p) ) p++; - p += abc_getnumber(p, &i); - if( i>0 && i < 127 ) - vol[0] = i; - else - vol[0] = 80; - while( isspace(*p) ) p++; - p += abc_getnumber(p, &i); - if( i>0 && i < 127 ) - vol[1] = i; - else - vol[1] = 80; -} - -static void abc_chan_to_tracks(ABCHANDLE *h, int tno, int ch) -{ - ABCTRACK *tp; - if( tno>0 && tno<33 ) { - for( tp=h->track; tp; tp=tp->next ) { - if( tp->vno == tno && (tp->vpos < GCHORDBPOS || tp->vpos > DRONEPOS2) ) - tp->chan = ch; - } - } -} - -// %%MIDI channel int1 -// channel numbers are 1-16 -static void abc_MIDI_channel(const char *p, ABCTRACK *tp, ABCHANDLE *h) -{ - int i1, i2; - i1 = tp? tp->vno: 1; - for( ; *p && isspace(*p); p++ ) ; - if( isdigit(*p) ) { - p += abc_getnumber(p, &i2); - if( i2 >= 1 && i2 <= 16 ) - abc_chan_to_tracks(h, i1, i2); // we start at 1 - } -} - -static void abc_instr_to_tracks(ABCHANDLE *h, int tno, int gm) -{ - ABCTRACK *tp; - if( tno>0 && tno<33 && gm>0 && gm<129 ) { - for( tp=h->track; tp; tp=tp->next ) { - if( tp->vno == tno && (tp->vpos < GCHORDBPOS || tp->vpos > DRONEPOS2) ) - tp->instr = gm; - } - } -} - -// %%MIDI program [int1] <int2> -// instrument numbers are 0-127 -static void abc_MIDI_program(const char *p, ABCTRACK *tp, ABCHANDLE *h) -{ - int i1, i2; - i1 = tp? tp->vno: 1; - for( ; *p && isspace(*p); p++ ) ; - if( isdigit(*p) ) { - p += abc_getnumber(p, &i2); - for( ; *p && isspace(*p); p++ ) ; - if( isdigit(*p) ) { - i1 = i2; - p += abc_getnumber(p, &i2); - } - abc_instr_to_tracks(h, i1, i2 + 1); // we start at 1 - } -} - -static void abc_mute_voice(ABCHANDLE *h, ABCTRACK *tp, int m) -{ - ABCTRACK *t; - for( t=h->track; t; t=t->next ) { - if( t->vno == tp->vno ) t->mute = m; - } -} - -// %%MIDI voice [<ID>] [instrument=<integer> [bank=<integer>]] [mute] -// instrument numbers are 1-128 -static void abc_MIDI_voice(const char *p, ABCTRACK *tp, ABCHANDLE *h) -{ - int i1, i2; - for( ; *p && isspace(*p); p++ ) ; - if( strncmp(p,"instrument=",11) && strncmp(p,"mute",4) ) { - tp = abc_locate_track(h, p, 0); - for( ; *p && !isspace(*p); p++ ) ; - for( ; *p && isspace(*p); p++ ) ; - } - i1 = tp? tp->vno: 1; - i2 = 0; - if( !strncmp(p,"instrument=",11) && isdigit(p[11]) ) { - p += 11; - p += abc_getnumber(p, &i2); - for( ; *p && isspace(*p); p++ ) ; - if( !strncmp(p,"bank=",5) && isdigit(p[5]) ) { - for( ; *p && !isspace(*p); p++ ) ; - for( ; *p && isspace(*p); p++ ) ; - } - } - if( tp ) abc_mute_voice(h,tp,0); - if( !strncmp(p,"mute",4) && (p[4]=='\0' || p[4]=='%' || isspace(p[4])) ) { - if( tp ) abc_mute_voice(h,tp,1); - } - abc_instr_to_tracks(h, i1, i2); // starts already at 1 (draft 4.0) -} - -// %%MIDI chordname <string> <int1> <int2> ... <int6> -static void abc_MIDI_chordname(const char *p) -{ - char name[20]; - int i, notes[6]; - - for( ; *p && isspace(*p); p++ ) ; - i = 0; - while ((i < 19) && (*p != ' ') && (*p != '\0')) { - name[i] = *p; - p = p + 1; - i = i + 1; - } - name[i] = '\0'; - if(*p != ' ') { - abc_message("Failure: Bad format for chordname command, %s", p); - } - else { - i = 0; - while ((i <= 6) && isspace(*p)) { - for( ; *p && isspace(*p); p++ ) ; - p += abc_getnumber(p, ¬es[i]); - i = i + 1; - } - abc_addchordname(name, i, notes); - } -} - -// %%MIDI drum <string> <inst 1> ... <inst n> <vol 1> ... <vol n> -// instrument numbers are 0-127 -static int abc_MIDI_drum(const char *p, ABCHANDLE *h) -{ - char *q; - int i,n,m; - while( isspace(*p) ) p++; - if( !strncmp(p,"on",2) && (isspace(p[2]) || p[2] == '\0') ) return 2; - if( !strncmp(p,"off",3) && (isspace(p[3]) || p[3] == '\0') ) return 1; - n = 0; - for( q = h->drum; *p && !isspace(*p); p++ ) { - if( !strchr("dz0123456789",*p) ) break; - *q++ = *p; - if( !isdigit(*p) ) { - if( !isdigit(p[1]) ) *q++ = '1'; - n++; // count the silences too.... - } - } - *q = '\0'; - q = h->drumins; - for( i = 0; i<n; i++ ) { - if( h->drum[i*2] == 'd' ) { - while( isspace(*p) ) p++; - if( !isdigit(*p) ) { - m = 0; - while( !isspace(*p) ) p++; - } - else - p += abc_getnumber(p,&m); - q[i] = m + 1; // we start at 1 - } - else q[i] = 0; - } - q = h->drumvol; - for( i = 0; i<n; i++ ) { - if( h->drum[i*2] == 'd' ) { - while( isspace(*p) ) p++; - if( !isdigit(*p) ) { - m = 0; - while( !isspace(*p) ) p++; - } - else - p += abc_getnumber(p,&m); - q[i] = m; - } - else q[i] = 0; - } - return 0; -} - -// %%MIDI gchord <string> -static int abc_MIDI_gchord(const char *p, ABCHANDLE *h) -{ - char *q; - while( isspace(*p) ) p++; - if( !strncmp(p,"on",2) && (isspace(p[2]) || p[2] == '\0') ) return 2; - if( !strncmp(p,"off",3) && (isspace(p[3]) || p[3] == '\0') ) return 1; - for( q = h->gchord; *p && !isspace(*p); p++ ) { - if( !strchr("fbcz0123456789ghijGHIJ",*p) ) break; - *q++ = *p; - if( !isdigit(*p) && !isdigit(p[1]) ) *q++ = '1'; - } - *q = '\0'; - return 0; -} - -static void abc_metric_gchord(ABCHANDLE *h, int mlen, int mdiv) -{ - switch( 16 * mlen + mdiv ) { - case 0x24: - case 0x44: - case 0x22: - abc_MIDI_gchord("fzczfzcz", h); - break; - case 0x64: - case 0x32: - abc_MIDI_gchord("fzczczfzczcz", h); - break; - case 0x34: - case 0x38: - abc_MIDI_gchord("fzczcz", h); - break; - case 0x68: - abc_MIDI_gchord("fzcfzc", h); - break; - case 0x98: - abc_MIDI_gchord("fzcfzcfzc", h); - break; - case 0xc8: - abc_MIDI_gchord("fzcfzcfzcfzc", h); - break; - default: - if( mlen % 3 == 0 ) - abc_MIDI_gchord("fzcfzcfzcfzcfzcfzcfzcfzcfzc", h); - else - abc_MIDI_gchord("fzczfzczfzczfzczfzczfzczfzcz", h); - if( mdiv == 8 ) h->gchord[mlen*2] = '\0'; - else h->gchord[mlen*4] = '\0'; - break; - } -} - -static void abc_MIDI_legato(const char *p, ABCTRACK *tp) -{ - for( ; *p && isspace(*p); p++ ) ; - if( !strncmp(p,"off",3) ) tp->legato = 0; - else tp->legato = 1; -} - -static void abc_M_field(const char *p, int *mlen, int *mdiv) -{ - if( !strncmp(p,"none",4) ) { - *mlen = 1; - *mdiv = 1; - return; - } - if( !strncmp(p,"C|",2) ) { - *mlen = 2; - *mdiv = 2; - return; - } - if( *p == 'C' ) { - *mlen = 4; - *mdiv = 4; - return; - } - p += abc_getexpr(p,mlen); - sscanf(p," / %d", mdiv); -} - -static int abc_drum_steps(const char *dch) -{ - const char *p; - int i=0; - for( p=dch; *p; p++ ) { - if( isdigit(*p) ) i += *p - '0';; - } - return i; -} - -static void abc_add_drum(ABCHANDLE *h, uint32_t tracktime, uint32_t bartime) -{ - ABCEVENT *e; - ABCTRACK *tp; - uint32_t etime, ctime , rtime, stime; - int i, g, steps, gnote, gsteps, nnum; - steps = abc_drum_steps(h->drum); - ctime = h->barticks; - // look up the last event in tpr drumtrack - tp = abc_locate_track(h, h->tpr->v, DRUMPOS); - e = tp->tail; - etime = e? e->tracktick: bartime; - if( etime > tracktime ) return; - if( etime < bartime ) rtime = h->barticks - ((bartime - etime) % h->barticks); - else rtime = (etime - bartime) % h->barticks; - stime = ctime*steps; - rtime *= steps; - rtime += stime; - gsteps = strlen(h->drum)/2; - g = 0; - while( rtime > stime ) { - rtime -= ctime*(h->drum[g*2+1] - '0'); - if( ++g == gsteps ) g = 0; - } - stime = (tracktime - etime) * steps; - rtime = 0; - while( rtime < stime ) { - gnote = h->drum[g*2]; - i = h->drum[g*2+1] - '0'; - if(gnote=='d') { - tp->instr = pat_gm_drumnr(h->drumins[g]-1); - nnum = pat_gm_drumnote(h->drumins[g]); - abc_add_drumnote(h, tp, etime + rtime/steps, nnum, h->drumvol[g]); - abc_add_noteoff(h,tp,etime + ( rtime + ctime * i )/steps); - } - if( ++g == gsteps ) g = 0; - rtime += ctime * i; - } -} - -static int abc_gchord_steps(const char *gch) -{ - const char *p; - int i=0; - for( p=gch; *p; p++ ) - if( isdigit(*p) ) i += *p - '0'; - return i; -} - -static void abc_add_gchord(ABCHANDLE *h, uint32_t tracktime, uint32_t bartime) -{ - ABCEVENT *e, *c; - ABCTRACK *tp; - uint32_t etime, ctime , rtime, stime; - int i, g, steps, gnote, gcnum, gsteps, nnum, glen; - // look up the last chord event in tpc - c = 0; - for( e = h->tpc->head; e; e = e->next ) - if( e->flg == 1 && e->cmd == cmdchord ) - c = e; - if( !c ) return; - gcnum = c->par[chordnum]; - steps = abc_gchord_steps(h->gchord); - ctime = h->barticks; - etime = 0; - for( i = GCHORDBPOS; i < DRUMPOS; i++ ) { - tp = abc_locate_track(h, h->tpc->v, i); - e = tp->tail; - if( !e ) e = c; - stime = e->tracktick; - if( stime > etime ) etime = stime; - } - if( etime > tracktime ) return; - if( etime < bartime ) rtime = h->barticks - ((bartime - etime) % h->barticks); - else rtime = (etime - bartime) % h->barticks; - stime = ctime * steps; - rtime *= steps; - rtime += stime; - gsteps = strlen(h->gchord); - g = 0; - while( rtime > stime ) { - glen = h->gchord[2*g+1] - '0'; - rtime -= ctime * glen; - if( ++g == gsteps ) g = 0; - } - stime = (tracktime - etime) * steps; - rtime = 0; - while( rtime < stime ) { - gnote = h->gchord[2*g]; - glen = h->gchord[2*g+1] - '0'; - if( ++g == gsteps ) g = 0; - nnum = 0; - switch(gnote) { - case 'b': - tp = abc_locate_track(h, h->tpc->v, GCHORDFPOS); - tp->instr = h->abcbassprog; - nnum = c->par[chordnote]+chordnotes[gcnum][0]+24; - abc_add_chordnote(h, tp, etime + rtime/steps, nnum, h->abcbassvol); - abc_add_noteoff(h,tp,etime + ( rtime + ctime * glen )/steps); - case 'c': - for( i = 1; i < chordlen[gcnum]; i++ ) { - tp = abc_locate_track(h, h->tpc->v, i+GCHORDFPOS); - tp->instr = h->abcchordprog; - nnum = c->par[chordnote]+chordnotes[gcnum][i]+24; - abc_add_chordnote(h, tp, etime + rtime/steps, nnum, h->abcchordvol); - abc_add_noteoff(h,tp,etime + ( rtime + ctime * glen )/steps); - } - rtime += ctime * glen; - break; - case 'f': - tp = abc_locate_track(h, h->tpc->v, GCHORDFPOS); - tp->instr = h->abcbassprog; - nnum = c->par[chordbase]+12; - abc_add_chordnote(h, tp, etime + rtime/steps, nnum, h->abcbassvol); - rtime += ctime * glen; - abc_add_noteoff(h,tp,etime + rtime/steps); - break; - case 'g': - case 'h': - case 'i': - case 'j': - case 'G': - case 'H': - case 'I': - case 'J': - i = toupper(gnote) - 'G'; - nnum = 0; - if( i < chordlen[gcnum] ) { - tp = abc_locate_track(h, h->tpc->v, GCHORDFPOS+i+1); - tp->instr = h->abcchordprog; - nnum = c->par[chordnote]+chordnotes[gcnum][i]+24; - if( isupper(gnote) ) nnum -= 12; - abc_add_chordnote(h, tp, etime + rtime/steps, nnum, h->abcchordvol); - } - rtime += ctime * glen; - if( nnum ) abc_add_noteoff(h,tp,etime + rtime/steps); - break; - case 'z': - rtime += ctime * glen; - break; - } - } -} - -// %%MIDI beat a b c n -// -// controls the way note velocities are selected. The first note in a bar has -// velocity a. Other "strong" notes have velocity b and all the rest have velocity -// c. a, b and c must be in the range 0-128. The parameter n determines which -// notes are "strong". If the time signature is x/y, then each note is given -// a position number k = 0, 1, 2 .. x-1 within each bar. Note that the units for -// n are not the unit note length. If k is a multiple of n, then the note is -// "strong". The volume specifiers !ppp! to !fff! are equivalent to the -// following : -// -// !ppp! = %%MIDI beat 30 20 10 1 -// !pp! = %%MIDI beat 45 35 20 1 -// !p! = %%MIDI beat 60 50 35 1 -// !mp! = %%MIDI beat 75 65 50 1 -// !mf! = %%MIDI beat 90 80 65 1 -// !f! = %%MIDI beat 105 95 80 1 -// !ff! = %%MIDI beat 120 110 95 1 -// !fff! = %%MIDI beat 127 125 110 1 -static void abc_MIDI_beat(ABCHANDLE *h, const char *p) -{ - int i,j; - h->beat[0] = 127; - h->beat[1] = 125; - h->beat[2] = 110; - h->beat[3] = 1; - for( j=0; j<4; j++ ) { - while( isspace(*p) ) p++; - if( *p ) { - p += abc_getnumber(p, &i); - if( i < 0 ) i = 0; - if( i > 127 ) i = 127; - h->beat[j] = i; - } - } - if( h->beat[3] == 0 ) h->beat[3] = 1; // BB Ruud says: do not let you make mad -} - -// -// %%MIDI beatstring <string of f, m and p> -// -// This provides an alternative way of specifying where the strong and weak -// stresses fall within a bar. 'f' means velocity a (normally strong), 'm' -// means velocity b (medium velocity) and 'p' means velocity c (soft velocity). -// For example, if the time signature is 7/8 with stresses on the first, fourth -// and sixth notes in the bar, we could use the following -// -// %%MIDI beatstring fppmpmp -static void abc_MIDI_beatstring(ABCHANDLE *h, const char *p) -{ - while( isspace(*p) ) p++; - if( h->beatstring ) _mm_free(h->allochandle, h->beatstring); - if( strlen(p) ) - h->beatstring = DupStr(h->allochandle,p,strlen(p)+1); - else - h->beatstring = NULL; -} - -static int abc_beat_vol(ABCHANDLE *h, int abcvol, int barpos) -{ - int vol; - if( h->beatstring ) { - vol = (h->beat[2] * 9) / 10; - if( barpos < (int)strlen(h->beatstring) ) { - switch(h->beatstring[barpos]) { - case 'f': - vol = h->beat[0]; - break; - case 'm': - vol = h->beat[1]; - break; - case 'p': - vol = h->beat[2]; - break; - default: - break; - } - } - } - else { - if( (barpos % h->beat[3]) == 0 ) { - if( barpos ) - vol = h->beat[1]; - else - vol = h->beat[0]; - } - else - vol = h->beat[2]; - } - vol *= abcvol; - vol /= 128; - return vol; -} - -static void abc_init_partpat(BYTE partp[27][2]) -{ - int i; - for( i=0; i<27; i++ ) { - partp[i][0] = 0xff; - partp[i][1] = 0; - } -} - -static int abc_partpat_to_orderlist(BYTE partp[27][2], const char *abcparts, ABCHANDLE *h, BYTE **list, int orderlen) -{ - int t, partsused; - const char *p; - BYTE *orderlist = *list; - static int ordersize = 0; - if( *list == NULL ) { - ordersize = 128; - orderlist = (BYTE *)_mm_calloc(h->ho, ordersize, sizeof(BYTE)); - *list = orderlist; - } - if( abcparts ) { - partsused = 0; - for( p = abcparts; *p; p++ ) { - for( t = partp[*p - 'A'][0]; t < partp[*p - 'A'][1]; t++ ) { - if( orderlen == ordersize ) { - ordersize <<= 1; - orderlist = (BYTE *)_mm_recalloc(h->ho, orderlist, ordersize, sizeof(BYTE)); - *list = orderlist; - } - orderlist[orderlen] = t; - orderlen++; - partsused++; - } - } - if( partsused ) return orderlen; - } - // some fool wrote a P: string in the header but didn't use P: in the body - for( t = partp[26][0]; t < partp[26][1]; t++ ) { - if( orderlen == ordersize ) { - ordersize <<= 1; - orderlist = (BYTE *)_mm_recalloc(h->ho, orderlist, ordersize, sizeof(BYTE)); - *list = orderlist; - } - orderlist[orderlen] = t; - orderlen++; - } - return orderlen; -} - -static void abc_globalslide(ABCHANDLE *h, uint32_t tracktime, int slide) -{ - ABCTRACK *tp; - ABCEVENT *e; - int hslide; - hslide = h->track? h->track->slidevol: slide; - for( tp=h->track; tp; tp = tp->next ) { - if( slide ) { - tp->slidevoltime = tracktime; - if( slide == 2 ) - tp->slidevol = 0; - } - if( tp->slidevol > -2 && slide < 2 ) - tp->slidevol = slide; - } - if( h->track && h->track->tail - && hslide != slide && slide == -2 - && h->track->tail->tracktick >= tracktime ) { - // need to update jumptypes in mastertrack from tracktime on... - for( e=h->track->head; e; e=e->next ) { - if( e->flg == 1 && e->cmd == cmdjump && e->tracktick >= tracktime ) { - switch( e->par[jumptype] ) { - case jumpnormal: - case jumpfade: - e->par[jumptype] = jumpfade; - break; - case jumpdacapo: - case jumpdcfade: - e->par[jumptype] = jumpdcfade; - break; - case jumpdasegno: - case jumpdsfade: - e->par[jumptype] = jumpdsfade; - break; - } - } - } - } -} - -static void abc_recalculate_tracktime(ABCHANDLE *h) { - ABCTRACK *ttp; - h->tracktime = 0; - for( ttp=h->track; ttp; ttp=ttp->next ) - if( ttp->tail && ttp->tail->tracktick > h->tracktime ) - h->tracktime = ttp->tail->tracktick; -} - -static void abc_MIDI_command(ABCHANDLE *h, char *p, char delim) { - int t; - // interpret some of the possibilitys - if( !strncmp(p,"bassprog",8) && isspace(p[8]) ) h->abcbassprog = abc_MIDI_getprog(p+8)+1; - if( !strncmp(p,"bassvol",7) && isspace(p[7]) ) h->abcbassvol = abc_MIDI_getnumber(p+7); - if( !strncmp(p,"beat",4) && isspace(p[4]) ) abc_MIDI_beat(h, p+4); - if( !strncmp(p,"beatstring",10) && isspace(p[10]) ) abc_MIDI_beatstring(h, p+4); - if( !strncmp(p,"chordname",9) && isspace(p[9]) ) abc_MIDI_chordname(p+9); - if( !strncmp(p,"chordprog",9) && isspace(p[9]) ) h->abcchordprog = abc_MIDI_getprog(p+9)+1; - if( !strncmp(p,"chordvol",8) && isspace(p[8]) ) h->abcchordvol = abc_MIDI_getnumber(p+8); - if( !strncmp(p,"drone",5) && isspace(p[5]) ) abc_MIDI_drone(p+5, &h->dronegm, h->dronepitch, h->dronevol); - if( !strncmp(p,"droneoff",8) && (p[8]=='\0' || p[8]==delim || isspace(p[8])) ) h->droneon = 0; - if( !strncmp(p,"droneon",7) && (p[7]=='\0' || p[7]==delim || isspace(p[7])) ) h->droneon = 1; - t = h->drumon; - if( !strncmp(p,"drum",4) && isspace(p[4]) ) { - h->drumon = abc_MIDI_drum(p+4, h); - if( h->drumon ) --h->drumon; - else h->drumon = t; - } - if( !strncmp(p,"drumoff",7) && (p[7]=='\0' || p[7]==delim || isspace(p[7])) ) h->drumon = 0; - if( !strncmp(p,"drumon",6) && (p[6]=='\0' || p[6]==delim || isspace(p[6])) ) h->drumon = 1; - if( t != h->drumon ) { - if( h->drumon && !h->tpr ) h->tpr = h->track; - if( h->tpr ) abc_add_drum_sync(h, h->tpr, h->tracktime); // don't start drumming from the beginning of time! - if( h->tpr && !h->drumon ) h->tpr = NULL; - } - t = h->gchordon; - if( !strncmp(p,"gchord",6) && (p[6]=='\0' || p[6]==delim || isspace(p[6])) ) { - h->gchordon = abc_MIDI_gchord(p+6, h); - if( h->gchordon ) --h->gchordon; - else h->gchordon = t; - } - if( !strncmp(p,"gchordoff",9) && (p[9]=='\0' || p[9]==delim || isspace(p[9])) ) h->gchordon = 0; - if( !strncmp(p,"gchordon",8) && (p[8]=='\0' || p[8]==delim || isspace(p[8])) ) h->gchordon = 1; - if( t != h->gchordon ) { - if( h->tpc ) abc_add_gchord_syncs(h, h->tpc, h->tracktime); - } - if( !strncmp(p,"channel",7) && isspace(p[7]) ) - abc_MIDI_channel(p+8, h->tp = abc_check_track(h, h->tp), h); - if( !strncmp(p,"program",7) && isspace(p[7]) ) - abc_MIDI_program(p+8, h->tp = abc_check_track(h, h->tp), h); - if( !strncmp(p,"voice",5) && isspace(p[5]) ) - abc_MIDI_voice(p+6, h->tp = abc_check_track(h, h->tp), h); - if( !strncmp(p,"legato",6) && (p[6]=='\0' || p[6]==delim || isspace(p[6])) ) - abc_MIDI_legato(p+6, h->tp = abc_check_track(h, h->tp)); -} - -// continuate line that ends with a backslash, can't do this in abc_gets because voice lines -// can have comment lines in between that must be parsed properly, for example: -// [V:1] cdef gabc' |\ << continuation backslash -// %%MIDI program 25 -// c'bag fedc | -// informational lines can have this too, so it is rather convoluted code... -static char *abc_continuated(ABCHANDLE *h, MMFILE *mmf, char *p) { - char *pm, *p1, *p2 = 0; - int continued; - pm = p; - while( pm[strlen(pm)-1]=='\\' ) { - p1 = strdup(pm); - if( p2 ) free(p2); - continued = 1; - while( continued ) { - continued = 0; - pm = abc_gets(h, mmf); - if( !pm ) { - abc_message("line not properly continued\n%s", p1); - return p1; - } - while( *pm && isspace(*pm) ) ++pm; - if( !strncmp(pm,"%%",2) ) { - for( p2 = pm+2; *p2 && isspace(*p2); p2++ ) ; - if( !strncmp(p2,"MIDI",4) && (p2[4]=='=' || isspace(p2[4])) ) { - for( p2+=5; *p2 && isspace(*p2); p2++ ) ; - if( *p2 == '=' ) - for( p2+=1; *p2 && isspace(*p2); p2++ ) ; - abc_MIDI_command(h,p2,'%'); - } - continued = 1; - } - } - p2 = (char *)malloc(strlen(p1)+strlen(pm)); - if( !p2 ) { - abc_message("macro line too long\n%s", p1); - return p1; - } - p1[strlen(p1)-1] = '\0'; // strip off the backslash - strcpy(p2,p1); - strcat(p2,pm); - pm = p2; - free(p1); - } - return pm; -} - -// ===================================================================================== -#ifdef NEWMIKMOD -BOOL ABC_Load(ABCHANDLE *h, UNIMOD *of, MMSTREAM *mmfile) -#else -BOOL CSoundFile::ReadABC(const uint8_t *lpStream, DWORD dwMemLength) -#endif -{ - static int avoid_reentry = 0; -#ifdef NEWMIKMOD -#define m_nDefaultTempo of->inittempo -#else - ABCHANDLE *h; - uint32_t numpat; - MMFILE mm, *mmfile; -#endif - uint32_t t; - char *line, *p, *pp, ch, ch0=0; - char barsig[52]; // for propagated accidental key signature within bar - char *abcparts; - uint8_t partpat[27][2], *orderlist; - int orderlen; - enum { NOWHERE, INBETWEEN, INHEAD, INBODY, INSKIPFORX, INSKIPFORQUOTE } abcstate; - ABCEVENT_JUMPTYPE j; - ABCEVENT_X_EFFECT abceffect; - int abceffoper; - int abcxcount=0, abcxwanted=0, abcxnumber=1; - int abckey, abcrate, abcchord, abcvol, abcbeatvol, abcnoslurs, abcnolegato, abcfermata, abcarpeggio, abcto; - int abctempo; - int cnotelen=0, cnotediv=0, snotelen, snotediv, mnotelen, mnotediv, notelen, notediv; - // c for chords, s for standard L: setting, m for M: barlength - int abchornpipe, brokenrithm, tupletp, tupletq, tupletr; - int ktempo; - uint32_t abcgrace=0, bartime, thistime=0; - ABCTRACK *tpd, *ttp; - ABCMACRO *mp; - int mmsp; -#ifdef NEWMIKMOD - MMSTREAM *mmstack[MAXABCINCLUDES]; - h->ho = _mmalloc_create("Load_ABC_ORDERLIST", NULL); -#else - MMFILE *mmstack[MAXABCINCLUDES]; - if( !TestABC(lpStream, dwMemLength) ) return FALSE; - h = ABC_Init(); - if( !h ) return FALSE; - mmfile = &mm; - mm.mm = (char *)lpStream; - mm.sz = dwMemLength; - mm.pos = 0; -#endif - while( avoid_reentry ) sleep(1); - avoid_reentry = 1; - pat_resetsmp(); - pat_init_patnames(); - m_nDefaultTempo = 0; - global_voiceno = 0; - abckey = 0; - h->tracktime = 0; - global_songstart = 0; - h->speed = 6; - abcrate = 240; - global_tempo_factor = 2; - global_tempo_divider = 1; - abctempo = 0; - ktempo = 0; - abceffect = none; - abceffoper = 0; - abcvol = 120; - h->abcchordvol = abcvol; - h->abcbassvol = abcvol; - h->abcchordprog = 25; // acoustic guitar - h->abcbassprog = 33; // acoustic bass - abcparts = 0; - abcnoslurs = 1; - abcnolegato = 1; - abcfermata = 0; - abcarpeggio = 0; - abcto = 0; - snotelen = 0; - snotediv = 0; - mnotelen = 1; - mnotediv = 1; - abchornpipe = 0; - brokenrithm = 0; - tupletp = 0; - tupletq = 0; - tupletr = 0; - h->ktrans = 0; - h->drumon = 0; - h->gchordon = 1; - h->droneon = 0; - h->tracktime = 0; - bartime = 0; - h->tp = NULL; - h->tpc = NULL; - h->tpr = NULL; - tpd = NULL; - h->dronegm = 71; - h->dronepitch[0] = 45; - h->dronepitch[1] = 33; - h->dronevol[0] = 80; - h->dronevol[1] = 80; - abc_new_umacro(h, "v = +downbow+"); - abc_new_umacro(h, "u = +upbow+"); - abc_new_umacro(h, "O = +coda+"); - abc_new_umacro(h, "S = +segno+"); - abc_new_umacro(h, "P = +uppermordent+"); - abc_new_umacro(h, "M = +lowermordent+"); - abc_new_umacro(h, "L = +emphasis+"); - abc_new_umacro(h, "H = +fermata+"); - abc_new_umacro(h, "T = +trill+"); - abc_new_umacro(h, "~ = +roll+"); - abc_setup_chordnames(); - abc_init_partpat(partpat); - abc_MIDI_beat(h, ""); // reset beat array - abc_MIDI_beatstring(h, ""); // reset beatstring - orderlist = NULL; - orderlen = 0; - mmsp = 1; - mmstack[0] = mmfile; - mmfseek(mmfile,0,SEEK_SET); - abcstate = NOWHERE; - if( h->pickrandom ) { - abcstate = INSKIPFORX; - abcxcount = 0; - mmfseek(mmfile,0,SEEK_SET); - while( (line=abc_gets(h, mmfile)) ) { - for( p=line; isspace(*p); p++ ) ; - if( !strncmp(p,"X:",2) ) abcxcount++; - } - if( abcxcount == 0 ) - abcstate = NOWHERE; - else - abcxwanted = (h->pickrandom - 1) % abcxcount; - abcxcount = 0; - mmfseek(mmfile,0,SEEK_SET); - } - while( mmsp > 0 ) { - mmsp--; - while((line=abc_gets(h, mmstack[mmsp]))) { - for( p=line; isspace(*p); p++ ) ; - switch(abcstate) { - case INSKIPFORX: - if( !strncmp(p,"X:",2) ) { - if( abcxcount++ != abcxwanted ) - break; - } - // fall through - case INBETWEEN: - if( !strncmp(p,"X:",2) ) { - abcstate = INHEAD; -#ifdef NEWMIKMOD - of->songname = NULL; -#else - memset(m_szNames[0], 0, 32); -#endif - for( p+=2; isspace(*p); p++ ) ; - abcxnumber = atoi(p); - abchornpipe = 0; - h->droneon = 0; - h->dronegm = 71; - h->dronepitch[0] = 45; - h->dronepitch[1] = 33; - h->dronevol[0] = 80; - h->dronevol[1] = 80; - for( ttp = h->track; ttp; ttp=ttp->next ) { - ttp->vno = 0; // mark track unused - ttp->capostart = NULL; - } - h->tp = NULL; // forget old voices - h->tpc = NULL; - h->tpr = NULL; - global_voiceno = 0; - abc_set_parts(&abcparts, 0); - abcgrace = 0; - h->ktrans = 0; - ktempo = 0; - h->gchordon = 1; - h->drumon = 0; - global_songstart = h->tracktime; - abc_MIDI_beat(h, ""); // reset beat array - abc_MIDI_beatstring(h, ""); // reset beatstring - strcpy(h->gchord, ""); // reset gchord string - abcnolegato = 1; // reset legato switch - } - break; - case NOWHERE: - if( p[0] != '\0' && p[1] == ':' ) { - abcstate = INHEAD; - abc_set_parts(&abcparts, 0); - strcpy(h->gchord, ""); - if( h->drumon && h->tpr ) abc_add_drum_sync(h, h->tpr, h->tracktime); - if( h->tpc && !h->gchordon ) abc_add_gchord_syncs(h, h->tpc, h->tracktime); - h->gchordon = 1; - h->drumon = 0; - } - else - break; - case INHEAD: - if( !strncmp(p,"L:",2) ) { - sscanf(p+2," %d / %d", &snotelen, &snotediv); - break; - } - if( !strncmp(p,"M:",2) ) { - abc_M_field(p+2, &mnotelen, &mnotediv); - break; - } - if( !strncmp(p,"P:",2) ) { - abc_set_parts(&abcparts, p+2); - break; - } - if( !strncmp(p,"Q:",2) ) { - abctempo = abc_extract_tempo(p+2,0); - ktempo = 1; - if( h->track ) { - // make h->tracktime start of a new age... - abc_add_partbreak(h, h->track, h->tracktime); - abc_add_tempo_event(h, h->track, h->tracktime, abctempo); - } - if( m_nDefaultTempo == 0 ) m_nDefaultTempo = abctempo; - break; - } - if( !strncmp(p,"T:",2) ) { - char buf[200]; - if( strchr(p,'%') ) *strchr(p,'%') = '\0'; - for( t=strlen(p)-1; isspace(p[t]); t-- ) - p[t]='\0'; - for( t=2; isspace(p[t]); t++ ) ; -#ifdef NEWMIKMOD - if( of->songname ) - strcpy(buf,of->songname); - else - strcpy(buf,""); -#else - strcpy(buf,m_szNames[0]); -#endif - if( strlen(buf) + strlen(p+t) > 199 ) p[t+199-strlen(buf)] = '\0'; // chop it of - if( strlen(buf) ) strcat(buf," "); // add a space - strcat(buf, p+t); -#ifdef NEWMIKMOD - of->songname = DupStr(of->allochandle, buf, strlen(buf)); -#else - if( strlen(buf) > 31 ) buf[31] = '\0'; // chop it of - strcpy(m_szNames[0], buf); -#endif - break; - } - if( !strncmp(p,"R:",2) ) { - for( p+=2; isspace(*p); p++ ) ; - if( !strncmp(p,"hornpipe",8) && (isspace(p[8]) || p[8]=='\0') ) abchornpipe = 1; - else abchornpipe = 0; - break; - } - if( !strncmp(p,"V:",2) ) { - for( t=2; p[t]==' '; t++ ) ; - h->tp = abc_locate_track(h, p+t, 0); - abcvol = h->tp->volume; - abcnolegato = !h->tp->legato; - if( !abcnolegato ) abcnoslurs = 0; - break; - } - if( !strncmp(p,"K:",2) ) { - abcstate = INBODY; - abckey = ABC_Key(p+2); - sprintf(barsig, "%s%s", sig[abckey], sig[abckey]); // reset the key signature - p = abc_skip_word(p+2); - h->ktrans = abc_transpose(p); - *p = '%'; // force skip rest of line - if( snotelen == 0 ) { // calculate default notelen from meter M: - if( mnotediv == 0 ) mnotediv = mnotelen = 1; // do'nt get nuked - snotelen = 100 * mnotelen / mnotediv; - if( snotelen > 74 ) - snotediv = 8; - else - snotediv = 16; - snotelen = 1; - } - abceffect = none; - abceffoper = 0; - if( !(snotelen == 1 && snotediv == 8) ) abchornpipe = 0; // no matter what they said at R: - brokenrithm = 0; - global_part = ' '; - abcgrace = 0; - abcnoslurs = abcnolegato; - abcto = 0; - h->tpc = NULL; // reset chord track - tpd = NULL; // reset drone track - h->tpr = NULL; // reset drum track - if( !strlen(h->gchord) ) abc_metric_gchord(h, mnotelen, mnotediv); - h->barticks = notelen_notediv_to_ticks(h->speed, mnotelen, mnotediv); - if( abctempo && !ktempo ) { // did not set tempo in this songpiece so reset to abcrate - abctempo = 0; - global_tempo_factor = 2; - global_tempo_divider = 1; - if( h->track ) { - // make h->tracktime start of a new age... - abc_add_partbreak(h, h->track, h->tracktime); - abc_add_tempo_event(h, h->track, h->tracktime, abcrate); - } - if( m_nDefaultTempo == 0 ) m_nDefaultTempo = abcrate; - } - abc_init_partpat(partpat); - partpat[26][0] = abc_patno(h, h->tracktime); - partpat[26][1] = 0; - abc_globalslide(h, h->tracktime, 2); // reset all volumeslides - break; - } - if( !strlen(p) ) - abcstate = INBETWEEN; - break; - case INSKIPFORQUOTE: - while( (ch=*p++) && (ch != '"') ) - ; - if( !ch ) break; - abcstate = INBODY; - // fall through - case INBODY: - if( !strlen(p) && h->track ) { // end of this song - abcstate = h->pickrandom? INSKIPFORX: INBETWEEN; - // last but not least shut off all pending events - abc_recalculate_tracktime(h); - for( ttp=h->track; ttp; ttp=ttp->next ) - abc_add_noteoff(h,ttp,h->tracktime); - abc_add_partbreak(h, h->track, h->tracktime); - t = abc_patno(h, h->tracktime); - if( abc_pattracktime(h, h->tracktime) % abcticks(64 * h->speed) ) t++; - if( global_part == ' ' ) { - partpat[26][1] = t; - if( abcparts ) { - for( t=0; t<26; t++ ) - if( partpat[t][0] < partpat[t][1] ) break; - if( t == 26 ) { - abc_message("parts (%s) set but not used", abcparts); - abc_set_parts(&abcparts, 0); // forget the parts array - } - } - } - else - partpat[global_part - 'A'][1] = t; - if( !abcparts ) abc_song_to_parts(h, &abcparts, partpat); - orderlen = abc_partpat_to_orderlist(partpat, abcparts, h, &orderlist, orderlen); - } - if( !strncmp(p,"V:",2) ) { - for( t=2; p[t]==' '; t++ ) ; - h->tp = abc_locate_track(h, p+t, 0); - sprintf(barsig, "%s%s", sig[abckey], sig[abckey]); // reset the key signature - abcgrace = 0; - brokenrithm = 0; - h->tracktime = abc_tracktime(h->tp); - bartime = h->tracktime; // it is not friendly to break voices in the middle of a track... - abcnolegato = !h->tp->legato; - if( !abcnolegato ) abcnoslurs = 0; - *p = '%'; // make me skip the rest of the line.... - } - if( !strncmp(p,"K:",2) ) { - abckey = ABC_Key(p+2); - sprintf(barsig, "%s%s", sig[abckey], sig[abckey]); // reset the key signature - p = abc_skip_word(p+2); - h->ktrans = abc_transpose(p); - *p = '%'; // make me skip the rest of the line.... - } - if( !strncmp(p,"L:",2) ) { - sscanf(p+2," %d / %d", &snotelen, &snotediv); - *p = '%'; // make me skip the rest of the line.... - } - if( !strncmp(p,"M:",2) ) { - abc_M_field(p+2, &mnotelen, &mnotediv); - h->barticks = notelen_notediv_to_ticks(h->speed, mnotelen, mnotediv); - *p = '%'; // make me skip the rest of the line.... - } - if( !strncmp(p,"Q:",2) ) { - abctempo = abc_extract_tempo(p+2,ch0=='\\'); - if( !h->track ) { - h->tp = abc_check_track(h, h->track); - h->tp->vno = 0; // mark reuseable (temporarely, until first notes come up) - } - abc_add_tempo_event(h, h->track, h->tracktime, abctempo); - *p = '%'; // make me skip the rest of the line.... - } - if( !strncmp(p,"T:",2) ) { - char buf[200]; - if( strchr(p,'%') ) *strchr(p,'%') = '\0'; - for( t=strlen(p)-1; isspace(p[t]); t-- ) - p[t]='\0'; - for( t=2; isspace(p[t]); t++ ) ; -#ifdef NEWMIKMOD - if( of->songname ) - strcpy(buf,of->songname); - else - strcpy(buf,""); -#else - strcpy(buf,m_szNames[0]); -#endif - if( strlen(buf) + strlen(p+t) > 198 ) p[t+198-strlen(buf)] = '\0'; // chop it of - if( strlen(buf) ) strcat(buf," "); // add a space - strcat(buf, p+t); -#ifdef NEWMIKMOD - of->songname = DupStr(of->allochandle, buf, strlen(buf)); -#else - if( strlen(buf) > 31 ) buf[31] = '\0'; // chop it of - strcpy(m_szNames[0], buf); -#endif - *p = '%'; // make me skip the rest of the line.... - } - break; - } - if( !strncmp(p,"m:",2) ) { - if( abcstate != INSKIPFORX ) { - char *pm; - pm = abc_continuated(h, mmstack[mmsp], p); - abc_new_macro(h, pm+2); - if( pm != p ) { - free(pm); - if( h->tp ) abcnolegato = !h->tp->legato; - if( !abcnolegato ) abcnoslurs = 0; - } - } - *p = '%'; // skip rest of line - } - if( !strncmp(p,"U:",2) ) { - abc_new_umacro(h, p+2); - *p = '%'; // skip rest of line - } - if( !strncmp(p,"w:",2) ) { // inline lyrics - *p = '%'; // skip rest of line - } - if( !strncmp(p,"W:",2) ) { // lyrics at end of song body - *p = '%'; // skip rest of line - } - if( !strncmp(p,"d:",2) ) { // oldstyle decorations - abc_message("warning: old style decorations not handled\n%s", p); - *p = '%'; // skip rest of line - } - if( !strncmp(p,"s:",2) ) { // newstyle decorations (symbols) - abc_message("warning: new style decorations not handled\n%s", p); - *p = '%'; // skip rest of line - } - if( !strncmp(p,"I:",2) && abcstate != INSKIPFORX ) { // handle like oldstyle '%%command' lines - p[0]= '%'; - p[1]= '%'; - } - if( !strncmp(p,"%%",2) ) { - for( p+=2; *p && isspace(*p); p++ ) ; - if( !strncmp(p,"abc-include",11) && isspace(p[11]) ) { - for( t=12; isspace(p[t]); t++ ) ; - if( p[t] ) { - mmsp++; - if( mmsp == MAXABCINCLUDES ) { - mmsp--; - abc_message("failure: too many abc-include's, %s", &p[t]); - } else { - mmstack[mmsp] = mmfopen(&p[t], "r"); - if( !mmstack[mmsp] ) { - mmsp--; - abc_message("failure: abc-include file %s not found", &p[t]); - } - } - } - else abc_message("failure: abc-include missing file name, %s", p); - } - if( !strncmp(p,"MIDI",4) && (p[4]=='=' || isspace(p[4])) && abcstate != INSKIPFORX ) { - for( p+=5; *p && isspace(*p); p++ ) ; - if( *p == '=' ) - for( p+=1; *p && isspace(*p); p++ ) ; - abc_MIDI_command(h,p,'%'); - if( h->tp ) abcnolegato = !h->tp->legato; - if( !abcnolegato ) abcnoslurs = 0; - } - if(*p) *p = '%'; // skip rest of line - } - if( abcstate == INBODY ) { - if( *p == 'P' && p[1] == ':' ) { // a line with a part indication - if( abcparts != NULL ) { - // make h->tracktime start of a new age... - if( !h->track ) { - h->tp = abc_check_track(h, h->track); - h->tp->vno = 0; // mark reuseable (temporarely, until first notes come up) - } - h->tracktime = h->track? abc_tracktime(h->track): 0; // global parts are voice independent - abc_add_partbreak(h, h->track, h->tracktime); - t = abc_patno(h, h->tracktime); - if( global_part == ' ' ) { - partpat[26][1] = t; - if( abcparts ) { - for( t=0; t<26; t++ ) - if( partpat[t][0] < partpat[t][1] ) break; - if( t == 26 ) { - abc_message("parts (%s) set but not used", abcparts); - abc_set_parts(&abcparts, 0); // forget the parts array - } - } - } - else - partpat[global_part - 'A'][1] = t; - // give every new coming abcevent the desired part indication - while( p[2]==' ' || p[2]=='.' ) p++; // skip blancs and dots - if( isupper(p[2]) ) - global_part = p[2]; - else - global_part = ' '; - if( global_part == ' ' ) - partpat[26][0] = t; - else - partpat[global_part - 'A'][0] = t; - } - *p = '%'; // make me skip the rest of the line.... - } - if( h->droneon && !tpd ) { - tpd = h->track; - if( tpd ) { - tpd = abc_locate_track(h, tpd->v, DRONEPOS1); - tpd->instr = h->dronegm; - abc_add_dronenote(h, tpd, h->tracktime, h->dronepitch[0], h->dronevol[0]); - tpd = abc_locate_track(h, tpd->v, DRONEPOS2); - tpd->instr = h->dronegm; - abc_add_dronenote(h, tpd, h->tracktime, h->dronepitch[1], h->dronevol[1]); - } - } - if( tpd && !h->droneon ) { - tpd = abc_locate_track(h, tpd->v, DRONEPOS1); - abc_add_noteoff(h, tpd, h->tracktime); - tpd = abc_locate_track(h, tpd->v, DRONEPOS2); - abc_add_noteoff(h, tpd, h->tracktime); - tpd = NULL; - } - if( h->drumon && !h->tpr ) { - h->tpr = h->track; - if( h->tpr ) abc_add_drum_sync(h, h->tpr, h->tracktime); // don't start drumming from the beginning of time! - } - if( h->tpr && !h->drumon ) h->tpr = NULL; - if( *p != '%' ) { // skip uninteresting lines - // plough thru the songline gathering mos.... - ch0 = ' '; - pp = 0; - while( (ch = *p++) ) { - if( isalpha(ch) && *p != ':' ) { // maybe a macro - for( mp=h->umacro; mp; mp=mp->next ) { - if( ch == mp->name[0] ) { - pp = p; - p = mp->subst; - ch = *p++; - break; - } - } - } - switch(ch) { - case '%': - abcto = 0; - while( *p ) p++; - break; - case '[': // chord follows or some inline field - abcto = 0; - if( *p=='|' ) break; // [| a thick-thin bar line, loop around and let case '|' handle it - if( !strncmp(p,"V:",2) ) { // inline voice change - for( t=2; isspace(p[t]); t++ ) ; - h->tp = abc_locate_track(h, p+t, 0); - for( ; *p && *p != ']'; p++ ) ; - abcgrace = 0; - brokenrithm = 0; - sprintf(barsig, "%s%s", sig[abckey], sig[abckey]); // reset the key signature - h->tracktime = abc_tracktime(h->tp); - bartime = h->tracktime; // it is not wise to break voices in the middle of a track... - abcvol = h->tp->volume; - abcnolegato = !h->tp->legato; - if( !abcnolegato ) abcnoslurs = 0; - break; - } - if( !strncmp(p,"K:",2) ) { - abckey = ABC_Key(p+2); - sprintf(barsig, "%s%s", sig[abckey], sig[abckey]); // reset the key signature - p = abc_skip_word(p+2); - h->ktrans = abc_transpose(p); - for( ; *p && *p != ']'; p++ ) ; - break; - } - if( !strncmp(p,"M:",2) ) { - abc_M_field(p+2, &mnotelen, &mnotediv); - for( ; *p && *p != ']'; p++ ) ; - h->barticks = notelen_notediv_to_ticks(h->speed, mnotelen, mnotediv); - break; - } - if( !strncmp(p,"P:",2) ) { // a [P:X] field inline - if( abcparts != NULL ) { - // make h->tracktime start of a new age... - abc_add_partbreak(h, h->track, h->tracktime); - t = abc_patno(h, h->tracktime); - if( global_part == ' ' ) - partpat[26][1] = t; - else - partpat[global_part - 'A'][1] = t; - // give every new coming abcevent the desired part indication - while( isspace(p[2]) || p[2]=='.' ) p++; // skip blancs and dots - if( isupper(p[2]) ) - global_part = p[2]; - else - global_part = ' '; - if( global_part == ' ' ) - partpat[26][0] = t; - else - partpat[global_part - 'A'][0] = t; - } - for( ; *p && *p != ']'; p++ ) ; - break; - } - if( !strncmp(p,"Q:",2) ) { - abctempo = abc_extract_tempo(p+2,1); - for( ; *p && *p != ']'; p++ ) ; - abc_add_tempo_event(h, h->track, h->tracktime, abctempo); - break; - } - if( !strncmp(p,"I:",2) ) { // interpret some of the possibilitys - for( p += 2; isspace(*p); p++ ) ; - if( !strncmp(p,"MIDI",4) && (p[4]=='=' || isspace(p[4])) ) { // interpret some of the possibilitys - for( p += 4; isspace(*p); p++ ) ; - if( *p == '=' ) - for( p += 1; isspace(*p); p++ ) ; - abc_MIDI_command(h, p, ']'); - if( h->tp ) abcnolegato = !h->tp->legato; - if( !abcnolegato ) abcnoslurs = 0; - } - for( ; *p && *p != ']'; p++ ) ; // skip rest of inline field - } - if( *p && p[1] == ':' ) { // some other kind of inline field - for( ; *p && *p != ']'; p++ ) ; - break; - } - if( *p && strchr("abcdefgABCDEFG^_=",*p) ) { - int cnl[8],cnd[8],vnl,nl0=0,nd0=0; // for chords with notes of varying length - abcchord = 0; - vnl = 0; - h->tp = abc_check_track(h, h->tp); - abc_track_clear_tiedvpos(h); - abcbeatvol = abc_beat_vol(h, abcvol, (h->tracktime - bartime)/notelen_notediv_to_ticks(h->speed,1,mnotediv)); - while( (ch=*p++) && (ch != ']') ) { - h->tp = abc_locate_track(h, h->tp->v, abcchord? abcchord+DRONEPOS2: 0); - p += abc_add_noteon(h, ch, p, h->tracktime, barsig, abcbeatvol, abceffect, abceffoper); - p += abc_notelen(p, ¬elen, ¬ediv); - if( *p == '-' ) { - p++; - if( h->tp->tail->flg != 1 ) - h->tp->tienote = h->tp->tail; - } - if( abcchord<8 ) { - cnl[abcchord] = notelen; - cnd[abcchord] = notediv; - } - if( abcchord==0 ) { - cnotelen = notelen; - cnotediv = notediv; - nl0 = notelen; - nd0 = notediv; - } - else { - if( cnotelen != notelen || cnotediv != notediv ) { - vnl = 1; - // update to longest duration - if( cnotelen * notediv < notelen * cnotediv ) { - cnotelen = notelen; - cnotediv = notediv; - abc_track_untie_short_chordnotes(h); - } - if( cnotelen * notediv > notelen * cnotediv ) { - if( h->tp->tienote ) { - abc_message("short notes in chord can not be tied:\n%s", h->line); - h->tp->tienote = 0; // short chord notes cannot be tied... - } - } - // update to shortest duration - if( nl0 * notediv > notelen * nd0 ) { - nl0 = notelen; - nd0 = notediv; - } - } - } - abcchord++; - } - p += abc_notelen(p, ¬elen, ¬ediv); - if( (ch = *p) == '-' ) p++; // tied chord... - if( abcarpeggio ) { // update starttime in the noteon events... - thistime = notelen_notediv_to_ticks(h->speed, nl0*notelen*snotelen, nd0*notediv*snotediv)/abcchord; - if( thistime > abcticks(h->speed) ) thistime = abcticks(h->speed); - for( nl0=1; nl0<abcchord; nl0++ ) { - h->tp = abc_locate_track(h, h->tp->v, nl0+DRONEPOS2); - h->tp->tail->tracktick = h->tracktime + thistime * nl0; - } - } - notelen *= cnotelen; - notediv *= cnotediv; - tupletr = abc_tuplet(¬elen, ¬ediv, tupletp, tupletq, tupletr); - while( isspace(*p) ) p++; // allow spacing in broken rithm notation - p += abc_brokenrithm(p, ¬elen, ¬ediv, &brokenrithm, abchornpipe); - thistime = notelen_notediv_to_ticks(h->speed, notelen*snotelen, notediv*snotediv); - if( abcfermata ) { - thistime <<= 1; - abcfermata = 0; - } - if( thistime > abcgrace ) { - thistime -= abcgrace; - abcgrace = 0; - } - else { - abcgrace -= thistime; - thistime = abcticks(h->speed); - abcgrace += abcticks(h->speed); - } - h->tracktime += thistime; - while( abcchord>0 ) { - abcchord--; - h->tp = abc_locate_track(h, h->tp->v, abcchord? abcchord+DRONEPOS2: 0); - if( vnl && (abcchord < 8) && (cnl[abcchord] != cnotelen || cnd[abcchord] != cnotediv) ) { - abc_add_noteoff(h, h->tp, - h->tracktime - thistime - + (thistime * cnl[abcchord] * cnotediv)/(cnd[abcchord] * cnotelen) ); - } - else { - if( ch=='-' && h->tp->tail->flg != 1 ) - h->tp->tienote = h->tp->tail; // copy noteon event to tienote in track - if( thistime > abcticks(h->speed) ) - abc_add_noteoff(h, h->tp, h->tracktime - abcnoslurs); - else - abc_add_noteoff(h, h->tp, h->tracktime); - } - } - if( h->gchordon && (h->tp == h->tpc) ) - abc_add_gchord(h, h->tracktime, bartime); - if( h->drumon && (h->tp == h->tpr) ) - abc_add_drum(h, h->tracktime, bartime); - abcarpeggio = 0; - if( abceffoper != 255 ) abceffect = none; - break; - } - if( isdigit(*p) ) { // different endings in repeats [i,j,n-r,s,... - h->tp = abc_check_track(h, h->tp); - abc_add_partbreak(h, h->tp, h->tracktime); - p += abc_getnumber(p, ¬elen); - abc_add_variant_start(h, h->tp, h->tracktime, notelen); - while( *p==',' || *p=='-' ) { - if( *p==',' ) { - p++; - p += abc_getnumber(p, ¬elen); - abc_add_variant_choise(h->tp, notelen); - } - else { - p++; - p += abc_getnumber(p, ¬ediv); - while( notelen < notediv ) { - notelen++; - abc_add_variant_choise(h->tp, notelen); - } - } - } - break; - } - // collect the notes in the chord - break; - case '(': // slurs follow or some tuplet (duplet, triplet etc.) - abcto = 0; - if( isdigit(*p) ) { - p += abc_getnumber(p,&tupletp); - tupletr = tupletp; // ABC draft 2.0 (4.13): if r is not given it defaults to p - switch( tupletp ) { // ABC draft 2.0 (4.13): q defaults depending on p and time signature - case 2: case 4: case 8: - tupletq = 3; - break; - case 3: case 6: - tupletq = 2; - break; - default: - if( snotediv == 8 ) - tupletq = 3; - else - tupletq = 2; - break; - } - if( *p==':' ) { - p++; - if( isdigit(*p) ) p += abc_getnumber(p,&tupletq); - if( *p==':' ) { - p++; - if( isdigit(*p) ) p += abc_getnumber(p,&tupletr); - } - } - } - else - abcnoslurs=0; - break; - case ')': // end of slurs - abcto = 0; - abcnoslurs = abcnolegato; - break; - case '{': // grace notes follow - abcto = 0; - h->tp = abc_check_track(h, h->tp); - abc_track_clear_tiedvpos(h); - abcgrace = 0; - abcbeatvol = abc_beat_vol(h, abcvol, (h->tracktime - bartime)/notelen_notediv_to_ticks(h->speed,1,mnotediv)); - while( (ch=*p++) && (ch != '}') ) { - p += abc_add_noteon(h, ch, p, h->tracktime+abcgrace, barsig, abcbeatvol, none, 0); - p += abc_notelen(p, ¬elen, ¬ediv); - if( *p=='-' ) { - p++; - if( h->tp->tail->flg != 1 ) - h->tp->tienote = h->tp->tail; - } - notediv *= 4; // grace notes factor 4 shorter (1/8 => 1/32) - abcgrace += notelen_notediv_to_ticks(h->speed, notelen*snotelen, notediv*snotediv); - abc_add_noteoff(h, h->tp, h->tracktime + abcgrace); - } - h->tracktime += abcgrace; - abc_add_sync(h, h->tp, h->tracktime); - if( h->gchordon && (h->tp == h->tpc) ) - abc_add_gchord(h, h->tracktime, bartime); - if( h->drumon && (h->tp == h->tpr) ) - abc_add_drum(h, h->tracktime, bartime); - break; - case '|': // bar symbols - abcto = 0; - if( h->gchordon && h->tp && (h->tp == h->tpc) ) - abc_add_gchord(h, h->tracktime, bartime); - if( h->drumon && (h->tp == h->tpr) ) - abc_add_drum(h, h->tracktime, bartime); - sprintf(barsig, "%s%s", sig[abckey], sig[abckey]); // reset the key signature - bartime = h->tracktime; - if( h->tp && h->tp->vpos ) h->tp = abc_locate_track(h, h->tp->v, 0); // reset from voice overlay - if( isdigit(*p) ) { // different endings in repeats |i,j,n-r,s,... - h->tp = abc_check_track(h, h->tp); - abc_add_partbreak(h, h->tp, h->tracktime); - p += abc_getnumber(p, ¬elen); - abc_add_variant_start(h, h->tp, h->tracktime, notelen); - while( *p==',' || *p=='-' ) { - if( *p==',' ) { - p++; - p += abc_getnumber(p, ¬elen); - abc_add_variant_choise(h->tp, notelen); - } - else { - p++; - p += abc_getnumber(p, ¬ediv); - while( notelen < notediv ) { - notelen++; - abc_add_variant_choise(h->tp, notelen); - } - } - } - break; - } - if( *p==':' ) { // repeat start - p++; - h->tp = abc_check_track(h, h->tp); - abc_add_partbreak(h, h->tp, h->tracktime); - abc_add_setloop(h, h->tp, h->tracktime); - } - break; - case '&': // voice overlay - abcto = 0; - h->tracktime = bartime; - h->tp = abc_check_track(h, h->tp); - t = h->tp->vpos; - h->tp = abc_locate_track(h, h->tp->v, t? t+1: DRONEPOS2+1); - break; - case ']': // staff break, end of song - abcto = 0; - break; - case ':': // repeat jump - abcto = 0; - h->tp = abc_check_track(h, h->tp); - j = (h->tp->slidevol == -2)? jumpfade: jumpnormal; - abc_add_setjumploop(h, h->tp, h->tracktime, j); - abc_add_partbreak(h, h->tp, h->tracktime); - if( *p==':' ) { // repeat start without intermediate bar symbol - p++; - abc_add_setloop(h, h->tp, h->tracktime); - } - break; - case '"': // chord notation - if( !strchr("_^<>@", *p) && !isdigit(*p) ) { // if it's not a annotation string - h->tp = abc_check_track(h, h->tp); - if( !h->tpc ) h->tpc = abc_locate_track(h, h->tp->v, 0); - if( h->tp == h->tpc ) abc_add_chord(p, h, h->tpc, h->tracktime); // only do chords for one voice - } - abcto = 0; - while( (ch=*p++) && (ch != '"') ) { - if( !strncasecmp(p,"fade",4) && h->track && h->track->slidevol > -2 ) - abc_globalslide(h, h->tracktime, -2); // set volumeslide to fade away... - if( !strncasecmp(p,"to coda",7) ) { - h->tp = abc_check_track(h, h->tp); - abc_add_partbreak(h, h->tp, h->tracktime); - abc_add_tocoda(h, h->tp, h->tracktime); - p+=7; - abcto = -1; - } - else - if( !isspace(*p) ) abcto = 0; - if( !strncasecmp(p,"to",2) && (isspace(p[2]) || p[2] == '"') ) abcto = 1; - } - if( !ch ) abcstate = INSKIPFORQUOTE; - break; - case '\\': // skip the rest of this line, should be the end of the line anyway - while( (ch=*p++) ) - ; - ch = '\\'; // remember for invoice tempo changes.... - break; - case '!': // line break, or deprecated old style decoration - case '+': // decorations new style - if( !strncmp(p,"coda",4) && p[4] == ch ) { - h->tp = abc_check_track(h, h->tp); - if( abcto ) { - if( abcto > 0 ) { - abc_add_partbreak(h, h->tp, h->tracktime); - abc_add_tocoda(h, h->tp, h->tracktime); - } - } - else { - abc_add_partbreak(h, h->tp, h->tracktime); - abc_add_coda(h, h->tp, h->tracktime); - } - p += 5; - abcto = 0; - break; - } - abcto = 0; - if( !strncmp(p,"arpeggio",8) && p[8] == ch ) { - abcarpeggio = 1; - p += 9; - break; - } - if( !strncmp(p,"crescendo(",10) && p[10] == ch ) { - h->tp = abc_check_track(h, h->tp); - abc_globalslide(h, h->tracktime, 1); - p += 11; - break; - } - if( !strncmp(p,"crescendo)",10) && p[10] == ch ) { - h->tp = abc_check_track(h, h->tp); - abc_globalslide(h, h->tracktime, 0); - p += 11; - break; - } - if( !strncmp(p,"<(",2) && p[2] == ch ) { - h->tp = abc_check_track(h, h->tp); - abc_globalslide(h, h->tracktime, 1); - p += 3; - break; - } - if( !strncmp(p,"<)",2) && p[2] == ch ) { - h->tp = abc_check_track(h, h->tp); - abc_globalslide(h, h->tracktime, 0); - p += 3; - break; - } - if( !strncmp(p,"dimimuendo(",11) && p[11] == ch ) { - h->tp = abc_check_track(h, h->tp); - abc_globalslide(h, h->tracktime, -1); - p += 12; - break; - } - if( !strncmp(p,"diminuendo)",11) && p[11] == ch ) { - h->tp = abc_check_track(h, h->tp); - abc_globalslide(h, h->tracktime, 0); - p += 12; - break; - } - if( !strncmp(p,">(",2) && p[2] == ch ) { - h->tp = abc_check_track(h, h->tp); - abc_globalslide(h, h->tracktime, -1); - p += 3; - break; - } - if( !strncmp(p,">)",2) && p[2] == ch ) { - h->tp = abc_check_track(h, h->tp); - abc_globalslide(h, h->tracktime, 0); - p += 3; - break; - } - if( !strncmp(p,"upbow",5) && p[5] == ch ) { - abceffect = bow; - abceffoper = 1; - p += 6; - break; - } - if( !strncmp(p,"downbow",7) && p[7] == ch ) { - abceffect = bow; - abceffoper = 0; - p += 8; - break; - } - if( !strncmp(p,"trill",5) && p[5] == ch ) { - abceffect = trill; - abceffoper = 0; - p += 6; - break; - } - if( !strncmp(p,"trill(",6) && p[6] == ch ) { - abceffect = trill; - abceffoper = 255; - p += 7; - break; - } - if( !strncmp(p,"trill)",6) && p[6] == ch ) { - abceffect = none; - abceffoper = 0; - p += 7; - break; - } - if( !strncmp(p,"accent",6) && p[6] == ch ) { - abceffect = accent; - abceffoper = 0; - p += 7; - break; - } - if( !strncmp(p,"emphasis",8) && p[8] == ch ) { - abceffect = accent; - abceffoper = 0; - p += 9; - break; - } - if( !strncmp(p,">",1) && p[1] == ch ) { - abceffect = accent; - abceffoper = 0; - p += 2; - break; - } - if( !strncmp(p,"fermata",7) && p[7] == ch ) { - abcfermata = 1; - p += 8; - break; - } - if( !strncmp(p,"fine",4) && p[4] == ch ) { - h->tp = abc_check_track(h, h->tp); - abc_add_partbreak(h, h->tp, h->tracktime); - abc_add_fine(h, h->tp, h->tracktime); - p += 5; - break; - } - if( !strncmp(p,"segno",5) && p[5] == ch ) { - h->tp = abc_check_track(h, h->tp); - abc_add_partbreak(h, h->tp, h->tracktime); - abc_add_segno(h, h->tp, h->tracktime); - p += 6; - break; - } - if( !strncmp(p,"tocoda",6) && p[6] == ch ) { - h->tp = abc_check_track(h, h->tp); - abc_add_partbreak(h, h->tp, h->tracktime); - abc_add_tocoda(h, h->tp, h->tracktime); - p += 7; - break; - } - if( !strncmp(p,"D.C.",4) && p[4] == ch ) { - h->tp = abc_check_track(h, h->tp); - j = (h->tp->slidevol == -2)? jumpdcfade: jumpdacapo; - abc_add_setjumploop(h, h->tp, h->tracktime, j); - abc_add_partbreak(h, h->tp, h->tracktime); - p += 5; - break; - } - if( !strncmp(p,"D.S.",4) && p[4] == ch ) { - h->tp = abc_check_track(h, h->tp); - j = (h->tp->slidevol == -2)? jumpdsfade: jumpdasegno; - abc_add_setjumploop(h, h->tp, h->tracktime, j); - abc_add_partbreak(h, h->tp, h->tracktime); - p += 5; - break; - } - if( !strncmp(p,"dacapo",6) && p[6] == ch ) { - h->tp = abc_check_track(h, h->tp); - j = (h->tp->slidevol == -2)? jumpdcfade: jumpdacapo; - abc_add_setjumploop(h, h->tp, h->tracktime, j); - abc_add_partbreak(h, h->tp, h->tracktime); - p += 7; - break; - } - if( !strncmp(p,"dacoda",6) && p[6] == ch ) { - h->tp = abc_check_track(h, h->tp); - j = (h->tp->slidevol == -2)? jumpdcfade: jumpdacapo; - abc_add_setjumploop(h, h->tp, h->tracktime, j); - abc_add_partbreak(h, h->tp, h->tracktime); - p += 7; - break; - } - if( ch == '!' ) { - for( t=0; p[t] && strchr("|[:]!",p[t])==0 && !isspace(p[t]); t++ ) ; - if( p[t] == '!' ) { // volume and other decorations, deprecated - h->tp = abc_check_track(h, h->tp); - abcvol = abc_parse_decorations(h, h->tp, p); - p = &p[t+1]; - } - } - else { - h->tp = abc_check_track(h, h->tp); - abcvol = abc_parse_decorations(h, h->tp, p); - while( (ch=*p++) && (ch != '+') ) - ; - } - break; - case '`': // back quotes are for readability - break; - case '.': // staccato marks - break; - default: // some kinda note must follow - if( strchr("abcdefgABCDEFG^_=X",ch) ) { - h->tp = abc_check_track(h, h->tp); - abc_track_clear_tiedvpos(h); - abcbeatvol = abc_beat_vol(h, abcvol, (h->tracktime - bartime)/notelen_notediv_to_ticks(h->speed,1,mnotediv)); - p += abc_add_noteon(h, ch, p, h->tracktime, barsig, abcbeatvol, abceffect, abceffoper); - if( abceffoper != 255 ) abceffect = none; - p += abc_notelen(p, ¬elen, ¬ediv); - if( *p=='-' ) { - p++; - if( h->tp->tail->flg != 1 ) - h->tp->tienote = h->tp->tail; - } - tupletr = abc_tuplet(¬elen, ¬ediv, tupletp, tupletq, tupletr); - while( isspace(*p) ) p++; // allow spacing in broken rithm notation - p += abc_brokenrithm(p, ¬elen, ¬ediv, &brokenrithm, abchornpipe); - thistime = notelen_notediv_to_ticks(h->speed, notelen*snotelen, notediv*snotediv); - if( abcfermata ) { - thistime <<= 1; - abcfermata = 0; - } - if( thistime > abcgrace ) { - thistime -= abcgrace; - abcgrace = 0; - } - else { - abcgrace -= thistime; - thistime = abcticks(h->speed); - abcgrace += abcticks(h->speed); - } - h->tracktime += thistime; - if( thistime > abcticks(h->speed) ) - abc_add_noteoff(h, h->tp, h->tracktime - abcnoslurs - (( ch0 == '.')? thistime / 2: 0)); - else - abc_add_noteoff(h, h->tp, h->tracktime); - abc_add_sync(h, h->tp, h->tracktime); - if( h->gchordon && (h->tp == h->tpc) ) - abc_add_gchord(h, h->tracktime, bartime); - if( h->drumon && (h->tp == h->tpr) ) - abc_add_drum(h, h->tracktime, bartime); - abcarpeggio = 0; - break; - } - if( strchr("zx",ch) ) { - h->tp = abc_check_track(h, h->tp); - abc_track_clear_tiednote(h); - p += abc_notelen(p, ¬elen, ¬ediv); - tupletr = abc_tuplet(¬elen, ¬ediv, tupletp, tupletq, tupletr); - while( isspace(*p) ) p++; // allow spacing in broken rithm notation - p += abc_brokenrithm(p, ¬elen, ¬ediv, &brokenrithm, abchornpipe); - thistime = notelen_notediv_to_ticks(h->speed, notelen*snotelen, notediv*snotediv); - if( abcfermata ) { - thistime <<= 1; - abcfermata = 0; - } - if( thistime > abcgrace ) { - thistime -= abcgrace; - abcgrace = 0; - } - else { - abcgrace -= thistime; - thistime = abcticks(h->speed); - abcgrace += abcticks(h->speed); - } - h->tracktime += thistime; - abc_add_sync(h, h->tp, h->tracktime); - if( h->gchordon && (h->tp == h->tpc) ) - abc_add_gchord(h, h->tracktime, bartime); - if( h->drumon && (h->tp == h->tpr) ) - abc_add_drum(h, h->tracktime, bartime); - abcarpeggio = 0; - break; - } - if( strchr("Z",ch) ) { - h->tp = abc_check_track(h, h->tp); - abc_track_clear_tiednote(h); - p += abc_notelen(p, ¬elen, ¬ediv); - thistime = notelen_notediv_to_ticks(h->speed, notelen*mnotelen, notediv*mnotediv); - if( abcfermata ) { - thistime <<= 1; - abcfermata = 0; - } - if( thistime > abcgrace ) { - thistime -= abcgrace; - abcgrace = 0; - } - else { - abcgrace -= thistime; - thistime = abcticks(h->speed); - abcgrace += abcticks(h->speed); - } - h->tracktime += thistime; - sprintf(barsig, "%s%s", sig[abckey], sig[abckey]); // reset the key signature - abc_add_sync(h, h->tp, h->tracktime); - if( h->gchordon && (h->tp == h->tpc) ) - abc_add_gchord(h, h->tracktime, bartime); - if( h->drumon && (h->tp == h->tpr) ) - abc_add_drum(h, h->tracktime, bartime); - abcarpeggio = 0; - break; - } - if( isalpha(ch) && *p==':' ) { - // some unprocessed field line? - while( *p ) p++; // skip it - break; - } - break; - } - ch0 = ch; // remember previous char, can be staccato dot... - if( pp ) { // did we have a U: macro substitution? - if( !*p ) { - p = pp; - pp = 0; - } - } - } - } - } - } - if( mmsp ) mmfclose(mmstack[mmsp]); - } - ABC_CleanupMacros(h); // we dont need them anymore - if( !h->track ) { - char buf[10]; - sprintf(buf,"%d",abcxnumber); - abc_message("abc X:%s has no body", buf); - h->track = abc_check_track(h, h->track); // for sanity... - } - if( abcstate == INBODY ) { - // last but not least shut off all pending events - abc_recalculate_tracktime(h); - for( ttp=h->track; ttp; ttp=ttp->next ) - abc_add_noteoff(h,ttp,h->tracktime); - abc_add_partbreak(h, h->track, h->tracktime); - t = abc_patno(h, h->tracktime); - if( abc_pattracktime(h, h->tracktime) % abcticks(64 * h->speed) ) t++; - if( global_part == ' ' ) { - partpat[26][1] = t; - if( abcparts ) { - for( t=0; t<26; t++ ) - if( partpat[t][0] < partpat[t][1] ) break; - if( t == 26 ) { - abc_message("parts (%s) set but not used", abcparts); - abc_set_parts(&abcparts, 0); // forget the parts array - } - } - } - else - partpat[global_part - 'A'][1] = t; - if( !abcparts ) abc_song_to_parts(h, &abcparts, partpat); - orderlen = abc_partpat_to_orderlist(partpat, abcparts, h, &orderlist, orderlen); - } - abc_synchronise_tracks(h); // distribute all control events - abc_recalculate_tracktime(h); -/* - - abctrack: - tracktick long - note byte - octave byte - instrument byte - effects byte - - tick = tracktick modulo speed - row = (tracktick div speed) modulo 64 - pat = (tracktick div speed) div 64 - ord = calculated - -*/ - if( (p=getenv(ABC_ENV_DUMPTRACKS)) ) { - printf("P:%s\n",abcparts); - for( t=0; t<26; t++ ) - if( partpat[t][1] >= partpat[t][0] ) - printf(" %c ",t+'A'); - if( partpat[26][1] >= partpat[26][0] ) - printf("All"); - printf("\n"); - for( t=0; t<27; t++ ) - if( partpat[t][1] >= partpat[t][0] ) - printf("%3d ",partpat[t][0]); - printf("\n"); - for( t=0; t<27; t++ ) - if( partpat[t][1] >= partpat[t][0] ) - printf("%3d ",partpat[t][1]); - printf("\n"); - for( t=0; (int)t<orderlen; t++ ) - printf("%3d ",t); - printf("\n"); - for( t=0; (int)t<orderlen; t++ ) - printf("%3d ",orderlist[t]); - printf("\n"); - abc_dumptracks(h,p); - } - // set module variables - if( abctempo == 0 ) abctempo = abcrate; - if( m_nDefaultTempo == 0 ) m_nDefaultTempo = abctempo; -#ifdef NEWMIKMOD - of->memsize = PTMEM_LAST; // Number of memory slots to reserve! - of->modtype = _mm_strdup(of->allochandle, ABC_Version); - of->numpat = 1+(modticks(h->tracktime) / h->speed / 64); - of->numpos = orderlen; - of->reppos = 0; - of->initspeed = h->speed; - of->numchn = abc_numtracks(h); - of->numtrk = of->numpat * of->numchn; - of->initvolume = 64; - of->pansep = 128; - // orderlist - if(!AllocPositions(of, orderlen)) { - avoid_reentry = 0; - return FALSE; - } - for(t=0; t<orderlen; t++) - of->positions[t] = orderlist[t]; - _mmalloc_close(h->ho); // get rid of orderlist memory -#else - m_nType = MOD_TYPE_ABC; - numpat = 1+(modticks(h->tracktime) / h->speed / 64); - m_nDefaultSpeed = h->speed; - m_nChannels = abc_numtracks(h); - m_dwSongFlags = SONG_LINEARSLIDES; - m_nMinPeriod = 28 << 2; - m_nMaxPeriod = 1712 << 3; - // orderlist - for(t=0; t < (uint32_t)orderlen; t++) - Order[t] = orderlist[t]; - free(orderlist); // get rid of orderlist memory -#endif -#ifdef NEWMIKMOD - // ============================== - // Load the pattern info now! - if(!AllocTracks(of)) return 0; - if(!AllocPatterns(of)) return 0; - of->ut = utrk_init(of->numchn, h->allochandle); - utrk_memory_reset(of->ut); - utrk_local_memflag(of->ut, PTMEM_PORTAMENTO, TRUE, FALSE); - ABC_ReadPatterns(of, h, of->numpat); - // load instruments after building the patterns (chan == 10 track handling) - if( !PAT_Load_Instruments(of) ) { - avoid_reentry = 0; - return FALSE; - } - // ============================================================ - // set panning positions - for(t=0; t<of->numchn; t++) { - of->panning[t] = PAN_LEFT+((t+2)%5)*((PAN_RIGHT - PAN_LEFT)/5); // 0x30 = std s3m val - } -#else - // ============================== - // Load the pattern info now! - if( ABC_ReadPatterns(Patterns, PatternSize, h, numpat, m_nChannels) ) { - // :^( need one more channel to handle the global events ;^b - m_nChannels++; - h->tp = abc_locate_track(h, "", 99); - abc_add_sync(h, h->tp, h->tracktime); - for( t=0; t<numpat; t++ ) { - FreePattern(Patterns[t]); - Patterns[t] = NULL; - } - ABC_ReadPatterns(Patterns, PatternSize, h, numpat, m_nChannels); - } - // load instruments after building the patterns (chan == 10 track handling) - if( !PAT_Load_Instruments(this) ) { - avoid_reentry = 0; - return FALSE; - } - // ============================================================ - // set panning positions - for(t=0; t<m_nChannels; t++) { - ChnSettings[t].nPan = 0x30+((t+2)%5)*((0xD0 - 0x30)/5); // 0x30 = std s3m val - ChnSettings[t].nVolume = 64; - } -#endif - avoid_reentry = 0; // it is safe now, I'm finished - abc_set_parts(&abcparts, 0); // free the parts array -#ifndef NEWMIKMOD - ABC_Cleanup(h); // we dont need it anymore -#endif - return 1; -} - -#ifdef NEWMIKMOD -// ===================================================================================== -CHAR *ABC_LoadTitle(MMSTREAM *mmfile) -// ===================================================================================== -{ - char s[128]; - int i; - // get the first line with T:songtitle - _mm_fseek(mmfile,0,SEEK_SET); - while(abc_fgets(mmfile,s,128)) { - if( s[0]=='T' && s[1]==':' ) { - for( i=2; s[i]==' '; i++ ) ; - return(DupStr(NULL, s+i,strlen(s+i))); - } - } - return NULL; -} - -MLOADER load_abc = -{ - "ABC", - "ABC draft 2.0", - 0x30, - NULL, - ABC_Test, - (void *(*)(void))ABC_Init, - (void (*)(ML_HANDLE *))ABC_Cleanup, - /* Every single loader seems to need one of these! */ - (BOOL (*)(ML_HANDLE *, UNIMOD *, MMSTREAM *))ABC_Load, - ABC_LoadTitle -}; -#endif |