--- abcmidi-20070318.orig/abcmatch.c +++ abcmidi-20070318/abcmatch.c @@ -132,7 +132,7 @@ float fract; int i; int skip_rests,multiplier,inchord,ingrace; -int maxpitch; +int maxpitch = -9999; *nnotes = 0; *nbars = 0; inchord = 0; @@ -392,6 +392,7 @@ int changes; int last_sample; if (mmsamples != isamples) return -1; +i = 0; dif = 0; changes = 0; last_sample = ipitch_samples[i]; @@ -683,10 +684,10 @@ { char *filename; int i,j; - int ikey,mkey; + int ikey,mkey = 0; int moffset; int transpose; - int mseqno; + int mseqno = 0; /* sequence number of template (match.abc) * mseqno can differ from xrefnum when running count_matched_tune_bars * because there is no guarantee the xref numbers are in @@ -717,6 +718,7 @@ &mtimesig_num, &mtimesig_denom,mbarlineptr,mnotelength,mmidipitch); /* trim off any initial bar lines */ + j = 0; for (i=0;i #include +#include /* define USE_INDEX if your C libraries have index() instead of strchr() */ #ifdef USE_INDEX @@ -77,7 +78,7 @@ char* crack(argc, argv, flags, ign) int argc; char **argv; char *flags; int ign; { - char *pv, *flgp, *strchr(); + char *pv, *flgp; while ((arg_index) < argc) { if (pvcon != NULL) --- abcmidi-20070318.orig/debian/README.Debian +++ abcmidi-20070318/debian/README.Debian @@ -0,0 +1,17 @@ +abcmidi for Debian +---------------------- + +This version of the abcmidi package contains the following tools: + + midi2abc version 2.5 + abc2midi version 1.30 + abc2abc version 1.22 + +The upstream abcMIDI package also contains an ABC-to-PostScript +converter called yaps. This can be found in the `abcmidi-yaps' +package. There is another software package called `yaps', which is +a program for talking to pagers (as in things that go beep in your +pocket), and while this apparently hasn't been packaged for Debian +yet, I am using the qualified name to avoid confusion. + + -- Anselm Lingnau , Tue, 20 Feb 2001 15:42:36 +0100 --- abcmidi-20070318.orig/debian/abcmidi-yaps.README.Debian +++ abcmidi-20070318/debian/abcmidi-yaps.README.Debian @@ -0,0 +1,20 @@ +abcmidi-yaps for Debian +----------------------- + +This package contains yaps 1.1 from abcMIDI 8 (which is available as a +Debian package `abcmidi'). It has been packaged separately for the +convenience of those who already use another ABC-to-PostScript +converter such as abc2ps. + +There is another software package called `yaps', which is a program +for talking to pagers (as in things that go beep in your pocket), and +while this apparently hasn't been packaged for Debian yet, I am using +the qualified name `abcmidi-yaps' to avoid confusion. The executable +is also called `abcmidi-yaps'. (Make(1) is your friend, and ln(1) +too.) + +There is a manual page which was contributed by Colin Watson +, and another, more detailed explanatory file +in /usr/share/doc/abcmidi-yaps/yaps.txt. + + -- Anselm Lingnau , Tue, 20 Feb 2001 15:42:36 +0100 --- abcmidi-20070318.orig/debian/abcmidi-yaps.dirs +++ abcmidi-20070318/debian/abcmidi-yaps.dirs @@ -0,0 +1,3 @@ +usr/bin +usr/share/doc/abcmidi-yaps +usr/share/man/man1 --- abcmidi-20070318.orig/debian/abcmidi-yaps.docs +++ abcmidi-20070318/debian/abcmidi-yaps.docs @@ -0,0 +1,3 @@ +doc/readme.txt +doc/yapshelp.txt +doc/programming/yaps.txt --- abcmidi-20070318.orig/debian/changelog +++ abcmidi-20070318/debian/changelog @@ -0,0 +1,134 @@ +abcmidi (20070318-3) unstable; urgency=low + + * QA upload. + * Maintainer field set to QA Group. + * Bump Standards-Version to 3.9.5. + * Set debhelper compatibility level to 9. + * Modify makefiles/unix.mak to accept LDFLAGS. + * Build with default Debian compiler flags defined by dpkg-buildflags. + * Add dependency on ${misc:Depends} (closes: #692722). + * Add build-{arch,indep} targets to debian/rules. + * Fix debian/watch (closes: #449958). + * Replace dh_clean -k, which is deprecated, with dh_prep. + + -- Emanuele Rocca Mon, 13 Jan 2014 21:21:35 +0100 + +abcmidi (20070318-2) unstable; urgency=low + + * Bring forward the fixes from 20060422-1 :^( + + -- Anselm Lingnau Fri, 24 Aug 2007 13:48:32 +0200 + +abcmidi (20070318-1) unstable; urgency=low + + * New upstream release + * Now includes "abcmatch" program and documentation + * Various small policy fixes + + -- Anselm Lingnau Fri, 24 Aug 2007 11:19:10 +0200 + +abcmidi (20060422-1) unstable; urgency=high + + * New upstream release + * Incorporate fixes by the Security Team for unchecked sscanf() calls + [drawtune.c, yapstree.c, CVE-2006-1514] + * Fix most warnings to do with uninitialised variables + * Incorporate those bits of Roger Leigh's NMU that still make sense + (closes: #288770) + + -- Anselm Lingnau Thu, 11 May 2006 00:50:52 +0200 + +abcmidi (20051010-1) unstable; urgency=low + + * New upstream release (closes: #304111) + + -- Anselm Lingnau Tue, 18 Oct 2005 03:13:57 +0200 + +abcmidi (20050101-2) unstable; urgency=low + + * Remove the "-Wformat-non-literal" gcc option which was introduced for + the last version, and which is not supported on all gcc + versions. Thanks to Andreas Jochens (closes: #288770). + + -- Anselm Lingnau Wed, 5 Jan 2005 20:46:27 +0100 + +abcmidi (20050101-1) unstable; urgency=low + + * New upstream release + * In particular, the DJB security bugs are now fixed (closes: #287050). + * Fixed another (very similar) security bug five lines above the other + ones. + + -- Anselm Lingnau Tue, 4 Jan 2005 08:37:05 +0100 + +abcmidi (20040821-1) unstable; urgency=low + + * New upstream release. + * Changed Suggests to include pmidi and abcm2ps, remove awe-midi. + * Adapted to policy 3.6.1. + + -- Anselm Lingnau Wed, 25 Aug 2004 01:34:41 +0200 + +abcmidi (20030521-1) unstable; urgency=low + + * New upstream release (upstream maintainer changed, too). + * Adapted to policy 3.5.9. + + -- Anselm Lingnau Tue, 27 May 2003 00:09:13 +0200 + +abcmidi (17-1) unstable; urgency=low + + * New upstream version + + -- Anselm Lingnau Wed, 18 Jul 2001 10:48:33 +0200 + +abcmidi (15-1) unstable; urgency=low + + * New upstream version (closes: #77524, #100874). + * Changed `Suggests:' to suggest various alternatives for MIDI playback + instead of just timidity. (Suggested by Michael Karcher.) + Closes: #98420 + + -- Anselm Lingnau Thu, 28 Jun 2001 13:25:17 +0200 + +abcmidi (8-2) unstable; urgency=low + + * Streamlined the package some more (again thanks to Colin Watson + ). + Closes: #80873 + + -- Anselm Lingnau Wed, 21 Feb 2001 10:14:43 +0100 + +abcmidi (8-1) unstable; urgency=low + + * New upstream version. + * Moved `yaps' into separate binary package abcmidi-yaps + (note that there is another software package called `yaps'). + * Adapted to policy version 3.5.2. + + -- Anselm Lingnau Tue, 20 Feb 2001 15:42:36 +0100 + +abcmidi (1.7.3-1) unstable; urgency=low + + * New upstream version. + * Converted build process to debhelper. This fixes bug#33577 where + the binaries would be installed in the wrong directory. + + -- Anselm Lingnau Fri, 19 Feb 1999 11:09:23 +0100 + +abcmidi (1.5.7-1) unstable; urgency=low + + * New upstream version. + * Miscellaneous formatting fixes to manpage. + + -- Anselm Lingnau Mon, 31 Aug 1998 14:47:12 +0200 + +abcmidi (1.5.1-1) unstable; urgency=low + + * Initial Release. + + -- Anselm Lingnau Thu, 27 Nov 1997 11:26:15 +0100 + +Local variables: +add-log-mailing-address "lingnau@debian.org" +End: --- abcmidi-20070318.orig/debian/compat +++ abcmidi-20070318/debian/compat @@ -0,0 +1 @@ +9 --- abcmidi-20070318.orig/debian/control +++ abcmidi-20070318/debian/control @@ -0,0 +1,40 @@ +Source: abcmidi +Section: sound +Priority: optional +Maintainer: Debian QA Group +Build-Depends: debhelper (>=9) +Standards-Version: 3.9.5 + +Package: abcmidi +Architecture: any +Depends: ${misc:Depends}, ${shlibs:Depends} +Suggests: abcmidi-yaps | abcm2ps, timidity | pmidi | playmidi +Description: converter from ABC to MIDI format and back + This package contains the programs `abc2midi' and `midi2abc', which + convert from the abc musical notation format to standard MIDI format + and vice-versa. They can generate accompaniment from guitar chords + in the abc file, as well as insert various MIDI events; the + MIDI-to-abc translation tries to figure out bars, triplets and + accidentals on its own. + . + The package also contains `abc2abc' (an abc prettyprinter/transposer), + `mftext' (a program that dumps a MIDI file as text), and `midicopy' + (a program that extracts specific tracks, channels or time intervals + from a MIDI file). + . + The programs in this package are based on the `midifilelib' + distribution available from http://www.harmony-central.com/MIDI/. + +Package: abcmidi-yaps +Architecture: any +Depends: ${misc:Depends}, ${shlibs:Depends} +Suggests: postscript-viewer, abcmidi +Description: yet another ABC to PostScript converter + This program translates tunes written in the ABC format to PostScript, + which can then be viewed on screen or printed. It is essentially a + (non-exclusive) alternative to abc2ps, being based on the abc2ps + PostScript code together with the ABC parser from the abcmidi package. + . + People interested in this kind of software should also check out the + abcm2ps package, which contains a similar program that has lots of + additional features. --- abcmidi-20070318.orig/debian/copyright +++ abcmidi-20070318/debian/copyright @@ -0,0 +1,28 @@ +This package was debianized by Anselm Lingnau on +Tue, 27 May 2003. + +It was downloaded from http://ifdo.pugmarks.com/~seymour/runabc/top.html + +Upstream Authors: James Allwright + Seymour Shlien + +Copyright: + +This is free software. You may copy and re-distribute it under the terms of +the GNU General Public License version 2 or later. You should have received +a copy of the GNU General Public License on Debian systems as +/usr/share/common-licenses/GPL; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +This package is to be found on the web at + +http://ifdo.pugmarks.com/~seymour/runabc/top.html + +These programs make use of the 'midifilelib' public domain MIDI file utilities, +available from + +http://www.harmony-central.com/MIDI/midifilelib.tar.gz + +If you have the source distribution and intend to re-compile the code, +read the file coding.txt. + --- abcmidi-20070318.orig/debian/dirs +++ abcmidi-20070318/debian/dirs @@ -0,0 +1,3 @@ +usr/bin +usr/share/doc/abcmidi +usr/share/man/man1 --- abcmidi-20070318.orig/debian/docs +++ abcmidi-20070318/debian/docs @@ -0,0 +1,7 @@ +doc/AUTHORS +doc/abcguide.txt +doc/history.txt +doc/readme.txt +doc/programming/abc2midi.txt +doc/programming/coding.txt +doc/programming/midi2abc.txt --- abcmidi-20070318.orig/debian/rules +++ abcmidi-20070318/debian/rules @@ -0,0 +1,80 @@ +#!/usr/bin/make -f +# Sample debian/rules that uses debhelper. +# GNU copyright 1997 by Joey Hess. +# +# Uncomment this to turn on verbose mode. +#export DH_VERBOSE=1 + +# This has to be exported to make some magic below work. +export DH_OPTIONS + +# This is K&R C, so don't worry about a couple of classes of warnings. +ifeq (,$(findstring debug,$(DEB_BUILD_OPTIONS))) +CFLAGS="-DANSILIBS -O2 -Wall -Wno-implicit -Wno-return-type -Wformat-nonliteral -c `dpkg-buildflags --get CFLAGS`" +else +CFLAGS="-DANSILIBS -O2 -g -Wall -Wno-implicit -Wno-return-type -Wformat-nonliteral -c `dpkg-buildflags --get CFLAGS`" +endif + +LDFLAGS="`dpkg-buildflags --get LDFLAGS`" + +build: build-arch build-indep +build-arch: build-stamp +build-indep: build-stamp + +build-stamp: + dh_testdir + + $(MAKE) -f makefiles/unix.mak CFLAGS=$(CFLAGS) LDFLAGS=$(LDFLAGS) + + touch build-stamp + +clean: + dh_testdir + dh_testroot + rm -f build-stamp + + $(MAKE) -f makefiles/unix.mak clean + + dh_clean + +install: DH_OPTIONS= +install: build + dh_testdir + dh_testroot + dh_prep + dh_installdirs + + set -e; \ + for i in abc2abc abcmatch abc2midi mftext midi2abc midicopy; do \ + install -m 755 $$i $(CURDIR)/debian/abcmidi/usr/bin/`basename $$i .exe`; \ + done + install -m 755 yaps $(CURDIR)/debian/abcmidi-yaps/usr/bin/abcmidi-yaps + cd doc; install -m 644 abc2abc.1 abcmatch.1 abc2midi.1 mftext.1 midi2abc.1 midicopy.1 \ + $(CURDIR)/debian/abcmidi/usr/share/man/man1 + cd doc; install -m 644 yaps.1 $(CURDIR)/debian/abcmidi-yaps/usr/share/man/man1/abcmidi-yaps.1 + +# Build architecture-independent files here. +# Pass -i to all debhelper commands in this target to reduce clutter. +binary-indep: DH_OPTIONS=-i +binary-indep: build install + +# Build architecture-dependent files here. +# Pass -a to all debhelper commands in this target to reduce clutter. +binary-arch: DH_OPTIONS=-a +binary-arch: build install + dh_testdir + dh_testroot + dh_installdocs + dh_installmenu + dh_installchangelogs + dh_strip + dh_compress + dh_fixperms + dh_installdeb + dh_shlibdeps + dh_gencontrol + dh_md5sums + dh_builddeb + +binary: binary-indep binary-arch +.PHONY: build clean binary-indep binary-arch binary install --- abcmidi-20070318.orig/debian/watch +++ abcmidi-20070318/debian/watch @@ -0,0 +1,7 @@ +# Example watch control file for uscan +# Rename this file to "watch" and then you can run the "uscan" command +# to check for upstream updates and more. +# Site Directory Pattern Version Script +version=3 +opts=uversionmangle=s/-//g \ +http://ifdo.pugmarks.com/~seymour/runabc/top.html abcMIDI-(.*)\.zip debian uupdate --- abcmidi-20070318.orig/doc/abcmatch.1 +++ abcmidi-20070318/doc/abcmatch.1 @@ -0,0 +1,177 @@ +.TH ABCMATCH 1 "24 August 2007" +.SH NAME +abcmatch \- search sequences of notes in an ABC file +.SH SYNOPSIS +\fBabcmatch\fP \fIdata-file\fP [\fInumber\fR] [-a] [-br \fId\fP] [-c] [-con] [-ign] [-length_hist] [-pitch_hist] [-qnt] [-r \fIn\fP] [-v] [-ver] +.SH "DESCRIPTION" +.PP +.B abcmatch +searches an ABC file containing (potentially) many tunes for specific +sequences of notes. For example, if you know a few bars of a tune, you +can use this program to find the tune having this sequence and perhaps +identify the tune. +.PP +At a minimum, abcmatch requires two files. A \fItemplate file\fP called +\fBmatch.abc\fP which contains the bars that you are searching for and +a large file consisting of a hundred or more ABC tunes. +The program automatically loads up the match.abc file and +then scans every tune in the large file. +.PP +Though the program can be run stand-alone, it is really meant to be +run with a GUI such as runabc.tcl (which is not yet part of +Debian). Most of its output is rather cryptic. +.SH "THE MATCHING PROCESS" +.PP +The \fItemplate file\fR must be a well-formed ABC file containing the +basic \fBX:\fP, \fBM:\fP, \fBL:\fP, and \fBK:\fP headers as well as +the bars to be matched. (Normally, this file is created by +runabc.tcl.) It is important to finish each bar in the match file with +a vertical line. +.PP +.B abcmatch +uses the key signature to figure out the relative position of the +notes in the scale, and to determine all the assumed sharps and +flats. Therefore the program can find matching bars in a tune that has +been transposed to another key, as long as the key difference is not +too large. Matches are output in a list format looking like +.P +29 30 4 +.br +30 31 4 + +.PP +Each line indicates a particular match found by the program. The first +number on each line gives the relative position of the tune in the +\fIdata-file\fP, while the next number gives the \fBX:\fP number of +that tune. The last number is the bar number of the matching tune. Bar +numbers are counted sequentially from the start of the tune, and all +\fBV:\fP and \fBP:\fP indications are ignored. That is, the bar number +returned by \fBabcmatch\fP may not match bar numbers printed by one of +the PostScript-producing ABC processors such as \fBabcm2ps\fP or +\fBabcmidi-yaps\fP. +.PP +For the purposes of matching, \fBabcmatch\fP ignores all guitar +chords, lyrics, note decorations (e.g., staccato markings), grace +notes, etc. In chords such as \fB[G2c2]\fP, only the highest note is +considered. Any warnings or error messages from the ABC parser are +suppressed unless the \fB-c\fP option is given. + +.SH OPTIONS +.TP +.B \-a +Report any matching bars. By default, if the template file contains a +sequence of several bars, the program will try to find places in the +data file where the whole sequence matches. With this option, it +returns all places in the data file where \fIany\fP of the bars in the +template file match. +.TP +.BI \-br " d" +`Brief mode' is designed to identify groups of tunes sharing common +bars. In this mode, the program determines the number of all bars in each +tune from the data file which are also present in the template +file. If the number of common bars is greater than or equal to the +value of the \fId\fP parameter, the program reports the tune and the +number of common bars. Currently there is no user control of the +matching criterion; the rhythm must match exactly, and the notes are +transposed to suit the key signature. +.TP +.B \-c +Display error and warning messages from the ABC parser (which are +suppressed by default). +.TP +.B \-con +Do a pitch contour match. In this case, the program uses the key +signature only to indicate accidentals. The pitch contour is computed +from the pitch difference (interval) between adjacent notes. That is, +\fBC2 DE\fP, \fBc2 de\fP, and \fBG2 AB\fP all have the same pitch +contour. +.TP +.B \-ign +Ignore simple bars. +.TP +.B \-length_hist +This does no matching at all but returns a histogram of the +distribution of note lengths in the data file. The output looks like + +.RS +length histogram +.br +12 100 +.br +24 20 +.br +36 6 +.br +48 2 +.br +72 4 +.RE + +.RS +where a quarter note is 24 units, an eight note 12 units, a dotted +half note 72 units etc. +.RE +.TP +.B \-pitch_hist +This does no matching at all but returns a histogram of the +distribution of pitches in the data file. The output looks like + +.RS +pitch histogram +.br +64 2 +.br +66 9 +.br +67 11 +... +.RE + +.RS +where the first number on each line is a MIDI note number and the +second is a count of the number of times that note occurred. +.RE +.TP +.B \-qnt +Do a quantized pitch contour match. This works as described above for +the \fB-con\fP option, but will also quantize the intervals as +follows: Unison and semitone intervals are assigned value 0, major +2nds to major 3rds value 1, and a perfect 4th or greater value +2. Negative numbers are used for descending intervals. +.TP +.BI \-r " n" +Resolution for matching. If the \fIn\fP parameter is zero, a perfect +match must be found, meaning that the lengths of each note in a bar +must match exactly in order to be reported. The larger the value of +\fIn\fP, the looser the match will be. Note lengths are converted into +temporal units where a quarter note is normally assigned a value of 24 +(therefore an eighth note has a value of 12, a sixteenth a value of 6, +a half note a value of 48 etc.) If you specify a temporal resolution +of 12, then the pitch values of the notes only need to match at the +time units that are multiples of an eight note. This means that the +program would match the two bars \fBC2 D2\fP and \fBC C D D\fP, as +well as \fBC2 D2\fP and \fBC/D/C/D/D2\fP. By selecting a suitable +value for \fIn\fP, you can search for matches only at the beginning of +a measure or at the beginning of each beat. +.TP +.B \-v +Run verbosely. +.TP +.B \-ver +Display the program's version number. +.SH LIMITATIONS +.PP +The program has some limitations. For example, the data file must +contain bar lines, and tied notes cannot be longer than the equivalent +of 8 quarter notes. A resolution (\fB-r\fP option) that is too small +may cause some buffers to be exceeded. When there are differences of +key signatures of more than 5 semitones, the program may transpose the +notes in the wrong direction. Also, tunes with more than one key +signature or time signature may not be processed correctly. +.SH "SEE ALSO" +.IR abc2midi "(1), " midi2abc "(1), " mftext "(1)" +.SH AUTHOR +This manual page was written by Anselm Lingnau +for the GNU/Linux system. +.SH VERSION +This manual page describes abcmatch version 1.42 as of 21 December 2006. --- abcmidi-20070318.orig/drawtune.c +++ abcmidi-20070318/drawtune.c @@ -29,7 +29,7 @@ #endif #include -#ifdef ANSILIBS +#if defined(ANSILIBS) || defined(__STDC__) #include #include #include @@ -329,6 +329,8 @@ return(i); } +/* This routine is never actually used anywhere. */ +#if 0 static void ISOdecode(char s[], char out[]) /* convert coded characters to straight 8-bit ascii */ { @@ -345,6 +347,7 @@ }; out[j] = '\0'; } +#endif static void ISOfprintf(char s[]) /* interpret special characters and print to file */ @@ -492,7 +495,7 @@ double x; char units[40]; - count = sscanf(s, "%lf%s", &x, units); + count = sscanf(s, "%lf%39s", &x, units); if (count > 0) { if ((count >= 2) && (strncmp(units, "cm", 2) == 0)) { x = x*28.3; @@ -689,6 +692,8 @@ int note; switch (clef->type) { + default: + event_error("unknown clef type in draw_keysig (shouldn't happen)"); case treble: offset = 0; break; @@ -1024,7 +1029,7 @@ struct feature* place; struct note* anote; int thisy, lasty, lastflip; - int stemdir; + int stemdir = 0; int doneflip; int ygap[10]; int accplace; @@ -1149,7 +1154,7 @@ { int i, d; int donenotes; - int start, stop; + int start, stop = 0; double x0, x1, y0, y1, offset; struct note* n; int stemup, beamdir; @@ -1244,9 +1249,9 @@ struct note* lastnote; struct chord* thischord; struct feature* chordplace; - struct tuple* thistuple; - enum tail_type chordbeaming; - int intuple, tuplecount; + struct tuple* thistuple = NULL; + enum tail_type chordbeaming = nostem; + int intuple, tuplecount = 0; struct feature* tuplefeature; ingrace = 0; @@ -1525,6 +1530,8 @@ ft->xright = BASS_RIGHT; ft->xleft = BASS_LEFT; break; + default: + event_error("noclef in sizevoice switch (shouldn't happen)"); }; if (theclef->octave > 0) { ft->yup = ft->yup + CLEFNUM_HT; @@ -1821,6 +1828,9 @@ exit(1); }; break; + default: + event_error("handlegracebeam for nostem (shouldn't happen)"); + break; }; } @@ -1950,7 +1960,7 @@ char fontname[80]; int fontsize, params; - params = sscanf(s, "%s %d", fontname, &fontsize); + params = sscanf(s, "%79s %d", fontname, &fontsize); if (params >= 1) { if (strcmp(fontname, "-") != 0) { if (thefont->name != NULL) { @@ -1974,7 +1984,7 @@ int result; p[0] = '\0'; - sscanf(s, " %10s", p); + sscanf(s, " %9s", p); result = 1; if ((strcmp(p, "0") == 0) || (strcmp(p, "no") == 0) || (strcmp(p, "false") == 0)) { @@ -2109,6 +2119,9 @@ /* notes beamed together */ { switch (n->beaming) { + case nostem: + event_error("handlebeam for nostem (shouldn't happen)"); + break; case single: beamctr = -1; break; @@ -2363,7 +2376,7 @@ struct feature* gracebeamnote[64]; struct chord* gracechording[64]; struct chord* gracelastchord; - int i, j; + int i = 0, j = 0; int ingrace; p = ft; @@ -2779,7 +2792,7 @@ { double x0, y0, x1, y1; struct feature* ft; - struct note* n; + struct note* n = NULL; struct rest* r; ft = s->begin; @@ -2839,7 +2852,7 @@ { double x0, y0, x1, y1; struct feature* ft; - struct note* n; + struct note* n = NULL; struct rest* r; if ((s == NULL) || (s->crossline == 0)) { @@ -2922,10 +2935,10 @@ int sharps; struct chord* thischord; int chordcount; - double xchord; + double xchord = 0.0; struct aclef* theclef; int printedline; - double xend; + double xend = 0.0; int inend; char endstr[80]; int ingrace; @@ -3282,7 +3295,7 @@ { struct feature* ft; double height, descender; - double yend, yinstruct, ygchord, ywords; + double yend = 0.0, yinstruct = 0.0, ygchord = 0.0, ywords = 0.0; struct vertspacing* avertspacing; /* skip over line number so we can check for end of tune */ @@ -3445,7 +3458,7 @@ int titleno; struct voice* thisvoice; int doneline; - double firstvline, lastvline; + double firstvline = 0, lastvline; struct voice* firstvoice; char xtitle[200]; struct bbox boundingbox; --- abcmidi-20070318.orig/genmidi.c +++ abcmidi-20070318/genmidi.c @@ -39,15 +39,15 @@ #include "genmidi.h" #include "midifile.h" #include -#ifdef ANSILIBS +#if defined(ANSILIBS) || defined(__STDC__) #include #include +#include #endif /* define USE_INDEX if your C libraries have index() instead of strchr() */ #ifdef USE_INDEX #define strchr index #endif -#include void single_note_tuning_change(int midikey, float midipitch); void addfract(int *xnum, int *xdenom, int a, int b); --- abcmidi-20070318.orig/makefiles/unix.mak +++ abcmidi-20070318/makefiles/unix.mak @@ -47,26 +47,26 @@ abc2midi : parseabc.o store.o genmidi.o midifile.o queues.o parser2.o $(LNK) -o abc2midi parseabc.o store.o genmidi.o queues.o \ - parser2.o midifile.o + parser2.o midifile.o $(LDFLAGS) abc2abc : parseabc.o toabc.o - $(LNK) -o abc2abc parseabc.o toabc.o + $(LNK) -o abc2abc parseabc.o toabc.o $(LDFLAGS) midi2abc : midifile.o midi2abc.o - $(LNK) midifile.o midi2abc.o -o midi2abc + $(LNK) midifile.o midi2abc.o -o midi2abc $(LDFLAGS) mftext : midifile.o mftext.o crack.o - $(LNK) midifile.o mftext.o crack.o -o mftext + $(LNK) midifile.o mftext.o crack.o -o mftext $(LDFLAGS) yaps : parseabc.o yapstree.o drawtune.o debug.o pslib.o position.o parser2.o $(LNK) -o yaps parseabc.o yapstree.o drawtune.o debug.o \ - position.o pslib.o parser2.o -o yaps + position.o pslib.o parser2.o -o yaps $(LDFLAGS) midicopy : midicopy.o - $(LNK) -o midicopy midicopy.o + $(LNK) -o midicopy midicopy.o $(LDFLAGS) abcmatch : abcmatch.o matchsup.o parseabc.o - $(LNK) abcmatch.o matchsup.o parseabc.o -o abcmatch + $(LNK) abcmatch.o matchsup.o parseabc.o -o abcmatch $(LDFLAGS) parseabc.o : parseabc.c abc.h parseabc.h @@ -111,7 +111,7 @@ matchsup.o : matchsup.c abc.h parseabc.h parser2.h clean : - rm *.o ${binaries} + rm -f *.o ${binaries} install: abc2midi midi2abc abc2abc mftext midicopy yaps abcmatch $(INSTALL) -m 755 ${binaries} ${prefix}/${bindir} --- abcmidi-20070318.orig/matchsup.c +++ abcmidi-20070318/matchsup.c @@ -1,1964 +1,1966 @@ -/* - matchsup.c (abcmatch support functions) - Seymour Shlien - - - - - * originally store.c - * abc2midi - program to convert abc files to MIDI files. - * Copyright (C) 1999 James Allwright - * e-mail: J.R.Allwright@westminster.ac.uk - -store.c was adapted for the purpose of analyzing the contents -of abc tunes. The code is much the same except many functions -related to the generation of midi files has been trimmed off. -In particular: links to the code in genmidi.c and queue.c are gone. -All the gchord stuff is removed. There are options to suppress -all warning and error messages. Certain variables are no longer -extern's (parts, partno, bar_num, global_transpose etc.). -Output file generation stuff is gone. A new variable xrefno is -added to pass the reference number to abcmatch. Event_init has -been moved to the main program abcmatch.c and maxnotes has -been raised to 3000 since there seems to be a problem with -the autoextend procedure. Some DEBUG statements were -added to addfeature - (they can probably be removed). Support -for text features and comments are gone. All the karaoke stuff -is gone. Tempo stuff, slurs, grace notes, decorations, hornpipe -indications are all ignored. Event_note was changed to ignore -trills and rolls. When a [chord] is included, only the highest -note is extracted from the chord. For debugging, a new function -print_feature_list was introduced.etc. - -Essentially for comparing abc files, we want to ignore repeats, -grace notes, staccato indications and midi indications. We are -only interested in comparing the tunes. The main output -which is used is the feature[],pitch,num[],denom[] list which -is used by abcmatch to create a new representation of the abc -file. - -Some abc files with interleaved voices will not be treated -propertly with this program. In general parts, repeats and -voice indications are ignored. - - - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - - -#define XTEN1 1 - -#include "abc.h" -#include "parseabc.h" -#include "parser2.h" -#include -#include - -#ifdef __MWERKS__ -#define __MACINTOSH__ 1 -#endif /* __MWERKS__ */ - -#ifdef __MACINTOSH__ -int setOutFileCreator(char *fileName,unsigned long theType, - unsigned long theCreator); -#endif /* __MACINTOSH__ */ -/* define USE_INDEX if your C libraries have index() instead of strchr() */ -#ifdef USE_INDEX -#define strchr index -#endif - -#ifdef ANSILIBS -#include -#include -#include -#else -extern char* strchr(); -extern void reduce(); -#endif - -#define MAXLINE 500 -#define INITTEXTS 20 -#define INITWORDS 20 -#define MAXCHANS 16 - -/*#define DEBUG*/ - - -/* global variables grouped roughly by function */ - -FILE *fp; - -programname fileprogram = ABCMATCH; - - -/* parsing stage */ -int tuplecount, tfact_num, tfact_denom, tnote_num, tnote_denom; -int specialtuple; -int gracenotes; -int headerpartlabel; -int dotune, pastheader; -int hornpipe, last_num, last_denom; -int timesigset; -int retain_accidentals; -int ratio_a, ratio_b; - -struct voicecontext { - /* maps of accidentals for each stave line */ - char basemap[7], workmap[7]; - int basemul[7], workmul[7]; - int default_length; - int voiceno; - int indexno; - int hasgchords; - int haswords; - int inslur; - int ingrace; - int octaveshift; - /* chord handling */ - int inchord, chordcount; - int chord_num, chord_denom; - /* details of last 2 notes/chords to apply length-modifiers to */ - int laststart, lastend, thisstart, thisend; - /* broken rythm handling */ - int brokentype, brokenmult, brokenpending; - int broken_stack[7]; - struct voicecontext* next; -}; -struct voicecontext global; -struct voicecontext* v; -struct voicecontext* head; -int voicecount; - -/* storage structure for strings */ -int maxtexts = INITTEXTS; -char** atext; -int ntexts = 0; - -int note_unit_length=8; - -/* general purpose storage structure */ -int maxnotes; -int *pitch, *num, *denom; -featuretype *feature; -int *pitchline; -int notes; - -int verbose = 0; -int nowarn=1; -int noerror=1; -int xmatch; -int sf, mi; - -/* Part handling */ -struct vstring part; -int parts, partno, partlabel; -int part_start[26], part_count[26]; - -int voicesused; - -/* Tempo handling (Q: field) */ -int time_num, time_denom; -long tempo; -int tempo_num, tempo_denom; -int relative_tempo, Qtempo; -extern int division; -extern int div_factor; - -/* output file generation */ -int check; -int ntracks; - -/* bar length checking */ -int bar_num, bar_denom; -int barchecking; -int beat; - -/* generating MIDI output */ -int middle_c; -extern int channels[MAXCHANS + 3]; - -int global_transpose; - -int additive; -int gfact_num, gfact_denom; - -/* karaoke handling */ -int karaoke, wcount; -char** words; -int maxwords = INITWORDS; -int xrefno; - -extern int intune; /* signals to parsetune that tune is finished */ - -/* Many of these functions have been retained in order to link with parseabc. -As I have been forced to also modifiy parseabc, now called abcparse, these -functions can also be removed eventually. - */ - -char *featname[] = { -"SINGLE_BAR", "DOUBLE_BAR", "BAR_REP", "REP_BAR", -"PLAY_ON_REP", "REP1", "REP2", "BAR1", -"REP_BAR2", "DOUBLE_REP", "THICK_THIN", "THIN_THICK", -"PART", "TEMPO", "TIME", "KEY", -"REST", "TUPLE", "NOTE", "NONOTE", -"OLDTIE", "TEXT", "SLUR_ON", "SLUR_OFF", -"TIE", "CLOSE_TIE", "TITLE", "CHANNEL", -"TRANSPOSE", "RTRANSPOSE", "GTRANSPOSE", "GRACEON", -"GRACEOFF", "SETGRACE", "SETC", "SETTRIM", "GCHORD", -"GCHORDON", "GCHORDOFF", "VOICE", "CHORDON", -"CHORDOFF", "CHORDOFFEX", "DRUMON", "DRUMOFF", -"DRONEON", "DRONEOFF", "SLUR_TIE", "TNOTE", -"LT", "GT", "DYNAMIC", "LINENUM", -"MUSICLINE", "MUSICSTOP", "WORDLINE", "WORDSTOP", -"INSTRUCTION", "NOBEAM", "CHORDNOTE", "CLEF", -"PRINTLINE", "NEWPAGE", "LEFT_TEXT", "CENTRE_TEXT", -"VSKIP", "COPYRIGHT", "COMPOSER", "ARPEGGIO", -"SPLITVOICE" -}; - - - -void event_info (place) -char * place; -{ -} - -void event_gchord (chord) -char * chord; -{ -} - -void event_slur (t) -int t; -{ -} - - -void event_instruction (s) -char *s; -{ -} - - -void event_reserved (p) -char p; -{ -} - -int bar_num, bar_denom, barno, barsize; -int b_num,b_denom; - -void reduce(a, b) -/* elimate common factors in fraction a/b */ -int *a, *b; -{ - int sign; - int t, n, m; - - if (*a < 0) { - sign = -1; - *a = -*a; - } else { - sign = 1; - }; - /* find HCF using Euclid's algorithm */ - if (*a > *b) { - n = *a; - m = *b; - } else { - n = *b; - m = *a; - }; - while (m != 0) { - t = n % m; - n = m; - m = t; - }; - *a = (*a/n)*sign; - *b = *b/n; -} - -void addunits(a, b) -/* add a/b to the count of units in the bar */ -int a, b; -{ - bar_num = bar_num*(b*b_denom) + (a*b_num)*bar_denom; - bar_denom = bar_denom * (b*b_denom); - reduce(&bar_num, &bar_denom); -} - - -void set_meter(n, m) -/* set up variables associated with meter */ -int n, m; -{ - /* set up barsize */ - barsize = n; - if (barsize % 3 == 0) { - beat = 3; - } else { - if (barsize % 2 == 0) { - beat = 2; - } else { - beat = barsize; - }; - }; - /* correction factor to make sure we count in the right units */ - if (m > 4) { - b_num = m/4; - b_denom = 1; - } else { - b_num = 1; - b_denom = 4/m; - }; -} - -int dummydecorator[DECSIZE]; /* used in event_chord */ - - -static struct voicecontext* newvoice(n) -/* allocate and initialize the data for a new voice */ -int n; -{ - struct voicecontext *s; - int i; - - s = (struct voicecontext*) checkmalloc(sizeof(struct voicecontext)); - voicecount = voicecount + 1; - s->voiceno = n; - s->indexno = voicecount; - s->default_length = global.default_length; - s->hasgchords = 0; - s->haswords = 0; - s->inslur = 0; - s->ingrace = 0; - s->inchord = 0; - s->chordcount = 0; - s->laststart = -1; - s->lastend = -1; - s->thisstart = -1; - s->thisend = -1; - s->brokenpending = -1; - s->next = NULL; - for (i=0; i<7; i++) { - s->basemap[i] = global.basemap[i]; - s->basemul[i] = global.basemul[i]; - s->workmap[i] = global.workmap[i]; - s->workmul[i] = global.workmul[i]; - }; - s->octaveshift = global.octaveshift; - return(s); -} - -static struct voicecontext* getvoicecontext(n) -/* find the data structure for a given voice number */ -int n; -{ - struct voicecontext *p; - struct voicecontext *q; - - p = head; - q = NULL; - while ((p != NULL) && (p->voiceno != n)) { - q = p; - p = p->next; - }; - if (p == NULL) { - p = newvoice(n); - if (q != NULL) { - q->next = p; - }; - }; - if (head == NULL) { - head = p; - }; - return(p); -} - -static void clearvoicecontexts() -/* free up all the memory allocated to voices */ -{ - struct voicecontext *p; - struct voicecontext *q; - - p = head; - while (p != NULL) { - q = p->next; - free(p); - p = q; - }; - head = NULL; -} - - - - -void event_text(s) -/* text found in abc file */ -char *s; -{ -} - - -void event_specific (package, s) -char *package, *s; -{ -} - - -void event_x_reserved(p) -/* reserved character H-Z found in abc file */ -char p; -{ -} - -void event_abbreviation(symbol, string, container) -/* abbreviation encountered - this is handled within the parser */ -char symbol; -char *string; -char container; -{ -} - - -void event_acciaccatura() -{ -/* does nothing here but outputs a / in abc2abc */ -return; -} - -void event_split_voice() -{ -} - - - -void event_tex(s) -/* TeX command found - ignore it */ -char *s; -{ -} - -void event_fatal_error(s) -/* print error message and halt */ -char *s; -{ - event_error(s); - exit(1); -} - -void event_error(s) -/* generic error handler */ -char *s; -{ -if (noerror) return; -#ifdef NOFTELL - extern int nullpass; - - if (nullpass != 1) { - printf("Error in line %d : %s\n", lineno, s); - }; -#else - printf("Error in line %d : %s\n", lineno, s); -#endif -} - -void event_warning(s) -/* generic warning handler - for flagging possible errors */ -char *s; -{ -if (nowarn) return; -#ifdef NOFTELL - extern int nullpass; - - if (nullpass != 1) { - printf("Warning in line %d : %s\n", lineno, s); - }; -#else - printf("Warning in line %d : %s\n", lineno, s); -#endif -} - -static int autoextend(maxnotes) -/* increase the number of abc elements the program can cope with */ -int maxnotes; -{ - int newlimit; - int *ptr; - featuretype *fptr; - int i; - - if (verbose) { - event_warning("Extending note capacity"); - }; - newlimit = maxnotes*2; - fptr = (featuretype*) checkmalloc(newlimit*sizeof(featuretype)); - for(i=0;i= maxnotes) { - maxnotes = autoextend(maxnotes); - }; -} - -void event_linebreak() -/* reached end of line in abc */ -{ - addfeature(LINENUM, lineno, 0, 0); -} - -void event_startmusicline() -/* starting to parse line of abc music */ -{ - addfeature(MUSICLINE, 0, 0, 0); -} - -void event_endmusicline(endchar) -/* finished parsing line of abc music */ -char endchar; -{ - addfeature(MUSICSTOP, 0, 0, 0); -} - -static void textfeature(type, s) -/* called while parsing abc - stores an item which requires an */ -/* associared string */ -int type; -char* s; -{ -} - -void event_comment(s) -/* comment found in abc */ -char *s; -{ -} - - -void event_startinline() -/* start of in-line field in abc music line */ -{ -} - -void event_closeinline() -/* end of in-line field in abc music line */ -{ -} - -void event_field(k, f) -/* Handles R: T: and any other field not handled elsewhere */ -char k; -char *f; -{ - if (dotune) { - switch (k) { - case 'R': - { - char* p; - - p = f; - skipspace(&p); -/******** if ((strncmp(p, "Hornpipe", 8) == 0) || - (strncmp(p, "hornpipe", 8) == 0)) { - hornpipe = 1; - }; -********/ - }; - break; - default: - { - }; - }; - }; -} - -void event_words(p, continuation) -/* handles a w: field in the abc */ -char* p; -int continuation; -{ -} - - -static void checkbreak() -/* check that we are in not in chord, grace notes or tuple */ -/* called at voice change */ -{ - if (tuplecount != 0) { - event_error("Previous voice has an unfinished tuple"); - tuplecount = 0; - }; - if (v->inchord != 0) { - event_error("Previous voice has incomplete chord"); - event_chordoff(1,1); - }; - if (v->ingrace != 0) { - event_error("Previous voice has unfinished grace notes"); - v->ingrace = 0; - }; -} - - -static void read_spec(spec, part) -/* converts a P: field to a list of part labels */ -/* e.g. P:A(AB)3(CD)2 becomes P:AABABABCDCD */ -/* A '+' indicates 'additive' behaviour (a part may include repeats). */ -/* A '-' indicates 'non-additive' behaviour (repeat marks in the music */ -/* are ignored and only repeats implied by the part order statement */ -/* are played). */ -char spec[]; -struct vstring* part; -{ -} - -void event_part(s) -/* handles a P: field in the abc */ -char* s; -{ - char* p; - - if (dotune) { - p = s; - skipspace(&p); - if (pastheader) { - if (((int)*p < 'A') || ((int)*p > 'Z')) { - event_error("Part must be one of A-Z"); - return; - }; - if ((headerpartlabel == 1) && (part.st[0] == *p)) { - /* P: field in header is not a label */ - headerpartlabel = 0; - /* remove speculative part label */ - feature[part_start[(int)*p - (int)'A']] = NONOTE; - } else { - if (part_start[(int)*p - (int)'A'] != -1) { - event_error("Part defined more than once"); - }; - }; - part_start[(int)*p - (int)'A'] = notes; - addfeature(PART, (int)*p, 0, 0); - checkbreak(); - v = getvoicecontext(1); - } else { - parts = 0; - read_spec(p, &part); - if (parts == 1) { - /* might be a label not a specificaton */ - headerpartlabel = 1; - }; - }; - }; -} - -void event_voice(n, s, vp) -/* handles a V: field in the abc */ -int n; -char *s; -struct voice_params *vp; -{ - if (pastheader || XTEN1) { - voicesused = 1; - if (pastheader) checkbreak(); - v = getvoicecontext(n); - addfeature(VOICE, v->indexno, 0, 0); - if (vp->gotoctave) { - event_octave(vp->octave,1); - }; - if (vp->gottranspose) { - addfeature(TRANSPOSE, vp->transpose, 0, 0); - }; - } else { - event_warning("V: in header ignored"); - }; -} - - -void event_length(n) -/* handles an L: field in the abc */ -int n; -{ - note_unit_length = 8; - if (pastheader) { - v->default_length = n; - } else { - global.default_length = n; - }; -} - -static void tempounits(t_num, t_denom) -/* interprets Q: once default length is known */ -int *t_num, *t_denom; -{ -} - -void event_tempo(n, a, b, rel, pre, post) -/* handles a Q: field e.g. Q: a/b = n or Q: Ca/b = n */ -/* strings before and after are ignored */ -int n; -int a, b, rel; -char *pre; -char *post; -{ -} - - -void event_timesig(n, m, dochecking) -/* handles an M: field M:n/m */ -int n, m, dochecking; -{ - if (dotune) { - if (pastheader) { - addfeature(TIME, dochecking, n, m); - } else { - time_num = n; - time_denom = m; - timesigset = 1; - barchecking = dochecking; - }; - }; -} - -void event_octave(num, local) -/* used internally by other routines when octave=N is encountered */ -/* in I: or K: fields */ -int num; -{ - if (dotune) { - if (pastheader || local) { - v->octaveshift = num; - } else { - global.octaveshift = num; - }; - }; -} - -void event_info_key(key, value) -char* key; -char* value; -{ - int num; - - if (strcmp(key, "octave")==0) { - num = readsnumf(value); - event_octave(num,0); - }; -} - -static void stack_broken(v) -struct voicecontext* v; -{ - v->broken_stack[0] = v->laststart; - v->broken_stack[1] = v->lastend; - v->broken_stack[2] = v->thisstart; - v->broken_stack[3] = v->thisend; - v->broken_stack[4] = v->brokentype; - v->broken_stack[5] = v->brokenmult; - v->broken_stack[6] = v->brokenpending; - v->laststart = -1; - v->lastend = -1; - v->thisstart = -1; - v->thisend = -1; - v->brokenpending = -1; -} - -static void restore_broken(v) -struct voicecontext* v; -{ - if (v->brokenpending != -1) { - event_error("Unresolved broken rhythm in grace notes"); - }; - v->laststart = v->broken_stack[0]; - v->lastend = v->broken_stack[1]; - v->thisstart = v->broken_stack[2]; - v->thisend = v->broken_stack[3]; - v->brokentype = v->broken_stack[4]; - v->brokenmult = v->broken_stack[5]; - v->brokenpending = v->broken_stack[6]; -} - -void event_graceon() -/* a { in the abc */ -{ - if (gracenotes) { - event_error("Nested grace notes not allowed"); - } else { - if (v->inchord) { - event_error("Grace notes not allowed in chord"); - } else { - gracenotes = 1; - addfeature(GRACEON, 0, 0, 0); - v->ingrace = 1; - stack_broken(v); - }; - }; -} - -void event_graceoff() -/* a } in the abc */ -{ - if (!gracenotes) { - event_error("} without matching {"); - } else { - gracenotes = 0; - addfeature(GRACEOFF, 0, 0, 0); - v->ingrace = 0; - restore_broken(v); - }; -} - -void event_rep1() -/* [1 in the abc */ -{ - addfeature(PLAY_ON_REP, 0, 0, 1); -/* - if ((notes == 0) || (feature[notes-1] != SINGLE_BAR)) { - event_error("[1 must follow a single bar"); - } else { - feature[notes-1] = BAR1; - }; -*/ -} - -void event_rep2() -/* [2 in the abc */ -{ - addfeature(PLAY_ON_REP, 0, 0, 2); -/* - if ((notes == 0) || (feature[notes-1] != REP_BAR)) { - event_error("[2 must follow a :| "); - } else { - feature[notes-1] = REP_BAR2; - }; -*/ -} - -void event_playonrep(s) -char* s; -/* [X in the abc, where X is a list of numbers */ -{ - int num, converted; - char seps[2]; - - converted = sscanf(s, "%d%1[,-]", &num, seps); - if (converted == 0) { - event_error("corrupted variant ending"); - } else { - if ((converted == 1) && (num != 0)) { - addfeature(PLAY_ON_REP, 0, 0, num); - } else { - textfeature(PLAY_ON_REP, s); - }; - }; -} - -static void slurtotie() -/* converts a pair of identical slurred notes to tied notes */ -{ -} - -void event_sluron(t) -/* called when ( is encountered in the abc */ -int t; -{ - if (t == 1) { - addfeature(SLUR_ON, 0, 0, 0); - v->inslur = 1; - }; -} - -void event_sluroff(t) -/* called when ) is encountered */ -int t; -{ - if (t == 0) { - slurtotie(); - addfeature(SLUR_OFF, 0, 0, 0); - v->inslur = 0; - }; -} - -void event_tie() -/* a tie - has been encountered in the abc */ -{ - addfeature(TIE, 0, 0, 0); -} - -void event_space() -/* space character in the abc is ignored by abc2midi */ -{ - /* ignore */ - /* printf("Space event\n"); */ -} - -void event_lineend(ch, n) -/* called when \ or ! or * or ** is encountered at the end of a line */ -char ch; -int n; -{ - /* ignore */ -} - -void event_broken(type, mult) -/* handles > >> >>> < << <<< in the abc */ -int type, mult; -{ - if (v->inchord) { - event_error("Broken rhythm not allowed in chord"); - } else { - if (v->ingrace) { - event_error("Broken rhythm not allowed in grace notes"); - } else { - v->brokentype = type; - v->brokenmult = mult; - v->brokenpending = 0; - }; - }; -} - -void event_tuple(n, q, r) -/* handles triplets (3 and general tuplets (n:q:r in the abc */ -int n, q, r; -{ - if (tuplecount > 0) { - event_error("nested tuples"); - } else { - if (r == 0) { - specialtuple = 0; - tuplecount = n; - } else { - specialtuple = 1; - tuplecount = r; - }; - if (q != 0) { - tfact_num = q; - tfact_denom = n; - } else { - if ((n < 2) || (n > 9)) { - event_error("Only tuples (2 - (9 allowed"); - tfact_num = 1; - tfact_denom = 1; - tuplecount = 0; - } else { - /* deduce tfact_num using standard abc rules */ - if ((n == 2) || (n == 4) || (n == 8)) tfact_num = 3; - if ((n == 3) || (n == 6)) tfact_num = 2; - if ((n == 5) || (n == 7) || (n == 9)) { - if ((time_num % 3) == 0) { - tfact_num = 3; - } else { - tfact_num = 2; - }; - }; - tfact_denom = n; - }; - }; - tnote_num = 0; - tnote_denom = 0; - }; -} - -void event_chord() -/* a + has been encountered in the abc */ -{ - if (v->inchord) { - event_chordoff(1,1); - } else { - event_chordon(dummydecorator); - }; -} - -static void lenmul(n, a, b) -/* multiply note length by a/b */ -int n, a, b; -{ - if ((feature[n] == NOTE) || (feature[n] == REST) || - (feature[n] == CHORDOFF)) { - num[n] = num[n] * a; - denom[n] = denom[n] * b; - reduce(&num[n], &denom[n]); - }; -} - - -static void brokenadjust() -/* adjust lengths of broken notes */ -{ - int num1, num2, denom12; - int j; - int failed; - - switch(v->brokenmult) { - case 1: - num1 = ratio_b; - num2 = ratio_a; - break; - case 2: - num1 = 7; - num2 = 1; - break; - case 3: - num1 = 15; - num2 = 1; - break; - }; - denom12 = (num1 + num2)/2; - if (v->brokentype == LT) { - j = num1; - num1 = num2; - num2 = j; - }; - failed = 0; - if ((v->laststart == -1) || (v->lastend == -1) || - (v->thisstart == -1) || (v->thisend == -1)) { - failed = 1; - } else { - /* check for same length notes */ - if ((num[v->laststart]*denom[v->thisstart]) != - (num[v->thisstart]*denom[v->laststart])) { - failed = 1; - }; - }; - if (failed) { - event_error("Cannot apply broken rhythm"); - } else { -/* - printf("Adjusting %d to %d and %d to %d\n", - v->laststart, v->lastend, v->thisstart, v->thisend); -*/ - for (j=v->laststart; j<=v->lastend; j++) { - lenmul(j, num1, denom12); - }; - for (j=v->thisstart; j<=v->thisend; j++) { - lenmul(j, num2, denom12); - }; - }; -} - -static void marknotestart() -/* voice data structure keeps a record of last few notes encountered */ -/* in order to process broken rhythm. This is called at the start of */ -/* a note or chord */ -{ - v->laststart = v->thisstart; - v->lastend = v->thisend; - v->thisstart = notes-1; -} - -static void marknoteend() -/* voice data structure keeps a record of last few notes encountered */ -/* in order to process broken rhythm. This is called at the end of */ -/* a note or chord */ -{ - v->thisend = notes-1; - if (v->brokenpending != -1) { - v->brokenpending = v->brokenpending + 1; - if (v->brokenpending == 1) { - brokenadjust(); - v->brokenpending = -1; - }; - }; -} - -static void marknote() -/* when handling a single note, not a chord, marknotestart() and */ -/* marknoteend() can be called together */ -{ - marknotestart(); - marknoteend(); -} - -/* just a stub to ignore 'y' */ -void event_spacing(n, m) -int n,m; -{ -} - -void event_rest(decorators,n,m,type) -/* rest of n/m in the abc */ -int n, m,type; -int decorators[DECSIZE]; -{ - int num, denom; - - num = n; - denom = m; - if (v == NULL) { - event_fatal_error("Internal error : no voice allocated"); - }; - if (v->inchord) v->chordcount = v->chordcount + 1; - if (tuplecount > 0) { - num = num * tfact_num; - denom = denom * tfact_denom; - if (tnote_num == 0) { - tnote_num = num; - tnote_denom = denom; - } else { - if (tnote_num * denom != num * tnote_denom) { - if (!specialtuple) { - event_warning("Different length notes in tuple"); - }; - }; - }; - if ((!gracenotes) && (!v->inchord)) { - tuplecount = tuplecount - 1; - }; - }; - if (v->chordcount == 1) { - v->chord_num = num*4; - v->chord_denom = denom*(v->default_length); - }; - if ((!v->ingrace) && ((!v->inchord)||(v->chordcount==1))) { - addunits(num, denom*(v->default_length)); - }; - last_num = 3; /* hornpiping (>) cannot follow rest */ - addfeature(REST, 0, num*4, denom*(v->default_length)); - if (!v->inchord ) { - marknote(); - }; -} - -void event_mrest(n,m) -/* multiple bar rest of n/m in the abc */ -/* we check for m == 1 in the parser */ -int n, m; -{ - int i; - int decorators[DECSIZE]; - decorators[FERMATA]=0; -/* it is not legal to pass a fermata to a multirest */ - - for (i=0; idefault_length), time_denom,0); - if (i != n-1) { - event_bar(SINGLE_BAR, ""); - }; - }; -} - - - -void event_chordon(int chorddecorators[]) -/* handles a chord start [ in the abc */ -/* the array chorddecorators is needed in toabc.c and yapstree.c */ -/* but is not relevant here. */ - -{ - if (v->inchord) { - event_error("Attempt to nest chords"); - } else { - addfeature(CHORDON, 0, 0, 0); - v->inchord = 1; - v->chordcount = 0; - v->chord_num = 0; - v->chord_denom = 1; - marknotestart(); - }; -} - -void event_chordoff(int chord_n, int chord_m) -/* handles a chord close ] in the abc */ -{ - if (!v->inchord) { - event_error("Chord already finished"); - } else { - - if(chord_m == 1 && chord_n == 1) /* chord length not set outside [] */ - addfeature(CHORDOFF, 0, v->chord_num, v->chord_denom); - else - addfeature(CHORDOFFEX, 0, chord_n*4, chord_m*v->default_length); - - v->inchord = 0; - v->chordcount = 0; - marknoteend(); - if (tuplecount > 0) --tuplecount; - }; -} - - -void event_finger(p) -/* a 1, 2, 3, 4 or 5 has been found in a guitar chord field */ -char *p; -{ - /* does nothing */ -} - -static int pitchof(note, accidental, mult, octave, propogate_accs) -/* finds MIDI pitch value for note */ -/* if propogate_accs is 1, apply any accidental to all instances of */ -/* that note in the bar. If propogate_accs is 0, accidental does not */ -/* apply to other notes */ -char note, accidental; -int mult, octave; -int propogate_accs; -{ - int p; - char acc; - int mul, noteno; - static int scale[7] = {0, 2, 4, 5, 7, 9, 11}; - char *anoctave = "cdefgab"; - - p = (int) ((long) strchr(anoctave, note) - (long) anoctave); - p = scale[p]; - acc = accidental; - mul = mult; - noteno = (int)note - 'a'; - if (acc == ' ') { - acc = v->workmap[noteno]; - mul = v->workmul[noteno]; - } else { - if ((retain_accidentals) && (propogate_accs)) { - v->workmap[noteno] = acc; - v->workmul[noteno] = mul; - }; - }; - if (acc == '^') p = p + mul; - if (acc == '_') p = p - mul; - return p + 12*octave + middle_c; -} - - - -static void hornp(num, denom) -/* If we have used R:hornpipe, this routine modifies the rhythm by */ -/* applying appropriate broken rhythm */ -int num, denom; -{ - if ((hornpipe) && (notes > 0) && (feature[notes-1] != GT)) { - if ((num*last_denom == last_num*denom) && (num == 1) && - (denom*time_num == 32)) { - if (((time_num == 4) && (bar_denom == 8)) || - ((time_num == 2) && (bar_denom == 16))) { - /* addfeature(GT, 1, 0, 0); */ - v->brokentype = GT; - v->brokenmult = 1; - v->brokenpending = 0; - }; - }; - last_num = num; - last_denom = denom; - }; -} - - -void event_note(decorators, accidental, mult, note, xoctave, n, m) -/* handles a note in the abc */ -int decorators[DECSIZE]; -int mult; -char accidental, note; -int xoctave, n, m; -{ - int pitch; - int pitch_noacc; - int num, denom; - int octave; - - if (v == NULL) { - event_fatal_error("Internal error - no voice allocated"); - }; - octave = xoctave + v->octaveshift; - num = n; - denom = m; - if (v->inchord) v->chordcount = v->chordcount + 1; - if (tuplecount > 0) { - num = num * tfact_num; - denom = denom * tfact_denom; - if (tnote_num == 0) { - tnote_num = num; - tnote_denom = denom; - } else { - if (tnote_num * denom != num * tnote_denom) { - if (!specialtuple) { - event_warning("Different length notes in tuple"); - }; - }; - }; - if ((!gracenotes) && - ((!v->inchord) || ((v->inchord) && (v->chordcount == 1)))) { - tuplecount = tuplecount - 1; - }; - }; - if ((!v->ingrace) && (!v->inchord)) { - hornp(num, denom*(v->default_length)); - } else { - last_num = 3; /* hornpiping (>) cannot follow chord or grace notes */ - }; - if ((!v->ingrace) && ((!v->inchord)||(v->chordcount==1))) { - addunits(num, denom*(v->default_length)); - }; - pitch = pitchof(note, accidental, mult, octave, 1); - pitch_noacc = pitchof(note,0,0,octave,0); - if (decorators[FERMATA]) { - num = num*2; - }; - if (v->chordcount == 1) { - v->chord_num = num*4; - v->chord_denom = denom*(v->default_length); - }; - - pitchline[notes] = pitch_noacc; - addfeature(NOTE, pitch, num*4, denom*(v->default_length)); - marknote(); -} - -void event_microtone(int dir, int a, int b) -{ -} - -void event_normal_tone() -{ -} - - - -char *get_accidental(place, accidental) -/* read in accidental - used by event_handle_gchord() */ -char *place; /* place in string being parsed */ -char *accidental; /* pointer to char variable */ -{ - char *p; - - p = place; - *accidental = '='; - if (*p == '#') { - *accidental = '^'; - p = p + 1; - }; - if (*p == 'b') { - *accidental = '_'; - p = p + 1; - }; - return(p); -} - -void event_handle_gchord(s) -/* handler for the guitar chords */ -char* s; -{ -} - -void event_handle_instruction(s) -/* handler for ! ! instructions */ -/* does ppp pp p mp mf f ff fff */ -/* also does !drum! and !nodrum! */ -char* s; -{ -} - -static void setmap(sf, map, mult) -/* work out accidentals to be applied to each note */ -int sf; /* number of sharps in key signature -7 to +7 */ -char map[7]; -int mult[7]; -{ - int j; - - for (j=0; j<7; j++) { - map[j] = '='; - mult[j] = 1; - }; - if (sf >= 1) map['f'-'a'] = '^'; - if (sf >= 2) map['c'-'a'] = '^'; - if (sf >= 3) map['g'-'a'] = '^'; - if (sf >= 4) map['d'-'a'] = '^'; - if (sf >= 5) map['a'-'a'] = '^'; - if (sf >= 6) map['e'-'a'] = '^'; - if (sf >= 7) map['b'-'a'] = '^'; - if (sf <= -1) map['b'-'a'] = '_'; - if (sf <= -2) map['e'-'a'] = '_'; - if (sf <= -3) map['a'-'a'] = '_'; - if (sf <= -4) map['d'-'a'] = '_'; - if (sf <= -5) map['g'-'a'] = '_'; - if (sf <= -6) map['c'-'a'] = '_'; - if (sf <= -7) map['f'-'a'] = '_'; -} - -static void altermap(v, modmap, modmul) -/* apply modifiers to a set of accidentals */ -struct voicecontext* v; -char modmap[7]; -int modmul[7]; -{ - int i; - - for (i=0; i<7; i++) { - if (modmap[i] != ' ') { - v->basemap[i] = modmap[i]; - v->basemul[i] = modmul[i]; - }; - }; -} - -static void copymap(v) -/* sets up working map at the start of each bar */ -struct voicecontext* v; -{ - int j; - - for (j=0; j<7; j++) { - v->workmap[j] = v->basemap[j]; - v->workmul[j] = v->basemul[j]; - }; -} - -/* workaround for problems with PCC compiler */ -/* data may be written to an internal buffer */ - -int myputc(c) -char c; -{ - return (putc(c,fp)); -} - -static void addfract(xnum, xdenom, a, b) -/* add a/b to the count of units in the bar */ -int *xnum; -int *xdenom; -int a, b; -{ - *xnum = (*xnum)*b + a*(*xdenom); - *xdenom = (*xdenom) * b; - reduce(xnum, xdenom); -} - - -static void dotie(j, xinchord,voiceno) -/* called in preprocessing stage to handle ties */ -/* we need the voiceno in case a tie is broken by a */ -/* voice switch. */ -int j, xinchord,voiceno; -{ - int tienote, place; - int tietodo, done; - int lastnote, lasttie; - int inchord; - int tied_num, tied_denom; - int localvoiceno; - int samechord; - - /* find note to be tied */ - samechord = 0; - if (xinchord) samechord = 1; - tienote = j; - localvoiceno = voiceno; - while ((tienote > 0) && (feature[tienote] != NOTE) && - (feature[tienote] != REST)) { - tienote = tienote - 1; - }; - if (feature[tienote] != NOTE) { - event_error("Cannot find note before tie"); - } else { - inchord = xinchord; - /* change NOTE + TIE to TNOTE + REST */ - feature[tienote] = TNOTE; - feature[j] = REST; - num[j] = num[tienote]; - denom[j] = denom[tienote]; - place = j; - tietodo = 1; - lasttie = j; - tied_num = num[tienote]; - tied_denom = denom[tienote]; - lastnote = -1; - done = 0; - while ((place < notes) && (tied_num >=0) && (done == 0)) { - /* printf("%d %s %d %d/%d ",place,featname[feature[place]],pitch[place],num[place],denom[place]); */ - switch (feature[place]) { - case NOTE: - if(localvoiceno != voiceno) break; - lastnote = place; - if ((tied_num == 0) && (tietodo == 0)) { - done = 1; - }; - if ((pitchline[place] == pitchline[tienote]) - && (tietodo == 1) && (samechord == 0)) { - /* tie in note */ - if (tied_num != 0) { - event_error("Time mismatch at tie"); - }; - tietodo = 0; - pitch[place] = pitch[tienote]; /* in case accidentals did not - propagate */ - /* add time to tied time */ - addfract(&tied_num, &tied_denom, num[place], denom[place]); - /* add time to tied note */ - addfract(&num[tienote], &denom[tienote], num[place], denom[place]); - /* change note to a rest */ - feature[place] = REST; - /* get rid of tie */ - if (lasttie != j) { - feature[lasttie] = OLDTIE; - }; - }; - if (inchord == 0) { - /* subtract time from tied time */ - addfract(&tied_num, &tied_denom, -num[place], denom[place]); - }; - break; - case REST: - if(localvoiceno != voiceno) break; - if ((tied_num == 0) && (tietodo == 0)) { - done = 1; - }; - if (inchord == 0) { - /* subtract time from tied time */ - addfract(&tied_num, &tied_denom, -num[place], denom[place]); - }; - break; - case TIE: - if(localvoiceno != voiceno) break; - if (lastnote == -1) { - event_error("Bad tie: possibly two ties in a row"); - } else { - if (pitch[lastnote] == pitch[tienote] && samechord == 0) { - lasttie = place; - tietodo = 1; - if (inchord) samechord = 1; - }; - }; - break; - case CHORDON: - if(localvoiceno != voiceno) break; - inchord = 1; - break; - case CHORDOFF: - case CHORDOFFEX: - samechord = 0; - if(localvoiceno != voiceno) break; - inchord = 0; - /* subtract time from tied time */ - addfract(&tied_num, &tied_denom, -num[place], denom[place]); - break; - case VOICE: - localvoiceno = pitch[place]; - default: - break; - }; - /*printf("tied_num = %d done = %d inchord = %d\n",tied_num, done, inchord); */ - place = place + 1; - }; - if (tietodo == 1) { - event_error("Could not find note to be tied"); - }; - }; -/* printf("dotie finished\n"); */ -} - -static void tiefix() -/* connect up tied notes and cleans up the */ -/* note lengths in the chords (eg [ace]3 ) */ -{ - int j; - int inchord; - int chord_num, chord_denom; - int chord_start,chord_end; - int voiceno; - - j = 0; - inchord = 0; - voiceno = 1; - while (j 0) { - event_playonrep(replist); - }; -/* - if (type == BAR1) { - addfeature(PLAY_ON_REP, 0, 0, 1); - }; - if (type == REP_BAR2) { - addfeature(PLAY_ON_REP, 0, 0, 2); - }; -*/ -} - - - - -void startfile() -/* called at the beginning of an abc tune by event_refno */ -/* This sets up all the default values */ -{ - int j; - - if (verbose) { - printf("scanning tune\n"); - }; - /* set up defaults */ - sf = 0; - mi = 0; - setmap(0, global.basemap, global.basemul); - copymap(&global); - global.octaveshift = 0; - voicecount = 0; - head = NULL; - v = NULL; - time_num = 4; - time_denom = 4; - timesigset = 0; - barchecking = 1; - global.default_length = -1; - event_tempo(120, 1, 4, 0,NULL, NULL); - notes = 0; - ntexts = 0; - gfact_num = 1; - gfact_denom = 3; - global_transpose = 0; - hornpipe = 0; - karaoke = 0; - retain_accidentals = 1; - ratio_a = 2; - ratio_b = 4; - wcount = 0; - parts = -1; - middle_c = 60; - for (j=0; j<26; j++) { - part_start[j] = -1; - }; - headerpartlabel = 0; - additive = 1; - initvstring(&part); - } - - -static void headerprocess() -/* called after the K: field has been reached, signifying the end of */ -/* the header and the start of the tune */ -{ - int t_num, t_denom; - - if (headerpartlabel == 1) { - part_start[(int)part.st[0] - (int)'A'] = notes; - addfeature(PART, part.st[0], 0, 0); - }; - addfeature(DOUBLE_BAR, 0, 0, 0); - pastheader = 1; - - gracenotes = 0; /* not in a grace notes section */ - if (!timesigset) { - event_warning("No M: in header, using default"); - }; - /* calculate time for a default length note */ - if (global.default_length == -1) { - if (((float) time_num)/time_denom < 0.75) { - global.default_length = 16; - } else { - global.default_length = 8; - }; - }; - bar_num = 0; - bar_denom = 1; - set_meter(time_num, time_denom); - if (hornpipe) { - if ((time_denom != 4) || ((time_num != 2) && (time_num != 4))) { - event_error("Hornpipe must be in 2/4 or 4/4 time"); - hornpipe = 0; - }; - }; - - tempounits(&t_num, &t_denom); - /* make tempo in terms of 1/4 notes */ -/* tempo = (long) 60*1000000*t_denom/(Qtempo*4*t_num); */ -/* div_factor = division; */ - voicesused = 0; -} - -void event_key(sharps, s, modeindex, modmap, modmul, gotkey, gotclef, clefname, - octave, transpose, gotoctave, gottranspose) -/* handles a K: field */ -int sharps; /* sharps is number of sharps in key signature */ -int modeindex; /* 0 major, 1,2,3 minor, 4 locrian, etc. */ -char *s; /* original string following K: */ -char modmap[7]; /* array of accidentals to be applied */ -int modmul[7]; /* array giving multiplicity of each accent (1 or 2) */ -int gotkey, gotclef; -int octave, transpose, gotoctave, gottranspose; -char* clefname; -{ - int minor; - if (modeindex >0 && modeindex <4) minor = 1; - if ((dotune) && gotkey) { - if (pastheader) { - setmap(sharps, v->basemap, v->basemul); - altermap(v, modmap, modmul); - copymap(v); - addfeature(KEY, sharps, 0, minor); - if (gottranspose) { - addfeature(TRANSPOSE, transpose, 0, 0); - }; - } else { - if (gottranspose) { - global_transpose = transpose; - }; - setmap(sharps, global.basemap, global.basemul); - altermap(&global, modmap, modmul); - copymap(&global); - sf = sharps; - mi = minor; - headerprocess(); - v = newvoice(1); - head = v; - }; - if (gotoctave) { - event_octave(octave,0); - }; - }; -} - - - -void print_feature_list () -{ -int i,length; -float fract; -printf("feature list \n"); -for (i=0;i -1) { - addfeature(PART, ' ', 0, 0); - }; - if (headerpartlabel == 1) { - event_error("P: field in header should go after K: field"); - }; - - tiefix(); - - - }; - for (i=0; i +#include + +#ifdef __MWERKS__ +#define __MACINTOSH__ 1 +#endif /* __MWERKS__ */ + +#ifdef __MACINTOSH__ +int setOutFileCreator(char *fileName,unsigned long theType, + unsigned long theCreator); +#endif /* __MACINTOSH__ */ +/* define USE_INDEX if your C libraries have index() instead of strchr() */ +#ifdef USE_INDEX +#define strchr index +#endif + +#ifdef ANSILIBS +#include +#include +#include +#else +extern char* strchr(); +extern void reduce(); +#endif + +#define MAXLINE 500 +#define INITTEXTS 20 +#define INITWORDS 20 +#define MAXCHANS 16 + +/*#define DEBUG*/ + + +/* global variables grouped roughly by function */ + +FILE *fp; + +programname fileprogram = ABCMATCH; + + +/* parsing stage */ +int tuplecount, tfact_num, tfact_denom, tnote_num, tnote_denom; +int specialtuple; +int gracenotes; +int headerpartlabel; +int dotune, pastheader; +int hornpipe, last_num, last_denom; +int timesigset; +int retain_accidentals; +int ratio_a, ratio_b; + +struct voicecontext { + /* maps of accidentals for each stave line */ + char basemap[7], workmap[7]; + int basemul[7], workmul[7]; + int default_length; + int voiceno; + int indexno; + int hasgchords; + int haswords; + int inslur; + int ingrace; + int octaveshift; + /* chord handling */ + int inchord, chordcount; + int chord_num, chord_denom; + /* details of last 2 notes/chords to apply length-modifiers to */ + int laststart, lastend, thisstart, thisend; + /* broken rythm handling */ + int brokentype, brokenmult, brokenpending; + int broken_stack[7]; + struct voicecontext* next; +}; +struct voicecontext global; +struct voicecontext* v; +struct voicecontext* head; +int voicecount; + +/* storage structure for strings */ +int maxtexts = INITTEXTS; +char** atext; +int ntexts = 0; + +int note_unit_length=8; + +/* general purpose storage structure */ +int maxnotes; +int *pitch, *num, *denom; +featuretype *feature; +int *pitchline; +int notes; + +int verbose = 0; +int nowarn=1; +int noerror=1; +int xmatch; +int sf, mi; + +/* Part handling */ +struct vstring part; +int parts, partno, partlabel; +int part_start[26], part_count[26]; + +int voicesused; + +/* Tempo handling (Q: field) */ +int time_num, time_denom; +long tempo; +int tempo_num, tempo_denom; +int relative_tempo, Qtempo; +extern int division; +extern int div_factor; + +/* output file generation */ +int check; +int ntracks; + +/* bar length checking */ +int bar_num, bar_denom; +int barchecking; +int beat; + +/* generating MIDI output */ +int middle_c; +extern int channels[MAXCHANS + 3]; + +int global_transpose; + +int additive; +int gfact_num, gfact_denom; + +/* karaoke handling */ +int karaoke, wcount; +char** words; +int maxwords = INITWORDS; +int xrefno; + +extern int intune; /* signals to parsetune that tune is finished */ + +/* Many of these functions have been retained in order to link with parseabc. +As I have been forced to also modifiy parseabc, now called abcparse, these +functions can also be removed eventually. + */ + +char *featname[] = { +"SINGLE_BAR", "DOUBLE_BAR", "BAR_REP", "REP_BAR", +"PLAY_ON_REP", "REP1", "REP2", "BAR1", +"REP_BAR2", "DOUBLE_REP", "THICK_THIN", "THIN_THICK", +"PART", "TEMPO", "TIME", "KEY", +"REST", "TUPLE", "NOTE", "NONOTE", +"OLDTIE", "TEXT", "SLUR_ON", "SLUR_OFF", +"TIE", "CLOSE_TIE", "TITLE", "CHANNEL", +"TRANSPOSE", "RTRANSPOSE", "GTRANSPOSE", "GRACEON", +"GRACEOFF", "SETGRACE", "SETC", "SETTRIM", "GCHORD", +"GCHORDON", "GCHORDOFF", "VOICE", "CHORDON", +"CHORDOFF", "CHORDOFFEX", "DRUMON", "DRUMOFF", +"DRONEON", "DRONEOFF", "SLUR_TIE", "TNOTE", +"LT", "GT", "DYNAMIC", "LINENUM", +"MUSICLINE", "MUSICSTOP", "WORDLINE", "WORDSTOP", +"INSTRUCTION", "NOBEAM", "CHORDNOTE", "CLEF", +"PRINTLINE", "NEWPAGE", "LEFT_TEXT", "CENTRE_TEXT", +"VSKIP", "COPYRIGHT", "COMPOSER", "ARPEGGIO", +"SPLITVOICE" +}; + + + +void event_info (place) +char * place; +{ +} + +void event_gchord (chord) +char * chord; +{ +} + +void event_slur (t) +int t; +{ +} + + +void event_instruction (s) +char *s; +{ +} + + +void event_reserved (p) +char p; +{ +} + +int bar_num, bar_denom, barno, barsize; +int b_num,b_denom; + +void reduce(a, b) +/* elimate common factors in fraction a/b */ +int *a, *b; +{ + int sign; + int t, n, m; + + if (*a < 0) { + sign = -1; + *a = -*a; + } else { + sign = 1; + }; + /* find HCF using Euclid's algorithm */ + if (*a > *b) { + n = *a; + m = *b; + } else { + n = *b; + m = *a; + }; + while (m != 0) { + t = n % m; + n = m; + m = t; + }; + *a = (*a/n)*sign; + *b = *b/n; +} + +void addunits(a, b) +/* add a/b to the count of units in the bar */ +int a, b; +{ + bar_num = bar_num*(b*b_denom) + (a*b_num)*bar_denom; + bar_denom = bar_denom * (b*b_denom); + reduce(&bar_num, &bar_denom); +} + + +void set_meter(n, m) +/* set up variables associated with meter */ +int n, m; +{ + /* set up barsize */ + barsize = n; + if (barsize % 3 == 0) { + beat = 3; + } else { + if (barsize % 2 == 0) { + beat = 2; + } else { + beat = barsize; + }; + }; + /* correction factor to make sure we count in the right units */ + if (m > 4) { + b_num = m/4; + b_denom = 1; + } else { + b_num = 1; + b_denom = 4/m; + }; +} + +int dummydecorator[DECSIZE]; /* used in event_chord */ + + +static struct voicecontext* newvoice(n) +/* allocate and initialize the data for a new voice */ +int n; +{ + struct voicecontext *s; + int i; + + s = (struct voicecontext*) checkmalloc(sizeof(struct voicecontext)); + voicecount = voicecount + 1; + s->voiceno = n; + s->indexno = voicecount; + s->default_length = global.default_length; + s->hasgchords = 0; + s->haswords = 0; + s->inslur = 0; + s->ingrace = 0; + s->inchord = 0; + s->chordcount = 0; + s->laststart = -1; + s->lastend = -1; + s->thisstart = -1; + s->thisend = -1; + s->brokenpending = -1; + s->next = NULL; + for (i=0; i<7; i++) { + s->basemap[i] = global.basemap[i]; + s->basemul[i] = global.basemul[i]; + s->workmap[i] = global.workmap[i]; + s->workmul[i] = global.workmul[i]; + }; + s->octaveshift = global.octaveshift; + return(s); +} + +static struct voicecontext* getvoicecontext(n) +/* find the data structure for a given voice number */ +int n; +{ + struct voicecontext *p; + struct voicecontext *q; + + p = head; + q = NULL; + while ((p != NULL) && (p->voiceno != n)) { + q = p; + p = p->next; + }; + if (p == NULL) { + p = newvoice(n); + if (q != NULL) { + q->next = p; + }; + }; + if (head == NULL) { + head = p; + }; + return(p); +} + +static void clearvoicecontexts() +/* free up all the memory allocated to voices */ +{ + struct voicecontext *p; + struct voicecontext *q; + + p = head; + while (p != NULL) { + q = p->next; + free(p); + p = q; + }; + head = NULL; +} + + + + +void event_text(s) +/* text found in abc file */ +char *s; +{ +} + + +void event_specific (package, s) +char *package, *s; +{ +} + + +void event_x_reserved(p) +/* reserved character H-Z found in abc file */ +char p; +{ +} + +void event_abbreviation(symbol, string, container) +/* abbreviation encountered - this is handled within the parser */ +char symbol; +char *string; +char container; +{ +} + + +void event_acciaccatura() +{ +/* does nothing here but outputs a / in abc2abc */ +return; +} + +void event_split_voice() +{ +} + + + +void event_tex(s) +/* TeX command found - ignore it */ +char *s; +{ +} + +void event_fatal_error(s) +/* print error message and halt */ +char *s; +{ + event_error(s); + exit(1); +} + +void event_error(s) +/* generic error handler */ +char *s; +{ +if (noerror) return; +#ifdef NOFTELL + extern int nullpass; + + if (nullpass != 1) { + printf("Error in line %d : %s\n", lineno, s); + }; +#else + printf("Error in line %d : %s\n", lineno, s); +#endif +} + +void event_warning(s) +/* generic warning handler - for flagging possible errors */ +char *s; +{ +if (nowarn) return; +#ifdef NOFTELL + extern int nullpass; + + if (nullpass != 1) { + printf("Warning in line %d : %s\n", lineno, s); + }; +#else + printf("Warning in line %d : %s\n", lineno, s); +#endif +} + +static int autoextend(maxnotes) +/* increase the number of abc elements the program can cope with */ +int maxnotes; +{ + int newlimit; + int *ptr; + featuretype *fptr; + int i; + + if (verbose) { + event_warning("Extending note capacity"); + }; + newlimit = maxnotes*2; + fptr = (featuretype*) checkmalloc(newlimit*sizeof(featuretype)); + for(i=0;i= maxnotes) { + maxnotes = autoextend(maxnotes); + }; +} + +void event_linebreak() +/* reached end of line in abc */ +{ + addfeature(LINENUM, lineno, 0, 0); +} + +void event_startmusicline() +/* starting to parse line of abc music */ +{ + addfeature(MUSICLINE, 0, 0, 0); +} + +void event_endmusicline(endchar) +/* finished parsing line of abc music */ +char endchar; +{ + addfeature(MUSICSTOP, 0, 0, 0); +} + +static void textfeature(type, s) +/* called while parsing abc - stores an item which requires an */ +/* associared string */ +int type; +char* s; +{ +} + +void event_comment(s) +/* comment found in abc */ +char *s; +{ +} + + +void event_startinline() +/* start of in-line field in abc music line */ +{ +} + +void event_closeinline() +/* end of in-line field in abc music line */ +{ +} + +void event_field(k, f) +/* Handles R: T: and any other field not handled elsewhere */ +char k; +char *f; +{ + if (dotune) { + switch (k) { + case 'R': + { + char* p; + + p = f; + skipspace(&p); +/******** if ((strncmp(p, "Hornpipe", 8) == 0) || + (strncmp(p, "hornpipe", 8) == 0)) { + hornpipe = 1; + }; +********/ + }; + break; + default: + { + }; + }; + }; +} + +void event_words(p, continuation) +/* handles a w: field in the abc */ +char* p; +int continuation; +{ +} + + +static void checkbreak() +/* check that we are in not in chord, grace notes or tuple */ +/* called at voice change */ +{ + if (tuplecount != 0) { + event_error("Previous voice has an unfinished tuple"); + tuplecount = 0; + }; + if (v->inchord != 0) { + event_error("Previous voice has incomplete chord"); + event_chordoff(1,1); + }; + if (v->ingrace != 0) { + event_error("Previous voice has unfinished grace notes"); + v->ingrace = 0; + }; +} + + +static void read_spec(spec, part) +/* converts a P: field to a list of part labels */ +/* e.g. P:A(AB)3(CD)2 becomes P:AABABABCDCD */ +/* A '+' indicates 'additive' behaviour (a part may include repeats). */ +/* A '-' indicates 'non-additive' behaviour (repeat marks in the music */ +/* are ignored and only repeats implied by the part order statement */ +/* are played). */ +char spec[]; +struct vstring* part; +{ +} + +void event_part(s) +/* handles a P: field in the abc */ +char* s; +{ + char* p; + + if (dotune) { + p = s; + skipspace(&p); + if (pastheader) { + if (((int)*p < 'A') || ((int)*p > 'Z')) { + event_error("Part must be one of A-Z"); + return; + }; + if ((headerpartlabel == 1) && (part.st[0] == *p)) { + /* P: field in header is not a label */ + headerpartlabel = 0; + /* remove speculative part label */ + feature[part_start[(int)*p - (int)'A']] = NONOTE; + } else { + if (part_start[(int)*p - (int)'A'] != -1) { + event_error("Part defined more than once"); + }; + }; + part_start[(int)*p - (int)'A'] = notes; + addfeature(PART, (int)*p, 0, 0); + checkbreak(); + v = getvoicecontext(1); + } else { + parts = 0; + read_spec(p, &part); + if (parts == 1) { + /* might be a label not a specificaton */ + headerpartlabel = 1; + }; + }; + }; +} + +void event_voice(n, s, vp) +/* handles a V: field in the abc */ +int n; +char *s; +struct voice_params *vp; +{ + if (pastheader || XTEN1) { + voicesused = 1; + if (pastheader) checkbreak(); + v = getvoicecontext(n); + addfeature(VOICE, v->indexno, 0, 0); + if (vp->gotoctave) { + event_octave(vp->octave,1); + }; + if (vp->gottranspose) { + addfeature(TRANSPOSE, vp->transpose, 0, 0); + }; + } else { + event_warning("V: in header ignored"); + }; +} + + +void event_length(n) +/* handles an L: field in the abc */ +int n; +{ + note_unit_length = 8; + if (pastheader) { + v->default_length = n; + } else { + global.default_length = n; + }; +} + +static void tempounits(t_num, t_denom) +/* interprets Q: once default length is known */ +int *t_num, *t_denom; +{ +} + +void event_tempo(n, a, b, rel, pre, post) +/* handles a Q: field e.g. Q: a/b = n or Q: Ca/b = n */ +/* strings before and after are ignored */ +int n; +int a, b, rel; +char *pre; +char *post; +{ +} + + +void event_timesig(n, m, dochecking) +/* handles an M: field M:n/m */ +int n, m, dochecking; +{ + if (dotune) { + if (pastheader) { + addfeature(TIME, dochecking, n, m); + } else { + time_num = n; + time_denom = m; + timesigset = 1; + barchecking = dochecking; + }; + }; +} + +void event_octave(num, local) +/* used internally by other routines when octave=N is encountered */ +/* in I: or K: fields */ +int num; +{ + if (dotune) { + if (pastheader || local) { + v->octaveshift = num; + } else { + global.octaveshift = num; + }; + }; +} + +void event_info_key(key, value) +char* key; +char* value; +{ + int num; + + if (strcmp(key, "octave")==0) { + num = readsnumf(value); + event_octave(num,0); + }; +} + +static void stack_broken(v) +struct voicecontext* v; +{ + v->broken_stack[0] = v->laststart; + v->broken_stack[1] = v->lastend; + v->broken_stack[2] = v->thisstart; + v->broken_stack[3] = v->thisend; + v->broken_stack[4] = v->brokentype; + v->broken_stack[5] = v->brokenmult; + v->broken_stack[6] = v->brokenpending; + v->laststart = -1; + v->lastend = -1; + v->thisstart = -1; + v->thisend = -1; + v->brokenpending = -1; +} + +static void restore_broken(v) +struct voicecontext* v; +{ + if (v->brokenpending != -1) { + event_error("Unresolved broken rhythm in grace notes"); + }; + v->laststart = v->broken_stack[0]; + v->lastend = v->broken_stack[1]; + v->thisstart = v->broken_stack[2]; + v->thisend = v->broken_stack[3]; + v->brokentype = v->broken_stack[4]; + v->brokenmult = v->broken_stack[5]; + v->brokenpending = v->broken_stack[6]; +} + +void event_graceon() +/* a { in the abc */ +{ + if (gracenotes) { + event_error("Nested grace notes not allowed"); + } else { + if (v->inchord) { + event_error("Grace notes not allowed in chord"); + } else { + gracenotes = 1; + addfeature(GRACEON, 0, 0, 0); + v->ingrace = 1; + stack_broken(v); + }; + }; +} + +void event_graceoff() +/* a } in the abc */ +{ + if (!gracenotes) { + event_error("} without matching {"); + } else { + gracenotes = 0; + addfeature(GRACEOFF, 0, 0, 0); + v->ingrace = 0; + restore_broken(v); + }; +} + +void event_rep1() +/* [1 in the abc */ +{ + addfeature(PLAY_ON_REP, 0, 0, 1); +/* + if ((notes == 0) || (feature[notes-1] != SINGLE_BAR)) { + event_error("[1 must follow a single bar"); + } else { + feature[notes-1] = BAR1; + }; +*/ +} + +void event_rep2() +/* [2 in the abc */ +{ + addfeature(PLAY_ON_REP, 0, 0, 2); +/* + if ((notes == 0) || (feature[notes-1] != REP_BAR)) { + event_error("[2 must follow a :| "); + } else { + feature[notes-1] = REP_BAR2; + }; +*/ +} + +void event_playonrep(s) +char* s; +/* [X in the abc, where X is a list of numbers */ +{ + int num, converted; + char seps[2]; + + converted = sscanf(s, "%d%1[,-]", &num, seps); + if (converted == 0) { + event_error("corrupted variant ending"); + } else { + if ((converted == 1) && (num != 0)) { + addfeature(PLAY_ON_REP, 0, 0, num); + } else { + textfeature(PLAY_ON_REP, s); + }; + }; +} + +static void slurtotie() +/* converts a pair of identical slurred notes to tied notes */ +{ +} + +void event_sluron(t) +/* called when ( is encountered in the abc */ +int t; +{ + if (t == 1) { + addfeature(SLUR_ON, 0, 0, 0); + v->inslur = 1; + }; +} + +void event_sluroff(t) +/* called when ) is encountered */ +int t; +{ + if (t == 0) { + slurtotie(); + addfeature(SLUR_OFF, 0, 0, 0); + v->inslur = 0; + }; +} + +void event_tie() +/* a tie - has been encountered in the abc */ +{ + addfeature(TIE, 0, 0, 0); +} + +void event_space() +/* space character in the abc is ignored by abc2midi */ +{ + /* ignore */ + /* printf("Space event\n"); */ +} + +void event_lineend(ch, n) +/* called when \ or ! or * or ** is encountered at the end of a line */ +char ch; +int n; +{ + /* ignore */ +} + +void event_broken(type, mult) +/* handles > >> >>> < << <<< in the abc */ +int type, mult; +{ + if (v->inchord) { + event_error("Broken rhythm not allowed in chord"); + } else { + if (v->ingrace) { + event_error("Broken rhythm not allowed in grace notes"); + } else { + v->brokentype = type; + v->brokenmult = mult; + v->brokenpending = 0; + }; + }; +} + +void event_tuple(n, q, r) +/* handles triplets (3 and general tuplets (n:q:r in the abc */ +int n, q, r; +{ + if (tuplecount > 0) { + event_error("nested tuples"); + } else { + if (r == 0) { + specialtuple = 0; + tuplecount = n; + } else { + specialtuple = 1; + tuplecount = r; + }; + if (q != 0) { + tfact_num = q; + tfact_denom = n; + } else { + if ((n < 2) || (n > 9)) { + event_error("Only tuples (2 - (9 allowed"); + tfact_num = 1; + tfact_denom = 1; + tuplecount = 0; + } else { + /* deduce tfact_num using standard abc rules */ + if ((n == 2) || (n == 4) || (n == 8)) tfact_num = 3; + if ((n == 3) || (n == 6)) tfact_num = 2; + if ((n == 5) || (n == 7) || (n == 9)) { + if ((time_num % 3) == 0) { + tfact_num = 3; + } else { + tfact_num = 2; + }; + }; + tfact_denom = n; + }; + }; + tnote_num = 0; + tnote_denom = 0; + }; +} + +void event_chord() +/* a + has been encountered in the abc */ +{ + if (v->inchord) { + event_chordoff(1,1); + } else { + event_chordon(dummydecorator); + }; +} + +static void lenmul(n, a, b) +/* multiply note length by a/b */ +int n, a, b; +{ + if ((feature[n] == NOTE) || (feature[n] == REST) || + (feature[n] == CHORDOFF)) { + num[n] = num[n] * a; + denom[n] = denom[n] * b; + reduce(&num[n], &denom[n]); + }; +} + + +static void brokenadjust() +/* adjust lengths of broken notes */ +{ + int num1, num2, denom12; + int j; + int failed; + + switch(v->brokenmult) { + default: + event_error("unsupported type of broken rhythm"); + case 1: + num1 = ratio_b; + num2 = ratio_a; + break; + case 2: + num1 = 7; + num2 = 1; + break; + case 3: + num1 = 15; + num2 = 1; + break; + }; + denom12 = (num1 + num2)/2; + if (v->brokentype == LT) { + j = num1; + num1 = num2; + num2 = j; + }; + failed = 0; + if ((v->laststart == -1) || (v->lastend == -1) || + (v->thisstart == -1) || (v->thisend == -1)) { + failed = 1; + } else { + /* check for same length notes */ + if ((num[v->laststart]*denom[v->thisstart]) != + (num[v->thisstart]*denom[v->laststart])) { + failed = 1; + }; + }; + if (failed) { + event_error("Cannot apply broken rhythm"); + } else { +/* + printf("Adjusting %d to %d and %d to %d\n", + v->laststart, v->lastend, v->thisstart, v->thisend); +*/ + for (j=v->laststart; j<=v->lastend; j++) { + lenmul(j, num1, denom12); + }; + for (j=v->thisstart; j<=v->thisend; j++) { + lenmul(j, num2, denom12); + }; + }; +} + +static void marknotestart() +/* voice data structure keeps a record of last few notes encountered */ +/* in order to process broken rhythm. This is called at the start of */ +/* a note or chord */ +{ + v->laststart = v->thisstart; + v->lastend = v->thisend; + v->thisstart = notes-1; +} + +static void marknoteend() +/* voice data structure keeps a record of last few notes encountered */ +/* in order to process broken rhythm. This is called at the end of */ +/* a note or chord */ +{ + v->thisend = notes-1; + if (v->brokenpending != -1) { + v->brokenpending = v->brokenpending + 1; + if (v->brokenpending == 1) { + brokenadjust(); + v->brokenpending = -1; + }; + }; +} + +static void marknote() +/* when handling a single note, not a chord, marknotestart() and */ +/* marknoteend() can be called together */ +{ + marknotestart(); + marknoteend(); +} + +/* just a stub to ignore 'y' */ +void event_spacing(n, m) +int n,m; +{ +} + +void event_rest(decorators,n,m,type) +/* rest of n/m in the abc */ +int n, m,type; +int decorators[DECSIZE]; +{ + int num, denom; + + num = n; + denom = m; + if (v == NULL) { + event_fatal_error("Internal error : no voice allocated"); + }; + if (v->inchord) v->chordcount = v->chordcount + 1; + if (tuplecount > 0) { + num = num * tfact_num; + denom = denom * tfact_denom; + if (tnote_num == 0) { + tnote_num = num; + tnote_denom = denom; + } else { + if (tnote_num * denom != num * tnote_denom) { + if (!specialtuple) { + event_warning("Different length notes in tuple"); + }; + }; + }; + if ((!gracenotes) && (!v->inchord)) { + tuplecount = tuplecount - 1; + }; + }; + if (v->chordcount == 1) { + v->chord_num = num*4; + v->chord_denom = denom*(v->default_length); + }; + if ((!v->ingrace) && ((!v->inchord)||(v->chordcount==1))) { + addunits(num, denom*(v->default_length)); + }; + last_num = 3; /* hornpiping (>) cannot follow rest */ + addfeature(REST, 0, num*4, denom*(v->default_length)); + if (!v->inchord ) { + marknote(); + }; +} + +void event_mrest(n,m) +/* multiple bar rest of n/m in the abc */ +/* we check for m == 1 in the parser */ +int n, m; +{ + int i; + int decorators[DECSIZE]; + decorators[FERMATA]=0; +/* it is not legal to pass a fermata to a multirest */ + + for (i=0; idefault_length), time_denom,0); + if (i != n-1) { + event_bar(SINGLE_BAR, ""); + }; + }; +} + + + +void event_chordon(int chorddecorators[]) +/* handles a chord start [ in the abc */ +/* the array chorddecorators is needed in toabc.c and yapstree.c */ +/* but is not relevant here. */ + +{ + if (v->inchord) { + event_error("Attempt to nest chords"); + } else { + addfeature(CHORDON, 0, 0, 0); + v->inchord = 1; + v->chordcount = 0; + v->chord_num = 0; + v->chord_denom = 1; + marknotestart(); + }; +} + +void event_chordoff(int chord_n, int chord_m) +/* handles a chord close ] in the abc */ +{ + if (!v->inchord) { + event_error("Chord already finished"); + } else { + + if(chord_m == 1 && chord_n == 1) /* chord length not set outside [] */ + addfeature(CHORDOFF, 0, v->chord_num, v->chord_denom); + else + addfeature(CHORDOFFEX, 0, chord_n*4, chord_m*v->default_length); + + v->inchord = 0; + v->chordcount = 0; + marknoteend(); + if (tuplecount > 0) --tuplecount; + }; +} + + +void event_finger(p) +/* a 1, 2, 3, 4 or 5 has been found in a guitar chord field */ +char *p; +{ + /* does nothing */ +} + +static int pitchof(note, accidental, mult, octave, propogate_accs) +/* finds MIDI pitch value for note */ +/* if propogate_accs is 1, apply any accidental to all instances of */ +/* that note in the bar. If propogate_accs is 0, accidental does not */ +/* apply to other notes */ +char note, accidental; +int mult, octave; +int propogate_accs; +{ + int p; + char acc; + int mul, noteno; + static int scale[7] = {0, 2, 4, 5, 7, 9, 11}; + char *anoctave = "cdefgab"; + + p = (int) ((long) strchr(anoctave, note) - (long) anoctave); + p = scale[p]; + acc = accidental; + mul = mult; + noteno = (int)note - 'a'; + if (acc == ' ') { + acc = v->workmap[noteno]; + mul = v->workmul[noteno]; + } else { + if ((retain_accidentals) && (propogate_accs)) { + v->workmap[noteno] = acc; + v->workmul[noteno] = mul; + }; + }; + if (acc == '^') p = p + mul; + if (acc == '_') p = p - mul; + return p + 12*octave + middle_c; +} + + + +static void hornp(num, denom) +/* If we have used R:hornpipe, this routine modifies the rhythm by */ +/* applying appropriate broken rhythm */ +int num, denom; +{ + if ((hornpipe) && (notes > 0) && (feature[notes-1] != GT)) { + if ((num*last_denom == last_num*denom) && (num == 1) && + (denom*time_num == 32)) { + if (((time_num == 4) && (bar_denom == 8)) || + ((time_num == 2) && (bar_denom == 16))) { + /* addfeature(GT, 1, 0, 0); */ + v->brokentype = GT; + v->brokenmult = 1; + v->brokenpending = 0; + }; + }; + last_num = num; + last_denom = denom; + }; +} + + +void event_note(decorators, accidental, mult, note, xoctave, n, m) +/* handles a note in the abc */ +int decorators[DECSIZE]; +int mult; +char accidental, note; +int xoctave, n, m; +{ + int pitch; + int pitch_noacc; + int num, denom; + int octave; + + if (v == NULL) { + event_fatal_error("Internal error - no voice allocated"); + }; + octave = xoctave + v->octaveshift; + num = n; + denom = m; + if (v->inchord) v->chordcount = v->chordcount + 1; + if (tuplecount > 0) { + num = num * tfact_num; + denom = denom * tfact_denom; + if (tnote_num == 0) { + tnote_num = num; + tnote_denom = denom; + } else { + if (tnote_num * denom != num * tnote_denom) { + if (!specialtuple) { + event_warning("Different length notes in tuple"); + }; + }; + }; + if ((!gracenotes) && + ((!v->inchord) || ((v->inchord) && (v->chordcount == 1)))) { + tuplecount = tuplecount - 1; + }; + }; + if ((!v->ingrace) && (!v->inchord)) { + hornp(num, denom*(v->default_length)); + } else { + last_num = 3; /* hornpiping (>) cannot follow chord or grace notes */ + }; + if ((!v->ingrace) && ((!v->inchord)||(v->chordcount==1))) { + addunits(num, denom*(v->default_length)); + }; + pitch = pitchof(note, accidental, mult, octave, 1); + pitch_noacc = pitchof(note,0,0,octave,0); + if (decorators[FERMATA]) { + num = num*2; + }; + if (v->chordcount == 1) { + v->chord_num = num*4; + v->chord_denom = denom*(v->default_length); + }; + + pitchline[notes] = pitch_noacc; + addfeature(NOTE, pitch, num*4, denom*(v->default_length)); + marknote(); +} + +void event_microtone(int dir, int a, int b) +{ +} + +void event_normal_tone() +{ +} + + + +char *get_accidental(place, accidental) +/* read in accidental - used by event_handle_gchord() */ +char *place; /* place in string being parsed */ +char *accidental; /* pointer to char variable */ +{ + char *p; + + p = place; + *accidental = '='; + if (*p == '#') { + *accidental = '^'; + p = p + 1; + }; + if (*p == 'b') { + *accidental = '_'; + p = p + 1; + }; + return(p); +} + +void event_handle_gchord(s) +/* handler for the guitar chords */ +char* s; +{ +} + +void event_handle_instruction(s) +/* handler for ! ! instructions */ +/* does ppp pp p mp mf f ff fff */ +/* also does !drum! and !nodrum! */ +char* s; +{ +} + +static void setmap(sf, map, mult) +/* work out accidentals to be applied to each note */ +int sf; /* number of sharps in key signature -7 to +7 */ +char map[7]; +int mult[7]; +{ + int j; + + for (j=0; j<7; j++) { + map[j] = '='; + mult[j] = 1; + }; + if (sf >= 1) map['f'-'a'] = '^'; + if (sf >= 2) map['c'-'a'] = '^'; + if (sf >= 3) map['g'-'a'] = '^'; + if (sf >= 4) map['d'-'a'] = '^'; + if (sf >= 5) map['a'-'a'] = '^'; + if (sf >= 6) map['e'-'a'] = '^'; + if (sf >= 7) map['b'-'a'] = '^'; + if (sf <= -1) map['b'-'a'] = '_'; + if (sf <= -2) map['e'-'a'] = '_'; + if (sf <= -3) map['a'-'a'] = '_'; + if (sf <= -4) map['d'-'a'] = '_'; + if (sf <= -5) map['g'-'a'] = '_'; + if (sf <= -6) map['c'-'a'] = '_'; + if (sf <= -7) map['f'-'a'] = '_'; +} + +static void altermap(v, modmap, modmul) +/* apply modifiers to a set of accidentals */ +struct voicecontext* v; +char modmap[7]; +int modmul[7]; +{ + int i; + + for (i=0; i<7; i++) { + if (modmap[i] != ' ') { + v->basemap[i] = modmap[i]; + v->basemul[i] = modmul[i]; + }; + }; +} + +static void copymap(v) +/* sets up working map at the start of each bar */ +struct voicecontext* v; +{ + int j; + + for (j=0; j<7; j++) { + v->workmap[j] = v->basemap[j]; + v->workmul[j] = v->basemul[j]; + }; +} + +/* workaround for problems with PCC compiler */ +/* data may be written to an internal buffer */ + +int myputc(c) +char c; +{ + return (putc(c,fp)); +} + +static void addfract(xnum, xdenom, a, b) +/* add a/b to the count of units in the bar */ +int *xnum; +int *xdenom; +int a, b; +{ + *xnum = (*xnum)*b + a*(*xdenom); + *xdenom = (*xdenom) * b; + reduce(xnum, xdenom); +} + + +static void dotie(j, xinchord,voiceno) +/* called in preprocessing stage to handle ties */ +/* we need the voiceno in case a tie is broken by a */ +/* voice switch. */ +int j, xinchord,voiceno; +{ + int tienote, place; + int tietodo, done; + int lastnote, lasttie; + int inchord; + int tied_num, tied_denom; + int localvoiceno; + int samechord; + + /* find note to be tied */ + samechord = 0; + if (xinchord) samechord = 1; + tienote = j; + localvoiceno = voiceno; + while ((tienote > 0) && (feature[tienote] != NOTE) && + (feature[tienote] != REST)) { + tienote = tienote - 1; + }; + if (feature[tienote] != NOTE) { + event_error("Cannot find note before tie"); + } else { + inchord = xinchord; + /* change NOTE + TIE to TNOTE + REST */ + feature[tienote] = TNOTE; + feature[j] = REST; + num[j] = num[tienote]; + denom[j] = denom[tienote]; + place = j; + tietodo = 1; + lasttie = j; + tied_num = num[tienote]; + tied_denom = denom[tienote]; + lastnote = -1; + done = 0; + while ((place < notes) && (tied_num >=0) && (done == 0)) { + /* printf("%d %s %d %d/%d ",place,featname[feature[place]],pitch[place],num[place],denom[place]); */ + switch (feature[place]) { + case NOTE: + if(localvoiceno != voiceno) break; + lastnote = place; + if ((tied_num == 0) && (tietodo == 0)) { + done = 1; + }; + if ((pitchline[place] == pitchline[tienote]) + && (tietodo == 1) && (samechord == 0)) { + /* tie in note */ + if (tied_num != 0) { + event_error("Time mismatch at tie"); + }; + tietodo = 0; + pitch[place] = pitch[tienote]; /* in case accidentals did not + propagate */ + /* add time to tied time */ + addfract(&tied_num, &tied_denom, num[place], denom[place]); + /* add time to tied note */ + addfract(&num[tienote], &denom[tienote], num[place], denom[place]); + /* change note to a rest */ + feature[place] = REST; + /* get rid of tie */ + if (lasttie != j) { + feature[lasttie] = OLDTIE; + }; + }; + if (inchord == 0) { + /* subtract time from tied time */ + addfract(&tied_num, &tied_denom, -num[place], denom[place]); + }; + break; + case REST: + if(localvoiceno != voiceno) break; + if ((tied_num == 0) && (tietodo == 0)) { + done = 1; + }; + if (inchord == 0) { + /* subtract time from tied time */ + addfract(&tied_num, &tied_denom, -num[place], denom[place]); + }; + break; + case TIE: + if(localvoiceno != voiceno) break; + if (lastnote == -1) { + event_error("Bad tie: possibly two ties in a row"); + } else { + if (pitch[lastnote] == pitch[tienote] && samechord == 0) { + lasttie = place; + tietodo = 1; + if (inchord) samechord = 1; + }; + }; + break; + case CHORDON: + if(localvoiceno != voiceno) break; + inchord = 1; + break; + case CHORDOFF: + case CHORDOFFEX: + samechord = 0; + if(localvoiceno != voiceno) break; + inchord = 0; + /* subtract time from tied time */ + addfract(&tied_num, &tied_denom, -num[place], denom[place]); + break; + case VOICE: + localvoiceno = pitch[place]; + default: + break; + }; + /*printf("tied_num = %d done = %d inchord = %d\n",tied_num, done, inchord); */ + place = place + 1; + }; + if (tietodo == 1) { + event_error("Could not find note to be tied"); + }; + }; +/* printf("dotie finished\n"); */ +} + +static void tiefix() +/* connect up tied notes and cleans up the */ +/* note lengths in the chords (eg [ace]3 ) */ +{ + int j; + int inchord; + int chord_num = 0, chord_denom = 0; + int chord_start,chord_end; + int voiceno; + + j = 0; + inchord = 0; + voiceno = 1; + while (j 0) { + event_playonrep(replist); + }; +/* + if (type == BAR1) { + addfeature(PLAY_ON_REP, 0, 0, 1); + }; + if (type == REP_BAR2) { + addfeature(PLAY_ON_REP, 0, 0, 2); + }; +*/ +} + + + + +void startfile() +/* called at the beginning of an abc tune by event_refno */ +/* This sets up all the default values */ +{ + int j; + + if (verbose) { + printf("scanning tune\n"); + }; + /* set up defaults */ + sf = 0; + mi = 0; + setmap(0, global.basemap, global.basemul); + copymap(&global); + global.octaveshift = 0; + voicecount = 0; + head = NULL; + v = NULL; + time_num = 4; + time_denom = 4; + timesigset = 0; + barchecking = 1; + global.default_length = -1; + event_tempo(120, 1, 4, 0,NULL, NULL); + notes = 0; + ntexts = 0; + gfact_num = 1; + gfact_denom = 3; + global_transpose = 0; + hornpipe = 0; + karaoke = 0; + retain_accidentals = 1; + ratio_a = 2; + ratio_b = 4; + wcount = 0; + parts = -1; + middle_c = 60; + for (j=0; j<26; j++) { + part_start[j] = -1; + }; + headerpartlabel = 0; + additive = 1; + initvstring(&part); + } + + +static void headerprocess() +/* called after the K: field has been reached, signifying the end of */ +/* the header and the start of the tune */ +{ + int t_num, t_denom; + + if (headerpartlabel == 1) { + part_start[(int)part.st[0] - (int)'A'] = notes; + addfeature(PART, part.st[0], 0, 0); + }; + addfeature(DOUBLE_BAR, 0, 0, 0); + pastheader = 1; + + gracenotes = 0; /* not in a grace notes section */ + if (!timesigset) { + event_warning("No M: in header, using default"); + }; + /* calculate time for a default length note */ + if (global.default_length == -1) { + if (((float) time_num)/time_denom < 0.75) { + global.default_length = 16; + } else { + global.default_length = 8; + }; + }; + bar_num = 0; + bar_denom = 1; + set_meter(time_num, time_denom); + if (hornpipe) { + if ((time_denom != 4) || ((time_num != 2) && (time_num != 4))) { + event_error("Hornpipe must be in 2/4 or 4/4 time"); + hornpipe = 0; + }; + }; + + tempounits(&t_num, &t_denom); + /* make tempo in terms of 1/4 notes */ +/* tempo = (long) 60*1000000*t_denom/(Qtempo*4*t_num); */ +/* div_factor = division; */ + voicesused = 0; +} + +void event_key(sharps, s, modeindex, modmap, modmul, gotkey, gotclef, clefname, + octave, transpose, gotoctave, gottranspose) +/* handles a K: field */ +int sharps; /* sharps is number of sharps in key signature */ +int modeindex; /* 0 major, 1,2,3 minor, 4 locrian, etc. */ +char *s; /* original string following K: */ +char modmap[7]; /* array of accidentals to be applied */ +int modmul[7]; /* array giving multiplicity of each accent (1 or 2) */ +int gotkey, gotclef; +int octave, transpose, gotoctave, gottranspose; +char* clefname; +{ + int minor; + if (modeindex >0 && modeindex <4) minor = 1; + if ((dotune) && gotkey) { + if (pastheader) { + setmap(sharps, v->basemap, v->basemul); + altermap(v, modmap, modmul); + copymap(v); + addfeature(KEY, sharps, 0, minor); + if (gottranspose) { + addfeature(TRANSPOSE, transpose, 0, 0); + }; + } else { + if (gottranspose) { + global_transpose = transpose; + }; + setmap(sharps, global.basemap, global.basemul); + altermap(&global, modmap, modmul); + copymap(&global); + sf = sharps; + mi = minor; + headerprocess(); + v = newvoice(1); + head = v; + }; + if (gotoctave) { + event_octave(octave,0); + }; + }; +} + + + +void print_feature_list () +{ +int i,length; +float fract; +printf("feature list \n"); +for (i=0;i -1) { + addfeature(PART, ' ', 0, 0); + }; + if (headerpartlabel == 1) { + event_error("P: field in header should go after K: field"); + }; + + tiefix(); + + + }; + for (i=0; i -#include -#ifdef ANSILIBS -#include -#endif -#include "midifile.h" - -static FILE *F; -int SECONDS; /* global that tells whether to display seconds or ticks */ -int division; /* from the file header */ -long tempo = 500000; /* the default tempo is 120 beats/minute */ - -filegetc() -{ - return(getc(F)); -} - -/* for crack */ -extern int arg_index; - -main(argc,argv) -char **argv; -{ - FILE *efopen(); - char *ch; - char *crack(); - - SECONDS = 0; - - while((ch = crack(argc,argv,"s",0)) != NULL){ - switch(*ch){ - case 's' : SECONDS = 1; break; - } - } - - if ((argc < 2 && !SECONDS) || (argc < 3 && SECONDS)) - F = stdin; - else - F = efopen(argv[arg_index],"rb"); - - initfuncs(); - Mf_getc = filegetc; - midifile(); - fclose(F); - exit(0); -} - -FILE * -efopen(name,mode) -char *name; -char *mode; -{ - FILE *f; - - if ( (f=fopen(name,mode)) == NULL ) { - fprintf(stderr,"Error - Cannot open file %s\n",name); - exit(0); - } - return(f); -} - -void error(s) -char *s; -{ - fprintf(stderr,"Error: %s\n",s); -} - -prtime() -{ - if(SECONDS) - printf("Time=%f ",mf_ticks2sec(Mf_currtime,division,tempo)); - else - printf("Time=%ld ",Mf_currtime); -} - -void txt_header(format,ntrks,ldivision) -{ - division = ldivision; - printf("Header format=%d ntrks=%d division=%d\n",format,ntrks,division); -} - -void txt_trackstart() -{ - printf("Track start\n"); -} - -void txt_trackend() -{ - printf("Track end\n"); -} - -void txt_noteon(chan,pitch,vol) -{ - prtime(); - printf("Note on, chan=%d pitch=%d vol=%d\n",chan+1,pitch,vol); -} - -void txt_noteoff(chan,pitch,vol) -{ - prtime(); - printf("Note off, chan=%d pitch=%d vol=%d\n",chan+1,pitch,vol); -} - -void txt_pressure(chan,pitch,press) -{ - prtime(); - printf("Pressure, chan=%d pitch=%d press=%d\n",chan+1,pitch,press); -} - -void txt_parameter(chan,control,value) -{ - prtime(); - printf("Parameter, chan=%d c1=%d c2=%d\n",chan+1,control,value); -} - -void txt_pitchbend(chan,msb,lsb) -{ - prtime(); - printf("Pitchbend, chan=%d msb=%d lsb=%d\n",chan+1,msb,lsb); -} - -void txt_program(chan,program) -{ - prtime(); - printf("Program, chan=%d program=%d\n",chan+1,program); -} - -void txt_chanpressure(chan,press) -{ - prtime(); - printf("Channel pressure, chan=%d pressure=%d\n",chan+1,press); -} - -void txt_sysex(leng,mess) -char *mess; -{ - prtime(); - printf("Sysex, leng=%d\n",leng); -} - -void txt_metamisc(type,leng,mess) -char *mess; -{ - prtime(); - printf("Meta event, unrecognized, type=0x%02x leng=%d\n",type,leng); -} - -void txt_metaspecial(type,leng,mess) -char *mess; -{ - prtime(); - printf("Meta event, sequencer-specific, type=0x%02x leng=%d\n",type,leng); -} - -void txt_metatext(type,leng,mess) -char *mess; -{ - static char *ttype[] = { - NULL, - "Text Event", /* type=0x01 */ - "Copyright Notice", /* type=0x02 */ - "Sequence/Track Name", - "Instrument Name", /* ... */ - "Lyric", - "Marker", - "Cue Point", /* type=0x07 */ - "Unrecognized" - }; - int unrecognized = (sizeof(ttype)/sizeof(char *)) - 1; - register int n, c; - register char *p = mess; - - if ( type < 1 || type > unrecognized ) - type = unrecognized; - prtime(); - printf("Meta Text, type=0x%02x (%s) leng=%d\n",type,ttype[type],leng); - printf(" Text = <"); - for ( n=0; n\n"); -} - -void txt_metaseq(num) -{ - prtime(); - printf("Meta event, sequence number = %d\n",num); -} - -void txt_metaeot() -{ - prtime(); - printf("Meta event, end of track\n"); -} - -void txt_keysig(sf,mi) -{ - prtime(); - printf("Key signature, sharp/flats=%d minor=%d\n",sf,mi); -} - -void txt_tempo(ltempo) -long ltempo; -{ - tempo = ltempo; - prtime(); - printf("Tempo, microseconds-per-MIDI-quarter-note=%ld\n",tempo); -} - -void txt_timesig(nn,dd,cc,bb) -{ - int denom = 1; - while ( dd-- > 0 ) - denom *= 2; - prtime(); - printf("Time signature=%d/%d MIDI-clocks/click=%d 32nd-notes/24-MIDI-clocks=%d\n", - nn,denom,cc,bb); -} - -void txt_smpte(hr,mn,se,fr,ff) -{ - prtime(); - printf("SMPTE, hour=%d minute=%d second=%d frame=%d fract-frame=%d\n", - hr,mn,se,fr,ff); -} - -void txt_arbitrary(leng,mess) -char *mess; -{ - prtime(); - printf("Arbitrary bytes, leng=%d\n",leng); -} - -initfuncs() -{ - Mf_error = error; - Mf_header = txt_header; - Mf_trackstart = txt_trackstart; - Mf_trackend = txt_trackend; - Mf_noteon = txt_noteon; - Mf_noteoff = txt_noteoff; - Mf_pressure = txt_pressure; - Mf_parameter = txt_parameter; - Mf_pitchbend = txt_pitchbend; - Mf_program = txt_program; - Mf_chanpressure = txt_chanpressure; - Mf_sysex = txt_sysex; - Mf_metamisc = txt_metamisc; - Mf_seqnum = txt_metaseq; - Mf_eot = txt_metaeot; - Mf_timesig = txt_timesig; - Mf_smpte = txt_smpte; - Mf_tempo = txt_tempo; - Mf_keysig = txt_keysig; - Mf_seqspecific = txt_metaspecial; - Mf_text = txt_metatext; - Mf_arbitrary = txt_arbitrary; -} +/* + * mftext + * + * Convert a MIDI file to verbose text. + * + * modified for portability 22/6/98 - error checking on file open failure + * removed. + */ + +#include +#if defined(ANSILIBS) || defined(__STDC__) +#include +#include +#endif +#include "midifile.h" + +static FILE *F; +int SECONDS; /* global that tells whether to display seconds or ticks */ +int division; /* from the file header */ +long tempo = 500000; /* the default tempo is 120 beats/minute */ + +filegetc() +{ + return(getc(F)); +} + +/* for crack */ +extern int arg_index; + +main(argc,argv) +char **argv; +{ + FILE *efopen(); + char *ch; + char *crack(); + + SECONDS = 0; + + while((ch = crack(argc,argv,"s",0)) != NULL){ + switch(*ch){ + case 's' : SECONDS = 1; break; + } + } + + if ((argc < 2 && !SECONDS) || (argc < 3 && SECONDS)) + F = stdin; + else + F = efopen(argv[arg_index],"rb"); + + initfuncs(); + Mf_getc = filegetc; + midifile(); + fclose(F); + exit(0); +} + +FILE * +efopen(name,mode) +char *name; +char *mode; +{ + FILE *f; + + if ( (f=fopen(name,mode)) == NULL ) { + fprintf(stderr,"Error - Cannot open file %s\n",name); + exit(0); + } + return(f); +} + +void error(s) +char *s; +{ + fprintf(stderr,"Error: %s\n",s); +} + +prtime() +{ + if(SECONDS) + printf("Time=%f ",mf_ticks2sec(Mf_currtime,division,tempo)); + else + printf("Time=%ld ",Mf_currtime); +} + +void txt_header(format,ntrks,ldivision) +{ + division = ldivision; + printf("Header format=%d ntrks=%d division=%d\n",format,ntrks,division); +} + +void txt_trackstart() +{ + printf("Track start\n"); +} + +void txt_trackend() +{ + printf("Track end\n"); +} + +void txt_noteon(chan,pitch,vol) +{ + prtime(); + printf("Note on, chan=%d pitch=%d vol=%d\n",chan+1,pitch,vol); +} + +void txt_noteoff(chan,pitch,vol) +{ + prtime(); + printf("Note off, chan=%d pitch=%d vol=%d\n",chan+1,pitch,vol); +} + +void txt_pressure(chan,pitch,press) +{ + prtime(); + printf("Pressure, chan=%d pitch=%d press=%d\n",chan+1,pitch,press); +} + +void txt_parameter(chan,control,value) +{ + prtime(); + printf("Parameter, chan=%d c1=%d c2=%d\n",chan+1,control,value); +} + +void txt_pitchbend(chan,msb,lsb) +{ + prtime(); + printf("Pitchbend, chan=%d msb=%d lsb=%d\n",chan+1,msb,lsb); +} + +void txt_program(chan,program) +{ + prtime(); + printf("Program, chan=%d program=%d\n",chan+1,program); +} + +void txt_chanpressure(chan,press) +{ + prtime(); + printf("Channel pressure, chan=%d pressure=%d\n",chan+1,press); +} + +void txt_sysex(leng,mess) +char *mess; +{ + prtime(); + printf("Sysex, leng=%d\n",leng); +} + +void txt_metamisc(type,leng,mess) +char *mess; +{ + prtime(); + printf("Meta event, unrecognized, type=0x%02x leng=%d\n",type,leng); +} + +void txt_metaspecial(type,leng,mess) +char *mess; +{ + prtime(); + printf("Meta event, sequencer-specific, type=0x%02x leng=%d\n",type,leng); +} + +void txt_metatext(type,leng,mess) +char *mess; +{ + static char *ttype[] = { + NULL, + "Text Event", /* type=0x01 */ + "Copyright Notice", /* type=0x02 */ + "Sequence/Track Name", + "Instrument Name", /* ... */ + "Lyric", + "Marker", + "Cue Point", /* type=0x07 */ + "Unrecognized" + }; + int unrecognized = (sizeof(ttype)/sizeof(char *)) - 1; + register int n, c; + register char *p = mess; + + if ( type < 1 || type > unrecognized ) + type = unrecognized; + prtime(); + printf("Meta Text, type=0x%02x (%s) leng=%d\n",type,ttype[type],leng); + printf(" Text = <"); + for ( n=0; n\n"); +} + +void txt_metaseq(num) +{ + prtime(); + printf("Meta event, sequence number = %d\n",num); +} + +void txt_metaeot() +{ + prtime(); + printf("Meta event, end of track\n"); +} + +void txt_keysig(sf,mi) +{ + prtime(); + printf("Key signature, sharp/flats=%d minor=%d\n",sf,mi); +} + +void txt_tempo(ltempo) +long ltempo; +{ + tempo = ltempo; + prtime(); + printf("Tempo, microseconds-per-MIDI-quarter-note=%ld\n",tempo); +} + +void txt_timesig(nn,dd,cc,bb) +{ + int denom = 1; + while ( dd-- > 0 ) + denom *= 2; + prtime(); + printf("Time signature=%d/%d MIDI-clocks/click=%d 32nd-notes/24-MIDI-clocks=%d\n", + nn,denom,cc,bb); +} + +void txt_smpte(hr,mn,se,fr,ff) +{ + prtime(); + printf("SMPTE, hour=%d minute=%d second=%d frame=%d fract-frame=%d\n", + hr,mn,se,fr,ff); +} + +void txt_arbitrary(leng,mess) +char *mess; +{ + prtime(); + printf("Arbitrary bytes, leng=%d\n",leng); +} + +initfuncs() +{ + Mf_error = error; + Mf_header = txt_header; + Mf_trackstart = txt_trackstart; + Mf_trackend = txt_trackend; + Mf_noteon = txt_noteon; + Mf_noteoff = txt_noteoff; + Mf_pressure = txt_pressure; + Mf_parameter = txt_parameter; + Mf_pitchbend = txt_pitchbend; + Mf_program = txt_program; + Mf_chanpressure = txt_chanpressure; + Mf_sysex = txt_sysex; + Mf_metamisc = txt_metamisc; + Mf_seqnum = txt_metaseq; + Mf_eot = txt_metaeot; + Mf_timesig = txt_timesig; + Mf_smpte = txt_smpte; + Mf_tempo = txt_tempo; + Mf_keysig = txt_keysig; + Mf_seqspecific = txt_metaspecial; + Mf_text = txt_metatext; + Mf_arbitrary = txt_arbitrary; +} --- abcmidi-20070318.orig/midi2abc.c +++ abcmidi-20070318/midi2abc.c @@ -1,3507 +1,3506 @@ -/* - * midi2abc - program to convert MIDI files to abc notation. - * Copyright (C) 1998 James Allwright - * e-mail: J.R.Allwright@westminster.ac.uk - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -/* new midi2abc - converts MIDI file to abc format files - * - * - * re-written to use dynamic data structures - * James Allwright - * 5th June 1998 - * - * added output file option -o - * added summary option -sum - * added option -u to enter xunit directly - * fixed computation of xunit using -b option - * added -obpl (one bar per line) option - * add check for carriage return embedded inside midi text line - * Seymour Shlien 04/March/00 - * made to conform as much as possible to the official version. - * check for drum track added - * when midi program channel is command encountered, we ensure that - * we are using the correct channel number for the Voice by sending - * a %%MIDI channel message. - * - * Many more changes (see doc/CHANGES) - * - * Seymour Shlien 2005 - * - * based on public domain 'midifilelib' package. - */ - -#define VERSION "2.90 March 15 2007" -#define SPLITCODE - -/* Microsoft Visual C++ Version 6.0 or higher */ -#ifdef _MSC_VER -#define ANSILIBS -#endif - -#include -#ifdef PCCFIX -#define stdout 1 -#endif - -/* define USE_INDEX if your C libraries have index() instead of strchr() */ -#ifdef USE_INDEX -#define strchr index -#endif - -#ifdef ANSILIBS -#include -#include -#include -#else -extern char* malloc(); -extern char* strchr(); -#endif -#include "midifile.h" -#define BUFFSIZE 200 -/* declare MIDDLE C */ -#define MIDDLE 72 -void initfuncs(); -void setupkey(int); -int testtrack(int trackno, int barbeats, int anacrusis); -int open_note(int chan, int pitch, int vol); -int close_note(int chan, int pitch, int *initvol); - - -/* Global variables and structures */ - -extern long Mf_toberead; - -static FILE *F; -static FILE *outhandle; /* for producing the abc file */ - -int tracknum=0; /* track number */ -int division; /* pulses per quarter note defined in MIDI header */ -long tempo = 500000; /* the default tempo is 120 quarter notes/minute */ -int unitlen; /* abc unit length usually defined in L: field */ -int header_unitlen; /* first unitlen set */ -int unitlen_set =0; /* once unitlen is set don't allow it to change */ -int parts_per_unitlen = 2; /* specifies minimum quantization size */ -long laston = 0; /* length of MIDI track in pulses or ticks */ -char textbuff[BUFFSIZE]; /*buffer for handling text output to abc file*/ -int trans[256], back[256]; /*translation tables for MIDI pitch to abc note*/ -char atog[256]; /* translation tables for MIDI pitch to abc note */ -int symbol[256]; /*translation tables for MIDI pitch to abc note */ -int key[12]; -int sharps; -int trackno, maintrack; -int format; /* MIDI file type */ - -int karaoke, inkaraoke; -int midline; -int tempocount=0; /* number of tempo indications in MIDI file */ -int gotkeysig=0; /*set to 1 if keysignature found in MIDI file */ - -/* global parameters that may be set by command line options */ -int xunit; /* pulses per abc unit length */ -int tsig_set; /* flag - time signature already set by user */ -int ksig_set; /* flag - key signature already set by user */ -int xunit_set;/* flat - xunit already set by user */ -int extracta; /* flag - get anacrusis from strong beat */ -int guessu; /* flag - estimate xunit from note durations */ -int guessa; /* flag - get anacrusis by minimizing tied notes */ -int guessk; /* flag - guess key signature */ -int summary; /* flag - output summary info of MIDI file */ -int keep_short; /*flag - preserve short notes */ -int swallow_rests; /* flag - absorb short rests */ -int midiprint; /* flag - run midigram instead of midi2abc */ -#ifdef SPLITCODE -int usesplits; /* flag - split measure into parts if needed */ -#endif -int restsize; /* smallest rest to absorb */ -int no_triplets; /* flag - suppress triplets or broken rhythm */ -int obpl = 0; /* flag to specify one bar per abc text line */ -int nogr = 0; /* flag to put a space between every note */ -int bars_per_line=4; /* number of bars per output line */ -int bars_per_staff=4; /* number of bars per music staff */ -int asig, bsig; /* time signature asig/bsig */ -int header_asig =0; /* first time signature encountered */ -int header_bsig =0; /* first time signature encountered */ -int header_bb; /* first ticks/quarter note encountered */ -int active_asig,active_bsig; /* last time signature declared */ -int last_asig, last_ksig; /* last time signature printed */ -int barsize; /* barsize in parts_per_unitlen units */ -int Qval; /* tempo - quarter notes per minute */ -int verbosity=0; /* control amount of detail messages in abcfile*/ - -/* global arguments dependent on command line options or computed */ - -int anacrusis=0; -int bars; -int keysig; -int header_keysig= -50; /* header key signature */ -int active_keysig = -50; /* last key signature declared */ -int xchannel; /* channel number to be extracted. -1 means all */ - - -/* structure for storing music notes */ -struct anote { - int pitch; /* MIDI pitch */ - int chan; /* MIDI channel */ - int vel; /* MIDI velocity */ - long time; /* MIDI onset time in pulses */ - long dtnext; /* time increment to next note in pulses */ - long tplay; /* note duration in pulses */ - int xnum; /* number of xunits to next note */ - int playnum; /* note duration in number of xunits */ - int posnum; /* note position in xunits */ - int splitnum; /* voice split number */ - /* int denom; */ -}; - - -/* linked list of notes */ -struct listx { - struct listx* next; - struct anote* note; -}; - -/* linked list of text items (strings) */ -struct tlistx { - struct tlistx* next; - char* text; - long when; /* time in pulses to output */ - int type; /* 0 - comments, other - field commands */ -}; - - -/* a MIDI track */ -struct atrack { - struct listx* head; /* first note */ - struct listx* tail; /* last note */ - struct tlistx* texthead; /* first text string */ - struct tlistx* texttail; /* last text string */ - int notes; /* number of notes in track */ - long tracklen; - long startwait; - int startunits; - int drumtrack; -}; - -/* can cope with up to 64 track MIDI files */ -struct atrack track[64]; -int trackcount = 0; -int maxbarcount = 0; -/* maxbarcount is used to return the numbers of bars created.*/ -/* obpl is a flag for one bar per line. */ - -/* double linked list of notes */ -/* used for temporary list of chords while abc is being generated */ -struct dlistx { - struct dlistx* next; - struct dlistx* last; - struct anote* note; -}; - -int notechan[2048],notechanvol[2048]; /*for linking on and off midi - channel commands */ -int last_tick; /* for getting last pulse number in MIDI file */ - - - -void remove_carriage_returns(); -int validnote(); -void printpitch(struct anote*); -void printfract(int, int); - - - - - -/* Stage 1. Parsing MIDI file */ - -/* Functions called during the reading pass of the MIDI file */ - -/* The following C routines are required by midifilelib. */ -/* They specify the action to be taken when various items */ -/* are encountered in the MIDI. The mfread function scans*/ -/* the MIDI file and calls these functions when needed. */ - - -int filegetc() -{ - return(getc(F)); -} - - -void fatal_error(s) -char* s; -/* fatal error encounterd - abort program */ -{ - fprintf(stderr, "%s\n", s); - exit(1); -} - - -void event_error(s) -char *s; -/* problem encountered but OK to continue */ -{ - char msg[256]; - - sprintf(msg, "Error: Time=%ld Track=%d %s\n", Mf_currtime, trackno, s); - printf(msg); -} - - -int* checkmalloc(bytes) -/* malloc with error checking */ -int bytes; -{ - int *p; - - p = (int*) malloc(bytes); - if (p == NULL) { - fatal_error("Out of memory error - cannot malloc!"); - }; - return (p); -} - - - -char* addstring(s) -/* create space for string and store it in memory */ -char* s; -{ - char* p; - - p = (char*) checkmalloc(strlen(s)+1); - strcpy(p, s); - return(p); -} - -void addtext(s, type) -/* add structure for text */ -/* used when parsing MIDI file */ -char* s; -int type; -{ - struct tlistx* newx; - - newx = (struct tlistx*) checkmalloc(sizeof(struct tlistx)); - newx->next = NULL; - newx->text = addstring(s); - newx->type = type; - newx->when = Mf_currtime; - if (track[trackno].texthead == NULL) { - track[trackno].texthead = newx; - track[trackno].texttail = newx; - } - else { - track[trackno].texttail->next = newx; - track[trackno].texttail = newx; - }; -} - - - -/* The MIDI file has separate commands for starting */ -/* and stopping a note. In order to determine the duration of */ -/* the note it is necessary to find the note_on command associated */ -/* with the note off command. We rely on the note's pitch and channel*/ -/* number to find the right note. While we are parsing the MIDI file */ -/* we maintain a list of all the notes that are currently on */ -/* head and tail of list of notes still playing. */ -/* The following doubly linked list is used for this purpose */ - -struct dlistx* playinghead; -struct dlistx* playingtail; - - -void noteplaying(p) -/* This function adds a new note to the playinghead list. */ -struct anote* p; -{ - struct dlistx* newx; - - newx = (struct dlistx*) checkmalloc(sizeof(struct dlistx)); - newx->note = p; - newx->next = NULL; - newx->last = playingtail; - if (playinghead == NULL) { - playinghead = newx; - }; - if (playingtail == NULL) { - playingtail = newx; - } - else { - playingtail->next = newx; - playingtail = newx; - }; -} - - -void addnote(p, ch, v) -/* add structure for note */ -/* used when parsing MIDI file */ -int p, v; -{ - struct listx* newx; - struct anote* newnote; - - track[trackno].notes = track[trackno].notes + 1; - newx = (struct listx*) checkmalloc(sizeof(struct listx)); - newnote = (struct anote*) checkmalloc(sizeof(struct anote)); - newx->next = NULL; - newx->note = newnote; - if (track[trackno].head == NULL) { - track[trackno].head = newx; - track[trackno].tail = newx; - } - else { - track[trackno].tail->next = newx; - track[trackno].tail = newx; - }; - if (ch == 9) { - track[trackno].drumtrack = 1; - }; - newnote->pitch = p; - newnote->chan = ch; - newnote->vel = v; - newnote->time = Mf_currtime; - laston = Mf_currtime; - newnote->tplay = Mf_currtime; - noteplaying(newnote); -} - - - -void notestop(p, ch) -/* MIDI note stops */ -/* used when parsing MIDI file */ -int p, ch; -{ - struct dlistx* i; - int found; - char msg[80]; - - i = playinghead; - found = 0; - while ((found == 0) && (i != NULL)) { - if ((i->note->pitch == p)&&(i->note->chan==ch)) { - found = 1; - } - else { - i = i->next; - }; - }; - if (found == 0) { - sprintf(msg, "Note terminated when not on - pitch %d", p); - event_error(msg); - return; - }; - /* fill in tplay field */ - i->note->tplay = Mf_currtime - (i->note->tplay); - /* remove note from list */ - if (i->last == NULL) { - playinghead = i->next; - } - else { - (i->last)->next = i->next; - }; - if (i->next == NULL) { - playingtail = i->last; - } - else { - (i->next)->last = i->last; - }; - free(i); -} - - - - -FILE * -efopen(name,mode) -char *name; -char *mode; -{ - FILE *f; - - if ( (f=fopen(name,mode)) == NULL ) { - char msg[256]; - sprintf(msg,"Error - Cannot open file %s",name); - fatal_error(msg); - } - return(f); -} - - -void error(s) -char *s; -{ - fprintf(stderr,"Error: %s\n",s); -} - - - -void txt_header(xformat,ntrks,ldivision) -int xformat, ntrks, ldivision; -{ - division = ldivision; - format = xformat; - if (format != 0) { - /* fprintf(outhandle,"%% format %d file %d tracks\n", format, ntrks);*/ - if(summary>0) printf("This midi file has %d tracks\n\n",ntrks); - } - else { -/* fprintf(outhandle,"%% type 0 midi file\n"); */ - if(summary>0) { - printf("This is a type 0 midi file.\n"); - printf("All the channels are in one track.\n"); - printf("You may need to process the channels separately\n\n"); - } - } - -} - - -void txt_trackstart() -{ - laston = 0L; - track[trackno].notes = 0; - track[trackno].head = NULL; - track[trackno].tail = NULL; - track[trackno].texthead = NULL; - track[trackno].texttail = NULL; - track[trackno].tracklen = Mf_currtime; - track[trackno].drumtrack = 0; -} - -void txt_trackend() -{ - /* check for unfinished notes */ - if (playinghead != NULL) { - printf("Error in MIDI file - notes still on at end of track!\n"); - }; - track[trackno].tracklen = Mf_currtime - track[trackno].tracklen; - trackno = trackno + 1; - trackcount = trackcount + 1; -} - -void txt_noteon(chan,pitch,vol) -int chan, pitch, vol; -{ - if ((xchannel == -1) || (chan == xchannel)) { - if (vol != 0) { - addnote(pitch, chan, vol); - } - else { - notestop(pitch, chan); - }; - }; -} - -void txt_noteoff(chan,pitch,vol) -int chan, pitch, vol; -{ - if ((xchannel == -1) || (chan == xchannel)) { - notestop(pitch, chan); - }; -} - -void txt_pressure(chan,pitch,press) -int chan, pitch, press; -{ -} - -void txt_parameter(chan,control,value) -int chan, control, value; -{ -} - -void txt_pitchbend(chan,msb,lsb) -int chan, msb, lsb; -{ -} - -void txt_program(chan,program) -int chan, program; -{ -/* - sprintf(textbuff, "%%%%MIDI program %d %d", - chan+1, program); -*/ - sprintf(textbuff, "%%%%MIDI program %d", program); - addtext(textbuff,0); -/* abc2midi does not use the same channel number as specified in - the original midi file, so we should not specify that channel - number in the %%MIDI program. If we leave it out the program - will refer to the current channel assigned to this voice. -*/ -} - -void txt_chanpressure(chan,press) -int chan, press; -{ -} - -void txt_sysex(leng,mess) -int leng; -char *mess; -{ -} - -void txt_metamisc(type,leng,mess) -int type, leng; -char *mess; -{ -} - -void txt_metaspecial(type,leng,mess) -int type, leng; -char *mess; -{ -} - -void txt_metatext(type,leng,mess) -int type, leng; -char *mess; -{ - char *ttype[] = { - NULL, - "Text Event", /* type=0x01 */ - "Copyright Notice", /* type=0x02 */ - "Sequence/Track Name", - "Instrument Name", /* ... */ - "Lyric", - "Marker", - "Cue Point", /* type=0x07 */ - "Unrecognized" - }; - int unrecognized = (sizeof(ttype)/sizeof(char *)) - 1; - unsigned char c; - int n; - char *p = mess; - char *buff; - char buffer2[BUFFSIZE]; - - if ((type < 1)||(type > unrecognized)) - type = unrecognized; - buff = textbuff; - for (n=0; n0) return; /* ignore other tempo indications */ - tempo = ltempo; - tempocount++; -} - - -void setup_timesig(nn, denom, bb) -int nn,denom,bb; -{ - asig = nn; - bsig = denom; -/* we must keep unitlen and xunit fixed for the entire tune */ - if (unitlen_set == 0) { - unitlen_set = 1; - if ((asig*4)/bsig >= 3) { - unitlen =8; - } - else { - unitlen = 16; - }; - } -/* set xunit for this unitlen */ - if(!xunit_set) xunit = (division*bb*4)/(8*unitlen); - barsize = parts_per_unitlen*asig*unitlen/bsig; -/* printf("setup_timesig: unitlen=%d xunit=%d barsize=%d\n",unitlen,xunit,barsize); */ - if (header_asig ==0) {header_asig = asig; - header_bsig = bsig; - header_unitlen = unitlen; - header_bb = bb; - } -} - - -void txt_timesig(nn,dd,cc,bb) -int nn, dd, cc, bb; -{ - int denom = 1; - while ( dd-- > 0 ) - denom *= 2; - sprintf(textbuff, - "%% Time signature=%d/%d MIDI-clocks/click=%d 32nd-notes/24-MIDI-clocks=%d", - nn,denom,cc,bb); - if (verbosity) addtext(textbuff,0); - sprintf(textbuff,"%d %d %d\n",nn,denom,bb); - if (!tsig_set) { - addtext(textbuff,2); - setup_timesig(nn, denom,bb); - } - if (summary>0) { - if(tsig_set) printf("Time signature = %d/%d suppressed\n",nn,denom); - else printf("Time signature = %d/%d\n",nn,denom); - } -} - - -void txt_smpte(hr,mn,se,fr,ff) -int hr, mn, se, fr, ff; -{ -} - -void txt_arbitrary(leng,mess) -char *mess; -int leng; -{ -} - - - -/* Dummy functions for handling MIDI messages. - * */ - void no_op0() {} - void no_op1(int dummy1) {} - void no_op2(int dummy1, int dummy2) {} - void no_op3(int dummy1, int dummy2, int dummy3) { } - void no_op4(int dummy1, int dummy2, int dummy3, int dummy4) { } - void no_op5(int dummy1, int dummy2, int dummy3, int dummy4, int dummy5) { } - - - -void print_txt_noteon(chan, pitch, vol) -{ -int start_time; -int initvol; -if (vol > 0) -open_note(chan, pitch, vol); -else { - start_time = close_note(chan, pitch,&initvol); - if (start_time >= 0) - /* printf("%8.4f %8.4f %d %d %d %d\n", - (double) start_time/(double) division, - (double) Mf_currtime/(double) division, - trackno+1, chan +1, pitch,initvol); - */ - printf("%d %ld %d %d %d %d\n", - start_time, Mf_currtime, trackno+1, chan +1, pitch,initvol); - - if(Mf_currtime > last_tick) last_tick = Mf_currtime; - } -} - - - -void print_txt_noteoff(chan, pitch, vol) -{ -int start_time,initvol; - -start_time = close_note(chan, pitch, &initvol); -if (start_time >= 0) -/* - printf("%8.4f %8.4f %d %d %d %d\n", - (double) start_time/(double) division, - (double) Mf_currtime/(double) division, - trackno+1, chan+1, pitch,initvol); -*/ - printf("%d %ld %d %d %d %d\n", - start_time, Mf_currtime, trackno+1, chan +1, pitch,initvol); - if(Mf_currtime > last_tick) last_tick = Mf_currtime; -} - - - -/* In order to associate a channel note off message with its - * corresponding note on message, we maintain the information - * the notechan array. When a midi pitch (0-127) is switched - * on for a particular channel, we record the time that it - * was turned on in the notechan array. As there are 16 channels - * and 128 pitches, we initialize an array 128*16 = 2048 elements - * long. -**/ -void init_notechan() -{ -/* signal that there are no active notes */ - int i; - for (i = 0; i < 2048; i++) notechan[i] = -1; -} - - -/* The next two functions update notechan when a channel note on - or note off is encountered. The second function close_note, - returns the time when the note was turned on. -*/ -int open_note(int chan, int pitch, int vol) -{ - notechan[128 * chan + pitch] = Mf_currtime; - notechanvol[128 * chan + pitch] = vol; - return 0; -} - - -int close_note(int chan, int pitch, int *initvol) -{ - int index, start_tick; - index = 128 * chan + pitch; - if (notechan[index] < 0) - return -1; - start_tick = notechan[index]; - *initvol = notechanvol[index]; - notechan[index] = -1; - return start_tick; -} - - -/* mftext mode */ -int prtime() -{ -/* if(Mf_currtime >= pulses) ignore=0; - if (ignore) return 1; - linecount++; - if(linecount > maxlines) {fclose(F); exit(0);} -*/ - int units; - units = 2; - if(units==1) - /*seconds*/ - printf("%6.2f ",mf_ticks2sec(Mf_currtime,division,tempo)); - else if (units==2) - /*beats*/ - printf("%6.2f ",(float) Mf_currtime/(float) division); - else - /*pulses*/ - printf("%6ld ",Mf_currtime); - return 0; -} - -char * pitch2key(int note) -{ -static char name[5]; -char* s = name; - switch(note % 12) - { - case 0: *s++ = 'c'; break; - case 1: *s++ = 'c'; *s++ = '#'; break; - case 2: *s++ = 'd'; break; - case 3: *s++ = 'd'; *s++ = '#'; break; - case 4: *s++ = 'e'; break; - case 5: *s++ = 'f'; break; - case 6: *s++ = 'f'; *s++ = '#'; break; - case 7: *s++ = 'g'; break; - case 8: *s++ = 'g'; *s++ = '#'; break; - case 9: *s++ = 'a'; break; - case 10: *s++ = 'a'; *s++ = '#'; break; - case 11: *s++ = 'b'; break; - } - sprintf(s, "%d", (note / 12)-1); /* octave (assuming Piano C4 is 60)*/ - return name; -} - -void mftxt_header (int format, int ntrks, int ldivision) -{ - division = ldivision; - printf("Header format=%d ntrks=%d division=%d\n",format,ntrks,division); -} - -void mftxt_trackstart() -{ - int numbytes; - tracknum++; - numbytes = Mf_toberead; - /*if(track != 0 && tracknum != track) {ignore_bytes(numbytes); return;} */ - printf("Track %d contains %d bytes\n",tracknum,numbytes); -} - - -void mftxt_noteon(chan,pitch,vol) -{ - char *key; -/* - if (onlychan >=0 && chan != onlychan) return; -*/ - if (prtime()) return; - key = pitch2key(pitch); - printf("Note on %2d %3s %3d\n",chan+1, key,vol); -} - -void mftxt_noteoff(chan,pitch,vol) -{ - char *key; -/* - if (onlychan >=0 && chan != onlychan) return; -*/ - if (prtime()) return; - key = pitch2key(pitch); - printf("Note off %2d %3s %3d\n",chan+1,key,vol); -} - -void mftxt_pressure(chan,pitch,press) -{ - char *key; - if (prtime()) return; - key = pitch2key(pitch); - printf("Pressure %2d %3s %3d\n",chan+1,key,press); -} - - -void mftxt_pitchbend(chan,msb,lsb) -{ -/* - if (onlychan >=0 && chan != onlychan) return; -*/ - if (prtime()) return; - printf("Pitchbnd %2d msb=%d lsb=%d\n",chan+1,msb,lsb); -} - - - -void mftxt_program(chan,program) -{ -static char *patches[] = { - "Acoustic Grand","Bright Acoustic","Electric Grand","Honky-Tonk", - "Electric Piano 1","Electric Piano 2","Harpsichord","Clav", - "Celesta", "Glockenspiel", "Music Box", "Vibraphone", - "Marimba", "Xylophone", "Tubular Bells", "Dulcimer", - "Drawbar Organ", "Percussive Organ", "Rock Organ", "Church Organ", - "Reed Organ", "Accordian", "Harmonica", "Tango Accordian", - "Acoustic Guitar (nylon)", "Acoustic Guitar (steel)", - "Electric Guitar (jazz)", "Electric Guitar (clean)", - "Electric Guitar (muted)", "Overdriven Guitar", - "Distortion Guitar", "Guitar Harmonics", - "Acoustic Bass", "Electric Bass (finger)", - "Electric Bass (pick)", "Fretless Bass", - "Slap Bass 1", "Slap Bass 2", "Synth Bass 1", "Synth Bass 2", - "Violin", "Viola", "Cello", "Contrabass", - "Tremolo Strings", "Pizzicato Strings", - "Orchestral Strings", "Timpani", - "String Ensemble 1", "String Ensemble 2", - "SynthStrings 1", "SynthStrings 2", - "Choir Aahs", "Voice Oohs", "Synth Voice", "Orchestra Hit", - "Trumpet", "Trombone", "Tuba", "Muted Trumpet", - "French Horn", "Brass Section", "SynthBrass 1", "SynthBrass 2", - "Soprano Sax", "Alto Sax", "Tenor Sax", "Baritone Sax", - "Oboe", "English Horn", "Bassoon", "Clarinet", - "Piccolo", "Flute", "Recorder", "Pan Flute", - "Blown Bottle", "Skakuhachi", "Whistle", "Ocarina", - "Lead 1 (square)", "Lead 2 (sawtooth)", - "Lead 3 (calliope)", "Lead 4 (chiff)", - "Lead 5 (charang)", "Lead 6 (voice)", - "Lead 7 (fifths)", "Lead 8 (bass+lead)", - "Pad 1 (new age)", "Pad 2 (warm)", - "Pad 3 (polysynth)", "Pad 4 (choir)", - "Pad 5 (bowed)", "Pad 6 (metallic)", - "Pad 7 (halo)", "Pad 8 (sweep)", - "FX 1 (rain)", "(soundtrack)", - "FX 3 (crystal)", "FX 4 (atmosphere)", - "FX 5 (brightness)", "FX 6 (goblins)", - "FX 7 (echoes)", "FX 8 (sci-fi)", - "Sitar", "Banjo", "Shamisen", "Koto", - "Kalimba", "Bagpipe", "Fiddle", "Shanai", - "Tinkle Bell", "Agogo", "Steel Drums", "Woodblock", - "Taiko Drum", "Melodic Tom", "Synth Drum", "Reverse Cymbal", - "Guitar Fret Noise", "Breath Noise", "Seashore", "Bird Tweet", - "Telephone ring", "Helicopter", "Applause", "Gunshot"}; -/* - if (onlychan >=0 && chan != onlychan) return; -*/ - if (prtime()) return; - printf("Program %2d %d (%s)\n",chan+1, program,patches[program]); - } - -void mftxt_chanpressure(chan,press) -{ - prtime(); - printf("Chanpres %2d pressure=%d\n",chan+1,press); -} - - -void mftxt_parameter(chan,control,value) -{ - static char *ctype[] = { - "Bank Select", "Modulation Wheel", /*1*/ - "Breath controller", "unknown", /*3*/ - "Foot Pedal", "Portamento Time", /*5*/ - "Data Entry", "Volume", /*7*/ - "Balance", "unknown", /*9*/ - "Pan position", "Expression", /*11*/ - "Effect Control 1", "Effect Control 2", /*13*/ - "unknown", "unknown", /*15*/ - "Slider 1", "Slider 2", /*17*/ - "Slider 3", "Slider 4", /*19*/ - "unknown", "unknown", /*21*/ - "unknown", "unknown", /*23*/ - "unknown", "unknown", /*25*/ - "unknown", "unknown", /*27*/ - "unknown", "unknown", /*29*/ - "unknown", "unknown", /*31*/ - "Bank Select (fine)", "Modulation Wheel (fine)", /*33*/ - "Breath controller (fine)", "unknown", /*35*/ - "Foot Pedal (fine)", "Portamento Time (fine)", /*37*/ - "Data Entry (fine)", "Volume (fine)", /*39*/ - "Balance (fine)", "unknown", /*41*/ - "Pan position (fine)", "Expression (fine)", /*43*/ - "Effect Control 1 (fine)", "Effect Control 2 (fine)", /*45*/ - "unknown", "unknown", /*47*/ - "unknown", "unknown", /*49*/ - "unknown", "unknown", /*51*/ - "unknown", "unknown", /*53*/ - "unknown", "unknown", /*55*/ - "unknown", "unknown", /*57*/ - "unknown", "unknown", /*59*/ -"unknown", "unknown", /*61*/ - "unknown", "unknown", /*63*/ - "Hold Pedal", "Portamento", /*65*/ - "Susteno Pedal", "Soft Pedal", /*67*/ - "Legato Pedal", "Hold 2 Pedal", /*69*/ - "Sound Variation", "Sound Timbre", /*71*/ - "Sound Release Time", "Sound Attack Time", /*73*/ - "Sound Brightness", "Sound Control 6", /*75*/ - "Sound Control 7", "Sound Control 8", /*77*/ - "Sound Control 9", "Sound Control 10", /*79*/ - "GP Button 1", "GP Button 2", /*81*/ - "GP Button 3", "GP Button 4", /*83*/ - "unknown", "unknown", /*85*/ - "unknown", "unknown", /*87*/ - "unknown", "unknown", /*89*/ - "unknown", "Effects Level", /*91*/ - "Tremolo Level", "Chorus Level", /*93*/ - "Celeste Level", "Phaser Level", /*95*/ - "Data button increment", "Data button decrement", /*97*/ - "NRP (fine)", "NRP (coarse)", /*99*/ - "Registered parameter (fine)", "Registered parameter (coarse)", /*101*/ - "unknown", "unknown", /*103*/ - "unknown", "unknown", /*105*/ - "unknown", "unknown", /*107*/ - "unknown", "unknown", /*109*/ - "unknown", "unknown", /*111*/ - "unknown", "unknown", /*113*/ - "unknown", "unknown", /*115*/ - "unknown", "unknown", /*117*/ - "unknown", "unknown", /*119*/ - "All Sound Off", "All Controllers Off", /*121*/ - "Local Keyboard (on/off)","All Notes Off", /*123*/ - "Omni Mode Off", "Omni Mode On", /*125*/ - "Mono Operation", "Poly Operation"}; - -/* if (onlychan >=0 && chan != onlychan) return; */ - if (prtime()) return; - - printf("CntlParm %2d %s = %d\n",chan+1, ctype[control],value); -} - - -void mftxt_metatext(type,leng,mess) -char *mess; -{ - static char *ttype[] = { - NULL, - "Text Event", /* type=0x01 */ - "Copyright Notice", /* type=0x02 */ - "Seqnce/Track Name", - "Instrument Name", /* ... */ - "Lyric", - "Marker", - "Cue Point", /* type=0x07 */ - "Unrecognized" - }; - int unrecognized = (sizeof(ttype)/sizeof(char *)) - 1; - int len; - register int n, c; - register char *p = mess; - - if ( type < 1 || type > unrecognized ) - type = unrecognized; - if (prtime()) return; - printf("Metatext (%s) ",ttype[type]); - len = leng; - if (len > 15) len = 15; - for ( n=0; n */ - printf( (isprint(c)||isspace(c)) ? "%c" : "\\0x%02x" , c); - } - if (leng>15) printf("..."); - printf("\n"); -} - -void mftxt_keysig(sf,mi) -{ - static char *major[] = {"Cb", "Gb", "Db", "Ab", "Eb", "Bb", "F", - "C", "G", "D", "A", "E", "B", "F#", "C#"}; - static char *minor[] = {"Abmin", "Ebmin", "Bbmin", "Fmin", "Cmin", - "Gmin", "Dmin", "Amin", "Emin", "Bmin", "F#min", "C#min", "G#min"}; - int index; - index = sf + 7; - if (prtime()) return; - if (mi) - printf("Metatext key signature %s (%d/%d)\n",minor[index],sf,mi); - else - printf("Metatext key signature %s (%d/%d)\n",major[index],sf,mi); -} - -void mftxt_tempo(ltempo) -long ltempo; -{ - tempo = ltempo; - if (prtime()) return; - printf("Metatext tempo = %6.2f bpm\n",60000000.0/tempo); -} - -void mftxt_timesig(nn,dd,cc,bb) -{ - int denom = 1; - while ( dd-- > 0 ) - denom *= 2; - if (prtime()) return; - printf("Metatext time signature=%d/%d\n",nn,denom); -/* printf("Time signature=%d/%d MIDI-clocks/click=%d \ - 32nd-notes/24-MIDI-clocks=%d\n", nn,denom,cc,bb); */ -} - -void mftxt_smpte(hr,mn,se,fr,ff) -{ - if (prtime()) return; - printf("Metatext SMPTE, %d:%d:%d %d=%d\n", hr,mn,se,fr,ff); -} - -void mftxt_metaeot() -{ - if (prtime()) return; - printf("Meta event, end of track\n"); -} - - -void initfunc_for_midinotes() -{ - Mf_error = error; - Mf_header = txt_header; - Mf_trackstart = txt_trackstart; - Mf_trackend = txt_trackend; - Mf_noteon = print_txt_noteon; - Mf_noteoff = print_txt_noteoff; - Mf_pressure = no_op3; - Mf_parameter = no_op3; - Mf_pitchbend = no_op3; - Mf_program = no_op2; - Mf_chanpressure = no_op3; - Mf_sysex = no_op2; - Mf_metamisc = no_op3; - Mf_seqnum = no_op1; - Mf_eot = no_op0; - Mf_timesig = no_op4; - Mf_smpte = no_op5; - Mf_tempo = no_op1; - Mf_keysig = no_op2; - Mf_seqspecific = no_op3; - Mf_text = no_op3; - Mf_arbitrary = no_op2; -} - - -void initfunc_for_mftext() -{ - Mf_error = error; - Mf_header = mftxt_header; - Mf_trackstart = mftxt_trackstart; - Mf_trackend = txt_trackend; - Mf_noteon = mftxt_noteon; - Mf_noteoff = mftxt_noteoff; - Mf_pressure =mftxt_pressure; - Mf_parameter = mftxt_parameter; - Mf_pitchbend = mftxt_pitchbend; - Mf_program = mftxt_program; - Mf_chanpressure = mftxt_chanpressure; - Mf_sysex = no_op2; - Mf_metamisc = no_op3; - Mf_seqnum = no_op1; - Mf_eot = mftxt_metaeot; - Mf_timesig = mftxt_timesig; - Mf_smpte = mftxt_smpte; - Mf_tempo = mftxt_tempo; - Mf_keysig = mftxt_keysig; - Mf_seqspecific = no_op3; - Mf_text = mftxt_metatext; - Mf_arbitrary = no_op2; -} - - - - -void initfuncs() -{ - Mf_error = error; - Mf_header = txt_header; - Mf_trackstart = txt_trackstart; - Mf_trackend = txt_trackend; - Mf_noteon = txt_noteon; - Mf_noteoff = txt_noteoff; - Mf_pressure = txt_pressure; - Mf_parameter = txt_parameter; - Mf_pitchbend = txt_pitchbend; - Mf_program = txt_program; - Mf_chanpressure = txt_chanpressure; - Mf_sysex = txt_sysex; - Mf_metamisc = txt_metamisc; - Mf_seqnum = txt_metaseq; - Mf_eot = txt_metaeot; - Mf_timesig = txt_timesig; - Mf_smpte = txt_smpte; - Mf_tempo = txt_tempo; - Mf_keysig = txt_keysig; - Mf_seqspecific = txt_metaspecial; - Mf_text = txt_metatext; - Mf_arbitrary = txt_arbitrary; -} - - -/* Stage 2 Quantize MIDI tracks. Get key signature, time signature... */ - - -void postprocess(trackno) -/* This routine calculates the time interval before the next note */ -/* called after the MIDI file has been read in */ -int trackno; -{ - struct listx* i; - - i = track[trackno].head; - if (i != NULL) { - track[trackno].startwait = i->note->time; - } - else { - track[trackno].startwait = 0; - }; - while (i != NULL) { - if (i->next != NULL) { - i->note->dtnext = i->next->note->time - i->note->time; - } - else { - i->note->dtnext = i->note->tplay; - }; - i = i->next; - }; -} - -void scannotes(trackno) -int trackno; -/* diagnostic routine to output notes in a track */ -{ - struct listx* i; - - i = track[trackno].head; - while (i != NULL) { - printf("Pitch %d chan %d vel %d time %ld %ld xnum %d playnum %d\n", - i->note->pitch, i->note->chan, - i->note->vel, i->note->dtnext, i->note->tplay, - i->note->xnum, i->note->playnum); - i = i->next; - }; -} - - -int xnum_to_next_nonchordal_note(fromitem,spare,quantum) -struct listx* fromitem; -int spare,quantum; -{ -struct anote* jnote; -struct listx* nextitem; -int i,xxnum; -jnote = fromitem->note; -if (jnote->xnum > 0) return jnote->xnum; -i = 0; -nextitem = fromitem->next; -while (nextitem != NULL && i < 5) { - jnote = nextitem->note; - xxnum = (2*(jnote->dtnext + spare + (quantum/4)))/quantum; - if (xxnum > 0) return xxnum; - i++; - nextitem = nextitem->next; - } -return 0; -} - -int quantize(trackno, xunit) -/* Work out how long each note is in musical time units. - * The results are placed in note.playnum */ -int trackno, xunit; -{ - struct listx* j; - struct anote* this; - int spare; - int toterror; - int quantum; - int posnum,xxnum; - - /* fix to avoid division by zero errors in strange MIDI */ - if (xunit == 0) { - return(10000); - }; - quantum = (int) (2.*xunit/parts_per_unitlen); /* xunit assume 2 parts_per_unit */ - track[trackno].startunits = (2*(track[trackno].startwait + (quantum/4)))/quantum; - spare = 0; - toterror = 0; - j = track[trackno].head; - posnum = 0; - while (j != NULL) { - this = j->note; - /* this->xnum is the quantized inter onset time */ - /* this->playnum is the quantized note length */ - this->xnum = (2*(this->dtnext + spare + (quantum/4)))/quantum; - this->playnum = (2*(this->tplay + (quantum/4)))/quantum; - if ((this->playnum == 0) && (keep_short)) { - this->playnum = 1; - }; - /* In the event of short rests, the inter onset time - * will be larger than the note length. However, for - * chords the inter onset time can be zero. */ - xxnum = xnum_to_next_nonchordal_note(j,spare,quantum); - if ((swallow_rests>=0) && (xxnum - this->playnum <= restsize) - && xxnum > 0) { - this->playnum = xxnum; - }; - /* this->denom = parts_per_unitlen; this variable is never used ! */ - spare = spare + this->dtnext - (this->xnum*xunit/parts_per_unitlen); - if (spare > 0) { - toterror = toterror + spare; - } - else { - toterror = toterror - spare; - }; - /* gradually forget old errors so that if xunit is slightly off, - errors don't accumulate over several bars */ - spare = (spare * 96)/100; - this->posnum = posnum; - posnum += this->xnum; - j = j->next; - }; - return(toterror); -} - - -void guesslengths(trackno) -/* work out most appropriate value for a unit of musical time */ -int trackno; -{ - int i; - int trial[100]; - float avlen, factor, tryx; - long min; - - min = track[trackno].tracklen; - if (track[trackno].notes == 0) { - return; - }; - avlen = ((float)(min))/((float)(track[trackno].notes)); - tryx = avlen * (float) 0.75; - factor = tryx/100; - for (i=0; i<100; i++) { - trial[i] = quantize(trackno, (int) tryx); - if ((long) trial[i] < min) { - min = (long) trial[i]; - xunit = (int) tryx; - }; - tryx = tryx + factor; - }; -xunit_set = 1; -} - - -int findana(maintrack, barsize) -/* work out anacrusis from MIDI */ -/* look for a strong beat marking the start of a bar */ -int maintrack; -int barsize; -{ - int min, mincount; - int place; - struct listx* p; - - min = 0; - mincount = 0; - place = 0; - p = track[maintrack].head; - while ((p != NULL) && (place < barsize)) { - if ((p->note->vel > min) && (place > 0)) { - min = p->note->vel; - mincount = place; - }; - place = place + (p->note->xnum); - p = p->next; - }; - return(mincount); -} - - - -int guessana(barbeats) -int barbeats; -/* try to guess length of anacrusis */ -{ - int score[64]; - int min, minplace; - int i,j; - - if (barbeats > 64) { - fatal_error("Bar size exceeds static limit of 64 units!"); - }; - for (j=0; jnote->pitch; - max = min; - totalnotes = 0; - for (j=0; jnote->pitch; - if (thispitch > max) { - max = thispitch; - } - else { - if (thispitch < min) { - min = thispitch; - }; - }; - n[thispitch % 12] = n[thispitch % 12] + 1; - p = p->next; - }; - }; - /* count black notes for each key */ - /* assume pitch = 0 is C */ - minkey = 0; - minblacks = totalnotes; - for (j=0; j<12; j++) { - key_score[j] = n[(j+1)%12] + n[(j+3)%12] + n[(j+6)%12] + - n[(j+8)%12] + n[(j+10)%12]; - /* printf("Score for key %d is %d\n", j, key_score[j]); */ - if (key_score[j] < minblacks) { - minkey = j; - minblacks = key_score[j]; - }; - }; - /* do conversion to abc pitches */ - /* Code changed to use absolute rather than */ - /* relative choice of pitch for 'c' */ - /* MIDDLE = (min + (max - min)/2 + 6)/12 * 12; */ - /* Do last note analysis */ - lastpitch = track[maintrack].tail->note->pitch; - if (minkey != (lastpitch%12)) { - fprintf(outhandle,"%% Last note suggests "); - switch((lastpitch+12-minkey)%12) { - case(2): - fprintf(outhandle,"Dorian "); - break; - case(4): - fprintf(outhandle,"Phrygian "); - break; - case(5): - fprintf(outhandle,"Lydian "); - break; - case(7): - fprintf(outhandle,"Mixolydian "); - break; - case(9): - fprintf(outhandle,"minor "); - break; - case(11): - fprintf(outhandle,"Locrian "); - break; - default: - fprintf(outhandle,"unknown "); - break; - }; - fprintf(outhandle,"mode tune\n"); - }; - /* switch to minor mode if it gives same number of accidentals */ - if ((minkey != ((lastpitch+3)%12)) && - (key_score[minkey] == key_score[(lastpitch+3)%12])) { - minkey = (lastpitch+3)%12; - }; - /* switch to major mode if it gives same number of accidentals */ - if ((minkey != (lastpitch%12)) && - (key_score[minkey] == key_score[lastpitch%12])) { - minkey = lastpitch%12; - }; - sharps = keysharps[minkey]; - return(sharps); -} - - - - -/* Stage 3 output MIDI tracks in abc format */ - - -/* head and tail of list of notes in current chord playing */ -/* used while abc is being generated */ -struct dlistx* chordhead; -struct dlistx* chordtail; - - -void printchordlist() -/* diagnostic routine */ -{ - struct dlistx* i; - - i = chordhead; - printf("----CHORD LIST------\n"); - while(i != NULL) { - printf("pitch %d len %d\n", i->note->pitch, i->note->playnum); - if (i->next == i) { - fatal_error("Loopback problem!"); - }; - i = i->next; - }; -} - -void checkchordlist() -/* diagnostic routine */ -/* validates data structure */ -{ - struct dlistx* i; - int n; - - if ((chordhead == NULL) && (chordtail == NULL)) { - return; - }; - if ((chordhead == NULL) && (chordtail != NULL)) { - fatal_error("chordhead == NULL and chordtail != NULL"); - }; - if ((chordhead != NULL) && (chordtail == NULL)) { - fatal_error("chordhead != NULL and chordtail == NULL"); - }; - if (chordhead->last != NULL) { - fatal_error("chordhead->last != NULL"); - }; - if (chordtail->next != NULL) { - fatal_error("chordtail->next != NULL"); - }; - i = chordhead; - n = 0; - while((i != NULL) && (i->next != NULL)) { - if (i->next->last != i) { - char msg[80]; - - sprintf(msg, "chordlist item %d : i->next->last!", n); - fatal_error(msg); - }; - i = i->next; - n = n + 1; - }; - /* checkchordlist(); */ -} - -void addtochord(p) -/* used when printing out abc */ -struct anote* p; -{ - struct dlistx* newx; - struct dlistx* place; - - newx = (struct dlistx*) checkmalloc(sizeof(struct dlistx)); - newx->note = p; - newx->next = NULL; - newx->last = NULL; - - if (chordhead == NULL) { - chordhead = newx; - chordtail = newx; - checkchordlist(); - return; - }; - place = chordhead; - while ((place != NULL) && (place->note->pitch > p->pitch)) { - place = place->next; - }; - if (place == chordhead) { - newx->next = chordhead; - chordhead->last = newx; - chordhead = newx; - checkchordlist(); - return; - }; - if (place == NULL) { - newx->last = chordtail; - chordtail->next = newx; - chordtail = newx; - checkchordlist(); - return; - }; - newx->next = place; - newx->last = place->last; - place->last = newx; - newx->last->next = newx; - checkchordlist(); -} - -struct dlistx* removefromchord(i) -/* used when printing out abc */ -struct dlistx* i; -{ - struct dlistx* newi; - - /* remove note from list */ - if (i->last == NULL) { - chordhead = i->next; - } - else { - (i->last)->next = i->next; - }; - if (i->next == NULL) { - chordtail = i->last; - } - else { - (i->next)->last = i->last; - }; - newi = i->next; - free(i); - checkchordlist(); - return(newi); -} - -int findshortest(gap) -/* find the first note in the chord to terminate */ -int gap; -{ - int min, v; - struct dlistx* p; - - p = chordhead; - min = gap; - while (p != NULL) { - v = p->note->playnum; - if (v < min) { - min = v; - }; - p = p->next; - }; - return(min); -} - -void advancechord(len) -/* adjust note lengths for all notes in the chord */ -int len; -{ - struct dlistx* p; - - p = chordhead; - while (p != NULL) { - if (p->note->playnum <= len) { - if (p->note->playnum < len) { - fatal_error("Error - note too short!"); - }; - /* remove note */ - checkchordlist(); - p = removefromchord(p); - } - else { - /* shorten note */ - p->note->playnum = p->note->playnum - len; - p = p->next; - }; - }; -} - -void freshline() -/* if the current line of abc or text is non-empty, start a new line */ -{ - if (midline == 1) { - fprintf(outhandle,"\n"); - midline = 0; - }; -} - - -void printnote (struct listx *i) -{ - printf("%ld ",i->note->time); - printpitch(i->note); - printfract(i->note->playnum, parts_per_unitlen); - printf(" %d %d %d %d\n",i->note->xnum, i->note->playnum, - i->note->posnum,i->note->splitnum); -} - -void listnotes(int trackno, int start, int end) -/* A diagnostic like scannotes. I usually call it when - I am in the debugger (for example in printtrack). -*/ -{ -struct listx* i; -int k; -i = track[trackno].head; -k = 0; -printf("ticks pitch xnum,playnum,posnum,splitnum\n"); -while (i != NULL && k < end) - { - if (k >= start) - printnote(i); - k++; - i = i->next; - } -} - - - -int testtrack(trackno, barbeats, anacrusis) -/* print out one track as abc */ -int trackno, barbeats, anacrusis; -{ - struct listx* i; - int step, gap; - int barnotes; - int barcount; - int breakcount; - - breakcount = 0; - chordhead = NULL; - chordtail = NULL; - i = track[trackno].head; - gap = 0; - if (anacrusis > 0) { - barnotes = anacrusis; - } - else { - barnotes = barbeats; - }; - barcount = 0; - while((i != NULL)||(gap != 0)) { - if (gap == 0) { - /* add notes to chord */ - addtochord(i->note); - gap = i->note->xnum; - i = i->next; - advancechord(0); /* get rid of any zero length notes */ - } - else { - step = findshortest(gap); - if (step > barnotes) { - step = barnotes; - }; - if (step == 0) { - fatal_error("Advancing by 0 in testtrack!"); - }; - advancechord(step); - gap = gap - step; - barnotes = barnotes - step; - if (barnotes == 0) { - if (chordhead != NULL) { - breakcount = breakcount + 1; - }; - barnotes = barbeats; - barcount = barcount + 1; - if (barcount>0 && barcount%4 ==0) { - /* can't zero barcount because I use it for computing maxbarcount */ - freshline(); - barcount = 0; - }; - }; - }; - }; - return(breakcount); -} - -void printpitch(j) -/* convert numerical value to abc pitch */ -struct anote* j; -{ - int p, po,i; - - p = j->pitch; - if (p == -1) { - fprintf(outhandle,"z"); - } - else { - po = p % 12; - if ((back[trans[p]] != p) || (key[po] == 1)) { - fprintf(outhandle,"%c%c", symbol[po], atog[p]); - for (i=p%12; i<256; i += 12) /* apply accidental to all octaves */ - back[trans[i]] = i; - } - else { - fprintf(outhandle,"%c", atog[p]); - }; - while (p >= MIDDLE + 12) { - fprintf(outhandle,"'"); - p = p - 12; - }; - while (p < MIDDLE - 12) { - fprintf(outhandle,","); - p = p + 12; - }; - }; -} - -static void reduce(a, b) -int *a, *b; -{ - int t, n, m; - - /* find HCF using Euclid's algorithm */ - if (*a > *b) { - n = *a; - m = *b; - } - else { - n = *b; - m = *a; - }; -while (m != 0) { - t = n % m; - n = m; - m = t; - }; -*a = *a/n; -*b = *b/n; -} - - - -void printfract(a, b) -/* print fraction */ -/* used when printing abc */ -int a, b; -{ - int c, d; - - c = a; - d = b; - reduce(&c,&d); - /* print out length */ - if (c != 1) { - fprintf(outhandle,"%d", c); - }; - if (d != 1) { - fprintf(outhandle,"/%d", d); - }; -} - -void printchord(len) -/* Print out the current chord. Any notes that haven't */ -/* finished at the end of the chord are tied into the next chord. */ -int len; -{ - struct dlistx* i; - - i = chordhead; - if (i == NULL) { - /* no notes in chord */ -#ifdef SPLITCODE - fprintf(outhandle,"x"); -#else - fprintf(outhandle,"z"); -#endif - printfract(len, parts_per_unitlen); - midline = 1; - } - else { - if (i->next == NULL) { - /* only one note in chord */ - printpitch(i->note); - printfract(len, parts_per_unitlen); - midline = 1; - if (len < i->note->playnum) { - fprintf(outhandle,"-"); - }; - } - else { - fprintf(outhandle,"["); - while (i != NULL) { - printpitch(i->note); - printfract(len, parts_per_unitlen); - if (len < i->note->playnum) { - fprintf(outhandle,"-"); - }; - if (nogr && i->next != NULL) fprintf(outhandle," "); - i = i->next; - }; - fprintf(outhandle,"]"); - midline = 1; - }; - }; -} - -char dospecial(i, barnotes, featurecount) -/* identify and print out triplets and broken rhythm */ -struct listx* i; -int* barnotes; -int* featurecount; -{ - int v1, v2, v3, vt; - int xa, xb; - int pnum; - long total, t1, t2, t3; - - - if ((chordhead != NULL) || (i == NULL) || (i->next == NULL) - /* || (asig%3 == 0) || (asig%2 != 0) 2004/may/09 SS*/) { - return(' '); - }; - t1 = i->note->dtnext; - v1 = i->note->xnum; - pnum = i->note->playnum; - if ((v1 < pnum) || (v1 > 1 + pnum) || (pnum == 0)) { - return(' '); - }; - t2 = i->next->note->dtnext; - v2 = i->next->note->xnum; - pnum = i->next->note->playnum; - if (/*(v2 < pnum) ||*/ (v2 > 1 + pnum) || (pnum == 0) || (v1+v2 > *barnotes)) { - return(' '); - }; - /* look for broken rhythm */ - total = t1 + t2; - if (total == 0L) { - /* shouldn't happen, but avoids possible divide by zero */ - return(' '); - }; - if (((v1+v2)%2 == 0) && ((v1+v2)%3 != 0)) { - vt = (v1+v2)/2; - if (vt == validnote(vt)) { - /* do not try to break a note which cannot be legally expressed */ - switch ((int) ((t1*6+(total/2))/total)) { - case 2: - *featurecount = 2; - i->note->xnum = vt; - i->note->playnum = vt; - i->next->note->xnum = vt; - i->next->note->playnum = vt; - return('<'); - break; - case 4: - *featurecount = 2; - i->note->xnum = vt; - i->note->playnum = vt; - i->next->note->xnum = vt; - i->next->note->playnum = vt; - return('>'); - break; - default: - break; - }; - }; - }; - /* look for triplet */ - if (i->next->next != NULL) { - t3 = i->next->next->note->dtnext; - v3 = i->next->next->note->xnum; - pnum = i->next->next->note->playnum; - if ((v3 < pnum) || (v3 > 1 + pnum) || (pnum == 0) || - (v1+v2+v3 > *barnotes)) { - return(' '); - }; - if ((v1+v2+v3)%2 != 0) { - return(' '); - }; - vt = (v1+v2+v3)/2; - if ((vt%2 == 1) && (vt > 1)) { - /* don't want strange fractions in triplet */ - return(' '); - }; - total = t1+t2+t3; - xa = (int) ((t1*6+(total/2))/total); - xb = (int) (((t1+t2)*6+(total/2))/total); - if ((xa == 2) && (xb == 4) && (vt%3 != 0) ) { - *featurecount = 3; - *barnotes = *barnotes + vt; - i->note->xnum = vt; - i->note->playnum = vt; - i->next->note->xnum = vt; - i->next->note->playnum = vt; - i->next->next->note->xnum = vt; - i->next->next->note->playnum = vt; - }; - }; - return(' '); -} - -int validnote(n) -int n; -/* work out a step which can be expressed as a musical time */ -{ - int v; - - if (n <= 4) { - v = n; - } - else { - v = 4; - while (v*2 <= n) { - v = v*2; - }; - if (v + v/2 <= n) { - v = v + v/2; - }; - }; - return(v); -} - -void handletext(t, textplace, trackno) -/* print out text occuring in the body of the track */ -/* The text is printed out at the appropriate place within the track */ -/* In addition the function handles key signature and time */ -/* signature changes that can occur in the middle of the tune. */ -long t; -struct tlistx** textplace; -int trackno; -{ - char* str; - char ch; - int type,sf,mi,nn,denom,bb; - - while (((*textplace) != NULL) && ((*textplace)->when <= t)) { - str = (*textplace)->text; - ch = *str; - type = (*textplace)->type; - remove_carriage_returns(str); - if (((int)ch == '\\') || ((int)ch == '/')) { - inkaraoke = 1; - }; - if ((inkaraoke == 1) && (karaoke == 1)) { - switch(ch) { - case ' ': - fprintf(outhandle,"%s", str); - midline = 1; - break; - case '\\': - freshline(); - fprintf(outhandle,"w:%s", str + 1); - midline = 1; - break; - case '/': - freshline(); - fprintf(outhandle,"w:%s", str + 1); - midline = 1; - break; - default : - if (midline == 0) { - fprintf(outhandle,"%%%s", str); - } - else { - fprintf(outhandle,"-%s", str); - }; - break; - }; - } - else { - freshline(); - ch=*(str+1); - switch (type) { - case 0: - if (ch != '%') - fprintf(outhandle,"%%%s\n", str); - else - fprintf(outhandle,"%s\n", str); - break; - case 1: /* key signature change */ - sscanf(str,"%d %d",&sf,&mi); - if((trackno != 0 || trackcount==1) && - (active_keysig != sf)) { - setupkey(sf); - active_keysig=sf; - } - break; - case 2: /* time signature change */ - sscanf(str,"%d %d %d",&nn,&denom,&bb); - if ((trackno != 0 || trackcount ==1) && - (active_asig != nn || active_bsig != denom)) - { - setup_timesig(nn,denom,bb); - fprintf(outhandle,"M: %d/%d\n",nn,denom); - fprintf(outhandle,"L: 1/%d\n",unitlen); - active_asig=nn; - active_bsig=denom; - } - break; - default: - break; - } - } - *textplace = (*textplace)->next; - } -} - - -#ifdef SPLITCODE - -/* This function identifies irregular chords, (notes which - do not exactly overlap in time). The notes in the - chords are split into separate lines (split numbers). - The xnum (delay) to next note is updated. -*/ - -int splitstart[10],splitend[10]; /* used in forming chords from notes*/ -int lastposnum[10]; /* posnum of previous note in linked list */ -int endposnum; /* posnum at last note in linked list */ -struct anote* prevnote[10]; /*previous note in linked list */ -struct listx* last_i[10]; /*note after finishing processing bar*/ -int existingsplits[10]; /* existing splits in active bar */ -struct dlistx* splitchordhead[10]; /* chordhead list for splitnum */ -struct dlistx* splitchordtail[10]; /* chordtail list for splitnum */ -int splitgap[10]; /* gap to next note at end of split measure */ - -void label_split(struct anote *note, int activesplit) -{ -/* The function assigns a split number (activesplit), to - a specific note, (*note). We also update splitstart - and splitend which specifies the region in time where - the another note must occur if it forms a proper chord. - After assigning a split number to the note we need to - update note->xnum as this indicates the gap to the - next note in the same split number. The function uses - a greedy algorithm. It assigns a note to the first - splitnumber code which satisfies the above constraint. - If it cannot find a splitnumber, a new one (voice or track) - is created. It would be nice if the voices kept the - high and low notes (in pitch) separate. -*/ - note->splitnum = activesplit; - splitstart[activesplit] = note->posnum; - splitend[activesplit] = splitstart[activesplit] + note->playnum; - if (prevnote[activesplit]) - prevnote[activesplit]->xnum = note->posnum - lastposnum[activesplit]; - lastposnum[activesplit] = note->posnum; - prevnote[activesplit] = note; - /* in case this is the last activesplit note make sure it - xnum points to end of track. Otherwise it will be changed - when the next activesplit note is labeled. - */ - note->xnum = endposnum - note->posnum; - existingsplits[activesplit]++; -} - - -void label_split_voices (int trackno) -{ -/* This function sorts all the notes in the track into - separate split part. A note is placed into a separate - part if it forms a chord in the current part but - does not have the same onset time and same end time. - If this occurs, we search for another part where - this does not happen. If we can't find such a part - a new part (split) is created. - The heuristic used needs to be improved, so - that split number 0 always contains notes and so - that notes in the same pitch range or duration are - given the same split number. -*/ -int activesplit,nsplits; -int done; -struct listx* i; -int k; -int firstposnum; -/* initializations */ -activesplit = 0; -nsplits = 0; -for (k=0;k<10;k++) { - splitstart[k]=splitend[k]=lastposnum[k]=0; - prevnote[k] = NULL; - existingsplits[k] = 0; - splitgap[k]=0; - } -i = track[trackno].head; -if (track[trackno].tail == 0x0) return; -endposnum =track[trackno].tail->note->posnum + - track[trackno].tail->note->playnum; - -if (i != NULL) label_split(i->note, activesplit); -/* now label all the notes in the track */ -while (i != NULL) - { - done =0; - if (nsplits == 0) { /*no splits exist, create split number 0 */ - activesplit = 0; - nsplits++; - i->note->splitnum = activesplit; - splitstart[activesplit] = i->note->posnum; - splitend[activesplit] = splitstart[activesplit] + i->note->playnum; - firstposnum = splitstart[activesplit]; - } else { /* do a compatibility check with the last split number */ - if ( ( i->note->posnum == splitstart[activesplit] - && i->note->playnum == (splitend[activesplit] - splitstart[activesplit])) - || i->note->posnum >= splitend[activesplit]) - { - if (existingsplits[activesplit] == 0) { - last_i[activesplit] = i; - splitgap[activesplit] = i->note->posnum - firstposnum; - } - label_split(i->note, activesplit); - done = 1; - } -/* need to search for any other compatible split numbers */ - if (done == 0) for (activesplit=0;activesplitnote->posnum == splitstart[activesplit] - && i->note->playnum == splitend[activesplit] - splitstart[activesplit]) - || i->note->posnum >= splitend[activesplit]) - { - if (existingsplits[activesplit] == 0) { - last_i[activesplit] = i; - splitgap[activesplit] = i->note->posnum - firstposnum; - } - label_split(i->note,activesplit); - done = 1; - break; - } - } - -/* No compatible split number found. Create new split */ - if (done == 0) { - if(nsplits < 10) {nsplits++; activesplit = nsplits-1;} - if (existingsplits[activesplit] == 0) { - last_i[activesplit] = i; - splitgap[activesplit] = i->note->posnum - firstposnum; - } - label_split(i->note,activesplit); - } - } -/* printf("note %d links to %d %d (%d %d)\n",i->note->pitch,activesplit, -i->note->posnum,splitstart[activesplit],splitend[activesplit]); -*/ - i = i->next; - } /* end while loop */ -} - - -int nextsplitnum(int splitnum) - { - while (splitnum < 9) { - splitnum++; - if (existingsplits[splitnum]) return splitnum; - } - return -1; -} - - -int count_splits() -{ -int i,n; -n = 0; -for (i=0;i<10;i++) - if (existingsplits[i]) n++; -return n; -} - - - - - -void printtrack_with_splits(trackno, anacrusis) -int trackno, anacrusis; -/* This function is an adaption of printtrack so that - notes with separate split numbers are in separated - regions in the measure. (Separated with &'s). - To do this we must make multiple passes through - each bar and maintain separate chordlists (in - event that some chords overlap over more than - one measure). -*/ -{ - struct listx* i; - struct tlistx* textplace; - struct tlistx* textplace0; /* track 0 text storage */ - int step, gap; - int barnotes; - int barcount; - int bars_on_line; - long now; - char broken; - int featurecount; - int last_barsize,barnotes_correction; - int splitnum = 0; - int j; - int nlines; - int done; - - nlines= 0; - label_split_voices (trackno); - - midline = 0; - featurecount = 0; - inkaraoke = 0; - now = 0L; - broken = ' '; - for (j=0;j<10;j++) { - splitchordhead[j] = NULL; - splitchordtail[j] = NULL; - } - i = track[trackno].head; - textplace = track[trackno].texthead; - textplace0 = track[0].texthead; - /*gap = track[trackno].startunits;*/ gap = 0; - if (anacrusis > 0) { - barnotes = anacrusis; - barcount = -1; - } - else { - barnotes = barsize; - barcount = 0; - }; - bars_on_line = 0; - last_barsize = barsize; - active_asig = header_asig; - active_bsig = header_bsig; - setup_timesig(header_asig,header_bsig,header_bb); - active_keysig = header_keysig; - handletext(now, &textplace, trackno); - splitnum = 0; - chordhead = splitchordhead[splitnum]; - chordtail = splitchordtail[splitnum]; - gap = splitgap[splitnum]; - - while((i != NULL)||(gap != 0)) { - if (gap == 0) { - /* do triplet here */ - if (featurecount == 0) { - if (!no_triplets) { - broken = dospecial(i, &barnotes, &featurecount); - }; - }; - -/* ignore any notes that are not in the current splitnum */ - if (i->note->splitnum == splitnum) { - /*printf("\nadding "); - printnote(i); */ - addtochord(i->note); - gap = i->note->xnum; - now = i->note->time; - } - - i = i->next; - advancechord(0); /* get rid of any zero length notes */ - if (trackcount > 1 && trackno !=0) - handletext(now, &textplace0, trackno); - handletext(now, &textplace,trackno); - barnotes_correction = barsize - last_barsize; - barnotes += barnotes_correction; - last_barsize = barsize; - } - else { - step = findshortest(gap); - if (step > barnotes) { - step = barnotes; - }; - step = validnote(step); - if (step == 0) { - fatal_error("Advancing by 0 in printtrack!"); - }; - if (featurecount == 3) - { - fprintf(outhandle," (3"); - }; - printchord(step); if ( featurecount > 0) { featurecount = featurecount - 1; }; - if ((featurecount == 1) && (broken != ' ')) { - fprintf(outhandle,"%c", broken); - }; - advancechord(step); - gap = gap - step; - barnotes = barnotes - step; - -/* at the end of the bar we must decide whether to place - a | or &. If we place a & then we have to return to - the beginning of the bar and process the next split number. -*/ - if (barnotes == 0) { /* end of bar ? */ - nlines++; - if (nlines > 5000) { - printf("\nProbably infinite loop: aborting\n"); - fprintf(outhandle,"\n\nProbably infinite loop: aborting\n"); - return; - } -/* save state for the last splitnum before going to the next */ - last_i[splitnum] = i; - splitchordhead[splitnum] = chordhead; - splitchordtail[splitnum] = chordtail; - splitgap[splitnum] = gap; - -/* look for the next splitnum which contains notes in - the current measure. If not, end the measure. -*/ - done = 0; - while (done != 1) { - splitnum = nextsplitnum(splitnum); - - if (splitnum == -1) { - fprintf(outhandle," | "); - splitnum = nextsplitnum(splitnum); - done = 1; - break; - } - - if (splitgap[splitnum] >= barsize) - { - splitgap[splitnum] -= barsize; - continue; /* look for other splits */ - } - - fprintf(outhandle, " & "); - i = last_i[splitnum]; - done = 1; - } -/* restore state for the next splitnum */ - chordhead = splitchordhead[splitnum]; - chordtail = splitchordtail[splitnum]; - checkchordlist(); - gap = splitgap[splitnum]; - i = last_i[splitnum]; - - /* - printf("returning to %ld ",i->note->time); - printpitch(i->note); - printf("\n"); - */ - - barnotes = barsize; - barcount = barcount + 1; - bars_on_line++; - if (barcount >0 && barcount%bars_per_staff == 0) { - freshline(); - bars_on_line=0; - } - /* can't zero barcount because I use it for computing maxbarcount */ - else if(bars_on_line >= bars_per_line && i != NULL) { - fprintf(outhandle," \\"); - freshline(); - bars_on_line=0;} - } - else if (featurecount == 0) { - /* note grouping algorithm */ - if ((barsize/parts_per_unitlen) % 3 == 0) { - if ( (barnotes/parts_per_unitlen) % 3 == 0 - &&(barnotes%parts_per_unitlen) == 0) { - fprintf(outhandle," "); - }; - } - else { - if (((barsize/parts_per_unitlen) % 2 == 0) - && (barnotes % parts_per_unitlen) == 0 - && ((barnotes/parts_per_unitlen) % 2 == 0)) { - fprintf(outhandle," "); - }; - }; - } - if (nogr) fprintf(outhandle," "); - }; - if (i == NULL) /* end of track before end of measure ? */ - { - last_i[splitnum] = i; - splitchordhead[splitnum] = chordhead; - splitchordtail[splitnum] = chordtail; - splitgap[splitnum] = gap; - splitnum = nextsplitnum(splitnum); - if (splitnum == -1) break; - chordhead = splitchordhead[splitnum]; - chordtail = splitchordtail[splitnum]; - gap = splitgap[splitnum]; - i = last_i[splitnum]; - if (barnotes != barsize) fprintf(outhandle, " & "); - barnotes = barsize; - } - - }; - /* print out all extra text */ - while (textplace != NULL) { - handletext(textplace->when, &textplace, trackno); - }; - freshline(); - if (barcount > maxbarcount) maxbarcount = barcount; -} - - - -void printtrack_split_voice(trackno, anacrusis) -/* print out one track as abc */ -int trackno, anacrusis; -{ - struct listx* i; - struct tlistx* textplace; - struct tlistx* textplace0; /* track 0 text storage */ - int step, gap; - int barnotes; - int barcount; - int bars_on_line; - long now; - char broken; - int featurecount; - int last_barsize,barnotes_correction; - int nlines; - int splitnum; - int lastnote_in_split; - - nlines= 0; - lastnote_in_split = 0; - label_split_voices (trackno); - midline = 0; - featurecount = 0; - inkaraoke = 0; - now = 0L; - broken = ' '; - chordhead = NULL; - chordtail = NULL; - i = track[trackno].head; - textplace = track[trackno].texthead; - textplace0 = track[0].texthead; - gap = track[trackno].startunits; - if (anacrusis > 0) { - barnotes = anacrusis; - barcount = -1; - } - else { - barnotes = barsize; - barcount = 0; - }; - bars_on_line = 0; - last_barsize = barsize; - active_asig = header_asig; - active_bsig = header_bsig; - setup_timesig(header_asig,header_bsig,header_bb); - active_keysig = header_keysig; - handletext(now, &textplace, trackno); - splitnum = 0; - gap = splitgap[splitnum]; - if (count_splits() > 1) fprintf(outhandle,"V: split%d%c\n",trackno+1,'A'+splitnum); - - while((i != NULL)||(gap != 0)) { - if (gap == 0) { - if (i->note->posnum + i->note->xnum == endposnum) lastnote_in_split = 1; - /* do triplet here */ - if (featurecount == 0) { - if (!no_triplets) { - broken = dospecial(i, &barnotes, &featurecount); - }; - }; -/* ignore any notes that are not in the current splitnum */ - if (i->note->splitnum == splitnum) { - /*printf("\nadding "); - printnote(i); */ - addtochord(i->note); - gap = i->note->xnum; - now = i->note->time; - } - i = i->next; - advancechord(0); /* get rid of any zero length notes */ - if (trackcount > 1 && trackno !=0) - handletext(now, &textplace0, trackno); - handletext(now, &textplace,trackno); - barnotes_correction = barsize - last_barsize; - barnotes += barnotes_correction; - last_barsize = barsize; - } - else { - step = findshortest(gap); - if (step > barnotes) { - step = barnotes; - }; - step = validnote(step); - if (step == 0) { - fatal_error("Advancing by 0 in printtrack!"); - }; - if (featurecount == 3) - { - fprintf(outhandle," (3"); - }; - printchord(step); - if ( featurecount > 0) { - featurecount = featurecount - 1; - }; - if ((featurecount == 1) && (broken != ' ')) { - fprintf(outhandle,"%c", broken); - }; - advancechord(step); - gap = gap - step; - barnotes = barnotes - step; - if (barnotes == 0) { - nlines++; - if (nlines > 5000) { - printf("\nProbably infinite loop: aborting\n"); - fprintf(outhandle,"\n\nProbably infinite loop: aborting\n"); - return; - } - fprintf(outhandle,"|"); - barnotes = barsize; - barcount = barcount + 1; - bars_on_line++; - if (barcount >0 && barcount%bars_per_staff == 0) { - freshline(); - bars_on_line=0; - } - /* can't zero barcount because I use it for computing maxbarcount */ - else if(bars_on_line >= bars_per_line && i != NULL) { - if (!lastnote_in_split) fprintf(outhandle," \\"); - freshline(); - bars_on_line=0;} - } - else if (featurecount == 0) { - /* note grouping algorithm */ - if ((barsize/parts_per_unitlen) % 3 == 0) { - if ( (barnotes/parts_per_unitlen) % 3 == 0 - &&(barnotes%parts_per_unitlen) == 0) { - fprintf(outhandle," "); - }; - } - else { - if (((barsize/parts_per_unitlen) % 2 == 0) - && (barnotes % parts_per_unitlen) == 0 - && ((barnotes/parts_per_unitlen) % 2 == 0)) { - fprintf(outhandle," "); - }; - }; - } - if (nogr) fprintf(outhandle," "); - }; - if (i == NULL && gap == 0) - { - i = track[trackno].head; - splitnum = nextsplitnum(splitnum); - lastnote_in_split = 0; - if (splitnum == -1) break; - gap = splitgap[splitnum]; - if(barnotes != barsize) freshline(); - fprintf(outhandle,"V:split%d%c\n",trackno+1,'A'+splitnum); - if (anacrusis > 0) { - barnotes = anacrusis; - barcount = -1; - } - else { - barnotes = barsize; - barcount = 0; - }; - } - }; - /* print out all extra text */ - while (textplace != NULL) { - handletext(textplace->when, &textplace, trackno); - }; - freshline(); - if (barcount > maxbarcount) maxbarcount = barcount; -} - -#endif - -void printtrack(trackno, anacrusis) -/* print out one track as abc */ -int trackno, anacrusis; -{ - struct listx* i; - struct tlistx* textplace; - struct tlistx* textplace0; /* track 0 text storage */ - int step, gap; - int barnotes; - int barcount; - int bars_on_line; - long now; - char broken; - int featurecount; - int last_barsize,barnotes_correction; - - midline = 0; - featurecount = 0; - inkaraoke = 0; - now = 0L; - broken = ' '; - chordhead = NULL; - chordtail = NULL; - i = track[trackno].head; - textplace = track[trackno].texthead; - textplace0 = track[0].texthead; - gap = track[trackno].startunits; - if (anacrusis > 0) { - barnotes = anacrusis; - barcount = -1; - } - else { - barnotes = barsize; - barcount = 0; - }; - bars_on_line = 0; - last_barsize = barsize; - active_asig = header_asig; - active_bsig = header_bsig; - setup_timesig(header_asig,header_bsig,header_bb); - active_keysig = header_keysig; - handletext(now, &textplace, trackno); - - while((i != NULL)||(gap != 0)) { - if (gap == 0) { - /* do triplet here */ - if (featurecount == 0) { - if (!no_triplets) { - broken = dospecial(i, &barnotes, &featurecount); - }; - }; - /* add notes to chord */ - addtochord(i->note); - gap = i->note->xnum; - now = i->note->time; - i = i->next; - advancechord(0); /* get rid of any zero length notes */ - if (trackcount > 1 && trackno !=0) - handletext(now, &textplace0, trackno); - handletext(now, &textplace,trackno); - barnotes_correction = barsize - last_barsize; - barnotes += barnotes_correction; - last_barsize = barsize; - } - else { - step = findshortest(gap); - if (step > barnotes) { - step = barnotes; - }; - step = validnote(step); - if (step == 0) { - fatal_error("Advancing by 0 in printtrack!"); - }; - if (featurecount == 3) - { - fprintf(outhandle," (3"); - }; - printchord(step); - if ( featurecount > 0) { - featurecount = featurecount - 1; - }; - if ((featurecount == 1) && (broken != ' ')) { - fprintf(outhandle,"%c", broken); - }; - advancechord(step); - gap = gap - step; - barnotes = barnotes - step; - if (barnotes == 0) { - fprintf(outhandle,"|"); - barnotes = barsize; - barcount = barcount + 1; - bars_on_line++; - if (barcount >0 && barcount%bars_per_staff == 0) { - freshline(); - bars_on_line=0; - } - /* can't zero barcount because I use it for computing maxbarcount */ - else if(bars_on_line >= bars_per_line && i != NULL) { - fprintf(outhandle," \\"); - freshline(); - bars_on_line=0;} - } - else if (featurecount == 0) { - /* note grouping algorithm */ - if ((barsize/parts_per_unitlen) % 3 == 0) { - if ( (barnotes/parts_per_unitlen) % 3 == 0 - &&(barnotes%parts_per_unitlen) == 0) { - fprintf(outhandle," "); - }; - } - else { - if (((barsize/parts_per_unitlen) % 2 == 0) - && (barnotes % parts_per_unitlen) == 0 - && ((barnotes/parts_per_unitlen) % 2 == 0)) { - fprintf(outhandle," "); - }; - }; - } - if (nogr) fprintf(outhandle," "); - }; - }; - /* print out all extra text */ - while (textplace != NULL) { - handletext(textplace->when, &textplace, trackno); - }; - freshline(); - if (barcount > maxbarcount) maxbarcount = barcount; -} - - - - -void remove_carriage_returns(char *str) -{ -/* a carriage return might be embedded in a midi text meta-event. - do not output this in the abc file or this would make a nonsyntactic - abc file. -*/ -char * loc; -while (loc = (char *) strchr(str,'\r')) *loc = ' '; -while (loc = (char *) strchr(str,'\n')) *loc = ' '; -} - - - -void printQ() -/* print out tempo for abc */ -{ - float Tnote, freq; - Tnote = mf_ticks2sec((long)((xunit*unitlen)/4), division, tempo); - freq = (float) 60.0/Tnote; - fprintf(outhandle,"Q:1/4=%d\n", (int) (freq+0.5)); - if (summary>0) printf("Tempo: %d quarter notes per minute\n", - (int) (freq + 0.5)); -} - - - - -void setupkey(sharps) -int sharps; -/* set up variables related to key signature */ -{ - char sharp[13], flat[13], shsymbol[13], flsymbol[13]; - int j, t, issharp; - int minkey; - - for (j=0; j<12; j++) - key[j] = 0; - minkey = (sharps+12)%12; - if (minkey%2 != 0) { - minkey = (minkey+6)%12; - }; - strcpy(sharp, "ccddeffggaab"); - strcpy(shsymbol, "=^=^==^=^=^="); - if (sharps == 6) { - sharp[6] = 'e'; - shsymbol[6] = '^'; - }; - strcpy(flat, "cddeefggaabb"); - strcpy(flsymbol, "=_=_==_=_=_="); - /* Print out key */ - - if (sharps >= 0) { - if (sharps == 6) { - fprintf(outhandle,"K:F#"); - } - else { - fprintf(outhandle,"K:%c", sharp[minkey] + 'A' - 'a'); - }; - issharp = 1; - } - else { - if (sharps == -1) { - fprintf(outhandle,"K:%c", flat[minkey] + 'A' - 'a'); - } - else { - fprintf(outhandle,"K:%cb", flat[minkey] + 'A' - 'a'); - }; - issharp = 0; - }; - if (sharps >= 0) { - fprintf(outhandle," %% %d sharps\n", sharps); - } - else { - fprintf(outhandle," %% %d flats\n", -sharps); - }; - key[(minkey+1)%12] = 1; - key[(minkey+3)%12] = 1; - key[(minkey+6)%12] = 1; - key[(minkey+8)%12] = 1; - key[(minkey+10)%12] = 1; - for (j=0; j<256; j++) { - t = j%12; - if (issharp) { - atog[j] = sharp[t]; - symbol[j] = shsymbol[t]; - } - else { - atog[j] = flat[t]; - symbol[j] = flsymbol[t]; - }; - trans[j] = 7*(j/12)+((int) atog[j] - 'a'); - if (j < MIDDLE) { - atog[j] = (char) (int) atog[j] + 'A' - 'a'; - }; - if (key[t] == 0) { - back[trans[j]] = j; - }; - }; -} - - - - -/* Functions for supporting the command line user interface to midi2abc. */ - - -int readnum(num) -/* read a number from a string */ -/* used for processing command line */ -char *num; -{ - int t; - char *p; - int neg; - - t = 0; - neg = 1; - p = num; - if (*p == '-') { - p = p + 1; - neg = -1; - }; - while (((int)*p >= '0') && ((int)*p <= '9')) { - t = t * 10 + (int) *p - '0'; - p = p + 1; - }; - return neg*t; -} - - -int readnump(p) -/* read a number from a string (subtly different) */ -/* used for processing command line */ -char **p; -{ - int t; - - t = 0; - while (((int)**p >= '0') && ((int)**p <= '9')) { - t = t * 10 + (int) **p - '0'; - *p = *p + 1; - }; - return t; -} - - -void readsig(a, b, sig) -/* read time signature */ -/* used for processing command line */ -int *a, *b; -char *sig; -{ - char *p; - int t; - - p = sig; - if ((int)*p == 'C') { - *a = 4; - *b = 4; - return; - }; - *a = readnump(&p); - if ((int)*p != '/') { - char msg[80]; - - sprintf(msg, "Expecting / in time signature found %c!", *p); - fatal_error(msg); - }; - p = p + 1; - *b = readnump(&p); - if ((*a == 0) || (*b == 0)) { - char msg[80]; - - sprintf(msg, "%d/%d is not a valid time signature!", *a, *b); - fatal_error(msg); - }; - t = *b; - while (t > 1) { - if (t%2 != 0) { - fatal_error("Bad key signature, divisor must be a power of 2!"); - } - else { - t = t/2; - }; - }; -} - -int is_power_of_two(int numb) -/* checks whether numb is a power of 2 less than 256 */ -{ -int i,k; -k = 1; -for (i= 0;i<8;i++) { - if(numb == k) return(1); - k *= 2; - } -return(0); -} - -int getarg(option, argc, argv) -/* extract arguments from command line */ -char *option; -char *argv[]; -int argc; -{ - int j, place; - - place = -1; - for (j=0; j= 0) bars_per_line=1; - if (!unitlen_set) { - if ((asig*4)/bsig >= 3) { - unitlen =8; - } - else { - unitlen = 16; - }; - } - arg = getarg("-b", argc, argv); - if ((arg != -1) && (arg < argc)) { - bars = readnum(argv[arg]); - } - else { - bars = 0; - }; - arg = getarg("-c", argc, argv); - if ((arg != -1) && (arg < argc)) { - xchannel = readnum(argv[arg]) - 1; - } - else { - xchannel = -1; - }; - arg = getarg("-k", argc, argv); - if ((arg != -1) && (arg < argc)) { - keysig = readnum(argv[arg]); - if (keysig<-6) keysig = 12 - ((-keysig)%12); - if (keysig>6) keysig = keysig%12; - if (keysig>6) keysig = keysig - 12; - ksig_set = 1; - } - else { - keysig = -50; - ksig_set = 0; - }; - - if(guessk) ksig_set=1; - - arg = getarg("-o",argc,argv); - if ((arg != -1) && (arg < argc)) { - outhandle = efopen(argv[arg],"w"); /* open output abc file */ - } - else { - outhandle = stdout; - }; - arg = getarg("-nt", argc, argv); - if (arg == -1) { - no_triplets = 0; - } - else { - no_triplets = 1; - }; - arg = getarg("-nogr",argc,argv); - if (arg != -1) - nogr=1; - else nogr = 0; - - arg = getarg("-f", argc, argv); - if (arg == -1) { - arg = huntfilename(argc, argv); - }; - if ((arg != -1) && (arg < argc)) { - F = efopen(argv[arg],"rb"); -/* fprintf(outhandle,"%% input file %s\n", argv[arg]); */ - } - else { - printf("midi2abc version %s\n usage :\n",VERSION); - printf("midi2abc filename \n"); - printf(" -a \n"); - printf(" -xa Extract anacrusis from file "); - printf("(find first strong note)\n"); - printf(" -ga Guess anacrusis (minimize ties across bars)\n"); - printf(" -gk Guess key signature \n"); - printf(" -gu Guess xunit from note duration statistics\n"); - printf(" -m