Notes on the code ----------------- These notes are for anyone who wants to re-compile, re-write or re-use bits of the code. Compilation ----------- The file midifile.c and the header file midifile.h are slightly changed from the midifilelib distribution. To see the program dependencies, examine the Makefile. The code is written in K&R style C and should be fairly easy to compile on any system with a C compiler and a make utility. Makefiles are provided for gcc/unix, DJGPP/DOS and PCC/DOS. You may get warning messages if your compiler prefers ANSI C style function prototypes. To compile the code, type make all If the complete compilation does not work, you can try compiling the individual programs separately : make midi2abc make abc2midi make abc2abc make mftext --------------------------------------------------------------------- Calling abc2midi or midi2abc from a GUI. ---------------------------------------- The programs should now have an exit value of 0 for normal termination and 1 for an error state. However, abc2midi will still exit with 0 if it finds non-fatal errors in the code, so the user should always have the option of looking at the program's text output (I don't want to get blamed when useful diagnostic output turns into the ubiquitous 'OK' click-button). ---------------------------------------------------------------------- The abc parser -------------- abc2midi has been written as a parser program (parseabc.c) and an event handler program (tomidi.c). The parser has been written so that it should be possible to write your own utility to handle the interpreted abc and link it with the parser code. This is very similar to the way that the midifilelib utilities work. Moreover, the parser makes it is possible to write out almost exactly what you read in. This means that in some cases the level of parsing is fairly primitive and you may wish to make use of routines in tomidi.c which doing further processing on an item. If you just want to do some fairly simple processing on the abc, you may find it easier to modify toabc.c, which is the back-end for abc2abc. In the first phase of parsing, the abc file is read and when, say, a note is encountered, the routine event_note() is called. The code for event_note is in the file tomidi.c. Encountering an X in the abc generally causes a routine called event_X() to be called. abc2midi builds up an internal representation of the tune. At the end of the abc tune, a little bit of processing is done on the internal representation before the routine writetrack() is called to actually write out the MIDI file. If there are repeats in the music, something that appears only once in the abc may be invoked twice by writetrack(). The internal representation uses the arrays feature[], pitch[], num[], and denom[]. feature[] holds a description of an object while the other arrays hold data relating to the object. The list of possible features can be found in the file abc.h . The main features are NOTE, a note of specified duration, REST, a pause of specified duration and TNOTE, a note of specified duration with no interval between when it starts and when the next item starts. This provides a simple way of representing chords. Ties, broken rhythm signs and grace note brackets are all deal with before writetrack() is called. To add your own special features, you could define a new feature type. However, an easier option is to use the %%MIDI format. If the parser encounters "%%MIDI command", where command is not recognized by the routine event_specific(), the string following %%MIDI is stored away and passed to the routine dodeferred() by writetrack() when the MIDI file is being written. Parsing the abc --------------- The abc is parsed line by line. Each line may be * A comment * A package-specific command * A field (which may have a trailing comment) * A blank line * A TeX command Having detected one of these, the parser calls an appropriate routine. If it is none of these, then within the tune body it is * A line of music (which may have a trailing comment). Which is parsed and individual elements recognized. Outside the tune body it is * A line of arbitrary text. and an appropriate routine is called. Routines called by the parser ----------------------------- These may be a bit out of date - look in the file parseabc.c for the actual interfaces. event_init(argc, argv, filename) int argc; char* argv[]; char** filename; - first routine called by the parser. Expects filename to be the name of the abc file to parse on return. event_text(s) char *s; - called whenever a line of text is encountered. event_tex(s) char *s; - called whenever a TeX command is encountered. event_linebreak() - called whenever a newline character is encountered. event_blankline() - called whenver a blank line is encountered. event_eof() - called when the end of file is reached. event_error(s) char *s; - called whenever an error condition is detected. Errors are generally not fatal within the parser. event_warning(s) char *s; - called whenever a condition which is likely to be an error is detected. event_comment(s) char *s; - called whenever a comment is encountered. The following are calls are invoked by fields in the abc : event_specific(package, s) char *package, *s; - recognizes %%package s event_length(n) int n; - recognizes L: event_refno(n) int n; - recognizes X: event_tempo(n, a, b, rel) int n, a, b; int relative; - recognizes Q: event_timesig(n, m) int n, m; - recognizes M: event_key(sharps, s, minor) int sharps; char *s; int minor; - recognizes K: event_part(s) char* s; - recognizes P: When any other field is encountered in the abc : event_field(k, f) char k; char *f; If a line of music is encountered, the elements of that line each trigger a call to one of the following events, provided that parsing of music lines has been enabled : event_graceon() event_graceoff() event_rep1() event_rep2() event_slur(t) int t; event_tie() event_rest(n,m) int n, m; event_bar(type) int type; event_space() event_lineend(ch, n) char ch; int n; event_broken(type, mult) int type, n; event_tuple(p, q, r) int p, q, r; - general tuple: q and r are zero if not present event_chord() - called whenever + is encountered. event_chordon() - called whenever [ is encountered. event_chordoff() - called whenever ] is encountered. event_gchord(s) char* s; event_reserved(p) char p; event_note(roll, staccato, updown, accidental, mult, note, octave, n, m) int roll, staccato, mult; char updown, accidental, note; int octave, n, m; In addition, there are 2 other routines : int getline() - returns the line currently being parsed parseron() - enable parsing of music lines. parseroff() - disable parsing of music lines. --------------------------------------------------------------------- Extensions to the abc Format ---------------------------- 1. The parser recognizes %%package as some package-specific command and calls event_specific with the package name and the string that follows it. 2. The abc standard defines notation for 4 octaves : C, - B, C - B c - b c' - b' The parser recognizes each additional comma as meaning "going down an extra octave", giving C,, - B,, C,,, - B,,, and so on. Likewise, each additional prime symbols s interpreted as "go up an extra octave" : c'' - b'' c''' - b''' and so on.