abcMIDI-2020.07.06.zip

This commit is contained in:
Seymour Shlien
2020-07-12 12:40:01 -04:00
commit 0497c9a75b
84 changed files with 66163 additions and 0 deletions

View File

@@ -0,0 +1,420 @@
Some Notes on the abc2midi Code
-------------------------------
written by Seymour Shlien
Abc2midi.txt - last updated 29 November 1999.
This file provides an algorithmic description of the program
abc2midi which converts an abc file into a midi file.
The sources of abc2midi now comprising of 6700 lines of C code are
contained in the following five files.
parseabc.c is the front end which scans the abc file and invokes
the appropriate event handler for each element it encounters
(eg. bar lines, notes, chords etc.) It happens to be the
front end for other programs such as abc2ps, yaps and
abc2abc.
store.c contains all the event handlers which are invoked from
parseabc. It converts the abc file into an internal
representation described later in this file.
genmidi.c converts this internal representation in an output midi
file.
queues.c are some utilities needed by genmidi.
midifile.c is a library of public domain routines to read and write
midifiles.
In order to handle the multiple voices, parts, repeats and accompaniments
which occur in abc files, the program performs multiple passes. The
midi file stores the different voices, accompaniment and lyrics in
individual tracks, so it is necessary to separates these parts prior
to writing it to the midi file. If there are repeats in the music,
something which appears only once in the abc file may be invoked twice
when creating the output midi file.
Parseabc.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. The parser is designed so that it can write out
almost exactly what it reads in. This means that in some cases
the level of parsing is fairly primitive and it may be necessary to make
use of routines in store.c which perform further processing on an item.
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 store.c. Encountering an X in the abc generally causes a
routine called event_X() to be called. An internal representation of the tune
is built up and when the end of an abc tune is reached, a little bit of
processing is done on the internal representation before the routine
mywritetrack() is called to actually write out the MIDI file.
The main program to abc2midi is contained in this file. Since this
main program is used to start other programs such as yaps, it is
fairly simple. It calls event_init defined in store.c which obtains
all the user parameters (eg. input filename) and then executes the
top level procedure, parsefile.
The procedure parsefile (filename), opens the specified file (or stdin)
and processes it one character at a time. The characters fill a line
buffer which is passed to the procedure parseline whenever a linebreak
character (eg. linefeed) is encountered. By doing it in this fashion,
abc2midi is able to eliminate the extra carriage return which occurs
in DOS files.
The procedure parseline first checks for blank lines and comments. A
blank line signals the end of the tune and the event_blankline is called
to initiate the next stage in processing. If it is neither a comment or
blank line, the procedure must decide whether the line is a a field line
(eg."X:2") or part of a music body (eg. "|:C>DGz|..."). This is decided
using the following rule. If the first letter begins with one of the field
letter commands and is immediately followed by a ":", then it is treated
as a field line and parsefield is called. Otherwise if a K: field line
was already encountered (variable inbody set to 1), then it is treated
as a line of music. If neither case is satisfied, then the line is
intepreted as plain text.
The procedure parsefield identifies the particular field line type
and invokes the appropriate support function or event handler. If the
field command occurs after the first K: line, then only certain field
lines are legal. (For example it is illegal to place a T: (title) line
after the K: (key signature) line.)
The procedure parsemusic is the most complex procedure in the file and
recognizes the musical notes, chords, guitar chord names, bar lines,
repeats, slurs, ties, graces etc. Appropriate event handlers and
support functions are called to complete the tasks of parsing the
information. The parsenote function, for example, must check for
decorations, accidentals, octave shifts as well as identifying the
note and its determining its duration.
Unlike the other software modules, parseabc.c contains few global
variables. The global variables linenum, inhead, inbody, parsing,
slur, parserinchord indicate which lexical component of the abc
tune is being processed.
store.c
-------
This is the most complex module consisting of almost 3000 lines
of source code. This module contains all of the event handlers which
may be invoked in the file parseabc.c. The main purpose of these
handlers are to build up an internal representation of the abc file
in the global memory arrays. This is a complete representation
which allows the regeneration of the abc file (eg. abc2abc) or
the creation of a midi file. The internal representation is used
by the genmidi.c software to create the midi file.
Global variables
The internal representation is stored in global variables defined
at the beginning of the file. A description of the most important
variables is given here.
The music is stored in the four arrays, feature, pitch, num, denom.
These arrays contains a list of the lexical components in the order
that they have been encountered or created.
The array "feature" identifies the type of component which can be one
of the following enum features.
SINGLE_BAR, DOUBLE_BAR, BAR_REP, REP_BAR, 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, TITLE, CHANNEL, TRANSPOSE, RTRANSPOSE, GRACEON,
GRACEOFF, SETGRACE, SETC, GCHORD, GCHORDON, GCHORDOFF, VOICE,
CHORDON, CHORDOFF, SLUR_TIE, TNOTE, LT, GT, DYNAMIC, LINENUM,
MUSICLINE, MUSICSTOP, WORDLINE, WORDSTOP
The array pitch[] mainly stores the pitch of a musical note,
represented in the same manner as in a midi file. Thus middle
C has a value of 60. The array has other uses, for example
in a LINENUM feature it stores the line number relative to
the X: reference command where the lexical feature has been
detected. The LINENUM feature is useful when reporting warnings
or errors in the input file. Duration of the notes are represented
as a fraction, where the standard unit is defined by the L:
command. If feature[n] is a NOTE, then num[n] and denom[n]
contain the numerator and denominator of this fraction.
Here is an example of the contents of these arrays for the
following small file in the same order that they are stored in
these arrays.
X: 1
T: sample
M: 2/4
L: 1/8
K: G
|: C>D[EF]G |C4:|
Feature Pitch Num Denom
LINENUM 2 0 0
TITLE 0 0 0
LINENUM 3 0 0
LINENUM 4 0 0
LINENUM 5 0 0
DOUBLE_BAR 0 0 0
LINENUM 6 0 0
MUSICLINE 0 0 0
BAR_REP 0 0 0
NOTE 60 2 3
NOTE 62 1 3
CHORDON 0 0 0
NOTE 64 1 2
NOTE 66 1 2
CHORDOFF 0 1 2
NOTE 67 1 2
SINGLE_BAR 0 0 0
NOTE 60 2 1
REP_BAR 0 0 0
MUSIC_STOP 0 0 0
LINENUM 7 0 0
In order to support multivoice abc files in the form
V:1
| ...| ...|....
V:2
| ...| ...|....
%
V:1
| ...| ...|....
V:2
| ...| ...|....
etc.
abc2midi maintains a voicecontext structure for each voice.
This allows each voice to define its own key signature, default
note length using internal field commands. There is a head
voicecontext which is used when no voice field commands are
defined in the abc file. The v[] array maintains a set of
all voices active in the abc file and voicecount keeps track
of the number of voices.
Similarly, abcmidi maintains a list of all the part stored
in the feature[], pitch[], num[] and denom[] arrays.
All text items (eg. title and some other fields) are stored
in char atext[][] arrays, so that they can be included in
the midi output file. The textual information is repeated
in each track of the output midi file.
Following the conventions in the midi file, the program uses
the quarter note as the standard unit of time instead of the
whole note. In contrast, the standard length in the abc file
is based on the whole note. For example in L:1/8, the fraction
refers to a whole note. In order to convert time units to
quarter notes, the numerator of the time specifications
for note lengths is multiplied by 4 when it is added to
the feature list.
Table of contents of procedures in store.c
getarg(option, argc, argv) - gets run time arguments.
newvoice(n) - creates a new voice context.
getvoicecontext() - finds or makes a voice context.
clearvoicecontexts() - frees up the memory of the voice context
event_init() - called by main program
event_text(s) - called when a line of text is encountered.
event_reserved(p) - handles reserved character codes H-Z.
event_tex(s) - called whenever a TeX command is encountered.
event_linebreak() - called whenever a newline character is encountered.
event_startmusicline() - called for each new music line.
event_endmusicline() - called at the end of each music line.
event_eof() - end of abc file encountered.
event_fatal_error(s) - reports fatal error.
event_error(s) - reports an error.
event_warning(s) - reports a potential problem.
event_comment(s) - called whenever a comment is encountered.
event_specific(package, s) - recognizes %%package s.
event_startinline() - beginning of an in-music field command.
event_closeinline() - finishes an in-music field command.
event_field(k,f) - for R:, T: and any other unprocessed field commands.
event_words(p) - processes a w: field command.
char_out(list,out,ch) - for building up a parts list in a P: command.
read_spec() - converts P:A(AB)3 to P:AABABAB etc.
event_part(s) - handles a P: field.
char_break() - reports error for improper voice change.
event_voice(n,s) - processes a V: field.
event_length(n) - recognizes L: field
event_blankline - starts finishfile() procedure.
event_refno(n) - recognizes X:
event_tempo(n, a, b, rel) - recognizes Q:
event_timesig(n, m) - recognizes M:
event_key(sharps, s, minor, modmap, modmul) - recognizes K:
event_graceon() - start of grace notes, "{" encountered.
event_graceoff() - end of grace notes, "}" encountered.
event_rep1() - handles first repeat indicated by [1.
event_rep2() - handles second repeat indicated by [2.
event_slur(t) -called when s encountered in abc.
event_sluron(t) called when "(" is encountered in abc.
event_sluroff(t) called when ")" is encountered in abc.
slurtotie() - converts slur into tied notes.
event_tie() - handles tie indication "-".
event_rest(n,m) - processes rest indication Z or z.
event_bar(type) - processes various types of bar lines.
event_space() - space character encountered. Ignored here.
event_linend(ch,n) - handles line continuation at end of line (eg. \).
event_broken(type, mult) - handles >, <, >> etc. in abc.
event_tuple(n,q,r) - handles triplets and general tuplets.
event_chord() - called whenever + is encountered.
marknotestart() - remembers last few notes in voice context.
marknoteend() - this is used to process broken rhythms (eg. >).
marknote() - called for single note (as opposed to chord).
event_chordon() - called whenever [ is encountered.
event_chordoff() - called whenever ] is encountered.
splitstring(s,sep,handler) - splits string with separator sep.
event_instuction(s) - handles !...! event.
getchordnumber(s) - searches known chords for chord s.
addchordname(s, len, notes) - adds chord name to known chord list.
event_gchord(s) - handles guitar chords.
event_handle_gchord(s) - handler for guitar chords.
event_handle_instruction(s) - handles dynamic indications (eg. !ppp!).
event_finger(p) - handles 1,2,...5 in guitar chord field (does nothing).
hornp(num,denom) - modifies rhythm to hornpipe.
event_note(roll, staccato, updown, accidental, mult, note, octave, n, m)
doroll(note,octave,n,m,pitch) - applies roll to note.
dotrill(note,octave,n,m,pitch) - applies trill to note.
pitchof(note,accidental,mult,octave) -finds MIDI pitch value
setmap(sf,map,mult) - converts key signature to accidental map.
altermap(v,modmap,modmul) - modifies accidental map.
copymap(v) - sets up working accidental map at beginning of bar.
addfeature(f,p,n,d) - places feature in internal tables.
autoextend(maxnotes) - increase memory limits for feature arrays.
textextend(maxstrings, stringarray) - resize array pointers to strings.
myputc(c) - workaround for problems with PCC compiler.
tiefix() - connect up tied notes.
dotie(j,xinchord) - called in preprocessing stage to handle ties.
addfrac(xnum,xdenom,a,b) - add a/b to the number of units in bar.
applybroken(place, type, n) - adjust length of broken notes.
brokenadjust() -adjust length of broken notes.
applygrace() - assign lengths to grace notes.
dograce() - assign lengths to grace notes.
lenmul(n, a, b) - multiply num(n),denom(n) by a/b.
zerobar() - start a new count of beats in the bar.
delendrep() - remove bogus repeat.
placeendrep(j) - patch up missing repeat.
placestartrep(j) - patch up missing repeat.
fixreps() - find and correct missing repeats in music.
startfile() - initialization performed after an event_refno.
tempounits(t_num, t_denom) - interprets Q: field.
setbeat() - sets default gchord command for time signature.
headerprocess() - called after the first K: field in tune.
finishfile() - starts next stage of processing when end of tune
is encountered.
All the functions in this file respond to event calls from parseabc.
Once the internal representation of the abc file is completed, the
procedure finishfile is called to perform some clean up and create
the midi file. An internal representation of the midi file is
first created and then it is written onto the designated output file.
As finishfile provides the link to the next module, genmidi.c, here
is a brief description of what it does.
proc finishfile performs several passes through the internal
representation to clean up the graces (dograce), the tied notes
(tiefix) and any unbalanced repeats. It then calls writetrack(i)
for each midi track to create the internal midi representation
and finally the midi representation is recorded in the output
file.
genmidi.c
---------
The procedure finishfile described above, creates each midi track
by calling the function writetrack which is defined here. To create
a track from the internal representation, the program must find all
the parts and put them in order with all the repeats. In addition, if
it contains karaoke text, this too must be placed in a separate track.
Any chordal accompaniment is generated from the guitar chord indications
and placed in another track. For multivoice and multipart music, a voice
may be missing in a particular part. If the voice is missing, the
procedure fillvoice ensures that all voices remain properly aligned when
the voice reappears in another part.
Here is a simple road map to the important procedures included in this
file.
dodeferred is here used to handle any dynamic indications (eg. !ppp!)
which may be contained in the file. The %%MIDI messages are stored
in a atext string which is pointed to by the contents of the pitch[]
array.
checkbar is called each time a bar line is encountered and reports
a warning if the wrong number of beats occur.
Transitions between parts are handled by the procedure partbreak.
There are a number of procedures for handling karoake text --
karaokestarttrack(), findwline(startline), getword(place,w),
write_syllable(place) and checksyllables().
For the first track, the meter, tempo and key signature are recorded
using the functions set_meter(n,m), write_meter(n,m), write_keysig(sf,mi).
Chordal accompaniment is produced by the procedure dogchords(i).
queues.c
--------
For each midi note, it is necessary to send a note-on and a note-off
instruction. When polyphonic music is played on the same track, keeping
track of the time to issue a note-off instruction may get complicated.
The procedures in this file are used to maintain a linked list for the
notes to be turned off. The notes are put into the list in the order
that they are encountered but the order in which to issue note-off
commands is maintained by the links. As many as 50 notes playing
simultaneously can be handled by the list.
Addendum
--------
The following section contains clarifications on various components
of abc2midi.
29 June 2003
Treatment of octave shifts.
The key signature field command K: has provision for shifting
a note using either transpose= or octave= subcommands. Both
of these functions operate quite differently and deserve some
description especially for multivoiced tunes.
The octave shift, is performed in event_note in store.c, using
the cached value v.octaveshift which is stored in the global
voicecontext structure, v. There is a structure for each voice
in the abc file. Whenever a new V: command is encountered,
event_voice (store.c) is invoked, which swaps the appropriate
voices structure into the global v array using the function
getvoicecontext(n). If getvoicecontext cannot find a cached
structure for that voice, then a new voice structure is created
and added to the linked list of voice structures. The v.octaveshift
variable is updated by event_octave which is called by event_key
(store.c) which is called by parsekey in parseabc.c
(Comment: it is not too clear how an octave switch is
handled in the middle of a repeat section. i.e. does the old
value get restored when repeating.)
(Description of transpose shift is in CHANGES July 1 2003.)

426
doc/programming/coding.txt Normal file
View File

@@ -0,0 +1,426 @@
Notes on the code
-----------------
These notes are for anyone who wants to re-compile, re-write or re-use
bits of the code. Additional information is available by downloading
the file abcextra.zip. This includes :
* man pages for abc2midi and midi2abc.
* A detailed description of the inner workings of abc2midi, written by
Seymour Shlien.
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. There are also some notes
on using the GUI front-end to Pacific C/DOS. You may get warning
messages if your compiler prefers ANSI C style function prototypes.
Choose the most suitable makefile; unix.mak, djgpp.mak or pcc.mak and
rename it as 'makefile'. If you are not using any of the above compilers,
you may have to edit the makefile so that it uses compilation flags
suitable for your compiler.
To compile the code, type
make all
If the complete compilation does not work, you can try compiling the
individual programs separately :
make midi2abc (or make midi2abc.exe)
make abc2midi (or make abc2midi.exe)
make abc2abc (or make abc2abc.exe)
make mftext (or make mftext.exe)
make yaps (or make yaps.exe)
Note that the make utility on some systems (e.g. GNU make) may require the
Makefile to be a unix text file and not a DOS text file. The difference
is that unix uses newline to mark the end of each line while DOS uses
carriage return and newline.
Note, if you have difficulty compiling the package because you do not have
snprintf see the note in doc/CHANGES dated January 08 2005 (and also
December 17 2004).
---------------------------------------------------------------------
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).
----------------------------------------------------------------------
Man pages
---------
Files: abc2midi.1 and midi2abc.1
Christoph Dalitz has written some man pages for abc2midi and
midi2abc. These should be installed in the sub-directory /man1
of the directory given by the MANPATH environment variable.
(The man command is usually only found on Unix variants).
The source distribution has been re-organized to contain only the
source and a few text files. If you want these man pages, you need
to download the file abcextra.zip.
---------------------------------------------------------------------
Code Layout and Indentation style
---------------------------------
If you want to add your own code and make it fit in with the existing
coding style, you can use GNU indent. The following is a DOS batch file
to invoke indent with the appropriate options.
indent -bad -bap -br -ce -cli0 -npcs -di1 -nbc -i2 -ts0 -psl -lp -ipo %1
rem
rem options for GNU indent to achieve my personal style
rem
rem -bad blank line after declaration block
rem -bap blank line after procedure body
rem -br brace on same line after if, struct and enum
rem -ce cuddle else
rem -cli0 case at same identation as switch
rem -npcs no space between procedure name and following open bracket
rem -di1 one space between variable type and variable name
rem -nbc comma-separated variables on the same line
rem -i2 indent 2 spaces
rem -ts0 no tabs
rem -npsl function type on same line as function name
rem -lp continuations matched to left parenthesis
rem -ip0 no indention of variables in K&R function headers
rem -ncs no space after cast
---------------------------------------------------------------------
Extensions to the abc Format
----------------------------
1. The parser recognizes
%%package <string>
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.
----------------------------------------------------------------------
abc2midi
--------
abc2midi consists of the following C source files:
parseabc.c - parses the input text and calls a routine for
every parsed element encountered.
parser2.c - performs some additional parsing that may not be
required.
store.c - builds an internal representation of the abc tune.
genmidi.c - uses the internal representation to generate
the MIDI file, using calls to MIDI-specific routines
in midifile.c
queues.c - library of routines for handling 'queues', a data
structure used internally by genmidi.c
midifile.c - Thompson and Czeisperger's public domain library of
MIDI file manipulation routines.
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 store.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.
----------------------------------------------------------------------
abc2abc
-------
abc2abc shares the parser with abc2midi, but instead of storing the
abc code in an internal format, it is written almost straight out
again. The components of abc2abc are:
parseabc.c - parser
toabc.c - generates output abc.
midifile.c - public domain MIDI library.
----------------------------------------------------------------------
YAPS
----
YAPS is written mainly using ANSI C style function headers and
compiled and tested using DJGPP (DOS/Windows port of gcc).
The code is composed of the following files:
parseabc.c - reads through the abc text file. When it recognizes an abc
"unit" it calls a routine such as event_note() or event_key().
yapstree.c - creates a data structure to represent a tune.
Generally, I have tried to use as small a number of passes through the
data structure as possible. This means that things like applying a
broken rhythm symbol > is done as the notes are read in, rather than
using a second pass. This results in a lot of variables being needed in
'struct voice' to keep track of what is going on as we read in the
current symbols. Different sets of these variables are used on different
passes through the data.
drawtune.c - responsible for creating the PostScript file. When a whole
tune has been read in, this calculates the size of each individual
element, works out spacing within each line, decides how to place the beam
for a group of beamed notes, then finally generates the PostScript for
the tune.
position.c - called by drawtune.c. This set of routines is responsible
for spacing each line correctly. Where the input abc is multi-voice,
elements played at the same time but in different voices are aligned.
pslib.c - a single routine to print out the entire library of PostScript
functions used by yaps.
debug.c - routines to print to screen the contents of a tune data
structure.
abc.h - header file defining abc element types.
structs.h - header file defining the data structures used by the program.
The voice structure holds a lot of cuurent context information, used by
the program as it does a pass through the voice.
sizes.h - header file containing macros to define sizes in points for all
the graphic elements.
Dynamic Memory Management
-------------------------
abc2midi uses a system of re-sizable arrays in order to handle arbitrary
size input. This scheme was a natural way to adapt the original fixed size
arrays, and is not as flexible as it might be. Yaps instead uses linked
lists. There is a tune data structure containing a linked list of voices
and the notes and other elements are stored in a linked list in each tune.
Some music elements contain their own linked lists; for example a note
may have a linked list of lyric syllables. Adding a new data item to an
element (e.g. a note) involves the following :
1. find 'struct note' in structs.h and add the element.
2. Initialize it in newnote().
3. If it is a pointer to a new data structure, make sure the new data
structure is de-allocated in freevoice().
----------------------------------------------------------------------
The abc parser
--------------
The parser (parseabc.c) has been written in such a way that it forms
an independent unit which must be linked with routines to handle
parsed units. This is very similar to the way that the
midifilelib utilities work.
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 whenever 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.

View File

@@ -0,0 +1,6 @@
/abc2midi.txt/1.1.1.1/Thu Sep 28 18:17:04 2006//
/coding.txt/1.1.1.1/Thu Sep 28 18:17:04 2006//
/midi2abc.txt/1.1.1.1/Thu Sep 28 18:17:04 2006//
/split.abc/1.1.1.1/Thu Sep 28 18:17:04 2006//
/yaps.txt/1.1.1.1/Thu Sep 28 18:17:04 2006//
D

View File

@@ -0,0 +1 @@
abcmidi/doc/programming

1
doc/programming/cvs/Root Normal file
View File

@@ -0,0 +1 @@
/home/seymour/CVSREPOS

View File

@@ -0,0 +1,227 @@
Notes on the midi2abc code
--------------------------
written by Seymour Shlien
midi2abc.txt - last updated December 5 1999
Introduction
Midi2abc is a program for converting a midi files into an abc file.
A midi file merely consists of a list of commands to turn on
and off a set of voices at specific times. The time units are
expressed in pulses where the number of pulses per second can
be deduced from the information in the midi file. Pitch is
specified in semitone units ranging from 0 to 127 where middle C
is assigned a value of 60.
There are two types of midi in general use. In type 0, all the
voices are interleaved in time in one track. Each voice goes
to a specific channel which is mapped to a particular musical
instrument or program. There is a limit of 16 voices since only
4 bits are assigned to indicate the channel number. In type 2,
the voices are placed in separate tracks. This format allows
handling more than 16 voices.
In order to create an abc file, midi2abc must determine the
length of a musical unit (for example an eighth note) in terms
of midi pulses, determine the key signature, and, finally map the
midi commands into musical notes.
Though the midi file specifies the number of pulses per quarter note
(PPQN) in the Mthd header chunk, this is not necessarily an
accurate indication. It is primarily used together with the tempo
indication to determine the number of pulses per second. Unless
the midi file was created by a computer program, the actual length
of a quarter note in midi pulses can depart from the nominal indication.
Midi2abc tries to determine the length using its own heuristic
algorithm.
The sources of the program are contained in two files: midi2abc.c and
midifile.c. This document does not try to describe completely how
this program works, but is more of a general road map to the software.
Algorithmic Description
The conversion is done in multiple passes. In the first pass, the
midi file is read and an internal representation of the file is
created and stored in global dynamic memory. In each subsequent pass,
other information is added to the internal representation and finally
it is written to the output abc file.
After parsing the input run parameters and performing various
initializations, the main program calls the procedure mfread
which is found in the midifile.c module. Mfread parses the different
midi components of the file and calls the appropriate functions
midi2abc to process these components. These functions begin with
the txt_ prefix, some of which are listed here.
txt_header midi header chunk
txt_trackstart start of midi track
txt_trackend end of midi track
txt_noteon note on channel command
txt_noteoff note off channel command
txt_program midi program definition or change
txt_metatext midi textual information
txt_keysig midi key signature indication
txt_tempo midi tempo indication
Many other functions such as txt_pressure and txt_parameter
corresponding to other midi commands, do nothing here.
These functions build up an internal representation of the midi file
in a global structure referenced through the track[64] structure.
Up to 64 midi tracks can be stored in the internal representation.
Each track structure (atrack structure) contains single and double
linked lists of notes or text strings which are described below.
In addition there are other linked lists (referenced by playinghead
and chordhead), used for keeping track of notes currently playing
and musical chords.
Each note is represented by an anote structure which stores various
parameters of the note. The anote structure is allocated dynamically
as the midi file is read. The first four entries of the structure
are filled in while the structures are being created by mfread.
These are entries are listed below.
anote.pitch pitch in midi units
anote.chan midi channel number
anote.vel midi velocity (corresponding to loudness)
anote.time time in midi pulses.
The other entries in the anote structure are determined in later passes.
The anote structures are linked together into a a listx structure which
is included in the atrack structure. The head and tail of the list are
contained in this structure to facilitate the construction of this list.
In addition there is tlistx structure for storing all the textual
information (for example words in a Karaoke midi file) which may be found
in the track.
There is a doubly linked list structure of anotes (dlistx,
*playinghead) which is used as a work space for matching the note off
command with the corresponding note on command. This is needed in order
to determine the length of time the note was turned on (called anote.tplay).
The internal representation is mainly constructed by the important
functions txt_noteon and txt_noteoff called by mfread. These functions
in turn call the functions addnote and notestop. The midi file contains
separate commands for turning a note on or off so that in order to
determine the length of time that a note has been on, it is necessary to
match a note-off command with the corresponding note-on command.
Every time a note is turned on, it is also added to the playhead (tail)
structure. The procedure notestop finds the corresponding note-on
command in the playhead structure, removes it, and records the
duration of the note which was turned on.
At the end of the first pass, the number of tracks is counted and each
track is processed by the function postprocess which computes the entry
anote.dtnext for each anote structure. This entry contains the time
interval between the current and the next note in the linked list of
notes.
The abc time unit length is either 1/8 or 1/16 depending on the time
signature. A time signature of 4/4 is assumed unless it is specified
by the run time parameters (-m or -xm). (If -xm is specified, then the
program uses the time signature given by the midi meta command if it
exists in the file.)
The next step involves the quantization of the midi time units
expressed in pulse counts into abc time units. It is first necessary
to estimate the length of an abc time unit in terms of midi time
units. This either is estimated using a heuristic algorithm,
guesslength, or is determined from the run time parameters (-Q or -b).
The function guesslength makes an initial guess by dividing the
total number of pulse counts in the track by the total number
of notes. It then tries 100 different lengths in the neighbourhood
of this initial guess and chooses the one which leads to the smallest
quantization error. The quantization error is determined by the function
quantizer which keeps track of the total deviation of the time
a note starts (in pulse counts) from the expected time the note
starts assuming the standard musical intervals. This deviation
can either drift positively or negatively with time. The total
error is determined by summing the absolute values of these
deviations for each bar.
Once the unit length has been determined, all the notes in all
tracks are quantized by the function quantizer. This function
assigns values to the anote entries, anote.xnum, anote.playnum
and anote.denom.
anote.xnum interval between the current note and following note
also called the gap.
anote.playnum note duration.
anote.denom always has the value of 2.
A musical part does not necessarily begin at the start of a bar line,
but may have some leading notes. This is called anacrusis.
There are two methods to estimate the anacrusis. The function findana
searches for the first upbeat by examining the velocities (loudness) of
the notes. The function guessana, chooses the anacrusis which minimizes
the number of tied notes across a bar line which is determined by the
function testtrack.
At this point the key signature of the tune must be determined.
The procedure findkey computes the frequency distribution of all the
notes in the piece and stores it in the local array n[]. The key
signature is determined by transposing the distribution by each
of the 12 keys and counting the number of sharp or flat notes. The
key signature is determined from the key which leads to the minimum
number of black keys on the piano. The mode of the scale (major,
minor, Dorian, etc.) is determined by looking at the final note of
the piece.
Once the key signature is determined, the assumed flats or sharps
are determined by the procedure setupkey. The program is now ready
for its final pass where the musical parts (or voices) are printed
in the output abc file.
The procedure printtrack processes the internal representation
of each midi track producing a separate voice for each track.
In order to handle chords which may be present in an individual
track, printtrack maintains a structure referenced by chordhead
by calling the support functions addchord(), advancechord(),
removechord() and printchord(). These functions handle single
notes as well as chords. Another function, dospecial(), handles
the triplets and broken rhythms (eg. dotted notes followed by
half sized note or vice versa) whenever they are detected. The
printchord() function is supported by the functions printfraction()
and printpitch().
After the track is printed, the memory allocated to the structures
for the internal representation of the tracks is freed.
The option -splitvoice was introduced to handle polyphonic chords.
Without this option polyphonic chords appear in the abc file
like this.
[DF-A-][FA-]Az|
this will be represented by three voices
V: split1A
D2 z6|
V: split1B
F4 z4|
V: split1C
A6 z2|
This option is implemented by the function printtrack_split_voice().
The function label_split_voices() is called to assign all the notes
in the track to their split voice. This assignment of each note is
stored in note->splitnum. This is a complex function since it needs
to try to match the onset and end of each note in the chord. If
it is unable to do this for a particular note, then the note is
assigned to a different split. At the end, nsplits were created.
The notes in each split are printed in a separate voice by the
function printtrack_split(). The function printtrack_split(splitnumber)
was derived from printtrack(); however, it only processes the
notes belonging to a particular splitnumber.
It was necessary to determine and store the offset of the first
note in each split using the function set_first_gaps() prior
to calling printtrack_split().

131
doc/programming/split.abc Normal file
View File

@@ -0,0 +1,131 @@
X:1
T: test split file 1
M: 2/4
L: 1/4
K: G
G & E & C|D|GA & EF|
X:2
T: test split file 2
M: 1/4
L: 1/4
K: G
%%MIDI program 20
D|G & E|C|F|G & E|
X:3
T: test split file 3
M: 2/4
L: 1/8
Q: 50
K: D
CD |EF AB & CD FG| G2 | BD D2 & GB B2|
X:4
T: test split file 4
M: 1/4
L: 1/4
K: G
V:1
|:G |[1 D & B:|
V:2
|:g |[1 d & b:|
V:1
[2 F & A|
V:2
[2 f & a|
X:5
T: test split file 5
M: 1/4
L: 1/4
K: G
G & E |D|
X:6
T: test split file 6
M: 1/4
L: 1/4
K: G
D|G & E|
X:7
T: test split file 7
M: 1/4
L: 1/4
K: G
D|G & E & C|F|
X:8
T: test split file 8
M: 1/4
L: 1/4
K: G
G & E & C|D|
X:9
T: test split file 9
M: 1/4
L: 1/4
K: G
G & E & C|D|F & A|
X:10
T: test split file 10
M: 1/4
L: 1/4
K: G
V:1
|:G |[1 D & B
V:2
|:g |[1 d & b
V:1
:|[2 F & A|
V:2
:|[2 f & a|
X:11
T: test split file 11
M: 1/4
L: 1/4
K: G
|:G & E :|D|F & A|
X:12
T: test split file 12
M: 1/4
L: 1/4
K: G
|:G & E |D:|F & A|
X:13
T: test split file 13
M: 1/4
L: 1/4
K: G
|:G & E |[1 D:|[2 F & A|
X:14
T: test split file 14
M: 1/4
L: 1/4
K: G
|:G |[1 D & B:|[2 F & A|
X:15
T: splits with octave=1
M: 4/4
L: 1/4
K: G octave=1
G A B C & E F G A|
X:16
T: test split file 13
M: 1/4
L: 1/4
K: G
|:G & E |1 D:|2 F & A|

134
doc/programming/yaps.txt Normal file
View File

@@ -0,0 +1,134 @@
Some Notes on the yaps Code
-------------------------------------------------------------
written by Seymour Shlien November 21 2004
This file gives an algorithmic description of the
yaps program which converts an abc file to a PostScript file.
The source consists of almost 10000 lines of C in the following
files.
parseabc.c is the front end which scans the abc file and invokes
the appropriate event handler for each element it encounters
(eg. bar lines, notes, chords etc.) It happens to be the
front end for other programs such as abc2midi, and
abc2abc. More details are given in abc2midi.txt.
yapstree.c contains all the event handlers called by the parser.
It produces a complex data structure called tune which
references many other structures. When the parser completes
processing the tune, event_blankline or event_eof calls
printtune (in drawtree.c) which processes the tune structure
producing a PostScript file. Unlike abc2midi, most of the
layout including the detailed beaming is done in the first
pass during the parsing stage. The information in this
structure is then processed by drawtune.c in two more
passes. An overview of these structures is provided here.
More details on the tune structure is provided in this
file.
drawtune.c contains the function printtune which turns the tune
structure into an actual PostScript file. This is done
in two passes. Before writing the PostScript file it
is necessary to determine the boundingbox of the output
image since this information is recorded in the header
of the output file. This is determined in the first pass
where functions monospace() or spacevoices() (in position.c)
are called. During this pass the pixel positions
of each object are recorded in the associated structures.
In the second pass, the actual PostScript file is written.
The function calls printlib() (in pslib.c) outputs
all the PostScript boiler plate macro definitions required
by yaps. The information in the tune structure is used
to output the music notation in a PostScript file.
position.c contains functions for determining the amount of space
that is required for the different music objects drawn
in the PostScript file.
parser2.c contains additional parsing functions missing in parseabc.
They handle more recent features added to the abcmidi package.
pslib.c Definition of new PostScript commands (eg. notes, clefs,
stems, tails, ...) which are copied to the PostScript
file.
debug.c Functions which support the -d option in yaps. It prints
some of the contents of the internal tune structure.
Data Structures
---------------
The data structures are defined in the include file structs.h.
The top level structure, tune is instantiated by init_tune which
is called by event_init or event_refno. It stores all the
information in the abc field commands (X: ,M:, L:, C:, O: and etc.).
It contains a pointer to the voice structure and a list of voice
pointers where most of the body information is recorded.
The voice structure is instantiated by the function newvoice
which is called by setvoice(n) whenever the voice context
switches in the abc file. Setvoice performs the voice switching
(which occurs in voice interleaved files) and either creates
a new voice or finds the matching voice structure already existing.
The voice structure contains the feature structure which
is somewhat similar in function to the one defined in store.c
(for abc2midi).
The feature structure encodes all the detailed information in
the body, using the same typedef enum featuretype defined
in abc.h. Unlike store.c there is no num and denom arrays. Instead
the feature struct contains a void* pointer called item which
can point to anything and where additional information can be
stored. If the feature type is a NOTE then a "note" struct
is created which records a lot of detailed information related
to the placement and visual representation of the note. They
include:
tail_type which specifies whether the note appears in
isolation or is part of a beamed group
base_exp whole, half, quarter, ... notes
dots how many dots follow
stemlength, stemup, fliphead, pitch, octave, accidentals, accents,...
(see struct.h)
Most of the information except actual positioning is determined
by functions such as count_dots and beamitem in yapstree.c.
You can view this information by running yaps.exe with the -d
run time parameter.
The handling of the note positioning is quite complex as
outlined below. It is therefore not easy to implement the
splitvoice feature into yaps. Here is a description.
The positioning of notes is done by the function
spacemultiline() which calls advance() unless one is printing
the voices separately. The positioning is done on all the voices
at the same time to ensure that they are lined up properly.
Spacemultiline accesses all the active voices using the functions
firstitem() and nextitem() which are used for handling any lists
of objects. Each voice maintains its own pointer to the current
feature being scanned (v->place). Each voice also maintains its
own pointer to the relative time of the note being scanned
in the variable v->time. (v->time contains both a numerator
and denominator.) The advance() function updates v->place,
v->time and interprets the voice features determining the
amount of space that is needed to plot the next object (itemspace)
and the number of plotable objects (items). The position to
plot the next object (x) is maintained by spacemultiline and
passed to advance. Advance() updates v->place->x with the position
to plot the object based on its width. Spacemultiline()
maintains a mastertime variable for maintaining synchrony
between all voices.
At least two passes are made through the voice features.
In the first pass provisional positions are computed for the
notes. The amount of space left over in the music lines is
computed and is used to determine the internote gaps.
In the second pass, the notes are repositioned to use up
the entire space in the staff line.
Spacemultiline is called for each staff line whose end is
signaled by a linefeed feature in the voice.