2003 March 27: Updated the man pages to abc2abc, abc2midi and midi2abc and created a new man page for yaps. Minor changes to midifile.c and midifile.h were made to minimize the number of warning error messages. Midi2abc was upgraded to be in line with the version I use with the script midi2abc.tcl. The syntax in mftext.c was improved to reduce the number of compilation warnings. 2003 April 12 abc2midi: for abc tunes with no guitar chords, an error message "Command not recognized" is issued whenever a %%MIDI chordprog or %%MIDI bassprog command is encountered. The problem occurs mainly with runabc, which performs only one pass through the tune and is unable to know whether guitar chords are present before sending %%MIDI commands. Since no MIDI program command is issued in this situation, the error message was disabled, The fix was made in dodeferred() in genmidi.c 2003 April 12 abc2midi assumes the ratio of 2:1 for long/short notes in broken rhythms specified with angle brackets (eg. c>d), Though this can be changed using the %%MIDI ratio command, it is inconvenient for many users since it is necessary to edit each tune in the abc file in order to effect this change. A new command parameter -RS (ratio standard) changes default ratio to 3:1 which is the standard music notation. The new parameter still allows the %%MIDI ratio command to override the default. The change was incorporated in event_init() of store.c. 2003 Apri 19 The proposed abc standard allows non numeric identifications for the voice field, eg. V: soprano instead of V:1. If you are creating a midi file, each unique identification string will mapped to a sequential numbers 1,2 etc, as if you had used numbers originally. The change allows abcMIDI to handle a number of new multivoiced abc files which have adopted this convention. Only the first 20 characters of the identification string are distinguished. Anything following the identification string is ignored. The identification string should not end with an equal sign =. If nonnumeric identifications are used, abc2midi will print the mapping between the id's and the numbers. This may be useful for catching spelling errors in the id's. The fix was made in function parsefield in parseabc.c. The change does not yet allow V: commands to appear before the body of the tune. A number of abc files may designate a rest using x instead of z. This means that this rest exists but should not appear in the printed score. I have modified the parser so it shall now interpret x as rest; however, if you are using yaps to print the score, this rest will still remain visible. Abc2midi will now treat x exactly like z. Abc2abc will probably automatically convert the x's to z's whether you want it or not. A minor change was made in parsemusic in parseabc.c. It is necessary to modify toabc.c and yapstree.c to fix the remaining problems. 2003 April 27 Guitar chords. The base note preceeded by a slash in the guitar chord may now be in lower case as well as upper case. For example, "G/B" and "G/b" will both be treated the same way. This complies with the proposed abc standard 1.7.6 (abc-draft.txt) and avoids problems with some files in the Nottingham database. The fix was made in event_handle_gchord in store.c. Guitar chords. When there is a change of meter, the gchord beat does not seem to get changed. I inserted a call to setbeat() in writetrack() in genmidi.c whenever a TIME feature is encountered. It was also necessary to change the definition of setbeat in store.c from static to external. 2003 May 3 Karoake lyrics: Improved the documentation for the functions write_syllable and getword in genmidi.c which handle the lyrics in the w: body line. If a bar line is placed in the lyric line between two tied notes, for example see below, "C6" c> G E2- | E2 (3 c d c | "E7" B> ^G E2- | E4 | w: All of me, | * why not take | all of me.* ^ write_syllable loses synchrony with the music while searching for the next bar line in the music. The problem was fixed by resetting waitforbar to 0 between the two calls of write_syllable, in writetrack (genmidi.c) after TNOTE is handled. I found most warning messages about mismatched lyric syllables to music notes have to do with users failing to notate syllables correctly when tied notes occur. (Failure to place a * or _ (underscore) preceding syllable of tied note. Confusing hyphen with underscore...) 2003 May 4 abc2midi file xref: Abc2midi has the option of converting only a particular tune in a abcfile to a midi file by specifying the X: reference number immediately following the abc file name. When this feature is used, warning messages such as Warning in line 28: T: outside tune body - possible missing X: The problem occurs in the function parsefield in parseabc.c. In order to catch the reference number of the selected tune, every line of the input file is parsed. A flag "parsing" equal to 0 or 1 is used to turn on the parsing inside the body of the of the music. This flag is turned in function event_refno() in store.c by calling the function parseon() in parseabc.c. Unfortunately all field lines (eg. T: , M:, L:, V: ...) were unaffected by this flag and continued to be parsed. When the T: field command is encountered, it falls through to the default: in parsefield and it is processed by the function, event_field in store.c. Event_field was designed to treat the T: and R: conditions but before handling these conditions it checks whether the control flag dotune is set. This flag is also set by event_refno. If the flag is not set, then event_field assumes that a T: field command was encountered without a preceding X: reference field which is a valid error condition. Since all field lines in the abc file are parsed this introduces other problems. Any anomaly in the field lines whether they are from the selected tune or not are reported. For example, if a user has selected for example tune 500 from a large abc file, errors in the field lines of other tunes will be reported. Furthermore, in some cases the program may crash in processing a field line of another tune. To address these problems, the functions parseline and parsefield in parseabc.c were modified so that all field lines (except for the X: field line) and all text lines are ignored for nonselected tunes. Parseline checks whether the flag parsing is set before calling parsemusic or event_text. In parsefield, the condition key == 'X' was moved from the switch control structure and treated separately immediately when entering this function. If parsing flag has not been set, the function returns immediately after checking for key == 'X'. This introduces a new problem. If the abc file has no X: field, the abcmidi programs does nothing without any error indication. To handle, this situation I introduced a the global variable parsing_started into parseabc.c, It is initialized to 0 and set to 1 when the function parseron() is called. Prior to the end of the function parsefile, the parsing_started variable is checked. If it is still 0, an error message is returned. Finally, event_linebreak() is suppressed in parsefile() whenever the variable parsing is not set. This avoids a lot of blank line output from abc2abc whenever the X: field is missing from the input abc file. This is a major change to the code, since it affects three programs, abc2midi, yaps and abc2abc. I hope this has not introduced new problems. 2003 May 11 Many tunes have a left repeat sign (|:) missing. In most cases it is fairly clear where to place the repeat sign and abc2midi merely puts a warning message "Assuming repeat". When you are processing a large group of abc tunes these messages may be annoying. A new parameter -NAR (no assuming repeat) will suppress this message when you are running abc2midi. However, occasionally you get the error message "Found unexpected :| ...". This is a more serious problem. Due to some ambiguity, the program store.c was unable to place a missing |: into the tune. During the second pass, genmidi.c encounters the :| and does not know where to begin the repeat. This is a real error since the repeat will not occur. This error message is not suppressed. The instructions !trill! and !fermata! are recognized by yaps and abc2midi and are treated in the same way as the decorations T and H preceding a note. To do this I introduced a new integer global array decorator_passback[] which is set by event_handle_instruction in both yapstree.c and store.c. The array is passed between files parseabc.c, store.c and yapstree.c as an extern. 2003 May 18 The symbol y used to denote a space in Barfly, is ignored and no longer causes an error message. It is deleted by abc2abc. 2003 May 19 Added an option to number bars in yaps. Note the bar numbers may not match those in abc2midi or other abc*ps programs. Introduced global flag barnums and global integer nnbars in yapstree.c which is set by event_init and linked to drawtune.c. Added new -k option in event_init in yapstree.c. In event_bar in yapstree.c passed the current bar number instead of NULL in addfeature. In drawtune.c introduced a new function printbarnumber which is called in various places in the function printvoiceline. %%MIDI chordname accepts negative semitone shifts relative to root. In function event_specific in store.c, replaced readnump with readsnump. 2003 May 22 Bar numbering in yaps is now in agreement with abc2midi but may differ by one unit with abc2ps and other members of its family. See abcguide.txt for more discussion. I moved the position of the call to checkbar() in event_bar() (yapstree.c) so it occurs before addfeature is called rather than after. The decoration field line d: (used inabcm2ps) is not parsed as a music line but is an ignored field line. Change was made in parseabc.c in parsefield() and parseline(). 2003 May 31 Yaps crashes when it encounters text preceeded by an underscore in a guitar chord. For example "G" AB/2B/2 "_quiet" DD| g/2g/2d/2d/2 | here yaps crashes when the function event_handle_gchord (in yapstree.c) encounters the text _quiet. The problem was fixed by ensuring that, cv->instruction_pending is not NULL prior to adding anything to this structure. 2003 June 6 Yaps ignores any guitar chords placed in front of a chord if the notes in the chord are not in descending order. For example in the following line |"Gm"[G2B2][Ac]|[Bd][Ac][GB]|"D"[A/2c/2][A/2c/2][Ac][Bd]| the guitar chords Gm and D do not appear because they precede a chords [G2B2] and [A/2c/2]. This problem also applies to any instructions (eg. !quiet!) which immediately precede a chord. The problem has to do with the way the gchord and instructions are processed by yapstree.c. When they are first encountered they are placed in temporary places, cv->gchord_pending and cv->instructions->pending. When the next note is encountered, the function newnote moves them to fields associated with that note. Unfortunately, when printvoiceline in drawtune.c processes the notes in a chord it expects the guitar chord or instructions to be associated with the first note encountered in the chord. (It checks chordcount variable.) This is not always true because the function insertnote in yapstree.c for some reason will reorder the the notes in the chord if they are not in descending order. The fix was to modify noteinsert in yapstree.c so that if it reorders the notes in the chord, it also moves the gchord and instructions fields to be with the first note. 14 June 2003 Yaps produces a segmentation error when it fails to find an expected continuation line and attempts to print a guitar chord.(eg.) X:1 T:example K:C "C" abcd|\ (In this example there is no more records following the backslash.) The error occurs when it tries to execute showtext in the function notetext in the file drawtune.c. The fix was to ensure that the pointer spacing is not NULL prior to calling showtext. 21 June 23 Abc2midi assumes the last %%MIDI gchord string specified as the default for the start of the tune. In the following tune, X: 1 T: gchords M:4/4 L:1/4 K:C "C" CCCC|CCCC| %%MIDI gchord czcz FFFF|FFFF| %%MIDI gchord fzzz GGGG|GGGG| %%MIDI gchord fcfz CCCC|CCCC| the gchord string was not set for the first two bars. It was expected that abc2midi would use the system default for 4/4 time, i.e. fzczfzcz. Instead, the last defined gchord fzfz was assumed, which is not expected. If the user places another %%MIDI gchord string before the first bar or adds a redundant meter field M:4/4 just before the first bar, everything is ok. Abc2midi calls setbeat which calls set_gchords just after it processes the first K: declaration in the field area. When abc2midi writes the first track writetrack(0) containing the melody, everything is still ok, except that the accompaniment is not written at this point. Each time writetrack encounters another %%MIDI gchord declaration, set_gchord changes the gchord string. When it is time to start the accompaniment track, the gchord string was left as the last declared string. The fix was to move the setbeat invocation from headerprocess() in store.c to the beginning of writetrack in genmidi.c when the accompaniment track is identified. I also added a short caveate in abcguide.txt about the setting of MIDI gchord string. 28 June 2003 The %%MIDI transpose command transposes all channels including the drum channel. For the drum channel, the pitch component selects the percussion instrument, so transposition is not appropriate here. The fix was applied to the function save_note in the file genmidi.c. Transposition is blocked if the drum channel 9 (counting from 0) is selected. 29 June 2003 Besides the key signature, the K: field can contain many other descriptors, such as the clef (treble, bass...), the octave and transposition. The code for parsing the K: field parsekey was rather convoluted and hard to understand. It was simplified by breaking it up into several functions. During this process, I discovered an Easter Egg (undocumented feature) in abc2midi. It is possible to transpose an individual voice without affecting the other voices. The documentation to these features was improved in abcguide.txt. 1 July 2003 The single voice transpose function described above does not work correctly in combination with the global transpose initiated by the %%MIDI transpose (or rtranspose) function. The original code in store.c and genmidi.c was confusing since communications between the two files was performed by both the feature/pitch arrays and a global variable global_transpose which was linked to both files using an extern int declaration. Here is a short description on how it was originally. Parsekey passes transpose to event_key. When a new transpose value is obtained from event_key, the TRANSPOSE flag is added to the feature array and the value of transpose is put in the pitch array. In addition the global_transpose variable (a variable linked to genmidi.c) is also set to transpose if event_key obtains the transpose value before getting to the body of the music. When a transpose value is obtained from event_specific (i.e. from a %%MIDI transpose indication) a TRANSPOSE flag is also added to the feature array and the linked variable global_transpose is always set to the transpose value. Genmidi.c processes the TRANSPOSE feature in the function writetrack. At the start of every track, writetrack sets the transpose variable (here not linked with store.c) to global_transpose. When TRANSPOSE feature is encountered the variable transpose is extracted from the pitch array. The transpose value is added to the note pitch whenever a note is issued. The transpose value is also stashed away by save_state in case a REPEAT feature is encountered. In this situation, the stashed value is recovered by restore_state. It would make more sense to treat transpose and global_transpose independently. i.e. new pitch = pitch + transpose + global_transpose. Also it would be be a good idea not to pass global_transpose to genmidi.c using "extern int" but setting it using a new feature GTRANSPOSE in the feature array. Fix: GTRANSPOSE introduced in abc.h. global_transpose variable and associated code eliminated from store.c. In writetrack in store.c, another switch condition for GTRANSPOSE was introduced. global_transpose initialized to 0. transpose initialized to 0 in starttrack. In noteon_data and addtoQ transpose + global_transpose are added to pitch. These changes now allow global_transpose and transpose functions to work together and independently. Basically transposition is now performed by either or both variables 'transpose' and 'global_transpose'. The only difference between these variables is that the transpose variable is reinitialized to zero each time a new track is started, while global_transpose is only initialized at the start of the tune. These variables are set only through the feature/pitch arrays in store.c. 5 July 2003 Abcm2ps allows the voice field to contain additional descriptor information such as the clef name. This information may indicate a voice transposition by one octave. Abc2midi and other abcMIDI programs currently ignore this information. Fix: A new function parsevoice was introduced into parseabc. which contains a combination of the code in both parsefield and parsekey. New parameters were introduced to event_voice in store.c, yapstree.c, toabc.c, parseabc.c and parseabc.h in order to pass this information. In store.c, event_voice will call event_octave if gotoctave is set and insert a TRANSPOSE feature in the feature/pitch array. In toabc.c, event_voice will also output the clef if gotclef is set. In the event that treble+8, treble-8, or tenor-8 is specified, parsevoice will set octave to the appropriate value and set gotoctave so that event_voice in store.c will also issue an event_octave. The transpose indication in the clef is detected in the function isclef() in parseabc.c which now has extra parameters. Please note no transposition is assumed for the bass clef. If it is desired that abc2midi transpose that voice, a octave=-1 or -2, should be included in the K: or V: field. 6 July 2003 Abc2midi considers the placement of a V: indication outside the music body (in the header) as an error and ignores it. Other applications such as abcm2ps permit V: indications to occur music header. In such instances, the voice field specifies information such as the clef to be used for that voice. Several changes were needed to handle the this convention. (1) In event_voice, the check "pastheader" was disabled; however, it is important not to call checkbreak() prior to passing the header. (2) It is necessary to create the first voicecontext structure immediately after the parser is started rather than wait for the first K: field (which ends the header block). Therefore, the code v = newvoice(1); head = v; was moved to event_refno and event_key was replaced getvoicecontext(1); (3) Normally event_octave will transpose all the music voices if it is called in the music header. This needs to be disabled when it is called from event_voice. A new parameter, local (as opposed to global) was introduced into event_voice to indicate such a situation. (It was necessary to also put this change in parseabc.c, yapstree.c, toabc.c, parseabc.h, in addition to store.c) 12 July 2003 Abc2midi loses synchronization between voices when a voice change occurs in the middle of a bar. The following tune does not get converted correctly into a MIDI file. X:1 T: sample M: 2/4 L: 1/8 K:G V:1 |:AG Bc| V:2 |:C2 C2| V:1 AG Bc|[1 V:2 C2 C2|[1 V:1 CDEF:|[2 EFG2| V:2 D2 D2:|[2 G4| The problem occurs when writetrack (in genmidi) is processing the second repeat. When it comes to the bar marked with a [1 it attempt to skip to the bar labeled [2, however, it failed to check for a voice change. (It is unusual to switches voices in the middle of a bar.) Instead it another [1 and outputs numerous error messages. The problem was fixed by checking for a voice change and searching for the continuation of the current active voice using the findvoice function. Yaps terminates prematurely if a tune does not contain a M: indication in the header. Yaps reports that there is no M: field but when it attempts to set it to the default 4/4 in startbody(), no voice structure has been created. To fix this problem lines of code, setvoice(1) and startbody() were interchanged in event_true_key() in yapstree.c 13 July 2003 Yaps bar alignment fails in multivoiced files containing tuples (eg. triplets). For example, X: 1 T: yaps trips on triplets M: 2/4 L: 1/8 K: G V:1 C4|C4|(3BBB (3BBB|C4|C4| V:2 F4|F4|F4|F4|F4| The bars for the second line do line up after the triplets. The function advance() in position.c does not set the notelengths in the case of triplets. As a result, spaceline() in position.c has the incorrect temporal position of the notes when it tries to place the notes on the staff. Fix: a new variable tuplenotes was introduced in the struct note (struct.h). This variable is set in event_note, in yapstree.c and contains the sequence number of the tuple note (descending). In event that advance() detects a tuple note (based on this variable), the temporal length is adjusted by multiplying it by the tuplefactor. (A new function mulfract was introduced for this purpose.). The notes and bars are lined up now, but more work is probably needed to get more pleasing spacing. 19 July 2003 Abc2midi fails to set key signature sharps or flats pattern in multivoiced tunes with voice indications in the header. For example in the following tune, X: 1 T: G minor scale M: 2/4 L: 1/8 V:2 K: Bb V:2 GABc|defg| the notes B and e are not flattened in the output MIDI file. This is a new bug I introduced in July 5, 2003 when I extended the abcMIDI package to handle voice field indications in the header block. For each voice there is a separate voicecontext structure which contains its own basemap for sharpening or flattening selected notes. See store.c code. (This permits the option of a voice to have its own key signature which is different from the other voices.) There is also a global voicecontext structure used for applying the key signature to all voices if they are not indicated separately. The global key signature is copied to the voicecontext of a separate voice at the time that the voicecontext structure is created. Unfortunately, if the voicecontext structure is created prior to setting the overall key signature with the first K: indicator, then the basemap for that voice is set for C major or A minor. Fix: a new flag, keyset was introduced in the voicecontext structure. This flag indicates whether the key signature was known at the time when the voicecontext structure was allocated by newvoice(). Whenever getvoicecontext() switches voices context, it now checks keyset to determine whether it is necessary to copy the basemap and related variables from the global voicecontext structure. I: octave=n has been disabled in abc2midi. Since an octave shift can be indicated in either the K: or V: field, it is no longer necessary to use the info field for setting the octave range. I have disabled this feature to discourage using the info field for setting the octave range. 20 July 2003 The hidden rest (x) was introduced in abcMIDI in April 19 2003. Abc2midi treated it as a regular rest but abc2abc automatically converted it into a regular rest z. The new functionality to transpose separate voices that was introduced in abc2midi now makes abc2abc even more useful. I have upgraded abc2abc so it now preserves the hidden rests in the abc files. Yaps continues to not distinguish the two types of rests (like abc2midi). Fix: introduced an extra variable in event_rest in parseabc.c, store.c, yapstree.c, toabc.c and parseabc.h. In toabc.c event_rest emits an x instead of a z if a hidden rest is detected. 16 August 2003 Abc2midi: The drum accompaniment is started or stopped using the instruction command !drum! and !nodrum!. The !drum! and !nodrum! commands are not part of the abc standard so other applications such as abc2ps and related clones do not understand this instruction. The programs either ignore or it or return a warning. I have introduced an alternate method of starting and stopping the drum track using the MIDI indications. %%MIDI drumon and %%MIDI drumoff This is similar to the method of starting and stopping gchords. (%%MIDI gchordon and %%MIDI gchordoff). I feel this is the preferred method and the older method will probably be deprecated. Fortunately, I am the only one using drum accompaniment (eg. isra.abc) so all of this has little impact. August 22 2003 Midi2abc creates a abc file with a blank title. It is more useful to place the name of the input midi file in the title. Midi2abc puts a blank line in the abc file in the event that a newline character \n is embedded in the meta_text. A blank line signifies the end of a tune, so the remaining part of the abc file is not processed. The function remove_carriage_return was updated so it now checks for both \r and \n. August 31 2003 Reorganized and improved documentation of midi2abc.c Many MIDI files have multiple tempo indications. In fact some MIDI files change the tempo at every beat. Midi2abc assumes the last tempo indication; however, in some MIDI files the tempo slows down at the end. When the resulting abc file is converted back to a MIDI file it plays much slower than the original. I have modified midi2abc so that it now assumes the first tempo indication and ignores all following indications. September 8 2003 Midi2abc identifies drum tracks (channel 10) but it needs to issue a %%MIDI channel 10 to that voice so that abc2midi will know to assign that voice channel 10. Printtrack was modified to test for a drum track. Added two new parameters, -bpl and -bps to control the formatting of the output abc file. These parameters control the number of bars printed per line, and the number of bars to be associated with a music staff. The -obpl (one bar per line) parameter is deprecated. September 13 2003 Midi2abc by default does not use the PPQN information in the MIDI header to determines the note length in MIDI pulses. Furthermore it ignores any time signature information in the MIDI file that may be present. Most MIDI files do contain valid information so midi2abc produces the best output when run time options -xl and -xm are included. Midi2abc was modified to make these run time options the default and the unnecessary flags -xl and -xm are now removed. To allow the user to force midi2abc to estimate xunits (MIDI pulses per standard unit note length) from the note duration statistics, a new option -gu was now introduced. Since this is a major change in how midi2abc runs, the version number was bumped up to 2.6. September 14 2003 Contrary to the documentation, the anacrusis is not specified in beats but in abc half unit lengths where a unit length is given in the L: field in the header. For example if L:1/8 and M: 4/4, an anacrusis of 1 beat is specified as 4 (i.e. four 1/16 units). This is due to the way the quantized music is represented in midi2abc. Midi2abc does not allow notes shorter than than 1/2 an L: unit. Therefore if the unit length is L: 1/8, the shortest note that can be produced by abc2midi is a sixteenth note. Note lengths are stored internally in midi2abc as numerator/denominator where the denominator is always 2. So a sixteenth note is quantized to a numerator value of 1. Therefore midi2abc has difficulty representing very short notes that are encountered in trills or drum rolls. In such situations you should use the -s option for short notes to get an approximation. This also explains why printtrack, findana and guessana want the barsize to be measured in half abc unit lengths (barsize is doubled in the calling sequence for these functions.) I have corrected the readme.txt and the midi2abc.1 man file. September 21 2003 Laura Michaels contributed patches to store.c, genmidi.c and abc.h to handle the Copyright extended information field (see abc2-draft) and to improve the production of Karaoke MIDI files. Laura Michaels also provided makefiles for other compilers such as Ming and Watfor. More details follow. The proposed standard introduces a new field using the syntax %%abc-copyright (c) Copyright John Smith 2003 Abc2midi now inserts this in the MIDI file in the form of a metatext copyright tag. Changes were made to the event_specific function in store.c to process the copyright information. Karaoke file applications such as Winamp, VanBasco;s Karaoke player, and WinKaraoke (on Windows) have difficulty extracting the composer and copyright information fields and confuse them with the Karaoke text. The function karaokestarttrack in genmidi.c was modified to handle additional @T information lines for composer and copyright information after the title line in the first MIDI track. In the Karaoke track (track 3), this information was also added in the form of @I fields. Also other abc information fields such as H: and A: were suppressed in the Karaoke track by setting texton to 0 in printtrack. The 98 character limit for text lines handled by event_field in store.c was changed to 255 (see default case in switch (k)). September 28 2003 For multivoiced abc files there is a need to be able to apply a fermata to a rest. For example, consider this file. X: 1 T: fermata applied to rest M: 2/4 L: 1/8 K: G [V:1] CDEF|GAF!fermata!G|C2 C2| [V:2] EFGA|Bcd!fermata!z|C2 C2| [V:1] CDEF|GAF!fermata!G|C2 C2| [V:2] EFGA|Bcd!fermata!G|C2 C2| If the fermata is not applied to the rest, there is a loss of synchronization between the two voices. The function event_rest was modified to get the array decorators from one of its passed parameters. In store.c event_rest would double the length of the rest (including hidden rests) if decorators[FERMATA] is set. In parseabc.c it was necessary to to update the decorators array for the case 'z' and 'x', prior to passing it to event_rest. Changes were also required in yapstree.c and toabc.c even though event_rest does not use the decorators array in these files. The declarations for event_rest in parseabc.h also needed to be changed. September 29 2003 A new problem with setbeat (store.c) was discovered. For the file X:1 T: time sig M: 2/4 L: 1/8 K: G "C" G2 G2| G2 G2| [M:3/4] G2 G2 G2|G2 G2 G2| The gchord output was not correct for the first two bars. This was caused by several problems in the code. (1) Setbeat calls set_gchord to set the gchord_seq, gchord_len, g_num, and g_denom used by dogchords. The values for g_num and g_denom were incorrect because they were computed from mtime_num and mtime_denom which were set by set_meter. The values of mtime_num and mtime_denom were the last values in the previous tracks processed so if there was a change of meter in the tune they would not reflect the initial value. (2) Setbeat chooses the appropriate gchord string on the basis of the time signature stored in the time_num and time_denom array. It is therefore necessary that these values remain current to the current context during the writetrack pass. Therefore set_meter was modified to update time_num and time_denom whenever it is called. Set_meter is called in several places. It was called in starttrack with the global parameters time_num and time_denom. Unfortunately these parameters are affected by the event_timesig which is called during the parsing stage. Therefore their values reflect the last time signature encountered during the parsing stage. It is necessary to cache the initial settings of the time signature set in the header block. New variables header_time_num and header_time_denom are defined in store.c and passed to genmidi.c as externals. In writetrack, for the accompaniment track it was necessary to call set_meter() with the header time signatures just prior to setbeat(). Set_meter is also called by write_meter in genmidi.c. Write_meter is called whenever a TIME feature (for time signature) is encountered. Fortunately, the correct time signature stored in the num[] and denom[] arrays are used. Setbeat is called shortly after in printtrack. October 13 2003 Though most MIDI files indicate a time signature few also indicate a key signature. Though midi2abc reports any key signature it finds in the MIDI file, it does not use it but insists on determining it by scanning all notes and choosing the key signature that minimizes the number of accidentals. This works fine if there are no key changes in the music. If the MIDI file does indeed indicate key signatures and key changes then midi2abc should use this information in creating the abc file. In a similar vein, for some MIDI files there may be more than one meter change. Midi2abc uses the first time signature that is indicated in the MIDI file. If it encounters other time signature indications later, it reports it but it still uses the initial time signature to transcribe the file. Again it would be desirable if midi2abc would act on this information. Looking at midi2abc.c, it was noticed that the function findkey() is always invoked except when the key signature is passed in one of the run time parameters. If a key signature or time signature metatext command is encountered, a time stamped text message is added to the tlistx structure associated with that track. These text messages are sent to the abc file at the appropriate time using the handletext function which is invoked by printtrack; however, no adjustment is made for any key or meter change. Further the barsize is assumed to be fixed. The barsize is a local variable in the main program and it is passed to printtrack as one of its parameters. The barsize controls the placement of bar lines in the output abc file. Numerous changes were needed to fix these problems. (1) A new global flag, gotkeysig was introduced to the code. It is initialized to zero but set to 1 whenever a key signature metatext command is encountered. (2) A new variable 'type' was added to the tlistx structure. If tlistx.text contains the key signature, tlistx.type is set to 1. If tlistx.text contains the time signature, tlistx.type is set to 2. For everything else, tlistx.type is set to 0. (3) The 'type' variable was added to the addtext() function and in the many places where it was invoked. (4) In the function txt_keysig(), the verbose message sent to the tlistx structure was replaced with just the sf and mi (number of sharps/flats and major/minor flag). (5) In the function txt_timesig(), The verbose message was replaced with just the key signature nn/denom. (6) Major additions were made to the function handletext() which now does more than just print text at the appropriate place. If the text string is a key signature or time signature as indicated by the type variable, then the key signature or time signature parameters are extracted. If it is a key signature, setupkey(sf) is called which does all the work of printing the K: field and setting up the tables for suppressing the accidentals. If it is a time signature, a M: %d/%d %d command is printed (time signature and pulses per quarter note). (7) The barsize variable was turned into a global variable like asig and bsig. (8) The function txt_timesig() was broken into two functions, txt_timesig and setup_timesig(). The new function setup_timesig() updates the global variables, asig, bsig and barsize. If unitlen was never set, it is also set as well as xunit. Because the notes are quantized in a separate pass, we must use a fixed xunit and unitlen for the entire file. Setup_timesig() is also called during the printtrack pass whenever handletext() detects a meter change. (9) Printtrack uses the barnotes counter to decide when to place a bar line. It is set to barsize at the beginning of each bar and it is decremented by each note. When it reaches zero a new bar line is issued. (It is done this way in order to handle anacrusis.) If barsize changes after the start of the bar it is necessary to correct barnotes. Printtrack keeps track of the previous barsize (last_barsize) and uses that to fix barnotes. (10) Added a new option -gk to force midi2abc to guess the key signature by minimizing accidentals even though the key signature is already indicated in the MIDI file. Normally it will automatically guess the key signature if no key signature is found in the file and the key signature is not specified with the -k parameter. Unfortunately, this was not all the needed changes. For multitrack MIDI files it is customary to reserve the first track for handling global operations such as tempo, key, meter changes, and text messages. The remaining tracks contain the actual music. In the case of multivoiced abc files, it is necessary to apply the meter change or key change to each voice. Therefore for each voice, midi2abc needs to also check the tlistx structure in track zero for any such changes. Another handletext() call was added to to printtrack to handle this situation. Abc2midi does not follow this convention exactly. For single voice abc files with possible bass/chord or drum accompaniment and possible Karaoke, it uses several tracks but it does not reserve track 0 for this special purpose. For multi voice abc files, abc2midi does use track 0 for this special purpose and places text and metatext commands grabbed from track one; however, because the delta times from the missing notes were not accounted for, the delta times for the time signature and key signatures are not correct. (They are all zero.) Fortunately, each track also has any key or time signature metatext commands with the correct delta times (assuming the abc file was notated correctly), so that information in track zero is not needed. The simplest fix was to suppress output of these meta commands in track 0. In writetrack (genmidi.c) a new flag 'timekey' was introduced to suppress MIDI commands for key/meter changes in track 0. The function setupkey does not work correctly after the first call to this function. After that, the accidentals are put in the wrong place. It was noticed that the array key[] is initialized to zero in the function findkey() instead of setupkey where it is actually used. Findkey() is normally only called once if it is called. The initialization code was moved to setupkey. October 25 2003 When the MIDI file has more than one key signature or time signature, the first key signature or time signature displayed in the header block reflects the last signature that was encountered in the MIDI file rather than the initial initial signature. This is corrected later on, however the abc file looks strange. To fix this problem new variables, header_asig, header_bsig, header_unitlen, header_keysig and header_bb were introduced. When parsing the MIDI file, they are set to the first time signature or key signature encountered. They are printed in the header block. For multitrack MIDI files, midi2abc prints out all the textual information for track 0 immediately following the end of the header block (first K: indication). This unfortunately may include a whole list of key signature or time signature meta text commands resulting in a correct but rather confusing abc file. To avoid this situation a new variable, trackno, was added to the function handletext. The function handletext now suppresses the K:, M:, and L: indications for track zero when the MIDI file has more than one track. October 26 2003 There are still circumstances where a redundant key signature or time signature is printed in the abc file. To avoid these situations new variables, active_asig, active_bsig and active_keysig were introduced. They are set to the current status. Before printing a new signature, the present status is checked and only changes are printed. November 9 2003 Midi2abc frequently fails to detect triplets in the MIDI file; even when it has been notated correctly using a music notation program. Therefore sets of triplets may be converted into D3/2D-[D/2-D/2]D A3/2B-[B/2C/2-]C| instead of (3D2D2D2 (3A2B2C2| which is another annoyance. Midi2abc.c has a special function called dospecial which attempts to detect broken notes (eg. C > D) and triplets; however, it does not seem to work consistently. The problem is that all notes are quantized to units of 1/32 or 1/16 notes, (depending on the meter). The length of a triplet note is 1/12 or 1/24 which does not get quantized exactly. Thus the representation of this sequence (calling scannotes in the debugger) appears as follows. Pitch 62 chan 0 vel 127 time 160 xnum 3 playnum 3 Pitch 62 chan 0 vel 90 time 160 xnum 2 playnum 3 Pitch 62 chan 0 vel 90 time 160 xnum 3 playnum 3 Pitch 69 chan 0 vel 90 time 160 xnum 3 playnum 3 Pitch 71 chan 0 vel 90 time 160 xnum 2 playnum 3 Pitch 60 chan 0 vel 90 time 160 xnum 3 playnum 3 time is in units of midi pulses, xnum and playnum are in quantized half units where xunit = 120 midi pulses. The time and xnum are the inter-onset time of the note (length between onset of this note and the next note). Playnum is the quantized duration of the note (from midi on to midi off). All of these variables are computed by the function quantize() in midi2abc. Note that 160 is not divided even by the half unit = 60. Playnum is rounded up but xnum compensates for the fact that it may have been too long in the previous note. The code in the function dospecial is far from transparent. It looks ahead one or two notes to determine whether this note and the following notes should be treated differently (either as broken or triplets) and uses the return character or featurecount array to signal to printtrack how to handle these notes. One of the tests in dospecial is the line just before the broken rhythm tests is (reformatted for clarity) if ((v2 < pnum) || (v2 > 1 + pnum) || (pnum == 0) || (v1+v2 > *barnotes )) { return(' '); where v1,v2 refer to the xnum values of this note and the next note and playnum is the playnum value of the next note. v2 happened to be less than pnum due to the adjustment discussed above, so the program returns from this function without testing for broken notes or triplets. I commented out /* (v2 default_length is placed in num, denom storage. CHORDOFFEX is a new feature type added to abc.h for handling this situation. Genmidi.c treats CHORDOFF and CHORDOFFEX the same way. A new function fix_enclosed_note_lengths was introduced to readjust the note lengths of all the notes in the chord in the event that it is set outside the enclosing brackets (i.e. CHORDOFFEX). The function tiefix now keeps track of the chord start ([) in the variable chord_start. When it encounters a CHORDOFFEX, it calls fix_enclosed_note_lengths. November 07 2004: -chord extension continued yaps: Unlike abc2midi, yaps only performs one pass through the abc file while preparing a very detailed layout of the music in a complex data tune data structure. You can view part of this structure by running yaps with the -d parameter. This data structure is passed to printtune() in drawtune.c. A new function fix_enclosed_note_lengths was created in the file yapstree.c to adjust the note durations. This function is called by event_chordoff when the parser encounters the end of a chord (']'). The new function does nothing if ] is not followed by a note length. Otherwise it corrects cv->barcount in order to avoid warnings regarding the number of beats in the bar. It replaces the note duration of each note in the chord with the new note duration. The function count_dots is called to replace the note duration representation. (There still seems to be a problem here.) abc2abc: Minimal changes in toabc.c were made. The function event_chordoff was modified to output the note length information following the chord if any and to correct the bar count. November 20 2004 The fix for handling chord extensions in yaps did not work properly and would frequently place tails on notes which should not have tails. It was discovered that chords have their own structure for indicating their PostScript representation and their tail is drawn by a function called drawchordtail. The yapstree.c function event_chordoff was modified to also update the chord structure when the chord extension occurs. Introduced a new folder called programming in the doc subdirectory and moved abc2midi.txt, midi2abc.txt and coding.txt into this folder. The folder contains some program implementation details. The file yaps.txt was renamed to yapshelp.txt. A new file yaps.txt describing the implementation of yaps was prepared. November 28 2004 Abc2midi new feature: all notes in a chord are started at the same instant. Inserting a short delay between the start of the notes in the chord would provide more control over the timbre. However to ensure that the music is not lengthened, it is necessary to ensure that all the notes end at the same time. Implementation of this feature was not easy due to the way the notes are handled are converted to MIDI commands in genmidi.c and the complexity of the queues.c code. MIDI note on commands are sent by a long chain of function calls starting with the function call to noteon(). Noteon() determines the velocity of the note from the beatstring and current context and then calls noteon_data(). Noteon_data() calls midi_noteon() and updates the tracklen. Midi_noteon() calls mf_write_midi_event which finally records the MIDI command. The MIDI command to stop playing the note is sent to a queue by the function addtoQ which is defined in the queue.c file. Finally if this note is not inside a chord, or if a end of chord feature has been encountered, the notes in the queue all processed by calling the function delay(). Delay() converts the note duration in MIDI tick units and calls the function timestep() which is defined in queues.c. The global variable delta_time indicates the time delay in MIDI tick units to execute the MIDI command. All MIDI command specify times relative to the time of the last command. Functions in genmidi.c generally reset delta_time to zero after sending a MIDI command. Otherwise, delta_time is adjusted by timestep() in queues.c. In order to control the delay intervals between notes in a chord, new global variables notecount, notedelay and totalnotedelay were introduced into genmidi.c. If notecount is greater than 1, delta_time is changed to notedelay and totalnotedelay is incremented by this amount. It is necessary to shorten the shifted notes by totalnotedelay so that they end at the same time. The new length is passed to addtoQ in queues.c. At the end of the chord, notecount and totalnotedelay are reset to zero. December 4 2004: (Continued from November 28 2004.) Unfortunately addtoQ does not know that the shortened notes have been shifted. When correcting the delay of the cached note in the structure, addtoQ now takes into account that the new note was shifted with respect to the previous note by notedelay which is also passed as a global variable. Finally, it was also necessary to adjust delta_time in timestep() by totalnotedelay. More comments were added to the code addtoQ and timestep in queues.c. The notedelay variable is set to 10 MIDI units as a default. (There are 480 MIDI units in one quarter note beat.) A new MIDI command %%MIDI chordattack n, was introduced in dodeferred() (genmidi.c) to allow the user to fine tune this variable. I do not recommend making this variable larger than the smallest note in the tune, (eg. 30 units if there are 1/16 note chords.) The abcguide.txt and abc2midi.1 documentation was updated. Thanks go to Hudson Lacerda for suggesting this improvement. Midi2abc outputs MIDI metatext commands as abc comments. In some cases they can be interpreted as pseudo comments causing undesirable actions by other software. For example, in the following the title MIDI program 17 is converted to metatext in the MIDI file. When midi2abc converts the MIDI file back to an abc file the text can be interpreted as a %%MIDI command. X:1 T:MIDI program 17 C:Hudson Lacerda M:12/8 L:1/8 Q:1/4=120 K:C %MIDI C,^C,D,^D,E,F,^F,G,^G,A,^A,B, | C^CD^DEF^FG^GA^AB | c^cd^def^fg^ga^ab | c'^c'd'^d'e'f'^f'g'^g'a'^a'b' | -- output from midi2abc -- X: 1 T: from (null) M: 12/8 L: 1/8 Q:1/4=120 K:C % 0 sharps %%MIDI program 17 %%MIDI C,^C,D, ^D,E,F, ^F,G,^G, A,^A,B,| \ =C^C=D ^DE=F ^F=G^G =A^AB| \ =c^c=d ^de=f ^f=g^g =a^ab| \ =c'^c'=d' ^d'e'=f' ^f'=g'^g' =a'^a'b'| As suggested by Hudson Lacerda, the fix is to add a space before the metatext. The sprintf statement near the end of the function txt_metatxt() was modified. Midi2abc should place the input file name in the title line instead of null. This has been changed. December 09 2004 Abc2midi new feature: introduced %%MIDI randomchordattack n. The delay between notes in a chord will vary randomly between 0 and n-1 MIDI units. It is recommended that n is not longer than the shortest chord. (If the shortest chord consisting of two notes is a 1/16 note then n should be not greater than 480/4 = 120. If there are three notes in the chord n should be less than 480/8 since the delays add up.) December 12 2004 - also see June 13 2005 New feature: chord extension applied to tied chords. In order for abc2midi to handle the syntax [CEG]3-[CEG]2 or something similar, it was necessary to make more changes in the code store.c. The code dotie() was not easy to figure out. To avoid working with this code, abc2midi patches up the feature,num,denom arrays so that it appears the same as if the old syntax [C3-E3-G3-][C2E2G2] was used instead. New functions, insertfeature() and removefeature() were written to insert or remove a feature in the middle of the arrays. The dotie() function was modified to also detect the CHORDOFFEX feature and treat it the same way as a CHORDOFF. The function fix_enclosed_note_lengths was modified to also catch the TNOTE feature and treat as a NOTE feature. A new function patchup_chordtie was introduced. The function stuffs a TIE feature after each note in the chord and returns the position of the first TIE. Many changes were made to the tiefix function(). Another local variable, chord_end was added. Chord_start and chord_end keep track of the feature index positions of the last chord scanned. If a TIE feature is immediately preceeded by a CHORDOFF or CHORDOFFEX feature, then that tie is stripped off and new ties are stuffed into the chord using the function patch_chordtie. Tiefix then backups into this chord so it can run dotie on all the internal ties. December 17 2004 Finished debugging chord tie feature. Tiefix no longer runs fix_enclosed_note_length when it backs up into the chord. Abc2midi: Limin Wang discovered and D.J. Bernstein reported two unprotected buffer overflows in store.c. This allows an attacker to gain control of the computer through a malicious abc file in an email message or from a web page that is fed into abc2midi. This applies to all versions of abc2midi. The buffers are now protected. Yaps, midi2abc: minor changes to reduce likelihood of buffer overflow. December 18 2004 Abc2midi new feature: Abc2midi recognizes the !f!, !pp!, etc indications and adjusts the audio level in the output MIDI file accordingly. Unfortunately this may get in the way for multivoiced abc files where the indications are placed in one voice but not the others. When the file is typeset by abcm2ps the output looks fine, but one of the voices is inaudible in the MIDI file. An example, is shown below. X: 1 T:ff_pp_1_1 C:ff_pp_1_1: the second voice is covered by the first one C:but the score could be interpreted as they both have to C:be played with the same intensity M:4/4 L:1/4 Q:1/4=100 %%MIDI transpose -12 %%staves (1 2) V: 1 clef=treble V: 2 clef=treble %V: 3 clef=treble % K:C %%measurenb 0 % [V: 1] G A c e | e c A G | A G A G | [V: 2] !ppp!C E E E | G E E E | F E D C | Things get more complicated when 2 or 3 voices share one stave (eg. classical guitar notation). It is not desirable to have to many "p"s printed over and under the stave. Abc2midi does not understand !crescendo! and !diminuendo! notation. A simple but not a perfect solution, is to introduce a new option in abc2midi which will tell abc2midi to ignore all dynamic indications. Fix: thanks to Michele for the code and suggestion. A new option -NFNP (no f no p) was introduced in store.c. Abcguide.txt and abcmidi.1 documentation was also updated. Abc2midi: Wrong tempo when L: missing in a multivoiced file. Abc2midi should assume a L:1/8 when the meter is 3/4 or larger and L:1/16 otherwise in the event that the default length of a note is not specified.. This works correctly for most abc files but fails in the following example. (The tune is played at the wrong tempo.) X: 1 T: no L M: 3/4 L: 1/8 Q: 80 V:1 clef=treble V:2 clef=treble K: G V: 1 abcdf2|gabcG2| V: 2 ABCDF2|ABCDF2| Analysis: abc2midi checks for missing L: in the function headerprocess() when it reaches the start of the tune body (the first K: field). If the note length, global.default_length, was not set at this point then it is set to 8 or 16. When a new voice is created by event_voice, it assumes a note length specified by global.default_length. In the above example, an event_voice is called prior to the start of the body so global.default_length is still undefined. The default_length for the voice remains undefined and abc2midi runs unpredictably. Fix: headerprocess now sets default_length to global.default_length for any voices that have already been created. January 1 2005 Abcmidi: does not handle a tie broken by a voice switch. In the following example, X:1 T: tie M: 2/4 L: 1/4 K: G V:1 AB-| V:2 cd| V:1 Bc| V:2 G2| the tie joining B is interrupted by a voice change. Abc2midi fails to join the notes. Fix: the functions tiefix and dotie now check for a voice change and do not attempt to tie notes belonging to different voices. Abcmidi: abcmidi fails to assign the channel to correct program (musical instrument) for the first note in a multivoiced abc file. In the following example: X:1 T: MIDI program M: 2/4 L: 1/4 V: S clef=treble name="Soprano" V: A clef=treble name="Alto" %%MIDI program 1 60 %%MIDI program 2 60 K: G V: S G A|B C|G A|F G| V: A z2|G A|F G|G A| The first note G is played on the piano instead of the French Horn as indicated by the command %%MIDI program 1 60 Analysis: the MIDI indications are inserted into the track number associated with the voice. In this example, voice A is mapped into track 2 and all the program indications are put into track 2. The midi player processes the tracks sequentially and does not see the program change in time to affect the first note in voice S so it is played on the default instrument, acoustic grand (piano). The simplest fix is to ensure all the MIDI indications go into the first voice as shown here. X:1 T: MIDI program M: 2/4 L: 1/4 V: S clef=treble name="Soprano" V: A clef=treble name="Alto" V: S %%MIDI program 1 60 %%MIDI program 2 60 K: G V: S G A|B C|G A|F G| V: A z2|G A|F G|G A| Alternatively you can place the %%MIDI program indication in the voice that it affects. (The channel number is no longer needed then.) See below. X:1 T: MIDI program M: 2/4 L: 1/4 V: S clef=treble name="Soprano" V: A clef=treble name="Alto" V: S K: G V: S %%MIDI program 60 G A|B C|G A|F G| V: A %%MIDI program 60 z2|G A|F G|G A| I shall update abcguide.txt regarding this issue. January 8 2005 Another exploitable error in store.c was found by Anselm Lingnau which causes a buffer overflow for %%abc-copyright. A fix using the snprintf routine was suggested. The snprintf routine is a recent addition to the C compiler; for those running older compilers you will need to download a portable GPL implementation of snprintf() from http://www.ijs.si/software/snprintf in order to compile and link abc2midi. (In case the web site changes, search for snprintf portable implementation.) If you are running an old or nonstandard operating system for which there is little likelihood of a buffer overflow exploit taking over your computer and it is too cumbersome to include snprintf, then you can define NO_SNPRINTF (in store.c) and it will use sprintf. Michele has added an additional correction to the broken tie fix I made on January 1 2004. In order to handle the following example which includes a chord in voice 2. X:1 T: tie M: 2/4 L: 1/4 K: G % V:1 AB-| V:2 [dA]c| V:1 Bc| V:2 GG| it is necessary to add if(localvoiceno != voiceno) break; after case CHORDOFFEX: in the function dotie. January 9 2005 Abc2midi: new decorations !arpeggio! and !breath! are introduced. When the !arpeggio! instruction precedes a chord, the notedelay time is temporarily set to three times its normal value. For the time being, the !breath! instruction is treated exactly the same as a staccato marking. (i.e. the length of the note is halved and followed by a rest of the same value.) Implementation: a new decoration BREATH was added and a new feature ARPEGGIO was added in abc.h. In store.c, additional code was added to event_handle_instruction to handle the !arpeggio! and !breath! commands. In event_note, both STACCATO and BREATH decorator flags are checked and treated the same way. New global variables staticnotedelay and staticchordattack were added and linked to notedelay and chordattack in several places. In writetrack, genmidi.c, a separate case statement in the main switch statement was introduced for ARPEGGIO. It changes the values of notedelay and noteattack to 3 times its nominal value. (They are restored back to their nominal values after a CHORDOFF or CHORDOFFEX feature.) Jan 22 2005 Abc2midi: a missing break statement caused abc2midi to crash when encountering !arpeggio!. Added a tune demonstrating the !arpeggio! instruction to demo.abc. Midi2abc: normally midi2abc groups the notes forming a beat together so that abc*2ps produces a pretty output. For some raw abc output, (eg.) B3/2z4^dz/2e3/2z3/2| it is easier to edit it if there is a space between every note (eg.) B3/2 z4 ^d z/2 e3/2 z3/2| A new option -nogr has been added to midi2abc. If it is included as one of the run time options, then a space is inserted between all notes that are not in triplets. Changes were made to printchord and printtrack in midi2abc.c. (Search for nogr to see changes.) February 03 2005 Abc2abc: introduced a new run time parameter -usekey. This is a generalization of the -nokeys -nokeyf transformation which converts the music representation to the key of C inserting any accidentals to preserve the original key signature. Now you can force abc2abc to represent the music in any key signature. The -usekey parameter is followed by a number specifying the number of sharps (positive number) or number of flats (negative number) in the desired key signature. Implementation in toabc.c: if usekey parameter is set to a nonzero value, the nokey parameter is set so that event_note2 is used to process the note. Setup_sharp_flats adjusts the arrays flatsym and sharpsym to match the desired key signature. The function printpitch prints the notes using these two arrays. February 04 2005 Abc2midi: It has been proposed that a new option be introduced that would propogate dynamic indications (pp, ff, etc) from voice 1 to all other voices so that they need only be declared once in voice 1. This would provide another solution to the problem discussed in December 18 2004 resulting in the introduction of the -NFNP option. Introduction of this feature is deferred for the time being but here is a description of what is involved in implementing such a feature. When parseabc.c sees an instuction eg. !ff!, it calls event_instruction (in parser2.c) which calls split_string which calls event_handle_instruction (in store.c). Event_handle_instruction interprets the instruction and calls event_specific with a MIDI beat x x x x command. Event_specific passes the string to textfeature which adds an entry DYNAMIC to the feature array and a pointer to the string in the pitch array. Note the feature array is used to handle all the voices, and the list of voice features are separated by VOICE entries. The problem is that it is impossible to propogate the DYNAMIC instructions to the other voices because the other voices may not exist (in the case the voices are specified serially in the abc file). The function writetrack in genmidi.c separates the specific voice from the feature array and creates a separate MIDI track for each voice. To address this problem, we would leave the code in store.c and parseabc.c however we would need to change writetrack in genmidi. Writetrack would now have to keep track of the beat number when processing a voice. When a DYNAMIC feature is encountered in voice 1, the beat number where this has occurred would be stored in an array, along with a pointer to the dynamic indication string. For all other voices, the DYNAMIC feature would be ignored but instead the beat number would be compared with the beat number where the dynamic indication occurred and dodeferred would be called when the beat number equals or exceeds the numbers cached away for voice 1. Worked on this project is deferred for the present time. February 05 2005 Abc2midi tie bug: For the file X:1 T: tie bug M: 2/4 L: 1/8 K: G [FA]-[FA] FA| abc2midi fails to tie the F# note. Fix: replaced the line 737 (in removefeature) in store.c pitchline[i] = pitch[i+1]; with pitchline[i] = pitchline[i+1]; February 12 2005 (also see June 13 2005) Michele reports the following bug in the function dotie in store.c. For the following tune, % X: 1 T: Tie bug M:C L:1/4 K:D [V: 1] | f/e/g/f/-f2 | [V: 2] | d3/2 d/-d2 | abc2midi returns the message Error in line 7 : Could not find note to be tied. The message is wrong, since abc2midi handles both ties correctly. Michele added the conditional break statements if(localvoiceno != voiceno) break; after case TIE: and after case CHORDON: which seems to fix the problem. Analysis: The function dotie is a real birds nest of code. Here is a description of how it works. Dotie is called by tiefix when a TIE feature is encountered. It has two parameters, j the index in the feature array where TIE was encountered and xinchord, a flag indicating whether the TIE is enclosed in a chord (eg [A-B] A). The reason for the complexity of the code is because the function dotie is controlled by three semaphores tietodo, done, and tied_denom. To start, dotie searches backwards for the note preceding the tie, and calls its address (in the feature space) tienote. It changes feature[tienote] from NOTE to TNOTE. It changes feature[j] from TIE to REST and sets the rest length to that of tienote (so they are both the same). Finally it sets the semaphores done = 0; tied_num = num[tienote]; tietodo = 1; which controls the stopping conditions of the following while loop that searches for the following note to be tied to tienote. Now the fun begins. To simplify things assume we do not have chords. The loop begins with the variable place set to j, the original position of the TIE now converted to a rest. So the first feature in the loop is guaranteed to be a REST. case REST: subtracts the length of the rest from tied_num so it is back to zero. Now the semaphores are done = 0; tietodo = 1; tied_num = 0; The loop variable place is incremented and now feature[place] probably points to a NOTE. Case NOTE: since tietodo is not zero the function compares the pitches (pitchline) of place and tienote. If they are equal, the tienote length is increased by the place note, the tied_num semaphore is also increased by the place note. Feature[place] is changed from a NOTE to a REST and to make things more confusing, if we are not in a chord the length of tied_num is now decremented by the place note so that it is back to zero. Finally the tietodo variable is also set to zero indicating that we have finally joined the two notes in the tie. The semaphores are now: done = 0; tietodo = 0; tied_num = 0; Unfortunately the while loop does not stop here and this is the reason for the spurious error message described above. In order for the while loop to stop, the variable done must be set to a nonzero value. This usually happens when the next NOTE or REST is found. In the above example, the next note is found in a different voice. The remedy is probably to end the while loop when tietodo is zero. However, since the code is working fine now I am rather reluctant to try it in case another bug surfaces. Feb 13 2005 Abcmidi /abcm2ps incompatibility problem for decorations applied to chords. It is perfectly normal to apply a fermata or a staccatto to a chord, eg H[C2E2G2] or .[CEG]; in fact abcm2ps prefers that you do it this way rather than [.C.E.G]. Abc2midi handles both notations correctly but it sends the following warning message if you use the former convention. Warning in line 6 : decorations applied to chord Nevertheless, abc2midi sends the chord decoration to each note in the chord and everything works fine provided you don't attempt to apply roll, trill or ornamentation to a chord. In the later case you receive an error message and the decoration is not applied. It is therefore preferable that parseabc does not produce this warning when abc2midi is running. Fix: it is convenient if parseabc.c knows which program is running (i.e. abc2midi, abc2abc or yaps). A new typedef programname which distinguishes ABC2MIDI, YAPS, and ABC2MIDI was added to abc.h. A programname variable called "program" was added as a global variable to store.c, yapstree.c and toabc.c and set to proper value. The program variable is linked to parseabc.c as an extern global. This variable is used to fine tune parseabc.c. Unfortunately not everything is well with yaps and abc2abc. Like abc2midi, the chord decoration is applied to every note in the chord. In the case of yaps, this does not produce an aesthetically pleasing result. Since yaps is not the preferred postscript converter and I am also not very knowledgeable of its internals, yaps shall remain as it is and the warnings serve a useful purpose. In the case of abc2abc, it is not desirable that it automatically converts H[A2C2E2] to [HA2HC2HE2] or something similar. A few more changes are necessary. It was necessary to introduce a new parameter (chorddecorators) into the function event_chordon. This entailed making changes to parseabc.h, parseabc.c, store.c, yapstree.c and toabc.c. In store.c and yapstree.c the new parameter is not used; however, in toabc.c extra code was added to event_chordon to print out any decorations applied to the chord. In parseabc.c the decorators were not inherited from the chorddecorators when parseabc.c was linked to toabc.c. Unfortunately event_chordon is also called by the function event_chord which handles the obsolete form of chords +CEG+. For store.c, yapstree.c and toabc.c, I introduced a global array dummydecorators[DECSIZE] which is initialized to zero's in event_init. This array is used in event_chord. February 14 2005 Abc2abc prints garbage in the V: field (reported by Hudson Lacerda). Given a normal file : X:1 T: abc2abc V: bug M: 4/4 L: 1/8 K: C V: 1 CDE FGABC| def gab c'2| V: 2 C8|C8| abc2abc outputs X: 1 T:abc2abc V: bug M:4/4 L:1/8 K:C V:1 name=(LI CDE FGABC| def gab c'2| V:2 name=(LI C8|C8| Analysis: the local variable gotname in the function parsevoice in parseabc is never initialized to zero. The problem was fixed by adding gotname = 0; February 21 2005 Microtone note capability has been introduced into abc2midi. A _/ means lower the pitch of the following note by a half a semitone. A ^/ means raise the pitch of the following note by a half a semitone. The microtone notation does not propogate across a measure but applies to only the immediate note. For chords in the same channel (voice), the microtone will apply to both notes no matter how it has been notated. For example [C_/E] is the same as [_/C_/E]. Following the convention in abcm2ps, (see features.txt in abcm2ps distribution), _3/4C will depress C by 3/4 of a semitone. It is assumed that the pitch range of the MIDI synthesizer pitch wheel is + or - two semitones in compliance with the General MIDI specifications. The maximum permissible pitchbend is therefore 2 semitones. Implementation: added a new function ismicrotone() called by parsenote() in parseabc.c. I also introduced functions event_microtone() and event_normal_tone() in store.c, yapstree.c and toabc.c. There has been no change to the operation of yaps or abc2abc. February 26 2005 Finished microtone implementation and added microtone documentation in abcguide.txt. March 12 2005 Abc2midi: There is a loss of synchrony in multivoiced files when a fermata is applied to notes of unequal lengths. For example: X:1 T: Fermata M:2/4 L:1/4 K: G V:1 cdef|B2 Hc2|gabc| V:2 efga|DHe3|gabc| the fermata is applied to c2 and e3 for voices 1 and 2. The fermata doubles the length of the notes c2 and e3 and there is a loss of synchrony between the voices in the next bar. Solution: I introduced new MIDI commands which control how the fermata is applied. %%MIDI fermatafixed The fermata adds a unit lengths to the note so HC2 is played C3. %%MIDI fermataproportional (default) the unit length is doubled so HC2 is played C4. Implementation: added new global flag fermata_fixed and modified event_specific to set this flag. Modified FERMATA treatment in event_note and event_rest. March 18 2005 Microtones in abc2midi. It is not clear whether the microtone notation should be treated as an accidental or a decoration. The abc2midi software treats it as a decoration. Thus in the following: X:1 T:micro Q:60 K:C =C ^/C ^C _/D D _/D ^C ^/C =C the second to last note ^/C is played as ^^/C since the accidental in the previous note propogates across the measure. If you want =^/C you must specify it in this manner. If ^/ and _/ satisfy the rules of accidentals then, they would be interpreted the same way as double sharps and double flats. Thus if you wrote ^^F E ^F G: the first note would be played as G and the third note would be played as F#. (You would not write ^^F E ^=F G.) It is not clear from the abc standard, the meaning of the following: [K: G] ^/F D E G| Is the first note a F natural raised a quarter tone, or is it a F# (as indicated by the key signature) raised by a quarter tone? Presently abc2midi treats it as the latter. To treat the notation as accidentals would mean that the quarter tones would propogate across a measure like sharps and flats. This would require introducing more code into abc2midi. (Further there would be other issues relating to transposition in abc2abc.) March 19 2005 abc2midi optional guitar chord syntax. The function event_handle_gchord in store.c was modified to ignore the parentheses in the guitar chord. (eg. "(C)" CDEF etc. ) The optional guitar chord is played. March 25 2005 abc2midi: note tied to two notes. In the following sample the tied note is not played correctly in the repeat. X:1 T: note tied to two notes M: 2/4 L: 1/8 K:G %%MIDI program 73 |:G2D2|ABCD-|[1 D4 :|[2 D2 G2| Unfortunately this is a difficult problem to fix. Store.c creates a feature/pitch/num/denom arrays which tells writetrack in genmidi.c how to create the MIDI file. Repeat actions are encoded into the feature array using the instructions BAR_REP, REP_BAR, PLAY_ON_REP, etc, which instruct writetrack to backtrack in the feature array and repeat certain sections. In other words the repeats are not expanded until writetrack creates the MIDI track. Tied notes are handled by the function dotie in store.c that determines which notes are tied and combines the tied notes into one note instruction in the feature array. In the above example, the tied note D-D4 in the first repeat and D-D2 in the second repeat have different durations. Dotie can only assign the D tied note one duration so it will be wrong in one of the repeats. To make things worse the code in dotie is unmanageable (see comments February 12 2005). To fix the problem the joining of ties, it would need to be done at the time that the repeats are expanded in writetrack rather than in a separate pass performed by dotie in store.c. The handling of ties is messy because they can also be embedded in chords; they cross barlines introducing problems with accidentals in music notation; interleaving of voices breaks up ties; we want abc2midi to gracefully handle tie syntax errors provide useful error message. Multiple repeats (eg |...|[1...|[2,3...|[4... :|) introduce another headache. One way of avoiding this problem is to notate the above sample differently as shown below. X:1 T: better way of handling tied notes in repeats M: 2/4 L: 1/8 K:G %%MIDI program 73 |:G2D2|[1 ABCD-| D4 :|[2 ABCD-| D2 G2| There is now five bars instead of four, but it avoids the above problem. Abc2midi: an alternative method for embedding %%MIDI commands. The syntax for placing %%MIDI instructions in the abc file requires that each command occupies a separate line in the abc file. This makes the resulting file look messy when you want to do drumon, drumoff, gchordon, gchordoff, in the middle of a line. The problem gets worse when the abc file also has lyrics included using the w: field command. It has been suggested that there should be an option to place MIDI instructions in the information field: eg.[I: MIDI drumon]. Abc2midi does have provision to parse inline I: fields using the function event_info. However, the code expects the field satisfy a specific syntax of the form [I: key1 = value1 key2 = value2 etc.] Thus you specify as many keys as you wish in the I: field. So far I have modified the function event_info_key in store.c so that it will now forward any info field commands of the form [I:MIDI = stuff] to the function event_specific which handles all %%MIDI commands. Thus you can now do the following. X:1 T: event info used for MIDI M:4/4 L:1/4 K:G [I: MIDI = program 70] DDEE|[I:MIDI=program 42] GEFG| instead of X:1 T: event info used for MIDI M:4/4 L:1/4 K:G %%MIDI program 70 DDEE|\ %%MIDI program 42 GEFG| Any %%MIDI command described in abcguide.txt may be embedded in the I: field; however the '=' is very important. Otherwise abc2midi will assume this field is just for the user's interest and just ignore it. Here is another example: X:1 T: event info used for MIDI M:4/4 L:1/4 K:G [I: oboe MIDI = program 69 MIDI = gchord fzcz MIDI = chordprog 1] BAG2|\ "G" EC GG|[I:MIDI= bassprog 100] DDDD|[I: MIDI =gchord ffffffff] G4| March 28 2005 Acciaccatura grace note notation. Abcm2ps compatability feature. Abc2mps accepts the notation {/b}a where the slash before the b tells it to display the grace note b as an acciaccatura. Parseabc.c does not understand this notation and returns an error message "Unrecognized character /". Fix: parseabc.c was modified to keep track whether it is inside a grace sequence using a new global variable ingrace. When the function parsemusic encounters a / that is not a note length indicator, it will call event_acciaccatura if ingrace flag is set. This function does nothing in abc2midi and yaps but it prints the / character in abc2abc. April 02 2005 Abc2midi does not handle microtones properly in multivoiced files. For example in, X:3 T:Miudezas C:Hudson Lacerda M:none Q:1/8=132 "ca." L:1/8 K:none clef=treble V:1 name="Clarineta em Sib" {=B}_/G {=B}^g | {=B}^F {_/e}=B {_/e}^/c' |\ {_/e}_/G {_/e}_/d' {=a}_/e | the first note B (grace note) was affected by the microtone which was intended to be applied on the second note G. Analysis: Multivoiced files (i.e. using V:1, V:2 etc.) place a header track (track 0) in the MIDI file where global DYNAMIC features such as %%MIDI program may be defined for all other voices. The microtone is sinces it uses the %%MIDI pitchbend, is also treated as a DYNAMIC feature. As a result the header track contains many pitchbends but no notes. This unfortunately handles all other notes in channel 0 in a random fashion. Fix: a new parameter, noteson, was introduced into the function dodeferred which handles all DYNAMIC features. Noteson is also a local variable controled by writetrack to specify whether NOTE features are to be processed by writetrack. This flag is now also used by dodeferred to determine whether pitchbend MIDI commands are to be inserted. April 07 2005 Introduced a new feature to midi2abc. Midi2abc.exe -mftext will now produce a mftext output of a specified input MIDI file. It was preferable to build mftext into midi2abc since I changed the output format; also runabc already links to too many executables and I would not like to keep track of version numbers for another program. April 09 2005 I have modified toabc.c (abc2abc) so that it will no longer transpose voices assigned to the drum channel (%%MIDI channel 10). Implementation: added a new entry, drumchan, in the voicetype structure which indicates whether this voice is to played on drums. Also added a new global, drumchan which is linked to voice.drumchan for the currently active voice. The event_specific function has been extended to catch %%MIDI channel 10 and update drumchan. The function setvoice() initializes voice[].drumchan to 0 when a new voice is created. The functions event_note1 and event_note2 now check the drumchan flag before transposing the note. April 10 2005 Abc2abc - abcm2ps compatibility issue. Abc2abc does not recognize the sname= "...". Fix: introduced new function parsesname in parseabc.c added new parameters to event_voice in parseabc.c, store.c, yapstree.c and toabc.c. (See September 26 2004 in this file for more details.) April 15 2005 Midi2abc: fixed problem causing midi2abc to crash when the MIDI command indicating the time signature is missing from the file. April 22 2005 Abc2midi: pitchbend inside a tied note. In the following example, the third note is held too long. X:1 T: bends M: 2/4 L: 1/8 K: G %%MIDI program 60 G4|G4|G2-_/G2|G4| Fix: in function dodeferred() (genmidi.c) for command == pitchbend, added tracklen = tracklen + delta_time; delta_time = 0L; after write_event(pitch_wheel, chan, data, 2); Also listen to the example 11 in demo.abc. April 23 2005 Abcmidi: introduced two more MIDI commands. %%MIDI portamento n turns on the portamento controller on the current channel and sets it to n. n is a 7 bit number which specifies the rate slides the pitch between two notes. (Unless you are composing 20 th century classical music, you may not wish to use this feature. Avoid slides between large pitch intervals.) %%MIDI noportamento turns off the portamento controller on the current channel. April 24 2005 Integration of abcmatch into abcmidi package. The main() function in parseabc.c was moved into store.c, yapstree.c, and toabc.c .The function parsetune was placed in parseabc.c. All makefiles were updated. (I cannot verify all of them; report any corrections to me.) The files abcstore.c and abcparse.c are no longer needed; delete them if they are lieing around. April 29 2005 Cleaned up all the compilation errors that occur in Microsoft Visual C version 6.0. May 03 2005 Abc2midi abcm2ps compatability feature: add new %%MIDI command %%MIDI beatmod n where n is a positive or negative integer. The command will increment (decrement) the loudness of the on beat, off beat and other notes by the amount n. Introduced new instructions: !<(! or !<)! or !crescendo(! or !crescendo)! which act like %%MIDI beatmod 15 Also !>(! or !>)! or !diminuendo(! or !diminuendo)! act like %%MIDI beatmod -15 Thus a pair of !<(! and !<)! does two loudness increments. One at the beginning of the crescendo and one at the end of the crescendo. This is not a gradual change but it is better than doing nothing. If the default beatmod value (15 or -15) is not ideal, you can change it using %%MIDI deltaloudness n where n is a positive number. Sample test file below: X: 1 T: crescendo M: 2/4 L: 1/8 K: G %%MIDI deltaloudness 20 !mf!cdef|edcB| !<(! cdef|!<)! edcB|AAAA| !>(! cdef|!>)! edcB|AAA| !crescendo(! cdef |!crescendo)!|edcB|AAA| !diminuendo(! cdef |!diminuendo)!|edcB|AAA| Implementation: updated dodeferred in genmidi.c, added global velocitychange in store.c and new code in event_specific and event_handle_instructions. abcguide.txt and abc2midi.1 documentation were updated. May 06 2005 It has been suggested that some abc2midi options could be global when they are used outside of a tune. For example: %%MIDI chordname %%MIDI ratio %%MIDI beat %%MIDI program It is rather difficult to add this feature since the handling of these options is not centralized but spread out in the store.c and genmidi.c code. Some of these options apply to specific voices which do not get instantiated until the voice is defined in the tune. This makes the full implementation rather formidable. I have introduced new code event_specific_in_header in store.c that attempts to handle some of the MIDI directives. Many of the MIDI directives send information to the feature[] array which does not exist prior to parsing the tune. I have not attempted to handle those directives. Presently, the only MIDI commands that will be recognized outside the tune are %%MIDI C %%MIDI nobarlines %%MIDI barlines %%MIDI fermatafixed %%MIDI fermataproportional %%MIDI ratio %%MIDI chordname %%MIDI deltaloudness All other MIDI commands outside the tune are ignored and will produce the warning "cannot handle this MIDI directive here". The following is a sample test file. %MIDI C 48 %%MIDI nobarlines %%MIDI ratio 5 1 %%MIDI chordname ugly 1 2 3 4 X: 1 T: test global settings M: 2/4 L: 1/8 K: C "G"CDEF|"Gugly" D>EF>C|^ABDA|AAC2| May 08 2005 Abc2midi: voice splitting. In some pieces of music a voice splits in two or more voices only in some measures. The new abc standard (and abcm2ps) provides a syntax for splitting a voice in a bar using the & symbol. When placed within a measure, it splits the current voice and attributes the notes that follow to the second voice. Voice splits are handled by creating separate voices which are in turn converted into separate MIDI tracks. To implement this feature, new variables were introduced into the voice structure defined in store.c int nbars; /* counts number of bars processed in voice */ int tosplitno /* points to new voice to handle split */ int fromsplitno /* points to voice initiating the split */ Both tosplitno and fromsplitno are intialized to -1 implying that a split voice does not yet exit. In an event of a split, tosplitno points to the new voice to go to. If it is -1, a a new voice needs to be created, and fromsplitno in the new voice is set to the voice from which initiated the split. In order not to confuse the new voice number with a voice number generated by a V: field, the split voice numbers start from 32. Global variables in store.c were introduced. int numsplits; /* keeps track of the number of split voices generated */ int splitdepth; /* keeps track of the number of splits in a bar */ A new function event_split_voice in store.c is called by parsemusic in parseabc.c when a '&' is encountered in a music line. A new function resync_split_voice adds bars of rests into the split voice so that bar is in the right position. A new function complete_all_split_voices ensures all split voices are the right length in order to avoid annoying messages like: Warning in line 7 : Track 2 is 3840 units long not 4800 A new function recurse_back_to_original_voice is called to recover from a split when a new bar line is encountered (see event_bar). Sample test file: X: 1 T: testing voice split M: 2/4 L: 1/8 K: G A4| G4 & e2g2|BGEE|CAEE & d2f2|F2G2| May 12 2005 Wrote a new function dumpfeat(n1,n2) in genmidi.c which prints out the contents of the feature,pitch,num,denom array between n1 and n2. The function is usually called in the debugger after stopping at a breakpoint in finishfile. May 13 2005 Abc2midi split voices: Problems occur when the music contains repeats. It is necessary to transfer the repeats to the split voice. The function event_bar checks for any repeat symbols. There are two cases. If we are already in a split voice then (eg. abcd & defg :|) we have to propagate the repeat back to the original voice while recursing back. If we are not in a split voice but we know that this voice does link to split voices, then we (eg abcd & defg |abcd :|) need to propagate the repeats downwards to the all the split voices. The function event_playonrep is also called by the parser and needs to check for split voices. May 14 2005 Now there is still another problem: the parser might encounter a repeat symbol before it knows that this voice splits. We must find a way of getting those repeat codes into the newly created split voice. Solution: a new function start_new_voice_and_sync is called when a split voice is first created. It scans the parent voice copying rests and various types of barlines and repeat codes into the feature array of the newly created voice. If it encounters a %%MIDI program, that is also copied. This way the new voice also inherits the same music instrument as its parent. If you wish to change the instrument of the split voice, you can do it this way. C2 EF & [I:MIDI= program 10] F2 D2| The new instrument will apply to all following bars of the split voice. Abc2abc was made split voice compliant. May 19 2005 Midicopy: will now return the playing time of the extracted segment. This only works when a segment is extracted using any combination of the -from and -to runtime parameters. Otherwise it returns 0.0. The program makes adjustments for any tempo changes that may occur inside this segment. May 21 2005 Corrected a bug in midi2abc. It was returning the time in seconds instead of beats when running with the -mftext option. May 22 2005 Midicopy: for some reason the meta command mf_write_tempo (which originated from midifile.c) alway writes delta_time 0. As a result all tempo meta commands are at the wrong time. When this was changed, tempo changes seem to be handled better. Midicopy now caches all tempo changes in a array of structures called tempo_array. This is used to update the current_tempo when other tracks (not containing tempo commands) are processed. The correct tempo is needed in order to get an accurate estimate of the playing time of the output file. A new function update_current_tempo is called each time Mf_currtime is updated. May 28 - 31 2005 June 04-06 2005 Midi2abc often produces a mess for piano music sequenced into a single track. There are many chords played by the left hand and the right hand usually has a different rhythm. Midi2abc tries to place all notes sounding at the same time into a single chord. To handle notes of different durations, some notes are tied to the next chord and others are not. The resulting output looks something like this. X: 1 T: Scarlatti, sonata 1 %***Missing time signature meta command in MIDI file M: 4/4 L: 1/8 Q:1/4=120 % Last note suggests Phrygian mode tune K:F % 1 flats % (C) John Sankey 1998 z/2d/2 (3efga/2-[a/2A/2] _d/2A/2[=d/2-D/2][d/2-E/2]\ [d/2-F/2]d/2-[d/2-G/2][d/2-A/2]| \ [d/2A,/2][e/2-_D/2][e/2A,/2][f/2=D/2-] [d/2D/2]z/2[g/2E/2-][e/2E/2]\ [a/2F/2-][f/2F/2][e/2G/2-][d/2G/2] [_dA]z/2[a/2-A/2-]| \ [a/2A/2][b/2A/2-][b/2a/2A/2] etc... Converting it to PostScript file produces something very difficult to read. Ideally the notes played by the different hands should be separated into two tracks. Chords should avoid internal tied noted. The abc standard contains the provision for splitting the notes in a single bar into separate voices. This should provide a means of simplifying the output. A new runtime parameter -splitbars was introduced, producing an output similar to below. X: 1 T: Scarlatti, sonata 1 %***Missing time signature meta command in MIDI file M: 4/4 L: 1/8 Q:1/4=120 % Last note suggests Phrygian mode tune K:F % 1 flats % (C) John Sankey 1998 z/2d/2 (3efga zd3- & \ z3A/2_d/2 A/2=D/2 (3EFGA/2A,/2 &\ d/2efgazd/2 z2| \ (3ef/2d/2z/2Ea/2f/2Gz2z/2 (3b/2a/2b/2 &\ EF GA A,_D/2A,/2 =Dz/2g/2& \ z3e f/2d/2z/2Ea/2f/2G/2-| b/2a/2b/2 etc.... Implementation: Separating the parts is complicated and incorporating these algorithms into midi2abc.c was even more difficult. The anote structure was extended to contain two new values. Posnum stores the position of the start of the note in xunit units. Splitnum assigns the note to one of several split voices. New functions label_split_voices and label_split scan the entire track and separate all the notes into separate parts when necessary. A note is assigned to an existing part if it follows the previous note or forms a chord matching the length of the previous note. Otherwise, label_split_voices searches for another active part satisfying this criterion. If there is no active part available, the note is put into a new part. Bar lines are ignored at this stage. Once all the notes are labeled into separate parts, the xnum value associated with the notes are updated so they indicate the number of units to the next note in the same part. A new version of printtrack called printtrack_with_splits was created from the printtrack code. In order to use as much of the original printtrack code, it make multiple passes through the same bar whenever the bar contains notes from different parts. In each pass a single part active in this bar is processed and printed. The code is barely working and is still experimental. It will probably not produce correct results for complicated MIDI files. Fortunately most MIDI files have proper chords and do not require this feature. June 04 2005 A problem with abcmatch.c causes it to return a bad xref number after processing the last tune in the file. This causes runabc.tcl to report an error similar to Error: can't read "tuneid(84)" :no such element in array. when running extras/grouper. The problem is that the notes variable in abcmatch.c does not get initialized to zero if parsetune() fails because it encounters an eof. To fix the problem, the function startfile() in matchsup.c is made global instead of static and it is called prior to calling parsetune() in abcmatch.c. June 10 2005 Midi2abc -splitbars: fixed segmentation error which occurs for tracks not containing any notes. June 13 2005 Abc2midi: "Time mismatch at tie" error when chord length declared outside of chord. X:1 T: multiple tie M: 2/4 L: 1/8 K:C [CE]/2-[CE]/2-[CE]|[CE]/2-[CE]/2-[CE]| K: G [C-E-]/2[CE]/2 [F2D2] [FD]| [C/2-E/2-][C/2E/2] [F2D2] [FD] | Abc2midi does not tie notes correctly in the above example. The chord extensions in November 4 2004 and December 12 2004 do not work correctly in combination. The problem occurs in the function dotie in the lines case CHORDOFF: case CHORDOFFEX: if(localvoiceno != voiceno) break; inchord = 0; /* subtract time from tied time */ addfract(&tied_num, &tied_denom, -num[place], denom[place]); break; after addfract subtracts num/denom from tied_num/tied_denom, tied_num should be zero. However, tied_num/tied_denom was not yet adjusted by fix_enclosed_note_length, so tied_num/tied_denom is not equal to num[place]/denom[place]. Since dotie finds tied_num to be non-zero in code /* tie in note */ if (tied_num != 0) { event_error("Time mismatch at tie"); }; it thinks that the notes inside the chord have unequal lengths and reports the time mismatch error. Furthermore, fix_enclosed_note_length is eventually called after the notes were tied making a further mess. Fix: Instead of calling fix_enclosed_note_length in a separate pass during tiefix, fix_enclosed_note_length is called during the parsing stage whenever a CHORDOFFEX feature is added (see event_chordoff). The variable nochordfix is now redundant and removed from the code. This guarantees that dotie sees the correct note lengths inside the chord. June 14 2005 Abc2midi: chord ties. In the following example, X:1 T: multiple ties M: 2/4 L: 1/8 K:C [CE]/2-[CE]/2-[CE]-|[CE]/2-[CE]/2-[CE]| The E notes are not joined. Fix: the function call patchup_chordtie was moved from tiefix to event_tie. In addtoQ (queues.c) a check for negative delay caused by apeggiate code Q[*ptr].delay = Q[*ptr].delay - wait -notedelay; if (Q[*ptr].delay < 0) Q[*ptr].delay = 0; was added. June 17 2005 Midi2abc: fixed bug in -splitbars causing program to go into an endless loop and various other bugs. June 25 2005 Midicopy: added line void WriteVarLen() in function mf_write_tempo to be compatible with the new gcc compiler. June 25 2005 Abc2midi: tieing repeated notes inside chords. Abc2midi returns a "Time mismatch at tie" error message for the following file. X: 1 T: tie M: 2/4 L: 1/8 K: C [CC]-[CC]-[CC]z| Analysis. The line is converted to [C-C-][C-C-][CC]z| and the function dotie attempts to tie C to the next note it sees which is the next C inside the same chord. This changes the length of the note in the chord leading to the above error message. Fix: a new variable samechord is introduced. When it is set to 1 it signifies that we are in the same chord where the tie mark - was placed, we do not link the tienote to any notes in that same chord. The flag samechord is cleared whenever we leave the chord (CHORDOFF or CHORDOFFEX). It is set again whenever a tie mark occurs inside a chord is encountered. Please note: a tie only connects one note. Therefore C-[CC] will tie C to only the first C in the chord. June 26 2005 Abc2midi does not correctly handle more than one bar split. In the following example, X: 1 T: testing voice split M: 2/4 L: 1/8 K: G %%MIDI program 24 A4 & c4 |G2F2 & BBDD & E,,4| E,,4 is played in the first bar coincident with A4 instead of the second bar. Analysis: various bugs caused abc2midi to fail with more than one split. locate_voice() must use voice indexno rather than voiceno. start_new_voice_and_sync must pass the voice indexno rather than voiceno to locate_voice(). June 27 2005 Midi2abc: changed name of parameter -usesplits to -splitbars. Added new parameter -splitvoices which eliminates non homophonic chords (ie. polyphonic) by splitting entire voices. Implementation: added new function printtrack_split_voice to midi2abc. June 28-30 2005 Midi2abc: fixed numerous bugs in printtrack_split_voice() and printtrack_with_splits(). July 02 2005 Abcmatch: upgraded the handling of chords and ties to be compatible with abc2midi. July 09 2005 Abcmatch: added an option to ignore simple bars. Midi2abc: withdrew -Midigram option and replaced it with -midigram. Note onset and offset time are now printed in MIDI time units rather than quarter notes units. July 14 2005 Abc2midi: voice split causes infinite loop when play on repeat (eg [1 or [2) specified. For the following file X:1 T:reproduce the bug in a smaller file C:H. C. L. Smith L:1/4 M:1/4 K:C D|:C|[1F:|[2F|E&C|| abc2midi emits the following error message in an endless loop. Error in line 8 : Bad variant list : reproduce the bug in a smaller file Warning in line 8 : Bar 2 has 2 units instead of 1 Error in line 8 : Bad variant list : reproduce the bug in a smaller file Warning in line 8 : Bar 2 has 2 units instead of 1 Error in line 8 :.... Analysis: when writing the voice split in bar E & C||, the function inlist (in genmidi.c) fails to get the repeat on repeat number (eg [2)) which was set for top level voice but not for the split voice. Fix: the problem was traced to the function start_new_voice_and_sync in store.c. It copies the repeat BAR feature (SINGLE_BAR, DOUBLE_BAR, etc..) to the split voice but for the PLAY_ON_REP feature it must also copy the pointer to the part number stored in denom[]. Now both feature[j] and denom[j] are both copied for all bar type features. July 15 2005 The above file exposes yet another problem leading to a loss of synchronization between the voices. The first indication that there is still something else wrong are the messages. Warning in line 8 : Bar 2 has 2 units instead of 1 Warning in line 8 : Bar 3 has 3 units instead of 1 in repeat Warning in line 8 : Track 2 is 4320 units long not 2880 When playing the output MIDI file, the note C in the split is played two bars late extending track 2. Analysis: A play on repeat symbol is always preceded by a bar or repeat bar (ie. | or :|). The function start_new_voice_and_sync treats the play on repeat symbol as another bar line and inserts a rest to complete the bar when in fact, it should just insert a PLAY_ON_REP. Since this bar is played twice, the C note comes two bars late. Treating PLAY_ON_REP as a separate case fixed the problem. July 17 2005 Abc2midi: voice split synchronization error when not all measures are equal in length. In the following file, the tune begins with an incomplete measure. X:1 T: anacrusis M: 2/4 L: 1/8 K: F AG|Fc Fc| d2 e2 & B2 c2| Analysis: start_new_voice_and_sync unfortunately assumes that every measure contains 2 beats. Fix: the function now counts the number of beats in each bar it processes. Abc2midi: MIDI attributes inheritance. As discussed in May 14, 2005 split voices inherit the MIDI characteristics from their ancestor. The following file does not work as expected. X:1 T:inherit 1 M:4/4 L:1/16 Q:1/4 =20 K: C %%MIDI channel 2 %%MIDI program 2 50 B2G2A2B2 EDEF EGFA & z2E4 D2 C8|] The split voice z2E4 ... is played on the Acoustical Piano (program 0) instead of the synthetic strings. However the following file works correctly. X:2 T:inherit 2 M:4/4 L:1/16 Q:1/4 =20 K: C %%MIDI program 50 B2G2A2B2 EDEF EGFA & z2E4 D2 C8|] Analysis: Each split gets its own voice and each voice gets its own channel number unless it is changed explicitly. The above should be equivalent to X:1 T:inherit 1 M:4/4 L:1/16 V:1 %%MIDI channel 2 %%MIDI program 2 50 B2G2A2B2 EDEF EGFA| V:2 %%MIDI channel 2 %%MIDI program 2 50 z2E4 D2 C8 Unfortunately, the %%MIDI channel 2 did not propogate to the split voice. Voice 1 was assigned channel 2 but voice 2 still had channel 1 (writetrack automatically assigns the first channel which is not in use). The bug was fixed by ensuring the CHANNEL feature also propogates into the split voice. You may wonder why X:2 worked correctly. This is because the MIDI program command without the channel indication applies to whatever channel is currently active. July 23 2005. Fixed bug causing midi2abc.exe to produce a segmentation error when running with the -splitbars option. (Failed to save state when doing a split voice context switch due to encountering an end of track before an end of measure. As a result the restored chordhead would point to the wrong place.) Added more code around line 2480 in printtrack_with_splits in midi2abc.c. August 13 2005. Abc2midi.exe does not handle correctly chords of the form [CE]2 when embedded in a triplet. For example in the file, X:1 T: triplet M: 4/4 L: 1/4 K:C (3C2 D2 [CE]2 | abc2midi produces an error messages Warning in line 6 : Different length notes in tuple Warning in line 6 : Different length notes in tuple and the [CE] chord is the wrong length. Analysis: event_note processes the internal lengths of the notes in a chord before it encounters the end of chord marker (]) and it does not know that the internal lengths may be adjusted externally after the end of chord. It sees the wrong length, and sends a warning. Event_chordoff fails to make an adjustment for the triplet (tuple) so that the function fix_enclosed_note_lengths sets the lengths of the internal chord notes to the wrong length. Fix: event_note bypasses the tuple test (for triplets) if the notes are inside a chord. The tuple test was also added in event_chordoff. It adjusts the setting of the note lengths (chord_n, chord_m) if the chord is inside a tuple. If chord_n and chord_m are not 1,1 then fix_enclosed_note_lengths is called. August 13 2005 Abc2midi.exe has difficulty handling tied notes enclosed in a slur. For example for the tune X:1 T: slur 1 M: 2/4 L: 1/8 K: G (GB-B) C|(DEF) B| the following messages appear Warning in line 6 : Slur in abc taken to mean a tie Error in line 6 : Bad tie: possibly two ties in a row Error in line 6 : Cannot find note before tie Surprisingly, the output MIDI file is still correct. Analysis and fix: Abc2midi does almost nothing when it encounters slurs. However, when it sees repeated notes inside a slur it tries to tie them together. For example for (G B B), abc2midi would try to tie the two B's together. This is the source of the above problem. I do not think this is a very useful feature so I have turned this feature off (in event_sluroff store.c). August 13 2005 The abc2-draft standard, http://abc.sourceforge.net/standard/abc2-draft.html has deprecated the !...! notation in favour of the +...+ notation. In order to comply with the change, abc2midi, abc2abc and yaps were modified to accept either convention. Thus you can use +trill+, +fermata+ +pp+ etc. as well as the deprecated notation (!trill! etc.). There is one conflict: in the early days of abc notation chords were notated as +CEG+ instead of [CEG]. There is probably very little music using this old convention. If you need to handle the old chord notation, you must now add the option -OCC to abc2midi, abc2abc or yaps. Sample file: X:1 T: decorations M: 2/4 L: 1/8 K: G +<(+ [CE]4 +<)+ |[CE] +trill+ DEF| !<(! [CE]4 !<)! |[CE] !trill! DEF| Implementation: Introduced a new global, oldchordconvention into parseabc.c which is linked externally to store.c, toabc.c and yaps.c. If this global is unset (ie. 0), then parsemusic in parseabc.c treats + and ! in the same manner. August 17 2005 Added new run time parameters to midicopy -fromsec and -tosec allowing you to select a section in terms of time in seconds. September 13 2005 Midicopy using the -fromsec option to select the start of the output MIDI file causes the music to be delayed by the the same amount of seconds. Analysis, the first note on (or note off) of the track has a delta_time equal to the time of the first note in the selected section of the original file. TiMidity has no problem since it ignores this delay. Other MIDI players are less compliant. This is a hard bug to fix properly when the tempo varies across the MIDI file. For such files, it is recommended that you use the -from and -to parameters and express the times in MIDI tick (pulse) units. The program now computes the right delay using the first tempo specification in the MIDI file. I noticed that when midicopy truncates the beginning of a file, a track may begin with a MIDI off command of a note that has not been turned on. I don't think this causes a problem. September 19 2005 Incorporated changes suggested by Mikhail Teterin into parseabc.c and store.c to modernize the C code. This includes the replacing of the functions casecmp(s1,s2) and stringcmp(s1,s2) with functions built into the C compiler. If this causes any problems with your compiler please notify me as soon as possible. Other changes were added to make the code more efficient and eliminate some warning messages. September 19 - October 8 2005 Abc2midi: another bug related to split chords was found. In the following example X:1 T: split test file M: 2/4 L: 1/8 Q: 50 K: D CD |EF AB & CD FG| G2 | BD D2 & GB B2| The zero th and second bar are only one beat long. The fix described on June 17 th handles the zero'th bar correctly but it does not address the second bar since a different function resync_split_voice is called to maintain synchrony. This function assumes all bars are a fixed length as specified in the time signature. This was a difficult bug to fix since it required major changes to the code. A new function sync_voice replaces the code for start_new_voice_and_sync and resync_split_voice. A test file used to debug these changes, split.abc, is included in the programming directory. Hopefully, I will not need to return to this file many times. October 8 2005 Abc2midi, yaps, abc2abc : extraneous warning "Slur within slur". For the following example, X:1 T: 2 slurs M: 2/4 L: 1/8 K: C V: 1 C2 (C2 |\ V: 2 (A2 G2) |\ V:1 D2) E2| V:2 G4| we get the warning Warning in line 9 : Slur within slur. Analysis, there are two overlapping slurs, but they are in separate voices so this should be no problem. Parseabc.c merely keeps a count of the number of open slurs with the variable slur and does not note that they are associated with specific voices. Fix: the warning message has been moved to store.c. October 9 2005 Abc2midi: grace notes are not applied correctly to a chord. In the following example, X:1 T: grace/chord M:2/4 L:1/8 K:G V:1 D4|{c'}[g3b3] c|z2 G2| V:2 F4|G3 e|z2 D2| The length of the host chord [g3b3] is not adjusted correctly. This results in a loss of synchronization between voice 1 and 2. Analysis: several bugs related to host chords were fixed in my new function applygrace_new() in store.c. The original code, applygrace_orig was also fixed. October 10 2005 Updated makefiles/unix.mak. Cleaned up some of the -Wall warning messages.