abcmidi/0000755000000000000000000000000012642211562011145 5ustar rootrootabcmidi/CHANGES0000644000000000000000000130650012562316654012156 0ustar rootroot2003 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 2003 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.Since the microtone uses the %%MIDI pitchbend, it 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. November 6 2005 New abc2midi feature for supporting drum tracks. Notes played on MIDI channel 10 (counting from 1), are interpreted by the General MIDI instrument as one of 47 percussion instruments (see abcguide.txt for list). Unfortunately, notating the music in this manner is rather awkward if you wish to convert it to common music notation using abcm2ps. Usually, only a few percussion instruments are used. To allow for better drum notation, you can alter the mapping between notes and percussion instruments using the new %%MIDI drummap command. For example for the tune: X:1 T: illustrating drummap command M: 4/4 L: 1/8 K: none %%MIDI channel 10 %%MIDI drummap E 36 %%MIDI drummap G 38 %%MIDI drummap _e 42 |: E2 GE zE z2 & z_e z_e z_e z_e :| would be played on the percussion instruments bass drum (36) acoustic snare (38) and closed hi-hat (42). Implementation: added new function parse_drummap() genmidi.c which handles the %%MIDI drummap command. parse_drummap() is called from the function dodeferred(). November 6 2005 Abc2midi: split voice does not propogate the octave shift command. eg. X:15 T: splits with octave=1 M: 4/4 L: 1/4 K: G octave=1 G A B C & E F G A| The notes E F G A are played an octave lower than intended. Fix: the v->octaveshift variable is passed to the split voice in the function event_split. December 08 2005 Abc2midi: the drummap feature illustrated on November 06 2005 produces an improper MIDI file. eg. X:1 T:unfinished M:2/4 L:1/16 K:F V:1 %%MIDI channel 10 %%MIDI drummap ^^g 72 % Long Whistle %%MIDI drummap _a 58 % Vibraslap ^^gz _a2-_a4 |] midi2abc.exe unfinished1.mid -mftext Header format=1 ntrks=2 division=480 Track 1 contains 40 bytes 0.00 Metatext tempo = 120.00 bpm 0.00 Metatext key signature F (-1/0) 0.00 Metatext time signature=2/4 0.00 Metatext (Seqnce/Track Name) unfinished Track 2 contains 35 bytes 0.00 Metatext (Seqnce/Track Name) unfinished 0.00 Note on 10 c5 105 0.25 Note off 10 a5 0 0.50 Note on 10 a#3 80 2.00 Note off 10 g#5 0 The note on's have the translated pitches but the note off's have the original pitches. As a result none of the MIDI note on's are properly terminated. For percussion instruments, this may not be noticeable since a decay is already built in. However, some midi players may complain. Fix: the function midi_noteoff in genmidi.c now checks for for channel 10. December 09 2005 Abcmidi: transposition should not be applied to the music in channel 10. In the following example X:1 T: drum transpose M: 2/4 L: 1/8 K: G transpose=-3 V:1 FAFA|EFG2| V:2 %%MIDI channel 10 %%MIDI drummap g 72 % Long Whistle %%MIDI drummap a 58 % Vibraslap agag|agag| The transpose=-3 changes percussion instruments. Fix: a test for channel 10 is made before the call to noteon_data() in the function noteon() in genmidi.c. Also in writetrack, a similar test was applied before addtoQ in two places (NOTE: and TNOTE:). December 17 2005 Abc2midi new feature: certain instruments such as an organ have no greatly emphasized beat notes and sound unnatural when the beat algorithm accents the down and off beats. To turn this feature use %%MIDI nobeataccents To turn it back on %%MIDI beataccents By default beat accents are turned on for any new tune. Thanks to Mike Scott for contributing the code to genmidi.c Implementation: a new variable beataccents which acts as a flag was introduced. January 7 2006 I have started looking into the problem of adding the split voice feature into yaps. In order for yaps to handle split voices, it was necessary to introduce a new feature code SPLITVOICE into abc.h. This had minor impact on the debugging code for genmidi.c and matchsup.c. Event_split_voice in yapstree.c now needs to insert a SPLITVOICE feature. To avoid "unknown type" message originating from sizevoice (in drawtune.c) it was necessary to add a case statement for SPLITVOICE even though it does nothing. To assist in debugging, the code in the showline function was split into a new function showfeature in debug.c. The real work is done in the function advance(..) in the file position.c (see additions in programming/yaps.txt). In order to allow spacemultiline to process all the notes playing at the same time, major changes are necessary. We want advance() to check a measure for splitvoices, and if found process all the notes in the bar in the order that they would be played. This means extending the voice structure defined in structs.h so that it maintains status information for v->tuplefactor, v->inchord, v->place,v->time for all splitvoices and telling advance() to handle the splitvoices in parallel. This work is beyond me at the present time and no further work was done. January 13 2006 abc2midi fails to tie note correctly in chord with an augmented unison interval. In the following example X:1 T:A) Matching non-perfect primes M:C L:1/2 K:C [=D^D-] [=D^D] z [=D-^D] [^D=D] z the D- tie and ^D- are done improperly. Analysis: In order to tie notes across bar lines where the accidental is assumed, (e.g. A_B-|BD), the function dotie performs the tie based on the pitch line (in the staff) rather than the actual pitch. Unfortunately there are cases where we run into trouble such as above. Partial Fix: dotie() has a new flag called newbar, which is set to 1 whenever a nonprocessed tie is followed by barline. The pitchline[] test is now only activated when newbar is set. Unfortunately, this is not a complete fix. The same problem reappears with this file for the second and third lines. X:1 T:Matching non-perfect primes M:2/4 L:1/2 K:C [=D^D-]| [^D=D] | z2 | [=D^D-]| [=D^D] | z2 | [=D-^D]| [^D=D] | z2 | [=D-^D]| [=D^D] | z2 | The feature array does not record whether accidentals have been spelled out explicitly so further checks cannot be done when applying ties across bar lines. I recommend that one just changes the order of the notes in the chord in order to get it to work. Fortunately, this problem occurs rarely. January 14 2006 Abc2midi fails to tie microtonal notes correctly. In the following example: X:1 T: tied microtonal pitches M:C L:1/2 K:C C ^13/16C - ^13/16C ^13/16C ^13/16C ^13/16C - C The two notes on the second line are tied together, but the first note is in C rather than ^13/16C causing an audible pitchbend. The notes in the third line are correct pitches but not joined. The tied notes in the fourth line are both incorrect pitches. Analyses: looking at the mftext output from midi2abc reveals the problem. midi2abc.exe tmp/X1.mid -mftext Header format=0 ntrks=1 division=480 Track 1 contains 141 bytes 0.00 Metatext tempo = 227.00 bpm 0.00 Metatext key signature C (0/0) 0.00 Metatext time signature=4/4 0.00 Program 1 73 (Flute) 0.00 Metatext (Seqnce/Track Name) tied microtonal... 0.00 Note on 1 c4 127 2.00 Note off 1 c4 0 2.00 Pitchbnd 1 msb=0 lsb=90 2.00 Note on 1 c4 107 2.00 Pitchbnd 1 msb=0 lsb=64 4.00 Pitchbnd 1 msb=0 lsb=90 6.00 Note off 1 c4 0 6.00 Pitchbnd 1 msb=0 lsb=64 6.00 Pitchbnd 1 msb=0 lsb=90 6.00 Note on 1 c4 107 8.00 Note off 1 c4 0 8.00 Pitchbnd 1 msb=0 lsb=64 8.00 Pitchbnd 1 msb=0 lsb=90 8.00 Note on 1 c4 117 10.00 Note off 1 c4 0 10.00 Pitchbnd 1 msb=0 lsb=64 10.00 Pitchbnd 1 msb=0 lsb=90 10.00 Note on 1 c4 107 10.00 Pitchbnd 1 msb=0 lsb=64 14.00 Note off 1 c4 0 This is another example where the handling of tied notes in dotie() store.c and writetrack() in genmidi.c have gets in the way. (The code was written before microtones was introduced into abcmidi.) The parser encircles every microtonal note with an event_microtone and event_normal_tone. The function dotie changes the tied note from NOTE to TNOTE, the TIE to a REST, and the note being tied to a REST. The function writetrack() unfortunately applies the delay() function for the NOTE feature but not for TNOTE. As a result, the pitchbend is restored to normal before the note even starts playing. Modernizing the tienote function (see February 12 2005 comments) is not an option since there were too many cases to worry about and it would probably take a long time to get out all the bugs out. Fix: a small patch was added to tienote() in store.c. It removes the DYNAMIC feature restoring the pitchbend to normal if it finds one immediately following the TNOTE. January 15 2006 The contour matching algorithm in abcmatch.c has been changed to use pitch interval between adjacent notes. A new run time parameter, -qnt was added which quantizes the contour interval. Details in abcmatch.txt. January 16 2006 Added new feature to yaps that allows you to switch from black to red output using !red! or +red+ instruction command. To restore insert !black! or +black+ in the abc file. e.g. X: 356 T:Banks of the Nile M:4/4 L:1/4 K:Eb B/2-G/2| F E F G| c B G E| F E- C C| C3 C|!red! E E G B!black!| c2 e c/2c/2| B B E F| G3 E/2E/2| E E G B| c c e c/2c/2| B B E F| G3 B/2G/2| F E F G| c B G E| F- E C C| C3|| The notes in the 6 bar are printed in red for emphasis. Implementation: In structs.h added a new structure struct dynamic {char color;}; In yapstree.c, added code to event_handle_instruction to detect !red! and !black! and addfeature(DYNAMIC,psaction) where psaction is a *dynamic struct. In drawtune.c added code to printvoiceline() to take appropriate issue a postscript command to change the color when it detects a DYNAMIC: feature. January 29 2006 Abc2midi: improved the microtone pitch accuracy. Replaced the code event_microtone (in store.c) with the code contributed by Hudson Lacerda. Introduced some support for single note tuning change using the universal system exclusive messages. Added new function in midifile.c single_note_tuning_change(). In function dodeferred in genmidi.c added a %%MIDI snt k pitch command where snt stands for single note tuning, k is the MIDI pitch being retuned (a number between 0 to 127) and pitch is a floating point number representing the new pitch value. Sample file follows. X:1 T: single note tuning M: 2/4 L: 1/8 K: G C \ %%MIDI snt 60 61.5 C cd| I have not yet updated abcguide.txt since this feature is provisional right now. Not all MIDI devices support this universal system exclusive message. February 05 2006 Abc2midi.exe eliminated the warning for microtones "divisor not a power of 2". Introduced a new copy of readlen (readlen_nocheck which is called by ismicrotone() and does not report this error.) March 14 2006 Abc2abc does not recognize "middle=XXX" in the V: field which is used by abcm2ps and silently drops it when transposing abc files. The fix was provided by Mike Scott who also cleaned up the parameter calling sequence to event_voice in parseabc.c. This also involved altering the code in store.c, yapstree.c, matchsup.c, and toabc.c. Thank you. Added #include to crack.c, mftext.c, pslib.c and queues.c which cleans up some of the compilation warnings.(Thanks to Martin Tarenskeen.) Apr 21 2006 (Mike Scott) The 'y' spacing character used by Barfly and abcm2ps was being silently dropped in parseabc.c. Added support for this (including a length specifier - is this used by anything?) to parseabc.c and abc2abc.c; stubs in the other modules including yaps mean they behave as before. June 7 2006 Midicopy: new runtime parameters -frombeat and -tobeat were introduced to copy a selection of a midi file. Midifile: new code was introduced to process an individual track in a multitrack MIDI file. June 25 2006 Abc2midi: added new feature to provide control over the articulation of the notes. The feature %%MIDI trim x/y introduces a gap between notes of duration x/y where x/y is the fraction of the unit note length defined by the L: field command. This gap is made by shortening every note by this amount whenever it is possible. If the note is too short, the gap is reduced. Slurs indicated by parentheses in the music body temporarily disable this feature. Implementation: added a new feature SETTRIM in abc.h. Added new globals variables trim,trim_num,trim_denom in genmidi.c. Added additional code in writetrack to initialize trim_num,trim_denom and to modify notes for switch conditions NOTE:, CHORDOFF:, and CHORDOFFEX. Added new switch state in writetrack to interpret feature SETTRIM. In store.c, added more code in event_specific to interpret the %%MIDI trim command. Abcguide.txt, abc2midi.1 and demo.abc were all updated. Thanks to Jacques Le Normand for the suggestion. July 28 2006 Midicopy still does not extract correctly a segment from some MIDI files when it is specified using the -fromsec and -tosec parameters. This occurs in multitrack MIDI files containing numerous tempo changes. Time units measured in seconds do not correspond between tracks. It was decided to completely change the method of handling segment extraction when time is specified in seconds. It is assumed that all tempo indications are placed in track 1 of the MIDI file. Tempo changes in other tracks are ignored. An initial pass is made through track 1 to extract all the tempo changes and store them in an array. This is used to map time in seconds to MIDI pulses or ticks. The -fromsec and -tosec parameters are converted to pulse units using this mapping. The program then extracts the MIDI information falling in this time interval. July 28 2006 Abc2midi returns the error message "First lyrics line must come after first music line" when processin abc files with lyrics and inline voice commands. For example X:1 T: inline voice M:5/8 L: 1/8 K:G [V:1] cdefg w: c d e f g [V:2] cdefg w: c d e f g I have little experience with lyrics in abc files. The problem is caused by the fact that the inline voice command starts up a new track which resets the variable thismline = -1. This indicates that a new music line was not yet encountered for this voice. If the notes cdefg were placed in a separate line, then the variable thismline was be set to the current line number and everything would be all right. Unfortunately, this is not the case and the abc2 draft standard excepts this syntax. See abc.sourceforge.net/standard/abc2-draft.html and in particular the canzonetta.abc file on that page. There is no easy way of detecting music information at this point other than updating the variable thismline every time a note is processed. Instead, I disabled the error message by commenting the line thismline = -1; in genmidi.c. Hopefully, this does not cause more damage. July 29 2006 Abc2midi: microtones (pitchbend) does not work correctly for tied notes enclosed in a slur. For example: X:1 T:bad pitchbend when tie + slur M:4/4 L:1/8 K:C "^Bad pitch bend when tie+slur" (^1/2C- ^1/2C =C) a- a4 | ^1/2C- ^1/2C =C a- a4 In the first bar, the tie does not work correctly and 3 notes are heard instead of two. Furthermore the first note does not have a pitchbend applied. In the second bar, the notes are played correctly. Analysis: running midi2abc with the -mftext option provides some indication of the problem. 0.00 Pitchbnd 1 msb=0 lsb=80 0.00 Note on 1 c4 105 0.00 Pitchbnd 1 msb=0 lsb=64 0.50 Pitchbnd 1 msb=0 lsb=80 1.00 Note off 1 c4 0 1.00 Pitchbnd 1 msb=0 lsb=64 1.00 Note on 1 c4 80 1.50 Note off 1 c4 0 The pitchbend is set prior to the note but is restored to normal immediately after the note is started (time 0.00). This is similar to the problem fixed on January 14 2006 (see this file). This suggests a problem with the function dotie(). Further analysis, revealed that the parser places a SLUR_TIE after every NOTE feature when the notes are enclosed inside a slur. The SLUR_TIE is not needed by abcmidi but it is used by yaps. Unfortunately, the function dotie() does not expect a SLUR_TIE to appear between the TNOTE and DYNAMIC so it fails to remove the DYNAMIC feature. Fix: A similar patch described in Janurary 14 2006 was added to dotie(). July 29 2006 Abc2midi: It is not commonly known that accidentals are not supposed to propogate across octaves. In the follow example, X:1 T: accidentals and octaves M: 2/4 L: 1/8 K: G C_EDe|C_EDe-|e2^f2|-f2g2| Abc2midi normally also flattens the e; however, technically it should not be doing this. Accidentals only apply to a specific note and should not affect the same pitch class in other octaves. Fix: in store.c workmap and workmul are now doubly indexed arrays. The second index keeps track of the octave. July 30 2006 Abc2abc transposition always reverts to the major key signature when it does a transposition. Analysis: the code in toabc.c represents the key signature in terms of the number of sharps and flats and ignores the mode of the original key signature when it is doing a transposition. Fix: (1) In parseabc.c the index to the array mode[] is saved in the variable modeindex when a mode string is matched. (2) in order to pass modeindex to event_key, the function parameter minor was replaced with modeindex and the variable minor was turned into a local variable which is computed from modeindex. This was done in all files where event_key is defined -- store.c, yapstree.c, matchsup.c, and toabc.c. (In actual fact, the variable minor was only used in store.c to set the minor flag in the MIDI file.) (3) A new function called compute_keysignature() from the sharps/flat representation and modeindex was added to toabc.c. (4) event_key in toabc uses this function to compute the correct key signature. August 04 2006 abc2midi: The treatment of microtones and microtones with accidentals for key signatures other than C major (or A minor) has been changed. Prior to version 1.87, if the music was in the key of G major, ^1/2F would be interpreted as raising F# by a half a microtone. Now the underlying key signature is ignored and the microtone is treated as a pure accidental. Thus ^1/2F raised F and not F#. Hopefully this is more intuitive. Thus accidentals and microtones are assumed to be applied to the natural form of the note irrespective of the key signature or the status of previous notes in the measure. However, accidentals other than microtones can still propagate to notes which do not have accidentals. To illustrate consider the following in the key of C major. _E _1/2E E __1/2E E| The second E is treated as E natural flattend by 1/2 microtone because E is always assumed to be in its natural form when preceded by any accidentals. Since the assumed natural of the second E propagates, the third E is also E natural and not Eb. The last note is Eb reduced by half a semitone. The last E would be played as Eb. See abcguide.txt for another example. Implementation turned out to be easier than expected. A new global (int microtone) was added to store.c. It is set to 1 by event_microtone and reset to 0 by event_normal_tone. The function pitchof(), now does not apply the active flats or sharps (of the key signature) or accidentals when the microtone global is set. August 4 2006 Abcm2ps has introduced an extension of the w: field referenced by the s: field which accepts ~ as a decoration. Unfortunately, the parser in the abcmidi package does not recognize this field command and attempts to treat the line as a music line. As a result a file such as X:1 T: s K:C cd ef g4 | ag ab c'4 |] s: "C"~~~ "C/E" | "Dm/F"* "G7" "C" s: .. .. +tenuto+ | .. .. !fermata! s: "_5"***"_6" | "_6"* "_7"*"_5" s: "_3"***"_3" | "_3"* "_5;3"*"_3" produces many error messages Error in line 6 : Single colon in bar Error in line 6 : Malformed note : expecting a-g or A-G Error in line 6 : *'s in middle of line ignored Error in line 7 : Single colon in bar Error in line 7 : Malformed note : expecting a-g or A-G Error in line 7 : Malformed note : expecting a-g or A-G Warning in line 7 : instruction !tenuto! ignored Error in line 7 : Malformed note : expecting a-g or A-G Error in line 7 : Malformed note : expecting a-g or A-G Error in line 8 : Single colon in bar Error in line 8 : *'s in middle of line ignored Error in line 8 : *'s in middle of line ignored Error in line 8 : *'s in middle of line ignored Error in line 9 : Single colon in bar Error in line 9 : *'s in middle of line ignored Error in line 9 : *'s in middle of line ignored Error in line 9 : *'s in middle of line ignored Similar error messages occur for other abcmidi programs, for example yaps, abc2abc etc. Fix: in parseabc.c: for function parsefield add s to the strchr string if ((inbody) && (strchr("EIKLMPQTVdwW", key) == NULL)) { event_error("Field not allowed in tune body"); and also added the case in the switch statement case 's': break; finally in parseline() added s to the strchr string in if (strchr("ABCDEFGHIKLMNOPQRSTUVdwWXZ", *p) != NULL) { q = p + 1; August 05 2006 Note trimming introduced in June 25 2006 causes loss of synchronization between two voices when notes are contained in a grace sequence. Fix: introduced a variable graceflag into writetrack() in genmidi.c. The flag is set when GRACE feature is encountered and restored to zero when GRACEOFF feature is encountered. Note trimming is disabled inside a grace sequence. Also note trimming is shutoff for short notes. In order to separate two slurs in a row, trimming is restored for the last note in a slur. August 08 2006 Abc2midi: split voices. In the file X:1 T: also D sharp continues in next bar K:C M:4/4 L:1/4 C^DEF & C4 | CDEF | The D in the second bar is sharpened. Fix: added call to function copymap() in the function recurse_back_to_original_voice(). August 29 2006 Abc2abc: handling of rests in tuples causes an error message. The problem does not occur in abc2midi or yaps. For example X:1 T: tuple rests M: 2/4 L: 1/8 K: C G4|(3z2A2B2|F4| abc2abc tuplerest.abc -t 3 X: 1 T:tuple rests M:2/4 L:1/8 K:C G4| %Error : Rest not allowed in tuple (3z2A2B2 %Error : Bar 1 is 7/12 not 2/4 |F4 %Error : Bar 2 is 1/3 not 2/4 | Fix: in the function event_rest in toabc.c, the error message was removed and the beat counter code was modified to consider tuples. September 09 2006 abc2abc: voice numbers not processed correctly. In the following example: X:1 T:voices M: 2/4 L:1/8 K:G V:1 ABCD|abcd| V:1I ABCD|abcd| V:1I was changed to V:1 producing an incorrect abc file. Analysis: the parsevoice() in parseabc decides whether the voice number is a number or a label based on the first character. Since the first character of 1I is a number it treats it as a number and ignores the I. This problem also persists for abc2midi and yaps. Fix: created a new function isnumberp(s) which determines whether the string s is a positive integer number and returns 0 for no and 1 for yes; replaced the original test with this function. September 11 2006 Abc2midi: handling of trilled notes for broken rhythms is not correct. In the following example, X:1 T: trill M: 2/4 L: 1/8 K:C %%MIDI ratio 3 1 TE>G TF3/A/| the length of notes E and G are not adjusted for broken rhythm and remain as equal values. Analysis: the handling of broken rhythms is fairly complicated in the file store.c. The location of E and G are maintained by variables v->thisstart, v->thisend and v->laststart, v->lastend by the functions marknotestart, marknoteend and marknote. (This also allows the handling of chords too.) When a > or < is encountered a number of flags (brokenpending, brokentype, brokenmult) are set by the function event_broken. The function marknotend checks these flags and calls brokenadjust to adjust the lengths of E and G using the stored variables v->thisstart, v->thisend etc. Trilling is handled by the function dotrill() which expands note E into a sequence of notes whose length depends upon the length of E and the tempo. In this example, the expansion is done prior to encountering the broken rhythm indicator >. After G is encountered, the lengths of the notes are adjusted for broken rhythm. Unfortunately, there is a bug in dotrill, and marknotestart was called for the last note in the trill sequence rather than the first note. The problem was fixed by changing this code. Note that in the above example, the number of notes in the trilled E and the trilled F are different. This is because E is not effectively expanded until after it was trilled. There is no easy fix to this problem other than avoiding mixing notations for broken rhythms. trilled F are different. than the first note September 22 2006 Midicopy.c: to avoid problems with some systems, the byte val for the runtime string -replace trk,loc,val is read as an integer (%d) instead of a char (%c). September 22 2006 Abc2abc, abc2midi etc. does not recognize "clef=G". In the following example, X:1 T: clef problem M: 2/4 L: 1/8 K: Am clef=G "Am"ABCD|ABCD| The following message appears: %Warning : cannot recognize clef indication K:Am clef=G Fix: added checks for clef=g or clef=G in the function isclef() in parseabc.c September 23 2006 Abc2abc removes blank lines from abc files. (These blank lines are usually to encircle comments between tunes in a multitune file. Analysis: whenever parseline() (in parseabc.c) detects a blank line, it calls event_blankline(). In abc2abc, event_blankline() only emits a blank line if the flag newbreaks is set. Unfortunately, this parameter is used for another purpose (i.e. reformating an abc file with new linebreaks every X bars using the -n X runtime parameter). This has nothing to do with handling already existing blank lines. Since event_blankline is called only when there is a blank line, it appears that the condition on the flag newbreaks should not be present. Fix: the condition statement was removed. A blank line will always be issued. Note that event_blankline also closes the tune and parser for that tune as usual. September 25 2006 Abc2midi: some users have complained about the unnecessary warnings and error messages issued by abc2midi. For example standard music practice does not require a leading repeat mark |: to be placed at the beginning of the sheet music and it is commonly left out in many abc transcriptions. Abc2midi typically warns the user that it has been left out but does the correct thing. Furthermore, the placement of a fermata sign will likely cause a message that a bar has too many beats. Too placate the users, I have introduced a new runtime parameter -quiet which will suppress all these messages. Note abc2midi parses the abc file in two passes and may not always handle assumed repeats correctly. For example if the tune begins with an anacrusis, abc2midi does not attempt to figure out whether the |: should be placed before or after the anacrusis. (This depends upon the placement of the end repeat.) In multipart files, abc2midi fails to place a starting repeat sign. In the case of multivoiced files, loss of synchronization between voices can occur because of user mistakes or because abc2midi made the wrong assumption. (For example, search for the word fermata in this file.) Though attempts have been made to standardize the abc music notation language, it is a living language and various variants are introduced now and then. Abc files that have been notated many years ago are not updated to correct for the various problems that are introduced by these new features. There is a variety of software to process abc files, but many of the developers have moved to other things and fail to maintain their software. Though these messages are an inconvenience to users they are useful in diagnosing problems when the MIDI file does not sound correctly. September 26 2006 Abc2midi: now supports linear temperament scale using code contributed by Magnus Jonsson. New %%MIDI commands are introduced to change the temperament. %%MIDI temperamentlinear octave_cents fifth_cents where the variables specify the size of an octave and size of a perfect fifth in cents where one cent is 1/100 of a semitone or 1/1200 of an octave. %%MIDI temperamentlinear 1200.0 700.0 produces the equal tempered scale. %%MIDI temperamentlinear 1200.5 698 produces a slightly stretched octaves and narrowed fifths. Quoting the Help for the program Scala http://www.xs4all.nl/~huygensf/scala/ A linear temperament is a cycle or chain of one particular interval, called the generator or formal fifth. Whenever by doing so a pitch originates that is outside the range of one formal octave (interval of equivalence), it is "wrapped" back inside by subtracting the formal octave value. Examples of this kind of scale are the Pythagorean scale generated by a pure fifth, and regular meantone scales. Implementation: store.c : added new globals temperament, octave_size, fifth_size which are set by %%MIDI temperamentlinear. Created a new function pitchof_b() which is similar to function pitchof() but also returns a pointer pitchbend. Pitchof_b() would eventually replace all calls to pitchof(). The function pitchof_b() applies the linear temperament scale if the global variable temperament is set. It updates the pointer pitchbend unless it was already set by a microtone. To store the pitchbend value of every note a new array bentpitch was added to the other arrays (pitch, num, denom, feature). The function event_note transfers the pitchbend value to bentpitch, so it can be used by writetrack() in the second pass (in genmidi). Other functions that had to be updated were doroll, dotrill, makecut, and doornament. genmidi.c : Added global array current_pitchbend[], which maintains the current pitchbend for each channel. It is initialized to 8192 (neutral value) by starttrack. The pitchbend value is now transferred to the function midi_noteon(). It will issue a pitchwheel command anytime a new pitchbend value occurs for the specific channel. Other functions like noteon_data() and save_note() also carry the parameter pitchbend. Limitations: linear temperament is not applied to guitar gchords. October 3 2006 Abc2midi: in order that microtones are applied correctly to in voice chords such as [CEG], it is necessary that each note in the chord be played on a separate MIDI channel. A new MIDI command "makechordchannels n" has been introduced for allocating MIDI channels specifically for the handling of chords. The value of n specifies the number of channels to be allocated. It should be one less the maximum number of notes in the chord. Note that since you have only 16 channels in a MIDI file and once the channel has been allocated it is unavailable for any other use. You need to do a separate allocation for each voice containing such chords. Implementation: In genmidi.c, introduced a global array chordchannels[] which is used to store the channel numbers for handling chords. chordchannel[0] is the channel number normally used for handling notes for that voice. Introduced a global integer nchordchannels storing the number of channels in chordchannels[]. Created a new function makechordchannels() for assigning these channels to chordchannels[]. Makechordchannels also sets the channels program (musical instrument) to the current program for the voice. (If you need to know the channel numbers that have been assigned, run abc2midi with the -v option (verbosity)). Created another branch in the function dodeferred() for handling the MIDI command makechordchannels(). October 15 2006 The following file was not parsed correctly. X:1 T: 2 or 3 tracks M: 3/4 L: 1/8 K:G g2| g2 fe b2| V:2 A2 |[B4E4] G2| Analysis: a bug I introduced recently resulted in the voice number (2) not being read correctly. Fix: in the function parsevoice() in parseabc.c, I changed the statement if (isnumberp(&s)) { to if (isnumberp(&s) == 0) { apparently, this function returns 0 if the string contains a positive number and 1 otherwise. October 27 2006 Abc2midi: using the command %%MIDI drumon causes the error MIDI read/write error : error: MIDI channel greater than 16 and abc2midi fails. This is another bug I had introduced. Adding the pitchbend parameter 8192 to save_note in function dodrus() in genmidi fixes this problem. October 27 2006 Abc2abc transpose places spurious spaces between notes breaking up the beaming pattern. For example for, X: 1 T: beaming error L: 1/8 M: 4/4 K: Eb ^C,,2 z2 z^C,/D,/ =E,/^F,/G,/=A,/ | B,/=A,/G,/^F,/ G,/=E,/^C,/D,/ E,/F,/G,/A,/ B,/A,/G,/A,/ | abc2abc beaming.abc -t 1 produces X: 1 T:beaming error L:1/8 M:4/4 K:Emaj ^^C,,2 z2 z^^C,/2 D,/2 ^E,/2^^F,/2 G,/2^A,/2 | B,/2^A,/2G,/2^^F,/2 G,/2^E,/2^^C ,/2 D,/2 E,/2 F,/2 G,/2 A,/2 B,/2 A,/2 G,/2 A,/2 | (note all the spaces between the notes in the second line of the body). Analysis: the local variable mult in event_note1() in toabc.c is used before it is defined. Fix: event_note1() now sets it to zero in case it is not set elsewhere. November 3 2006 Abc2midi bug: pitches are incorrect for staccato notes. eg X:1 T: staccato bug M:3/2 L:1/2 Q:1/4=70 %%MIDI program 16 %%MIDI nobeataccents K:C =B=c=d | .=B.=c.=d | The pitches of the last three notes have been affected by a pitchbend. Analysis: This is a bug I recently introduced. The bentpitch[] feature was not set to 8192 for staccato notes. Fix: added the following line bentpitch[notes] = active_pitchbend; before addfeature(NOTE, ...); in event_note() in store.c. Also added it in doornament(). November 3 2006 Abc2midi bug: the following file causes the error message MIDI read/write error : error: MIDI channel greater than 16 to appear. X:1 T: makechord M:3/2 L:1/2 Q:1/4=70 V:1 %%MIDI nobeataccents %%MIDI program 16 %%MIDI makechordchannels 2 V:2 %%MIDI program 16 %%MIDI makechordchannels 2 V:3 %%MIDI program 16 %%MIDI makechordchannels 2 K:C % V:1 [c'_/e'g'] V:2 [c_/eg] V:3 [C_/EG] Analysis: there was a missing parameter (bentpitch) in the function call to noteon_data() when channel == 9. As a result the function noteon_data() received a meaningless channel number. However, since channel 9 is reserved for percussion, it should never have been assigned. To fix this problem, the global variable channels[9] was set to 1 in writetrack() (genmidi.c), so that findchannel() will not select this channel. December 9 2006 Abc2midi bug: the %%MIDI drone command returns an error MIDI channel > 16. Fix: missing parameter in function midi_noteon(), pitchbend, was added. December 12 2006 Abc2midi bug: split voices does not work correctly when it is embedded in a part (eg. P:B). For example: X: 1 T: bad merge M: 4/4 L: 1/8 K: C P:A | C2 D2 E2 F2 | G2 A2 B2 c2 | P:B | C2 D2 E2 F2 & C,2 D,2 E,2 F,2 | G2 A2 B2 c2 | The split voice does not merge correctly in the above example. Analysis: not all voices may be indicated in a part. As a precaution, genmidi calls partbreak which fills in any missing voices. Unfortunately, split voices are automatically resynced which causes the voice to be filled in twice. Fix: a new global array dependent_voice[] was added in store.c and linked to genmidi.c. This array contains flags indicating where the particular voice was a natural voice created by a voice command (V:) or whether this is a split voice dependent on the natural voice. The function partbreak checks this flag and does nothing if is a dependent voice. December 21 2006 Voice bug (abc2midi, yaps): the fix described in September 9 2006 caused another bug. For the following example: X:1 T: noel M: 2/4 L: 1/4 K: C V: alpha C E|D F| V: beta A C| G B| The parser fails to handle nonnumeric voice numbers. Fix: in line 996 of parseabc.c isnumberp returns 1 if the character string is a positive number and 0 if it is not. The 0 was replaced with 1 as shown below. if (isnumberp(&s) == 1) { December 26 2006 Midi2abc bug. Some music notation programs automatically place short rests between notes and chords in order to improve the articulation. Midi2abc is able to ignore these rests using the -sr parameter as described in the midi2abc.1 documentation. Unfortunately, this feature does not work correctly when rests are placed in between chords. Analysis: the quantize() function decides whether to eliminate the rest based on the difference between the inter note interval (note->xnum) and the "on" time of the note (note->play). For some of the chordal notes, note->xnum is zero since all the notes in the chord start at the same time. This causes the program to produce erroneous results. Fix: a new function xnum_to_next_nonchordal_note() was introduced to look ahead past all the chordal notes and return the quantized note interval to the next nonchordal note. The quantize function uses this value when the -sr option is turned on. (I have a feeling this fix may not work correctly when the notes in the chord are not all equal length. In other words I do not recommend using the -sr option with -splitbars or -splitvoice.) January 02 2007 Abc2midi bug: %%MIDI trim does not work according to documentation. The trim command is used to control the articulation of notes. Like staccato it shortens the playing time of the note, leaving a silent period before the next note. According to the documentation the amount shortened should be the trim fraction time the unit note length. It turns out that the trim length was not adjusted for the unit note length so that the following example did not work. X:1 T: trim M: 2/4 L: 1/8 K: C %%MIDI trim 1/2 CDEF| Fix: store.c was modified so that trim value set is a fraction of the unit note length as defined by the L: field command. Note, that if the unit note length is changed again, it is necessary to reissue another trim command, eg. X:1 T: trim M: 2/4 L: 1/8 K: C %%MIDI trim 1/2 CDEF| L: 1/16 %%MIDI trim 1/2 CDEF CDEF CDEF CDEF| Otherwise the trim length will remain unchanged. January 06 2007 Abc2midi bug: wrong bar count when %%MIDI trim command mixed with chords. In the following example, X:1 T: Bad barcount M: 2/4 L: 1/8 K: C %%MIDI trim 1/2 AB CD |AC DF |[A2c2] DF | [AB]2 [CD]2 | Abc2midi produces the following warnings: Warning in line 9 : Bar 2 has 7/4 units instead of 2 Warning in line 10 : Bar 3 has 3/2 units instead of 2 Furthermore, this may throw off the gchord accompaniment if it exists. Fix: in writetrack for case CHORDOFF: and CHORDOFFEX:, the function addunits() is called before trim adjustment instead of after. March 15 2007 Abc2midi ends a MIDI track immediately after the last note. On some MIDI synthesizers, this introduces a small artefact at the end of the MIDI file. Fix, a short delay of 25 MIDI pulses is inserted before the end of track. This was incorporated in the function clearQ() in queues.c. Midi2abc -mftext mode was modified to report end of track meta command. December 09 2007 New feature in abc2midi: the program now recognizes the command %%propagate-accidentals not as described in http://abc.sourceforge.net/standard/abc2-draft.html directive 11.3 This command suppresses propagation of accidentals across a bar. The commands %%propagate-accidentals pitch or %%propagate-accidentals octave restores propagation. Presently only octave method is used. For example: M:2/4 L:1/8 K:Eb %%propagate-accidentals not A =A A2| A2 is flattened since the natural sign does not propagate. January 04 2008 Running yaps with the -E option to produce encapsulated postscript file (.eps) causes the program to crash with the error message *** glibc detected *** yaps: double free or corruption (!prev): 0x08d5f390 Analysis: the program attempts to close the output file twice. close_output_file was called once by printtune() (when it encountered a blank line) and again by event_eof() when it encountered an eof. The operating system does not set the filehandle to NULL after the file was closed defeating the conditional test in close_output_file. Fix: after closing the file the file handler is set to NULL. March 09 2008 Midi2abc: added a new option -title for providing the title of the tune to insert in the abc file. June 07 2008 Abc2midi: introduced a warning for chords containing unequal notes (eg. [c2e] will cause a warning to be issued). The warning was added in writetrack in genmidi.c. In order to get a reasonable output, the incorrect chord will be played as [c2e2]. (The length of the first note dominates.) June 13 2008 Abc2midi: produces a warning "Different length notes in tuple" when one of the notes in the tuple is a chord. eg. X:1 T: triplet chord M: 2/4 L: 1/16 K: D [DF]4 (3[B2d2]c2d2 | Analysis: the problem was traced to a bug in the function event_chordoff in store.c which was introduced with the chord syntax extension described in November 4 2004. In computing the tuple adjusted note length, the function always uses chord_n and chord_m parameters even when they do not apply (equal to 1/1). Fix new local variables c_m and c_n are introduced which are set to chord_n,chord_m or num[chordstart] and denum[chordstart] depending on whether the chord syntax extension is used or not. The tuplet adjusted note length is computed from c_n and c_m. It was also necessary to change event_note so that tuples are processed for chords too. June 14 2008 Abc2midi: ornaments (eg ~G3) does not work correctly for default length other than 1/8 (L: 1/8). Analysis, doornament (in store.c) assumes L:1/8 for dotted quarter notes. This was fixed. June 24 2008 Abc2midi: new feature. The %%MIDI drum line can sound quite monotonous if it is repeated each bar. To circumvent this problem a new MIDI command %%MIDI drumbars n where n is a small number will spread out the drum string over n consecutive bars. By default drumbars is set to 1 maintaining compatibility with existing abc files. You should take care that the drumstring is evenly divisible between the drumbar bars. Also the time signature should not change between bars in a drumbar unit. Sample usage: X:1 T: splitting a drum string into two bars M: 2/4 L: 1/8 K: G %%MIDI drum zdzdzdzd 39 59 50 60 %%MIDI drumon z4| z4| z4| z4| %%MIDI drumbars 2 %%MIDI drum zdzdzdzd 39 59 50 60 z4| z4| z4| z4| Implementation: All the changes were confined to genmidi.c Two new variables drumbars and drumbarcount are introduced. Drumbars modifies drum_denom in set_drums. (This changes the duration of a unit drum hit.) The function checkbar resets the drum_ptr every drumbars using the drumbarcount variable. July 2 2008 Regarding the drumbars implementation it is necessary to reset drumbarcount to 0 in writetrack after drumbars is initialized back to 1. July 17 2008 Abc2midi bug: the following sample causes abc2midi to issue a warning Warning in line 9 : Bar 0 has 10 units instead of 6 in repeat X:1 T: meter change M:5/8 L:1/8 K:C % |: [M:6/8] D6 &\ [M:6/8] E6 | [M:4/8] F4 :| Analysis: the warning is issued when writetrack is processing track 2 which is the split voice track during the repeat. The two [M:6/8] field commands ensure that the split voice track also sets the meter to 6/8 time. However the split voice track was not reset to [M:4/8] unless we do it explicitly with [M:4/8] F4 & [M:4/8] z4|. Store.c/sync_voices inserts a required rest z4 into bar 2 of the split voice but it does not include a time signature command which is needed to ensure that genmidi/checkbar will process the bar correctly. Fix: Added case TIME: addfeature(feature[j], pitch[j], num[j], denom[j]); /* copy feature */ break; /* [SS] 2008-07-17 */ into the code of sync_voices. July 17 2008 Abc2abc: removed the space between X: and the reference number. July 21 2008 Removed all static declarations in parseabc.c In parsekey(str) initialized the local string clefstr and modestr. July 21 2008 Abc2midi bug: key signature and accidental propagation applied to drum channel. In the following example, X:1 T: drum key M: 4/4 L: 1/8 K: A V:1 Z|ABcd efga| V:2 %%MIDI channel 10 G,, ^F,, z1 F,, E,, ^D,, z2|G,, ^F,, z1 F,, E,, ^D,, z2| voice 2 is assigned to the drum channel so the notes G,, ^F reference individual drum instruments rather than pitches. Since the key signature is A major (F#, C# and G#), event_note automatically raises G and F one semitone and propagates ^F across the bar. This is not desired for the drum channel. Fix: in store.c, a new variable, int drumchannel was added to struct voicecontext. It is initialized to 0. When event_specific handles a %%MIDI channel 10, drumchannel is set to 1. For other channels it is set to 0. A new function barepitch() was created from the function pitchof_b. This function does not apply the key signature or note propagation. The function event_note now checks whether v->drumchannel is set and calls barepitch() instead of pitchof_b() in such circumstances. (See Cuckoo's Nest in demo.abc for a sample.) August 4 2008 Midi2abc: new feature. The -mftext prints the name of the drum patch for channel 10 and noteon commands. August 11 2008 Abc2midi bug: The following abc file cause abc2midi to halt with a segmentation error. X:1 T: trim problem M:3/4 L:1/4 %%MIDI trim 1/8 K:C ABC|DEF| Analysis: the error occurs in event_specific when the function addfeature(SETTRIM, 1, 4*a, b*v->default_length); is called. The voice structure does not exist causing a segmentation error when v->default_length is addressed. (v does not exist until the body of the abc file.) Fix: if v does not exist, addfeature(SETTRIM,...) get the default_length from global.default_length. Comment: event_refno creates the voice structure and then destroys it when it calls startfile(). This does not cause a problem but makes the code obscure. August 12 2008 Another abc2midi trim bug: the following warnings are Warning in line 9 : unequal notes in chord 7/8 versus 1/1 Warning in line 9 : unequal notes in chord 3/4 versus 1/1 are the produced from this file. X:1 T: trim problem M:3/4 L:1/4 K:C %%MIDI trim 1/8 %%MIDI makechordchannels 2 CD[ABc]| Analysis: the problem was traced to the function writetrack in genmidi.c. The note length is trimmed inside the switch case for NOTE:. The length of the trimmed note is saved and trimming is reapplied to this length for each note of the chord. This bug was probably introduced in June 7 2008 in order to make the the first note in a chord to dominate. Fix: new variables tnote_num and tnote_denom are introduced specifically for note trimming. August 12 2008 Still another abc2midi trim bug. For split voices, the notes are trimmed in only one voice. In the following example, the notes CDE are trimmed but not EFG. X:1 T: another trim problem M:3/4 L:1/4 %%MIDI trim 1/8 %%MIDI makechordchannels 2 %%MIDI program 20 K:C CDE & EFG| Fix: another case statement SETTRIM: was added to sync_voice() in store.c Note that %%MIDI trim command only applies to a single voice. September 17 2008 Abc2midi bug: wrong bass note when expanding guitar chord with inversion. The bass note should be the note after the / rather than the pitch of the chord. Thus "C/E" should be represented by E,,x [G,E,C,] rather than C,,x [G,E,C]. Fix: case 'f' in function dogchords() in genmidi.c no tests for an inversion. If an inversion is indicated, the bass note is changed. September 18 2008 Abc2midi new feature: added the run time option (-NCOM) to suppress some textual comments in the output midi file. September 24 2008 Abc2midi bug: for multitune abc files, the temperament is not automatically turned off at the start of the next tune. Fix: temperament is initialized to zero in startfile() in store.c September 24 2008 Abc2midi new behaviour: the 'strange note' in a gchord is no longer included in the chord. (i.e. F/G is now expanded as G,, [F,A,C] instead of G,, [G,,F,A,C]. (Suggested by H. Lacerda). Change made in configure_gchord() in genmidi.c September 28 2008 Abc2midi bug when selecting tune from collection. When the abc2midi is used to create a single MIDI file from an abc file containing a collection of tune which contains %%MIDI commands, abc2midi numerous warnings 'cannot handle this MIDI directive here' for the non-selected tunes. For example abc2midi balk2.abc 237 -v Reference X: 180 Warning in line 9 : cannot handle this MIDI directive here Reference X: 181 Warning in line 34 : cannot handle this MIDI directive here Warning in line 35 : cannot handle this MIDI directive here Warning in line 36 : cannot handle this MIDI directive here Warning in line 37 : cannot handle this MIDI directive here Reference X: 182 [snip] This obscures real warnings from the selected tune. Analysis: the messages are issued by event_specific_in_header() which was designed to process MIDI commands which appear before the first tune (X: refno), in the file. The function is called when dotune == 0, which is true for unselected tunes. This means that some of the directives in the nonselected tunes (e.g. nobarlines, fermatafixed, ...) can affect the selected tune. Furthermore, some other MIDI directives which are not recognized by the function cause the above warnings to occur. In the following example (headercommands.abc), %%MIDI nobarlines X:1 T: tune 1 M: 2/4 K:G %%MIDI barlines %%MIDI program 100 X:2 T: tune 2 M: 2/4 K: F etc. the directive %%MIDI nobarlines appearing before the first tune is to apply to all tunes in the abc file except where specifically overrided (in tune 1). When we run abc2midi headercommands 2 we are expecting %%MIDI nobarlines to apply to tune 2. However, this was changed in the nonselected tune 1 and the %%MIDI program 100 command causes the message 'cannot handle this MIDI directive here'. Fix: a new global variable started_parsing initialized to zero was introduced in store.c. When event_refno is invoked, the variable started_parsing is set to 1. The function event_specific_in_header is called only if started_parsing is still 0. February 20 2009 Yaps bug. The -E option (for encapsulated postscript) does not compute the boundingbox correctly if the abc file contains note fields (N:). eg. X:1 T:A test N:A note K:C AB cd ef ga | \ AB cd ef ga | \ AB cd ef ga | \ AB cd ef ga | AB cd ef ga | \ AB cd ef ga | \ AB cd ef ga | \ AB cd ef ga |] The bottom part of the last staff is cutoff. Analysis: the function tuneheight() in drawtune.c did not account for space used by the note fields. Fix: added several lines of code to the function to scan through the notefield list and adjust the page height. March 17 2009 Abc2midi new feature: a new command %%MIDI gchordbars n was introduced that acts in the same manner as %%MIDI drumbars (see June 14 2008). but applies to the gchord string instead. The command spreads the gchord string over n consecutive bars. In the following example: X:1 T: gchordbars M: 2/4 L: 1/8 K: C %%MIDI gchordbars 2 %%MIDI gchord fzczIzHz "C" c2 "G" c2|"C" g4|"G"c4|g4| fzcz applies to bars 0 and 2 while IzHz applies to bars 1 and 3. For this function to work properly, it is important that the length of the gchord string be exactly divisible by n where n is the number of bars that the gchord string applies to. If gchordbars is not specified, it is assumed to be one bar. Implementation is similar to drumbars. New variables gchordbars and gchordbarcount were introduced in genmidi.c June 23 2009 Abc2midi does not attempt to fill in missing left repeats |: in multipart and multivoiced files. New code was introduced to solve this problem. The functions scan_for_missing_repeats(), add_missing_repeats(), clear_voice_repeat_arrays() was added to store.c. July 22 2009 Abc2midi produces irrelevant error messages %%MIDI drumon must occur after the first K: header when extracting a particular tune in a file containing a collection, eg. abc2midi balk1.abc 10 Fix: in event_specific() in store.c now check the flag dotune. if (strcmp(command,"drumon") == 0 && dotune) { addfeature(DRUMON, 0, 0, 0); etc. July 22 2009 Abc2midi produces the error message found another |: after a |: for the file X:1 T:title M:4/4 L:1/4 K:C A2 c2 :: d2 c2 :| Fix: set bar_rep_found[voicenum] = 1 after inserting missing BAR_REP. September 20 2009 Abc2midi bug: the following file produces a faulty midi file. X:1 T: bug M: 4/4 L: 1/4 K: G V:1 %%MIDI control 7 49 C4|\ %%MIDI control 7 48 C4|\ %%MIDI control 7 47 C4|\ %%MIDI control 7 46 C4| %%MIDI control 7 45 Analysis: As seen below track 1 which contains only control codes is 56 beats long while track 2 which contains the notes is only 16 notes. The control codes in track 1 are not placed at the correct times. ur@localhost abc]$ midi2abc err1.mid -mftext Header format=1 ntrks=2 division=480 Track 1 contains 57 bytes 0.00 Metatext tempo = 120.00 bpm 0.00 Metatext key signature G (1/0) 0.00 Metatext time signature=4/4 0.00 Metatext (Seqnce/Track Name) bug 0.00 CntlParm 1 Volume = 49 4.00 CntlParm 1 Volume = 48 12.00 CntlParm 1 Volume = 47 24.00 CntlParm 1 Volume = 46 40.00 CntlParm 1 Volume = 45 56.05 Meta event, end of track Track 2 contains 67 bytes 0.00 Metatext (Seqnce/Track Name) bug 0.00 CntlParm 1 Volume = 49 0.00 Note on 1 c4 105 4.00 Note off 1 c4 0 4.00 CntlParm 1 Volume = 48 4.00 Note on 1 c4 105 8.00 Note off 1 c4 0 8.00 CntlParm 1 Volume = 47 8.00 Note on 1 c4 105 12.00 Note off 1 c4 0 12.00 CntlParm 1 Volume = 46 12.01 Note on 1 c4 105 16.00 Note off 1 c4 0 16.01 CntlParm 1 Volume = 45 16.06 Meta event, end of track Explanation: when abc2midi produces a type 2 MIDI file (multitracks), track 1 only contains comments, time signature and control codes while the other tracks contain the actual note-on/note-off codes corresponding to the different voices. When abc2midi produces a type 1 MIDI file corresponding to the bare bones abc file (no voices or accompaniment), then there is only one track and all note-on/note-off commands are in the same track. For historic reasons, MIDI control codes are placed in both track 1 and track 2 for voice 1, and the control codes for the other voices are put into their own track. (I dare not change this since it could cause a problem somewhere else.) However, there appears to be a bug since the times of the control codes seem to be incorrect. Fix: I reset delta_time to 0 at the end of the function genmidi.c/dodeferred(). It seems to fix the problem. October 23 2009 Abc2midi bug: the function dograce fails to adjust the length of the host notes in a chord. In the following example X:1 T: grace chord problem M: 2/4 L: 1/8 K: C A2 B2|{edc}[cg]2 d2| The chord [cg]2 is not shortened by the length of the grace note {edc}; however if the chord is expressed as [c2g2] the chord is shortened correctly. Analysis:the function applygrace_new() in store.c fails to recognize the CHORDOFFEX feature which is used to express chords of this type. Fix: the function now checks for that feature. December 12 2009 Abc2midi bug: dynamics (eg !pp!) deletes previous rest. In the following example: X:1 T: dynamic problem M:4/4 L:1/4 K:C |ABcd|Az3|!pp!dcBA|] The rest z3 is destroyed by the !pp! indication. Analysis: this bug was introduced on September 20 2009 when delta_time was reset to 0 in dodeferred(). Fix, a global variable rest_pending was added to indicate that a rest has not yet been instantiated in the MIDI file and not to reset delta_time. The variable rest_pending is set to zero for every NOTE, TNOTE or CHORDON feature but set to 1 for a REST feature. **note** this change was undone Feb 4 2010 December 18 2009 Abc2midi bug: split voices (also known as voice overlay) works incorrectly when there are in repeats. For example X:1 T: voice overlay in repeats M: 2/4 L: 1/4 K: G |:C D &b/c/d/e/| F G:| used to work but now does not repeat the voice overlay. (It does not matter whether an opening repeat |: is present.) However, if you put a V:1 after K:G as shown here X:1 T: voice overlay in repeats M: 2/4 L: 1/4 K: G V: 1 |:C D &b/c/d/e/| F G:| it then works correctly. Analysis: this is a new bug that was introduced after the changes on June 23 2009. The function scan_for_missing_repeats corrupts the feature arrays. Here is the feature arrays just before calling scan_for_missing_repeats. 0 LINENUM 2 0 0 0 1 TITLE 0 0 0 0 2 LINENUM 3 0 0 0 3 LINENUM 4 0 0 0 4 LINENUM 5 0 0 0 5 DOUBLE_BAR 0 0 0 0 6 LINENUM 6 0 0 0 7 MUSICLINE 0 0 0 0 8 BAR_REP 0 0 0 0 9 NOTE 60 8192 1 1 10 NOTE 62 8192 1 1 11 SINGLE_BAR 0 0 0 0 12 VOICE 2 0 0 0 13 DOUBLE_BAR 0 0 0 0 14 BAR_REP 0 0 0 0 15 NOTE 83 8192 1 2 16 NOTE 72 8192 1 2 17 NOTE 74 8192 1 2 18 NOTE 76 8192 1 2 19 SINGLE_BAR 0 0 0 0 20 VOICE 1 0 0 0 21 NOTE 66 8192 1 1 22 NOTE 67 8192 1 1 23 REP_BAR 0 0 0 0 24 VOICE 2 0 0 0 25 REST 0 0 2 1 26 REP_BAR 0 0 0 0 27 VOICE 1 0 0 0 28 MUSICSTOP 0 0 0 0 29 LINENUM 7 0 0 0 30 VOICE 2 0 0 0 31 SINGLE_BAR 0 0 0 0 Here is the feature array afterwards. 1 TITLE 0 0 0 0 2 LINENUM 3 0 0 0 3 LINENUM 4 0 0 0 4 LINENUM 5 0 0 0 5 DOUBLE_BAR 0 0 0 0 6 LINENUM 6 0 0 0 7 MUSICLINE 0 0 0 0 8 BAR_REP 0 0 0 0 9 NOTE 60 8192 1 1 10 NOTE 62 8192 1 1 11 SINGLE_BAR 0 0 0 0 12 VOICE 2 0 0 0 13 DOUBLE_BAR 0 0 0 0 14 BAR_REP 0 0 0 0 15 NOTE 83 8192 1 2 16 NOTE 72 8192 1 2 17 NOTE 74 8192 1 2 18 NOTE 76 8192 1 2 19 SINGLE_BAR 0 0 0 0 20 VOICE 1 0 0 0 21 NOTE 66 8192 1 1 22 NOTE 67 8192 1 1 23 BAR_REP 0 0 0 0 24 REP_BAR 0 0 0 0 25 VOICE 2 0 0 0 26 REST 0 0 2 1 27 REP_BAR 0 0 0 0 28 VOICE 1 0 0 0 29 MUSICSTOP 0 0 0 0 30 LINENUM 7 0 0 0 31 VOICE 2 0 0 0 32 SINGLE_BAR 0 0 0 0 Note that feature BAR_REP was placed at 23 immediately before REP_BAR. The problem is that the first VOICE 1 feature was found after the first bar was processed and a split voice (VOICE 2) was generated. scan_for_missing_repeats automatically places a BAR_REP 3 indices past (24) the VOICE 1 (20) command which it expects to be before the first note. This messes up the feature array. If the abc file has a V:1 after the K: then the BAR_REP is placed at the right place. Fix: Always place a VOICE 1 command after the first K: in the abc file. In event_key (store.c) addfeature(VOICE, ...) after getvoicecontext(1) if not inside body of abc file. (There may be a K: indication inside another voice and we do not want to automatically switch to VOICE 1.) ***This change was removed on December 21 ***. December 20 2009 abc2midi bug: X:1 T: embedded V: command and voice overlay %%MIDI program 2 41 K:C [V:1] | cde2 & egc'2 | C8 & z4 e'4 | c8 :| [V:2] |C,D,E,2 | C,,8 | C,8 :| the voice overlay gets garbled but if we write V:1 | cde2 & egc'2 | C8 & z4 e'4 | c8 :| V:2 |C,D,E,2 | C,,8 | C,8 :| it works fine. In scan_for_missing_repeats changed add_leftrepeat_at[num2add] = voicestart[voicenum]+3; to add_leftrepeat_at[num2add] = voicestart[voicenum]+2; December 21 2009 abc2midi bug: abc2midi fails to convert the simple file X:1 T: one track M: 2/4 L: 1/4 K: C CD|EF|GA|Bc| Fix: removed insertion of VOICE feature after the event_key. instead event_key remembers the location to place a VOICE feature in the variable v1index in case a event_split_voice is encountered and voicesused is 0. January 05 2010 abc2midi bug: loss of voice synchronization when stacatto, chords and dynamics mixed. In the following example, X:1 T:staccato and dynamics M:4/4 L:1/8 K:G V:1 C4 G4|A4 G4| V:2 [.D4.G4]!p!C2C2|D4F4| the chord [.D4.G4] is one beat two short causing a loss of synchronization between the two voices. However if abc2midi is run with the option -NFNP which causes abc2midi to ignore the dynamic indication !p!, the voices remain in synchronization. Analysis, the stacatto markings embedded in a chord causes a REST feature to be embedded in the chord. 21 CHORDON 0 0 0 0 22 REST 62 0 2 1 23 NOTE 62 8192 1 1 24 NOTE 67 8192 1 1 25 CHORDOFF 0 0 2 1 normally a stacatto places the rest after the shortened note but for chords it is done differently. (It is rather unusual to find stacatto markings inside a chord.) Nevertheless, the notes are still played with the rest following. (Another quirk of abc2midi.) Fix: in writetrack() (genmidi.c) rest_pending is no longer reset to 0 if the note is inside a chord. **note** this change was undone Feb 4 2010 January 06 2010 Abc2midi new feature: a missing Fermata in a multivoiced tune can cause a loss of synchrony between the voices. As an aid in detecting this problem, a new run parameter was introduced. -NFEM will cause abc2midi to ignore all fermata markings in the abc tune. Implementation: introduced a new global variable ignore_fermata which is normally set to 0 into store.c. If it is nonzero, then decorators[FERMATA] is ignored. January 10 2010 Abc2midi new feature: though abc2midi should shorten the notes preceded by a grace sequence in some circumstances it may fail to shorten it the right amount causing the voice track to lose synchrony with the other tracks. As an aid to detecting this problem, a new run parameter was introduced. -NGRA will cause abc2midi to ignore all notes in a grace sequence (enclosed in curly brackets {}). Implementation: a new global variable ignore_gracenotes (normally set to 0) was introduced in store.c. If both ignore_gracenotes and gracenotes are nonzero, then event_note ignores the current note. January 14 2010 Abc2midi bug: the -NGRA option messes up the output abc file for the following example. Track 2 is shorter than track 1. X:1 T:-NGRA option makes a mess L:1/2 M:2/2 K:C V:1 |: {d-}[de]f|ga :| V:2 |: {E-}[EF]G|AB :| Analysis: (You should review the operation of dotie and tiefix as described in this file at February 12 2005. Note the many other problems that were encountered with this code.) Before calling tiefix, the feature array looks as follows. (gdb) call dumpfeat(0,notes) 0 LINENUM 3 0 0 0 1 TITLE 0 0 0 0 2 LINENUM 4 0 0 0 3 LINENUM 5 0 0 0 4 LINENUM 6 0 0 0 5 DOUBLE_BAR 0 0 0 0 6 LINENUM 7 0 0 0 7 VOICE 1 0 0 0 8 LINENUM 8 0 0 0 9 MUSICLINE 0 0 0 0 10 BAR_REP 0 0 0 0 11 GRACEON 0 0 0 0 12 TIE 0 0 0 0 13 GRACEOFF 0 0 0 0 14 CHORDON 0 0 0 0 15 NOTE 74 8192 2 1 16 NOTE 76 8192 2 1 17 CHORDOFF 0 0 2 1 18 NOTE 77 8192 2 1 19 SINGLE_BAR 0 0 0 0 20 NOTE 79 8192 2 1 21 NOTE 81 8192 2 1 22 REP_BAR 0 0 0 0 23 MUSICSTOP 0 0 0 0 24 LINENUM 9 0 0 0 25 VOICE 2 0 0 0 26 LINENUM 10 0 0 0 27 MUSICLINE 0 0 0 0 28 BAR_REP 0 0 0 0 29 GRACEON 0 0 0 0 30 TIE 0 0 0 0 31 GRACEOFF 0 0 0 0 32 CHORDON 0 0 0 0 33 NOTE 64 8192 2 1 34 NOTE 65 8192 2 1 35 CHORDOFF 0 0 2 1 36 NOTE 67 8192 2 1 37 SINGLE_BAR 0 0 0 0 38 NOTE 69 8192 2 1 39 NOTE 71 8192 2 1 40 REP_BAR 0 0 0 0 41 MUSICSTOP 0 0 0 0 42 LINENUM 11 0 0 0 43 SINGLE_BAR 0 0 0 0 Note that that there is a TIE feature enclosed in the GRACEON and GRACEOF area but there is no NOTE or REST preceding. This is because we ran abc2midi with -NGRA which had removed all the notes enclosed by the grace complex. When dotie, attempts to process the TIE at 12 it fails to find a NOTE or REST and exits; however when dotie attempts to process the TIE as 30, it finds a NOTE in a different voice at position 21 and all hell breaks loose a big mess. Fix: to prevent dotie from searching for a NOTE or REST in a previous voice, we cause a break when feature[TIENOTE] == VOICE. while ((tienote > 0) && (feature[tienote] != NOTE) && (feature[tienote] != REST)) { tienote = tienote - 1; if (feature[tienote] == VOICE) break; /* [SS] 2010-01-15 */ }; to prevent a TIE from appearing in the first place in a grace complex when -NGRA was specified we add if (gracenotes && ignore_gracenotes) return; /* [SS] 2010-01-12 */ in the event_tie() function. January 23 2010 Code clean-up to remove the numerous warnings when compiling with the -Wall compilation flag. genmidi.c, mftext.c, midifile.c, midifile.h, and store.c were modified. There are still a few warnings to be checked out later. February 01 2010 Code clean-up. Removed unused functions -- slurtotie(), applybroken(), and delendrep() in store.c. February 01 2010 Abc2midi: support for multivoiced lyrics introduced. The following tune illustrates multivoiced lyrics. X:1 T:multivoiced lyrics M:2/4 L:1/16 K:C V:1 clef=treble V:2 clef=treble %%staves 1 2 V:1 C4 C4 | E4 G4 | c8 |] w: 1 2 3 4 5 V:2 C4 E4 | C4 B,4 | C8 |] w: 11 12 13 14 15 A warning "More than one voice with words in" appears. Though the MIDI file plays properly, the lyrics do not appear correctly in MIDI file players such as Melody Player. It was necessary to some significant changes to the way the information in the w: field is transferred to the MIDI file in order to ensure compatibility. This section describes how abc2midi treats the w: field in order to incorporate lyric text into a karoake style MIDI file. For multivoiced abc files, abc2midi only handles the lyrics in the first voice. There is interest in generalizing the program so that it can handle lyrics in multiple voices which are common in choir music. Parsing stage (store.c) ------------------------ All lyric text is copied into string array called words char** words; which is allocated by checkmalloc(maxwords*sizeof(char) where maxwords is set to INITWORDS 20. Each time a w: field is encountered, event_words() in store.c is invoked and places the string of text in the w: into words[wcount] where wcount is incremented. A new feature, WORDLINE is added to the feature array. The index wcount is saved in the pitch[] component of the feature arrays. If there is no continuation, of the w: command, then a WORDSTOP feature is added to signal the end of the w: field. In the event that the wcount index reaches maxwords, the function textextend() doubles the allocated space in words[] and doubles maxwords. event_words() also verifies that the lyrics originate from only one voice. Creation of the MIDI file (genmidi.c) ------------------------------------- Genmidi records the MIDI tracks using the function writetrack() which is called by mfwrite() in midifile.c. Mfwrite() was called by finishfile() in store.c There is no one to one correspondence between voices and MIDI tracks. Some voices may have two tracks. A voice containing lyrics is mapped into two tracks, one for the notes and another for the words. Two semaphores, wordson and noteson signal writetrack whether to record only the words, only the notes or both in the track. When writetrack scans through all the features in the feat array for the specific voice, the NOTE: and TNOTE: blocks inscribe the words or notes in the MIDI file depending on the status of the wordson and noteon semaphores. The gchord accompaniment is placed in a separate track, gchordtrack which was set by finishfile() in store.c. The voice containing the gchord indications is passed frome store.c to genmidi.c by means of the variable gchordvoice. The same applies to drumtrack and dronetrack which rely on drumvoice and dronevoice to establish the synchronization. The voice structures used in store.c are not passed to genmidi.c. All the information for writing the MIDI tracks come from the above semaphores and the feature,pitch,num,denom arrays which were passed from store.c. Genmidi does not know whether it is writing a split voice track (voice overlay) or a regular voice track. They both look the same. Genmidi must know the number of tracks in the MIDI file since this is recorded in the header chunk of the MIDI file. The current design of writetrack() assumes that if a lyrics track exists it must be in track 2 (counting from zero). There can be only one lyric track. To allow more than one lyric track (or voice containing lyrics), to allow a track to have notes as well as words embedded requires passing more information to genmidi. For instance we need to know whether a particular track should record lyrics or notes, and which voice number is the source. Changes: ------- Created a new function dump_voicecontext() in store.c which prints out the descriptors of all the voice contexts. Created a new structure trackstructure in store.c struct trackstruct {enum {NOTES, WORDS, NOTEWORDS, GCHORDS, DRUMS, DRONE} tracktype; int voicenum; }; and a new array Created struct trackstruct trackdescriptor[40]; which will be shared with genmidi.c Created a new function setup_trackstructure() in store.c which modifies trackdescriptor[]. Modified writetrack() in genmidi.c so that it can write more than one lyric track. Introduced an option to write lyrics in either the same track as the notes or else in a separate track (-STFW). Added "int hasdrums" to voice structure in store.c. Added "int hasdrone" to voice structure in store.c Cleaned out dronevoice, drumvoice, dronetrack, drumtrack, gchordvoice, gchordtrack variables from store.c and genmidi.c Removed warning "More than one voice with guitar chords in" One of the benefits of the new organization is that now you can have drums and gchords in more than one voice as shown in the following examples X:1 T: double gchords M: 2/4 L: 1/8 K: C V:1 %%MIDI chordprog 1 %%MIDI gchord fffff "G" z4|z4| V:2 %%MIDI chordprog 90 %%MIDI bassprog 90 %%MIDI gchord ghii "G" z4|z4| X:1 T: drums in two voices M: 2/4 L:1/8 K: C V:1 %%MIDI drum dddddddd 35 36 37 38 35 36 37 38 %%MIDI drumon |G4|G4| V:2 %%MIDI drum d2d2 40 41 %%MIDI drumon |C2D2|EFGA| February 04 2010 Abc2midi bug: the following tune is not converted correctly and the drone is not heard. X: 129 T: Drone Bug M: 2/4 L: 1/8 K: Gdor Q:1/4=140 G\ %%MIDI drone 109 67 67 50 50 %%MIDI droneon %%MIDI program 41 | c2 c2 |(3cBA GB|c2 c2 |(3cBA GB | %%MIDI program 111 %%MIDI droneoff Analysis: this yet another bug introduced by the change in dodeferred (September 20 2009). (See also December 12 2009 and Jan 05 2010). Fix: in dodeferred replaced the lines /********* delta_time = 0L; [SS] 2009-09-20 [SS] 2009-12-12*/ if (!rest_pending) delta_time = 0L; /* [SS] 2009-12-12 */ with if(wordson+noteson+gchordson+drumson+droneon == 0) delta_time = 0L; This is a better fix to the bug addressed on September 20 2009. Removed the variable rest_pending and all references in genmidi.c February 07 2010 Abc2midi: segmentation errors when applying abc2midi on a large collection of tunes in an abc file. Analysis: two array index out of bounds problems were identified in store.c. The variable num2add was not reset to 0 in the function scan_for_missing_repeats() causing the array add_leftrepeat_at[100] to overrun when a large collection of tunes is processed. (Also many spurious BAR_REP's are inserted into the feature[] array.) A separate problem caused by insertion of BAR_REPs is that the part_start[] array no longer points to the correct location of the PART feature in the feature[] array. This causes fillvoice() to induce a segmentation error because partlabel contains bad data. Fix: (1) reset num2add to 0 in scan_for_missing_repeats(), (2) add_missing_repeats() also increments the addresses in part_start[] after each insert in the feature[] array. As a precaution, fillvoice() in genmidi() reports an error if variable partlabel is out of bounds. As a precaution v1index is also reset to -1 and splitdepth set to 0 in startfile(). February 09 2010 Abc2midi bug: drum voice fails to materialize in this tune. X: 30 T: Drum fails to materialize M: 8/4 L: 1/8 Q: 1/4=120 K: D octave=1 %%MIDI program 74 %%MIDI drum dzdzdzdzzzzzzdddd 41 43 41 43 45 45 45 45 |:z2g2e2c2 gagfe2c2|\ %%MIDI drumon z2g2e2c2 gagfe2c2| c2^d2e2ga g2^d2ccg2|\ c2^d2e2ga g2^d2ccc2:| Analysis: setup_trackstructure() sets the number of tracks to 1 if there is no drumvoice, gchordvoice, karaoke, or dronevoice. Unfortunately drumvoice was not set when %%MIDI drumon was encountered. Fix: drumvoice is set to v->indexno when %%MIDI drumon is found. February 23 2010 Abc2midi lyric bug: abc2midi does not treat the double hyphen in the w: line. In the following example X:1 T: lyric bug M: 5/4 L: 1/4 K: G cdefg w:one two--three four the word four should be under the g note not f. Analysis: the problem occurs in the function getword() in genmidi.c. After processing a syllable the second 'while loop' skips over all following control codes. It should increment syllcount when it encounters a hyphen so that another note will be skipped. February 23 2010 Abc2abc does not copy s: and d: (symbols and decoration lines) but instead puts a blank line. In the following example: X: 2 T:Aaron's (Rarified) Air M:4/4 L:1/4 K:G D|"G"DG "D7"FA|"G"G2 DD|G3/2A/2 Bc|\ d3d|"C"e3/2d/2 ce|"G"d3/2c/2 Bd|"Am"cB AG|\ s: .. .... .... .... "D7"FG AD| abc2abc example.abc abc2abc aaron.abc -t 2 X:2 T:Aaron's (Rarified) Air M:4/4 L:1/4 K:Amaj E|"A"EA "E7"GB|"A"A2 EE|A3/2B/2 cd|\ e3e|"D"f3/2e/2 df|"A"e3/2d/2 ce|"Bm"dc BA|\ "E7"GA BE| Fix: added event_field(key, place) to case 'd' and case 's' in parsefield(key,field) in parseabc.c. March 27 2010 - contributed by Bas Schoutsen abc2midi now reads w: lines starting with hyphens, example: X:1 K:C A w:la- BcdA w:---la X:2 K:C A w:la-- BcdA w:---- BcdA w:--la Fix: introduced new global variable hyphenstate in genmidi.c/getword(). April 08 2010 contribution by Bas Schoutsen Abc2midi lyric bug: tied notes at the end of the line shifts the lyrics one place further ahead in the following example. X:1 T: tie 2 M:4/4 L:1/4 K:C cdef-| w:c d e x- fgag w:-g a g Fix: in genmidi.c a new global variable onemorenote were introduced plus additional code in getword() and checksylables() to handle the situation. April 15 2010 Abc2midi: incompatibility with Melody Player, MidiNotate, NoteWorthy Player and other commercial products. In the following example, X:1 T:Zijn niet de tien gereinigd C:Willem Vogel M:C| K:C z4z2A2|[M:5/4]c4A2A2A2|[M:3/4]c4A2|[M:5/4]d4B2B2B2|[M:C|]e4A4|d4G4|c4B2A2|G6G2|A4E2E2|G4D4|E4F4|D8-|D8-|!fermata!D8|] the time signature 5/4 is placed at the beginning instead of the second measure. Analysis, the MIDI meta Text event Time signaturea= 5/4 is placed at MIDI Time = 1919 instead of MIDI Time = 1920. Apparently, when the MIDI Player performs the division 1919/480 (where 480 is the number of divisions per beat) the result is truncated instead of rounded. Fix, in set_meter(n,m) defined in genmidi.c, the last statement was changed to mf_write_meta_event(delta_time, time_signature, data, 4); (delta_time replaces 0L.) **Note** this change was retracted on July 07 2010 and a different fix was introduced. April 21 2010 Abc2midi bug: The fix described on April 15 2010 introduced a more serious bug. In the following example X: 15 T: Accompaniment starts at the wrong time M: 2/4 L: 1/8 K: Am %%MIDI program 57 | CDEF|CDEF| CDEF|CDEF| M:2/4 %%MIDI drum dddz 35 48 60 %%MIDI drumon %%MIDI gchord fczz %%MIDI bassvol 40 %%MIDI chordvol 40 |"D" dcBd |d2B2 |cBAc |B2A2 |\ z2d2- |d2B2 |c4 |B2A2 | Both the drum and chordal accompaniment start 4 bars late. If the second M:2/4 indication is left out, the accompaniment starts at the correct time. Fix: in set_meter() the change if (noteson) /* [SS] 2010-04-21 */ mf_write_meta_event(delta_time, time_signature, data, 4); /* [SS] 2010-04-15 */ else mf_write_meta_event(0L, time_signature, data, 4); /* [SS] 2010-04-15 */ seems to fix the problem. **Note** this change was retracted on July 07 2010 and a different fix was introduced. May 08 2010 Abc2midi new feature: the abc draft standard 2.0 http://abc.sourceforge.net/standard/abc2-draft.html#K:%20-%20key allows one to explicitly define all accidentals of a key signature using the notation K: exp Thus K:DPhr ^f could also be notated as K:D exp _b _e ^f where exp is an abbreviation for explicit. The standard states that the notes should be in lower case; however, as a compatibility measure with abcm2ps upper case notes are also allowed with this feature. Fix: in parseabc.c (parsekey) checked for string "exp" and set a new variable explict to 1 if the string is present. Added the variable explict to the function event_key(..) which is defined in store.c, toabc.c, yapstree.c, matchsup.c, and parseabc.h. Note the applications abc2abc, yaps, abcmatch do not support this feature presently. May 20 2010 Abc2midi in compatiblity. For the following example X: 1 T: Araber tants R: Terkish M: C L: 1/8 K: Dphr ^F D2 "A"\ | "D"FGA2 A2A2 | "Gm"B6 AG | "D"^FGA2 "Eb"BAGA | "D"GF3 z2D2 | abc2midi ignores ^F in the K: field command. The draft 2.0 standard states that modifiers should be in lower case. Thus the K: field should be written as K: Dphr ^f Since abcm2ps allows upper case modifiers too and distinguishes them, I now allow both upper and lower case modifiers. Fix: commented out if (expict) in parseabc/parsekey(). This also maintains compatibility with various Klezmer transcriptions. May 21 2010 Abc2midi bug: abc2midi crashes when the -c option (checking only) is selected. eg. abc2midi test.abc -c Floating point exception Analysis: division by zero occurs when set_meter(header_time_num, header_time_denom) because both input parameters are zero. These parameters are not set when the c option is selected. Fix: in finishfile() (store.c) set header_time_num and header_time_denom when check is set. if (check) { Mf_putc = nullputc; header_time_num = time_num; /* [SS] 2010-05-21 */ header_time_denom = time_denom; /* [SS] 2010-05-21 */ May 24 2010 Abc2midi compatibility bug: the key signature K:C^f^c is not parsed correctly. (Such indications occur in many Klezmer tunes.) Analysis: parsekey (in parseabc.c) expects a space separating the key signature modifiers ^f and ^c. Fix: readword() in parseabc.c was changed so that it splits a string when it encounters '^' and '_' as well as '='. May 26 2010 Abc2midi crashes with a segmentation error for file demo.abc (included with abcMIDI package) when run on any specific tune eg. [seymour@localhost abc]$ abc2midi demo.abc 2 writing MIDI file demo2.mid Segmentation fault Analysis: abc2midi scans the entire demo.abc file. When it encounters %%MIDI drumon in tune 7, it attempts to set v->drumon = 1. The v structure has not been allocated, so a null pointer is encountered. Fix: also tested the variable dotune in the following test if (strcmp(command,"drumon") == 0 && dotune) { /* [SS] 2010-05-26 */ in event_specific, in store.c. May 31 2010 Abc2midi does not process K: field when key is missing but sharps and flats are indicated explicitly. This typically occurs in some Klezmer tunes. In the following example X:1 T:explicit key M:2/4 L:1/8 K:^c^d^e CDEF|DEGA| abc2midi returns the messages Error in line 5 : First K: field must specify key signature Warning in line 6 : Ignoring text: CDEF|DEGA| Error in line 7 : No valid K: field found at start of tune and does not produce a MIDI file Analysis: the messages are produced when parsekey returns a zero value for the flag gotkey. Fix: if parsekey succeeds in parsing some information in the K: field (parse == 1), then gotkey is set to 1 and sf is set to 0 (i.e. C scale). June 26 2010 Abc2midi bug. Tempo command (eg Q:60) applied at the wrong place in a multivoiced abc file containing a change in dynamics. In the following example: X: 1 T: Branles M: 4/4 L:1/8 Q:1/4=110 K:C V:1 CDEF GABc | CDEF !p!GA[Q:60]Bc | V:2 K:C |[C,G,]4 [G,,F,]4 | [C,G,]4 [G,,F,]4 | the Q:60 is applied after the second note (D). Analysis: the !p! command resets delta_time to zero in track 1 (where the TEMPO command is inserted) because of the line if(wordson+noteson+gchordson+drumson+droneon == 0) delta_time = 0L; at the conclusion of the function dodeferred (in genmidi.c). As a result when TEMPO is encountered, delta_time only reflects the next two notes GA after the !p!. Unfortunately, if we do not set delta_time to 0L, then another bug comes back (September 20 2009). Fix: it is necessary to introduce another global delta_time_track0 which is shared between genmidi.c and queues.c. delta_time_track0 is updated by queues.c but is only used by the TEMPO command in genmidi.c July 1 2010 Abc2midi does not recognize tabs in field commands K: and V: eg. X: 1 T:Danse M: 4/4 L:1/8 Q:1/4=110 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% V:1 nm=Oboe snm=Ob V:2 nm=Basse snm=Bs %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% V:1 % Oboe %%MIDI channel 1 %%MIDI program 68 K:Gm GABc def2|edcd BcA2 | GABc def2|ec[Q:100]B[Q:90]d[Q:80] A[Q:70]F[Q:60]G2|] V:2 % Basse %%MIDI channel 2 %%MIDI program 46 K:Gm [G,,D,]4 [G,,D,]4 |[G,,D,]4 [G,,D,]4 |[G,,D,]4 [G,,D,]4 |[G,,D,]4 [G,,D,]4 |] %%% Analyses: tabs instead of spaces occur after V:1 and V:2. Abc2midi processes 1\tnm=Oboe as a single word etc. As a result abc2midi identifies four voices instead of 2. Fix: in readword() (parseabc.c) added (*p != '\t') in the while predicate. July 07 2010 Abc2midi bug occurs when a rest is followed by a time signature. In the following example: X:1 T: time signature M: 2/4 L: 1/8 K: C V:1 E2D2|[M:2/4] D2F2| V:2 z4|[M:2/4] f2e2| the rest z4 is held too long causing a loss of synchrony between the two voices. If the following meter change is removed in the two voices, the problem disappears. The rest is also held too long in the single voiced tune (no V: command). Analysis: this bug was introduced with the April 15 - April 21 2010 changes to write_meter() in genmidi.c (see above). Fix, I restored write_meter() to its original state reintroducing the incompatibility with Melody Player and several other players. To fix the incompatibility, delta_time was initialized to 1 instead of 0 in writetrack() (genmidi.c). July 11 2010 Abc2midi: new feature. Added warning "no default gchord string for this meter". The message appears once if no gchord string could be set and a guitar chord appears in the music. Implementation: the gchord string is set to 'x' by default. If dogchords finds 'x' it outputs the message one time. July 27 2010 Abc2midi: possible bug. No voice command assumed. In the following sample: X:1 T: voices M: 2/4 L: 1/8 K: G GABc|BAGF| V:2 FGAB|defg| tht V: field occurs past body; will include this body with this voice."); 1 voice command is missing after the K: G. abcm2ps understands that there are two voices; however, abc2midi appends the second voice to the first voice. Analysis: in order to handle named voices parsevoice in parseabc.c assigns a sequential number starting from 1 to the first voice it encounters. This gets confused with the body which also has the same voice number. I did not see any clean way of fixing this problems; however, there is now a warning in event_voice (store.c) when this potential problem occurs. {event_warning("First V: field occurs past body; will combine this body with this voice."); In order to detect this problem, it was necessary to introduce the flag bodystarted. July 29 2010 Abc2midi bug: in the following tune X:1 T: K: bug M: 4/4 L: 1/4 K: E V:1 K: treble EFGA|Bcde| the E major scale was not set up. Analysis: this bug was introduced in May 31 2010. In the second K: command, parsekey (in parseabc.c) sets sf to 0 and gotkey to 1. This forces event_key to change the key signature to the C major scale. Fix: in order to handle key signature mods, we introduced a new flag modnotes which is set when it encounters a ^, _ or == in the K: command. If gotkey is zero and modnotes is set, then explct is set to 1 so that event_key will process the key signature modifications. August 12 2010 Abc2midi bug: delayed start of drum pattern for second voice. In the following example: X:1 T: drumbug M:4/4 L:1/1 K:C % V:1 %%MIDI drumon %%MIDI drum d2zd 35 38 120 50 %| x|x| % V:2 %%MIDI drumon %%MIDI drum dzdz 67 68 100 80 %| x|x| the drum generator for the second voice begins one bar late. If you remove the comment before the single bar in second to last line, the second voice starts on time. Analysis: dodrums() in genmidi.c is called by progress_sequence in queues.c provided the Q structure is not empty (Qhead not -1). In the case of the first voice, the Q structure is setup by checkbar() in genmidi.c because it was called by softcheckbar() when the DOUBLE_BAR feature was encountered. For the second voice, no DOUBLE_BAR feature was encountered, so the Q structure was not set up for the drum track. If the voice starts with a single bar, checkbar() is called and everything is properly initialized. Fix: added to starttrack() in genmidi.c if (drumson) { /* [SS] 2010-08-12 */ drum_ptr = 0; addtoQ(0, drum_denom, -1, drum_ptr, 0); } This seems to fix the problem. August 28 2010 abc2midi bug: voice splits does not work when the unit length is not the default value 1/8. In the example X:1 T: split voice bug. K:C L:1/2 |:cd |1 c2 & e2 :|2 C2 & G2 |] The split voice was transformed with the wrong unit length. If L: is set to 1/8 the MIDI file is correct. Analysis: v->default_length has the wrong value for the split voice. Fix: in event_split_voice (store.c) v->default_length is transfered to the split voice. August 31 2010 abc2midi bug: rests inserts after [Q:1/4=100]. In the following example X:1 T: Rallentando M: 4/4 L: 1/4 Q:1/4=120 K: C C C C C | C C C C | C C C C | C C [Q:1/4=100]C [Q:1/4=80]C | C1 |] there is a large silent period inserted after the Q:1/4=100 command. Inserting a V:1 after K: C fixes this problem. Analysis: this bug was introduced on June 26 2010 in effort to fix a related problem. Unfortunately, for single track MIDI files this caused another problem. Fix: if the MIDI file has only one track, the program reverts to the old code. September 28 2010 abc2midi bug: multiple repeats does not work correctly. In the following example, X:1 T: repeats M: 2/4 L: 1/8 K: C |:G2A2|[1,3 B2f2:|[2,4 B2c2:| G2A2 is played again after the last repeat. Analysis: in genmidi.c maxrepeats was incremented to 5. Fix: limited maxrepeats to 4 or less. (Note [1,3,5 does not work because inlist() in genmidi.c does not check beyond two numbers.) November 21 2010 abc2midi bug: when the path name to the abc file contains embedded periods, eg. "C:\Documents and Settings\midi.stadsmuur.INTERN.018\Local Settings\Temp\temp.abc" abc2midi places the output midi file in the wrong folder eg. "C:\Documents and Settings\midi Analysis: the problem is in the code *filename = argv[1]; outbase = addstring(argv[1]); for (j = 0; j< (int) strlen(outbase); j++) { if (outbase[j] == '.') outbase[j] = '\0'; }; }; in the function event_init() in store.c. Fix, the loop should go backwards and stop at the first period. outbase = addstring(argv[1]); /* [RM] 2010-11-20 */ for (j = (int) strlen(outbase); j>0 ; j--) { if (outbase[j] == '.') { outbase[j] = '\0'; break; } }; Thank you Reinier Maliepaard for identifying the bug and proposing a solution. December 07 2010 abc2midi: New feature: tempo indication compatibility with abc standard 2.0. The standard allows the following syntax for the Q: command; X:1 T:tempo M:2/4 L:1/4 K:G Q: "Adagio" CD|EF| Q: "Adagio" 1/4=40 GA|Bc| Explanation: "Adagio" translates into 1/4=59. In the second Q: command, 1/4=40 overrides the default tempo for "Adagio". See abcguide.txt for other tempo directives. Please note that the double quotes are mandatory. Implementation: in store.c, translation tables temponame[] and temporate[] were added; also the function get_tempo_from_name() was introduced. December 10 2010 Abc2midi bug: abc2midi crashes if the above tempo descriptor is not enclosed in double quotes. See example below. X:1 T:tempo causes crash M:2/4 L:1/4 K:G Q: Adagio CD|EF| Analysis: the segmentation error occurs in the new function get_tempo_from_name(s) in store.c. The string s is empty nad causes the program to crash when strcasecmp() is called. Fix: added the test if (s == NULL) return 0; /* [SS] 2010-12-10 */ in get_tempo_from_name(s). Now the program returns Error in line 6 : malformed Q: field ignored December 12 2010 yaps: bug. The following file crashes yaps. X:1 T:yaps segmentation error Q:1/4=60 M:2/4 L:1/16 K:Bb Q:1/4=60 "F"F2FF AFAc |"Bb" B2 z2 B2 \ z2 | z4 | %%printtempo 0 "Bb"((3_b2a2g2) f2d2 | B2BB dBdf | "F"F2FF AFAc | "Bb"B2z2 "D"A2z2 | P:Accelerando --------------------------->---------------->----------------------- [Q:1/4=65] "Gm"G2B2 G2B2 |[Q:1/4=70] "D"A2 D4 D2 |[Q:1/4=80] "Gm"G2B2 G2B2 |[Q:1/4=90] "D"d2z2 d4 | Analysis: yaps does not expect such a long label in the P: field. Fix: in event_parts(s), in yapstree.c, changed char label[20] to char label[200]. January 1 2011 abc2midi irrelevant messages when running on a collection of tunes in a file. (eg. "voice mapping ..." and "First V: field occurs past body..."). Analysis: the variable voicecode in parseabc.c was not reset to 0 when the next tune was processed. Also the variable bodystarted in store.c was not reset to 0 when the next tune was processed. Fix: in parseabc.c, call init_voicecode() after event_ref() called; in store.c, set bodystarted to 0 in event_ref(). February 21 2011 abc2abc : the program now attempts to transpose the key modifications in the key signature. For example: K: Dphr^F will be transposed to EPhr^G (for abc2abc -t 2). Explicit key modifications are also supported. These key signatures are used a lot in Klezmer music. Unfortunately, the algorithm does not always work correctly. Perhaps someone can help me. All the new code is in toabc.c before the function event_key(). I have given up in treating double sharps and double flat modifications. April 14 2011 abc2abc bug: when using the voice extraction feature -V n, the program still reports errors occurring in other voices causing some confusion. In the following example, voice 1 has 5 beats instead of 4 in bar 1 (we count from zero). X:1 T: confusing error message M: 4/4 L: 1/4 K: C V:1 ABcg|dcABE| V:2 Acde|feFE| When extracting voice 2: abc2abc xabc.abc -V 2 X:1 T:invisible note problem M:4/4 L:1/4 K:C %Error : Bar 1 is 5/4 not 4/4 V:2 Acde|feFE| The error message applies to a problem in voice 1 even though the program is extracting voice 2. Analysis, abc2abc processes the entire file but merely suppresses all voices except the one requested. Error messages in other voices are not suppressed. Fix: the flag output_on in toabc.c is used to suppress output of the unwanted voices. The functions event_error(s) and event_warning(s) now check both flags echeck and output_on before printing. April 14 2011 abc2abc bug: when extracting a particular voice, abc2abc fails to print the part field command P:. In the following example, X:1 T: abc2abc missing part M: 2/4 L: 1/8 K: G P: Intro V:1 V:2 V:3 P:A V:1 V:2 V:3 abc2abc pabc.abc -V 1 X:1 T:abc2abc missing part M:2/4 L:1/8 K:G P:Intro V:1 V:1 P:A is missing in the output, however abc2abc pabc.abc -V 3 X:1 T:abc2abc missing part M:2/4 L:1/8 K:G P:Intro V:3 P:A V:3 P:A is present when the last voice is requested. Analysis: P:A is considered to be part of voice 3, so it was suppressed when any other voice was extracted. Fix: the P: command should be treated as the start of a new section so that the control flag output_on should be set to 1 whenenver this command is encountered. This occurs in the function event_part() in toabc.c. April 17 2011 abc2abc new feature: normally abc2abc converts all instructions (decorations) like !ppp! to +ppp+ in order to comply with the abc standard 2.0 which has deprecated the former convention. A new option -noplus, causes abc2abc to use the deprecated convention to represent all instructions and decorations. Implementation: a new global integer noplus was introduced in toabc.c code. April 17 2011 abc2abc bug: abc2abc fails to recognize clef=perc, eg. X:1 T: clef= error M: 2/4 L: 1/8 K: G V:drum clef=perc !f! CDEF| causes abc2abc to issue a warning %Warning : cannot recognize clef indication Fix: added to isclef() in parseabc.c if (strncmp(s, "perc",1) == 0 && strict==0) { gotclef = 1; } /* [SS] 2011-04-17 */ April 18 2011 abc2abc bug: fails to transfer all voice parameters. In the following example X:1 T: missing stafflines parameter M: 2/4 L: 1/8 K: G V:drum clef=perc stafflines=1 CDEF| abc2abc fails to copy 'stafflines=1' to stdout. Analysis: parsevoice in parseabc.c ignores anything it does not recognize. stafflines=1 is a parameter used by abcm2ps. Fix: added to voice_params in parseabc.h int gotother; char other[V_STRLEN]; added to parsevoice(s) in parseabc.c vparams.gotother = 0; vparams.other[0] = '\0'; if (!parsed) parsed = parseother()... introduced a new function in parseabc.c parseother(); added to event_voice() in toabc.c if( vp->gotother ) { sprintf(output, " %s", vp->other); emit_string(output);} April 19 2011 parseother() in parseabc.c added check for break caused by '='. April 19 2011 Abc2midi: By popular demand the message "missing BAR_REP for voice inserted for voice ... " has been suppressed. The BAR_REP |: is still inserted back when it is expected. (It could be inserted in the wrong place.) April 29 2011 Abc2midi: Jurgen Schwietering has contributed the roll ornament for the harp described here. The operation is quite simple, instead of generating a grace the ~ ornament on harp is a roll with the same 3 notes (always) which can be quite accurately transcribed as ~n2 := n/n/n (BTW played always with fingers 4 3 2 [a m i]) ~n3 := n/n/n2 (for dotted, execution same as previous) It is NOT a movement done before the beat like graces. It is very common among folk harpists. A new MIDI command %%MIDI harpmode 1 changes the ornament to harp mode. To switch back to regular mode, use %%MIDI harpmode 0 Alternatively, you can specify the harp mode in the command line to abc2midi, eg. abc2midi inputfile.abc -HARP Implementation: a new global variable harpmode was introduced which is modified by the MIDI command or set in event_init() in store.c. The function doornament() checks the harpmode flag and calls the new functions makeharproll3() or makeharproll() in store.c. Here is a sample file to test this feature. X:61 T:The Glass of Beer C:Reel, Trad. Irish C:Arr. Gráinne Hambly M:4/4 L:1/8 K:D Q:1/4=130 %%MIDI program 1 46 %%MIDI harpmode 1 ~B3 ~B4 B| ~B2 B/B/B ~B4| %%MIDI harpmode 0 ~B2 B/B/B ~B3 B| ~B2 B/B/B ~B4| June 6 2011 Abc2midi bug: For the following file, X:1 T:part not found M:3/8 L:1/16 P:B K:Dphr^f %MIDI gchord fzz P:A "G"cdefga:| P:B M:2/4 |:d4e4:| (Comment: a common trick in transcribing music to abc is to temporary split it into parts so that you do not have listen to the beginning each time you are checking it out. The following problem occurs when you attempt to skip the beginning.) abc2midi returns the error message genmidi.c:fillvoice partlabel -55 out of range genmidi.c:fillvoice partlabel -55 out of range and the resulting MIDI file does not contain any music. Analysis: The function findpart (in genmidi.c) looks for P:B in the feature[24] which was its original location, unfortunately it has been moved to feature[25] by add_missing_repeats() (store.c) but part_start was not updated correctly. The problem is with the loop, for (j=0;jD B,>D G>TB | GA Bc dc | GA Bc dc | [V:2] B,>A, G,>A, B,>D | G,A, B,C DC | G,A, B,C DC | The problem also appears when trills are combined with grace notes as illustrated here. X:1 L:1/8 M:3/4 K:Am Q:1/4=60 V:1 c2 {d}TcB/c/ d>B | BA Ac e>d | V:2 A2{B}A^G/A/ B>G |^GE EA c>B | Analysis: The trilled or rolled notes are expanded into a sequence of notes as soon as they are detected. As a result, the grace or broken rhythm is applied to the first note of this sequence. To fix this problem it is necessary to expand trills and rolls after broken rhythms and grace notes are treated rather than as soon as they are detected. Fix: (2012-05-29 to 2012-06-03) a new function expand_ornaments () is called by finishfile() that converts trilled and rolled notes into a sequence of notes. The defunct function dotrill() was split into dotrill_setup() (called by event_note) and dotrill_output() called by expand_ornaments(). Similarly, doroll() was split into doroll_setup() and doroll_output(). Notes to treated by expand_ornaments() were flagged using a new feature array called decotype[] which was checkmalloc'd like stressvelocity, and pitchline. If the note was flagged it is treated by either dotrill_output() or doroll_output() depending on its type. The implementation was complicated by the problem, that the internal representation of the music in the feature arrays does not preserve the key signature information which is needed to decide whether to ascend (descend) a tone or semitone in the trill or roll. Therefore it was still necessary to analyze the context of the trill or roll at the time of detection using the .._setup() functions and save the generation parameters for .._output() in a specifically designed struct called notestruct. These structures are generated as needed, but a pointer array noteaddr[1000], (assuming not more than 999 trills or rolls occur in a particular tune) is used to find the struct. The notestruct struct thus acts as a bridge between the setup and output functions. Treatment of microtones added another complications and at this point I have not verified whether the new code is correct with regard to microtones. There is still a synchronization problem when broken rhythms are combined with ornaments as illustrated below. X:1 T: ornament test M: 2/4 L: 1/8 K: G V:1 D2 >~B2 |c2 G2| V:2 F2 >D2| e2 D2| Ornaments are handled in a different fashion. If harpmode is set, then ornaments are expanded into a sequence of notes like trills and rolls. If harpmode is not set, then a grace note is inserted prior to the note and graceon() is called to make the final adjustments. Furthermore if the note is dotted, then two grace notes are added. For the present time you should avoid combining ornaments with broken rhythms in multivoiced tunes. August 08 2012 Abc2midi, yaps, abc2abc: The time signature C| or c| is now interpreted as 2/2 instead of 4/4. Implementation: added another test in void readsig() in parseabc.c October 03 2012 Chinese character support in lyrics was added to abc2midi by Bow Yi Jang . Changes were restricted to the function getword(.) in genmidi.c November 03 2012 Abc2midi multirest bug. In the following example, X:1 T: multirest problem M: 2/4 L: 1/8 K: G Z|G4|\ M:3/4 L:1/8 Z|D6| The second multirest preceding D6 is held for two beats instead of three and the warning Warning in line 9 : Bar 2 has 2 units instead of 3 appears. Analysis: the function event_mrest (store.c) uses the initial time signature 2/4 stored in time_num/time_denom which does not get updated by event_timesig() once the parser is in the body. abc2midi must keep track of two time signatures: time_num/time_denom which is declared in the initial field commands and mtime_num/mtime_denom which may be updated in the middle of the body. The initial time signature, is important for multivoiced tunes where the initial declaration is carried to the start of all the voices. The active time signature mtime_num/mtime_denom is only updated in the second stage in set_meter() when genmidi is processing the feature[] array and writing the MIDI tracks. However, the active time signature is also needed when event_mrest is called to write multiple bars of rests. Unfortunately, the active time signature was not maintained during the initial parsing stage (first stage). Fix: the variables mtime_num and mtime_num are now also used during the first pass and maintained in event_timesig(). event_mrest() uses the active time signature mtime_num/mtime_denom rather than the initial time signature time_num/time_denom. November 08 2012 Abc2midi: multirest bug part 2. The problem with meter change and multirests persists in multivoiced tunes. In the following example, X:1 T: Multirest bug part 2 M:C L:1/4 K:F V: 1 V: 2 %%MIDI program 1 73 %%MIDI program 2 40 %%staves [{ 1 2 }] [V: 1] F A z c| z4 | [M:3/8][L:1/8] F/>G/ FA|B/>c/ BA | G/>A/ GF|C3|] [V: 2] A F3 | Z | [M:3/8][L:1/8] Z | G/>A/ GA | B/>c/ BA | G3|] The first multirest Z in voice 2 is held for 3/8 instead of of 1/4. Analysis: voice 1 changes mtime_num/mtime_denom to 3/8 and it remains in that state at the start of voice 2. Fix: new variables int active_meter_num, active_meter_denom are introduced into the voicecontext struct. They are used to maintain the values of mtime_num and mtime_denom over voice switches. November 15 2012 Abc2midi extension: abc2midi treats Xn the same way as Zn, to be compatible with the new version of abcm2ps. Fix in parseabc.c added case 'X': /* [SS] 2012-11-15 */ after case 'Z': November 21 2012 Abc2midi: verbose option provides more detail if set to 4 or 5 for tracking segmentation errors. November 22 2012 The fixes for the following two problems were provided by Philippe De Muyter. The input line size in parseabc.c was increased from 256 to 512 to accommodate abc files that are automatically generated (eg midi2abc). char inputline[512]; Abc2abc truncates the voice ids when it encounters the first invalid character without giving any warning. eg. X:1 T: invalid voice M: 2/4 L: 1/8 K: G V: A_1 abcd| V: A_2 DEFG| only one voice is detected. Fix: In interpret_voicestring() in parseabc.c the following code was added after c = readword(code,s); if (*c != '\0' && *c != ' ' && *c != ']') { sprintf(msg, "invalid character `%c' in Voice ID", *c); event_error(msg); } Now abc2abc and abc2midi complain that they encountered an invalid character. November 23 2012 abc2midi bug: unable to trill or roll tied notes. In the following example X:1 T:trill-issue M:2/4 L:1/8 K:F V: 1 z4|z3d| V: 2 %%MIDI program 1 73 %%MIDI program 2 40 TF2 Tc2-| c Tf2-f| The tied notes c2-c and f2-f do not get trilled. Analysis: this bug was introduced on July 03 2012 in the attempt to fix other problems associated with trills. The function expand_ornaments() only processes NOTE features and ignores TNOTE features used to designate tied notes. Fix: The solution is to change TNOTE to a NOTE. However, writetrack() in genmidi.c processes TNOTE features in a special way in order that checkbar() will work when a tied note extends over a measure. The TNOTE invokes a midi on command but a midi off command is deduced from the following REST(s) which are associated with the tied note. Therefore, if we change TNOTE to a NOTE we also need to eliminate the REST(s) which are part of the TNOTE sequence. This is done by a new function, convert_tnote_to_note(). Unfortunately, this is not a clean fix. Checkbar() will give a misleading message when the tied note extends over a measure. Also, lyrics may not align correctly with tied and trilled notes. It gets messy to make expand_ornaments() to split up a trill across a measure. November 25 2012 Abc2midi: the compiler on Windows PC does not initialize arrays to zero when they are allocated. As a protection the arrays the bentpitch and decotype are now initialized to 0 when they are allocated. Some array pointers are now checked for valid values. December 01 2012 -- submitted by Philippe de Muyter abc2abc truncates a line to 512 characters without warning in the -P mode. (This is the continuation of the changes November 22 2012.) Analysis event_error is muted during the output so it is necessary to simulate it with a plain printf in the function print_inputline_nolinefeed() in the file parseabc.c. December 11 2012 abc2midi: bend note, new feature. Placing the instruction !bend! slides the pitch of the following note up. For examples: X:1 T: pitchbend M: 6/8 L: 1/8 K: Gdor %%MIDI program 78 whistle %%MIDI transpose 12 DEF G3|DEF !bend!G3| the second G is slid up. Implementation: added a new function note_effect to queues.c which is called by timestep(). Note effect inserts a sequence of pitch bend events prior to sending a MIDI note off. Added a new integer member, effect, to struct Qitem. The flag, effect, determines whether note_effect is invoked. An additional parameter, effect, was added to the function addtoQ which is also defined in queues.c. The function addtoQ is called in many places in genmidi.c. In abc.h added a new feature called EFFECT. The feature is inserted before a note when the instruction !bend! is encountered -- see event_handle_instruction() in store.c. In genmidi.c added a global flag, effecton, which is usually set to zero except when the EFFECT feature is encountered. The NOTE: handler in writetrack returns effecton in one of the addtoQ function calls. December 12 2012 abc2midi: bend configuration. Introduced two variables bendvelocity and bendacceleration into note_effect. Note_effect inserts 8 MIDI pitchbends equally spaced inside a note. The pitchbend is initialized to the neutral value of 8192. During the loop repeated 8 times, pitchbend and bandvelocity are incremented as follows. pitchbend = pitchbend + bendvelocity bendvelocity = bendvelocity + bendacceleration. The pitchbend is limited between 0 and 16383 usually corresponding to a negative and positive shift of two semitones on most General MIDI instruments. The variables bendvelocity and bendacceration can be set by the following %%MIDI command. %%MIDI bendvelocity n1 n2 where the integers n1 and n2 are the velocities and acceleration respectively. By default, n1 and n2 are initialized to 100 and 200. December 25 2012 Abc2midi part/trill bug. Introducing trills or ornaments in a multipart abc file causes erratic behaviour. For example, X:1 T:parts M:2/4 L:1/8 P:B K:C P:A CDEF|TGABc| P:B cBAG|FEDC| Part B is not played when the trill is present in part A. Analysis, abc2midi stores the start position of each part in the array part_start during the parsing stage. Unfortunately, things may move around during the later stages. The function expand_ornaments() inserts additional notes in the feature arrays when it does its expansion. This shifts the position of the parts and the information in the part_start array is no longer valid. Fix: created a new function fix_part_start() in store.c which is called after expand_ornaments() in finishfile(). Jan 27 2013 Abc2midi: the abc2midi allows but does not recommend the tempo command to just specify a number. eg. Q:320. abc2midi automatically assumes that this number refers to a quarter note; however, the abc standard 2.0 specifies that it should refer to the unit length specified by the L: command prior to the body. Fix: in parseabc.c changed a=1 to a=0 in the function parse_tempo(). The existing code in tempunits() in store.c does all the rest. Jan 28 2013 Abc2midi: the above change was withdrawn since there is disagreement between abc standard 1.7.6 and abc standard 2.0. February 25 2013 Abcmatch: introduced -wpitch_hist runtime parameter for computing the pitch histogram weighted by the note length. Some minor clean-up of the output. February 26 2013 Abcmatch: negative array index fixed in abcmatch.c (compute_note_histogram). Problem is exposed on Windows operating system. March 08 2013 -- patch submitted by Philippe De Muyter Abc2abc: the -V and -P options have been generalized so that more than one voice can be selected using a comma separated list. Implementation: The long global variable selected_voices represents the selected voice in a bit map. Each bit in the word corresponds to a specific voice number. Two new functions are introduced. parse_voices_selection parses the voices_string in the -P or -V command and converts it into the bitmap in the selected_voices variable. must_emit_voice(n) examines the n'th bit of the selected_voices and indicates whether it is on or off. The other change is the replacement of the control - if ((selected_voice != -1) && (n != selected_voice)) { with + if (!must_emit_voice(n)) { /* [PHDM] 2013-03-08 */ March 10 2013 -- also submitted by Philippe De Muyter abc2abc: fix chord's tuple length calculation Up to now, bar length was increased at first note of chord, and tuple status was lost at first note of last chord. When a chord in a tuple had a length modifier, the resulting bar length was wrong, which caused wrong error messages. With X:1 T:wrongbarlengtherror M:4/4 L:1/8 K:C z8 | z6 (3 [fd]/ [fd]3/ [fd] | z6 (3 [f/d/] [f3/d3/] [fd] | abc2abc gave a wrong message : %Error : Bar 1 is 13/12 not 4/4 Fix that, by incrementing bar length and decrementing `tuplenotes' at chordoff time, not at first chord note. Move also the tuple-implied length conversion in `addunits', to avoid code duplication. Because there are two ways to specify a chord length, [c2e2g2] and [ceg]2 in the first case, we must now memorize the note length to be able to retrieve it at chordoff time; this is done in the new `chordfactor' variable. Additionnaly, as 'addunits' is only called when we know the exact length of a note or chord, `repudiate_lastaddunits' is now useless and removed. March 14 2013 Abc2midi: part/repeat bug. In the following example X:1 T: Part - repeat bug Q:1/2=120 M:2/2 L:1/4 K:D %%vskip 0 P:Intro |: "Em"e4 || P:A || "D"d4 :| abc2midi returns the following messages: Error in line 12 : found another |: after a |: Warning in line 12 : Assuming repeat Warning in line 12 : replacing with double repeat (::) writing MIDI file temp21.mid Furthermore, the e4 in the Intro is repeated and then the D4 in part A is repeated. Since the P: are only labels here (there is no P: command preceding K:), it was expected that the entire the tune would be played as |: "Em" e4 | "D" d4 :| Analysis: the function scan_for_missing_repeats() which was introduced in June 23 2009 is the source of the problem. The function assumes that the tune is actually in two parts and inserts a |: in the beginning of part A. When fixreps() is called it discovers that two |: occur without an intervening :|, so it decides to replace the second |: with a double repeat ::. (Note that fixreps() would not be called if the parts were real and not just annotations.) Fix: The useless conditional statement if (J == PART || j == VOICE || j == BAR_REP etc. was commented out since it does nothing. In the following statement, an additional check parts != -1 was added. If parts == -1, this implies that the part indications are merely annotations and do imply a real part as abc2midi is concerned. Therefore bar_rep_found[] and voicestart[] are not cleared again, implying that a |: may need to be introduced at the beginning of the part if the part ends with a :|. March 20 2013 Abc2midi: invisible and visible multirest confusion with field commands. Z and X are used both as field declarations (X: reference number and Z: transcription source) and as multirests in the body. In unusual cases where the multirest is followed by a repeat sign and happens to be at the beginning of a line, it can cause confusion. For example, X:1 T: rests M:3/4 K:C c6|e6|^g6|\ X ::\ C6|e'6|^G6|\ Z :|\ [CE^G]6|] X:2 T:rests M:3/4 K:C c6|e6|^g6|\ X1::\ C6|e'6|^G6|\ Z1:|\ [CE^G]6|] are two examples which abc2midi fails to interpret correctly. parseline() in parseabc.c attempts to treat X :: and Z :| as field commands even though they are malformed. Abc2abc also does not produce correct output. Fortunately parseline issues warnings Warning in line 8 : whitespace in field declaration Warning in line 8 : potentially ambiguous line Error in line 8 : Missing Number and the transcriber is urged to reformat the line to avoid this problem. Fix: I am not sure whether I should fix this problem. In any case, I have put a small patch in parseline() so that the above examples are treated correctly. March 21 2013 abcmatch: several bug fixes and a new feature -pitch_table. Given a file containing a collection of tunes eg. Modes.abc, abcmatch Modes.abc -pitch_table will output the interval weighted pitch histogram for each tune. If the output is stored in a separate file, eg. Modes.tab, this table could be used for searching for the tune having the closest matching pitch histogram (a feature to be introduced in runabc). March 26 2013 abc2midi bug: if a chord is preceded by a Roll or Trill indication, abc2midi fails to encode the chord in the MIDI file. For example: X:1 T: chordtrill M: 4/4 L: 1/8 K:C V:1 %%MIDI program 16 T[ceg]4 [AEc]4 :| V:2 %%MIDI channel 10 GA GA GA GA :| A warning is issued that trills and rolls are not implemented for chords, but [ceg]4 is not encoded in the MIDI file. Fix: in event_note, in store.c added the lines pitchline[notes] = pitch_noacc; /* [SS] 2013-03-26 */ bentpitch[notes] = active_pitchbend; /* [SS] 2013-03-26 */ addfeature(NOTE, pitch, num*4, denom*2*(v->default_length)); /* [SS] */ following the statement event_error("Rolls and trills not supported in chords"); April 10 2013 Abc2midi: new feature. Added a new runtime option -CSM . This option allows one to customize the BarFly stress models by providing an external file. Background: the 32 stress models are presently built-in the source code in the file stresspat.c. This has the advantage that executables can be distributed without an auxiliary data file containing the models. However, the user does not have much leeway to alter the models or add additional stress models. The -CSM feature addresses this limitation by allowing the user to add more models for other rhythm designators (eg lesnoto), and to alter one or more of the existing models. There is room to add up to 16 additional models. The feature requires the user to specify a text file which contains these models. Description of the external file and how it works is given in abcguide.txt and a sample of such a file is given in the pt folder (customstress.txt). Implementation: a new function read_custom_stress_file() was introduced in the file stresspat.c. Assuming the file conforms exactly with the expected format, the function reads all the models provided. For each model, if the rhythm designator and meter conflict with one of the existing standard models, the function will update the characteristics of that model. Otherwise the function will append the model to the current list. April 11 2013 Corrected a minor error in init_stresspat() (Tango) in stresspat.c. As a convenience, I have produced default_stress.txt in the format that read_custom_stress_file() accepts. Default_stress.txt contains the built in models to abc2midi. You can find the file in the pt (Phil Taylor) folder. April 17 2013 Abcmatch: numerous bugs fixed. Introduced a new matching -norhythm. The matching algorithm ignores the length of the notes and only matches the sequence of pitches in a bar. The file abcmatch.txt was updated. More internal documentation was added in abcmatch.c April 20 2013 Abc2midi bug: combination of chords and broken rhythm. In the following example, X:1 T: broken rhythms M: 2/4 L: 1/8 K: F [DF]2 > [CE]2| The second chord [CE]2 begins before the end of chord [DF]2. Analysis: the function brokenadjust() (store.c) is called to adjust the lengths of the notes to effect the broken rhythm. It adjusts the notes inside the chord but fails to adjust the length associated with the CHORD (CHORDOFFEX feature). This causes timestep() in queues.c to be called too early, causing the second chord to start to early. Fix: in the function lenmul() added another condition, || (feature[n] == CHORDOFFEX)) /* [SS] 2013-04-20 */ April 21 2013 Fixed: a potential memory overflow in parsing the repeat string. In getrep() (parseabc.c) ensured the array index for playonrep_list does not exceed 50. April 24 2013 Suppressed warning in abc2midi. For the following example, X:1 T:TEST TUPLES M:2/2 L:1/4 Q:1/2=80 K:G [F,A,D] (3[df]/[eg]/[^e^g]/ [fa][CF] | [F,A,D] (3[d/f/][e/g/][^e/^g/] [fa][CF] | abc2midi issues the following warnings. Warning in line 7 : Different length notes in tuple for chord Warning in line 7 : Different length notes in tuple for chord Warning in line 7 : Different length notes in tuple for chord Analysis: the message is issued when closing each of the tuple chords in the first line. The length of the note in the tuple is stored in the variables tnote_num, tnote_denom when the first tuple note is encountered. Unfortunately when the chord note duration is applied (here one half), the note length no longer matches the stored values tnote_num and tnote_denom and a warning is sent. The output midi file nevertheless correct. Fix: abc2midi stores the note length of the tuple in tnote_num, and tnote_denom. A chordoff feature can modify the value of a tuple note (i.e. chord) if its length is indicated outside the chord (eg. [CE]3/2. If the modified chord length does not match the stored value tnote_num, tnote_denom set by event_note, a warning is issued. It is getting too complicated to keep track of a tuple note inside and outside a chord, so I have decided to just suppress the error message for tuples of chords. (i.e. I would have to make extensive changes to the logic of the program to get it working properly.) May 07 2013 Abcmatch: introducing -fixed runtime parameter. It allows matching to go across a bar line. See doc/abcmatch.txt for more information. May 10 2013 Midicopy: bug in extracting a segment of a MIDI file. When the segment starts in the middle of a note playing, it causes a loss of synchronization between the tracks. Analysis: there was an attempt to write a negative MIDI time increment when Mf_currcopytime exceeds Mf_currtime. Fix: set negative values to zero in the function WriteVarLen(value). June 06 2013 Abc2midi: potential segmentation error when applying stress model. The following tune contains stray text which abc2midi assumes to be part of the body of the tune. X: 157 T: Cliffs of Moher N: page 51 R: jig M: 6/8 K: Ador "Am"eaa bag| (4efaf "G"ged| "Am"c2A BAG| "Em"EFG ABc|\ "Am"eaa bag| (4efaf "G"ged| "Am"cAA BAG| "Em"EFG "Am"A3 :| "Am"efe dBA| efe dBA| "G"G2d dBA| GAB dBd|\ "Am"efe dBA| efe dBA| "G"GAB dBG| "Em"EFG "Am"A3| ~e3 dBA|~e3 dBA|"G"~G3 dBA|GAB dBd|\ "Am"efe dee|cee Bee|"G"EFG BAG|EDB, "Am" A,3| This abc file is used to generate the MIDI files and pdf file for volume 2 of the music collection used by the Ottawa Slow (Celtic) Jam. The file is derived from http://www.ceolas.org/pub/tunes/abc.tunes/sessionTunes.abc When the stray text is processed in the Barfly mode (-BF), the array index to the variable fdursum exceeds the allocated memory 32 which can cause a segmentation error on some systems. Fix: in the function fdursum_at_segment in genmidi.c, replaced inx0 = inx0 - nseg; with inx0 = inx0 % nseg; /* [SS] 2013-06-07 */ which is executed if inx0 > nseg. June 09 2013 Abcmatch: in -br mode the program returns both the number of matching bars in the tune and template. September 04 2013 Midicopy: new feature. Introduced the run time option -tempo n (beats/min). When this option is included all tempo messages in the midi file are replaced with the specified value. Implementation: in metaevent() when a tempo message is encountered, if newtempo is greater than zero, write the newtempo value instead of the value in the source midifile. The value of newtempo is set by the -tempo run time option. September 06 2013 Midicopy: new feature. Introduced the run time option -speed f (multiplier). When this option is included all tempo messages in the midi file are are multiplied by the factor f where f is a floating point number between 0.05 and 10.0. This speeds up or slows the music by this factor. September 07 2013 Midicopy: new feature. Introduced the run time option -drumfocus n m where n is the pitch code of the selected drum line and m is the velocity value to be applied to all other drum lines. The feature, highlights the selected drum line by attenuating all other drum lines by playing them at level m (m varies from 0 to 127). Implementation: the velocities of the other drum lines are set to m in function chanmessage() prior to sending a 'note on' message. September 08 2013 Midicopy: fixed function tick_to_seconds so it returns the correct time when the tempo is changed by -tempo or -speed. September 10 2013 Midi2abc, midicopy: bug fix. Midi2abc or midicopy may fail for some midi files which use the running status. A few midi files attempt to save a few bytes by not transmitting the status byte for a channel message when status byte has not changed. For clarification, the status byte contains the channel message like "note on channel 10". The status byte is followed by one or two data bytes specifying the particular note it applies to and the velocity value. Since data bytes are restricted to 6 bits and status bytes always contain a value exceeding 6 bits, it is easy to tell when a status byte is missing. The running status, saves a few bytes when several notes in a chord are turned on (or off) at the same time. The bug occurred when a metatext message is inserted inside a running status complex (eg. note on channel 10, metatext, note on channel 10). Midi2abc and midicopy abort with the message "unexpected byte 0x..". Analysis: the bug was traced to the code writetrack() in midifile.c and also midicopy.c. It is necessary to store the last status byte that occurred in the last channel message. Note a metatext message is not a channel message. A new local variable, laststatus, was introduced in the code. September 15 2013 Midicopy: new feature. Added an option -mutenodrum [level] to mute all channels to velocity level if the channel is not 9 (drum channel). If level is not provided, it is set to zero. Ocotober 1 2013 Midicopy: new feature. Added the option -setdrumloudness n m where n is the drum number between 35 and 81 inclusive and m is the new velocity between 0 and 127, All instances of the selected drum are assigned the given loudness (velocity). October 15 2013 Abcmatch: new feature. Added options -interval_hist and -interval_table to analyze the pitch intervals between adjacent notes. The program produces a histogram of the note intervals in MIDI (semitone) units. October 22 2013 Abcmatch: new feature. Added the option to accept a certain number of insertion, deletion, and substitution errors using the Levenshtein distance measure. October 28 2013 Midicopy: new feature: added the option to list the tracks to exclude from copying. eg. -xtrks 4,5 indicates to copy all tracks except 4 and 5. October 30 2013 Abc2midi: bug fix. A key change in the middle of a tune does not propagate to the split voice. In the following example, X:1 T:Test L:1/4 M:2/2 Q:1/2=110 K:C V:1 C4 | [K:Bb]B4 & B,4 | B,4 was not flattened. Analysis: the key change [K;Bb] was not propagated to the split voice. Fix: in event_split_voice() in store.c, the active basemap and basemul arrays for the voice was saved in a temporary area and transferred to the split voice. October 31 2013 abc2midi and yaps bug: for the following example, X:1 T: :|] ending M:C N:Portland p.19 R:march K:D |:"G" b2a2 "A"g2e2| "D"d4 d4 :|] abc2midi returns the error Error in line 10 : Chord already finished and yaps returns the error Error in line 7: no chord to close Analysis: these are extraneous error messages. Parsemusic() in parseabc.c detects the THIN_THICK bar line |] but does not detect it when it is preceded with ':'. Fix: check for ']' in this case and skip over. November 02 2013 Abc2midi: some instructions which are meaningful to abcm2ps are meaningless to abc2midi and cause a warning. In the following example, abc2midi cannot interpret !4! and !0!. X:1 T: instructions M: 4/4 L: 1/8 K: A "E"FEF(G "A" A2) !4!!0! [A2A2]| Warning in line 6 : instruction !4! ignored Warning in line 6 : instruction !0! ignored Analysis: event_handle_instructions(s) in store.c issues this warning when it cannot interpret this message. Fix: the message is suppressed if -quiet is included in the runtime parameters. November 2 2013 abc2midi indicates the wrong line number in a warning. In the following example, X:1 T: Slurs M: 2/4 L: 1/8 K: F z(GFE |:DE) FG| AB (3cBA:| abc2midi returns the message Error in line 8 : Unexpected end of slur found The end of slur is actually in line 7. Analysis: on the second repeat, no slur was started so an end of slur is not expected - but the line number in the error message is wrong. The repeat :| causes writetrack (in genmidi.c) to backtrack it restores the state variables to the condition where the opening repeat sign |: occurs but the state variables do not include the line number used by the warning or error message. Fix: expanded the functions save_state() and restore_state() so that the line number can also be saved. November 4 2013 abc2midi bug: A bug was detected when abc2midi is run with the Barfly stress model (-BF 1). For the following file t.abc X: 1 T: Barfly implementation bug R: jig M: 6/8 L: 1/8 K: G |: "C"c3 "G/B"B3 | "D7/A"AGF "G"GBd :| abc2midi t.abc -BF 1 the note c3 or B3 may be inaudible in some instances. Analysis: the local variable vel in the function noteon() may end up being undefined. In certain cases stress_factors() called by noteon() may not set the variable vel, in which case we expect note_beat() to be called. Unfortunately, if vel was initally nonzero note_beat is note called and vel has a random value. Fix: initialize vel to 0 in noteon(). November 04 2013 yaps fix: On January 16 2006 an option to display the notes in red was introduced. This code did not work well because the other musical components were also colored red. The problem was fixed by maintaining the color in black and temporarily switching the color to red when a note, beam or rest is drawn. A new variable redcolor was introduced in drawtune.c and set by the !red! command and reset to zero by !black!. The functions drawnote(), drawrest, and drawbeam() test this variable and switch the color to red on a temporary basis in order to draw the object. November 12 2013 abcmatch.c improvement. When running in absolute versus contour mode, abcmatch frequently transposes in the wrong direction when the key signatures differ since it does not know which direction to go. abcmatch now transposes in the direction of minimum distance between keys. For cut time C| abcmatch translates it to 4/4 rather than 2/2 so it can find more matches. Both changes are in abcmatch.c November 17 2013 abcmatch.c. Bug fixes so the matched bars have correct bar numbers. November 26 2013 abcmatch.c -br threshold applies to the number of matched bars in template instead of matched tune. December 2 2013 abc2midi bug - split voices and repeats. The following tune is not converted correctly. X:1 T: test split file 13 M: 1/4 L: 1/4 K: G |:G & E |1 D:|2 F & A| On conversion: writing MIDI file s11.mid Error in line 8 : Need || |: :| or :: to mark end of variant ending Warning in line 8 : Track 2 is 1946 units long not 2426 The program produces to MIDI tracks of unequal length. Track one contains G D G D F and track two contains E z E A. In other words track 1 plays both section one and two in the repeat instead of just section two. Surprisingly if we replace |1 and |2 with |[1 and |[2 respectively, the conversion is done correctly and there are no errors or warnings. Analysis: in the first pass the feature PLAY_ON_REP belonging to voice 1 was placed in voice 2 and two PLAY_ON_REP features appear consecutively in voice 2 resulting in the error, "Need || |: :| or :: ..." message. When the [1 and [2 are used, the internal representation contained in the feature arrays is correct. The problem was traced to the code in event_bar in store.c. When the [1 and [2 is used, the PLAY_ON_REP is handled correctly by event_playonrep() which is called directly by parsemusic in parseabc.c. When |1 or |2 is used, parsemusic does not catch these codes and they are handled (mishandled) by event_bar when a split voice is present. Fix: event_bar() was reorganized so that bar commands are sent to the original voice rather than the child split voices. When the child split voices are sync'd the bar commands are copied to the child voices. This seems to work better. The function recurse_back_and_change_bar() is no longer in use. The test tune was added to split.abc in the doc/programming/ folder. December 14 2013 abc2midi: The warning "track x is xxxx units long instead of ..." was changed to "track x is .... quarter notes long instead of ..." The change is was made in writetrack() in genmidi.c. December 25 2013 abc2midi bug: abc2midi does not read customstress files correctly using the -CSM option. The following file containing Lesnoto 7/8 7 7 110 1.3 90 1.0 80 0.7 100 1.2 90 0.8 100 1.2 90 0.8 is not read correctly. Neither the name Lesnoto or the meter is stored in the stresspat structure. Analysis: in the function read_custom_stress_file() in stresspat.c the lines stresspat[index].name = name; stresspat[index].meter = meter; copy the address instead of the contents of string arrays name and meter. The lines should read strcpy(stresspat[index].name,name); /* [RZ] 2013-12-25 */ strcpy(stresspat[index].meter, meter); /* [RZ] 2013-12-25 */ also gain and expand are not copied into the structures. add stresspat[index].vel[i] = gain; /* [RZ] 2013-12-25 */ stresspat[index].expcoef[i] = expand; /* [RZ] 2013-12-25 */ I am grateful to roman.zimmermann@gmx.at for identifying the bug and providing the fix. January 01 2014 Abcmatch: fixed matchsup.c so it catches only the first title of a tune in case that it has alternate titles. January 05 2014 Midiabc: bug the msb and lsb values were interchanged in mftext_pitchbend. mftext_pitchbend now also returns the value of bend in MIDI units. January 06-09 2014 abc2midi new feaure: introducing an option to provide microtone tuning in the key signature for example K:F ^1/2D besides flattening B also flattens D's by a half a semitone. Implementation includes changes to parsekey in parseabc.c which now has to check for microtones in the list of notes following the key signature. A new parameter modmicrotone is introduced in the function event_key() which is found in parseabc.c, store.c, yapstree.c, toabc.c and matchsup.c. A new struct 'fraction' was added in parseabc.h. In store.c altermap() has a new parameter struct modmic[7], which is used to transfer the key signature microtone specifications from modmicrotone in event_key to a new struct in the voice struct called basmic[7]. v->basmic stores the key signature microtone specs if present. Function newvoice in store.c transfers global->basemic to v->basemic. Function pitchof_b in store.c checks v->basemic to see if the note has a microtone defined in the key signature. parsenote in parseabc.c resets microtone to 0 (through event_normal_tone()) if the note is not a microtone. This is a lot of changes. I hope, I have not introduced new bugs. If a microtone is detected by parsenote(), its parameters are stored in the struct fraction setmicrotone. This struct is automatically reset to 0,0 if no microtone is detected. January 12 2014 abc2midi new feature: Makam style music (Turkish) uses a more complex music scale (as opposed to the equal temperament scale). The comma53 scale divides an octave into 53 microtones. To use this scale put "%%MIDI tuningsystem comma53" in your abc file. Implementation: added to new functions in store.c init_p48toc53 initializes the array pt48toc[]. convert_to_comma53() changes midipitch and midibend values. Added a new command, %%MIDI tuningsystem comma53 January 14 2014 corrections to convert_to_comma53(). Some debugging #defs. January 16 2014 some fixes to pitchof_b and parsekey. January 20 2014 abc2midi: microtones now propagate across a bar just like accidentals. Major modifications to pitchof_b and other minor fixes (in store.c) were made. January 26 2014 abc2midi: more microtone bug fixes. Each octave can hold its own microtones. i.e. v->workmic is now a two dimensional array just like workmap and workmul. February 05 2014 abc2midi: the following file causes abc2midi (and other programs) to behave erratically. X:9 T:Have you ever wondered? L:1/8 M:4/4 Q:1/2=90 K:G V:1 CDEF | W:| Have you ever | wondered why the | girls do | skipping, and the W:| boys play | football and the | grans do | knitting? W:| Who made the | rules that the | people all o- | bey? And W:| What's with the | "girls' thing", | "boys' thing" | anyway? X:10 T:Warm-up 1 L:1/4 M:2/2 Q:1/2=80 K:Bb |[B,DFB]2z2 | abc2midi returns the message Warning in line 9 : Potentially ambiguous line. Warning in line 9 : Ignoring reserved character W Error in line 9 : Unrecognized character: o Error in line 9 : Malformed note : expecting a-g or A-G Error in line 9 : Unrecognized character: r Error in line 9 : Unrecognized character: w Error in line 9 : Unrecognized character: o Error in line 9 : Unrecognized character: n and many more messages Analysis: abc2midi sees :| after the W and assumes it is an end repeat in the body. It tries to treat the rest of the line like music. Fix: I have improved the warning in parseabc.c so it is more meaningful. It is now Warning in line 9 : Potentially ambiguous line - either a :| repeat or a field command -- cannot distinguish. This applies to all programs, yaps, abc2abc etc but it is too much trouble to give them new version numbers. April 03 2014 Abc2midi bug: tied note at end of bar combined with Barfly stress model. In the following example: X:1 T: Stress model bug L:1/8 M:2/4 K:Gmin %%MIDI ptstress 4 100 1.10 100 1.10 100 1.0 100 0.8 |Gc BA-|AG FG| Abc2midi returns the following error message writing MIDI file stress1.mid Warning in line 7 : Bar 1 has 21/10 units instead of 2 Analysis: the problem is with the tied note A which crosses a measure. The tied notes A-|A are tied together into a single note by the function tiefix() in store.c and the stress model is applied to the combined note. This becomes obvious when running abc2midi with -v 2 option.r 2 pitch 67 from = 0/1 (0/1) to 1/2 (1/1) becomes 0/1 11/20 - 11/20 pitch 72 from = 1/2 (1/1) to 1/1 (2/1) becomes 11/20 11/10 - 11/20 pitch 70 from = 1/1 (2/1) to 3/2 (3/1) becomes 11/10 8/5 - 1/2 pitch 69 from = 3/2 (3/1) to 5/2 (5/1) becomes 8/5 51/20 - 19/20 bar 3 pitch 67 from = 0/1 (0/1) to 1/2 (1/1) becomes 0/1 11/20 - 11/20 pitch 65 from = 1/2 (1/1) to 1/1 (2/1) becomes 11/20 11/10 - 11/20 pitch 67 from = 1/1 (2/1) to 3/2 (3/1) becomes 11/10 8/5 - 1/2 bar 4 writing MIDI file stress The fix is to apply the stress model prior to combining the tied notes. The fix was applied to the function finishfile() in store.c April 10 2014 Abc2midi bug: The P: field was introduced to allow repeating parts of the tune in complex patterns such as P:ABCBD; however it is frequently used just to annotate a section of the music. When it is used as annotation, you often get annoying warnings such as. Error in line 10 : Part must be one of A-Z In some situations, this annotation may cause the music to play incorrectly. For example in this tune, X:1 T: part annotationmistaken M: 3/4 K: G V:1 B3c BA|B3c BA|B4e2|B3d ef| g4 g2|f4 e2|f3 gf2|B6| V:2 G3A GF|G3A GF|E4B2|G4E2| P: section B B4 B2|^d4 ^c2|^d3 e d2|F6| the last line in V:2 is played twice. Fix: in event_part() in store.c we check whether a valid P: command like P:A2BC was detected in the header. If none was found, abc2midi ignores any P: commands after the header. April 24 2014 abc2midi: slur bug Abc2midi sometimes reports unbalanced slurs when they are actually correct. For example X:1 T: Slur error messages L:1/8 M:2/2 Q:1/2=110 K:Dm P:A |: "Dm"a2ag a2ag | "^/"agfe dcAF | "Gm"GABA B^cdc | "^/"d^cBA BAGB | "A"A=B^cB cded | "^/"efgf eA=B^c | "^/"d(^ga)(e f)(^cd)(A |1 "^/"B)AFE GAdf :|2 "^/"B)AFE DCB,A, | P:B |: "Gm"G,BBB BcBB | "^/"B,BBB BcBB | "Dm"FAAA Adde | "^/"fedc AFED | "Gm"DBBB BcBB | "A"EAAA A=B^cA | "^/"d(^ga)(e f)(^cd)(A |1 "^/"B)AFE DCB,A,:|2 "^/"B)AFE "Dm"D4 | The following messages were returned. Warning in line 9 : No slur to close Warning in line 12 : No slur to close writing MIDI file colin1.mid Error in line 12 : Unexpected start of slur found Error in line 12 : Unexpected start of slur found Error in line 12 : Unexpected start of slur found analysis: abc2midi could not match the slurs when they cross into a part section (eg :[2 "^/" B) ...). fix: slur indications do not affect the output midi file so the messages are somewhat irrelevant. The warnings and error messages have been suppressed. August 11 2014 Introduced a new variable abcversion and parse the comment %%abc-version 2.0 or %%abc-version 2.1 if present. August 14 2014 Bug: line continuation of a lyric field w: does not work. In the following example, X:1 T: vocal M: 4/4 L: 1/4 K: G G A G B|\ E A G B| w: ga ba la ba |\ fa ma da ka| GGGB| w: la ma fa da| the line fa ma da ka is not processed as part of the previous w: field. Apparently there was an attempt in preparse_words(s) (in parseabc.c) to handle continuations of the w: field, however, the implementation was not complete. (There is no signal, telling parseline() to treat the continuation of the w: field.) Therefore this feature never worked in all of the abcmidi programs (abc2midi, abc2abc and yaps). I have decided not to support this feature and instead plan to introduce an alternative using the +: command defined in the 2.1 abc standard. The following warning message is now being issued when this situation is detected. Warning in line 8 : \n continuation no longer supported in w: line August 15 2014 New feature: the abc-version 2.1 standard introduces a new method for continuing the w; using the +: for lyrics. It also discourages the use of the backslash continuation. To handle the +: line, it was necessary to keep track of the last field command. A new global char lastfieldcmd was introduced in parseabc. The variable is modified at the end of function parsefield in parseabc.c. Presently it only signals a w: field command. For all other field commands it is set to a blank. A new case statement for +: was also introduced in parsefield(). It calls a new function, append_fieldcmd() if lastfieldcmd == 'w'. The function parseline() was extended to recoginize +: as a valid field command. The function parsefield() was modified to allow the +: command to appear in the body of the tune. August 16 2014 Continuing from above: introduced a new function concatenatestrings() in parseabc.c. In store.c, yapstree.c, toabc.c and matchsup.c introduced a new function called appendfield(). Appendfield() was only implemented in store.c where it calls a new function called append_words. In the files, appendfield() merely returns a message that it is not implemented yet. September 07 2014 Continuing from above: the function appendfield() in toabc.c was replaced so abc2abc will also handle the +: command. Note that abc2abc the -n X option which reformats with a new linebreak every X bars will probably not work correctly when the tune contains lyrics. September 09 2014 Abc2midi fix: the !bend! action does not apply correctly to microtones. In the following example: X:1 T: bend about microtone M: 4/4 L: 1/4 K: G !bend!_1/4D2 z2|!bend!D2 z2| !bend!^1/4D2 z2|!bend!D2 z2| All the bends start from D natural. Analysis: queues.c always initializes pitchbend to 8192 rather than the value set by the microtone. Fix: it was necessary to introduce another global variable, int bendstate, to be shared between genmidi.c and queues.c. The variable bendstate stores the pitchbend value when midi_noteon is called (in genmidi.c). In note_effect() in queues.c, pitchbend is set to bendstate rather than 8192. September 10 2014 September 11 2014 Abc2midi: introducing %%MIDI bendstring n1 n2 n3 ... This is a more general way of specifying the pitchbend track for a note. The command is followed by a series of integers n1, n2 etc. which specify the change to pitchbend following each time increment. Method: In genmidi.c introduced the array benddata[16] which holds the series of integers and bendnvals the number of these integers. Benddata and bendvals is passed to genmidi through an extern declaration. In dodeferred() in genmidi.c added a test for %%MIDI bendstring. In queues.c added a new function, note_effect2() which increments the pitchbend variable by benddata[i], and produces a %%MIDI pitchbend command at regular time intervals. In genmidi.c introduced a variable bendtype and set it to 1. The %%MIDI bendstring command sets bendtype to 2 to signal that the function note_effect2() should be called instead of note_effect(). September 22 2014 September 23 2014 September 24 2014 Abc2midi: when only one integer follows the %%MIDI bendstring command, the !bend! command now applies the pitchbend to the entire note. This provides another method for shifting the pitch of the note instead of preceding it with a microtone accidental. At the end of the note, the pitch of the note is restored to its original value. Implementation: in dodeferred() in genmidi.c we check for just one value following the bendstring command and set the bendtype variable to 3 so that queues.c calls the new function note_effect3(). September 28 2014 Extended the maximum bendstring length to 50. October 16 2014 Abc2midi: in some applications it may be desirable to suppresses all messages. A new option -silent was introduced to suppress the the other warnings and messages not handled by the -quiet option. eg. abc2midi nottingham.abc -silent -quiet produces almost not output except for the MIDI files. October 29 2014 ... Abc2midi: more work was done with the bar repeat code in store.c Abc2midi returns the incorrect line number when it detects a problem with bar length on repeat. Analysis: there are two functions which attempt to detect and fix problems with repeats in store.c -- scan_for_missing_repeats() and fixreps() each trying to fix different problems. When the abc tune does not have voices or parts, it was discovered that voicestart[0] is still initialized to zero and does not indicate the position of the start of the music line further the inserted DOUBLE_BAR code was placed in the wrong place by the function headerprocess(). The function scan_for_missing_repeasts() was modified to search for the first instance of MUSICLINE and to insert a DOUBLE_BAR feature immediately after. The voicestart[0] variable was set to this position. November 02 2014 Incorporated changes to the makefile and manpages suggested by Ross Gammon who does Debian Quality Assurance. November 02 2014 Abc2midi bug: the b code in the gchord string does not work correctly when there are inversions. eg. X:1 T: gchord M: 4/4 L: 1/4 K: C %%MIDI gchord fb "C" z4|"C/E" z4| The second bar is played at E,,4 [C4G,4E,4C,,4] instead of E,,4 [C4G,4E,4E,,4] Fix: In dogchords() (genmidi.c) case 'b' was changed so that it is identical to case 'f' except that there is no break ending that case (it progresses to case 'c'). November 9 2014 Abc2midi grace bug: in the following example, the grace notes cause a loss of synchronization between the two voices. X:1 T:Grace problem M: 2/4 L: 1/4 K: G Q:1/4 =60 V:1 {cde}f/|ed|cB| V:2 z|CD|CD| According to the documentation the grace notes are given a length of 1/8 or half of the unit length specified in the L: field. The three grace notes cde add up to be longer than the home note f, so it is impossible to trim f in order to accommodate the grace sequence. According to the documentation, abc2midi should cut out the grace sequence in order to avoid loss of synchronization. Instead abc2midi does not affect the grace sequence and the two voices are out of synchronization. Analysis: the function applygrace_new() in store.c computes the difference between the length of the grace sequence and the home note, but the test should read if (adjusted_num <= 0.0) /* not long enough */ instead of if (adjusted_den <= 0.0) I would guess this bug has been around since 2004. In addition I added a warning that the grace sequence is too long. The code to change the length of the grace notes to zero did not work correctly for some reason that I have not tried to figure out -- (mf_write_midi_event tries to record a delta_time = -1). Instead I just removed all the grace notes from the feature representation. November 18 2014 Abc2midi fermata bug: the !fermata! instruction applied to a rest also applies to the following chord. In the following example, X:1 T: fermata rest bug. L: 1/8 M: 6/8 K:D !fermata!z6 |[A,DF]2G [CDFA]GF |C D2 C D2| Both z6 and [A,DF]2 are doubled in length. Incidently if we substituted Hz6 for !fermata!z6, the program works correctly. Analysis: as evident in this file, this is not the first !fermata! bug. Apparently in this case, decorators[FERMATA] flag was not reset to 0 after the event_rest() in parseabc.c. The fix was to add the statement decorators[FERMATA] = 0 after the event_rest() call in parseabc.c. Note it is not correct to apply a fermata to a multirest. i.e. Z3| means three bars of rests. HZ3 does not mean three bars of fermata rests and the same applies to !fermata!Z3. In addition, I have improved the bar length warning to include the track number where it was applied. The track number is related to the voice number in some way. December 25 2014 Abc2midi new feature: the error and warning messages now provide both the line and character position location in the abc tune where the message was issued. Implementation: the character position is stored in the variable lineposition in parseabc.c. This variable is linked as an extern to store.c and genmidi.c. A new array charloc[] in store.c was introduced to record the character position when addfeature() is called. When writetrack is executed in genmidi.c, lineposition is updated for each feature element processed. lineposition and linenum are now both printed by event_error() and event_warning() in store.c. February 22 2015 bugs.debian.org reported that abc2abc, abcmatch, yaps, and midi2abc crash with certain malformed input parameters. Fixes were applied to toabc.c, abcmatch.c, yapstree.c and midi2abc.c. March 11 2015 Abc2midi multirest bug. It is common to list the voices before the time signature and unit length declaration. X:1 T: correct test file V:1 name="1_Requinta_Eb" sname="1Re_Eb" %config, program 1 72 /control 7 80 /transpose +3 V:2 name="1_Clarineta_Bb" sname="1Cl_Bb" %config, program 2 71 /control 7 80 /transpose -2 V:3 name="1_Saxofone_Eb" sname="1Sx_Eb" %config, program 3 65 /control 7 80 /transpose +3 V:4 name="1_Corneta_Bb" sname="1Cr_Bb" %config, program 4 59 /control 7 80 /transpose -2 M: 2/4 L: 1/8 K: G V: 1 C4| C4| C4| C4| V:2 z4| z4| z4| z4| V:3 Z| Z| Z| Z| V:4 Z4| In this example abc2midi does not get the correct time signature and unit length for voices 1 to 3. Fix: Added a new function meter_voice_update(n,m) which sets the meter for all declared voices if not past the header. March 16 2015 Abc2midi - new feature. In theory there should not be any limit on the number of tracks that is produced provided that the user takes care of assigning the right channels to the voices. I have extended the voicecode array in parseabc.c so that 24 voices can be handled without overruning the array. In genmidi.c I have merely changed the name of the array channels[] to channel_in_use[] so its purpose is better understood. The use of more than 16 tracks will lead to some warnings issued but the program should still produce a useful MIDI file. March 23 2015 Abc2midi - improvements. In order to support extended voice overlay, introduced two new functions event_start_extended_overlay() and event_stop_extended_overlay which are called from parsemusic() in parseabc.c when (& or &) are detected in the abc file. The two functions are defined in store.c, toabc.c, yapstree.c and matchsup.c. The functions turn on and turn off the state variable extended_overlay_running. In event_specific() in store.c we verify that channel in %%MIDI channel command lies between 1 and 16 inclusive. If not it is set to 1 and an error message is issued. A new state variable no_more_free_channels is introduced in store.c and set to zero in finishfile(). When findchannel() in genmidi.c cannot find a free channel a message "All 16 MIDI channels used up" is issued and the variable no_more_free_channels is set to 1. March 24 2015 Abc2midi - improvements. Abc2midi in the past did not keep track of the channel assignments. If we allow inheriting channel assignments for split voices, now called voice overlays, we need to know the MIDI channel assigned to the voice. I added midichannel to the voicestruct in store.c to store the MIDI channel when a %%MIDI channel is encountered. So far %%MIDI channel also calls addfeature() to add a channel feature in the feature array. (This is how the channel number has been passed to writetrack in the past.) The function findchannel() in genmidi.c does not know that a channel number was already assigned to the track (if that was the case). The voicestruct is not passed to genmidi.c from store.c but trackdescriptor is passed as an external. I therefore added midichannel to trackstruct in genmidi.h and set trackdescriptor.midichannel in the function setup_trackstructure() in store.c. Added an argument tracknum to starttrack() in genmidi.c so it can grab the midichannel number from trackdescriptor[]. The function event_split_voice() now passes the midi channel number assigned to the voice to the new voice that it creates. The behaviour of the split voice now depends on whether a channel number has been assigned to the original voice. If no channel number has been assigned, then both the original and child voice will have a midichannel of -1. If the value is -1, then a new and distinct channel number is assigned to each voice. Otherwise the original and child voices will assume to the same channel number that was given when the voice was created. March 25 2015 March 26 2015 Adding code to support extended split voices. In event_bar (store.c) do not recurse back to the original voice if inside an extended_overlay. In stop_extended_overlay(), recurse back to the original voice. The following is an example of the extended voice overlay. X:1 T: extended voice overlay M:2/4 L:1/4 K:C GA|(&Bc|de|de&FG|FG|FG|&)|DE| GA|(&Bc|de|de&FG|FG|FG|&)|DE| April 08 2015 The parsing of the key signature when it contains modifiers with double flats or double sharps does not work correctly. For example: X:1 T: double flat M: 2/4 L: 1/8 K: Ab _F__B_/2C F2 B2|C2D2| The double flat preceeding B in the key signature was interpreted as a single flat and B2 in the first bar was converted to Bb instead of A. Fix: the logic in readword() in parseabc.c was changed so that a break does not occur on the second flat or sharp. April 13 2015 Abc2midi, abc2abc, yaps : minor bug. The tune X:1 T: single colon M: 2/4 L: 1/8 K: F [|: ABcd|ABDF:|] returns a message 'Single colon in bar', otherwise the output is correct. Analysis: this is a problem with parsemusic() in parseabc.c. When the parser encounters | it check for a : following and treats them both as BAR_REP. On the other hand if the parser encounters [| it neglects to check for a following : and the : is not associated with anything. Fix: added a check for ':' in case '['. April 17 2015 Abc2midi staccato chord bug. %abc-2.1 X:1 T: staccato problem M:2/4 L:1/4 Q:1/4=116 K:D % V:K % % Case 1: works if isolated: % F A/ .[DF]/ | % % Case 2: works: % F A/ [.D/.F/] | E E & Cx | % % Case 3: works: % F A/ [DF]/ | E E & Cx | % % Case 4: doesn't work: F A/ .[DF]/ | E E & Cx | % % Case 5: doesn't work: F A/ [.D.F]/ | E E & Cx | Both cases 4 and 5 return an error message Warning in line-char 26-28 : Track 2 is 4.554167 quarter notes long not 4.054167 and the note C# in the voice overlay comes 1/2 beat late. Analysis, the staccato introduces a REST in the internal representation of the chord. When the length of the chord is specified at the end of the abc chord representation, eg. [CEG]n/m), abc2midi calls the function fix_enclosed_note_lengths which changes the lengths of all the enclosed notes to n/m. Unfortunately, the REST in the chord was not expected and was not modified. The representation of the underlying voice is incorrect and as a result the overlain voice does not get synchronized at the right place. Fix: now test for NOTE, TNOTE and REST in the chord in the function fix_enclosed_note_lengths in store.c. April 28 2015 Abc2midi: dotted slur The abc standard recognizes dotted slurs which abcm2ps displays as a slur with a dotted curve. The dotted slur is indicated with parenthesis preceded by a period as shown below. X:1 T: DottedSlur M: 2/4 L: 1/8 K: A .(ABcd)|(ABcd)|ABcd| Currently abc2midi reports the error. Error in line-char 6-0 : Malformed note : expecting a-g or A-G Analysis: parsemusic() in parseabc.c assumes '.' is a staccato decoration and expects a note to follow. Instead it sees a '(' and reports an error. Since abc2midi does not treat slurs differently, the resulting MIDI file is correct. Fix: If a '.' is encountered, parsemusic checks for a following '('. The fix also affects abc2abc, yaps, and abcmatch. April 29 2015 Abc2midi always prints its version number when it runs. May 11 2015 Abc2midi does not recognize the inline command [r: some remark]. X:1 T:Remark not allowed C:JWDJ M:4/4 L:1/4 K:C [K:D] A2 B2| [r:!fermata!]G4 |] Analysis: the 2.1 standard allows users to enter a remark inside a line using the [r: ...] inline field. This command should be treated the same way as a comment indicated with a '%' in the first column of the text line (eg.) % comment Abc2midi does not recognize r: inside an inline field command and reports an error. Error in line-char 7-13 : Field not allowed in tune body Fix: In parsefield() in parseabc.c, added r to the string EIKLMPQTVdswW+ . Thus if ((inbody) && (strchr ("EIKLMPQTVdrswW+", key) == NULL)) /* [SS] 2015-05-11 */ The following switch statement falls into case default: which treats the field as plain text. Note: Though the standard probably allows the remark to extend over several lines, eg. X:1 T:Long remark not allowed C:JWDJ M:4/4 L:1/4 K:C [K:D] A2 B2| [r: some long remark]G4 |] this is not supported in the abcmidi package. (It would require more extensive modification.) The user should use '%' to insert multiline comments. May 13 2015 abc2midi, abc2abc, yaps voice transpose bug. In the following sample, X:1 T: octave problem M: 4/4 L: 1/4 V:1 clef=treble octave=-1 V:2 clef=treble octave=-1 K:G V:1 ABCD|EFGA| V:2 abcd|ABCD| Applying abc2abc to the tune returns X:1 T:octave problem M:4/4 L:1/4 V:1 clef=treble octave=0 V:2 clef=treble octave=0 K:G V:1 ABCD|EFGA| V:2 abcd|ABCD| octave was changed to zero and abc2midi applied on the same tune does not shift down the pitch by an octave. If we change V:1 and V:2 to V:1 octave=-1 V:2 octave=-1 the programs work correctly. Analysis: This is an issue with the code parsevoice() in parseabc. The clef=treble also specifies the octave and sets the flag cgotoctave to 1. This flag indicates that the octave is also set by the clef command. If you wanted octave=-1 you should say clef=treble-8. To avoid further confusion, in the future, I modified parsevoice so that it allows octave= following the clef= property to override the octave value set by the clef= property. The parsevoice() code is rather brittle and expects all the voice parameters to be in a specific order. The code looks for the following properties in this order. clef= transpose= octave= name= sname= middle= If the properties are not in this order, they may be missed. The function parsevoice scans the V: string looking for the properties in the specific order using the 'while (*s != '\0). Each time a property is found the pointer *s is advanced past that property by one of the functions parsetranspose(), parseoctave(), parsename(), and etc and the while loop goes back to the beginning. parseclef() is called repeatedly and even though it does not find clef=, it still returns the variable 'word' which is used for matching by the above mentioned functions. If I am rewriting the code, I would replace casecmp() with strcmp() and use a switch (word) control to call one of the functions parsetranspose(), parseoctave(), and etc. This involves changing all of those functions too. Note parsetranspose() and parseoctave() are also called when the K: field is scanned. May 17 2015 abc2midi: %%MIDI makechordchannels bug The makechordchannels command was introduced in October 3 2006 for handling chords consisting of notes consisting of microtones. When the command appears after a V: declaration, too many chord channels are created which may cause the 15 channel limit (one channel is used for percussion), to be exceeded. For example, X:1 T: too many chord channels M: 2/4 L: 1/4 K:G V:1 %%MIDI beataccents %%MIDI makechordchannels 7 G2| V:2 %%MIDI program 42 %%MIDI nobeataccents E2| V:3 %%MIDI program 43 C2| The following errors are reported. Error in line-char 10-2 : All 16 MIDI channels used up. Error in line-char 15-2 : Channel limit exceeded Analysis: During the creation of track 0 (the header track in a type 1 MIDI file), the entire tune is scanned and some of the MIDI commands are activated. Unfortunately, the makechordchannels is activated twice; once for track 0 and once for track 1. The chord channels created in track 0 are never used. An abc tune that creates at type 0 MIDI file, (i.e. no voices, guitar chords, percussion etc.) would not pose a problem for this implementation. Fix: Added a test in the function makechordchannels (in genmidi.c) to prevent the creation of chord channels in track 0 for multitrack MIDI files. May 19 2015 Abc2midi temperament support was extended by Hudson F.M. Lacerda. Microtone accidentals can be used along with temperamentlinear. In that case, the accidental ratio is based on the new chromatic semitone size, defined as 7 fifths minus 4 octaves. (Run abc2midi with the verbose option (-v) to see the temperament values.) As an exception, the microtonal deviation in cents can be represented by using denominator=100 in the accidentals. For example:
X:1
T:\%\%MIDI temperamentlinear - microtone accidentals in cents
%%postscript /ft5475{M -3 3 RM 6 -6 RL 2 SLW stroke}def
%%postscript /ft35939{2 copy ft0 M -7.5 -3 RM 12 F3 (7) show}def
M:none
K:C
%%scale 1.3
V:1
%%MIDI program 17
%%MIDI temperamentlinear 1200 702 %% Pythagorian tunings
%%MIDI makechordchannels 3
"^Pure;major;chord"\
[C_22/100EG]8 y |\
"^Pythagorian;major;chord"\
[CEG]8 y ||\
"^Pure;4:5:6:7;chord"\
[C_22/100EG_141/100B]8 y |\
"^Pythagorean;7-chord"\
[CEG_B]8 y ||

A new command %%temperamentequal was introduced.
%%MIDI temperamentequal [octave_cents] [fifth_steps] [sharp_steps] This command sets a tempered scale defined by 'ndiv' equal divisions of 'octave_cents' (default is the octave = 1200 cents). The optional parameter 'fifth_steps', if provided, is an integer that defines the size of the fifth in steps of the temperament. This sets where is the note G in the temperament. When 'fifth_steps' is omited or 0 (zero), the program computes it as an approximation of the frequency ratio 3/1, minus the (possibly tempered) octave. The optional 'sharp_steps' defines the meaning of the accidentals. 'sharp_steps' is the number of steps between a natural note and a sharpened note (e.g. between =C and ^C). By default, the size of a sharp/flat deviation is based on the size of the chromatic semitone in the specified temperament: 7 fifths minus 4 octaves. The values in use in the temperament can be viewed by running abc2midi with the command-line option -v (verbose). With temperamentequal (as with temperamentlinear), microtone accidentals are interpreted as fractions of the sharp size in the specified temperament, except if they use denominator=100, which defines microtonal deviations in cents. The conventional temperament can be reset with the command temperamentnormal. See also: temperamentlinear, temperamentnormal, makechordchannels Implementation: Changes in store.c are marked with [HL] 2015-05-15 New global variable 'sharp_size' It is the the size, in pitchbend units, of the chromatic step between (e.g.) =C and ^C. (This is computed from octave and fifth sizes when using temperamentlinear or temperamentequal.) event_specific() Function changed to modify the command temperamentlinear and to add the command temperamentequal. temperamentlinear: Compute 'sharp_size'; Print information when -v (verbose option); Fix the command name in the error message. temperamentequal (new command): Compute octave_size, fifth_size, sharp_size; Temperament information when -v (Verbose option). pitchof_b() Function changed to handle microtones in user-defined temperaments. Global variable 'sharp_size' is used for that. event_microtone() Rounding instead truncation as slight improvement of precision. (MIDI bend is rough for tuning.) May 21 2015 Abc2midi drone bug: The %%MIDI drone command is ineffective. In the following example, X: 1 T:Banks and Braes M:6/8 L:1/8 S:Slow March K:HP %%MIDI program 109 %%MIDI gracedivider 4 %%MIDI drone 67 44 45 90 90 %%MIDI droneon {Gdc}d2{g}d{g}ede|\ {g}faf{gef}e2{g}d/2e/2| the %%MIDI drone 67 44 45 90 90 does not change the drone characteristics. Analysis: The drone is put in a separate MIDI track. The %%MIDI drone command is processed in the first track, and updates the elements of the drone structure. When the drone track is written starttrack() in genmidi.c, initializes the drone structure destroying any information that was recorded. Fix: initialization of the drone structure is done during compilation time. Note, if the tune has more than one %%MIDI drone command, only the last one is effective. June 01 2015 Abc2midi new feature: introducing new commands %%MIDIdef and %%MIDIx. %%MIDIdef code line links code a unique string less than 7 letters to a line of strings that normally occurs in a MIDI command. For example %%MIDIdef bnd1 bendstring 400 400 300 100 -100 300 400 400 400 link the string bnd1 to " bendstring 400 400 300 100 -100 300 400 400 400" Now you can call up the MIDI command %%MIDI bendstring 400 400 300 100 -100 300 400 400 400 using a shorthand %%MIDIx bnd1. Example: X:1 %%MIDIdef type1 bendstring 0 0 600 600 600 600 0 -600 -600 -600 -600 -600 -120 0 %%MIDIdef type2 bendstring 0 0 0 0 0 0 400 800 800 -800 -800 -400 -400 -400 %%MIDIdef inst program 67 %%MIDIdef t3 bendstring 0 0 0 0 0 500 500 600 600 -600 -600 -500 -500 T: MIDI M:2/4 L:1/2 K: D %%MIDIx inst %%MIDIx type1 !bend!A|B|\ %%MIDIx type2 !bend!C|D| This is useful when you have several different bendstrings and you wish to call them up in different places in the tune using a code. There is a limit of 20 distinct MIDIdef's in your tune. Implementation: in parseabc.c added a new function readaln which is like readstr but scans for the next word (that may contain numerics) in the input string. (The words are separated by spaces or tabs.) In store.c, added two new functions parse_mididefs(s) and expand_midix(s) for handling the %%MIDIdef and %%MIDIx commands. These functions are called in the function event_specific(). June 02 2015 continuation: added strcmp(key, "MIDIx") in event_info_key() in store.c June 07 2015 Abc2midi bug: the !bend! command does not work inside a slur. In the following example, X:1 T: slur and bend M: 2/4 L: 1/8 K: F %%MIDI bendstring 500 500 500 0 -500 -500 -500 %%MIDI program 73 !bend! D4|(!bend! F4| D4| a bend is not applied on F4. Analysis: writetrack() in genmidi.c tests whether a note is inside a slur. If it is inside a slur, both note triming and note bending were suppressed. Fix, writetrack() was modified to allow note bending inside a slur. The MIDIdef, MIDIx code word was allowed to contain up to 31 characters. All characters except white spaces are allowed inside the code word. June 08 2015 Abc2midi bug: !bend! causes tracklenth to be too small. Fix: in timestep() in queues.c, update tracklen before note_effect is called instead as after. June 16 2015 Abc2midi new feature: introducing %%MIDI expand m/n. This acts like %%MIDI trim m/n except it expands the note by this amount. Implementation: added feature EXPAND to featuretype in abc.h. In event_specific() in store.c, test for %%MIDI command 'expand' and addfeature(EXPAND,...) if found. In genmidi.c introduce new globals (expand, expand_num, and expand_denom) which are set in writetrack when feature EXPAND is detected. If the flag expand is set, then the active note is expanded. Here is a test tune. X:1 T: note expansion M: 4/4 L: 1/2 K: G %%MIDI program 52 CD|GA| %%MIDI expand 1/2 de|fe|BA| June 16 2015 Abc2midi new feature: added track identification annotation to midi file so we know whether it is a gchord, note, lyric, drum, etc track. June 30 2015 Abc2midi split voice bug: change of unit length defined by L: does not propagate to the voice overlay. eg. X:1 T: split voice bug - unit length M: 4/4 L:1/8 K: G C8 & E8|\ L:1/4 cdAB & GAEF|G4 & D4:| causes loss of synchronization starting from the second measure. Analysis: the L:1/4 does not change the unit length in the split voice and the notes GAEF and D4 are too short. Fix: in event_split_voice() in store.c set the unit length to the same length as the parent voice. July 02 2015 Abc2abc bug: the fix introduced in May 13 2015 introduced another problem. In the example X:1 T: Octave M: 2/4 L: 1/8 K: G V:1 clef=treble+8 CDEF|ABcd| Applying abc2abc returns X:1 T:Octave M:2/4 L:1/8 K:G V:1 clef=treble+8 octave=1 CDEF|ABcd| Unfortunately the added parameter octave=1 causes abcm2ps to also display the notes one octave higher. Analysis: the parameter octave=1 is useful to abc2midi as it tells the program to shift the notes up one octave when it creates the midi file; however, this is not desired when running abcm2ps. Abcm2ps uses clef=treble+8 to place an 8 above the treble clef and that is sufficient. The problems occurs in the function isclef() in parseabc.c. The function changes gotoctave to 1 when it sees treble+8. The fix on May 13 2015 forces event_voice to issue an octave=1 when it sees cgotoctave = 1. Fix: in isclef() a conditional block {} was created for all if (fileprogram == ABC2MIDI && *gotoctave != 1 && *octave != 1) statements, and *gotoctave = 1 was moved inside this block. July 08 2015 abc2midi feature: added sus4 to the list of chord names recognized. Added hint to message 'Unrecognized chord name ...". July 15 2015 abc2midi bug: abc2midi crashes (segmentation error) on %%MIDIx. In the following example: X:1 T: segmentation error M: 2/4 L: 1/8 K: G %%MIDIx crash ABCD| abc2midi fails. Analysis: abc2midi fails to detect that there is no corresponding %%MIDIdef for the code word 'crash'. Fix: the function expand_midix() now checks for this case. July 24-28 2015 abc2midi: new feature !shape! and %%MIDI controlstring. Introduced a new midi command %%MIDI controlstring n m1 m2 m3 ... where n, m1, m2, and etc are numbers between 0 and 127. %%MIDI controlstring n m1 is equivalent to the %%MIDI control command. When more than one data value m1 and etc. follow, then this defines how to shape the note following the !shape! instruction. The following example illustrates shaping the note F4 by varying the mod wheel. X:1 T: control string M: 4/4 L: 1/4 K: G %%MIDI controlstring 1 125 80 40 0 %%MIDI program 60 !shape! F4| D4|F2G2| The midi file produced will look like Header format=0 ntrks=1 division=480 Track 1 contains 115 bytes 0.00 Metatext (Text Event) note track 0.00 Metatext tempo = 120.00 bpm 0.00 Metatext key signature G (1/0) 0.00 Metatext time signature=4/4 0.00 Metatext (Seqnce/Track Name) control string 0.00 Program 1 60 (French Horn) 0.00 Note on 1 f#4 105 1.00 CntlParm 1 Modulation Wheel = 125 2.00 CntlParm 1 Modulation Wheel = 80 3.00 CntlParm 1 Modulation Wheel = 40 3.99 CntlParm 1 Modulation Wheel = 0 4.00 Note off 1 f#4 0 4.00 Note on 1 d4 105 8.00 Note off 1 d4 0 8.00 Note on 1 f#4 105 10.00 Note off 1 f#4 0 10.00 Note on 1 g4 95 12.00 Note off 1 g4 0 12.05 Meta event, end of track The whole note F# is modified in 4 equal segments. Note the !shape! does not work in combination with the !bend! command presently. Implementation: created the new function note_effect4() in queues.c The maximum number of codenames for %%MIDIdef has been increased to 200. The codename can now be as long as 31 letters. July 27 2015 - August 3 2015 abc2midi: extension of !shape! for combining %%MIDI controlstring and %%MIDI bendstring. Implementation: added a new struct eventstruct and a struct array eventlist[200]. Created new procedures note_effect5(), output_eventlist(), and compare_events(). August 4 2015 abc2midi: channel bug. The following tune plays incorrectly. X: 1 T: channel problem M: 6/8 L: 1/8 K: G %%MIDI channel 1 %%MIDI bassprog 68 %%MIDI chordprog 20 D | "G"G3 GAB | "D"ABA ABd | The melody should be played on the Acoustic Piano; instead it is played on the oboe (MIDI program 68). Analysis: The %%MIDI channel setting is redundant and causes the problem. Both the melody and the bass accompaniment use the same channel. The command %%MIDI bassprog 68 causes the melody to be played by program 68 (the oboe). The bug was introduced in March 16 2015. The variable channel_in_use[channel] was not set to 1 correctly in starttrack() in genmidi.c. August 06 2015 Fixed compile issue on Mac OS 10.10.4 in genmidi.c August 10 2015 - August 11 2015 abc2midi new feature: %%MIDI controlstring restores the controller back to its default after the shaped note is played. The default can be changed with a regular %%MIDI control command. Implementation: added a new array controldefaults[] in genmidi.c which is linked to queue.c. abcmidi/Makefile.in0000644000000000000000000001175212604111246013214 0ustar rootroot# Generic unix/gcc Makefile for abcMIDI package # # # compilation #ifdefs - you need to compile with these defined to get # the code to compile with PCC. # # NOFTELL in midifile.c and genmidi.c selects a version of the file-writing # code which doesn't use file seeking. # # PCCFIX in mftext.c midifile.c midi2abc.c # comments out various things that aren't available in PCC # # ANSILIBS includes some ANSI header files (which gcc can live without, # but other compilers may want). # # USE_INDEX causes index() to be used instead of strchr(). This is needed # by some pre-ANSI C compilers. # # ASCTIME causes asctime() to be used instead of strftime() in pslib.c. # If ANSILIBS is not set, neither routine is used. # # KANDR selects functions prototypes without argument prototypes. # currently yaps will only compile in ANSI mode. # # # On running make, you may get the mysterious message : # # ', needed by `parseabc.o'. Stop `abc.h # # This means you are using GNU make and this file is in DOS text format. To # cure the problem, change this file from using PC-style end-of-line (carriage # return and line feed) to unix style end-of-line (line feed). VERSION = @VERSION@ CC = @CC@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ CFLAGS = -DANSILIBS @CFLAGS@ CPPFLAGS = @DEFS@ @CPPFLAGS@ -I. LDFLAGS = @LDFLAGS@ -lm prefix = @prefix@ exec_prefix = @exec_prefix@ srcdir = @srcdir@ VPATH = @srcdir@ bindir = @bindir@ libdir = @libdir@ datadir = @datarootdir@ docdir = @datarootdir@/doc/abcmidi mandir = @datarootdir@/man/man1 binaries=abc2midi midi2abc abc2abc mftext yaps midicopy abcmatch all : abc2midi midi2abc abc2abc mftext yaps midicopy abcmatch OBJECTS_ABC2MIDI=parseabc.o store.o genmidi.o midifile.o queues.o parser2.o stresspat.o abc2midi : $(OBJECTS_ABC2MIDI) $(CC) $(CFLAGS) -o abc2midi $(OBJECTS_ABC2MIDI) $(LDFLAGS) -lm $(OBJECTS_ABC2MIDI): abc.h parseabc.h config.h Makefile OBJECTS_ABC2ABC=parseabc.o toabc.o abc2abc : $(OBJECTS_ABC2ABC) $(CC) $(CFLAGS) -o abc2abc $(OBJECTS_ABC2ABC) $(LDFLAGS) $(OBJECTS_ABC2ABC): abc.h parseabc.h config.h Makefile OBJECTS_MIDI2ABC=midifile.o midi2abc.o midi2abc : $(OBJECTS_MIDI2ABC) $(CC) $(CFLAGS) -o midi2abc $(OBJECTS_MIDI2ABC) $(LDFLAGS) $(OBJECTS_MIDI2ABC): abc.h midifile.h config.h Makefile OBJECTS_MFTEXT=midifile.o mftext.o crack.o mftext : $(OBJECTS_MFTEXT) $(CC) $(CFLAGS) -o mftext $(OBJECTS_MFTEXT) $(LDFLAGS) $(OBJECTS_MFTEXT): abc.h midifile.h config.h Makefile OBJECTS_YAPS=parseabc.o yapstree.o drawtune.o debug.o pslib.o position.o parser2.o yaps : $(OBJECTS_YAPS) $(CC) $(CFLAGS) -o yaps $(OBJECTS_YAPS) $(LDFLAGS) $(OBJECTS_YAPS): abc.h midifile.h config.h Makefile OBJECTS_MIDICOPY=midicopy.o midicopy : $(OBJECTS_MIDICOPY) $(CC) $(CFLAGS) -o midicopy $(OBJECTS_MIDICOPY) $(LDFLAGS) $(OBJECTS_MIDICOPY): abc.h midifile.h midicopy.h config.h Makefile OBJECTS_ABCMATCH=abcmatch.o matchsup.o parseabc.o abcmatch : $(OBJECTS_ABCMATCH) $(CC) $(CFLAGS) -o abcmatch $(OBJECTS_ABCMATCH) $(LDFLAGS) $(OBJECTS_ABCMATCH): abc.h midifile.h config.h Makefile parseabc.o : parseabc.c abc.h parseabc.h parser2.o : parser2.c abc.h parseabc.h parser2.h toabc.o : toabc.c abc.h parseabc.h # could use -DNOFTELL here genmidi.o : genmidi.c abc.h midifile.h genmidi.h stresspat.o : stresspat.c store.o : store.c abc.h parseabc.h midifile.h genmidi.h queues.o : queues.c genmidi.h # could use -DNOFTELL here midifile.o : midifile.c midifile.h midi2abc.o : midi2abc.c midifile.h midicopy.o : midicopy.c midicopy.h abcmatch.o: abcmatch.c abc.h crack.o : crack.c mftext.o : mftext.c midifile.h # objects needed by yaps # yapstree.o: yapstree.c abc.h parseabc.h structs.h drawtune.h drawtune.o: drawtune.c structs.h sizes.h abc.h drawtune.h pslib.o: pslib.c drawtune.h position.o: position.c abc.h structs.h sizes.h debug.o: debug.c structs.h abc.h #objects for abcmatch # matchsup.o : matchsup.c abc.h parseabc.h parser2.h clean : rm *.o ${binaries} install: abc2midi midi2abc abc2abc mftext midicopy yaps abcmatch $(INSTALL) -d $(DESTDIR)$(bindir) $(INSTALL) -m 755 ${binaries} $(DESTDIR)$(bindir) # install documentation $(INSTALL) -d $(DESTDIR)${docdir} $(INSTALL) -m 644 doc/*.txt $(DESTDIR)$(docdir) $(INSTALL) -m 644 doc/AUTHORS $(DESTDIR)$(docdir) $(INSTALL) -m 644 doc/CHANGES $(DESTDIR)$(docdir) $(INSTALL) -m 644 VERSION $(DESTDIR)$(docdir) # install manpages $(INSTALL) -d $(DESTDIR)${mandir} $(INSTALL) -m 644 doc/*.1 $(DESTDIR)$(mandir) uninstall: echo "uninstalling..."; #rm -f $(DESTDIR)$(bindir)/$(binaries) rm -f $(DESTDIR)$(bindir)/abc2midi rm -f $(DESTDIR)$(bindir)/abc2abc rm -f $(DESTDIR)$(bindir)/yaps rm -f $(DESTDIR)$(bindir)/midi2abc rm -f $(DESTDIR)$(bindir)/mftext rm -f $(DESTDIR)$(bindir)/abcmatch rm -f $(DESTDIR)$(bindir)/midicopy rm -f $(DESTDIR)$(docdir)/*.txt rm -f $(DESTDIR)$(docdir)/AUTHORS rm -f $(DESTDIR)$(docdir)/CHANGES rm -f $(DESTDIR)$(docdir)/VERSION rm -f $(DESTDIR)$(mandir)/*.1 rmdir $(DESTDIR)$(docdir) abcmidi/config.h.in0000644000000000000000000000002411617434730013171 0ustar rootroot/* config.h.in */ abcmidi/toabc.c0000644000000000000000000017464512620356124012422 0ustar rootroot/* * toabc.c - part of abc2abc - program to manipulate abc files. * Copyright (C) 1999 James Allwright * e-mail: J.R.Allwright@westminster.ac.uk * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA * */ /* back-end for outputting (possibly modified) abc */ #define VERSION "1.84 November 10 2015 abc2abc" /* for Microsoft Visual C++ 6.0 or higher */ #ifdef _MSC_VER #define ANSILIBS #endif #include "abc.h" #include "parseabc.h" #include /* define USE_INDEX if your C libraries have index() instead of strchr() */ #ifdef USE_INDEX #define strchr index #endif #ifdef ANSILIBS #include #include #include #else extern char* strchr(); #endif #define MAX_VOICES 30 /* should be plenty! */ programname fileprogram = ABC2ABC; extern int oldchordconvention; /* for handling +..+ chords */ /* holds a fraction */ struct fract { int num; int denom; }; struct fract barlen; /* length of a bar as given by the time signature */ struct fract unitlen; /* unit length as given by the L: field */ struct fract count; /* length of bar so far */ struct fract prevcount; /* length of bar before last increment */ struct fract tuplefactor; /* factor associated with a tuple (N */ struct fract chordfactor; /* factor of the first note in a chord [PHDM] 2013-03-10 */ struct fract breakpoint; /* used to break bar into beamed sets of notes */ int barno; /* number of bar within tune */ int newspacing; /* was -s option selected ? */ int barcheck, repcheck; /* indicate -b and -r options selected */ int echeck; /* was error-checking turned off ? (-e option) */ int newbreaks; /* was -n option selected ? */ int nodouble_accidentals; int totalnotes, notecount; int bars_per_line; /* number supplied after -n option */ int barcount; int expect_repeat; int tuplenotes, barend; int xinhead, xinbody; /* are we in head or body of abc tune ? */ int inmusic; /* are we in a line of notes (in the tune body) ? */ int startline, blankline; int transpose; /* number of semitones to transpose by (-t option) */ struct fract lenfactor; /* fraction to scale note lengths; -v,-d options */ int newkey; /* key after transposition (expressed as no. of sharps) */ int lines; /* used by transposition */ int orig_key_number; /* used for gchord transposition */ int new_key_number; /* used for gchord transposition */ int oldtable[7], newtable[7]; /* for handling transposition */ int inchord; /* are we in a chord [ ] ? */ int ingrace; /* are we in a grace note set { } ? */ int chordcount; /* number of notes or rests in current chord */ int inlinefield; /* boolean - are we in [: ] ? */ int cleanup; /* boolean to indicate -u option (update notation) */ char tmp[2000]; /* buffer to hold abc output being assembled */ int output_on = 1; /* if 0 suppress output */ int passthru = 0; /* output original abc file [SS] 2011-06-07 */ long selected_voices = -1; /* all voices are selected [PHDM] 2013-03-08 */ int newrefnos; /* boolean for -X option (renumber X: fields) */ int newref; /* next new number for X: field */ int useflats=0; /* flag associated with nokey.*/ int adapt_useflats_to_gchords = 1; /* experimental flag */ int usekey = 0; int drumchan=0; /* flag to suppress transposition */ int noplus; /* flag for outputting !..! instructions instead of +...+ */ extern int nokey; /* signals no key signature assumed */ extern int voicecodes ; /* from parseabc.c */ extern char voicecode[16][30]; /*for interpreting V: string */ struct voicetype { /* information needed for each voice */ int number; /* voice number from V: field */ int barcount; int foundbar; struct abctext* currentline; int bars_remaining; int bars_complete; int drumchan; } voice[MAX_VOICES]; int voicecount, this_voice, next_voice; enum abctype {field, bar, barline}; /* linestat is used by -n for deciding when to generate a newline */ enum linestattype {fresh, midmusic, endmusicline, postfield}; enum linestattype linestat; /* struct abctext is used to store abc lines for re-formatting (-n option) */ struct lyricwords{ struct lyricwords* nextverse; char* words; }; struct abctext{ /* linked list used to store output before re-formatting */ struct abctext* next; char* text; enum abctype type; int notes; struct lyricwords* lyrics; }; struct abctext* head; struct abctext* tail; extern char *mode[]; extern int modekeyshift[]; int basemap[7], workmap[7]; /* for -nokey and pitchof() */ int workmul[7]; void copymap(); void printpitch(int); void setup_sharps_flats (int sf); int pitchof(char note,int accidental,int mult,int octave); static int purgespace(p) char* p; /* if string p is empty or consists of spaces, set p to the empty string */ /* and return 1, otherwise return 0. Used to test tmp */ /* part of new linebreak option (-n) */ { int blank; char *s; blank = 1; s = p; while (*s != '\0') { if (*s != ' ') blank = 0; s = s + 1; }; if (blank) { *p = '\0'; }; return(blank); } int zero_barcount(foundbar) /* initialize bar counter for abctext elements */ /* part of new linebreak option (-n) */ int *foundbar; { *foundbar = 0; return(0); } int new_barcount(type, foundbar, oldcount) enum abctype type; int *foundbar; int oldcount; /* work out whether we have reached the end of a bar in abctext elements */ /* and increment barcount if we have */ /* part of new linebreak option (-n) */ { int new_value; new_value = oldcount; if (type == bar) { *foundbar = 1; }; if ((type == barline) && (*foundbar == 1)) { new_value = new_value + 1; *foundbar = 0; }; return(new_value); } static void setline(t) enum linestattype t; /* generates newline, or continuation, or nothing at all */ /* part of new linebreak option (-n) */ { if ((t == fresh) && ((linestat == postfield) || (linestat == endmusicline))) { printf("\n"); }; if ((t == fresh) && (linestat == midmusic)) { printf("\\\n"); }; linestat = t; } static int flush_abctext(bars, termination) int bars; enum linestattype termination; /* outputs up to the specified number of bars of stored music */ /* and frees up the storage allocated for those bars. */ /* returns the number of bars actually output */ /* part of new linebreak option (-n) */ { struct abctext *p, *nextp; struct lyricwords *q, *r; struct lyricwords *barlyrics; int count, donewords, wordline; int i, foundtext; int foundbar; /* printf("flush_abctext called\n"); */ /* print music */ p = head; count = zero_barcount(&foundbar); while ((p != NULL) && (count < bars)) { if (p->type == field) { setline(fresh); }; printf("%s", p->text); if (p->type == field) { setline(postfield); setline(fresh); } else { setline(midmusic); }; count = new_barcount(p->type, &foundbar, count); if ((count == bars) && (p->type == barline)) { setline(endmusicline); }; p = p->next; }; if (linestat == midmusic) { setline(termination); }; if (bars > 0) { /* print out any w: lines */ donewords = 0; wordline = 0; while (donewords == 0) { p = head; foundtext = 0; count = zero_barcount(&foundbar); while ((p != NULL) && (count < bars)) { barlyrics = p->lyrics; for (i=0; inextverse; }; }; if (barlyrics != NULL) { if (foundtext == 0) { setline(fresh); printf("w:"); foundtext = 1; }; printf("%s",barlyrics->words); }; count = new_barcount(p->type, &foundbar, count); p = p->next; }; if (foundtext == 0) { donewords = 1; } else { setline(postfield); setline(fresh); }; wordline = wordline + 1; }; }; /* move head on and free up space used by stuff printed out */ count = zero_barcount(&foundbar); p = head; foundbar = 0; while ((p != NULL) && (count < bars)) { if (p != NULL) { free(p->text); q = p->lyrics; while (q != NULL) { free(q->words); r = q->nextverse; free(q); q = r; }; count = new_barcount(p->type, &foundbar, count); nextp = p->next; free(p); p = nextp; }; head = p; }; if (head == NULL) { tail = NULL; }; return(count); } void complete_bars(v) /* mark all bars as completed (i.e. having associated w: fields parsed) */ /* and out put all music lines which contain the full set of bars */ /* part of new linebreak option (-n) */ struct voicetype *v; { int bars_done; v->bars_complete = v->bars_complete + v->barcount; v->barcount = 0; while (v->bars_complete > v->bars_remaining) { bars_done = flush_abctext(v->bars_remaining, endmusicline); setline(fresh); v->bars_complete = v->bars_complete - bars_done; v->bars_remaining = v->bars_remaining - bars_done; if (v->bars_remaining == 0) { v->bars_remaining = bars_per_line; }; }; } void complete_all(v, termination) struct voicetype *v; enum linestattype termination; /* output all remaining music and fields */ /* part of new linebreak option (-n) */ { int bars_done; complete_bars(v); bars_done = flush_abctext(v->bars_remaining+1, termination); v->bars_complete = v->bars_complete - bars_done; v->bars_remaining = v->bars_remaining - bars_done; if (v->bars_remaining == 0) { v->bars_remaining = bars_per_line; }; head = NULL; tail = NULL; voice[this_voice].currentline = NULL; } static struct abctext* newabctext(t) enum abctype t; /* called at newlines and barlines */ /* adds current output text to linked list structure */ /* part of new linebreak option (-n) */ { struct abctext* p; if (output_on == 0) { p = NULL; return(p); }; if (newbreaks) { /* if ((t == field) && (!xinbody || (this_voice != next_voice))) { */ if (t == field) { complete_all(&voice[this_voice], midmusic); this_voice = next_voice; }; p = (struct abctext*) checkmalloc(sizeof(struct abctext)); p->text = addstring(tmp); tmp[0] = '\0'; p->next = NULL; p->type = t; p->lyrics = NULL; if (t == bar) { p->notes = notecount; totalnotes = totalnotes + notecount; notecount = 0; } else { p->notes = 0; }; if (xinbody) { voice[this_voice].barcount = new_barcount(t, &voice[this_voice].foundbar, voice[this_voice].barcount); }; if (head == NULL) { head = p; tail = p; } else { tail->next = p; tail = p; }; if ((t != field) && (voice[this_voice].currentline == NULL)) { voice[this_voice].currentline = p; }; } else { printf("%s", tmp); /* output to stdout is here */ tmp[0] = '\0'; p = NULL; }; inmusic = 1; return(p); } static int nextnotes() /* return the number of notes in the next bar */ /* part of new linebreak option (-n) */ { int n, got; struct abctext* p; p = head; n = 100; got = 0; while ((p != NULL) && (!got)) { if (p->type == bar) { n = p->notes; got = 1; } else { p = p->next; }; }; return(n); } static void reduce(a, b) int *a, *b; { int t, n, m; /* find HCF using Euclid's algorithm */ if (*a > *b) { n = *a; m = *b; } else { n = *b; m = *a; }; while (m != 0) { t = n % m; n = m; m = t; }; *a = *a/n; *b = *b/n; } /* * addunits must be called for each single note or rest and * at each chord end. When called at chordoff time, make * sure that inchord is still true. [PHDM] 2013-03-10 */ static void addunits(n, m) int n, m; /* add fraction n/m to count */ { if (inchord) { /* [PHDM] 2013-03-10 */ if (!chordcount) /* empty chord */ return; n *= chordfactor.num; m *= chordfactor.denom; } if (tuplenotes) { /* [PHDM] 2013-03-10 */ n *= tuplefactor.num; m *= tuplefactor.denom; tuplenotes = tuplenotes - 1; }; count.num = n*count.denom + count.num*(m*unitlen.denom); count.denom = (m*unitlen.denom)*count.denom; reduce(&count.num, &count.denom); } void parse_voices_selection(voices_string) /* [PHDM] 2013-03-08 */ char *voices_string; { char *s = voices_string; selected_voices = 0; if (voices_string == 0x0) return; /* [SS] 2015-02-22 */ do { int v = readnump(&s); selected_voices |= 1 << v; } while (*s++); } int must_emit_voice(n) /* [PHDM] 2013-03-08 */ int n; { return selected_voices & (1 << n); } void event_init(argc, argv, filename) int argc; char* argv[]; char** filename; /* routine called on program start-up */ { int targ, narg; if ((getarg("-h", argc, argv) != -1) || (argc < 2)) { printf("abc2abc version %s\n",VERSION); printf("Usage: abc2abc [-s] [-n X] [-b] [-r] [-e] [-t X]\n"); printf(" [-u] [-d] [-v] [-V X[,Y,,,]] [-P X[,Y...]] [-ver] [-X n]\n"); printf(" -s for new spacing\n"); printf(" -n X to re-format the abc with a new linebreak every X bars\n"); printf(" -b to remove bar checking\n"); printf(" -r to remove repeat checking\n"); printf(" -e to remove all error reports\n"); printf(" -t X to transpose X semitones\n"); printf(" -nda No double accidentals in guitar chords\n"); printf(" -nokeys No key signature. Use sharps\n"); printf(" -nokeyf No key signature. Use flats\n"); printf(" -u to update notation ([] for chords and () for slurs)\n"); printf(" -usekey n Use key signature sf (sharps/flats)\n"); printf(" -d to notate with doubled note lengths\n"); printf(" -v to notate with halved note lengths\n"); printf(" -V X[,Y...] to output only voices X,Y...\n"); printf(" -P X[,Y...] restricts action to voice X,Y..., leaving other voices intact\n"); printf(" -ver prints version number and exits\n"); printf(" -X n renumber the all X: fields as n, n+1, ..\n"); printf(" -OCC old chord convention (eg. +CE+)\n"); /*printf(" -noplus use !...! instead of +...+ for instructions\n"); [SS] 2012-06-04 */ exit(0); } else { *filename = argv[1]; }; nodouble_accidentals = 0; /* use correct guitar chords */ if (getarg("-ver",argc,argv) != -1) { printf("%s\n",VERSION); exit(0); } if (getarg("-u", argc, argv) == -1) { cleanup = 0; } else { cleanup = 1; oldchordconvention = 1; }; if (getarg("-s", argc, argv) == -1) { newspacing = 0; } else { newspacing = 1; }; narg = getarg("-X", argc, argv); if (narg == -1) { newrefnos = 0; } else { newrefnos = 1; if (narg < argc) { newref = readnumf(argv[narg]); } else { newref = 1; }; }; if (getarg("-e", argc, argv) == -1) { echeck = 1; } else { echeck = 0; }; narg = getarg("-n", argc, argv); if (narg == -1) { newbreaks = 0; } else { newbreaks = 1; if (narg >= argc) { event_error("No value for bars per line after -n"); bars_per_line = 4; } else { bars_per_line = readnumf(argv[narg]); if (bars_per_line < 1) { bars_per_line = 4; }; }; }; if (getarg("-b", argc, argv) != -1) { barcheck = 0; } else { barcheck = 1; }; if (getarg("-r", argc, argv) != -1) { repcheck = 0; } else { repcheck = 1; }; if (getarg("-v", argc, argv) != -1) { lenfactor.num = 1; lenfactor.denom = 2; } else { if (getarg("-d", argc, argv) != -1) { lenfactor.num = 2; lenfactor.denom = 1; } else { lenfactor.num = 1; lenfactor.denom = 1; }; }; targ = getarg("-t", argc, argv); if (targ == -1) { transpose = 0; } else { if (targ >= argc) { event_error("No tranpose value supplied"); } else { if (*argv[targ] == '-') { transpose = -readnumf(argv[targ]+1); } else if (*argv[targ] == '+') { transpose = readnumf(argv[targ]+1); } else { transpose = readnumf(argv[targ]); }; }; }; targ = getarg("-nda",argc,argv); if (targ != -1) nodouble_accidentals = 1; targ = getarg("-nokeys",argc,argv); if (targ != -1) nokey=1; targ = getarg("-nokeyf",argc,argv); if (targ != -1) {nokey=1; useflats=1;} targ = getarg("-V", argc, argv); if (targ != -1) { parse_voices_selection(argv[targ]); /* [PHDM] 2013-03-08 */ }; targ = getarg("-P", argc, argv); /* [SS] 2011-06-07 */ if (targ != -1) { passthru = 1; parse_voices_selection(argv[targ]); /* [PHDM] 2013-03-08 */ } targ = getarg("-usekey",argc,argv); if (targ != -1) { usekey = readsnumf(argv[targ]); nokey = 1; if (usekey < 0) useflats=1; if (usekey <-5) usekey = -5; if (usekey >5) usekey = 5; setup_sharps_flats (usekey); } if (getarg("-OCC",argc,argv) != -1) oldchordconvention=1; /*if (getarg("-noplus",argc,argv) != -1) noplus = 1; [SS] 2012-06-04*/ /* printf("%% output from abc2abc\n"); */ startline = 1; blankline = 0; xinbody =0; inmusic = 0; inchord = 0; ingrace = 0; head = NULL; tail = NULL; tmp[0] = '\0'; totalnotes = 0; } void emit_string(s) char *s; /* output string */ { if (output_on) { strcpy(tmp+strlen(tmp), s); }; } void emit_char(ch) char ch; /* output single character */ { char *place; if (output_on) { place = tmp+strlen(tmp); *place = ch; *(place+1) = '\0'; }; } void emit_int(n) int n; /* output integer */ { if (output_on) { sprintf(tmp+strlen(tmp), "%d", n); }; } void emit_string_sprintf(s1, s2) char *s1; char *s2; /* output string containing string expression %s */ { if (output_on) { sprintf(tmp+strlen(tmp), s1, s2); }; } void emit_int_sprintf(s, n) char *s; int n; /* output string containing int expression %d */ { if (output_on) { sprintf(tmp+strlen(tmp), s, n); }; } void unemit_inline() /* remove previously output start of inline field */ /* needed for -V voice selection option */ { int len; len = strlen(tmp); if ((len > 0) && (tmp[len-1] == '[')) { tmp[len-1] = '\0'; /* delete last character */ } else { event_error("Internal error - Could not delete ["); }; } static void close_newabc() /* output all remaining abc_text elements */ /* part of new linebreak option (-n) */ { if (newbreaks) { complete_all(&voice[this_voice], endmusicline); if (linestat == midmusic) setline(endmusicline); setline(fresh); }; } void event_eof() { close_newabc(); } void event_blankline() { output_on = 1; close_newabc(); /* if (newbreaks) [SS] 2006-09-23 */ printf("\n"); xinbody = 0; xinhead = 0; parseroff(); blankline = 1; } void event_text(p) char *p; { emit_string_sprintf("%%%s", p); inmusic = 0; } void event_reserved(p) char p; { emit_char(p); inmusic = 0; } void event_tex(s) char *s; { emit_string(s); inmusic = 0; } void print_inputline(); /* from parseabc.c */ void event_linebreak() { if (!output_on && passthru) print_inputline(); /* [SS] 2011-06-07*/ if (newbreaks) { if (!purgespace(tmp)) { if (inmusic) { newabctext(bar); } else { newabctext(field); }; }; } else { newabctext(bar); if (output_on) { printf("\n"); /* linefeed to stdout is here */ }; /* don't output new line if voice is already suppressed otherwise we will get lots of blank lines where we are suppressing output. [SS] feb-10-2002. */ }; } void event_startmusicline() /* encountered the start of a line of notes */ { voice[this_voice].currentline = NULL; complete_bars(&voice[this_voice]); } void event_endmusicline(endchar) char endchar; /* encountered the end of a line of notes */ { } void event_error(s) char *s; { if (echeck && output_on) { /* [SS] 2011-04-14 */ printf("\n%%Error : %s\n", s); }; } void event_warning(s) char *s; { if (echeck && output_on) { /* [SS] 2011-04-14 */ printf("\n%%Warning : %s\n", s); }; } void event_comment(s) char *s; { if (newbreaks && (!purgespace(tmp))) { if (inmusic) { newabctext(bar); } else { newabctext(field); }; }; emit_string_sprintf("%%%s", s); inmusic = 0; } void event_specific(package, s) char *package, *s; { char command[40]; int ch; char *p; emit_string("%%"); emit_string(package); emit_string(s); inmusic = 0; /* detect drum channel by searching for %%MIDI channel 10 */ if (strcmp(package,"MIDI") != 0) return; p = s; skipspace(&p); readstr(command, &p, 40); if (strcmp(command, "channel") != 0) return; skipspace(&p); ch = readnump(&p); if(ch == 10) { voice[next_voice].drumchan = 1; drumchan = 1; } /* printf("event_specific: next_voice = %d\n",next_voice); */ } void event_info(f) /* handles info field I: */ char *f; { emit_string_sprintf("I:%s", f); inmusic = 0; } void event_field(k, f) char k; char *f; { emit_char(k); emit_char(':'); emit_string(f); inmusic = 0; } struct abctext* getbar(place) struct abctext *place; /* find first element in list which is a bar of music */ { struct abctext *newplace; newplace = place; while ((newplace != NULL) && ((newplace->type != bar) || (newplace->notes == 0))) { newplace = newplace->next; }; return(newplace); } struct abctext* getnextbar(place) struct abctext *place; /* find next element in list which is a bar of music */ { struct abctext *newplace; newplace = place; if (newplace != NULL) { newplace = getbar(newplace->next); }; return(newplace); }; void append_lyrics(place, newwords) struct abctext *place; char *newwords; /* add lyrics to end of lyric list associated with bar */ { struct lyricwords* new_words; struct lyricwords *new_place; if (place == NULL) { return; }; /* printf("append_lyrics has %s at %s\n", newwords, place->text); */ new_words = (struct lyricwords*)checkmalloc(sizeof(struct lyricwords)); /* add words to bar */ new_words->nextverse = NULL; new_words->words = addstring(newwords); if (place->lyrics == NULL) { place->lyrics = new_words; } else { new_place = place->lyrics; /* find end of list */ while (new_place->nextverse != NULL) { new_place = new_place->nextverse; }; new_place->nextverse = new_words; }; } struct abctext* apply_bar(syll, place, notesleft, barwords) /* advance to next bar (on finding '|' in a w: field) */ char* syll; struct abctext *place; int *notesleft; struct vstring *barwords; { struct abctext* new_place; if (place == NULL) { return(NULL); }; new_place = place; addtext(syll, barwords); append_lyrics(place, barwords->st); /* go on to next bar */ clearvstring(barwords); new_place = getnextbar(place); if (new_place != NULL) { *notesleft = new_place->notes; }; return(new_place); } struct abctext* apply_syllable(syll, place, notesleft, barwords) /* attach syllable to appropriate place in abctext structure */ char* syll; struct abctext *place; int *notesleft; struct vstring *barwords; { struct abctext* new_place; char msg[80]; if (place == NULL) { sprintf(msg, "Cannot find note to match \"%s\"", syll); event_error(msg); return(NULL); }; new_place = place; addtext(syll, barwords); *notesleft = *notesleft - 1; if (*notesleft == 0) { append_lyrics(place, barwords->st); /* go on to next bar */ clearvstring(barwords); new_place = getnextbar(place); if (new_place != NULL) { *notesleft = new_place->notes; }; }; return(new_place); } void parse_words(p) char* p; /* Break up a line of lyrics (w: ) into component syllables */ { struct vstring syll; struct vstring barwords; char* q; unsigned char ch; int errors; int found_hyphen; struct abctext *place; int notesleft; if (!xinbody) { event_error("w: field outside tune body"); return; }; place = getbar(voice[this_voice].currentline); if (place == NULL) { event_error("No music to match w: line to"); return; }; notesleft = voice[this_voice].currentline->notes; initvstring(&barwords); errors = 0; if (place == NULL) { event_error("No notes to match words"); return; }; initvstring(&syll); q = p; skipspace(&q); while (*q != '\0') { found_hyphen = 0; clearvstring(&syll); ch = *q; while(ch=='|') { addch('|', &syll); addch(' ', &syll); place = apply_bar(syll.st, place, ¬esleft, &barwords); clearvstring(&syll); q++; ch = *q; }; /* PCC seems to require (ch != ' ') on the next line */ /* presumably PCC's version of ispunct() thinks ' ' is punctuation */ while (((ch>127)||isalnum(ch)||ispunct(ch))&&(ch != ' ')&& (ch != '_')&&(ch != '-')&&(ch != '*')&& (ch != '|')) { if ((ch == '\\') && (*(q+1)=='-')) { addch('\\', &syll); ch = '-'; q++; }; /* syllable[i] = ch; */ addch(ch, &syll); q++; ch = *q; }; skipspace(&q); if (ch == '-') { found_hyphen = 1; addch(ch, &syll); while (isspace(ch)||(ch=='-')) { q++; ch = *q; }; }; if (syll.len > 0) { if (!found_hyphen) { addch(' ', &syll); }; place = apply_syllable(syll.st, place, ¬esleft, &barwords); } else { if (ch=='_') { clearvstring(&syll); addch('_', &syll); addch(' ', &syll); place = apply_syllable(syll.st, place, ¬esleft, &barwords); q++; ch = *q; }; if (ch=='*') { clearvstring(&syll); addch('*', &syll); addch(' ', &syll); place = apply_syllable(syll.st, place, ¬esleft, &barwords); q++; ch = *q; }; }; }; if (errors > 0) { event_error("Lyric line too long for music"); } else { clearvstring(&syll); }; freevstring(&syll); } void event_words(p, continuation) char* p; int continuation; /* a w: field has been encountered */ { struct vstring afield; if (xinbody && newbreaks) { parse_words(p); } else { initvstring(&afield); addtext(p, &afield); if (continuation) { addch(' ', &afield); addch('\\', &afield); }; event_field('w', afield.st); }; } /* [SS] 2014-09-07 */ void appendfield (morewords) char *morewords; { emit_string("+: "); emit_string(morewords); } void event_part(s) char* s; { if (xinbody) { complete_bars(&voice[this_voice]); }; output_on = 1; /* [SS] 2011-04-14 */ emit_string_sprintf("P:%s", s); inmusic = 0; } int setvoice(num) int num; /* we need to keep track of current voice for new linebreak handling (-n) */ /* change voice to num. If voice does not exist, start new one */ { int i, voice_index; i = 0; while ((i < voicecount) && (voice[i].number != num)) { i = i + 1; }; if ((i < voicecount) && (voice[i].number == num)) { voice_index = i; drumchan = voice[voice_index].drumchan; /* printf("voice_index = %d drumchan = %d\n",voice_index,drumchan); */ } else { voice_index = voicecount; if (voicecount < MAX_VOICES) { voicecount = voicecount + 1; } else { event_error("Number of voices exceeds static limit MAX_VOICES"); }; voice[voice_index].number = num; voice[voice_index].barcount = zero_barcount(&voice[voice_index].foundbar); voice[voice_index].bars_complete = 0; voice[voice_index].bars_remaining = bars_per_line; voice[voice_index].drumchan = 0; }; voice[voice_index].currentline = NULL; return(voice_index); } void event_voice(n, s, vp) int n; char *s; struct voice_params *vp; { char output[32]; if (xinbody) { next_voice = setvoice(n); }; if (!must_emit_voice(n)) { /* [PHDM] 2013-03-08 */ if ((inlinefield) && (output_on == 1)) { unemit_inline(); }; /*output_on = 0; [SS] 2011-06-10 */ if (xinbody) output_on = 0; /* [SS] 2011-06-10 */ } else { if (output_on == 0) { output_on = 1; if (inlinefield) { emit_string("["); /* regenerate missing [ */ }; }; }; if (strlen(s) == 0) { if(voicecodes >= n) emit_string_sprintf("V:%s",voicecode[n-1]); else emit_int_sprintf("V:%d", n); if (vp->gotclef) {sprintf(output," clef=%s", vp->clefname); emit_string(output);} if (vp->gotoctave) {sprintf(output," octave=%d", vp->octave); emit_string(output);} if (vp->gottranspose) {sprintf(output," transpose=%d", vp->transpose); emit_string(output);} if (vp->gotname) {sprintf(output," name=%s", vp->namestring); emit_string(output);} if (vp->gotsname) {sprintf(output," sname=%s", vp->snamestring); emit_string(output);} if( vp->gotmiddle ) { sprintf(output, " middle=%s", vp->middlestring); emit_string(output);} if( vp->gotother ) { sprintf(output, " %s", vp->other); emit_string(output);} /* [SS] 2011-04-18 */ } else { if(voicecodes >= n) emit_string_sprintf("V:%s",voicecode[n-1]); emit_int_sprintf("V:%d ", n); if (vp->gotclef) {sprintf(output," clef=%s", vp->clefname); emit_string(output);} if (vp->gotoctave) {sprintf(output," octave=%d", vp->octave); emit_string(output);} if (vp->gottranspose) {sprintf(output," transpose=%d", vp->transpose); emit_string(output);} if (vp->gotname) {sprintf(output," name=%s", vp->namestring); emit_string(output);} if( vp->gotmiddle ) { sprintf(output, " middle=%s", vp->middlestring); emit_string(output);} if( vp->gotother ) { sprintf(output, " %s", vp->other); emit_string(output);} /* [SS] 2011-04-18 */ emit_string(s); }; inmusic = 0; } void event_length(n) int n; { struct fract newunit; newunit.num = lenfactor.denom; newunit.denom = lenfactor.num * n; reduce(&newunit.num, &newunit.denom); emit_int_sprintf("L:%d/", newunit.num); emit_int(newunit.denom); unitlen.num = 1; unitlen.denom = n; inmusic = 0; } void event_refno(n) int n; { if (xinbody) { close_newabc(); }; output_on = 1; if (newrefnos) { emit_int_sprintf("X:%d", newref); newref = newref + 1; } else { emit_int_sprintf("X:%d", n); }; parseron(); xinhead = 1; notecount = 0; unitlen.num = 0; unitlen.denom = 1; barlen.num = 0; barlen.denom = 1; inmusic = 0; barcount = 0; } void event_tempo(n, a, b, relative, pre, post) int n, a, b; int relative; char *pre; char *post; { struct fract newlen; emit_string("Q:"); if (pre != NULL) { emit_string_sprintf("\"%s\"", pre); }; if (n != 0) { if ((a == 0) && (b == 0)) { emit_int(n); } else { if (relative) { newlen.num = a * lenfactor.num; newlen.denom = b * lenfactor.denom; reduce(&newlen.num, &newlen.denom); emit_int_sprintf("C%d/", newlen.num); emit_int(newlen.denom); emit_int_sprintf("=%d", n); } else { emit_int_sprintf("%d/", a); emit_int(b); emit_int_sprintf("=%d", n); }; }; }; if (post != NULL) { emit_string_sprintf("\"%s\"", post); }; inmusic = 0; } void event_timesig(n, m, checkbars) int n, m, checkbars; /* [code contributed by Larry Myerscough 2015-11-5] * checkbars definition extended: * 0=> no, * 1=>yes, use numerical notation * 2=>yes, use 'common' notation for 2/2 or 4/4 according to numerator * */ { if (checkbars == 1) { emit_int_sprintf("M:%d/", n); emit_int(m); } else if (checkbars == 2) { emit_int_sprintf("M:C", n); if (n != 4) emit_string("|"); } else { emit_string("M:none"); barcheck = 0; }; barlen.num = n; barlen.denom = m; breakpoint.num = n; breakpoint.denom = m; if ((n == 9) || (n == 6)) { breakpoint.num = 3; breakpoint.denom = barlen.denom; }; if (n%2 == 0) { breakpoint.num = barlen.num/2; breakpoint.denom = barlen.denom; }; barend = n/breakpoint.num; inmusic = 0; } static void setmap(sf, map) int sf; int map[7]; { /* map[0] to map[7] corresponds to keys a to g and indicates whether they are flattened or sharpened. sf encodes the key signature by indicating the number of sharps (positive numbers) or flats (negative numbers) */ int j; for (j=0; j<7; j++) { map[j] = 0; }; if (sf >= 1) map['f'-'a'] = 1; if (sf >= 2) map['c'-'a'] = 1; if (sf >= 3) map['g'-'a'] = 1; if (sf >= 4) map['d'-'a'] = 1; if (sf >= 5) map['a'-'a'] = 1; if (sf >= 6) map['e'-'a'] = 1; if (sf >= 7) map['b'-'a'] = 1; if (sf <= -1) map['b'-'a'] = -1; if (sf <= -2) map['e'-'a'] = -1; if (sf <= -3) map['a'-'a'] = -1; if (sf <= -4) map['d'-'a'] = -1; if (sf <= -5) map['g'-'a'] = -1; if (sf <= -6) map['c'-'a'] = -1; if (sf <= -7) map['f'-'a'] = -1; } static void start_tune() { parseron(); count.num =0; count.denom = 1; barno = 0; tuplenotes = 0; expect_repeat = -1; /* repeat from start may occur [J-FM] 2012-06-04 */ inlinefield = 0; if (barlen.num == 0) { /* generate missing time signature */ event_linebreak(); event_timesig(4, 4, 1); inmusic = 0; }; if (unitlen.num == 0) { if ((float) barlen.num / (float) barlen.denom < 0.75) { unitlen.num = 1; unitlen.denom = 16; } else { unitlen.num = 1; unitlen.denom = 8; }; }; voicecount = 0; this_voice = setvoice(1); next_voice = this_voice; } void compute_keysignature (int sf,int modeindex, char * keysignature) { char *notes[7] = {"A","B","C","D","E","F","G"}; int sf2note[12] = {3,0,4,1,5,2,6,3,0,4,1,5}; char *flatsharp[2] = {"b","#"}; int index0,index1,index; int map[7]; index0 = sf+5; /* -5 6) index -=7; strcpy(keysignature,notes[index]); /* propogate sharp or flat to key signature of mode */ if (map[index] == -1) strcat(keysignature,flatsharp[0]); if (map[index] == 1) strcat(keysignature,flatsharp[1]); /* add mode name */ strcat(keysignature,mode[modeindex]); } /* [SS] 2011-02-15 */ /* Support functions to transpose key signature modifiers (eg. K: DPhr ^F * K: D exp _b_e^f ). * Method: we represent the notes in the key signature (with modifiers) in * a chromatic scale semiseq. semiseq(i) == 1 means the note is in the * key signature, semiseq(i) == 0 means the note is not present in the * key signature. semiseq(0) corresponds to A natural, semiseq(11) * represents G# or Ab. We transpose the notes by shifting (with * rotation) semiseq() left or right. We then read back the notes * of the shifted sequence, ignoring all flats and sharps in the * new key signature corresponding to this transpose. modmap indicates the key modifiers using the convention in event_key. */ int debugsemi = 0; /* set to one if debugging ! [SS] 2011-02-21 */ int semiseq[12]; int semiseqbase[12]; char modmap[7]; int convertnote[7] = {0,2,3,5,7,8,10}; /* needed to convert modmap to semiseq representation */ int sfpos[7] = {8, 3, 10, 5, 0, 7, 2}; /* FCGDAEB */ int sfneg[7] = {2, 7, 0, 5, 10, 3, 8}; /* needed to convert the key signature to semiseq representation */ char *semisharp[12] = {"=A", "^A", "=B", "=C", "^C", "D", "^D", "=E", "=F", "^F", "=G", "^G"}; char *semiflat[12] = {"=A", "_B", "=B", "=C", "_D", "=D", "_E", "=E", "=F", "_G", "=G", "_A"}; /* needed to convert the semiseq representation to the notes */ int modmap_not_empty (char* modmap) { int i; for (i=0;i<7;i++) if (modmap[i] != ' ') {return 1;} return 0; } void print_semiseq(); void sf2semi (int sf) { /* apply key signature to semiseq */ int i; for (i=0;i<12;i++) semiseqbase[i]=0; for (i=0;i<7;i++) semiseqbase[sfpos[i]] = 1; if (sf == 0) return; if (sf > 0) {for (i=0;i 6) newkeysigsf = newkeysigsf -12; if (newkeysigsf <-5) newkeysigsf = newkeysigsf +12; if (debugsemi) printf("newkeysigsf= %d\n",newkeysigsf); sf2semi(oldkeysigsf); for (i=0;i<12;i++) semiseq[i] = semiseqbase[i]; print_semiseq(); note2semi(modmap); if (debugsemi) printf("applying note2semi\n"); print_semiseq(); transpose_semiseq(semitranspose); if (debugsemi) printf("applying transpose %d\n",semitranspose); print_semiseq(); return pickup_accidentals_for(newkeysigsf,explict); } /* end of [SS] 2011-02-15 */ void event_key(sharps, s, modeindex, modmap, modmul, modmicrotone, gotkey, gotclef, clefname, octave, xtranspose, gotoctave, gottranspose, explict) int sharps; char *s; int modeindex; char modmap[7]; int modmul[7]; struct fraction modmicrotone[7]; /* [SS[ 2014-01-06 */ int gotkey, gotclef; char* clefname; int octave, xtranspose, gotoctave, gottranspose; int explict; { static char* keys[12] = {"Db", "Ab", "Eb", "Bb", "F", "C", "G", "D", "A", "E", "B", "F#"}; char signature[10]; if (!xinbody && passthru) {print_inputline_nolinefeed(); /* [SS] 2011-06-10 */ if ((xinhead) && (!xinbody)) { xinbody = 1; start_tune(); }; inmusic = 0; return; } if (gotkey) { setmap(sharps, basemap); /* required by copymap and pitchof */ setmap(sharps, oldtable); copymap(); newkey = (sharps+7*transpose)%12; if (sharps < -5) orig_key_number = (int) keys[sharps+17][0] - (int) 'A'; else if (sharps > 6) orig_key_number = (int)keys[sharps-7][0] - (int) 'A'; else orig_key_number = (int) keys[sharps+5][0] - (int) 'A'; lines = (sharps+7*transpose)/12; if (newkey > 6) { newkey = newkey - 12; lines = lines + 1; }; if (newkey < -5) { newkey = newkey + 12; lines = lines - 1; }; setmap(newkey, newtable); /* used by event_note1 */ new_key_number = (int) keys[newkey+5][0] - (int) 'A'; if (modmap_not_empty (modmap)) { transpose_modmap(sharps,transpose,modmap,explict); } }; emit_string("K:"); if (transpose == 0 && !nokey) { emit_string(s); } else { if (gotkey) { if (!nokey) { /* emit_string(keys[newkey+5]); */ compute_keysignature(newkey,modeindex,signature); /* [SS] 2006-07-30*/ emit_string(signature); /* [SS] 2006-07-30 */ if (explict) emit_string(" exp"); /* 2011-02-21*/ emit_string(trans_string); /* [SS] 2011-02-20 */ } else if (usekey == 0) emit_string("none"); else emit_string(keys[usekey+5]); if (gotclef) { emit_string(" "); }; }; if (gotclef) { emit_string_sprintf("clef=%s", clefname); }; if (gotoctave) { emit_int_sprintf(" octave=%d", octave); }; if (gottranspose) { emit_int_sprintf(" transpose=%d", xtranspose); }; }; if ((xinhead) && (!xinbody)) { xinbody = 1; start_tune(); }; inmusic = 0; } static void printlen(a, b) int a, b; { if (a != 1) { emit_int(a); }; if (b != 1) { emit_int_sprintf("/%d", b); }; } void event_spacing(n, m) int n, m; { emit_string("y"); printlen(n, m); } void event_rest(decorators,n,m,type) int n, m, type; int decorators[DECSIZE]; { struct fract newlen; inmusic = 1; if( type == 1) emit_string("x"); else emit_string("z"); newlen.num = n * lenfactor.num; newlen.denom = m * lenfactor.denom; reduce(&newlen.num, &newlen.denom); printlen(newlen.num, newlen.denom); if (inchord) { chordcount = chordcount + 1; if (chordcount == 1) { /* [PHDM] 2013-03-10 */ chordfactor.num = n; chordfactor.denom = m; } }; if ((!ingrace) && (!inchord)) { addunits(n, m); }; } void event_mrest(n,m) int n, m; { inmusic = 1; emit_string("Z"); printlen(n,m); if (inchord) { event_error("Multiple bar rest not allowed in chord"); }; if (tuplenotes != 0) { event_error("Multiple bar rest not allowed in tuple"); }; } void event_bar(type, replist) int type; char* replist; { char msg[40]; if (!purgespace(tmp)) { if (inmusic) { newabctext(bar); } else { newabctext(field); }; }; switch(type) { case SINGLE_BAR: emit_string_sprintf("|%s", replist); break; case DOUBLE_BAR: emit_string("||"); break; case THIN_THICK: emit_string("|]"); break; case THICK_THIN: emit_string("[|"); break; case BAR_REP: emit_string("|:"); if (expect_repeat > 0 /* no error if first repeat [J-FM] 2012-06-04 */ && repcheck) { event_error("Expecting repeat, found |:"); }; expect_repeat = 1; break; case REP_BAR: emit_string_sprintf(":|%s", replist); if ((!expect_repeat) && (repcheck)) { event_warning("No repeat expected, found :|"); }; expect_repeat = 0; break; case BAR1: emit_string("|1"); if ((!expect_repeat) && (repcheck)) { event_warning("found |1 in non-repeat section"); }; break; case REP_BAR2: emit_string(":|2"); if ((!expect_repeat) && (repcheck)) { event_warning("No repeat expected, found :|2"); }; expect_repeat = 0; break; case DOUBLE_REP: emit_string("::"); if ((!expect_repeat) && (repcheck)) { event_error("No repeat expected, found ::"); }; expect_repeat = 1; break; }; if ((count.num*barlen.denom != barlen.num*count.denom) && (count.num != 0) && (barno != 0) && (barcheck)) { /* [J-FM] 2012-06-04 start */ switch (type) { case BAR_REP: case REP_BAR: case BAR1: case REP_BAR2: case DOUBLE_REP: break; /* no error if repeat bar */ default: sprintf(msg, "Bar %d is %d/%d not %d/%d", barno, count.num, count.denom, barlen.num, barlen.denom ); event_error(msg); count.num = 0; count.denom = 1; break; } } else { count.num = 0; count.denom = 1; } /* [J-FM] 2012-06-04 end */ newabctext(barline); barno = barno + 1; copymap(); } void event_space() { if (!newspacing) { emit_string(" "); }; } void event_graceon() { emit_string("{"); ingrace = 1; } void event_graceoff() { emit_string("}"); ingrace = 0; } void event_rep1() { emit_string(" [1"); } void event_rep2() { emit_string(" [2"); } void event_playonrep(s) char*s; { emit_string_sprintf(" [%s", s); } void event_broken(type, n) int type, n; { int i; if (type == GT) { for (i=0; i'); }; } else { for (i=0; i') || (*s == '@')) { emit_string_sprintf("\"%s\"", s); } else { char* p; int pitch; int j; if (newkey >= 0) { roots = sharproots; bases = sharpbases; } else { roots = flatroots; bases = flatbases; }; p = s; chordstart = 1; j = 0; while (*p != '\0') { if (chordstart) { if ((*p >= 'A') && (*p <= 'G')) { key_number = (int) *p - ((int) 'A'); old_triad_number = key_number - orig_key_number+1; if (old_triad_number < 1) old_triad_number += 7; pitch = (offset[key_number] + transpose)%12; p = p + 1; if (*p == 'b') { pitch = pitch - 1; p = p + 1; }; if (*p == '#') { pitch = pitch + 1; p = p + 1; }; pitch = (pitch + 12)%12; key_number = (int) roots[pitch][0] - (int) 'A'; new_triad_number = key_number - new_key_number +1; if (new_triad_number < 1) new_triad_number += 7; triad_diff = new_triad_number - old_triad_number; if (!nodouble_accidentals && (triad_diff == -1 || triad_diff == 6)) { /* printf("*** %d old chord = %s (%d) new chord = %s (%d)\n", triad_diff,s,old_triad_number,roots[pitch],new_triad_number); */ pitch = pitch+1; pitch = (pitch+12)%12; strcpy(&newchord[j],roots[pitch]); j = strlen(newchord); strcpy(&newchord[j],"b"); j = j+1; if (adapt_useflats_to_gchords) useflats=1; } else if (!nodouble_accidentals && (triad_diff ==1 || triad_diff == -6)) { /* printf("*** %d old chord = %s (%d) new chord = %s (%d)\n", triad_diff,s,old_triad_number,roots[pitch],new_triad_number); */ pitch = pitch-1; pitch = (pitch+12)%12; strcpy(&newchord[j],roots[pitch]); j = strlen(newchord); strcpy(&newchord[j],"#"); j = j+1; if (adapt_useflats_to_gchords) useflats=0; } else /* no extra flats or sharps needed */ { strcpy(&newchord[j], roots[pitch]); j = strlen(newchord); } chordstart = 0; } else { if ((*p >= 'a') && (*p <= 'g')) { key_number = (int) *p - ((int) 'a'); old_triad_number = key_number - orig_key_number+1; if (old_triad_number < 1) old_triad_number += 7; pitch = (offset[key_number] + transpose)%12; p = p + 1; if (*p == 'b') { pitch = pitch - 1; p = p + 1; }; if (*p == '#') { pitch = pitch + 1; p = p + 1; }; pitch = (pitch + 12)%12; key_number = (int) bases[pitch][0] - (int) 'a'; new_triad_number = key_number - new_key_number +1; if (new_triad_number < 1) new_triad_number += 7; triad_diff = new_triad_number - old_triad_number; if (!nodouble_accidentals && (triad_diff == -1 || triad_diff == 6)) { /* printf("*** %d old chord = %s (%d) new chord = %s (%d)\n", triad_diff,s,old_triad_number,bases[pitch],new_triad_number); */ pitch = pitch+1; pitch = (pitch+12)%12; strcpy(&newchord[j],bases[pitch]); j = strlen(newchord); strcpy(&newchord[j],"b"); j = j+1; } else if (!nodouble_accidentals && (triad_diff ==1 || triad_diff == -6)) { /* printf("*** %d old chord = %s (%d) new chord = %s (%d)\n", triad_diff,s,old_triad_number,bases[pitch],new_triad_number);*/ pitch = pitch-1; pitch = (pitch+12)%12; strcpy(&newchord[j],bases[pitch]); j = strlen(newchord); strcpy(&newchord[j],"#"); j = j+1; } else { strcpy(&newchord[j], bases[pitch]); j = strlen(newchord); } chordstart = 0; } else { if (isalpha(*p)) { chordstart = 0; }; newchord[j] = *p; p = p + 1; j = j + 1; newchord[j] = '\0'; }; }; } else { if ((*p == '/') || (*p == '(') || (*p == ' ')) { chordstart = 1; }; newchord[j] = *p; p = p + 1; j = j + 1; newchord[j] = '\0'; }; if (j >= 49) { event_error("guitar chord contains too much text"); while (*p != '\0') { p = p + 1; }; }; }; emit_string_sprintf("\"%s\"", newchord); }; } void event_gchord(s) char* s; { splitstring(s, ';', event_handle_gchord); } void event_instruction(s) char* s; { if (oldchordconvention || noplus) emit_string_sprintf("!%s!", s); else emit_string_sprintf("+%s+", s); } void event_slur(t) int t; { if (cleanup) { if (t) { emit_string("("); } else { emit_string(")"); }; } else { emit_string("s"); }; } void event_sluron(t) int t; { emit_string("("); } void event_sluroff(t) int t; { emit_string(")"); } void event_tie() { emit_string("-"); } void event_lineend(ch, n) char ch; int n; { int i; if (!newbreaks) { for (i = 0; i 0) { accidental = '^'; mult = acc; }; if (acc < 0) { accidental = '_'; mult = -acc; }; }; }; if (!ingrace) { notecount = notecount + 1; }; for (t=0; t= 1) { emit_char(note); t = octave; while (t > 1) { emit_string("'"); t = t - 1; }; } else { emit_char((char) ((int)note + 'C' - 'c')); t = octave; while (t < 0) { emit_string(","); t = t + 1; }; }; newlen.num = n * lenfactor.num; newlen.denom = m * lenfactor.denom; reduce(&newlen.num, &newlen.denom); printlen(newlen.num, newlen.denom); if (inchord) { chordcount = chordcount + 1; if (chordcount == 1) { /* [PHDM] 2013-03-10 */ chordfactor.num = n; chordfactor.denom = m; } }; if ((!ingrace) && (!inchord)) { addunits(n, m); }; if (newspacing) { barpoint.num = count.num * breakpoint.denom; barpoint.denom = breakpoint.num * count.denom; reduce(&barpoint.num, &barpoint.denom); if ((barpoint.denom == 1) && (barpoint.num != 0) && (barpoint.num != barend)) { emit_string(" "); }; }; } /* these functions are here to satisfy the linker */ void event_microtone(int dir, int a, int b) { } void event_normal_tone() { } int accidental_to_code (char xaccidental) { switch (xaccidental) { case ' ': return 10; break; case '_': return -1; break; case '^': return 1; break; case '=': return 0; break; default: return 10; } } void event_note2(decorators, xaccidental, xmult, xnote, xoctave, n, m) /* this function is called if flag nokey is set */ int decorators[DECSIZE]; int xmult; char xaccidental, xnote; int xoctave, n, m; { int t; struct fract barpoint; struct fract newlen; int acc,assumed_acc; int propogate; int val; char *anoctave = "cdefgab"; int midipitch; for (t=0; t=1) {sharpsym[6] = 0; sharpsym[5] = 2;} if (sf >=2) {sharpsym[1] = 0; sharpsym[0] = 2;} if (sf >=3) {sharpsym[8] = 0; sharpsym[7] = 2;} if (sf >=4) {sharpsym[3] = 0; sharpsym[2] = 2;} if (sf >=5) {sharpsym[10]= 0; sharpsym[9] = 2;} if (sf <= -1) {flatsym[10] = 0; flatsym[11] = 2;} if (sf <= -2) {flatsym[3] = 0; flatsym[4] =2;} if (sf <= -3) {flatsym[8] = 0; flatsym[9] =2;} if (sf <= -4) {flatsym[1] = 0; flatsym[2] =2;} if (sf <= -5) {flatsym[6] = 0; flatsym[6] =2;} } void printpitch(int pitch) /* convert midi pitch value to abc note */ { int p; char keylet,symlet; int keynum,symcod; char string[16]; p = pitch%12; if (useflats) {keynum = flatmap[p]; symcod = flatsym[p]; } else {keynum = sharpmap[p]; symcod = sharpsym[p]; } if (pitch= MIDDLE + 12) { emit_string("'"); p = p - 12; }; while (p < MIDDLE - 12) { emit_string(","); p = p + 12; }; } int main(argc,argv) int argc; char *argv[]; { char *filename; oldchordconvention = 0; /* for handling +..+ chords */ noplus = 1; /* [SS] 2012-06-04 */ /*for (i=0;i #ifdef ANSILIBS #include #endif #include "abc.h" #include "structs.h" #include "sizes.h" extern struct tune thetune; extern double scaledwidth; static void addfract(f, n, m) struct fract* f; int n, m; /* add n/m to fraction pointed to by f */ /* like addunits(), but does not use unitlength */ { f->num = n*f->denom + m*f->num; f->denom = m*f->denom; reducef(f); } static void mulfract(f, n, m) struct fract* f; int n, m; /* multiply n/m to fraction pointed to by f */ /* like addunits(), but does not use unitlength */ { f->num = n*f->num; f->denom = m*f->denom; reducef(f); } static void advance(struct voice* v, int phase, int* items, double* itemspace, double x) /* move on one symbol in the specified voice */ { struct feature* p; struct rest* arest; struct note* anote; struct fract tuplefactor, notelen; int done; int stepon; int zerotime, newline; switch(phase) { case 1: zerotime = 1; newline=0; break; case 2: zerotime = 0; newline=0; break; case 3: zerotime = 0; newline=1; break; default: printf("Internal error: phase = %d\n", phase); exit(1); break; }; *itemspace = 0.0; *items = 0; p = v->place; if (p == NULL) { v->atlineend = 1; }; done = 0; while ((p != NULL) && (done==0)) { p->x = (float) (x + p->xleft); stepon = 1; switch(p->type) { case MUSICLINE: v->inmusic = 1; break; case PRINTLINE: v->inmusic = 0; done = 1; if (!newline) { v->atlineend = 1; stepon = 0; }; break; case CLEF: case KEY: case TIME: if (!v->inmusic) { break; }; case SINGLE_BAR: case DOUBLE_BAR: case BAR_REP: case REP_BAR: case BAR1: case REP_BAR2: case DOUBLE_REP: case THICK_THIN: case THIN_THICK: *itemspace = *itemspace + p->xleft + p->xright; *items = *items + 1; if (!newline) { done = 1; }; break; case REST: case NOTE: tuplefactor = v->tuplefactor; if ((zerotime==1) && (!v->ingrace)) { done = 1; stepon = 0; } else { if ((!v->inchord)&&(!newline)) { done = 1; }; *itemspace = *itemspace + p->xleft + p->xright; *items = *items + 1; if (p->type == REST) { arest = p->item; addfract(&v->time, arest->len.num, arest->len.denom); }; if ((p->type == NOTE) && (!v->ingrace)) { anote = p->item; notelen = anote->len; if (anote->tuplenotes >0) { mulfract(¬elen,tuplefactor.num,tuplefactor.denom); } addfract(&v->time, notelen.num, notelen.denom); /* printf("%c %d/%d %d/%d\n",anote->pitch,notelen.num,notelen.denom, v->time.num,v->time.denom); */ }; }; break; case CHORDON: if ((zerotime==1)&&(!v->ingrace)) { done = 1; stepon = 0; } else { v->inchord = 1; }; break; case CHORDOFF: if (v->inchord == 1) { v->inchord = 0; if ((!v->ingrace)&&(!newline)) { done = 1; }; }; break; case GRACEON: v->ingrace = 1; break; case GRACEOFF: v->ingrace = 0; break; default: break; }; if (stepon) { p = p->next; } else { done = 1; }; }; v->place = p; if (p == NULL) { v->atlineend = 1; }; } static int gefract(struct fract* a, struct fract* b) /* compare two fractions a greater than or equal to b */ /* returns (a >= b) */ { if ((a->num*b->denom) >= (b->num*a->denom)) { return(1); } else { return(0); }; } static int gtfract(struct fract* a, struct fract* b) /* compare two fractions a greater than b */ /* returns (a > b) */ { if ((a->num*b->denom) > (b->num*a->denom)) { return(1); } else { return(0); }; } static int spacemultiline(struct fract* mastertime, struct tune* t) /* calculate spacing for one line (but possibly multiple voices) */ { int i; int items, thisitems, maxitems; int totalitems; double thiswidth, maxwidth; double totalwidth; double x, gap; int done; struct voice* v; struct fract minlen; /* two passes - on the second pass, inter-symbol spacing is */ /* known so elements can be given their correct x position */ gap = 0.0; for (i=0; i<2; i++) { setfract(mastertime, 0, 1); v = firstitem(&t->voices); while (v != NULL) { v->place = v->lineplace; v->ingrace = 0; v->atlineend = 0; setfract(&v->time, 0, 1); v = nextitem(&t->voices); }; done = 0; items = 0; x = 0.0; totalitems = 0; totalwidth = 0.0; /* count up items in a line */ while (done == 0) { maxitems = 0; maxwidth = 0.0; /* first do zero-time symbols */ v = firstitem(&t->voices); while (v != NULL) { if ((!v->atlineend)&&(gefract(mastertime, &v->time))) { advance(v, 1, &thisitems, &thiswidth, x); if (thisitems > maxitems) { maxitems = thisitems; }; if (thiswidth > maxwidth) { maxwidth = thiswidth; }; }; v = nextitem(&t->voices); }; if (maxitems == 0) { /* now try moving forward in time */ /* advance all voices at or before mastertime */ v = firstitem(&t->voices); while (v != NULL) { if ((!v->atlineend)&&(gefract(mastertime, &v->time))) { advance(v, 2, &thisitems, &thiswidth, x); if (thisitems > maxitems) { maxitems = thisitems; }; if (thiswidth > maxwidth) { maxwidth = thiswidth; }; }; v = nextitem(&t->voices); }; /* calculate new mastertime */ v = firstitem(&t->voices); setfract(&minlen, 0, 1); done = 1; while (v != NULL) { if (!v->atlineend) { done = 0; if (minlen.num == 0) { setfract(&minlen, v->time.num, v->time.denom); } else { if (gtfract(&minlen, &v->time)) { setfract(&minlen, v->time.num, v->time.denom); }; }; }; v = nextitem(&t->voices); }; setfract(mastertime, minlen.num, minlen.denom); }; totalitems = totalitems + maxitems; totalwidth = totalwidth + maxwidth; if (maxitems > 0) { x = x + maxwidth + gap; }; }; /* now calculate inter-symbol gap */ if (totalitems > 1) { gap = (scaledwidth - totalwidth)/(totalitems-1); } else { gap = 1.0; }; if (gap < 0.0) { event_error("Overfull music line"); }; if (gap > MAXGAP) { event_error("Underfull music line"); gap = MAXGAP; }; }; if (totalitems == 0) { return(1); } else { return(0); }; } void spacevoices(struct tune* t) { struct fract mastertime; int donelines; struct voice* v; int items; double x1; /* initialize voices */ v = firstitem(&t->voices); while (v != NULL) { v->lineplace = v->first; v->inmusic=0; v = nextitem(&t->voices); }; donelines = 0; while(donelines == 0) { donelines = spacemultiline(&mastertime, t); v = firstitem(&t->voices); while (v != NULL) { v->lineplace = v->place; advance(v, 3, &items, &x1, 0.0); v->lineplace = v->place; v = nextitem(&t->voices); }; }; } static int spaceline(struct voice* v) /* allocate spare space across the width of a single stave line */ /* thereby fixing the x position of all notes and other elements */ /* returns 0 when the end of the voice is reached, 1 otherwise */ { struct feature* p; double x, lastx; int inmusic, items; double itemspace; double gap; itemspace = 0.0; items = 0; inmusic = 0; p = v->place; while ((p != NULL) && (p->type != PRINTLINE)) { switch(p->type) { case MUSICLINE: inmusic = 1; break; case PRINTLINE: inmusic = 0; break; case CLEF: case KEY: case TIME: if (!inmusic) { break; }; case SINGLE_BAR: case DOUBLE_BAR: case BAR_REP: case REP_BAR: case BAR1: case REP_BAR2: case DOUBLE_REP: case THICK_THIN: case THIN_THICK: case REST: case NOTE: itemspace = itemspace + p->xleft + p->xright; items = items + 1; break; default: break; }; p = p->next; }; if (items > 1) { gap = (scaledwidth - itemspace)/((double)(items-1)); } else { gap = 1.0; }; if (gap < 0.0) { event_error("Overfull music line"); }; if (gap > MAXGAP) { event_error("Underfull music line"); gap = MAXGAP; }; /* now assign positions */ x = 0.0; p = v->place; inmusic = 0; while ((p != NULL) && (p->type != PRINTLINE)) { switch(p->type) { case MUSICLINE: inmusic = 1; break; case PRINTLINE: inmusic = 0; break; case CHORDNOTE: p->x = (float) lastx; break; case CLEF: case KEY: case TIME: if (!inmusic) { break; }; case SINGLE_BAR: case DOUBLE_BAR: case BAR_REP: case REP_BAR: case BAR1: case REP_BAR2: case DOUBLE_REP: case THICK_THIN: case THIN_THICK: case REST: case NOTE: x = x + p->xleft; p->x = (float) x; lastx = x; x = x + p->xright + gap; break; default: break; }; p = p->next; }; while ((p!=NULL)&&((p->type == PRINTLINE)||(p->type==LINENUM))) { p = p->next; }; v->place = p; if (p == NULL) { return(0); } else { return(1); }; } void monospace(struct tune* t) { int doneline; struct voice* v; v = firstitem(&t->voices); while (v != NULL) { doneline = 1; v->place = v->first; while (doneline == 1) { doneline = spaceline(v); }; v = nextitem(&t->voices); }; } abcmidi/midifile.h0000644000000000000000000000654211326640652013113 0ustar rootroot/* definitions for MIDI file parsing code */ #include extern int (*Mf_getc)(); extern void (*Mf_header)(); extern void (*Mf_trackstart)(); extern void (*Mf_trackend)(); extern void (*Mf_noteon)(); extern void (*Mf_noteoff)(); extern void (*Mf_pressure)(); extern void (*Mf_parameter)(); extern void (*Mf_pitchbend)(); extern void (*Mf_program)(); extern void (*Mf_chanpressure)(); extern void (*Mf_sysex)(); extern void (*Mf_metamisc)(); extern void (*Mf_seqspecific)(); extern void (*Mf_seqnum)(); extern void (*Mf_text)(); extern void (*Mf_eot)(); extern void (*Mf_timesig)(); extern void (*Mf_smpte)(); extern void (*Mf_tempo)(); extern void (*Mf_keysig)(); extern void (*Mf_arbitrary)(); extern void (*Mf_error)(); extern long Mf_currtime; extern int Mf_nomerge; /* definitions for MIDI file writing code */ extern int (*Mf_putc)(); extern long (*Mf_writetrack)(); extern int (*Mf_writetempotrack)(); float mf_ticks2sec(); long mf_sec2ticks(); void mfwrite(); void mfread(); int mf_write_meta_event(); int mf_write_midi_event(); void mf_write_tempo(); void mferror(); /* MIDI status commands most significant bit is 1 */ #define note_off 0x80 #define note_on 0x90 #define poly_aftertouch 0xa0 #define control_change 0xb0 #define program_chng 0xc0 #define channel_aftertouch 0xd0 #define pitch_wheel 0xe0 #define system_exclusive 0xf0 #define delay_packet (1111) /* 7 bit controllers */ #define damper_pedal 0x40 #define portamento 0x41 #define sostenuto 0x42 #define soft_pedal 0x43 #define general_4 0x44 #define hold_2 0x45 #define general_5 0x50 #define general_6 0x51 #define general_7 0x52 #define general_8 0x53 #define tremolo_depth 0x5c #define chorus_depth 0x5d #define detune 0x5e #define phaser_depth 0x5f /* parameter values */ #define data_inc 0x60 #define data_dec 0x61 /* parameter selection */ #define non_reg_lsb 0x62 #define non_reg_msb 0x63 #define reg_lsb 0x64 #define reg_msb 0x65 /* Standard MIDI Files meta event definitions */ #define meta_event 0xFF #define sequence_number 0x00 #define text_event 0x01 #define copyright_notice 0x02 #define sequence_name 0x03 #define instrument_name 0x04 #define lyric 0x05 #define marker 0x06 #define cue_point 0x07 #define channel_prefix 0x20 #define end_of_track 0x2f #define set_tempo 0x51 #define smpte_offset 0x54 #define time_signature 0x58 #define key_signature 0x59 #define sequencer_specific 0x74 /* Manufacturer's ID number */ #define Seq_Circuits (0x01) /* Sequential Circuits Inc. */ #define Big_Briar (0x02) /* Big Briar Inc. */ #define Octave (0x03) /* Octave/Plateau */ #define Moog (0x04) /* Moog Music */ #define Passport (0x05) /* Passport Designs */ #define Lexicon (0x06) /* Lexicon */ #define Tempi (0x20) /* Bon Tempi */ #define Siel (0x21) /* S.I.E.L. */ #define Kawai (0x41) #define Roland (0x42) #define Korg (0x42) #define Yamaha (0x43) /* miscellaneous definitions */ #define MThd 0x4d546864 #define MTrk 0x4d54726b #define lowerbyte(x) ((unsigned char)(x & 0xff)) #define upperbyte(x) ((unsigned char)((x & 0xff00)>>8)) abcmidi/legacy_code/0000755000000000000000000000000011414351420013375 5ustar rootrootabcmidi/legacy_code/casecmp.c0000644000000000000000000000214411020033716015153 0ustar rootrootstatic int casecmp(s1, s2) /* case-insensitive compare 2 strings */ /* return 0 if equal */ /* 1 if s1 > s2 */ /* -1 if s1 > s2 */ char s1[]; char s2[]; { int i, val, done; char c1, c2; i = 0; done = 0; while (done == 0) { c1 = tolower(s1[i]); c2 = tolower(s2[i]); if (c1 > c2) { val = 1; done = 1; } else { if (c1 < c2) { val = -1; done = 1; } else { if (c1 == '\0') { val = 0; done = 1; } else { i = i + 1; }; }; }; }; return(val); } static int stringcmp(s1, s2) /* case sensitive compare 2 strings */ /* return 0 if equal */ /* 1 if s1 > s2 */ /* -1 if s1 > s2 */ char s1[]; char s2[]; { int i, val, done; i = 0; done = 0; while (done == 0) { if (s1[i] > s2[i]) { val = 1; done = 1; } else { if (s1[i] < s2[i]) { val = -1; done = 1; } else { if (s1[i] == '\0') { val = 0; done = 1; } else { i = i + 1; }; }; }; }; return(val); } abcmidi/drawtune.h0000644000000000000000000000145411020033716013143 0ustar rootroot/* drawtune.h - part of yaps */ /* this file declares the routines in drawtune.c that are used elsewhere */ /* for Microsoft Visual C++ version 6.0 or higher */ extern int eps_out; /* bounding box for encapsulated PostScript */ struct bbox { int llx, lly, urx, ury; }; #ifdef ANSILIBS extern void setmargins(char* s); extern void setpagesize(char* s); extern void open_output_file(char* filename, struct bbox* boundingbox); extern void close_output_file(void); extern void newpage(void); extern void centretext(char* s); extern void lefttext(char* s); extern void vskip(double gap); #else extern void setmargins(); extern void setpagesize(); extern void open_output_file(); extern void close_output_file(); extern void newpage(); extern void centretext(); extern void lefttext(); extern void vskip(); #endif abcmidi/configure0000755000000000000000000043053312564557320013074 0ustar rootroot#! /bin/sh # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.67 for abcmidi 2011-08-03. # # Report bugs to seymour shlien fy733@ncf.ca . # # # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, # 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software # Foundation, Inc. # # # This configure script is free software; the Free Software Foundation # gives unlimited permission to copy, distribute and modify it. ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH if test "x$CONFIG_SHELL" = x; then as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which # is contrary to our usage. Disable this feature. alias -g '\${1+\"\$@\"}'='\"\$@\"' setopt NO_GLOB_SUBST else case \`(set -o) 2>/dev/null\` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi " as_required="as_fn_return () { (exit \$1); } as_fn_success () { as_fn_return 0; } as_fn_failure () { as_fn_return 1; } as_fn_ret_success () { return 0; } as_fn_ret_failure () { return 1; } exitcode=0 as_fn_success || { exitcode=1; echo as_fn_success failed.; } as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : else exitcode=1; echo positional parameters were not saved. fi test x\$exitcode = x0 || exit 1" as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 test \$(( 1 + 1 )) = 2 || exit 1" if (eval "$as_required") 2>/dev/null; then : as_have_required=yes else as_have_required=no fi if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR as_found=false for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. as_found=: case $as_dir in #( /*) for as_base in sh bash ksh sh5; do # Try only shells that exist, to save several forks. as_shell=$as_dir/$as_base if { test -f "$as_shell" || test -f "$as_shell.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : CONFIG_SHELL=$as_shell as_have_required=yes if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : break 2 fi fi done;; esac as_found=false done $as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : CONFIG_SHELL=$SHELL as_have_required=yes fi; } IFS=$as_save_IFS if test "x$CONFIG_SHELL" != x; then : # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV export CONFIG_SHELL exec "$CONFIG_SHELL" "$as_myself" ${1+"$@"} fi if test x$as_have_required = xno; then : $as_echo "$0: This script requires a shell more modern than all" $as_echo "$0: the shells that I found on your system." if test x${ZSH_VERSION+set} = xset ; then $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" $as_echo "$0: be upgraded to zsh 4.3.4 or later." else $as_echo "$0: Please tell bug-autoconf@gnu.org and $0: Seymour Shlien (fy733@ncf.ca) about your system, including any $0: error possibly output before this message. Then install $0: a modern shell, or manually run the script under such a $0: shell if you do have one." fi exit 1 fi fi fi SHELL=${CONFIG_SHELL-/bin/sh} export SHELL # Unset more variables known to interfere with behavior of common tools. CLICOLOR_FORCE= GREP_OPTIONS= unset CLICOLOR_FORCE GREP_OPTIONS ## --------------------- ## ## M4sh Shell Functions. ## ## --------------------- ## # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits as_lineno_1=$LINENO as_lineno_1a=$LINENO as_lineno_2=$LINENO as_lineno_2a=$LINENO eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) sed -n ' p /[$]LINENO/= ' <$as_myself | sed ' s/[$]LINENO.*/&-/ t lineno b :lineno N :loop s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ t loop s/-\n.*// ' >$as_me.lineno && chmod +x "$as_me.lineno" || { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } # Don't try to exec as it changes $[0], causing all sort of problems # (the dirname of $[0] is not the place where we might find the # original and so on. Autoconf is especially sensitive to this). . "./$as_me.lineno" # Exit status is that of the last command. exit } ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -p'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -p' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -p' fi else as_ln_s='cp -p' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi if test -x / >/dev/null 2>&1; then as_test_x='test -x' else if ls -dL / >/dev/null 2>&1; then as_ls_L_option=L else as_ls_L_option= fi as_test_x=' eval sh -c '\'' if test -d "$1"; then test -d "$1/."; else case $1 in #( -*)set "./$1";; esac; case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #(( ???[sx]*):;;*)false;;esac;fi '\'' sh ' fi as_executable_p=$as_test_x # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" test -n "$DJDIR" || exec 7<&0 &1 # Name of the host. # hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, # so uname gets run too. ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` # # Initializations. # ac_default_prefix=/usr/local ac_clean_files= ac_config_libobj_dir=. LIBOBJS= cross_compiling=no subdirs= MFLAGS= MAKEFLAGS= # Identity of this package. PACKAGE_NAME='abcmidi' PACKAGE_TARNAME='abcmidi' PACKAGE_VERSION='2011-08-03' PACKAGE_STRING='abcmidi 2011-08-03' PACKAGE_BUGREPORT='fy733@ncf.ca' PACKAGE_URL='' ac_unique_file="abc.h" # Factoring default headers for most tests. ac_includes_default="\ #include #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_STAT_H # include #endif #ifdef STDC_HEADERS # include # include #else # ifdef HAVE_STDLIB_H # include # endif #endif #ifdef HAVE_STRING_H # if !defined STDC_HEADERS && defined HAVE_MEMORY_H # include # endif # include #endif #ifdef HAVE_STRINGS_H # include #endif #ifdef HAVE_INTTYPES_H # include #endif #ifdef HAVE_STDINT_H # include #endif #ifdef HAVE_UNISTD_H # include #endif" ac_subst_vars='LTLIBOBJS LIBOBJS EGREP GREP CPP INSTALL_DATA INSTALL_SCRIPT INSTALL_PROGRAM OBJEXT EXEEXT ac_ct_CC CPPFLAGS LDFLAGS CFLAGS CC target_alias host_alias build_alias LIBS ECHO_T ECHO_N ECHO_C DEFS mandir localedir libdir psdir pdfdir dvidir htmldir infodir docdir oldincludedir includedir localstatedir sharedstatedir sysconfdir datadir datarootdir libexecdir sbindir bindir program_transform_name prefix exec_prefix PACKAGE_URL PACKAGE_BUGREPORT PACKAGE_STRING PACKAGE_VERSION PACKAGE_TARNAME PACKAGE_NAME PATH_SEPARATOR SHELL' ac_subst_files='' ac_user_opts=' enable_option_checking enable_debug ' ac_precious_vars='build_alias host_alias target_alias CC CFLAGS LDFLAGS LIBS CPPFLAGS CPP' # Initialize some variables set by options. ac_init_help= ac_init_version=false ac_unrecognized_opts= ac_unrecognized_sep= # The variables have the same names as the options, with # dashes changed to underlines. cache_file=/dev/null exec_prefix=NONE no_create= no_recursion= prefix=NONE program_prefix=NONE program_suffix=NONE program_transform_name=s,x,x, silent= site= srcdir= verbose= x_includes=NONE x_libraries=NONE # Installation directory options. # These are left unexpanded so users can "make install exec_prefix=/foo" # and all the variables that are supposed to be based on exec_prefix # by default will actually change. # Use braces instead of parens because sh, perl, etc. also accept them. # (The list follows the same order as the GNU Coding Standards.) bindir='${exec_prefix}/bin' sbindir='${exec_prefix}/sbin' libexecdir='${exec_prefix}/libexec' datarootdir='${prefix}/share' datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' infodir='${datarootdir}/info' htmldir='${docdir}' dvidir='${docdir}' pdfdir='${docdir}' psdir='${docdir}' libdir='${exec_prefix}/lib' localedir='${datarootdir}/locale' mandir='${datarootdir}/man' ac_prev= ac_dashdash= for ac_option do # If the previous option needs an argument, assign it. if test -n "$ac_prev"; then eval $ac_prev=\$ac_option ac_prev= continue fi case $ac_option in *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; *=) ac_optarg= ;; *) ac_optarg=yes ;; esac # Accept the important Cygnus configure options, so we can diagnose typos. case $ac_dashdash$ac_option in --) ac_dashdash=yes ;; -bindir | --bindir | --bindi | --bind | --bin | --bi) ac_prev=bindir ;; -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) bindir=$ac_optarg ;; -build | --build | --buil | --bui | --bu) ac_prev=build_alias ;; -build=* | --build=* | --buil=* | --bui=* | --bu=*) build_alias=$ac_optarg ;; -cache-file | --cache-file | --cache-fil | --cache-fi \ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) ac_prev=cache_file ;; -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) cache_file=$ac_optarg ;; --config-cache | -C) cache_file=config.cache ;; -datadir | --datadir | --datadi | --datad) ac_prev=datadir ;; -datadir=* | --datadir=* | --datadi=* | --datad=*) datadir=$ac_optarg ;; -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ | --dataroo | --dataro | --datar) ac_prev=datarootdir ;; -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) datarootdir=$ac_optarg ;; -disable-* | --disable-*) ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=no ;; -docdir | --docdir | --docdi | --doc | --do) ac_prev=docdir ;; -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) docdir=$ac_optarg ;; -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) ac_prev=dvidir ;; -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) dvidir=$ac_optarg ;; -enable-* | --enable-*) ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=\$ac_optarg ;; -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ | --exec | --exe | --ex) ac_prev=exec_prefix ;; -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ | --exec=* | --exe=* | --ex=*) exec_prefix=$ac_optarg ;; -gas | --gas | --ga | --g) # Obsolete; use --with-gas. with_gas=yes ;; -help | --help | --hel | --he | -h) ac_init_help=long ;; -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) ac_init_help=recursive ;; -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) ac_init_help=short ;; -host | --host | --hos | --ho) ac_prev=host_alias ;; -host=* | --host=* | --hos=* | --ho=*) host_alias=$ac_optarg ;; -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) ac_prev=htmldir ;; -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ | --ht=*) htmldir=$ac_optarg ;; -includedir | --includedir | --includedi | --included | --include \ | --includ | --inclu | --incl | --inc) ac_prev=includedir ;; -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ | --includ=* | --inclu=* | --incl=* | --inc=*) includedir=$ac_optarg ;; -infodir | --infodir | --infodi | --infod | --info | --inf) ac_prev=infodir ;; -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) infodir=$ac_optarg ;; -libdir | --libdir | --libdi | --libd) ac_prev=libdir ;; -libdir=* | --libdir=* | --libdi=* | --libd=*) libdir=$ac_optarg ;; -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ | --libexe | --libex | --libe) ac_prev=libexecdir ;; -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ | --libexe=* | --libex=* | --libe=*) libexecdir=$ac_optarg ;; -localedir | --localedir | --localedi | --localed | --locale) ac_prev=localedir ;; -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) localedir=$ac_optarg ;; -localstatedir | --localstatedir | --localstatedi | --localstated \ | --localstate | --localstat | --localsta | --localst | --locals) ac_prev=localstatedir ;; -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) localstatedir=$ac_optarg ;; -mandir | --mandir | --mandi | --mand | --man | --ma | --m) ac_prev=mandir ;; -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) mandir=$ac_optarg ;; -nfp | --nfp | --nf) # Obsolete; use --without-fp. with_fp=no ;; -no-create | --no-create | --no-creat | --no-crea | --no-cre \ | --no-cr | --no-c | -n) no_create=yes ;; -no-recursion | --no-recursion | --no-recursio | --no-recursi \ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) no_recursion=yes ;; -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ | --oldin | --oldi | --old | --ol | --o) ac_prev=oldincludedir ;; -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) oldincludedir=$ac_optarg ;; -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) ac_prev=prefix ;; -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) prefix=$ac_optarg ;; -program-prefix | --program-prefix | --program-prefi | --program-pref \ | --program-pre | --program-pr | --program-p) ac_prev=program_prefix ;; -program-prefix=* | --program-prefix=* | --program-prefi=* \ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) program_prefix=$ac_optarg ;; -program-suffix | --program-suffix | --program-suffi | --program-suff \ | --program-suf | --program-su | --program-s) ac_prev=program_suffix ;; -program-suffix=* | --program-suffix=* | --program-suffi=* \ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) program_suffix=$ac_optarg ;; -program-transform-name | --program-transform-name \ | --program-transform-nam | --program-transform-na \ | --program-transform-n | --program-transform- \ | --program-transform | --program-transfor \ | --program-transfo | --program-transf \ | --program-trans | --program-tran \ | --progr-tra | --program-tr | --program-t) ac_prev=program_transform_name ;; -program-transform-name=* | --program-transform-name=* \ | --program-transform-nam=* | --program-transform-na=* \ | --program-transform-n=* | --program-transform-=* \ | --program-transform=* | --program-transfor=* \ | --program-transfo=* | --program-transf=* \ | --program-trans=* | --program-tran=* \ | --progr-tra=* | --program-tr=* | --program-t=*) program_transform_name=$ac_optarg ;; -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) ac_prev=pdfdir ;; -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) pdfdir=$ac_optarg ;; -psdir | --psdir | --psdi | --psd | --ps) ac_prev=psdir ;; -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) psdir=$ac_optarg ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) silent=yes ;; -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ | --sbi=* | --sb=*) sbindir=$ac_optarg ;; -sharedstatedir | --sharedstatedir | --sharedstatedi \ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ | --sharedst | --shareds | --shared | --share | --shar \ | --sha | --sh) ac_prev=sharedstatedir ;; -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ | --sha=* | --sh=*) sharedstatedir=$ac_optarg ;; -site | --site | --sit) ac_prev=site ;; -site=* | --site=* | --sit=*) site=$ac_optarg ;; -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) ac_prev=srcdir ;; -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) srcdir=$ac_optarg ;; -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ | --syscon | --sysco | --sysc | --sys | --sy) ac_prev=sysconfdir ;; -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) sysconfdir=$ac_optarg ;; -target | --target | --targe | --targ | --tar | --ta | --t) ac_prev=target_alias ;; -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) target_alias=$ac_optarg ;; -v | -verbose | --verbose | --verbos | --verbo | --verb) verbose=yes ;; -version | --version | --versio | --versi | --vers | -V) ac_init_version=: ;; -with-* | --with-*) ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=\$ac_optarg ;; -without-* | --without-*) ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=no ;; --x) # Obsolete; use --with-x. with_x=yes ;; -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ | --x-incl | --x-inc | --x-in | --x-i) ac_prev=x_includes ;; -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) x_includes=$ac_optarg ;; -x-libraries | --x-libraries | --x-librarie | --x-librari \ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) ac_prev=x_libraries ;; -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) x_libraries=$ac_optarg ;; -*) as_fn_error $? "unrecognized option: \`$ac_option' Try \`$0 --help' for more information" ;; *=*) ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` # Reject names that are not valid shell variable names. case $ac_envvar in #( '' | [0-9]* | *[!_$as_cr_alnum]* ) as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; esac eval $ac_envvar=\$ac_optarg export $ac_envvar ;; *) # FIXME: should be removed in autoconf 3.0. $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option} ;; esac done if test -n "$ac_prev"; then ac_option=--`echo $ac_prev | sed 's/_/-/g'` as_fn_error $? "missing argument to $ac_option" fi if test -n "$ac_unrecognized_opts"; then case $enable_option_checking in no) ;; fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; esac fi # Check all directory arguments for consistency. for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ libdir localedir mandir do eval ac_val=\$$ac_var # Remove trailing slashes. case $ac_val in */ ) ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` eval $ac_var=\$ac_val;; esac # Be sure to have absolute directory names. case $ac_val in [\\/$]* | ?:[\\/]* ) continue;; NONE | '' ) case $ac_var in *prefix ) continue;; esac;; esac as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" done # There might be people who depend on the old broken behavior: `$host' # used to hold the argument of --host etc. # FIXME: To remove some day. build=$build_alias host=$host_alias target=$target_alias # FIXME: To remove some day. if test "x$host_alias" != x; then if test "x$build_alias" = x; then cross_compiling=maybe $as_echo "$as_me: WARNING: if you wanted to set the --build type, don't use --host. If a cross compiler is detected then cross compile mode will be used" >&2 elif test "x$build_alias" != "x$host_alias"; then cross_compiling=yes fi fi ac_tool_prefix= test -n "$host_alias" && ac_tool_prefix=$host_alias- test "$silent" = yes && exec 6>/dev/null ac_pwd=`pwd` && test -n "$ac_pwd" && ac_ls_di=`ls -di .` && ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || as_fn_error $? "working directory cannot be determined" test "X$ac_ls_di" = "X$ac_pwd_ls_di" || as_fn_error $? "pwd does not report name of working directory" # Find the source files, if location was not specified. if test -z "$srcdir"; then ac_srcdir_defaulted=yes # Try the directory containing this script, then the parent directory. ac_confdir=`$as_dirname -- "$as_myself" || $as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_myself" : 'X\(//\)[^/]' \| \ X"$as_myself" : 'X\(//\)$' \| \ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_myself" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` srcdir=$ac_confdir if test ! -r "$srcdir/$ac_unique_file"; then srcdir=.. fi else ac_srcdir_defaulted=no fi if test ! -r "$srcdir/$ac_unique_file"; then test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" fi ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" ac_abs_confdir=`( cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" pwd)` # When building in place, set srcdir=. if test "$ac_abs_confdir" = "$ac_pwd"; then srcdir=. fi # Remove unnecessary trailing slashes from srcdir. # Double slashes in file names in object file debugging info # mess up M-x gdb in Emacs. case $srcdir in */) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; esac for ac_var in $ac_precious_vars; do eval ac_env_${ac_var}_set=\${${ac_var}+set} eval ac_env_${ac_var}_value=\$${ac_var} eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} eval ac_cv_env_${ac_var}_value=\$${ac_var} done # # Report the --help message. # if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF \`configure' configures abcmidi 2011-08-03 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... To assign environment variables (e.g., CC, CFLAGS...), specify them as VAR=VALUE. See below for descriptions of some of the useful variables. Defaults for the options are specified in brackets. Configuration: -h, --help display this help and exit --help=short display options specific to this package --help=recursive display the short help of all the included packages -V, --version display version information and exit -q, --quiet, --silent do not print \`checking ...' messages --cache-file=FILE cache test results in FILE [disabled] -C, --config-cache alias for \`--cache-file=config.cache' -n, --no-create do not create output files --srcdir=DIR find the sources in DIR [configure dir or \`..'] Installation directories: --prefix=PREFIX install architecture-independent files in PREFIX [$ac_default_prefix] --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX [PREFIX] By default, \`make install' will install all the files in \`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify an installation prefix other than \`$ac_default_prefix' using \`--prefix', for instance \`--prefix=\$HOME'. For better control, use the options below. Fine tuning of the installation directories: --bindir=DIR user executables [EPREFIX/bin] --sbindir=DIR system admin executables [EPREFIX/sbin] --libexecdir=DIR program executables [EPREFIX/libexec] --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] --datadir=DIR read-only architecture-independent data [DATAROOTDIR] --infodir=DIR info documentation [DATAROOTDIR/info] --localedir=DIR locale-dependent data [DATAROOTDIR/locale] --mandir=DIR man documentation [DATAROOTDIR/man] --docdir=DIR documentation root [DATAROOTDIR/doc/abcmidi] --htmldir=DIR html documentation [DOCDIR] --dvidir=DIR dvi documentation [DOCDIR] --pdfdir=DIR pdf documentation [DOCDIR] --psdir=DIR ps documentation [DOCDIR] _ACEOF cat <<\_ACEOF _ACEOF fi if test -n "$ac_init_help"; then case $ac_init_help in short | recursive ) echo "Configuration of abcmidi 2011-08-03:";; esac cat <<\_ACEOF Optional Features: --disable-option-checking ignore unrecognized --enable/--with options --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) --enable-FEATURE[=ARG] include FEATURE [ARG=yes] --enable-debug Enable debugging information Some influential environment variables: CC C compiler command CFLAGS C compiler flags LDFLAGS linker flags, e.g. -L if you have libraries in a nonstandard directory LIBS libraries to pass to the linker, e.g. -l CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if you have headers in a nonstandard directory CPP C preprocessor Use these variables to override the choices made by `configure' or to help it to find libraries and programs with nonstandard names/locations. Report bugs to Seymour Shlien fy733@ncf.ca . _ACEOF ac_status=$? fi if test "$ac_init_help" = "recursive"; then # If there are subdirs, report their specific --help. for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue test -d "$ac_dir" || { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || continue ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix cd "$ac_dir" || { ac_status=$?; continue; } # Check for guested configure. if test -f "$ac_srcdir/configure.gnu"; then echo && $SHELL "$ac_srcdir/configure.gnu" --help=recursive elif test -f "$ac_srcdir/configure"; then echo && $SHELL "$ac_srcdir/configure" --help=recursive else $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 fi || ac_status=$? cd "$ac_pwd" || { ac_status=$?; break; } done fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF abcmidi configure 2011-08-03 generated by GNU Autoconf 2.67 Copyright (C) 2010 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. _ACEOF exit fi ## ------------------------ ## ## Autoconf initialization. ## ## ------------------------ ## # ac_fn_c_try_compile LINENO # -------------------------- # Try to compile conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} as_fn_set_status $ac_retval } # ac_fn_c_try_compile # ac_fn_c_try_link LINENO # ----------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_link () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext conftest$ac_exeext if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || $as_test_x conftest$ac_exeext }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would # interfere with the next link command; also delete a directory that is # left behind by Apple's compiler. We do this before executing the actions. rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} as_fn_set_status $ac_retval } # ac_fn_c_try_link # ac_fn_c_try_cpp LINENO # ---------------------- # Try to preprocess conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_cpp () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_cpp conftest.$ac_ext" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } > conftest.i && { test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || test ! -s conftest.err }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} as_fn_set_status $ac_retval } # ac_fn_c_try_cpp # ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES # ------------------------------------------------------- # Tests whether HEADER exists, giving a warning if it cannot be compiled using # the include files in INCLUDES and setting the cache variable VAR # accordingly. ac_fn_c_check_header_mongrel () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if eval "test \"\${$3+set}\"" = set; then : { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval "test \"\${$3+set}\"" = set; then : $as_echo_n "(cached) " >&6 fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } else # Is the header compilable? { $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5 $as_echo_n "checking $2 usability... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_header_compiler=yes else ac_header_compiler=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5 $as_echo "$ac_header_compiler" >&6; } # Is the header present? { $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5 $as_echo_n "checking $2 presence... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include <$2> _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : ac_header_preproc=yes else ac_header_preproc=no fi rm -f conftest.err conftest.i conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5 $as_echo "$ac_header_preproc" >&6; } # So? What about this header? case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #(( yes:no: ) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5 $as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 $as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} ;; no:yes:* ) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5 $as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5 $as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5 $as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5 $as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 $as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} ( $as_echo "## ------------------------------------ ## ## Report this to Seymour Shlien fy733@ncf.ca ## ## ------------------------------------ ##" ) | sed "s/^/$as_me: WARNING: /" >&2 ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval "test \"\${$3+set}\"" = set; then : $as_echo_n "(cached) " >&6 else eval "$3=\$ac_header_compiler" fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } fi eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} } # ac_fn_c_check_header_mongrel # ac_fn_c_try_run LINENO # ---------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. Assumes # that executables *can* be run. ac_fn_c_try_run () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then : ac_retval=0 else $as_echo "$as_me: program exited with status $ac_status" >&5 $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=$ac_status fi rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} as_fn_set_status $ac_retval } # ac_fn_c_try_run # ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES # ------------------------------------------------------- # Tests whether HEADER exists and can be compiled using the include files in # INCLUDES, setting the cache variable VAR accordingly. ac_fn_c_check_header_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval "test \"\${$3+set}\"" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_c_try_compile "$LINENO"; then : eval "$3=yes" else eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} } # ac_fn_c_check_header_compile # ac_fn_c_check_type LINENO TYPE VAR INCLUDES # ------------------------------------------- # Tests whether TYPE exists after having included INCLUDES, setting cache # variable VAR accordingly. ac_fn_c_check_type () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval "test \"\${$3+set}\"" = set; then : $as_echo_n "(cached) " >&6 else eval "$3=no" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { if (sizeof ($2)) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { if (sizeof (($2))) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : else eval "$3=yes" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} } # ac_fn_c_check_type # ac_fn_c_check_func LINENO FUNC VAR # ---------------------------------- # Tests whether FUNC exists, setting the cache variable VAR accordingly ac_fn_c_check_func () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval "test \"\${$3+set}\"" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Define $2 to an innocuous variant, in case declares $2. For example, HP-UX 11i declares gettimeofday. */ #define $2 innocuous_$2 /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $2 (); below. Prefer to if __STDC__ is defined, since exists even on freestanding compilers. */ #ifdef __STDC__ # include #else # include #endif #undef $2 /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char $2 (); /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined __stub_$2 || defined __stub___$2 choke me #endif int main () { return $2 (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : eval "$3=yes" else eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} } # ac_fn_c_check_func cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. It was created by abcmidi $as_me 2011-08-03, which was generated by GNU Autoconf 2.67. Invocation command line was $ $0 $@ _ACEOF exec 5>>config.log { cat <<_ASUNAME ## --------- ## ## Platform. ## ## --------- ## hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` /bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` /bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` /usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` /bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` /bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` _ASUNAME as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. $as_echo "PATH: $as_dir" done IFS=$as_save_IFS } >&5 cat >&5 <<_ACEOF ## ----------- ## ## Core tests. ## ## ----------- ## _ACEOF # Keep a trace of the command line. # Strip out --no-create and --no-recursion so they do not pile up. # Strip out --silent because we don't want to record it for future runs. # Also quote any args containing shell meta-characters. # Make two passes to allow for proper duplicate-argument suppression. ac_configure_args= ac_configure_args0= ac_configure_args1= ac_must_keep_next=false for ac_pass in 1 2 do for ac_arg do case $ac_arg in -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) continue ;; *\'*) ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac case $ac_pass in 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; 2) as_fn_append ac_configure_args1 " '$ac_arg'" if test $ac_must_keep_next = true; then ac_must_keep_next=false # Got value, back to normal. else case $ac_arg in *=* | --config-cache | -C | -disable-* | --disable-* \ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ | -with-* | --with-* | -without-* | --without-* | --x) case "$ac_configure_args0 " in "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; esac ;; -* ) ac_must_keep_next=true ;; esac fi as_fn_append ac_configure_args " '$ac_arg'" ;; esac done done { ac_configure_args0=; unset ac_configure_args0;} { ac_configure_args1=; unset ac_configure_args1;} # When interrupted or exit'd, cleanup temporary files, and complete # config.log. We remove comments because anyway the quotes in there # would cause problems or look ugly. # WARNING: Use '\'' to represent an apostrophe within the trap. # WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. trap 'exit_status=$? # Save into config.log some information that might help in debugging. { echo $as_echo "## ---------------- ## ## Cache variables. ## ## ---------------- ##" echo # The following way of writing the cache mishandles newlines in values, ( for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( *${as_nl}ac_space=\ *) sed -n \ "s/'\''/'\''\\\\'\'''\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" ;; #( *) sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) echo $as_echo "## ----------------- ## ## Output variables. ## ## ----------------- ##" echo for ac_var in $ac_subst_vars do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo if test -n "$ac_subst_files"; then $as_echo "## ------------------- ## ## File substitutions. ## ## ------------------- ##" echo for ac_var in $ac_subst_files do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo fi if test -s confdefs.h; then $as_echo "## ----------- ## ## confdefs.h. ## ## ----------- ##" echo cat confdefs.h echo fi test "$ac_signal" != 0 && $as_echo "$as_me: caught signal $ac_signal" $as_echo "$as_me: exit $exit_status" } >&5 rm -f core *.core core.conftest.* && rm -f -r conftest* confdefs* conf$$* $ac_clean_files && exit $exit_status ' 0 for ac_signal in 1 2 13 15; do trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal done ac_signal=0 # confdefs.h avoids OS command line length limits that DEFS can exceed. rm -f -r conftest* confdefs.h $as_echo "/* confdefs.h */" > confdefs.h # Predefined preprocessor variables. cat >>confdefs.h <<_ACEOF #define PACKAGE_NAME "$PACKAGE_NAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_TARNAME "$PACKAGE_TARNAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_VERSION "$PACKAGE_VERSION" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_STRING "$PACKAGE_STRING" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_URL "$PACKAGE_URL" _ACEOF # Let the site file select an alternate cache file if it wants to. # Prefer an explicitly selected file to automatically selected ones. ac_site_file1=NONE ac_site_file2=NONE if test -n "$CONFIG_SITE"; then # We do not want a PATH search for config.site. case $CONFIG_SITE in #(( -*) ac_site_file1=./$CONFIG_SITE;; */*) ac_site_file1=$CONFIG_SITE;; *) ac_site_file1=./$CONFIG_SITE;; esac elif test "x$prefix" != xNONE; then ac_site_file1=$prefix/share/config.site ac_site_file2=$prefix/etc/config.site else ac_site_file1=$ac_default_prefix/share/config.site ac_site_file2=$ac_default_prefix/etc/config.site fi for ac_site_file in "$ac_site_file1" "$ac_site_file2" do test "x$ac_site_file" = xNONE && continue if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 $as_echo "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 . "$ac_site_file" \ || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "failed to load site script $ac_site_file See \`config.log' for more details" "$LINENO" 5 ; } fi done if test -r "$cache_file"; then # Some versions of bash will fail to source /dev/null (special files # actually), so we avoid doing that. DJGPP emulates it as a regular file. if test /dev/null != "$cache_file" && test -f "$cache_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 $as_echo "$as_me: loading cache $cache_file" >&6;} case $cache_file in [\\/]* | ?:[\\/]* ) . "$cache_file";; *) . "./$cache_file";; esac fi else { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 $as_echo "$as_me: creating cache $cache_file" >&6;} >$cache_file fi # Check that the precious variables saved in the cache have kept the same # value. ac_cache_corrupted=false for ac_var in $ac_precious_vars; do eval ac_old_set=\$ac_cv_env_${ac_var}_set eval ac_new_set=\$ac_env_${ac_var}_set eval ac_old_val=\$ac_cv_env_${ac_var}_value eval ac_new_val=\$ac_env_${ac_var}_value case $ac_old_set,$ac_new_set in set,) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} ac_cache_corrupted=: ;; ,set) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} ac_cache_corrupted=: ;; ,);; *) if test "x$ac_old_val" != "x$ac_new_val"; then # differences in whitespace do not lead to failure. ac_old_val_w=`echo x $ac_old_val` ac_new_val_w=`echo x $ac_new_val` if test "$ac_old_val_w" != "$ac_new_val_w"; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 $as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} ac_cache_corrupted=: else { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 $as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} eval $ac_var=\$ac_old_val fi { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 $as_echo "$as_me: former value: \`$ac_old_val'" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 $as_echo "$as_me: current value: \`$ac_new_val'" >&2;} fi;; esac # Pass precious variables to config.status. if test "$ac_new_set" = set; then case $ac_new_val in *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; *) ac_arg=$ac_var=$ac_new_val ;; esac case " $ac_configure_args " in *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. *) as_fn_append ac_configure_args " '$ac_arg'" ;; esac fi done if $ac_cache_corrupted; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 $as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 fi ## -------------------- ## ## Main body of script. ## ## -------------------- ## ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_config_headers="$ac_config_headers config.h" # Checks for programs. cflags_save="$CFLAGS" ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. set dummy ${ac_tool_prefix}gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_CC+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_CC="${ac_tool_prefix}gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_ac_ct_CC+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_CC="gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi else CC="$ac_cv_prog_CC" fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. set dummy ${ac_tool_prefix}cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_CC+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_CC="${ac_tool_prefix}cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi fi if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_CC+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else ac_prog_rejected=no as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue fi ac_cv_prog_CC="cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS if test $ac_prog_rejected = yes; then # We found a bogon in the path, so make sure we never use it. set dummy $ac_cv_prog_CC shift if test $# != 0; then # We chose a different compiler from the bogus one. # However, it has the same basename, so the bogon will be chosen # first if we set CC to just the basename; use the full file name. shift ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" fi fi fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then for ac_prog in cl.exe do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_CC+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$CC" && break done fi if test -z "$CC"; then ac_ct_CC=$CC for ac_prog in cl.exe do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_ac_ct_CC+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_CC="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_CC" && break done if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi fi fi test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "no acceptable C compiler found in \$PATH See \`config.log' for more details" "$LINENO" 5 ; } # Provide some information about the compiler. $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then sed '10a\ ... rest of stderr output deleted ... 10q' conftest.err >conftest.er1 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" # Try to create an executable without -o first, disregard a.out. # It will help us diagnose broken compilers, and finding out an intuition # of exeext. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 $as_echo_n "checking whether the C compiler works... " >&6; } ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` # The possible output files: ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" ac_rmfiles= for ac_file in $ac_files do case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; * ) ac_rmfiles="$ac_rmfiles $ac_file";; esac done rm -f $ac_rmfiles if { { ac_try="$ac_link_default" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link_default") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. # So ignore a value of `no', otherwise this would lead to `EXEEXT = no' # in a Makefile. We should not override ac_cv_exeext if it was cached, # so that the user can short-circuit this test for compilers unknown to # Autoconf. for ac_file in $ac_files '' do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; [ab].out ) # We found the default executable, but exeext='' is most # certainly right. break;; *.* ) if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; then :; else ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` fi # We set ac_cv_exeext here because the later test for it is not # safe: cross compilers may not add the suffix if given an `-o' # argument, so we may need to know it at that point already. # Even if this section looks crufty: it has the advantage of # actually working. break;; * ) break;; esac done test "$ac_cv_exeext" = no && ac_cv_exeext= else ac_file='' fi if test -z "$ac_file"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "C compiler cannot create executables See \`config.log' for more details" "$LINENO" 5 ; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 $as_echo_n "checking for C compiler default output file name... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 $as_echo "$ac_file" >&6; } ac_exeext=$ac_cv_exeext rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 $as_echo_n "checking for suffix of executables... " >&6; } if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : # If both `conftest.exe' and `conftest' are `present' (well, observable) # catch `conftest.exe'. For instance with Cygwin, `ls conftest' will # work properly (i.e., refer to `conftest.exe'), while it won't with # `rm'. for ac_file in conftest.exe conftest conftest.*; do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` break;; * ) break;; esac done else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of executables: cannot compile and link See \`config.log' for more details" "$LINENO" 5 ; } fi rm -f conftest conftest$ac_cv_exeext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 $as_echo "$ac_cv_exeext" >&6; } rm -f conftest.$ac_ext EXEEXT=$ac_cv_exeext ac_exeext=$EXEEXT cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { FILE *f = fopen ("conftest.out", "w"); return ferror (f) || fclose (f) != 0; ; return 0; } _ACEOF ac_clean_files="$ac_clean_files conftest.out" # Check that the compiler produces executables we can run. If not, either # the compiler is broken, or we cross compile. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 $as_echo_n "checking whether we are cross compiling... " >&6; } if test "$cross_compiling" != yes; then { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if { ac_try='./conftest$ac_cv_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then cross_compiling=no else if test "$cross_compiling" = maybe; then cross_compiling=yes else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot run C compiled programs. If you meant to cross compile, use \`--host'. See \`config.log' for more details" "$LINENO" 5 ; } fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 $as_echo "$cross_compiling" >&6; } rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 $as_echo_n "checking for suffix of object files... " >&6; } if test "${ac_cv_objext+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF rm -f conftest.o conftest.obj if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : for ac_file in conftest.o conftest.obj conftest.*; do test -f "$ac_file" || continue; case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` break;; esac done else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of object files: cannot compile See \`config.log' for more details" "$LINENO" 5 ; } fi rm -f conftest.$ac_cv_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 $as_echo "$ac_cv_objext" >&6; } OBJEXT=$ac_cv_objext ac_objext=$OBJEXT { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 $as_echo_n "checking whether we are using the GNU C compiler... " >&6; } if test "${ac_cv_c_compiler_gnu+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_compiler_gnu=yes else ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 $as_echo "$ac_cv_c_compiler_gnu" >&6; } if test $ac_compiler_gnu = yes; then GCC=yes else GCC= fi ac_test_CFLAGS=${CFLAGS+set} ac_save_CFLAGS=$CFLAGS { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 $as_echo_n "checking whether $CC accepts -g... " >&6; } if test "${ac_cv_prog_cc_g+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_save_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes ac_cv_prog_cc_g=no CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes else CFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : else ac_c_werror_flag=$ac_save_c_werror_flag CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_c_werror_flag=$ac_save_c_werror_flag fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 $as_echo "$ac_cv_prog_cc_g" >&6; } if test "$ac_test_CFLAGS" = set; then CFLAGS=$ac_save_CFLAGS elif test $ac_cv_prog_cc_g = yes; then if test "$GCC" = yes; then CFLAGS="-g -O2" else CFLAGS="-g" fi else if test "$GCC" = yes; then CFLAGS="-O2" else CFLAGS= fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 $as_echo_n "checking for $CC option to accept ISO C89... " >&6; } if test "${ac_cv_prog_cc_c89+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_cv_prog_cc_c89=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #include /* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ struct buf { int x; }; FILE * (*rcsopen) (struct buf *, struct stat *, int); static char *e (p, i) char **p; int i; { return p[i]; } static char *f (char * (*g) (char **, int), char **p, ...) { char *s; va_list v; va_start (v,p); s = g (p, va_arg (v,int)); va_end (v); return s; } /* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has function prototypes and stuff, but not '\xHH' hex character constants. These don't provoke an error unfortunately, instead are silently treated as 'x'. The following induces an error, until -std is added to get proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an array size at least. It's necessary to write '\x00'==0 to get something that's true only with -std. */ int osf4_cc_array ['\x00' == 0 ? 1 : -1]; /* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters inside strings and character constants. */ #define FOO(x) 'x' int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; int test (int i, double x); struct s1 {int (*f) (int a);}; struct s2 {int (*f) (double a);}; int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); int argc; char **argv; int main () { return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; ; return 0; } _ACEOF for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_c89=$ac_arg fi rm -f core conftest.err conftest.$ac_objext test "x$ac_cv_prog_cc_c89" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi # AC_CACHE_VAL case "x$ac_cv_prog_cc_c89" in x) { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 $as_echo "none needed" >&6; } ;; xno) { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 $as_echo "unsupported" >&6; } ;; *) CC="$CC $ac_cv_prog_cc_c89" { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 $as_echo "$ac_cv_prog_cc_c89" >&6; } ;; esac if test "x$ac_cv_prog_cc_c89" != xno; then : fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu CFLAGS="$cflags_save" # Check whether --enable-debug was given. if test "${enable_debug+set}" = set; then : enableval=$enable_debug; USE_DEBUG="$enableval" else USE_DEBUG="no" fi if test $USE_DEBUG = yes ; then CFLAGS="$CFLAGS -g" else CFLAGS="$CFLAGS -O2" fi ac_aux_dir= for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do if test -f "$ac_dir/install-sh"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install-sh -c" break elif test -f "$ac_dir/install.sh"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install.sh -c" break elif test -f "$ac_dir/shtool"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/shtool install -c" break fi done if test -z "$ac_aux_dir"; then as_fn_error $? "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$LINENO" 5 fi # These three variables are undocumented and unsupported, # and are intended to be withdrawn in a future Autoconf release. # They can cause serious problems if a builder's source tree is in a directory # whose full name contains unusual characters. ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. # Find a good install program. We prefer a C program (faster), # so one script is as good as another. But avoid the broken or # incompatible versions: # SysV /etc/install, /usr/sbin/install # SunOS /usr/etc/install # IRIX /sbin/install # AIX /bin/install # AmigaOS /C/install, which installs bootblocks on floppy discs # AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag # AFS /usr/afsws/bin/install, which mishandles nonexistent args # SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" # OS/2's system install, which has a completely different semantic # ./install, which can be erroneously created by make from ./install.sh. # Reject install programs that cannot install multiple files. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 $as_echo_n "checking for a BSD-compatible install... " >&6; } if test -z "$INSTALL"; then if test "${ac_cv_path_install+set}" = set; then : $as_echo_n "(cached) " >&6 else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. # Account for people who put trailing slashes in PATH elements. case $as_dir/ in #(( ./ | .// | /[cC]/* | \ /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \ /usr/ucb/* ) ;; *) # OSF1 and SCO ODT 3.0 have their own names for install. # Don't use installbsd from OSF since it installs stuff as root # by default. for ac_prog in ginstall scoinst install; do for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; }; then if test $ac_prog = install && grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # AIX install. It has an incompatible calling convention. : elif test $ac_prog = install && grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # program-specific install script used by HP pwplus--don't use. : else rm -rf conftest.one conftest.two conftest.dir echo one > conftest.one echo two > conftest.two mkdir conftest.dir if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" && test -s conftest.one && test -s conftest.two && test -s conftest.dir/conftest.one && test -s conftest.dir/conftest.two then ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" break 3 fi fi fi done done ;; esac done IFS=$as_save_IFS rm -rf conftest.one conftest.two conftest.dir fi if test "${ac_cv_path_install+set}" = set; then INSTALL=$ac_cv_path_install else # As a last resort, use the slow shell script. Don't cache a # value for INSTALL within a source directory, because that will # break other packages using the cache if that directory is # removed, or if the value is a relative name. INSTALL=$ac_install_sh fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 $as_echo "$INSTALL" >&6; } # Use test -z because SunOS4 sh mishandles braces in ${var-val}. # It thinks the first close brace ends the variable substitution. test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' # Checks for libraries. # FIXME: Replace `main' with a function in `-lm': { $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -lm" >&5 $as_echo_n "checking for main in -lm... " >&6; } if test "${ac_cv_lib_m_main+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lm $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { return main (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_m_main=yes else ac_cv_lib_m_main=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_m_main" >&5 $as_echo "$ac_cv_lib_m_main" >&6; } if test "x$ac_cv_lib_m_main" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBM 1 _ACEOF LIBS="-lm $LIBS" fi # Checks for header files. ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 $as_echo_n "checking how to run the C preprocessor... " >&6; } # On Suns, sometimes $CPP names a directory. if test -n "$CPP" && test -d "$CPP"; then CPP= fi if test -z "$CPP"; then if test "${ac_cv_prog_CPP+set}" = set; then : $as_echo_n "(cached) " >&6 else # Double quotes because CPP needs to be expanded for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" do ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : break fi done ac_cv_prog_CPP=$CPP fi CPP=$ac_cv_prog_CPP else ac_cv_prog_CPP=$CPP fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 $as_echo "$CPP" >&6; } ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "C preprocessor \"$CPP\" fails sanity check See \`config.log' for more details" "$LINENO" 5 ; } fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 $as_echo_n "checking for grep that handles long lines and -e... " >&6; } if test "${ac_cv_path_GREP+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -z "$GREP"; then ac_path_GREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in grep ggrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" { test -f "$ac_path_GREP" && $as_test_x "$ac_path_GREP"; } || continue # Check for GNU ac_path_GREP and select it if it is found. # Check for GNU $ac_path_GREP case `"$ac_path_GREP" --version 2>&1` in *GNU*) ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'GREP' >> "conftest.nl" "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_GREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_GREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_GREP"; then as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_GREP=$GREP fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 $as_echo "$ac_cv_path_GREP" >&6; } GREP="$ac_cv_path_GREP" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 $as_echo_n "checking for egrep... " >&6; } if test "${ac_cv_path_EGREP+set}" = set; then : $as_echo_n "(cached) " >&6 else if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 then ac_cv_path_EGREP="$GREP -E" else if test -z "$EGREP"; then ac_path_EGREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in egrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" { test -f "$ac_path_EGREP" && $as_test_x "$ac_path_EGREP"; } || continue # Check for GNU ac_path_EGREP and select it if it is found. # Check for GNU $ac_path_EGREP case `"$ac_path_EGREP" --version 2>&1` in *GNU*) ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'EGREP' >> "conftest.nl" "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_EGREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_EGREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_EGREP"; then as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_EGREP=$EGREP fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 $as_echo "$ac_cv_path_EGREP" >&6; } EGREP="$ac_cv_path_EGREP" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 $as_echo_n "checking for ANSI C header files... " >&6; } if test "${ac_cv_header_stdc+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #include int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_header_stdc=yes else ac_cv_header_stdc=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if test $ac_cv_header_stdc = yes; then # SunOS 4.x string.h does not declare mem*, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "memchr" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "free" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. if test "$cross_compiling" = yes; then : : else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #if ((' ' & 0x0FF) == 0x020) # define ISLOWER(c) ('a' <= (c) && (c) <= 'z') # define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) #else # define ISLOWER(c) \ (('a' <= (c) && (c) <= 'i') \ || ('j' <= (c) && (c) <= 'r') \ || ('s' <= (c) && (c) <= 'z')) # define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) #endif #define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) int main () { int i; for (i = 0; i < 256; i++) if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) return 2; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : else ac_cv_header_stdc=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 $as_echo "$ac_cv_header_stdc" >&6; } if test $ac_cv_header_stdc = yes; then $as_echo "#define STDC_HEADERS 1" >>confdefs.h fi # On IRIX 5.3, sys/types and inttypes.h are conflicting. for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ inttypes.h stdint.h unistd.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default " if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done for ac_header in stdlib.h string.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done # Checks for typedefs, structures, and compiler characteristics. ac_fn_c_check_type "$LINENO" "size_t" "ac_cv_type_size_t" "$ac_includes_default" if test "x$ac_cv_type_size_t" = x""yes; then : else cat >>confdefs.h <<_ACEOF #define size_t unsigned int _ACEOF fi # Checks for library functions. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for error_at_line" >&5 $as_echo_n "checking for error_at_line... " >&6; } if test "${ac_cv_lib_error_at_line+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { error_at_line (0, 0, "", 0, "an error occurred"); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_error_at_line=yes else ac_cv_lib_error_at_line=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_error_at_line" >&5 $as_echo "$ac_cv_lib_error_at_line" >&6; } if test $ac_cv_lib_error_at_line = no; then case " $LIBOBJS " in *" error.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS error.$ac_objext" ;; esac fi for ac_header in stdlib.h do : ac_fn_c_check_header_mongrel "$LINENO" "stdlib.h" "ac_cv_header_stdlib_h" "$ac_includes_default" if test "x$ac_cv_header_stdlib_h" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STDLIB_H 1 _ACEOF fi done { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU libc compatible malloc" >&5 $as_echo_n "checking for GNU libc compatible malloc... " >&6; } if test "${ac_cv_func_malloc_0_nonnull+set}" = set; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : ac_cv_func_malloc_0_nonnull=no else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #if defined STDC_HEADERS || defined HAVE_STDLIB_H # include #else char *malloc (); #endif int main () { return ! malloc (0); ; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : ac_cv_func_malloc_0_nonnull=yes else ac_cv_func_malloc_0_nonnull=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_malloc_0_nonnull" >&5 $as_echo "$ac_cv_func_malloc_0_nonnull" >&6; } if test $ac_cv_func_malloc_0_nonnull = yes; then : $as_echo "#define HAVE_MALLOC 1" >>confdefs.h else $as_echo "#define HAVE_MALLOC 0" >>confdefs.h case " $LIBOBJS " in *" malloc.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS malloc.$ac_objext" ;; esac $as_echo "#define malloc rpl_malloc" >>confdefs.h fi for ac_func in strcasecmp strchr do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF fi done ac_config_files="$ac_config_files Makefile" cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure # scripts and configure runs, see configure's option --config-cache. # It is not useful on other systems. If it contains results you don't # want to keep, you may remove or edit it. # # config.status only pays attention to the cache file if you give it # the --recheck option to rerun configure. # # `ac_cv_env_foo' variables (set or unset) will be overridden when # loading this file, other *unset* `ac_cv_foo' will be assigned the # following values. _ACEOF # The following way of writing the cache mishandles newlines in values, # but we know of no workaround that is simple, portable, and efficient. # So, we kill variables containing newlines. # Ultrix sh set writes to stderr and can't be redirected directly, # and sets the high bit in the cache file unless we assign to the vars. ( for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space=' '; set) 2>&1` in #( *${as_nl}ac_space=\ *) # `set' does not quote correctly, so add quotes: double-quote # substitution turns \\\\ into \\, and sed turns \\ into \. sed -n \ "s/'/'\\\\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" ;; #( *) # `set' quotes correctly as required by POSIX, so do not add quotes. sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) | sed ' /^ac_cv_env_/b end t clear :clear s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ t end s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ :end' >>confcache if diff "$cache_file" confcache >/dev/null 2>&1; then :; else if test -w "$cache_file"; then test "x$cache_file" != "x/dev/null" && { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 $as_echo "$as_me: updating cache $cache_file" >&6;} cat confcache >$cache_file else { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 $as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} fi fi rm -f confcache test "x$prefix" = xNONE && prefix=$ac_default_prefix # Let make expand exec_prefix. test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' DEFS=-DHAVE_CONFIG_H ac_libobjs= ac_ltlibobjs= U= for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue # 1. Remove the extension, and $U if already installed. ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' ac_i=`$as_echo "$ac_i" | sed "$ac_script"` # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR # will be set to the directory where LIBOBJS objects are built. as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' done LIBOBJS=$ac_libobjs LTLIBOBJS=$ac_ltlibobjs : ${CONFIG_STATUS=./config.status} ac_write_fail=0 ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files $CONFIG_STATUS" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 $as_echo "$as_me: creating $CONFIG_STATUS" >&6;} as_write_fail=0 cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 #! $SHELL # Generated by $as_me. # Run this file to recreate the current configuration. # Compiler output produced by configure, useful for debugging # configure, is in config.log if it exists. debug=false ac_cs_recheck=false ac_cs_silent=false SHELL=\${CONFIG_SHELL-$SHELL} export SHELL _ASEOF cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -p'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -p' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -p' fi else as_ln_s='cp -p' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi if test -x / >/dev/null 2>&1; then as_test_x='test -x' else if ls -dL / >/dev/null 2>&1; then as_ls_L_option=L else as_ls_L_option= fi as_test_x=' eval sh -c '\'' if test -d "$1"; then test -d "$1/."; else case $1 in #( -*)set "./$1";; esac; case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #(( ???[sx]*):;;*)false;;esac;fi '\'' sh ' fi as_executable_p=$as_test_x # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" exec 6>&1 ## ----------------------------------- ## ## Main body of $CONFIG_STATUS script. ## ## ----------------------------------- ## _ASEOF test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Save the log message, to keep $0 and so on meaningful, and to # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" This file was extended by abcmidi $as_me 2011-08-03, which was generated by GNU Autoconf 2.67. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS CONFIG_LINKS = $CONFIG_LINKS CONFIG_COMMANDS = $CONFIG_COMMANDS $ $0 $@ on `(hostname || uname -n) 2>/dev/null | sed 1q` " _ACEOF case $ac_config_files in *" "*) set x $ac_config_files; shift; ac_config_files=$*;; esac case $ac_config_headers in *" "*) set x $ac_config_headers; shift; ac_config_headers=$*;; esac cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # Files that config.status was made for. config_files="$ac_config_files" config_headers="$ac_config_headers" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 ac_cs_usage="\ \`$as_me' instantiates files and other configuration actions from templates according to the current configuration. Unless the files and actions are specified as TAGs, all are instantiated by default. Usage: $0 [OPTION]... [TAG]... -h, --help print this help, then exit -V, --version print version number and configuration settings, then exit --config print configuration, then exit -q, --quiet, --silent do not print progress messages -d, --debug don't remove temporary files --recheck update $as_me by reconfiguring in the same conditions --file=FILE[:TEMPLATE] instantiate the configuration file FILE --header=FILE[:TEMPLATE] instantiate the configuration header FILE Configuration files: $config_files Configuration headers: $config_headers Report bugs to Seymour Shlien ." _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ abcmidi config.status 2011-08-03 configured by $0, generated by GNU Autoconf 2.67, with options \\"\$ac_cs_config\\" Copyright (C) 2010 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." ac_pwd='$ac_pwd' srcdir='$srcdir' INSTALL='$INSTALL' test -n "\$AWK" || AWK=awk _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # The default lists apply if the user does not specify any file. ac_need_defaults=: while test $# != 0 do case $1 in --*=?*) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` ac_shift=: ;; --*=) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg= ac_shift=: ;; *) ac_option=$1 ac_optarg=$2 ac_shift=shift ;; esac case $ac_option in # Handling of the options. -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) ac_cs_recheck=: ;; --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) $as_echo "$ac_cs_version"; exit ;; --config | --confi | --conf | --con | --co | --c ) $as_echo "$ac_cs_config"; exit ;; --debug | --debu | --deb | --de | --d | -d ) debug=: ;; --file | --fil | --fi | --f ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; '') as_fn_error $? "missing file argument" ;; esac as_fn_append CONFIG_FILES " '$ac_optarg'" ac_need_defaults=false;; --header | --heade | --head | --hea ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; esac as_fn_append CONFIG_HEADERS " '$ac_optarg'" ac_need_defaults=false;; --he | --h) # Conflict between --help and --header as_fn_error $? "ambiguous option: \`$1' Try \`$0 --help' for more information.";; --help | --hel | -h ) $as_echo "$ac_cs_usage"; exit ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil | --si | --s) ac_cs_silent=: ;; # This is an error. -*) as_fn_error $? "unrecognized option: \`$1' Try \`$0 --help' for more information." ;; *) as_fn_append ac_config_targets " $1" ac_need_defaults=false ;; esac shift done ac_configure_extra_args= if $ac_cs_silent; then exec 6>/dev/null ac_configure_extra_args="$ac_configure_extra_args --silent" fi _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 if \$ac_cs_recheck; then set X '$SHELL' '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion shift \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 CONFIG_SHELL='$SHELL' export CONFIG_SHELL exec "\$@" fi _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 exec 5>>config.log { echo sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX ## Running $as_me. ## _ASBOX $as_echo "$ac_log" } >&5 _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Handling of arguments. for ac_config_target in $ac_config_targets do case $ac_config_target in "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;; "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5 ;; esac done # If the user did not use the arguments to specify the items to instantiate, # then the envvar interface is used. Set only those that are not. # We use the long form for the default assignment because of an extremely # bizarre bug on SunOS 4.1.3. if $ac_need_defaults; then test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers fi # Have a temporary directory for convenience. Make it in the build tree # simply because there is no reason against having it here, and in addition, # creating and moving files from /tmp can sometimes cause problems. # Hook for its removal unless debugging. # Note that there is a small window in which the directory will not be cleaned: # after its creation but before its name has been assigned to `$tmp'. $debug || { tmp= trap 'exit_status=$? { test -z "$tmp" || test ! -d "$tmp" || rm -fr "$tmp"; } && exit $exit_status ' 0 trap 'as_fn_exit 1' 1 2 13 15 } # Create a (secure) tmp directory for tmp files. { tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" } || { tmp=./conf$$-$RANDOM (umask 077 && mkdir "$tmp") } || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 # Set up the scripts for CONFIG_FILES section. # No need to generate them if there are no CONFIG_FILES. # This happens for instance with `./config.status config.h'. if test -n "$CONFIG_FILES"; then ac_cr=`echo X | tr X '\015'` # On cygwin, bash can eat \r inside `` if the user requested igncr. # But we know of no other shell where ac_cr would be empty at this # point, so we can use a bashism as a fallback. if test "x$ac_cr" = x; then eval ac_cr=\$\'\\r\' fi ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then ac_cs_awk_cr='\\r' else ac_cs_awk_cr=$ac_cr fi echo 'BEGIN {' >"$tmp/subs1.awk" && _ACEOF { echo "cat >conf$$subs.awk <<_ACEOF" && echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && echo "_ACEOF" } >conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` ac_delim='%!_!# ' for ac_last_try in false false false false false :; do . ./conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` if test $ac_delim_n = $ac_delim_num; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done rm -f conf$$subs.sh cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 cat >>"\$tmp/subs1.awk" <<\\_ACAWK && _ACEOF sed -n ' h s/^/S["/; s/!.*/"]=/ p g s/^[^!]*!// :repl t repl s/'"$ac_delim"'$// t delim :nl h s/\(.\{148\}\)..*/\1/ t more1 s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ p n b repl :more1 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t nl :delim h s/\(.\{148\}\)..*/\1/ t more2 s/["\\]/\\&/g; s/^/"/; s/$/"/ p b :more2 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t delim ' >$CONFIG_STATUS || ac_write_fail=1 rm -f conf$$subs.awk cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACAWK cat >>"\$tmp/subs1.awk" <<_ACAWK && for (key in S) S_is_set[key] = 1 FS = "" } { line = $ 0 nfields = split(line, field, "@") substed = 0 len = length(field[1]) for (i = 2; i < nfields; i++) { key = field[i] keylen = length(key) if (S_is_set[key]) { value = S[key] line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) len += length(value) + length(field[++i]) substed = 1 } else len += 1 + keylen } print line } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" else cat fi < "$tmp/subs1.awk" > "$tmp/subs.awk" \ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 _ACEOF # VPATH may cause trouble with some makes, so we remove sole $(srcdir), # ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and # trailing colons and then remove the whole line if VPATH becomes empty # (actually we leave an empty line to preserve line numbers). if test "x$srcdir" = x.; then ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ h s/// s/^/:/ s/[ ]*$/:/ s/:\$(srcdir):/:/g s/:\${srcdir}:/:/g s/:@srcdir@:/:/g s/^:*// s/:*$// x s/\(=[ ]*\).*/\1/ G s/\n// s/^[^=]*=[ ]*$// }' fi cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 fi # test -n "$CONFIG_FILES" # Set up the scripts for CONFIG_HEADERS section. # No need to generate them if there are no CONFIG_HEADERS. # This happens for instance with `./config.status Makefile'. if test -n "$CONFIG_HEADERS"; then cat >"$tmp/defines.awk" <<\_ACAWK || BEGIN { _ACEOF # Transform confdefs.h into an awk script `defines.awk', embedded as # here-document in config.status, that substitutes the proper values into # config.h.in to produce config.h. # Create a delimiter string that does not exist in confdefs.h, to ease # handling of long lines. ac_delim='%!_!# ' for ac_last_try in false false :; do ac_t=`sed -n "/$ac_delim/p" confdefs.h` if test -z "$ac_t"; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done # For the awk script, D is an array of macro values keyed by name, # likewise P contains macro parameters if any. Preserve backslash # newline sequences. ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]* sed -n ' s/.\{148\}/&'"$ac_delim"'/g t rset :rset s/^[ ]*#[ ]*define[ ][ ]*/ / t def d :def s/\\$// t bsnl s/["\\]/\\&/g s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ D["\1"]=" \3"/p s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p d :bsnl s/["\\]/\\&/g s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ D["\1"]=" \3\\\\\\n"\\/p t cont s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p t cont d :cont n s/.\{148\}/&'"$ac_delim"'/g t clear :clear s/\\$// t bsnlc s/["\\]/\\&/g; s/^/"/; s/$/"/p d :bsnlc s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p b cont ' >$CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 for (key in D) D_is_set[key] = 1 FS = "" } /^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ { line = \$ 0 split(line, arg, " ") if (arg[1] == "#") { defundef = arg[2] mac1 = arg[3] } else { defundef = substr(arg[1], 2) mac1 = arg[2] } split(mac1, mac2, "(") #) macro = mac2[1] prefix = substr(line, 1, index(line, defundef) - 1) if (D_is_set[macro]) { # Preserve the white space surrounding the "#". print prefix "define", macro P[macro] D[macro] next } else { # Replace #undef with comments. This is necessary, for example, # in the case of _POSIX_SOURCE, which is predefined and required # on some systems where configure will not decide to define it. if (defundef == "undef") { print "/*", prefix defundef, macro, "*/" next } } } { print } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 as_fn_error $? "could not setup config headers machinery" "$LINENO" 5 fi # test -n "$CONFIG_HEADERS" eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS " shift for ac_tag do case $ac_tag in :[FHLC]) ac_mode=$ac_tag; continue;; esac case $ac_mode$ac_tag in :[FHL]*:*);; :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5 ;; :[FH]-) ac_tag=-:-;; :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; esac ac_save_IFS=$IFS IFS=: set x $ac_tag IFS=$ac_save_IFS shift ac_file=$1 shift case $ac_mode in :L) ac_source=$1;; :[FH]) ac_file_inputs= for ac_f do case $ac_f in -) ac_f="$tmp/stdin";; *) # Look for the file first in the build tree, then in the source tree # (if the path is not absolute). The absolute path cannot be DOS-style, # because $ac_f cannot contain `:'. test -f "$ac_f" || case $ac_f in [\\/$]*) false;; *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; esac || as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5 ;; esac case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac as_fn_append ac_file_inputs " '$ac_f'" done # Let's still pretend it is `configure' which instantiates (i.e., don't # use $as_me), people would be surprised to read: # /* config.h. Generated by config.status. */ configure_input='Generated from '` $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' `' by configure.' if test x"$ac_file" != x-; then configure_input="$ac_file. $configure_input" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 $as_echo "$as_me: creating $ac_file" >&6;} fi # Neutralize special characters interpreted by sed in replacement strings. case $configure_input in #( *\&* | *\|* | *\\* ) ac_sed_conf_input=`$as_echo "$configure_input" | sed 's/[\\\\&|]/\\\\&/g'`;; #( *) ac_sed_conf_input=$configure_input;; esac case $ac_tag in *:-:* | *:-) cat >"$tmp/stdin" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; esac ;; esac ac_dir=`$as_dirname -- "$ac_file" || $as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$ac_file" : 'X\(//\)[^/]' \| \ X"$ac_file" : 'X\(//\)$' \| \ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$ac_file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` as_dir="$ac_dir"; as_fn_mkdir_p ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix case $ac_mode in :F) # # CONFIG_FILE # case $INSTALL in [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; esac _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # If the template does not know about datarootdir, expand it. # FIXME: This hack should be removed a few years after 2.60. ac_datarootdir_hack=; ac_datarootdir_seen= ac_sed_dataroot=' /datarootdir/ { p q } /@datadir@/p /@docdir@/p /@infodir@/p /@localedir@/p /@mandir@/p' case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in *datarootdir*) ac_datarootdir_seen=yes;; *@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 $as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_datarootdir_hack=' s&@datadir@&$datadir&g s&@docdir@&$docdir&g s&@infodir@&$infodir&g s&@localedir@&$localedir&g s&@mandir@&$mandir&g s&\\\${datarootdir}&$datarootdir&g' ;; esac _ACEOF # Neutralize VPATH when `$srcdir' = `.'. # Shell code in configure.ac might set extrasub. # FIXME: do we really want to maintain this feature? cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_sed_extra="$ac_vpsub $extrasub _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 :t /@[a-zA-Z_][a-zA-Z_0-9]*@/!b s|@configure_input@|$ac_sed_conf_input|;t t s&@top_builddir@&$ac_top_builddir_sub&;t t s&@top_build_prefix@&$ac_top_build_prefix&;t t s&@srcdir@&$ac_srcdir&;t t s&@abs_srcdir@&$ac_abs_srcdir&;t t s&@top_srcdir@&$ac_top_srcdir&;t t s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t s&@builddir@&$ac_builddir&;t t s&@abs_builddir@&$ac_abs_builddir&;t t s&@abs_top_builddir@&$ac_abs_top_builddir&;t t s&@INSTALL@&$ac_INSTALL&;t t $ac_datarootdir_hack " eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$tmp/subs.awk" >$tmp/out \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && { ac_out=`sed -n '/\${datarootdir}/p' "$tmp/out"`; test -n "$ac_out"; } && { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' "$tmp/out"`; test -z "$ac_out"; } && { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&5 $as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&2;} rm -f "$tmp/stdin" case $ac_file in -) cat "$tmp/out" && rm -f "$tmp/out";; *) rm -f "$ac_file" && mv "$tmp/out" "$ac_file";; esac \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; :H) # # CONFIG_HEADER # if test x"$ac_file" != x-; then { $as_echo "/* $configure_input */" \ && eval '$AWK -f "$tmp/defines.awk"' "$ac_file_inputs" } >"$tmp/config.h" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 if diff "$ac_file" "$tmp/config.h" >/dev/null 2>&1; then { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 $as_echo "$as_me: $ac_file is unchanged" >&6;} else rm -f "$ac_file" mv "$tmp/config.h" "$ac_file" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 fi else $as_echo "/* $configure_input */" \ && eval '$AWK -f "$tmp/defines.awk"' "$ac_file_inputs" \ || as_fn_error $? "could not create -" "$LINENO" 5 fi ;; esac done # for ac_tag as_fn_exit 0 _ACEOF ac_clean_files=$ac_clean_files_save test $ac_write_fail = 0 || as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 # configure is writing to config.log, and then calls config.status. # config.status does its own redirection, appending to config.log. # Unfortunately, on DOS this fails, as config.log is still kept open # by configure, so config.status won't be able to write to it; its # output is simply discarded. So we exec the FD to /dev/null, # effectively closing config.log, so it can be properly (re)opened and # appended to by config.status. When coming back to configure, we # need to make the FD available again. if test "$no_create" != yes; then ac_cs_success=: ac_config_status_args= test "$silent" = yes && ac_config_status_args="$ac_config_status_args --quiet" exec 5>/dev/null $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false exec 5>>config.log # Use ||, not &&, to avoid exiting from the if with $? = 1, which # would make configure fail if this is the last instruction. $ac_cs_success || as_fn_exit 1 fi if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} fi abcmidi/midicopy.h0000644000000000000000000000463611020033716013134 0ustar rootroot/* definitions for MIDI file writing code */ float mf_ticks2sec(); long mf_sec2ticks(); void mfwrite(); void mfread(); /* MIDI status commands most significant bit is 1 */ #define note_off 0x80 #define note_on 0x90 #define poly_aftertouch 0xa0 #define control_change 0xb0 #define program_chng 0xc0 #define channel_aftertouch 0xd0 #define pitch_wheel 0xe0 #define system_exclusive 0xf0 #define delay_packet (1111) /* 7 bit controllers */ #define damper_pedal 0x40 #define portamento 0x41 #define sostenuto 0x42 #define soft_pedal 0x43 #define general_4 0x44 #define hold_2 0x45 #define general_5 0x50 #define general_6 0x51 #define general_7 0x52 #define general_8 0x53 #define tremolo_depth 0x5c #define chorus_depth 0x5d #define detune 0x5e #define phaser_depth 0x5f /* parameter values */ #define data_inc 0x60 #define data_dec 0x61 /* parameter selection */ #define non_reg_lsb 0x62 #define non_reg_msb 0x63 #define reg_lsb 0x64 #define reg_msb 0x65 /* Standard MIDI Files meta event definitions */ #define meta_event 0xFF #define sequence_number 0x00 #define text_event 0x01 #define copyright_notice 0x02 #define sequence_name 0x03 #define instrument_name 0x04 #define lyric 0x05 #define marker 0x06 #define cue_point 0x07 #define channel_prefix 0x20 #define end_of_track 0x2f #define set_tempo 0x51 #define smpte_offset 0x54 #define time_signature 0x58 #define key_signature 0x59 #define sequencer_specific 0x74 /* Manufacturer's ID number */ #define Seq_Circuits (0x01) /* Sequential Circuits Inc. */ #define Big_Briar (0x02) /* Big Briar Inc. */ #define Octave (0x03) /* Octave/Plateau */ #define Moog (0x04) /* Moog Music */ #define Passport (0x05) /* Passport Designs */ #define Lexicon (0x06) /* Lexicon */ #define Tempi (0x20) /* Bon Tempi */ #define Siel (0x21) /* S.I.E.L. */ #define Kawai (0x41) #define Roland (0x42) #define Korg (0x42) #define Yamaha (0x43) /* miscellaneous definitions */ #define MThd 0x4d546864 #define MTrk 0x4d54726b #define lowerbyte(x) ((unsigned char)(x & 0xff)) #define upperbyte(x) ((unsigned char)((x & 0xff00)>>8)) abcmidi/yapstree.c0000644000000000000000000020545512622033430013152 0ustar rootroot/* * yaps - program to convert abc files to PostScript. * Copyright (C) 1999 James Allwright * e-mail: J.R.Allwright@westminster.ac.uk * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA * */ /* yapstree.c - back-end for abc parser. */ /* generates a data structure suitable for typeset music */ #define VERSION "1.63 November 15 2015 yaps" #include #ifdef USE_INDEX #define strchr index #endif /* for Microsoft VC 6++ or higher */ #ifdef _MSC_VER #define ANSILIBS #endif #ifdef ANSILIBS #include #include #include #else char* strchr(); #endif #include "abc.h" #include "parseabc.h" #include "parser2.h" #include "structs.h" #include "drawtune.h" extern void setscaling(char *s); extern void font_command(); extern void setup_fonts(); extern void printtune(struct tune *t); extern void set_keysig(struct key *k, struct key *newval); programname fileprogram = YAPS; extern int oldchordconvention; /* for handling +..+ chords */ struct voice* cv; struct tune thetune; char outputname[256]; char outputroot[256]; char matchstring[256]; int fileopen; int repcheck; int xinhead; int xinbody; int suppress; int debugging; int pagenumbering; int separate_voices; int print_xref; int landscape; int barnums,nnbars; extern int gchords_above; extern int decorators_passback[DECSIZE]; /* a kludge for passing information from the event_handle_instruction to parsenote in parseabc.c */ enum linestattype {fresh, midmusic, endmusicline, postfield}; enum linestattype linestat; int dummydecorator[DECSIZE]; /* used in event_chord */ void setfract(f, a, b) struct fract* f; int a, b; /* assign value to fraction */ { f->num = a; f->denom = b; } void reducef(f) struct fract* f; /* reducef fraction to smallest terms */ { int t, n, m; /* find HCF using Euclid's algorithm */ if (f->num > f->denom) { n = f->num; m = f->denom; } else { n = f->denom; m = f->num; }; while (m != 0) { t = n % m; n = m; m = t; }; f->num = f->num/n; f->denom = f->denom/n; } static struct fract* newfract(int a, int b) /* create an initialized fraction */ { struct fract* f; f = (struct fract*)checkmalloc(sizeof(struct fract)); f->num = a; f->denom = b; return(f); } static struct slurtie* newslurtie() /* create a new slur/tie data structure */ { struct slurtie* f; f = (struct slurtie*)checkmalloc(sizeof(struct slurtie)); f->begin = NULL; f->end = NULL; f->crossline = 0; return(f); } static struct atempo* newtempo(int count, int n, int m, int relative, char *pre, char *post) /* create an initialized tempo data structure */ { struct atempo* t; t = (struct atempo*)checkmalloc(sizeof(struct atempo)); t->count = count; t->basenote.num = n; t->basenote.denom = m; t->relative = relative; if (pre == NULL) { t->pre = NULL; } else { t->pre = addstring(pre); }; if (post == NULL) { t->post = NULL; } else { t->post = addstring(post); }; return(t); } static struct vertspacing* newvertspacing() /* create new vertspacing structure */ { struct vertspacing* p; p = (struct vertspacing*)checkmalloc(sizeof(struct vertspacing)); p->height = 0.0; p->descender = 0.0; p->yend = 0.0; p->yinstruct = 0.0; p->ygchord = 0.0; p->ywords = 0.0; return(p); } static struct tuple* newtuple(int n, int q, int r, int label) /* create tuple data structure */ { struct tuple* f; f = (struct tuple*)checkmalloc(sizeof(struct tuple)); f->n = n; f->q = q; f->r = r; f->label = label; f->beamed = 1; return(f); } static struct chord* newchord() /* create chord data structure */ { struct chord* f; f = (struct chord*)checkmalloc(sizeof(struct chord)); f->ytop = 0; f->ybot = 0; return(f); } struct aclef* newclef(enum cleftype t, int octave) /* create and initialize clef data structure */ { struct aclef* f; f = (struct aclef*)checkmalloc(sizeof(struct aclef)); f->type = t; f->octave = octave; return(f); } struct key* newkey(char* name, int sharps, char accidental[], int mult[]) /* create and initialize key signature */ { struct key* k; int i; k = (struct key*)checkmalloc(sizeof(struct key)); k->name = addstring(name); k->sharps = sharps; for (i=0; i<7; i++) { k->map[i] = accidental[i]; k->mult[i] = mult[i]; }; return(k); } void init_llist(struct llist* l) /* initialize a linked list */ { l->first = NULL; l->last = NULL; l->place = NULL; } void addtolist(struct llist* p, void* item) /* append an item to a linked list */ { struct el* x; x = (struct el*)checkmalloc(sizeof(struct el)); x->next = NULL; x->datum = item; if (p->first == NULL) { p->first = x; p->last = x; } else { p->last->next = x; p->last = x; }; } void* firstitem(struct llist* p) /* find the first item in the list */ /* also initialize for a traversal using nextitem() */ { if (p == NULL) { return(NULL); }; p->place = p->first; if (p->place == NULL) { return(NULL); } else { return(p->place->datum); }; } void* nextitem(struct llist* p) /* return 'next' item in the list. Successive calls return successive */ /* items or NULL after the end of the list has been reached. firstitem() */ /* must be called prior to the first call to nextitem() */ { if (p->place == NULL) { return(NULL); } else { p->place = p->place->next; if (p->place == NULL) { return(NULL); } else { return(p->place->datum); }; }; } void freellist(struct llist* l) /* frees up all dynamically allocated memory used to build the linked list */ { void* p; struct el* e; struct el* olde; /* printf("freellist\n"); */ if (l != NULL) { p = firstitem(l); while (p != NULL) { free(p); p = nextitem(l); }; e = l->first; while (e != NULL) { olde = e; e = e->next; free(olde); }; init_llist(l); }; } static void closebeam(struct voice* v) /* called after a run of notes to be beamed together */ { struct note* n; struct feature* ft; int stemup; int ingrace; if (cv->tuplenotes > 0) { cv->thistuple->beamed = 0; }; if (v->beamroot == v->beamend) { ft = v->beamroot; n = ft->item; n->beaming = single; v->beamroot = NULL; return; }; if (v->beammax + v->beammin > 2*4) { stemup = 0; } else { stemup = 1; }; ft = v->beamroot; ingrace = 0; while ((ft != NULL) && (ft != v->beamend)) { switch (ft->type) { case NOTE: if (ingrace == 0) { n = ft->item; n->stemup = stemup; }; break; case GRACEON: ingrace = 1; break; case GRACEOFF: ingrace = 0; break; default: break; }; ft = ft->next; }; if (ft == v->beamend) { n = ft->item; n->stemup = stemup; n->beaming = endbeam; } else { printf("closebeam: internal data error\n"); exit(1); }; v->beamroot = NULL; } static void closegracebeam(struct voice* v) /* called after a run of grace notes to be beamed together */ { struct note* n; struct feature* ft; ft = v->gracebeamend; if (ft == NULL) { event_error("Missing grace notes"); } else { n = ft->item; if (v->gracebeamroot == v->gracebeamend) { n->beaming = single; } else { n->beaming = endbeam; }; }; } static void insertnote(struct feature* chordplace, struct feature* newfeature) /* place NOTE in decreasing pitch order within chord */ { struct note* n; struct note* newnote; struct feature* f; struct feature* previous; int foundplace; newnote = newfeature->item; previous = chordplace; f = chordplace->next; foundplace = 0; n = NULL; while ((f != NULL)&&(f->type==NOTE)&&(foundplace == 0)) { n = f->item; if (newnote->y > n->y) { foundplace = 1; } else { previous = f; f = f->next; }; }; /* printvoiceline in drawtune.c expects the gchord or * instructions to be associated with the first note in * chord. If the notes are reordered then we need * to move these fields. * if previous == chordplace then move n->gchords and * n->instructions to newnote->gchords and newnote->instructions */ if (previous == chordplace && n != NULL) { newnote->gchords = n->gchords; newnote->instructions = n->instructions; n->gchords = NULL; n->instructions = NULL; } newfeature->next = previous->next; previous->next = newfeature; if (newfeature->next == NULL) { cv->last = newfeature; }; } static void beamitem(featuretype mytype, void* newitem, struct feature* x) /* This routine is responsible for working out which notes are to be */ /* beamed together and recording this in the note structure record */ { struct note* n; /* deal with beaming here */ if (cv->ingrace) { if (mytype == NOTE) { n = newitem; n->stemup = 1; if (cv->gracebeamroot == NULL) { cv->gracebeamroot = x; cv->gracebeamend = x; n->beaming = startbeam; } else { cv->gracebeamend = x; n->beaming = midbeam; }; }; } else { if (cv->beamroot != NULL) { switch (mytype) { case NOTE: n = newitem; if (n->base_exp >= -2) { n->beaming = single; closebeam(cv); } else { /* extend beam */ if (n->y > cv->beammax) { cv->beammax = n->y; }; if (n->y < cv->beammin) { cv->beammin = n->y; }; cv->beamend = x; n->beaming = midbeam; }; break; case KEY: case REST: case NOBEAM: case SINGLE_BAR: case DOUBLE_BAR: case BAR_REP: case REP_BAR: case BAR1: case REP_BAR2: case DOUBLE_REP: case THICK_THIN: case THIN_THICK: case TUPLE: case MUSICSTOP: /* closebeam */ closebeam(cv); break; default: break; }; } else { if (mytype == NOTE) { n = newitem; if (n->base_exp >= -2) { n->beaming = single; } else { n->beaming = startbeam; cv->beammax = n->y; cv->beammin = n->y; cv->beamroot = x; cv->beamend = x; }; }; }; }; } static struct feature* addfeature(featuretype mytype, void* newitem) /* append a new data element to the linked list for the current voice */ /* The element can be a note or lots of other things */ { struct voice* p; struct feature* x; p = cv; /* printf("in addfeature type=%d\n", mytype); */ if (cv == NULL) { printf("ERROR: no current voice in addfeature type=%d\n", mytype); printf("xinhead = %d xinbody = %d\n", xinhead, xinbody); exit(0); }; x = (struct feature*)checkmalloc(sizeof(struct feature)); x->next = NULL; x->type = mytype; x->item = newitem; x->xleft = 0; x->xright = 0; x->yup = 0; x->ydown = 0; if (cv->first == NULL) { cv->first = x; cv->last = x; beamitem(mytype, newitem, x); } else { if ((cv->last == NULL)||(cv->last->next != NULL)) { printf("expecting NULL at list end!\n"); exit(0); }; if ((cv->inchord)&&(mytype==NOTE)) { insertnote(cv->chordplace, x); } else { cv->last->next = x; cv->last = x; beamitem(mytype, newitem, x); }; }; return(x); } struct llist* newlist() /* create and initialize a new linked list */ { struct llist* l; l = (struct llist*)checkmalloc(sizeof(struct llist)); init_llist(l); return(l); } static int notenum(int octave, char ch, enum cleftype clef, int clefoctave) /* converts note to number for stave position */ /* note E is zero (bottom line of stave) */ { int n; n = 5 + (7 + ch -'c')%7 + 7*(octave-1); switch (clef) { case treble: break; case soprano: n = n + 2; break; case mezzo: n = n + 4; break; case alto: n = n + 6; break; case tenor: n = n + 8; break; case baritone: n = n + 10; break; case bass: n = n + 12; break; case noclef: break; }; switch (clefoctave) { case -22: n = n + 21; break; case -15: n = n + 14; break; case -8: n = n + 7; break; case 8: n = n - 7; break; case 15: n = n - 14; break; case 22: n = n - 21; break; default: break; }; return(n); } int count_dots(int *base, int *base_exp, int n, int m) /* convert fraction to 2^base_exp followed by dots */ /* previously used 1/base instead of 2^base_exp */ /* -1 indicates a note value which is impossible to represent */ { int dots; int start; int a, b; *base = 1; /* set default value if we fail */ *base_exp = 0; if ((n<1)||(m<1)) { return(-1); }; /* check denominator is power of 2 */ a = m; while (a>1) { if (a%2 == 1) { return(-1); }; a = a/2; }; dots = 0; start = m; while (start < n) { start = start*2; *base_exp = *base_exp + 1; }; while (start > n) { start = start/2; *base_exp = *base_exp - 1; }; if (start == 0) { printf("Problem with %d / %d\n", n, m); exit(0); }; *base = m/start; a = n - start; b = start; while (a>0) { dots = dots + 1; b = b/2; a = a - b; if (a< 0) { return(-1); }; }; return(dots); } static char* decstring(int decorators[]) /* creates a string of decorators (ornament, staccato, roll, up-bow etc.) */ /* from a boolean array */ { int i, j; char decs[DECSIZE+1]; j = 0; for (i=0; ilen, a, b); reducef(&n->len); n->dots = count_dots(&n->base, &n->base_exp, n->len.num, n->len.denom); /* if (n->dots == -1) { event_error("Illegal note length"); }; */ n->accents = decstring(decorators); n->accidental = xaccidental; n->acc_offset = 0; n->fliphead = 0; n->mult = xmult; n->octave = xoctave; n->pitch = xnote; n->y = notenum(xoctave, xnote, cv->clef->type, cv->clef->octave); if (n->y < 4) { n->stemup = 1; } else { n->stemup = 0; }; n->stemlength = 0.0; n->syllables = NULL; if (cv->ingrace) { n->gchords = NULL; n->instructions = NULL; } else { n->gchords = cv->gchords_pending; cv->gchords_pending = NULL; n->instructions = cv->instructions_pending; cv->instructions_pending = NULL; }; return(n); } static struct rest* newrest(int a, int b, int multi) /* create and set up a new rest structure */ { struct rest* n; n = (struct rest*)checkmalloc(sizeof(struct rest)); setfract(&n->len, a, b); n->dots = count_dots(&n->base, &n->base_exp, a, b); if (n->dots == -1) { event_error("Illegal rest length"); }; n->multibar = multi; if (cv->ingrace) { n->gchords = NULL; n->instructions = NULL; } else { n->gchords = cv->gchords_pending; cv->gchords_pending = NULL; n->instructions = cv->instructions_pending; cv->instructions_pending = NULL; }; return(n); } static void addunits(f, n, m) struct fract* f; int n, m; /* add n/m to fraction pointed to by f */ { f->num = n*f->denom*(cv->unitlen.num) + f->num*(m*cv->unitlen.denom); f->denom = (m*cv->unitlen.denom)*f->denom; reducef(f); } static void addfractions(f,n,m) struct fract* f; int n,m; { f->num = n*f->denom + f->num*m; f->denom = m*f->denom; reducef(f); } static struct voice* newvoice(int n) /* create and set up a new voice data structure */ { struct voice* v; v = (struct voice*)checkmalloc(sizeof(struct voice)); v->first = NULL; v->last = NULL; v->voiceno = n; v->octaveshift = thetune.octaveshift; setfract(&v->unitlen, thetune.unitlen.num, thetune.unitlen.denom); v->changetime = 0; v->inslur = 0; v->ingrace = 0; v->inchord = 0; v->expect_repeat = 0; v->tuplenotes = 0; v->thistuple = NULL; v->tuple_count = 0; v->brokenpending = -1; v->tiespending = 0; v->slurpending = 0; v->slurcount = 0; v->barno = 0; v->barchecking = thetune.barchecking; setfract(&v->barlen, thetune.meter.num, thetune.meter.denom); v->clef = newclef(thetune.clef.type, thetune.clef.octave); if (thetune.keysig == NULL) { printf("Trying to set up voice with no key signature\n"); exit(0); } else { v->keysig = newkey(thetune.keysig->name, thetune.keysig->sharps, thetune.keysig->map, thetune.keysig->mult); }; v->tempo = NULL; setfract(&v->barcount, 0, 1); setfract(&v->meter, thetune.meter.num, thetune.meter.denom); v->lastnote = NULL; v->laststart = NULL; v->lastend = NULL; v->line = header; v->thisstart = NULL; v->thisend = NULL; v->gchords_pending = NULL; v->instructions_pending = NULL; v->beamed_tuple_pending = 0; v->linestart = NULL; v->lineend = NULL; v->more_lyrics = 0; v->lyric_errors = 0; v->thischord = NULL; v->chordplace = NULL; v->beamroot = NULL; v->beamend = NULL; v->gracebeamroot = NULL; v->gracebeamend = NULL; return(v); } static void setvoice(int n) /* set current voice to voice n. If voice n does not exist, create it */ { struct voice* v; struct el* l; int done; if (thetune.voices.first == NULL) { cv = newvoice(n); v = cv; addtolist(&thetune.voices, (void*)v); } else { l = thetune.voices.first; done = 0; while ((done == 0) && (l != NULL)) { if (((struct voice*)l->datum)->voiceno == n) { done = 1; cv = (struct voice*)l->datum; } else { l = l->next; }; }; if (done == 0) { cv = newvoice(n); v = cv; addtolist(&thetune.voices, (void*)v); }; }; } static void init_tune(struct tune* t, int x) /* initialize tune structure */ { t->no = x; t->octaveshift = 0; init_llist(&t->title); t->composer = NULL; t->origin = NULL; t->parts = NULL; init_llist(&t->notes); init_llist(&t->voices); setfract(&t->meter, 0, 1); setfract(&t->unitlen, 0, 1); t->cv = NULL; t->keysig = NULL; t->clef.type = treble; t->clef.octave = 0; t->tempo = NULL; init_llist(&t->words); }; static void freekey(struct key* k) /* free up memory allocated for key data structure */ { if (k != NULL) { if (k->name != NULL) { free(k->name); }; free(k); }; } static void freetempo(struct atempo *t) /* free up memory allocated for temp data structure */ { if (t->pre != NULL) { free(t->pre); }; if (t->post != NULL) { free(t->post); }; } static void freefeature(void* item, featuretype type) /* free memory allocated for feature in voice */ { struct note *n; struct rest *r; switch(type) { case NOTE: n = item; if (n->accents != NULL) { free(n->accents); }; if (n->syllables != NULL) { freellist(n->syllables); free(n->syllables); }; if (n->gchords != NULL) { freellist(n->gchords); free(n->gchords); }; if (n->instructions != NULL) { freellist(n->instructions); free(n->instructions); }; free(n); break; case REST: r = item; if (r->gchords != NULL) { freellist(r->gchords); free(r->gchords); }; if (r->instructions != NULL) { freellist(r->instructions); free(r->instructions); }; free(r); break; case KEY: freekey(item); break; case TEMPO: freetempo(item); break; case CLEF: case TIME: case PART: case CHORDON: case TUPLE: case SLUR_ON: case TIE: case PLAY_ON_REP: case LEFT_TEXT: case PRINTLINE: if (item != NULL) { free(item); }; break; default: break; }; } static void freevoice(struct voice* v) /* free up memory allocated for voice data structure and voice data */ { struct feature* ft; struct feature* oldft; ft = v->first; while (ft != NULL) { freefeature(ft->item, ft->type); oldft = ft; ft = ft->next; free(oldft); }; if (v->keysig != NULL) { freekey(v->keysig); v->keysig = NULL; }; if (v->tempo != NULL) { freetempo(v->tempo); v->tempo = NULL; }; if (v->clef != NULL) { free(v->clef); }; v->clef = NULL; } static void freetune(struct tune* t) /* free up all dynamically allocated memory associated with tune */ { struct voice* v; if (t->composer != NULL) { free(t->composer); t->composer = NULL; }; if (t->origin != NULL) { free(t->origin); t->origin = NULL; }; if (t->parts != NULL) { free(t->parts); t->parts = NULL; }; freellist(&t->title); freellist(&t->notes); if (t->keysig != NULL) { freekey(t->keysig); t->keysig = NULL; }; if (t->tempo != NULL) { freetempo(t->tempo); t->tempo = NULL; }; v = firstitem(&t->voices); while (v != NULL) { freevoice(v); v = nextitem(&t->voices); }; freellist(&t->voices); freellist(&t->words); } static int checkmatch(int refno) /* compares current reference number against list of numbers */ /* following -e argument */ /* returns 1 if tune has been selected and 0 otherwise */ { int select; int n1, n2; char* place; place = matchstring; if (strlen(matchstring)==0) { select = 1; } else { select = 0; while ((select==0)&&(*place >= '0')&&(*place <='9')) { n1 = readnump(&place); if (n1 == refno) { select = 1; } else { if (*place == ',') { place = place+1; } else { if (*place == '-') { place = place+1; n2 = readnump(&place); if ((refno >= n1)&&(refno <= n2)) { select = 1; } else { if (*place == ',') { place = place+1; }; }; }; }; }; }; if ((select==0)&&(*place != '\0')) { event_warning("Number list after -e not fully parsed"); }; }; return(select); } void event_init(argc, argv, filename) int argc; char* argv[]; char** filename; /* initialization routine - called once at the start of the program */ /* interprets the parameters in argv */ { char* place; int filearg; int refmatch; int papsize, margins, newscale; int ier; int j; if (getarg("-ver",argc, argv) != -1) { printf("%s\n",VERSION); exit(0); } if (getarg("-d", argc, argv) != -1) { debugging = 1; } else { debugging = 0; }; if (getarg("-E", argc, argv) != -1) { eps_out = 1; } else { eps_out = 0; }; if (getarg("-OCC",argc,argv) != -1) oldchordconvention=1; if (getarg("-V", argc, argv) != -1) { separate_voices = 1; } else { separate_voices = 0; }; if (getarg("-x", argc, argv) != -1) { print_xref = 1; } else { print_xref = 0; }; if (getarg("-N", argc, argv) != -1) { pagenumbering = 1; } else { pagenumbering = 0; }; if (getarg("-l", argc, argv) != -1) { landscape = 1; } else { landscape = 0; }; newscale = getarg("-s", argc, argv); if ((newscale != -1) && (argc >= newscale+1)) { /* [SS] 2015-02-22 */ setscaling(argv[newscale]); } else { setscaling(""); }; margins = getarg("-M", argc, argv); if ((margins != -1) && (argc >= margins)) { setmargins(argv[margins]); } else { setmargins(""); }; papsize = getarg("-P", argc, argv); if ((papsize != -1) && (argc >= papsize)) { setpagesize(argv[papsize]); } else { setpagesize(""); }; barnums = getarg("-k",argc,argv); ier = 0; if ((barnums != -1) && (argc > barnums)) ier = sscanf(argv[barnums],"%d",&nnbars); if ((barnums != -1) && (ier <1)) nnbars = 1; refmatch = getarg("-e", argc, argv); if (refmatch == -1) { *matchstring = '\0'; } else { if (strlen(argv[refmatch]) < 255) { strcpy(matchstring, argv[refmatch]); } else { event_error("Exceeded character limit for -e string"); exit(1); }; }; if ((getarg("-h", argc, argv) != -1) || (argc < 2)) { printf("yaps version %s\n",VERSION); printf("Usage: yaps []\n"); printf(" possible options are -\n"); printf(" -ver :prints version number and exits\n"); printf(" -d : debug - display data structure\n"); printf(" -e : draw tunes with reference numbers in list\n"); printf(" list is comma-separated and may contain ranges\n"); printf(" but no spaces e.g. 1,3,7-20\n"); printf(" -E : generate Encapsulated PostScript\n"); printf(" -l : landscape mode\n"); printf(" -M XXXxYYY : set margin sizes in points\n"); printf(" 28.3 points = 1cm, 72 points = 1 inch\n"); printf(" -N : add page numbering\n"); printf(" -k [nn] : number every nn bars\n"); printf(" -o : specify output file\n"); printf(" -P ss : paper size; 0 is A4, 1 is US Letter\n"); printf(" or XXXxYYY to set size in points\n"); printf(" -s XX : scaling factor (default is 0.7)\n"); printf(" -V : separate voices in multi-voice tune\n"); printf(" -x : print tune number in X: field\n"); printf(" -OCC : old chord convention (eg. +CE+)\n"); printf("Takes an abc music file and converts it to PostScript.\n"); printf("If no output filename is given, then by default it is\n"); printf("the input filename but with extension .ps .\n"); exit(0); } else { *filename = argv[1]; }; fileopen = 0; filearg = getarg("-o", argc, argv); if (filearg != -1) { /*strcpy(outputname, argv[filearg]); security risk buffer overflow */ strncpy(outputname, argv[filearg],256); } else { /* strcpy(outputname, argv[1]); security risk: buffer overflow */ strncpy(outputname, argv[1],256); place = strchr(outputname, '.'); if (place == NULL) { strcat(outputname, ".ps"); } else { strcpy(place, ".ps"); }; if (strcmp(argv[1], outputname)==0) { printf("argument must be abc file, not PostScript file\n"); exit(1); }; }; /* create filename root for EPS output */ strcpy(outputroot, outputname); place = strchr(outputroot, '.'); if (place != NULL) { *place = '\0'; }; xinbody =0; xinhead = 0; suppress = 0; init_tune(&thetune, -1); setup_fonts(); /* open_output_file(outputname); */ for (j=0;jinchord) { event_error("incomplete chord at end of voice"); v->inchord = 0; }; if (v->brokenpending != -1) { event_error("incomplete broken rhythm at end of voice"); v->brokenpending = -1; }; if ((v->slurcount > 0)||(v->slurpending)) { event_error("incomplete slur at end of voice"); v->slurcount = 0; v->slurpending = 0; }; if (v->tiespending) { event_error("incomplete ties at end of voice"); v->tiespending = 0; }; if (v->gchords_pending != NULL) { freellist(v->gchords_pending); free(v->gchords_pending); v->gchords_pending = NULL; }; if (v->instructions_pending != NULL) { freellist(v->instructions_pending); free(v->instructions_pending); v->instructions_pending = NULL; }; if (v->tuplenotes > 0) { event_error("incomplete tuple at end of voice"); v->tuplenotes = 0; }; } static void check_tune_end(struct tune* t) /* check that all voices have been completed properly */ { struct voice* v; v = firstitem(&t->voices); while (v != NULL) { check_voice_end(v); v = nextitem(&t->voices); }; } void event_eof() /* end of input file has been encountered */ { if (xinbody) { check_tune_end(&thetune); printtune(&thetune); }; freetune(&thetune); close_output_file(); } void event_blankline() /* A blank line has been encountered */ { if (xinbody) { check_tune_end(&thetune); printtune(&thetune); }; freetune(&thetune); xinbody = 0; xinhead = 0; suppress = 0; parseroff(); } void event_text(p) /* Text outside an abc tune has been encountered */ char *p; { } void event_x_reserved(p) char p; { } void event_abbreviation(symbol, string, container) /* abbreviation declaratiion - handled by parser. Ignore it here */ char symbol; char *string; char container; { } void event_acciaccatura() { /* does nothing but outputs a / in toabc.c */ return; } /* [SS] 2015-03-23 */ void event_start_extended_overlay() { event_error("extended overlay not implemented in yaps"); } void event_stop_extended_overlay() { event_error("extended overlay not implemented in yaps"); } void event_split_voice() { /* [SS] 2015-11-15 * changed (void*) to (int *) */ addfeature(SPLITVOICE, (int *) lineno); event_error("voice split not implemented in yaps"); } void event_tex(s) char *s; /* A TeX command has been found in the abc */ { } void event_linebreak() /* A linebreak has been encountered */ { /* [SS] 2015-11-15 * changed (void*) to (int *) */ if (xinbody) { addfeature(LINENUM, (int *)lineno); }; } static void tidy_ties() /* create CLOSE_TIE features for ties straddling two lines of music */ /* CLOSE_TIE appears in the new music line */ { struct feature* ft; struct slurtie* s; int i; for (i=0; itiespending; i++) { ft = cv->tie_place[i]; /* pointer to TIE feature */ s = ft->item; addfeature(CLOSE_TIE, s); }; } void event_startmusicline() /* We are at the start of a line of abc notes */ { cv->linestart = addfeature(MUSICLINE, (void*)NULL); if (cv->more_lyrics != 0) { event_error("Missing continuation w: field"); cv->more_lyrics = 0; }; if ((cv->line == header) || (cv->line == newline)) { addfeature(CLEF, newclef(cv->clef->type, cv->clef->octave)); addfeature(KEY, newkey(cv->keysig->name, cv->keysig->sharps, cv->keysig->map, cv->keysig->mult)); if ((cv->line == header)||(cv->changetime)) { addfeature(TIME, newfract(cv->meter.num, cv->meter.denom)); cv->changetime = 0; }; cv->line = midline; tidy_ties(); }; cv->lineend = NULL; } static void divide_ties() /* mark unresolved ties and slurs as straddling two lines of music */ { struct feature* ft; struct slurtie* s; int i; for (i=0; itiespending; i++) { ft = cv->tie_place[i]; /* pointer to TIE feature */ s = ft->item; s->crossline = 1; }; for (i=0; islurcount; i++) { s = cv->slur_place[i]; s->crossline = 1; }; } void event_endmusicline(endchar) char endchar; /* We are at the end of a line of abc notes */ { cv->lineend = addfeature(MUSICSTOP, (void*)NULL); if ((endchar == ' ') || (endchar == '!')) { addfeature(PRINTLINE, newvertspacing()); cv->line = newline; divide_ties(); }; } void event_error(s) char *s; /* report any error message */ { printf("Error in line %d : %s\n", lineno, s); } void event_warning(s) char *s; /* report any warning message */ { printf("Warning in line %d : %s\n", lineno, s); } void event_comment(s) char *s; /* A comment has been encountered in the input */ { } int make_open() /* called as fileopen = make_open() */ /* if file is not already open, open it and set fileopen */ { if (fileopen == 0) { open_output_file(outputname, (void*)NULL); fileopen = 1; }; return(1); } void event_specific(p, str) char *p; /* first word after %% */ char *str; /* string following first word */ /* The special comment %% has been found */ /* abc2midi uses it for the %%MIDI commands */ /* yaps implements some of the abc2ps commands */ { char* s; double vspace; char units[80]; int count; /* ensure file has been opened since most commands require this */ if (!eps_out) { fileopen = make_open(); }; s = str; skipspace(&s); if (strcmp(p, "newpage") == 0) { if (xinbody == 0) { if (fileopen) { newpage(); }; } else { addfeature(NEWPAGE, (void*)NULL); }; }; if (strcmp(p, "text") == 0) { if (xinbody == 0) { if (fileopen) { lefttext(s); }; } else { addfeature(LEFT_TEXT, addstring(s)); }; }; if ((strcmp(p, "centre") == 0) || (strcmp(p, "center") == 0)) { if (xinbody == 0) { if (fileopen) { centretext(s); }; } else { addfeature(CENTRE_TEXT, addstring(s)); }; }; if (strcmp(p, "vskip") == 0) { count = sscanf(s, "%lf%s", &vspace, units); if (count > 0) { if ((count >= 2) && (strncmp(units, "cm", 2) == 0)) { vspace = vspace*28.3; }; if ((count >= 2) && (strncmp(units, "in", 2) == 0)) { vspace = vspace*72.0 ; }; if (xinbody == 0) { if (fileopen) { vskip(vspace); }; } else { addfeature(VSKIP, (int*)((int)vspace)); }; }; }; if (strcmp(p, "chordsabove") == 0) { gchords_above = 1; }; if (strcmp(p, "chordsbelow") == 0) { gchords_above = 0; }; /* look for font-related commands */ font_command(p, s); } void event_field(k, f) char k; char *f; /* A field line has been encountered in the input abc */ { switch (k) { case 'T': if (debugging) { printf("T:%s\n", f); }; addtolist(&thetune.title, addstring(f)); break; case 'C': if (thetune.composer != NULL) { event_error("More than one C: field in tune"); } else { thetune.composer = addstring(f); }; break; case 'O': if (thetune.origin != NULL) { event_error("More than one O: field in tune"); } else { thetune.origin = addstring(f); }; break; case 'W': if (debugging) { printf("W:%s\n", f); }; addtolist(&thetune.words, addstring(f)); break; case 'N': addtolist(&thetune.notes, addstring(f)); break; default: break; }; } struct feature* findbar(struct feature* wordplace, int* errors) /* hunts through voice to find next bar data structure */ { struct feature* ft; ft = wordplace; while ((ft != NULL) && (ft != cv->lineend) && (ft->type != MUSICSTOP) && (ft->type != SINGLE_BAR) && (ft->type != DOUBLE_BAR) && (ft->type != BAR_REP) && (ft->type != REP_BAR) && (ft->type != DOUBLE_REP) && (ft->type != THICK_THIN) && (ft->type != THIN_THICK) && (ft->type != BAR1) && (ft->type != REP_BAR2)) { ft = ft->next; }; if ((ft == NULL) || (ft == cv->lineend) || (ft->type == MUSICSTOP)) { *errors = *errors + 1; } else { ft = ft->next; }; return(ft); } struct feature* apply_syll(char* s, struct feature* wordplace, int* errors) /* attaches a syllable from the lyrics to the appropriate note */ { struct note* n; struct feature* ft; int inchord; ft = wordplace; inchord = 0; while ((ft != NULL) && (ft != cv->lineend) && (ft->type != NOTE)) { if (ft->type == CHORDON) { inchord = 1; }; ft = ft->next; /* skip over any grace notes */ if ((ft != NULL) && (ft->type == GRACEON)) { while ((ft != NULL) && (ft != cv->lineend) && (ft->type != GRACEOFF)) { ft = ft->next; }; }; }; if ((ft == NULL) || (ft == cv->lineend)) { *errors = *errors + 1; return(ft); }; if (ft->type == NOTE) { n = ft->item; if (n->syllables == NULL) { n->syllables = newlist(); }; /* if (strlen(s) < 80) { ISOdecode(s, isocode); addtolist(n->syllables, addstring(isocode)); } else { */ addtolist(n->syllables, addstring(s)); /* }; */ }; ft = ft->next; /* skip over any chord */ if (inchord) { while ((ft != NULL) && (ft->type != CHORDOFF) && (ft != cv->lineend)) { ft = ft->next; }; }; return(ft); } void event_words(p, continuation) char* p; int continuation; /* A line of lyrics (w: ) has been encountered in the abc */ { struct vstring syll; char* q; struct feature* wordplace; unsigned char ch; int errors; if (!xinbody) { if (!suppress) { event_error("w: field outside tune body"); }; return; }; wordplace = cv->linestart; if (cv->more_lyrics) { errors = cv->lyric_errors; } else { errors = 0; }; if (wordplace == NULL) { event_error("No notes to match words"); return; }; initvstring(&syll); q = p; skipspace(&q); while (*q != '\0') { clearvstring(&syll); ch = *q; while(ch=='|') { wordplace = findbar(wordplace, &errors); q++; ch = *q; }; while (((ch>127)||isalnum(ch)||ispunct(ch))&& (ch != '_')&&(ch != '-')&&(ch != '*')&& (ch != '|')) { if (ch == '~') { ch = ' '; }; if ((ch == '\\') && (*(q+1)=='-')) { ch = '-'; q++; }; /* syllable[i] = ch; */ addch(ch, &syll); q++; ch = *q; }; skipspace(&q); if (ch == '-') { addch(ch, &syll); while (isspace(ch)||(ch=='-')) { q++; ch = *q; }; }; if (syll.len > 0) { wordplace = apply_syll(syll.st, wordplace, &errors); } else { if (ch=='_') { clearvstring(&syll); addch('_', &syll); wordplace = apply_syll(syll.st, wordplace, &errors); q++; ch = *q; }; if (ch=='*') { clearvstring(&syll); addch(' ', &syll); wordplace = apply_syll(syll.st, wordplace, &errors); q++; ch = *q; }; }; }; if (continuation) { cv->more_lyrics = 1; cv->lyric_errors = errors; cv->linestart = wordplace; } else { cv->more_lyrics = 0; if (errors > 0) { event_error("Lyric line too long for music"); } else { clearvstring(&syll); wordplace = apply_syll(syll.st, wordplace, &errors); if (errors == 0) { event_error("Lyric line too short for music"); }; }; }; freevstring(&syll); } /* [SS] 2014-08-16 */ void appendfield (morewords) char *morewords; { printf("appendfield not implemented here\n"); } void event_part(s) char* s; /* A part field (P: ) has been encountered in the abc */ { char label[200]; /* [SS] 2010-12-12 */ if (xinhead) { if (thetune.parts != NULL) { event_error("Multiple P: fields in header"); } else { thetune.parts = addstring(s); }; }; if (xinbody) { /* addfeature(PART, addstring(s)); */ /* PART is handled like an instruction */ if (cv->instructions_pending == NULL) { cv->instructions_pending = newlist(); }; sprintf(label, ":p%s", s); addtolist(cv->instructions_pending, addstring(label)); }; } void event_voice(n, s, vp) int n; char *s; struct voice_params *vp; /* A voice field (V: ) has been encountered */ { if (xinbody) { setvoice(n); } else { if (!suppress) { event_error("V: field outside tune body"); }; }; } void event_length(n) int n; /* A length field (L: ) has been encountered */ { if (xinhead) { setfract(&thetune.unitlen, 1, n); } else { if (xinbody) { setfract(&cv->unitlen, 1, n); } else { if (!suppress) { event_warning("L: field outside tune ignored"); }; }; }; } void event_refno(n) int n; /* A reference field (X: ) has been encountered. This indicates the start */ /* of a new tune */ { if (xinhead) { event_error("incomplete tune"); }; if (xinbody) { check_tune_end(&thetune); printtune(&thetune); }; freetune(&thetune); xinbody = 0; xinhead = 0; suppress = 0; parseroff(); if (debugging) { printf("X:%d\n", n); }; if (checkmatch(n)) { parseron(); /* fileopen = make_open(); */ xinhead = 1; xinbody = 0; init_tune(&thetune, n); } else { suppress = 1; }; } void event_tempo(n, a, b, relative, pre, post) int n, a, b; int relative; char *pre; /* text before tempo */ char *post; /* text after tempo */ /* A tempo field Q: has been encountered in the abc */ /* Q:a/b=N will have relative = 0 */ /* Q:N will have a=0 and b=0 */ /* Q:Ca/b = N will have relative = 1 */ { if (xinhead) { thetune.tempo = newtempo(n, a, b, relative, pre, post); } else { if (xinbody) { if ((a == 0) && (b == 0)) { addfeature(TEMPO, newtempo(n, cv->unitlen.num, cv->unitlen.denom, 0, pre, post)); } else { addfeature(TEMPO, newtempo(n, a, b, relative, pre, post)); }; } else { if (!suppress) { event_warning("Q: field outside tune ignored"); }; }; }; } void event_timesig(n, m, checkbars) int n, m, checkbars; /* A time signature (M: ) has been encountered in the abc */ { if (xinhead) { setfract(&thetune.meter, n, m); thetune.barchecking = checkbars; } else { if (xinbody) { if (checkbars == 1) { addfeature(TIME, newfract(n,m)); setfract(&cv->meter, n, m); setfract(&cv->barlen, n, m); if (cv->line != midline) { cv->changetime = 1; }; cv->barchecking = 1; } else { cv->barchecking = 0; }; } else { if (!suppress) { event_warning("M: field outside tune ignored"); }; }; }; } enum cleftype findclef(clefstr, oct) char* clefstr; int* oct; /* converts a clef name string to an enumerated type */ /* also looks for +8 +15 +22 -8 -15 -22 octave shift */ { enum cleftype type; char* p; int interval; type = noclef; p = clefstr; if (strncmp(clefstr, "treble", 6)==0) { type = treble; p = p + 6; }; if (strncmp(clefstr, "bass", 4)==0) { type = bass; p = p + 4; }; if (strncmp(clefstr, "baritone", 8)==0) { type = baritone; p = p + 8; }; if (strncmp(clefstr, "tenor", 5)==0) { type = tenor; p = p + 5; }; if (strncmp(clefstr, "alto", 4)==0) { type = alto; p = p + 4; }; if (strncmp(clefstr, "mezzo", 5)==0) { type = mezzo; p = p + 5; }; if (strncmp(clefstr, "mezzo-soprano", 13)==0) { type = mezzo; p = p + 13; }; if (strncmp(clefstr, "soprano", 7)==0) { type = soprano; p = p + 7; }; interval = 0; if ((type != noclef) && ((*p == '+') || (*p == '-'))) { sscanf(p+1, "%d", &interval); if ((interval == 8) || (interval == 15) || (interval == 22)) { if (*p == '-') { interval = -interval; }; } else { interval = 0; }; }; *oct = interval; return(type); } void event_clef(char* clefstr) /* a clef has been encountered in the abc */ { enum cleftype clef; int num; clef = findclef(clefstr, &num); if (xinbody) { cv->clef->type = clef; cv->clef->octave = num; addfeature(CLEF, newclef(clef, num)); }; if ((xinhead) && (!xinbody)) { if (clef != noclef) { thetune.clef.type = clef; thetune.clef.octave = num; }; }; } void setmap(sf, map, mult) /* work out accidentals to be applied to each note */ int sf; /* number of sharps in key signature -7 to +7 */ char map[7]; int mult[7]; { int j; for (j=0; j<7; j++) { map[j] = '='; mult[j] = 1; }; if (sf >= 1) map['f'-'a'] = '^'; if (sf >= 2) map['c'-'a'] = '^'; if (sf >= 3) map['g'-'a'] = '^'; if (sf >= 4) map['d'-'a'] = '^'; if (sf >= 5) map['a'-'a'] = '^'; if (sf >= 6) map['e'-'a'] = '^'; if (sf >= 7) map['b'-'a'] = '^'; if (sf <= -1) map['b'-'a'] = '_'; if (sf <= -2) map['e'-'a'] = '_'; if (sf <= -3) map['a'-'a'] = '_'; if (sf <= -4) map['d'-'a'] = '_'; if (sf <= -5) map['g'-'a'] = '_'; if (sf <= -6) map['c'-'a'] = '_'; if (sf <= -7) map['f'-'a'] = '_'; } void altermap(basemap, basemul, modmap, modmul) /* apply modifiers to a set of accidentals */ char basemap[7], modmap[7]; int basemul[7], modmul[7]; { int i; for (i=0; i<7; i++) { if (modmap[i] != ' ') { basemap[i] = modmap[i]; basemul[i] = modmul[i]; }; }; } void resolve_tempo(struct atempo* t, struct fract* unitlen) /* Tempo may be given relative to the unit note length. At the start of */ /* the tune, we will know what this is and can deduce the tempo value. */ /* Can also deduce tempo if it has been given as a number only. */ { if (t->relative==1) { setfract(&t->basenote, t->basenote.num*unitlen->num, t->basenote.denom*unitlen->denom); reducef(&t->basenote); t->relative = 0; }; if ((t->basenote.num == 0) && (t->basenote.denom == 0)) { setfract(&t->basenote, unitlen->num, unitlen->denom); reducef(&t->basenote); }; } static void start_body() /* We have reached the end of the header section and need to set */ /* default values for anything not explicitly declared */ { parseron(); if (thetune.meter.num == 0) { event_warning("no M: field, assuming 4/4"); /* generate missing time signature */ event_timesig(4, 4, 1); event_linebreak(); }; if (thetune.unitlen.num == 0) { event_warning("no L: field, using default rule"); if ((double) thetune.meter.num / (double) thetune.meter.denom < 0.75) { /*setfract(&thetune.unitlen, 1, 16); [SS] 2004-09-06 */ event_length(16); } else { /* setfract(&thetune.unitlen, 1, 8); */ event_length(8); }; }; if (thetune.tempo != NULL) { resolve_tempo(thetune.tempo, &thetune.unitlen); }; } void event_true_key(sharps, s, modeindex, modmap, modmul) int sharps; char *s; int modeindex; /* 0 major, 1,2,3 minor, 4 locrian, etc. */ char modmap[7]; int modmul[7]; /* key detected in K: field */ { char basemap[7]; int basemul[7]; struct key* akey; int minor; minor =0; if (modeindex >0 && modeindex <4) minor = 1; setmap(sharps, basemap, basemul); altermap(basemap, basemul, modmap, modmul); if (xinbody) { akey = newkey(s, sharps, basemap, basemul); addfeature(KEY, akey); set_keysig(cv->keysig, akey); }; if (xinhead) { if (thetune.keysig == NULL) { thetune.keysig = newkey(s, sharps, basemap, basemul); } else { event_warning("Key specified twice"); }; xinbody = 1; xinhead = 0; setvoice(1); start_body(); }; } void event_octave(int num, int local) /* deals with the special command I:octave=N */ { if (xinhead) { thetune.octaveshift = num; }; if (xinbody) { cv->octaveshift = num; }; } void event_key(sharps, s, minor, modmap, modmul, modmicrotone, gotkey, gotclef, clefstr, octave, transpose, gotoctave, gottranspose, explict) int sharps; char *s; int minor; char modmap[7]; int modmul[7]; struct fraction modmicrotone[7]; /* [SS] 2014-01-06 */ int gotkey, gotclef; char* clefstr; int octave, transpose, gotoctave, gottranspose; int explict; /* A key field (K: ) has been encountered */ { if (xinhead || xinbody) { if (gotclef==1) { event_clef(clefstr); }; if (gotkey==1) { event_true_key(sharps, s, minor, modmap, modmul); }; }; if (gotoctave) { event_octave(octave,0); }; } static void checkbar(int type) /* Make sure that bar lasts for the correct musical time */ { int valid; char msg[80]; int a1, a2; valid = 0; a1 = cv->barlen.num*cv->barcount.denom; a2 = cv->barcount.num*cv->barlen.denom; if (a1 == a2) { cv->barcount.num = 0; cv->barcount.denom = 1; cv->barno = cv->barno + 1; } else { if (((type==BAR_REP)||(type==REP_BAR)||(type==DOUBLE_REP)) && (a1 > a2)) { /* do nothing */ } else { if ((cv->barno > 0) && (cv->barcount.num != 0) && (cv->barchecking != 0)) { sprintf(msg, "Bar %d is %d/%d not %d/%d", cv->barno, cv->barcount.num, cv->barcount.denom, cv->barlen.num, cv->barlen.denom); event_warning(msg); cv->barcount.num = 0; cv->barcount.denom = 1; cv->barno = cv->barno + 1; } else { cv->barcount.num = 0; cv->barcount.denom = 1; cv->barno = cv->barno + 1; }; }; }; } void event_bar(type, playonrep_list) int type; char* playonrep_list; /* A bar has been encountered in the abc */ { if (cv->inchord) { event_warning("Bar line not permitted within chord"); return; }; checkbar(type); /* increment bar number if bar complete */ /* [SS] 2015-11-15 * changed (void*) to (int *) */ addfeature(type, (int *)cv->barno); /* save bar number */ switch(type) { case SINGLE_BAR: break; case DOUBLE_BAR: break; case THIN_THICK: break; case THICK_THIN: break; case BAR_REP: if ((cv->expect_repeat) && (repcheck)) { event_error("Expecting repeat, found |:"); }; cv->expect_repeat = 1; break; case REP_BAR: if ((!cv->expect_repeat) && (repcheck)) { event_error("No repeat expected, found :|"); }; cv->expect_repeat = 0; break; case BAR1: if ((!cv->expect_repeat) && (repcheck)) { event_error("found |1 in non-repeat section"); }; break; case REP_BAR2: if ((!cv->expect_repeat) && (repcheck)) { event_error("No repeat expected, found :|2"); }; cv->expect_repeat = 0; break; case DOUBLE_REP: if ((!cv->expect_repeat) && (repcheck)) { event_error("No repeat expected, found ::"); }; cv->expect_repeat = 1; break; }; if ((playonrep_list != NULL) && (strlen(playonrep_list) > 0)) { event_playonrep(playonrep_list); }; } void event_space() /* A region of whitespace has been encountered */ { addfeature(NOBEAM, NULL); } void event_graceon() /* start of grace note(s) */ { if (cv->inchord) { event_error("grace notes not allowed within chord"); return; }; if (cv->ingrace) { event_error("nested grace notes not allowed"); return; }; cv->gracebeamroot = NULL; cv->gracebeamend = NULL; cv->ingrace = 1; addfeature(GRACEON, NULL); } void event_graceoff() /* end of grace note(s) */ { if (!cv->ingrace) { event_error("No grace notes to close"); return; }; if (cv->inchord) { event_error("cannot close grace notes within chord"); return; }; addfeature(GRACEOFF, NULL); closegracebeam(cv); cv->ingrace = 0; cv->gracebeamroot = NULL; cv->gracebeamend = NULL; } void event_rep1() /* start of first repeat */ { addfeature(REP1, NULL); } void event_rep2() /* start of second repeat */ { addfeature(REP2, NULL); } void event_playonrep(s) char* s; /* play on repeat(s) X - where X can be a list */ { addfeature(PLAY_ON_REP, addstring(s)); } void event_broken(type, mult) /* handles > >> >>> < << <<< in the abc */ int type, mult; { if (cv->inchord) { event_error("Broken rhythm not allowed in chord"); } else { if (cv->ingrace) { event_error("Broken rhythm not allowed in grace notes"); } else { cv->brokentype = type; cv->brokenmult = mult; cv->brokenpending = 0; }; }; } void event_tuple(n, q, r) int n, q, r; /* Start of a tuple has been encountered (e.g. triplet) */ /* Meaning is "play next r notes at q/n of notated value" */ /* where all 3 exist, otherwise r defaults to n and ratio */ /* is deduced from standard rules if q is missing */ { if (cv->tuplenotes != 0) { event_error("tuple within tuple not allowed"); return; }; if (r != 0) { cv->tuplenotes = r; } else { cv->tuplenotes = n; }; if (q != 0) { cv->tuplefactor.num = q; cv->tuplefactor.denom = n; } else { cv->tuplefactor.denom = n; if ((n == 2) || (n == 4) || (n == 8)) cv->tuplefactor.num = 3; if ((n == 3) || (n == 6)) cv->tuplefactor.num = 2; if ((n == 5) || (n == 7) || (n == 9)) { if ((cv->barlen.num % 3) == 0) { cv->tuplefactor.num = 3; } else { cv->tuplefactor.num = 2; }; }; }; cv->thistuple = newtuple(cv->tuplefactor.denom, cv->tuplefactor.num, cv->tuplenotes, n); addfeature(TUPLE, cv->thistuple); } void event_startinline() { } void event_closeinline() { } void event_handle_gchord(s) char* s; /* Guitar/Accompaniment chord placed in linked list for association */ /* with next suitable note */ { if (cv->gchords_pending == NULL) { cv->gchords_pending = newlist(); }; if (*s == '_') { if (cv->instructions_pending == NULL) { cv->instructions_pending = newlist(); }; addtolist(cv->instructions_pending, addstring(s+1)); } else { addtolist(cv->gchords_pending, addstring(s)); }; } void event_handle_instruction(s) char* s; /* An instruction (! !) has been encountered */ { char* inst; static char segno[3] = ":s"; static char coda[3] = ":c"; struct dynamic *psaction; int done; done = 0; inst = s; if (strcmp(s, "fermata") == 0) { decorators_passback[4] =1; /* don't show !fermata!. Treat it like H in music line */ return; } if (strcmp(s, "trill") == 0) { decorators_passback[6] =1; /* don't show !trill!. Treat it like T in music line */ return; } if (strcmp(s, "segno") == 0) { inst = segno; done = 1; }; if (strcmp(s, "coda") == 0) { inst = coda; done = 1; }; if (done == 1) { if (cv->instructions_pending == NULL) { cv->instructions_pending = newlist(); }; addtolist(cv->instructions_pending, addstring(inst)); return; } if (strcmp(s,"red") == 0) { psaction = (struct dynamic*) checkmalloc(sizeof(struct note)); psaction->color = 'r'; addfeature(DYNAMIC,psaction); } if (strcmp(s,"black") == 0) { psaction = (struct dynamic*) checkmalloc(sizeof(struct note)); psaction->color = 'b'; addfeature(DYNAMIC,psaction); } } struct slurtie* resolve_slur(struct feature* lastnote) /* when an end-of-slur marker ')' is found, this routine works out */ /* where the other end of the slur was */ { int i; int resolved; struct slurtie* s; resolved = 0; if (lastnote != NULL) { for (i=0; islurcount; i++) { if ((resolved == 0) && (cv->slur_place[i]->begin != NULL) && (cv->slur_place[i]->begin != lastnote)) { resolved = 1; cv->slur_place[i]->end = lastnote; s = cv->slur_place[i]; cv->slur_place[i] = cv->slur_place[cv->slurcount-1]; cv->slurcount = cv->slurcount - 1; }; }; }; if (resolved == 0) { event_error("Could not find start of slur to match close slur"); s = NULL; }; return(s); } static void startslurs(struct feature* firstnote) /* When a note is found after a (, set note to be start of slur */ /* Note may be the start of more than one slur */ { int i; for (i=0; islurcount; i++) { if (cv->slur_place[i]->begin == NULL) { cv->slur_place[i]->begin = firstnote; }; }; } void event_sluron(t) int t; /* start of slur */ { struct slurtie* s; s = newslurtie(); addfeature(SLUR_ON, s); cv->slurpending = 1; if (cv->slurcount < MAX_SLURS) { cv->slur_place[cv->slurcount] = s; cv->slurcount = cv->slurcount+1; } else { event_error("Static limit on number of slurs exceeded"); }; } void event_sluroff(t) int t; /* end of slur */ { struct slurtie* s; s = resolve_slur(cv->lastnote); addfeature(SLUR_OFF, s); } static void resolve_ties(struct feature* f) /* try to match up note to previous tied note */ { struct feature* ft; struct slurtie* s; struct note* m; struct note* n; int i, j; n = f->item; for (i=0; itiespending; i++) { ft = cv->tie_place[i]; /* pointer to TIE feature */ s = ft->item; ft = s->begin; /* pointer to NOTE feature */ m = ft->item; if (m->y == n->y) { /* pitch match found */ s->end = f; j = cv->tiespending; cv->tie_place[i] = cv->tie_place[j-1]; cv->tie_status[i] = cv->tie_status[j-1]; cv->tiespending = j-1; }; }; } static void advance_ties() /* deal with unresolved tied notes as musical time advances */ { int i, j; for (i=0; itiespending; i++) { cv->tie_status[i]++; }; i = 0; j = cv->tiespending; while (i < j) { if (cv->tie_status[i] >= 2) { event_error("No note to tie to"); cv->tie_place[i] = cv->tie_place[j-1]; cv->tie_status[i] = cv->tie_status[j-1]; j = j - 1; } else { i = i + 1; }; }; cv->tiespending = j; } void event_tie() /* tie encountered in the abc */ { struct slurtie* s; struct feature* place; int i; if ((cv->lastnote == NULL)||(cv->lastnote->type != NOTE)) { event_error("No note to tie"); } else { s = newslurtie(); place = addfeature(TIE, s); s->begin = cv->lastnote; cv->lastnote = NULL; i = cv->tiespending; if (i < MAX_TIES) { cv->tie_place[i] = place; cv->tie_status[i] = 0; cv->tiespending = cv->tiespending + 1; } else { event_error("Internal limit on ties exceeded"); }; }; } void event_lineend(ch, n) char ch; int n; /* Line ending with n copies of special character ch */ { } static void lenmul(n, a, b) /* multiply note length by a/b */ struct feature* n; int a, b; { struct note *anote; struct rest* arest; struct fract* afract; if (n->type == NOTE) { anote = n->item; afract = &anote->len; afract->num = afract->num * a; afract->denom = afract->denom * b; reducef(afract); /* re-calculate base, base_exp and dots */ anote->dots = count_dots(&anote->base, &anote->base_exp, anote->len.num, anote->len.denom); }; if (n->type == REST) { arest = n->item; afract = &arest->len; afract->num = afract->num * a; afract->denom = afract->denom * b; reducef(afract); /* re-calculate base, base_exp and dots */ arest->dots = count_dots(&arest->base, &arest->base_exp, arest->len.num, arest->len.denom); }; } struct fract* getlenfract(struct feature *f) /* find fractional length of NOTE or REST */ { struct fract *len; struct note *anote; struct rest *arest; len = NULL; if (f->type == NOTE) { anote = f->item; len = &(anote->len); }; if (f->type == REST) { arest = f->item; len = &(arest->len); }; return(len); } static void brokenadjust() /* adjust lengths of broken notes */ { int num1, num2, denom12; struct feature* j; struct fract* fr1; struct fract* fr2; int temp; int failed; int done; switch(cv->brokenmult) { case 1: num1 = 3; num2 = 1; break; case 2: num1 = 7; num2 = 1; break; case 3: num1 = 15; num2 = 1; break; }; denom12 = (num1 + num2)/2; if (cv->brokentype == LT) { temp = num1; num1 = num2; num2 = temp; }; failed = 0; if ((cv->laststart == NULL) || (cv->lastend == NULL) || (cv->thisstart == NULL) || (cv->thisend == NULL)) { failed = 1; } else { /* check for same length notes */ fr1 = getlenfract(cv->laststart); fr2 = getlenfract(cv->thisstart); /* fr1 = cv->laststart->item; fr2 = cv->thisstart->item; */ if ((fr1->num * fr2->denom) != (fr2->num * fr1->denom)) { failed = 1; }; }; if (failed) { event_error("Cannot apply broken rhythm"); } else { /* printf("Adjusting %d to %d and %d to %d\n", cv->laststart, cv->lastend, cv->thisstart, cv->thisend); */ j = cv->laststart; done = 0; while (done == 0) { lenmul(j, num1, denom12); done = (j == cv->lastend); j = j->next; }; j = cv->thisstart; done = 0; while (done == 0) { lenmul(j, num2, denom12); done = (j == cv->thisend); j = j->next; }; }; } static void marknotestart(struct feature* place) /* voice data structure keeps a record of last few notes encountered */ /* in order to process broken rhythm. This is called at the start of */ /* a note or chord */ { cv->laststart = cv->thisstart; cv->lastend = cv->thisend; cv->thisstart = place; } static void marknoteend(struct feature* place) /* voice data structure keeps a record of last few notes encountered */ /* in order to process broken rhythm. This is called at the end of */ /* a note or chord */ { cv->thisend = place; if (cv->brokenpending != -1) { cv->brokenpending = cv->brokenpending + 1; if (cv->brokenpending == 1) { brokenadjust(); cv->brokenpending = -1; }; }; } static void marknote(struct feature* place) /* when handling a single note, not a chord, marknotestart() and */ /* marknoteend() can be called together */ { marknotestart(place); marknoteend(place); } static void markchord(struct feature* chordplace) /* find start and end of chord for applying broken rhythm */ { struct feature* first; struct feature* last; first = chordplace->next; last = first; while ((last->next != NULL)&&(last->next->type==NOTE)) { last = last->next; }; marknotestart(first); marknoteend(last); } void event_chord() /* handles old '+' notation which marks the start and end of each chord */ { if (cv->inchord) { event_chordoff(1,1); } else { event_chordon(dummydecorator); }; } void event_chordon(int chorddecorators[]) /* start of a chord */ /* the array chorddecorators is not used yet. */ { if (cv->inchord) { event_error("nested chords found"); return; }; cv->inchord = 1; cv->chordcount = 0; cv->thischord = newchord(); cv->chordplace = addfeature(CHORDON, cv->thischord); } void fix_enclosed_note_lengths(struct feature* chordplace, int chord_n, int chord_m, int * base, int * base_exp) { struct feature* f; struct note* anote; if (chord_n ==1 && chord_m ==1) return; f = chordplace->next; anote = f->item; /* remove old note length from barcount */ addfractions(&cv->barcount, -anote->len.num, anote->len.denom); while ((f != NULL)&&((f->type==NOTE)||(f->type=CHORDNOTE))) { anote = f->item; /* remove old note length from barcount */ setfract(&anote->len, chord_n*cv->unitlen.num, chord_m*cv->unitlen.denom); reducef(&anote->len); /*printf("NOTE %c%c %d / %d\n", anote->accidental, anote->pitch, anote->len.num, anote->len.denom); */ anote->dots = count_dots(&anote->base, &anote->base_exp, anote->len.num, anote->len.denom); f = f->next; *base = anote->base; *base_exp = anote->base_exp; } /* and new note length to barcount */ addfractions(&cv->barcount, anote->len.num, anote->len.denom); } void event_chordoff(int chord_n, int chord_m) /* end of a chord */ { struct feature* ft; struct chord* thechord; struct note* firstnote; int base,base_exp; if (!cv->inchord) { event_error("no chord to close"); return; }; ft = cv->chordplace; if ((ft != NULL) && (ft->next != NULL) && (ft->next->type == NOTE)) { thechord = ft->item; firstnote = ft->next->item; /* beaming for 1st note in chord */ beamitem(NOTE, firstnote, ft->next); markchord(ft); thechord->base = firstnote->base; thechord->base_exp = firstnote->base_exp; } else { event_error("mis-formed chord"); }; if (cv->chordplace) { fix_enclosed_note_lengths(cv->chordplace,chord_n,chord_m,&base,&base_exp); if (chord_n != 1 || chord_m != 1) { thechord->base = base; thechord->base_exp = base_exp; } } cv->inchord = 0; cv->thischord = NULL; cv->chordplace = NULL; advance_ties(); addfeature(CHORDOFF, NULL); } /* just a stub to ignore 'y' */ void event_spacing(n, m) int n,m; { } void xevent_rest(n, m, multi) int n, m, multi; /* A rest has been encountered in the abc */ /* multi is 0 for ordinary rests or count for multibar rests */ { struct feature* restplace; if (cv->ingrace) { event_warning("rest in grace notes ignored"); return; }; if (cv->inchord) { event_warning("rest in chord ignored"); return; }; if ((multi > 0) && (cv->tuplenotes > 0)) { event_error("Multiple bar rest not allowed in tuple"); }; advance_ties(); restplace = addfeature(REST, newrest(n*cv->unitlen.num, m*cv->unitlen.denom, multi)); if (cv->slurpending) { startslurs(restplace); cv->slurpending = 0; }; cv->lastnote = restplace; if (cv->inchord) { cv->chordcount = cv->chordcount + 1; } else { marknote(restplace); }; if ((!cv->ingrace) && (!cv->inchord || (cv->chordcount == 1))) { if (cv->tuplenotes == 0) { if (multi == 0) { addunits(&cv->barcount, n, m); }; } else { addunits(&cv->barcount, n*cv->tuplefactor.num, m*cv->tuplefactor.denom); cv->thistuple->beamed = 0; cv->tuplenotes = cv->tuplenotes - 1; if (cv->tuplenotes == 0) { cv->thistuple = NULL; }; }; }; } void event_rest(decorators,n,m,type) int n, m,type; int decorators[DECSIZE]; /* A rest has been encountered in the abc */ { xevent_rest(n, m, 0); } void event_mrest(n,m) int n, m; /* A multiple bar rest has been encountered in the abc */ { xevent_rest(1, 1, n); } void event_note(decorators, xaccidental, xmult, xnote, xoctave, n, m) int decorators[DECSIZE]; int xmult; char xaccidental, xnote; int xoctave, n, m; /* note found in abc */ { struct note* nt; struct feature* noteplace; struct chord* thechord; int pitchval; nt = newnote(decorators, xaccidental, xmult, xnote, xoctave+cv->octaveshift, n * cv->unitlen.num, m * cv->unitlen.denom); nt->tuplenotes = cv->tuplenotes; noteplace = addfeature(NOTE, nt); cv->lastnote = noteplace; resolve_ties(noteplace); if (cv->slurpending) { startslurs(noteplace); cv->slurpending = 0; }; if (!cv->inchord) { marknote(noteplace); advance_ties(); } else { thechord = cv->thischord; pitchval = notenum(xoctave, xnote, cv->clef->type, cv->clef->octave); if (cv->chordcount == 0) { thechord->ytop = pitchval; thechord->ybot = pitchval; } else { if (pitchval > thechord->ytop) { thechord->ytop = pitchval; }; if (pitchval < thechord->ybot) { thechord->ybot = pitchval; }; }; cv->chordcount = cv->chordcount + 1; }; if ((!cv->ingrace) && (!cv->inchord || (cv->chordcount == 1))) { if (cv->tuplenotes == 0) { addunits(&cv->barcount, n, m); } else { addunits(&cv->barcount, n*cv->tuplefactor.num, m*cv->tuplefactor.denom); if (nt->base_exp > -3) { cv->thistuple->beamed = 0; }; cv->tuplenotes = cv->tuplenotes - 1; if (cv->tuplenotes == 0) { cv->thistuple = NULL; /* prevent beaming from tuple to non-tuple notes */ addfeature(NOBEAM, NULL); }; }; }; } /* these functions are here to satisfy the linker */ void event_microtone(int dir, int a, int b) { } void event_normal_tone() { } void event_info_key(key, value) char* key; char* value; /* handles a (key,value) pair found in an I: field */ { int num; if (strcmp(key, "clef")==0) { event_clef(value); }; if (strcmp(key, "octave")==0) { num = readsnumf(value); event_octave(num,0); }; } int main(argc,argv) int argc; char *argv[]; { char *filename; int i; oldchordconvention = 0; for (i=0;i #include #ifdef ANSILIBS #include #include #else char *strcpy(), *strcat(); #endif /* int exit(), free(); */ /* Line commmented out JRA 19/12/95 */ /* public stuff */ /* Functions to be called while processing the MIDI file. */ int (*Mf_getc)() = NULLFUNC; void (*Mf_error)() = NULLFUNC; void (*Mf_header)() = NULLFUNC; void (*Mf_trackstart)() = NULLFUNC; void (*Mf_trackend)() = NULLFUNC; void (*Mf_noteon)() = NULLFUNC; void (*Mf_noteoff)() = NULLFUNC; void (*Mf_pressure)() = NULLFUNC; void (*Mf_parameter)() = NULLFUNC; void (*Mf_pitchbend)() = NULLFUNC; void (*Mf_program)() = NULLFUNC; void (*Mf_chanpressure)() = NULLFUNC; void (*Mf_sysex)() = NULLFUNC; void (*Mf_arbitrary)() = NULLFUNC; void (*Mf_metamisc)() = NULLFUNC; void (*Mf_seqnum)() = NULLFUNC; void (*Mf_eot)() = NULLFUNC; void (*Mf_smpte)() = NULLFUNC; void (*Mf_tempo)() = NULLFUNC; void (*Mf_timesig)() = NULLFUNC; void (*Mf_keysig)() = NULLFUNC; void (*Mf_seqspecific)() = NULLFUNC; void (*Mf_text)() = NULLFUNC; /* Functions to implement in order to write a MIDI file */ int (*Mf_putc)() = NULLFUNC; long (*Mf_writetrack)() = NULLFUNC; int (*Mf_writetempotrack)() = NULLFUNC; int Mf_nomerge = 0; /* 1 => continue'ed system exclusives are */ /* not collapsed. */ long Mf_currtime = 0L; /* current time in delta-time units */ /* private stuff */ long Mf_toberead = 0L; long Mf_bytesread = 0L; static long Mf_numbyteswritten = 0L; static long readvarinum(); static long read32bit(); static long to32bit(); static int read16bit(); static int to16bit(); static char *msg(); int skiptrack (); /* this block was previously in midifile.h [SS] 2010-01-23*/ static int readtrack(); static void readheader(); static void badbyte(); static void metaevent(); static void sysex(); static void chanmessage(); static void msginit(); static void msgadd(); static void biggermsg(); static void mf_write_track_chunk(); static void mf_write_header_chunk(); static void WriteVarLen(); static void write32bit(); static void write16bit(); static int msgleng(); static int eputc(); /* end of block */ /* following declaration added 27/8/96 JRA static readheader(), readtrack(), badbyte(), metaevent(), sysex(), chanmessage(), msginit(), msgleng(), msgadd(), biggermsg(); */ int ntrks; void mfread() /* The only non-static function in this file. */ { int track; if ( Mf_getc == NULLFUNC ) mferror("mfread() called without setting Mf_getc"); readheader(); track =1; while (readtrack()) {track++; if(track>ntrks) break; } } void mfreadtrk(itrack) /* The only non-static function in this file. */ int itrack; { int track,ok; if ( Mf_getc == NULLFUNC ) mferror("mfprocess() called without setting Mf_getc"); readheader(); track =1; ok = 1; for (track=1;track<=ntrks && ok == 1;track++) {if (track == itrack) ok = readtrack(); else ok = skiptrack(); } } /* for backward compatibility with the original lib */ void midifile() { mfread(); } static int readmt(s) /* read through the "MThd" or "MTrk" header string */ char *s; { int n = 0; char *p = s; int c; while ( n++<4 && (c=(*Mf_getc)()) != EOF ) { if ( c != *p++ ) { char buff[32]; (void) strcpy(buff,"expecting "); (void) strcat(buff,s); mferror(buff); } } return(c); } static int egetc() /* read a single character and abort on EOF */ { int c = (*Mf_getc)(); if ( c == EOF ) mferror("premature EOF"); Mf_toberead--; Mf_bytesread++; return(c); } static void readheader() /* read a header chunk */ { int format, division; if ( readmt("MThd") == EOF ) return; Mf_toberead = read32bit(); Mf_bytesread = 0; format = read16bit(); ntrks = read16bit(); division = read16bit(); if ( Mf_header ) (*Mf_header)(format,ntrks,division); /* flush any extra stuff, in case the length of header is not 6 */ while ( Mf_toberead > 0 ) (void) egetc(); } int skiptrack () { int byte; if ( readmt("MTrk") == EOF ) return(0); Mf_toberead = read32bit(); byte = 0; while (Mf_toberead && byte != EOF) byte = egetc(); if (byte == EOF) {mferror("premature EOF\n"); return(0);} return(1); } int readtrack() /* read a track chunk */ { /* This array is indexed by the high half of a status byte. It's */ /* value is either the number of bytes needed (1 or 2) for a channel */ /* message, or 0 (meaning it's not a channel message). */ static int chantype[] = { 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00 through 0x70 */ 2, 2, 2, 2, 1, 1, 2, 0 /* 0x80 through 0xf0 */ }; long lookfor; int c, c1, type; int sysexcontinue = 0; /* 1 if last message was an unfinished sysex */ int running = 0; /* 1 when running status used */ int status = 0; /* status value (e.g. 0x90==note-on) */ int laststatus; /* for running status */ int needed; long varinum; laststatus = 0; if ( readmt("MTrk") == EOF ) return(0); Mf_toberead = read32bit(); Mf_currtime = 0; Mf_bytesread =0; if ( Mf_trackstart ) (*Mf_trackstart)(); while ( Mf_toberead > 0 ) { Mf_currtime += readvarinum(); /* delta time */ c = egetc(); if ( sysexcontinue && c != 0xf7 ) mferror("didn't find expected continuation of a sysex"); /* if bit 7 not set, there is no status byte following the * delta time, so it must a running status and we assume the * last status occuring in the preceding channel message. */ if ( (c & 0x80) == 0 ) { /* running status? */ if ( status == 0 ) mferror("unexpected running status"); running = 1; } else { /* [SS] 2013-09-10 */ if (c>>4 != 0x0f) { /* if it is not a meta event save the status*/ laststatus = c; } running = 0; status = c; } /* [SS] 2013-09-10 */ if (running) needed = chantype[ (laststatus>>4) & 0xf]; else needed = chantype[ (status>>4) & 0xf ]; if ( needed ) { /* ie. is it a channel message? */ if ( running ) { c1 = c; chanmessage( laststatus, c1, (needed>1) ? egetc() : 0 ); } else { c1 = egetc(); chanmessage( status, c1, (needed>1) ? egetc() : 0 ); } continue;; } switch ( c ) { case 0xff: /* meta event */ type = egetc(); varinum = readvarinum(); lookfor = Mf_toberead - varinum; msginit(); while ( Mf_toberead > lookfor ) msgadd(egetc()); metaevent(type); break; case 0xf0: /* start of system exclusive */ varinum = readvarinum(); lookfor = Mf_toberead - varinum; msginit(); msgadd(0xf0); while ( Mf_toberead > lookfor ) msgadd(c=egetc()); if ( c==0xf7 || Mf_nomerge==0 ) sysex(); else sysexcontinue = 1; /* merge into next msg */ break; case 0xf7: /* sysex continuation or arbitrary stuff */ varinum = readvarinum(); lookfor = Mf_toberead - varinum; if ( ! sysexcontinue ) msginit(); while ( Mf_toberead > lookfor ) msgadd(c=egetc()); if ( ! sysexcontinue ) { if ( Mf_arbitrary ) (*Mf_arbitrary)(msgleng(),msg()); } else if ( c == 0xf7 ) { sysex(); sysexcontinue = 0; } break; default: badbyte(c); break; } } if ( Mf_trackend ) (*Mf_trackend)(); return(1); } static void badbyte(c) int c; { char buff[32]; (void) sprintf(buff,"unexpected byte: 0x%02x",c); mferror(buff); } static void metaevent(type) int type; { int leng; char *m; leng = msgleng(); m = msg(); switch ( type ) { case 0x00: if ( Mf_seqnum ) (*Mf_seqnum)(to16bit(m[0],m[1])); break; case 0x01: /* Text event */ case 0x02: /* Copyright notice */ case 0x03: /* Sequence/Track name */ case 0x04: /* Instrument name */ case 0x05: /* Lyric */ case 0x06: /* Marker */ case 0x07: /* Cue point */ case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f: /* These are all text events */ if ( Mf_text ) (*Mf_text)(type,leng,m); break; case 0x2f: /* End of Track */ if ( Mf_eot ) (*Mf_eot)(); break; case 0x51: /* Set tempo */ if ( Mf_tempo ) (*Mf_tempo)(to32bit(0,m[0],m[1],m[2])); break; case 0x54: if ( Mf_smpte ) (*Mf_smpte)(m[0],m[1],m[2],m[3],m[4]); break; case 0x58: if ( Mf_timesig ) (*Mf_timesig)(m[0],m[1],m[2],m[3]); break; case 0x59: if ( Mf_keysig ) (*Mf_keysig)(m[0],m[1]); break; case 0x7f: if ( Mf_seqspecific ) (*Mf_seqspecific)(leng,m); break; default: if ( Mf_metamisc ) (*Mf_metamisc)(type,leng,m); } } static void sysex() { if ( Mf_sysex ) (*Mf_sysex)(msgleng(),msg()); } static void chanmessage(status,c1,c2) int status; int c1, c2; { int chan = status & 0xf; switch ( status & 0xf0 ) { case 0x80: if ( Mf_noteoff ) (*Mf_noteoff)(chan,c1,c2); break; case 0x90: if ( Mf_noteon ) (*Mf_noteon)(chan,c1,c2); break; case 0xa0: if ( Mf_pressure ) (*Mf_pressure)(chan,c1,c2); break; case 0xb0: if ( Mf_parameter ) (*Mf_parameter)(chan,c1,c2); break; case 0xe0: if ( Mf_pitchbend ) (*Mf_pitchbend)(chan,c1,c2); break; case 0xc0: if ( Mf_program ) (*Mf_program)(chan,c1); break; case 0xd0: if ( Mf_chanpressure ) (*Mf_chanpressure)(chan,c1); break; } } /* readvarinum - read a varying-length number, and return the */ /* number of characters it took. */ static long readvarinum() { long value; int c; c = egetc(); value = c; if ( c & 0x80 ) { value &= 0x7f; do { c = egetc(); value = (value << 7) + (c & 0x7f); } while (c & 0x80); } return (value); } static long to32bit(c1,c2,c3,c4) int c1, c2, c3, c4; { long value = 0L; value = (c1 & 0xff); value = (value<<8) + (c2 & 0xff); value = (value<<8) + (c3 & 0xff); value = (value<<8) + (c4 & 0xff); return (value); } static int to16bit(c1,c2) int c1, c2; { return ((c1 & 0xff ) << 8) + (c2 & 0xff); } static long read32bit() { int c1, c2, c3, c4; c1 = egetc(); c2 = egetc(); c3 = egetc(); c4 = egetc(); return to32bit(c1,c2,c3,c4); } static int read16bit() { int c1, c2; c1 = egetc(); c2 = egetc(); return to16bit(c1,c2); } /* static */ void mferror(s) char *s; { if ( Mf_error ) { (*Mf_error)(s); exit(1); } else { printf("MIDI read/write error : %s\n", s); exit(1); }; } /* The code below allows collection of a system exclusive message of */ /* arbitrary length. The Msgbuff is expanded as necessary. The only */ /* visible data/routines are msginit(), msgadd(), msg(), msgleng(). */ #define MSGINCREMENT 128 static char *Msgbuff = NULL; /* message buffer */ static int Msgsize = 0; /* Size of currently allocated Msg */ static int Msgindex = 0; /* index of next available location in Msg */ static void msginit() { Msgindex = 0; } static char * msg() { return(Msgbuff); } static int msgleng() { return(Msgindex); } static void msgadd(c) int c; { /* If necessary, allocate larger message buffer. */ if ( Msgindex >= Msgsize ) biggermsg(); Msgbuff[Msgindex++] = c; } static void biggermsg() { /* char *malloc(); */ char *newmess; char *oldmess = Msgbuff; int oldleng = Msgsize; Msgsize += MSGINCREMENT; newmess = (char *) malloc( (unsigned)(sizeof(char)*Msgsize) ); if(newmess == NULL) mferror("malloc error!"); /* copy old message into larger new one */ if ( oldmess != NULL ) { register char *p = newmess; register char *q = oldmess; register char *endq = &oldmess[oldleng]; for ( ; q!=endq ; p++,q++ ) *p = *q; free(oldmess); } Msgbuff = newmess; } /* * mfwrite() - The only fuction you'll need to call to write out * a midi file. * * format 0 - Single multi-channel track * 1 - Multiple simultaneous tracks * 2 - One or more sequentially independent * single track patterns * ntracks The number of tracks in the file. * division This is kind of tricky, it can represent two * things, depending on whether it is positive or negative * (bit 15 set or not). If bit 15 of division is zero, * bits 14 through 0 represent the number of delta-time * "ticks" which make up a quarter note. If bit 15 of * division is a one, delta-times in a file correspond to * subdivisions of a second similiar to SMPTE and MIDI * time code. In this format bits 14 through 8 contain * one of four values - 24, -25, -29, or -30, * corresponding to the four standard SMPTE and MIDI * time code frame per second formats, where -29 * represents 30 drop frame. The second byte * consisting of bits 7 through 0 corresponds the the * resolution within a frame. Refer the Standard MIDI * Files 1.0 spec for more details. * fp This should be the open file pointer to the file you * want to write. It will have be a global in order * to work with Mf_putc. */ void mfwrite(format,ntracks,division,fp) int format,ntracks,division; FILE *fp; { int i; if ( Mf_putc == NULLFUNC ) mferror("mf_write() called without setting Mf_putc"); if ( Mf_writetrack == NULLFUNC ) mferror("mf_write() called without setting Mf_writetrack"); /* every MIDI file starts with a header */ mf_write_header_chunk(format,ntracks,division); /* In format 1 files, the first track is a tempo map */ if(format == 1 && ( Mf_writetempotrack )) { (*Mf_writetempotrack)(); } /* The rest of the file is a series of tracks */ for(i = 0; i < ntracks; i++) mf_write_track_chunk(i,fp); } #ifdef NOFTELL int nullpass = 0; #endif int nullputc(c) /* dummy putc for abc checking option */ /* also used for FTELL work-around */ char c; { int t; t = ((int) c) & 0xFF; return (t); } static void mf_write_track_chunk(which_track,fp) int which_track; FILE *fp; { long trkhdr,trklength; long offset, place_marker; long endspace; /* There is an alternate version of this code selected by NOFTELL which doesn't require use of file seek */ #ifdef NOFTELL int (*tempfunc)() = NULLFUNC; extern int myputc(); trkhdr = MTrk; trklength = 0; tempfunc = Mf_putc; Mf_putc = nullputc; Mf_numbyteswritten = 0L; /* the header's length doesn't count */ /* dummy write track */ nullpass = 1; if( Mf_writetrack ) { endspace = (*Mf_writetrack)(which_track); } WriteVarLen(endspace); /* mf_write End of track meta event */ /* eputc(0); */ eputc(meta_event); eputc(end_of_track); eputc(0); trklength = Mf_numbyteswritten; /* now actually write track */ Mf_putc = tempfunc; nullpass = 0; write32bit(trkhdr); write32bit(trklength); Mf_numbyteswritten = 0L; /* the header's length doesn't count */ /* now output the data */ if( Mf_writetrack ) { endspace = (*Mf_writetrack)(which_track); } WriteVarLen(endspace); eputc(meta_event); eputc(end_of_track); eputc(0); if (trklength != Mf_numbyteswritten) { mferror("NOFTELL workaround failed to predict tracklength"); } #else /* this is the original code */ trkhdr = MTrk; trklength = 0; /* Remember where the length was written, because we don't know how long it will be until we've finished writing */ offset = ftell(fp); #ifdef DEBUG printf("offset = %d\n",(int) offset); #endif /* Write the track chunk header */ write32bit(trkhdr); write32bit(trklength); Mf_numbyteswritten = 0L; /* the header's length doesn't count */ if( Mf_writetrack ) { endspace = (*Mf_writetrack)(which_track); } /* mf_write End of track meta event */ WriteVarLen(endspace); /* eputc(0); */ eputc(meta_event); eputc(end_of_track); eputc(0); /* It's impossible to know how long the track chunk will be beforehand, so the position of the track length data is kept so that it can be written after the chunk has been generated */ place_marker = ftell(fp); /* This method turned out not to be portable because the parameter returned from ftell is not guaranteed to be in bytes on every machine */ /* track.length = place_marker - offset - (long) sizeof(track); */ #ifdef DEBUG printf("length = %d\n",(int) trklength); #endif if(fseek(fp,offset,0) < 0) mferror("error seeking during final stage of write"); trklength = Mf_numbyteswritten; /* Re-mf_write the track chunk header with right length */ write32bit(trkhdr); write32bit(trklength); fseek(fp,place_marker,0); #endif } /* End gen_track_chunk() */ static void mf_write_header_chunk(format,ntracks,division) int format,ntracks,division; { long ident,length; ident = MThd; /* Head chunk identifier */ length = 6; /* Chunk length */ /* individual bytes of the header must be written separately to preserve byte order across cpu types :-( */ write32bit(ident); write32bit(length); write16bit(format); write16bit(ntracks); write16bit(division); } /* end gen_header_chunk() */ /* * mf_write_midi_event() * * Library routine to mf_write a single MIDI track event in the standard MIDI * file format. The format is: * * * * In this case, event can be any multi-byte midi message, such as * "note on", "note off", etc. * * delta_time - the time in ticks since the last event. * type - the type of meta event. * chan - The midi channel. * data - A pointer to a block of chars containing the META EVENT, * data. * size - The length of the meta-event data. */ int mf_write_midi_event(delta_time, type, chan, data, size) long delta_time; int chan,type; int size; char *data; { int i; char c; WriteVarLen(delta_time); /* all MIDI events start with the type in the first four bits, and the channel in the lower four bits */ c = (char) (type | chan); if(chan > 15) { mferror("error: MIDI channel greater than 16"); }; eputc(c); /* write out the data bytes */ for(i = 0; i < size; i++) eputc(data[i]); return(size); } /* end mf_write MIDI event */ /* * mf_write_meta_event() * * Library routine to mf_write a single meta event in the standard MIDI * file format. The format of a meta event is: * * * * delta_time - the time in ticks since the last event. * type - the type of meta event. * data - A pointer to a block of chars containing the META EVENT, * data. * size - The length of the meta-event data. */ int mf_write_meta_event(delta_time, type, data, size) long delta_time; char *data; int type; int size; { int i; WriteVarLen(delta_time); /* This marks the fact we're writing a meta-event */ eputc(meta_event); /* The type of meta event */ eputc(type); /* The length of the data bytes to follow */ WriteVarLen((long)size); for(i = 0; i < size; i++) { if(eputc((data[i] & 0xff)) != (data[i] & 0xff)) return(-1); } return(size); } /* end mf_write_meta_event */ void mf_write_tempo(tempo) long tempo; { /* Write tempo */ /* all tempos are written as 120 beats/minute, */ /* expressed in microseconds/quarter note */ eputc(0); eputc(meta_event); eputc(set_tempo); eputc(3); eputc((char)(0xff & (tempo >> 16))); eputc((char)(0xff & (tempo >> 8))); eputc((char)(0xff & tempo)); } /* * This routine converts delta times in seconds into ticks. The * else statement is needed because the formula is different for tracks * based on notes and tracks based on SMPTE times. * */ long mf_sec2ticks(secs,division,tempo) float secs; int division; long tempo; { long ticks; float smpte_format, smpte_resolution; if(division > 0) { ticks = (long) ((secs * ((float)(division))* 1000000.0) / ((float)(tempo))+0.5); } else { smpte_format = upperbyte(division); smpte_resolution = lowerbyte(division); ticks = (long) (secs * smpte_format * smpte_resolution * 1000000.0 + 0.5); }; return (ticks); } /* end of sec2ticks() */ /* * Write multi-length bytes to MIDI format files */ static void WriteVarLen(value) long value; { long buffer; buffer = value & 0x7f; while((value >>= 7) > 0) { buffer <<= 8; buffer |= 0x80; buffer += (value & 0x7f); } while(1){ eputc((char)(buffer & 0xff)); if(buffer & 0x80) buffer >>= 8; else return; } }/* end of WriteVarLen */ void single_note_tuning_change(int key, float midipitch) { unsigned char kk,xx,yy,zz; int number,intfraction; float fraction; eputc(0); /* varinum delta_t (time to next event) */ eputc(0xf0); /* sysex initiation */ eputc(11); /* 11 bytes included in sysex */ eputc(127); /* universal sysex command (0x7f) */ eputc(0); /* device id */ eputc(8); /* midi tuning */ eputc(2); /* note change */ eputc(0); /* program number 0 - 127 */ eputc(1); /* only one change */ kk = (unsigned char) 127 & key; eputc(kk); /* MIDI key 0 - 127 */ number = (int) midipitch; fraction = midipitch - (float) number; if (fraction < 0.0) fraction = -fraction; intfraction = (int) fraction*16384; xx = 0x7f & number; yy = intfraction/128; zz = intfraction % 128; yy = 0x7f & yy; zz = 0x7f & zz; eputc(xx); eputc(yy); eputc(zz); eputc(247); /* 0xf7 terminates sysex command */ } /* * This routine converts delta times in ticks into seconds. The * else statement is needed because the formula is different for tracks * based on notes and tracks based on SMPTE times. * */ float mf_ticks2sec(ticks,division,tempo) int division; long tempo; long ticks; { float ret; float smpte_format, smpte_resolution; if(division > 0) { ret = ((float) (((float)(ticks) * (float)(tempo)) / ((float)(division) * 1000000.0))); } else { smpte_format = upperbyte(division); smpte_resolution = lowerbyte(division); ret = (float) ((float) ticks / (smpte_format * smpte_resolution * 1000000.0)); } return (ret); } /* end of ticks2sec() */ /* * write32bit() * write16bit() * * These routines are used to make sure that the byte order of * the various data types remains constant between machines. This * helps make sure that the code will be portable from one system * to the next. It is slightly dangerous that it assumes that longs * have at least 32 bits and ints have at least 16 bits, but this * has been true at least on PCs, UNIX machines, and Macintosh's. * */ static void write32bit(data) long data; { eputc((char)((data >> 24) & 0xff)); eputc((char)((data >> 16) & 0xff)); eputc((char)((data >> 8 ) & 0xff)); eputc((char)(data & 0xff)); } static void write16bit(data) int data; { eputc((char)((data & 0xff00) >> 8)); eputc((char)(data & 0xff)); } /* write a single character and abort on error */ static int eputc(c) char c; { int return_val; if((Mf_putc) == NULLFUNC) { mferror("Mf_putc undefined"); return(-1); } return_val = (*Mf_putc)(c); if ( return_val == EOF ) mferror("error writing"); #ifdef PCCFIX /* This seems to be needed for the FTELL workaround */ if (return_val != -1) { return_val = (int) c; }; #endif Mf_numbyteswritten++; if(Mf_numbyteswritten > 500000) { printf("eputc: aborting because of file runaway (infinite loop)\n"); exit(1); } return(return_val); } abcmidi/makefiles/0000755000000000000000000000000012610703670013106 5ustar rootrootabcmidi/makefiles/makefile.bcc0000644000000000000000000000776111736126450015352 0ustar rootroot# Borland command line compiler bcc version 5.5 Makefile for abcMIDI package # Can also use mingw or gnu standard make program with this makefile. # # # compilation #ifdefs - you may need to change these defined to get # the code to compile with a different C compiler. # # NOFTELL in midifile.c and tomidi.c selects a version of the file-writing # code which doesn't use file seeking. # # PCCFIX in mftext.c midifile.c midi2abc.c # comments out various things that aren't available in PCC # # USE_INDEX causes index() to be used instead of strchr(). This is needed # by some pre-ANSI C compilers. # # ASCTIME causes asctime() to be used instead of strftime() in pslib.c. # If ANSILIBS is not set, neither routine is used. # # ANSILIBS causes code to include some ANSI standard headers # # KANDR selects functions prototypes without argument prototypes. # # If your Borland compiler is in another path, change the include # and library options below in CFLAGS and LDFLAGS. # CC=bcc32 CFLAGS=-g0 -v -WC -c -I/bcc55/include LNK=ilink32 LDFLAGS=/ap /L\bcc55\lib c0x32.obj LDFLAGS2=import32.lib cw32.lib all : abc2midi.exe midi2abc.exe abc2abc.exe mftext.exe yaps.exe midicopy.exe abcmatch.exe abc2midi.exe : parseabc.obj store.obj genmidi.obj queues.obj midifile.obj parser2.obj stresspat.obj -lm $(LNK) $(LDFLAGS) parseabc.obj genmidi.obj store.obj \ queues.obj midifile.obj parser2.obj stresspat.obj, abc2midi.exe,, $(LDFLAGS2) abc2abc.exe : parseabc.obj toabc.obj $(LNK) $(LDFLAGS) parseabc.obj toabc.obj, abc2abc.exe,, $(LDFLAGS2) midi2abc.exe : midifile.obj midi2abc.obj $(LNK) $(LDFLAGS) midifile.obj midi2abc.obj, midi2abc.exe,, $(LDFLAGS2) mftext.exe : midifile.obj mftext.obj crack.obj $(LNK) $(LDFLAGS) midifile.obj mftext.obj crack.obj, mftext.exe,, $(LDFLAGS2) yaps.exe : parseabc.obj yapstree.obj drawtune.obj debug.obj pslib.obj position.obj parser2.obj $(LNK) $(LDFLAGS) parseabc.obj yapstree.obj drawtune.obj debug.obj \ position.obj pslib.obj parser2.obj, yaps.exe,, $(LDFLAGS2) midicopy.exe: midicopy.obj $(LNK) $(LDFLAGS) midicopy.obj, midicopy.exe,, $(LDFLAGS2) abcmatch.exe : abcmatch.obj matchsup.obj parseabc.obj $(LNK) $(LDFLAGS) abcmatch.obj matchsup.obj parseabc.obj, abcmatch.exe,, $(LDFLAGS2) # common parser object code # parseabc.obj : parseabc.c abc.h parseabc.h $(CC) $(CFLAGS) parseabc.c parser2.obj : parser2.c parseabc.h parser2.h $(CC) $(CFLAGS) parser2.c # objects needed by abc2abc # toabc.obj : toabc.c abc.h parseabc.h $(CC) $(CFLAGS) toabc.c # objects needed by abc2midi # store.obj : store.c abc.h parseabc.h parser2.h genmidi.h $(CC) $(CFLAGS) store.c genmidi.obj : genmidi.c abc.h midifile.h genmidi.h $(CC) $(CFLAGS) genmidi.c stresspat.obj : stresspat.c $(CC) $(CFLAGS) stresspat.c queues.obj: queues.c genmidi.h $(CC) $(CFLAGS) queues.c # common midifile library # # could use -DNOFTELL here midifile.obj : midifile.c midifile.h $(CC) $(CFLAGS) midifile.c # objects needed by yaps # yapstree.obj: yapstree.c abc.h parseabc.h structs.h drawtune.h parser2.h $(CC) $(CFLAGS) yapstree.c drawtune.obj: drawtune.c structs.h sizes.h abc.h drawtune.h $(CC) $(CFLAGS) drawtune.c pslib.obj: pslib.c drawtune.h $(CC) $(CFLAGS) pslib.c position.obj: position.c abc.h structs.h sizes.h $(CC) $(CFLAGS) position.c debug.obj: debug.c structs.h abc.h $(CC) $(CFLAGS) debug.c # objects needed by midi2abc # midi2abc.obj : midi2abc.c midifile.h $(CC) $(CFLAGS) midi2abc.c # objects for mftext # crack.obj : crack.c $(CC) $(CFLAGS) crack.c mftext.obj : mftext.c midifile.h $(CC) $(CFLAGS) mftext.c # objects for midicopy # midicopy.obj :midicopy.c midicopy.h $(CC) $(CFLAGS) midicopy.c # objects for abcmatch # abcmatch.obj : abcmatch.c abc.h $(CC) $(CFLAGS) abcmatch. matchsup.obj : matchsup.c abc.h parseabc.h parser2.h $(CC) $(CFLAGS) matchsup.c clean: rm *.obj rm *.exe zipfile: midi2abc.exe abc2midi.exe mftext.exe yaps.exe abc2abc.exe midicopy.exe zip pcexe2.zip *.exe readme.txt abcguide.txt demo.abc yaps.txt abcmidi/makefiles/pcc.mak0000644000000000000000000000452311736126402014351 0ustar rootroot# PCC Makefile for abcMIDI package # # # compilation #ifdefs - you need to define some of these to get # the code to compile with PCC. # # NOFTELL in midifile.c and genmidi.c selects a version of the file-writing # code which doesn't use file seeking. # # PCCFIX in mftext.c midifile.c midi2abc.c # comments out various things that aren't available in PCC # and applies a fix needed for file writing # # ANSILIBS causes appropriate ANSI .h files to be #included. # # KANDR selects function prototypes with argument prototypes. # # USE_INDEX replaces calls to strchr() with calls to index(). # CC=pcc CFLAGS=-nPCCFIX -nNOFTELL -nUSE_INDEX -nKANDR LNK=pccl all : abc2midi.exe midi2abc.exe abc2abc.exe mftext.exe yaps.exe midicopy.exe abcmatch.exe abc2midi.exe : parseabc.o store.o genmidi.o queues.o midifile.o parser2.o stresspat.o -lm $(LNK) -Lc:\bin\pcc\ -Oabc2midi parseabc.o store.o genmidi.o queues.o midifile.o parser2.o stresspat.o abc2abc.exe : parseabc.o toabc.o $(LNK) -Lc:\bin\pcc\ -Oabc2abc parseabc.o toabc.o midi2abc.exe : midifile.o midi2abc.o $(LNK) -Lc:\bin\pcc\ midifile.o midi2abc.o -Omidi2abc mftext.exe : midifile.o mftext.o crack.o $(LNK) -Lc:\bin\pcc\ midifile.o mftext.o crack.o -Omftext midicopy.exe: midicopy.o $(LNK) -Lc:\bin\pcc\ midicopy.o -Omidicopy $(CFLAGS) parseabc.o : parseabc.c abc.h parseabc.h $(CC) parseabc.c $(CFLAGS) parser2.o : parser2.c abc.h parseabc.h parser2.h $(CC) parser2.c $(CFLAGS) toabc.o : toabc.c abc.h parseabc.h $(CC) toabc.c $(CFLAGS) genmidi.o : genmidi.c abc.h midifile.h parseabc.h genmidi.h $(CC) genmidi.c $(CFLAGS) stresspat.o : stresspat.c $(CC) stresspat.c $(CFLAGS) store.o : store.c abc.h midifile.h parseabc.h $(CC) store.c $(CFLAGS) queues.o : queues.c genmidi.h $(CC) queues.c $(CFLAGS) midifile.o : midifile.c midifile.h $(CC) midifile.c $(CFLAGS) midi2abc.o : midi2abc.c midifile.h $(CC) midi2abc.c $(CFLAGS) crack.o : crack.c $(CC) crack.c $(CFLAGS) mftext.o : mftext.c midifile.h $(CC) mftext.c $(CFLAGS) midicopy.o : midicopy.c $(CC) midicopy.c $(CFLAGS) abcmatch.o : abcmatch.c $(CC) abcmatch.c $(CFLAGS) matchsup.o : matchsup.c $(CC) matchsup.c $(CFLAGS) clean: del *.exe del *.o zipfile: abc2midi.exe midi2abc.exe abc2abc.exe mftext.exe midicopy.exe abcmatch.exe zip pcexe.zip *.exe readme.txt abcguide.txt demo.abc abcmidi/makefiles/djgpp.mak0000644000000000000000000000716611736126272014723 0ustar rootroot# DJGPP (DOS port of gcc) Makefile for abcMIDI package # # # compilation #ifdefs - you may need to change these defined to get # the code to compile with a different C compiler. # # NOFTELL in midifile.c and genmidi.c selects a version of the file-writing # code which doesn't use file seeking. # # PCCFIX in mftext.c midifile.c midi2abc.c # comments out various things that aren't available in PCC # # USE_INDEX causes index() to be used instead of strchr(). This is needed # by some pre-ANSI C compilers. # # ASCTIME causes asctime() to be used instead of strftime() in pslib.c. # If ANSILIBS is not set, neither routine is used. # # ANSILIBS causes code to include some ANSI standard headers # # KANDR selects functions prototypes without argument prototypes. # # NO_SNPRINTF causes code to use printf instead of snprintf which # is less secure. CC=gcc CFLAGS=-c -ansi -DANSILIBS -DNO_SNPRINTF -Wformat -Wtraditional # -ansi forces ANSI compliance LNK=gcc all : abc2midi.exe midi2abc.exe abc2abc.exe mftext.exe yaps.exe\ midicopy.exe abcmatch.exe abc2midi.exe : parseabc.o store.o genmidi.o queues.o midifile.o parser2.o $(LNK) -o abc2midi.exe parseabc.o genmidi.o store.o \ queues.o midifile.o parser2.o stresspat.o -lm abc2abc.exe : parseabc.o toabc.o $(LNK) -o abc2abc.exe parseabc.o toabc.o midi2abc.exe : midifile.o midi2abc.o $(LNK) midifile.o midi2abc.o -o midi2abc.exe mftext.exe : midifile.o mftext.o crack.o $(LNK) midifile.o mftext.o crack.o -o mftext.exe midicopy.exe : midicopy.o $(LNK) midicopy.o -o midicopy.exe abcmatch.exe : abcmatch.o matchsup.o parseabc.o $(LNK) abcmatch.o matchsup.o parseabc.o -o abcmatch.exe yaps.exe : parseabc.o yapstree.o drawtune.o debug.o pslib.o position.o parser2.o $(LNK) -o yaps.exe parseabc.o yapstree.o drawtune.o debug.o \ position.o pslib.o parser2.o # common parser object code # parseabc.o : parseabc.c abc.h parseabc.h $(CC) $(CFLAGS) parseabc.c parser2.o : parser2.c parseabc.h parser2.h $(CC) $(CFLAGS) parser2.c # objects needed by abc2abc # toabc.o : toabc.c abc.h parseabc.h $(CC) $(CFLAGS) toabc.c # objects needed by abc2midi # store.o : store.c abc.h parseabc.h parser2.h genmidi.h $(CC) $(CFLAGS) store.c genmidi.o : genmidi.c abc.h midifile.h genmidi.h $(CC) $(CFLAGS) genmidi.c stresspat.o: stresspat.c $(CC) $(CFLAGS) stresspat.c # could use -DNOFTELL here tomidi.o : tomidi.c abc.h midifile.h $(CC) $(CFLAGS) tomidi.c queues.o: queues.c genmidi.h $(CC) $(CFLAGS) queues.c midicopy.o: midicopy.c midicopy.h $(CC) $(CFLAGS) midicopy.c abcmatch.o: abcmatch.c abc.h $(CC) $(CFLAGS) abcmatch.c # common midifile library # # could use -DNOFTELL here midifile.o : midifile.c midifile.h $(CC) $(CFLAGS) midifile.c # objects needed by yaps # yapstree.o: yapstree.c abc.h parseabc.h structs.h drawtune.h parser2.h $(CC) $(CFLAGS) yapstree.c drawtune.o: drawtune.c structs.h sizes.h abc.h drawtune.h $(CC) $(CFLAGS) drawtune.c pslib.o: pslib.c drawtune.h $(CC) $(CFLAGS) pslib.c position.o: position.c abc.h structs.h sizes.h $(CC) $(CFLAGS) position.c debug.o: debug.c structs.h abc.h $(CC) $(CFLAGS) debug.c # objects needed by midi2abc # midi2abc.o : midi2abc.c midifile.h $(CC) $(CFLAGS) midi2abc.c # objects for mftext # crack.o : crack.c $(CC) $(CFLAGS) crack.c mftext.o : mftext.c midifile.h $(CC) $(CFLAGS) mftext.c # objects for abcmatch # matchsup.o : matchsup.c abc.h parseabc.h parser2.h $(CC) $(CFLAGS) matchsup.c clean: del *.o del *.exe zipfile: midi2abc.exe abc2midi.exe mftext.exe yaps.exe\ abc2abc.exe midicopy.exe zip pcexe2.zip *.exe readme.txt abcguide.txt demo.abc yaps.txt abcmidi/makefiles/makefile.wd0000644000000000000000000000772711736126532015240 0ustar rootroot# Watcom DOS 32 bit Makefile for abcMIDI package # Use mingw or gnu standard make program with this makefile. # # # compilation #ifdefs - you may need to change these defined to get # the code to compile with a different C compiler. # # NOFTELL in midifile.c and genmidi.c selects a version of the file-writing # code which doesn't use file seeking. # # PCCFIX in mftext.c midifile.c midi2abc.c # comments out various things that aren't available in PCC # # USE_INDEX causes index() to be used instead of strchr(). This is needed # by some pre-ANSI C compilers. # # ASCTIME causes asctime() to be used instead of strftime() in pslib.c. # If ANSILIBS is not set, neither routine is used. # # ANSILIBS causes code to include some ANSI standard headers # # KANDR selects functions prototypes without argument prototypes. # CC=wcc386 CFLAGS=-ic:\\watcom\\h -w4 -e25 -zq -od -d2 -5r -bt=dos -mf -DANSILIBS LDFLAGS=sys dos4g name LDFLAGS2=d all op inc op st=200000 op maxe=25 op q op symf LNK=wlink all : abc2midi.exe midi2abc.exe abc2abc.exe mftext.exe yaps.exe midicopy.exe abcmatch.exe abc2midi.exe : parseabc.obj store.obj genmidi.obj queues.obj midifile.obj parser2.obj -lm $(LNK) $(LDFLAGS) abc2midi.exe $(LDFLAGS2) FILE parseabc.obj FILE genmidi.obj FILE store.obj \ FILE queues.obj FILE midifile.obj FILE parser2.obj FILE stresspat.obj abc2abc.exe : parseabc.obj toabc.obj $(LNK) $(LDFLAGS) abc2abc.exe $(LDFLAGS2) FILE parseabc.obj FILE toabc.obj midi2abc.exe : midifile.obj midi2abc.obj $(LNK) $(LDFLAGS) midi2abc.exe $(LDFLAGS2) FILE midifile.obj FILE midi2abc.obj mftext.exe : midifile.obj mftext.obj crack.obj $(LNK) $(LDFLAGS) mftext.exe $(LDFLAGS2) FILE midifile.obj FILE mftext.obj FILE crack.obj midicopy.exe: midicopy.obj $(LNK) $(LDFLAGS) midicopy.exe $(LDFLAGS2) FILE midicopy.obj abcmatch.exe : abcmatch.obj matchsup.obj parseabc.obj $(LNK) $(LDFLAGS) abcmatch.exe $(LDFLAGS) FILE abcmatch.obj matchsup.obj parseabc.obj yaps.exe : parseabc.obj yapstree.obj drawtune.obj debug.obj pslib.obj position.obj parser2.obj $(LNK) $(LDFLAGS) yaps.exe $(LDFLAGS2) FILE parseabc.obj FILE yapstree.obj FILE drawtune.obj FILE debug.obj FILE position.obj FILE pslib.obj FILE parser2.obj # common parser object code # parseabc.obj : parseabc.c abc.h parseabc.h $(CC) $(CFLAGS) parseabc.c parser2.obj : parser2.c parseabc.h parser2.h $(CC) $(CFLAGS) parser2.c # objects needed by abc2abc # toabc.obj : toabc.c abc.h parseabc.h $(CC) $(CFLAGS) toabc.c # objects needed by abc2midi # store.obj : store.c abc.h parseabc.h parser2.h genmidi.h $(CC) $(CFLAGS) store.c genmidi.obj : genmidi.c abc.h midifile.h genmidi.h $(CC) $(CFLAGS) genmidi.c stresspat.obj : stresspat.c $(CC) $(CFLAGS) stresspat.c # could use -DNOFTELL here queues.obj: queues.c genmidi.h $(CC) $(CFLAGS) queues.c # common midifile library # # could use -DNOFTELL here midifile.obj : midifile.c midifile.h $(CC) $(CFLAGS) midifile.c # objects needed by yaps # yapstree.obj: yapstree.c abc.h parseabc.h structs.h drawtune.h parser2.h $(CC) $(CFLAGS) yapstree.c drawtune.obj: drawtune.c structs.h sizes.h abc.h drawtune.h $(CC) $(CFLAGS) drawtune.c pslib.obj: pslib.c drawtune.h $(CC) $(CFLAGS) pslib.c position.obj: position.c abc.h structs.h sizes.h $(CC) $(CFLAGS) position.c debug.obj: debug.c structs.h abc.h $(CC) $(CFLAGS) debug.c # objects needed by midi2abc # midi2abc.obj : midi2abc.c midifile.h $(CC) $(CFLAGS) midi2abc.c # objects for mftext # crack.obj : crack.c $(CC) $(CFLAGS) crack.c mftext.obj : mftext.c midifile.h $(CC) $(CFLAGS) mftext.c # objects for midicopy # midicopy.obj :midicopy.c midicopy.h $(CC) $(CFLAGS) midicopy.c # objects for abcmatch # abcmatch.obj :abcmatch.c abc.h $(CC) $(CFLAGS) abcmatch.c matchsup.obj :matchsup.c abc.h parseabc.h parser2.h $(CC) $(CFLAGS) matchsup.c clean: rm *.obj rm *.exe zipfile: midi2abc.exe abc2midi.exe mftext.exe yaps.exe abc2abc.exe zip pcexe2.zip *.exe readme.txt abcguide.txt demo.abc yaps.txt abcmidi/makefiles/makefile.w320000777000000000000000000000515512610703512015230 0ustar rootroot # tested with MS Visual C++ 2010 Express # build with: # nmake /F makefiles\makefile.w32 all !include # $(cvars) static link # $(cvarsdll) dynamically link # add -O2 to end of line for speed optimization # add -O1 for size optimization #comp = $(cc) /wd4996 -D_CRT_SECURE_NO_WARNINGS $(cflags) $(cvars) comp = $(cc) /wd4996 -D_CRT_SECURE_NO_WARNINGS $(cflags) $(cvarsdll) #all: abc2midi midi2abc abc2abc mftext yaps midicopy abcmatch all: abc2midi.exe midi2abc.exe abc2abc.exe mftext.exe yaps.exe midicopy.exe abcmatch.exe abc2midi.exe: parseabc.obj store.obj genmidi.obj midifile.obj queues.obj parser2.obj stresspat.obj $(link) $(conflags) -out:abc2midi.exe parseabc.obj store.obj genmidi.obj queues.obj parser2.obj midifile.obj stresspat.obj abcmatch.exe: abcmatch.obj matchsup.obj parseabc.obj $(link) $(conflags) -out:abcmatch.exe abcmatch.obj matchsup.obj parseabc.obj midi2abc.exe: midifile.obj midi2abc.obj $(link) $(conflags) -out:midi2abc.exe midifile.obj midi2abc.obj abc2abc.exe: parseabc.obj toabc.obj $(link) $(conflags) -out:abc2abc.exe parseabc.obj toabc.obj mftext.exe: midifile.obj mftext.obj crack.obj $(link) $(conflags) -out:mftext.exe midifile.obj mftext.obj crack.obj midicopy.exe: midicopy.obj $(link) $(conflags) -out:midicopy.exe midicopy.obj yaps.exe: parseabc.obj yapstree.obj drawtune.obj debug.obj pslib.obj position.obj parser2.obj $(link) $(conflags) -out:yaps.exe parseabc.obj yapstree.obj drawtune.obj debug.obj position.obj pslib.obj parser2.obj $(conlibs) abcmatch.obj: abcmatch.c abc.h $(comp) abcmatch.c crack.obj: crack.c $(comp) crack.c debug.obj: debug.c structs.h abc.h $(comp) debug.c drawtune.obj: drawtune.c structs.h sizes.h abc.h drawtune.h $(comp) drawtune.c genmidi.obj: genmidi.c abc.h midifile.h genmidi.h $(comp) genmidi.c matchsup.obj: matchsup.c abc.h parseabc.h parser2.h $(comp) matchsup.c mftext.obj: mftext.c midifile.h $(comp) mftext.c midi2abc.obj: midi2abc.c midifile.h $(comp) midi2abc.c midifile.obj: midifile.c midifile.h $(comp) midifile.c parseabc.obj: parseabc.c abc.h parseabc.h $(comp) parseabc.c parser2.obj: parser2.c abc.h parseabc.h parser2.h $(comp) parser2.c position.obj: position.c abc.h structs.h sizes.h $(comp) position.c pslib.obj: pslib.c drawtune.h $(comp) pslib.c queues.obj: queues.c genmidi.h $(comp) queues.c store.obj: store.c abc.h parseabc.h midifile.h genmidi.h $(comp) store.c stresspat.obj: stresspat.c $(comp) stresspat.c toabc.obj: toabc.c abc.h parseabc.h $(comp) toabc.c yapstree.obj: yapstree.c abc.h parseabc.h structs.h drawtune.h $(comp) yapstree.c clean: del *.obj del *.exe abcmidi/makefiles/unix.mak0000644000000000000000000000712311736126560014573 0ustar rootroot# Generic unix/gcc Makefile for abcMIDI package # # # compilation #ifdefs - you need to compile with these defined to get # the code to compile with PCC. # # NOFTELL in midifile.c and genmidi.c selects a version of the file-writing # code which doesn't use file seeking. # # PCCFIX in mftext.c midifile.c midi2abc.c # comments out various things that aren't available in PCC # # ANSILIBS includes some ANSI header files (which gcc can live without, # but other compilers may want). # # USE_INDEX causes index() to be used instead of strchr(). This is needed # by some pre-ANSI C compilers. # # ASCTIME causes asctime() to be used instead of strftime() in pslib.c. # If ANSILIBS is not set, neither routine is used. # # KANDR selects functions prototypes without argument prototypes. # currently yaps will only compile in ANSI mode. # # # On running make, you may get the mysterious message : # # ', needed by `parseabc.o'. Stop `abc.h # # This means you are using GNU make and this file is in DOS text format. To # cure the problem, change this file from using PC-style end-of-line (carriage # return and line feed) to unix style end-of-line (line feed). CC=gcc CFLAGS=-DANSILIBS -O2 LNK=gcc INSTALL=install prefix=/usr/local binaries=abc2midi midi2abc abc2abc mftext yaps midicopy abcmatch docdir=share/doc/abcmidi bindir=bin mandir=share/man/man1 all : abc2midi midi2abc abc2abc mftext yaps midicopy abcmatch abc2midi : parseabc.o store.o genmidi.o midifile.o queues.o parser2.o stresspat.o -lm $(LNK) -o abc2midi parseabc.o store.o genmidi.o queues.o \ parser2.o midifile.o stresspat.o abc2abc : parseabc.o toabc.o $(LNK) -o abc2abc parseabc.o toabc.o midi2abc : midifile.o midi2abc.o $(LNK) midifile.o midi2abc.o -o midi2abc mftext : midifile.o mftext.o crack.o $(LNK) midifile.o mftext.o crack.o -o mftext yaps : parseabc.o yapstree.o drawtune.o debug.o pslib.o position.o parser2.o $(LNK) -o yaps parseabc.o yapstree.o drawtune.o debug.o \ position.o pslib.o parser2.o -o yaps midicopy : midicopy.o $(LNK) -o midicopy midicopy.o abcmatch : abcmatch.o matchsup.o parseabc.o $(LNK) abcmatch.o matchsup.o parseabc.o -o abcmatch parseabc.o : parseabc.c abc.h parseabc.h parser2.o : parser2.c abc.h parseabc.h parser2.h toabc.o : toabc.c abc.h parseabc.h # could use -DNOFTELL here genmidi.o : genmidi.c abc.h midifile.h genmidi.h stresspat.o : stresspat.c store.o : store.c abc.h parseabc.h midifile.h genmidi.h queues.o : queues.c genmidi.h # could use -DNOFTELL here midifile.o : midifile.c midifile.h midi2abc.o : midi2abc.c midifile.h midicopy.o : midicopy.c midicopy.h abcmatch.o: abcmatch.c abc.h crack.o : crack.c mftext.o : mftext.c midifile.h # objects needed by yaps # yapstree.o: yapstree.c abc.h parseabc.h structs.h drawtune.h drawtune.o: drawtune.c structs.h sizes.h abc.h drawtune.h pslib.o: pslib.c drawtune.h position.o: position.c abc.h structs.h sizes.h debug.o: debug.c structs.h abc.h #objects for abcmatch # matchsup.o : matchsup.c abc.h parseabc.h parser2.h clean : rm *.o ${binaries} install: abc2midi midi2abc abc2abc mftext midicopy yaps abcmatch $(INSTALL) -m 755 ${binaries} ${prefix}/${bindir} # install documentation test -d ${PREFIX}/share/doc/abcmidi || mkdir -p ${prefix}/${docdir} $(INSTALL) -m 644 doc/*.txt ${prefix}/${docdir} $(INSTALL) -m 644 doc/AUTHORS ${prefix}/${docdir} $(INSTALL) -m 644 doc/CHANGES ${prefix}/${docdir} $(INSTALL) -m 644 VERSION ${prefix}/${docdir} # install manpages test -d ${prefix}/${mandir} || mkdir -p ${prefix}/${mandir}; $(INSTALL) -m 644 doc/*.1 ${prefix}/${mandir} abcmidi/makefiles/makefile.wat0000644000000000000000000001012411736126350015400 0ustar rootroot# Watcom Win32 Makefile for abcMIDI package # Use mingw or gnu standard make program with this makefile. # # # compilation #ifdefs - you may need to change these defined to get # the code to compile with a different C compiler. # # NOFTELL in midifile.c and genmidi.c selects a version of the file-writing # code which doesn't use file seeking. # # PCCFIX in mftext.c midifile.c midi2abc.c # comments out various things that aren't available in PCC # # USE_INDEX causes index() to be used instead of strchr(). This is needed # by some pre-ANSI C compilers. # # ASCTIME causes asctime() to be used instead of strftime() in pslib.c. # If ANSILIBS is not set, neither routine is used. # # ANSILIBS causes code to include some ANSI standard headers # # KANDR selects functions prototypes without argument prototypes. # CC=wcc386 CFLAGS=-ic:\\watcom\\h;c:\\watcom\\h\\nt -w4 -e25 -zq -od -d2 -5r -bt=nt -mf -DANSILIBS LDFLAGS=sys nt name LDFLAGS2=d all op inc op st=200000 op maxe=25 op q op symf LNK=wlink all : abc2midi.exe midi2abc.exe abc2abc.exe mftext.exe yaps.exe midicopy.exe abcmatch.exe abc2midi.exe : parseabc.obj store.obj genmidi.obj queues.obj midifile.obj parser2.obj stresspat.obj -lm $(LNK) $(LDFLAGS) abc2midi.exe $(LDFLAGS2) FILE parseabc.obj FILE genmidi.obj FILE store.obj \ FILE queues.obj FILE midifile.obj FILE parser2.obj FILE stresspat.obj abc2abc.exe : parseabc.obj toabc.obj $(LNK) $(LDFLAGS) abc2abc.exe $(LDFLAGS2) FILE parseabc.obj FILE toabc.obj midi2abc.exe : midifile.obj midi2abc.obj $(LNK) $(LDFLAGS) midi2abc.exe $(LDFLAGS2) FILE midifile.obj FILE midi2abc.obj mftext.exe : midifile.obj mftext.obj crack.obj $(LNK) $(LDFLAGS) mftext.exe $(LDFLAGS2) FILE midifile.obj FILE mftext.obj FILE crack.obj midicopy.exe : midicopy.obj $(LNK) $(LDFLAGS) midicopy.exe $(LDFLAGS2) FILE midicopy.obj yaps.exe : parseabc.obj yapstree.obj drawtune.obj debug.obj pslib.obj position.obj parser2.obj $(LNK) $(LDFLAGS) yaps.exe $(LDFLAGS2) FILE parseabc.obj FILE yapstree.obj FILE drawtune.obj FILE debug.obj FILE position.obj FILE pslib.obj FILE parser2.obj abcmatch.exe : abcmatch.obj matchsup.obj parseabc.obj $(LNK) $(LDFLAGS) abcmatch.exe $(LDFLAGS2) FILE abcmatch.obj FILE matchsup.obj FILE parseabc.obj # common parser object code # parseabc.obj : parseabc.c abc.h parseabc.h $(CC) $(CFLAGS) parseabc.c parser2.obj : parser2.c parseabc.h parser2.h $(CC) $(CFLAGS) parser2.c # objects needed by abc2abc # toabc.obj : toabc.c abc.h parseabc.h $(CC) $(CFLAGS) toabc.c # objects needed by abc2midi # store.obj : store.c abc.h parseabc.h parser2.h genmidi.h $(CC) $(CFLAGS) store.c genmidi.obj : genmidi.c abc.h midifile.h genmidi.h $(CC) $(CFLAGS) genmidi.c stresspat.obj : stresspat.c $(CC) $(CFLAGS) stresspat.c # could use -DNOFTELL here tomidi.obj : tomidi.c abc.h midifile.h $(CC) $(CFLAGS) tomidi.c queues.obj: queues.c genmidi.h $(CC) $(CFLAGS) queues.c # common midifile library # # could use -DNOFTELL here midifile.obj : midifile.c midifile.h $(CC) $(CFLAGS) midifile.c # objects needed by yaps # yapstree.obj: yapstree.c abc.h parseabc.h structs.h drawtune.h parser2.h $(CC) $(CFLAGS) yapstree.c drawtune.obj: drawtune.c structs.h sizes.h abc.h drawtune.h $(CC) $(CFLAGS) drawtune.c pslib.obj: pslib.c drawtune.h $(CC) $(CFLAGS) pslib.c position.obj: position.c abc.h structs.h sizes.h $(CC) $(CFLAGS) position.c debug.obj: debug.c structs.h abc.h $(CC) $(CFLAGS) debug.c # objects needed by midi2abc # midi2abc.obj : midi2abc.c midifile.h $(CC) $(CFLAGS) midi2abc.c # objects for mftext # crack.obj : crack.c $(CC) $(CFLAGS) crack.c mftext.obj : mftext.c midifile.h $(CC) $(CFLAGS) mftext.c # objects for midicopy # midicopy.obj : midicopy.c midicopy.h $(CC) $(CFLAGS) midicopy.c #objects for abcmtch # abcmatch.obj : abcmatch.c abc.h $(CC) $(CFLAGS) abcmatch.c matchsup.obj : matchsup.c abc.h parseabc.h parser2.h genmidi.h $(CC) $(CFLAGS) matchsup.c clean: rm *.obj rm *.exe zipfile: midi2abc.exe abc2midi.exe mftext.exe yaps.exe abc2abc.exe abcmatch.exe zip pcexe2.zip *.exe readme.txt abcguide.txt demo.abc yaps.txt abcmidi/makefiles/makefile.ming0000644000000000000000000000674211736126320015547 0ustar rootroot# Mingw Win32 Makefile for abcMIDI package # # # compilation #ifdefs - you may need to change these defined to get # the code to compile with a different C compiler. # # NOFTELL in midifile.c and tomidi.c selects a version of the file-writing # code which doesn't use file seeking. # # PCCFIX in mftext.c midifile.c midi2abc.c # comments out various things that aren't available in PCC # # USE_INDEX causes index() to be used instead of strchr(). This is needed # by some pre-ANSI C compilers. # # ASCTIME causes asctime() to be used instead of strftime() in pslib.c. # If ANSILIBS is not set, neither routine is used. # # ANSILIBS causes code to include some ANSI standard headers # # KANDR selects functions prototypes without argument prototypes. # # If your mingw compiler is in another path, change the include # options below in CFLAGS. # CC=gcc CFLAGS=-c -I/mingw/i386-mingw32/include LNK=gcc LDFLAGS=-o all : abc2midi.exe midi2abc.exe abc2abc.exe mftext.exe yaps.exe \ midicopy.exe abcmatch.exe abc2midi.exe : parseabc.o store.o genmidi.o queues.o midifile.o parser2.o $(LNK) $(LDFLAGS) abc2midi.exe parseabc.o genmidi.o store.o \ queues.o midifile.o parser2.o -stresspat.o -lm abc2abc.exe : parseabc.o toabc.o $(LNK) $(LDFLAGS) abc2abc.exe parseabc.o toabc.o midi2abc.exe : midifile.o midi2abc.o $(LNK) $(LDFLAGS) midi2abc.exe midifile.o midi2abc.o mftext.exe : midifile.o mftext.o crack.o $(LNK) $(LDFLAGS) mftext.exe midifile.o mftext.o crack.o yaps.exe : parseabc.o yapstree.o drawtune.o debug.o pslib.o position.o parser2.o $(LNK) $(LDFLAGS) yaps.exe parseabc.o yapstree.o drawtune.o debug.o \ position.o pslib.o parser2.o midicopy.exe: midicopy.o $(LNK) $(LDFLAGS) midicopy.exe midicopy.o abcmatch.exe : abcmatch.o matchsup.o parseabc.o $(LNK) abcmatch.o matchsup.o parseabc.o -o abcmatch.exe # common parser object code # parseabc.o : parseabc.c abc.h parseabc.h $(CC) $(CFLAGS) parseabc.c parser2.o : parser2.c parseabc.h parser2.h $(CC) $(CFLAGS) parser2.c # objects needed by abc2abc # toabc.o : toabc.c abc.h parseabc.h $(CC) $(CFLAGS) toabc.c # objects needed by abc2midi # store.o : store.c abc.h parseabc.h parser2.h genmidi.h $(CC) $(CFLAGS) store.c genmidi.o : genmidi.c abc.h midifile.h genmidi.h $(CC) $(CFLAGS) genmidi.c stresspat.o : stresspat.c $(CC) $(CFLAGS) stresspat.c # could use -DNOFTELL here tomidi.o : tomidi.c abc.h midifile.h $(CC) $(CFLAGS) tomidi.c queues.o: queues.c genmidi.h $(CC) $(CFLAGS) queues.c # common midifile library # # could use -DNOFTELL here midifile.o : midifile.c midifile.h $(CC) $(CFLAGS) midifile.c # objects needed by yaps # yapstree.o: yapstree.c abc.h parseabc.h structs.h drawtune.h parser2.h $(CC) $(CFLAGS) yapstree.c drawtune.o: drawtune.c structs.h sizes.h abc.h drawtune.h $(CC) $(CFLAGS) drawtune.c pslib.o: pslib.c drawtune.h $(CC) $(CFLAGS) pslib.c position.o: position.c abc.h structs.h sizes.h $(CC) $(CFLAGS) position.c debug.o: debug.c structs.h abc.h $(CC) $(CFLAGS) debug.c # objects needed by midi2abc # midi2abc.o : midi2abc.c midifile.h $(CC) $(CFLAGS) midi2abc.c # objects for mftext # crack.o : crack.c $(CC) $(CFLAGS) crack.c mftext.o : mftext.c midifile.h $(CC) $(CFLAGS) mftext.c # objects needed for midicopy # midicopy.o : midicopy.c $(CC) $(CFLAGS) midicopy.c clean: rm *.o rm *.exe zipfile: midi2abc.exe abc2midi.exe mftext.exe yaps.exe abc2abc.exe midicopy.exe zip pcexe2.zip *.exe readme.txt abcguide.txt demo.abc yaps.txt abcmidi/midi2abc.c0000644000000000000000000026315112610701432012766 0ustar rootroot/* * midi2abc - program to convert MIDI files to abc notation. * Copyright (C) 1998 James Allwright * e-mail: J.R.Allwright@westminster.ac.uk * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA * */ /* new midi2abc - converts MIDI file to abc format files * * * re-written to use dynamic data structures * James Allwright * 5th June 1998 * * added output file option -o * added summary option -sum * added option -u to enter xunit directly * fixed computation of xunit using -b option * added -obpl (one bar per line) option * add check for carriage return embedded inside midi text line * Seymour Shlien 04/March/00 * made to conform as much as possible to the official version. * check for drum track added * when midi program channel is command encountered, we ensure that * we are using the correct channel number for the Voice by sending * a %%MIDI channel message. * * Many more changes (see doc/CHANGES) * * Seymour Shlien 2005 * * based on public domain 'midifilelib' package. */ #define VERSION "2.99 October 18 2015" #define SPLITCODE /* Microsoft Visual C++ Version 6.0 or higher */ #ifdef _MSC_VER #define ANSILIBS #endif #include #ifdef PCCFIX #define stdout 1 #endif /* define USE_INDEX if your C libraries have index() instead of strchr() */ #ifdef USE_INDEX #define strchr index #endif #ifdef ANSILIBS #include #include #include #else extern char* malloc(); extern char* strchr(); #endif #include "midifile.h" #define BUFFSIZE 200 /* declare MIDDLE C */ #define MIDDLE 72 void initfuncs(); void setupkey(int); int testtrack(int trackno, int barbeats, int anacrusis); int open_note(int chan, int pitch, int vol); int close_note(int chan, int pitch, int *initvol); /* Global variables and structures */ extern long Mf_toberead; static FILE *F; static FILE *outhandle; /* for producing the abc file */ int tracknum=0; /* track number */ int division; /* pulses per quarter note defined in MIDI header */ long tempo = 500000; /* the default tempo is 120 quarter notes/minute */ int unitlen; /* abc unit length usually defined in L: field */ int header_unitlen; /* first unitlen set */ int unitlen_set =0; /* once unitlen is set don't allow it to change */ int parts_per_unitlen = 2; /* specifies minimum quantization size */ long laston = 0; /* length of MIDI track in pulses or ticks */ char textbuff[BUFFSIZE]; /*buffer for handling text output to abc file*/ int trans[256], back[256]; /*translation tables for MIDI pitch to abc note*/ char atog[256]; /* translation tables for MIDI pitch to abc note */ int symbol[256]; /*translation tables for MIDI pitch to abc note */ int key[12]; int sharps; int trackno, maintrack; int format; /* MIDI file type */ int karaoke, inkaraoke; int midline; int tempocount=0; /* number of tempo indications in MIDI file */ int gotkeysig=0; /*set to 1 if keysignature found in MIDI file */ /* global parameters that may be set by command line options */ int xunit; /* pulses per abc unit length */ int tsig_set; /* flag - time signature already set by user */ int ksig_set; /* flag - key signature already set by user */ int xunit_set;/* flat - xunit already set by user */ int extracta; /* flag - get anacrusis from strong beat */ int guessu; /* flag - estimate xunit from note durations */ int guessa; /* flag - get anacrusis by minimizing tied notes */ int guessk; /* flag - guess key signature */ int summary; /* flag - output summary info of MIDI file */ int keep_short; /*flag - preserve short notes */ int swallow_rests; /* flag - absorb short rests */ int midiprint; /* flag - run midigram instead of midi2abc */ #ifdef SPLITCODE int usesplits; /* flag - split measure into parts if needed */ #endif int restsize; /* smallest rest to absorb */ int no_triplets; /* flag - suppress triplets or broken rhythm */ int obpl = 0; /* flag to specify one bar per abc text line */ int nogr = 0; /* flag to put a space between every note */ int bars_per_line=4; /* number of bars per output line */ int bars_per_staff=4; /* number of bars per music staff */ int asig, bsig; /* time signature asig/bsig */ int header_asig =0; /* first time signature encountered */ int header_bsig =0; /* first time signature encountered */ int header_bb; /* first ticks/quarter note encountered */ int active_asig,active_bsig; /* last time signature declared */ int last_asig, last_ksig; /* last time signature printed */ int barsize; /* barsize in parts_per_unitlen units */ int Qval; /* tempo - quarter notes per minute */ int verbosity=0; /* control amount of detail messages in abcfile*/ /* global arguments dependent on command line options or computed */ int anacrusis=0; int bars; int keysig; int header_keysig= -50; /* header key signature */ int active_keysig = -50; /* last key signature declared */ int xchannel; /* channel number to be extracted. -1 means all */ /* structure for storing music notes */ struct anote { int pitch; /* MIDI pitch */ int chan; /* MIDI channel */ int vel; /* MIDI velocity */ long time; /* MIDI onset time in pulses */ long dtnext; /* time increment to next note in pulses */ long tplay; /* note duration in pulses */ int xnum; /* number of xunits to next note */ int playnum; /* note duration in number of xunits */ int posnum; /* note position in xunits */ int splitnum; /* voice split number */ /* int denom; */ }; /* linked list of notes */ struct listx { struct listx* next; struct anote* note; }; /* linked list of text items (strings) */ struct tlistx { struct tlistx* next; char* text; long when; /* time in pulses to output */ int type; /* 0 - comments, other - field commands */ }; /* a MIDI track */ struct atrack { struct listx* head; /* first note */ struct listx* tail; /* last note */ struct tlistx* texthead; /* first text string */ struct tlistx* texttail; /* last text string */ int notes; /* number of notes in track */ long tracklen; long startwait; int startunits; int drumtrack; }; /* can cope with up to 64 track MIDI files */ struct atrack track[64]; int trackcount = 0; int maxbarcount = 0; /* maxbarcount is used to return the numbers of bars created.*/ /* obpl is a flag for one bar per line. */ /* double linked list of notes */ /* used for temporary list of chords while abc is being generated */ struct dlistx { struct dlistx* next; struct dlistx* last; struct anote* note; }; int notechan[2048],notechanvol[2048]; /*for linking on and off midi channel commands */ int last_tick; /* for getting last pulse number in MIDI file */ char *title = NULL; /* for pasting title from argv[] */ char *origin = NULL; /* for adding O: info from argv[] */ void remove_carriage_returns(); int validnote(); void printpitch(struct anote*); void printfract(int, int); /* Stage 1. Parsing MIDI file */ /* Functions called during the reading pass of the MIDI file */ /* The following C routines are required by midifilelib. */ /* They specify the action to be taken when various items */ /* are encountered in the MIDI. The mfread function scans*/ /* the MIDI file and calls these functions when needed. */ int filegetc() { return(getc(F)); } void fatal_error(s) char* s; /* fatal error encounterd - abort program */ { fprintf(stderr, "%s\n", s); exit(1); } void event_error(s) char *s; /* problem encountered but OK to continue */ { char msg[256]; sprintf(msg, "Error: Time=%ld Track=%d %s\n", Mf_currtime, trackno, s); printf("%s",msg); } int* checkmalloc(bytes) /* malloc with error checking */ int bytes; { int *p; p = (int*) malloc(bytes); if (p == NULL) { fatal_error("Out of memory error - cannot malloc!"); }; return (p); } char* addstring(s) /* create space for string and store it in memory */ char* s; { char* p; p = (char*) checkmalloc(strlen(s)+1); strcpy(p, s); return(p); } void addtext(s, type) /* add structure for text */ /* used when parsing MIDI file */ char* s; int type; { struct tlistx* newx; newx = (struct tlistx*) checkmalloc(sizeof(struct tlistx)); newx->next = NULL; newx->text = addstring(s); newx->type = type; newx->when = Mf_currtime; if (track[trackno].texthead == NULL) { track[trackno].texthead = newx; track[trackno].texttail = newx; } else { track[trackno].texttail->next = newx; track[trackno].texttail = newx; }; } /* The MIDI file has separate commands for starting */ /* and stopping a note. In order to determine the duration of */ /* the note it is necessary to find the note_on command associated */ /* with the note off command. We rely on the note's pitch and channel*/ /* number to find the right note. While we are parsing the MIDI file */ /* we maintain a list of all the notes that are currently on */ /* head and tail of list of notes still playing. */ /* The following doubly linked list is used for this purpose */ struct dlistx* playinghead; struct dlistx* playingtail; void noteplaying(p) /* This function adds a new note to the playinghead list. */ struct anote* p; { struct dlistx* newx; newx = (struct dlistx*) checkmalloc(sizeof(struct dlistx)); newx->note = p; newx->next = NULL; newx->last = playingtail; if (playinghead == NULL) { playinghead = newx; }; if (playingtail == NULL) { playingtail = newx; } else { playingtail->next = newx; playingtail = newx; }; } void addnote(p, ch, v) /* add structure for note */ /* used when parsing MIDI file */ int p, ch, v; { struct listx* newx; struct anote* newnote; track[trackno].notes = track[trackno].notes + 1; newx = (struct listx*) checkmalloc(sizeof(struct listx)); newnote = (struct anote*) checkmalloc(sizeof(struct anote)); newx->next = NULL; newx->note = newnote; if (track[trackno].head == NULL) { track[trackno].head = newx; track[trackno].tail = newx; } else { track[trackno].tail->next = newx; track[trackno].tail = newx; }; if (ch == 9) { track[trackno].drumtrack = 1; }; newnote->pitch = p; newnote->chan = ch; newnote->vel = v; newnote->time = Mf_currtime; laston = Mf_currtime; newnote->tplay = Mf_currtime; noteplaying(newnote); } void notestop(p, ch) /* MIDI note stops */ /* used when parsing MIDI file */ int p, ch; { struct dlistx* i; int found; char msg[80]; i = playinghead; found = 0; while ((found == 0) && (i != NULL)) { if ((i->note->pitch == p)&&(i->note->chan==ch)) { found = 1; } else { i = i->next; }; }; if (found == 0) { sprintf(msg, "Note terminated when not on - pitch %d", p); event_error(msg); return; }; /* fill in tplay field */ i->note->tplay = Mf_currtime - (i->note->tplay); /* remove note from list */ if (i->last == NULL) { playinghead = i->next; } else { (i->last)->next = i->next; }; if (i->next == NULL) { playingtail = i->last; } else { (i->next)->last = i->last; }; free(i); } FILE * efopen(name,mode) char *name; char *mode; { FILE *f; if ( (f=fopen(name,mode)) == NULL ) { char msg[256]; sprintf(msg,"Error - Cannot open file %s",name); fatal_error(msg); } return(f); } void error(s) char *s; { fprintf(stderr,"Error: %s\n",s); } void txt_header(xformat,ntrks,ldivision) int xformat, ntrks, ldivision; { division = ldivision; format = xformat; if (format != 0) { /* fprintf(outhandle,"%% format %d file %d tracks\n", format, ntrks);*/ if(summary>0) printf("This midi file has %d tracks\n\n",ntrks); } else { /* fprintf(outhandle,"%% type 0 midi file\n"); */ if(summary>0) { printf("This is a type 0 midi file.\n"); printf("All the channels are in one track.\n"); printf("You may need to process the channels separately\n\n"); } } } void txt_trackstart() { laston = 0L; track[trackno].notes = 0; track[trackno].head = NULL; track[trackno].tail = NULL; track[trackno].texthead = NULL; track[trackno].texttail = NULL; track[trackno].tracklen = Mf_currtime; track[trackno].drumtrack = 0; } void txt_trackend() { /* check for unfinished notes */ if (playinghead != NULL) { printf("Error in MIDI file - notes still on at end of track!\n"); }; track[trackno].tracklen = Mf_currtime - track[trackno].tracklen; trackno = trackno + 1; trackcount = trackcount + 1; } void txt_noteon(chan,pitch,vol) int chan, pitch, vol; { if ((xchannel == -1) || (chan == xchannel)) { if (vol != 0) { addnote(pitch, chan, vol); } else { notestop(pitch, chan); }; }; } void txt_noteoff(chan,pitch,vol) int chan, pitch, vol; { if ((xchannel == -1) || (chan == xchannel)) { notestop(pitch, chan); }; } void txt_pressure(chan,pitch,press) int chan, pitch, press; { } void txt_parameter(chan,control,value) int chan, control, value; { } void txt_pitchbend(chan,lsb,msb) int chan, msb, lsb; { } void txt_program(chan,program) int chan, program; { /* sprintf(textbuff, "%%%%MIDI program %d %d", chan+1, program); */ sprintf(textbuff, "%%%%MIDI program %d", program); addtext(textbuff,0); /* abc2midi does not use the same channel number as specified in the original midi file, so we should not specify that channel number in the %%MIDI program. If we leave it out the program will refer to the current channel assigned to this voice. */ } void txt_chanpressure(chan,press) int chan, press; { } void txt_sysex(leng,mess) int leng; char *mess; { } void txt_metamisc(type,leng,mess) int type, leng; char *mess; { } void txt_metaspecial(type,leng,mess) int type, leng; char *mess; { } void txt_metatext(type,leng,mess) int type, leng; char *mess; { char *ttype[] = { NULL, "Text Event", /* type=0x01 */ "Copyright Notice", /* type=0x02 */ "Sequence/Track Name", "Instrument Name", /* ... */ "Lyric", "Marker", "Cue Point", /* type=0x07 */ "Unrecognized" }; int unrecognized = (sizeof(ttype)/sizeof(char *)) - 1; unsigned char c; int n; char *p = mess; char *buff; char buffer2[BUFFSIZE]; if ((type < 1)||(type > unrecognized)) type = unrecognized; buff = textbuff; for (n=0; n0) return; /* ignore other tempo indications */ tempo = ltempo; tempocount++; } void setup_timesig(nn, denom, bb) int nn,denom,bb; { asig = nn; bsig = denom; /* we must keep unitlen and xunit fixed for the entire tune */ if (unitlen_set == 0) { unitlen_set = 1; if ((asig*4)/bsig >= 3) { unitlen =8; } else { unitlen = 16; }; } /* set xunit for this unitlen */ if(!xunit_set) xunit = (division*bb*4)/(8*unitlen); barsize = parts_per_unitlen*asig*unitlen/bsig; /* printf("setup_timesig: unitlen=%d xunit=%d barsize=%d\n",unitlen,xunit,barsize); */ if (header_asig ==0) {header_asig = asig; header_bsig = bsig; header_unitlen = unitlen; header_bb = bb; } } void txt_timesig(nn,dd,cc,bb) int nn, dd, cc, bb; { int denom = 1; while ( dd-- > 0 ) denom *= 2; sprintf(textbuff, "%% Time signature=%d/%d MIDI-clocks/click=%d 32nd-notes/24-MIDI-clocks=%d", nn,denom,cc,bb); if (verbosity) addtext(textbuff,0); sprintf(textbuff,"%d %d %d\n",nn,denom,bb); if (!tsig_set) { addtext(textbuff,2); setup_timesig(nn, denom,bb); } if (summary>0) { if(tsig_set) printf("Time signature = %d/%d suppressed\n",nn,denom); else printf("Time signature = %d/%d\n",nn,denom); } } void txt_smpte(hr,mn,se,fr,ff) int hr, mn, se, fr, ff; { } void txt_arbitrary(leng,mess) char *mess; int leng; { } /* Dummy functions for handling MIDI messages. * */ void no_op0() {} void no_op1(int dummy1) {} void no_op2(int dummy1, int dummy2) {} void no_op3(int dummy1, int dummy2, int dummy3) { } void no_op4(int dummy1, int dummy2, int dummy3, int dummy4) { } void no_op5(int dummy1, int dummy2, int dummy3, int dummy4, int dummy5) { } void print_txt_noteon(chan, pitch, vol) int chan, pitch, vol; { int start_time; int initvol; if (vol > 0) open_note(chan, pitch, vol); else { start_time = close_note(chan, pitch,&initvol); if (start_time >= 0) /* printf("%8.4f %8.4f %d %d %d %d\n", (double) start_time/(double) division, (double) Mf_currtime/(double) division, trackno+1, chan +1, pitch,initvol); */ printf("%d %ld %d %d %d %d\n", start_time, Mf_currtime, trackno+1, chan +1, pitch,initvol); if(Mf_currtime > last_tick) last_tick = Mf_currtime; } } void print_txt_noteoff(chan, pitch, vol) int chan, pitch, vol; { int start_time,initvol; start_time = close_note(chan, pitch, &initvol); if (start_time >= 0) /* printf("%8.4f %8.4f %d %d %d %d\n", (double) start_time/(double) division, (double) Mf_currtime/(double) division, trackno+1, chan+1, pitch,initvol); */ printf("%d %ld %d %d %d %d\n", start_time, Mf_currtime, trackno+1, chan +1, pitch,initvol); if(Mf_currtime > last_tick) last_tick = Mf_currtime; } /* In order to associate a channel note off message with its * corresponding note on message, we maintain the information * the notechan array. When a midi pitch (0-127) is switched * on for a particular channel, we record the time that it * was turned on in the notechan array. As there are 16 channels * and 128 pitches, we initialize an array 128*16 = 2048 elements * long. **/ void init_notechan() { /* signal that there are no active notes */ int i; for (i = 0; i < 2048; i++) notechan[i] = -1; } /* The next two functions update notechan when a channel note on or note off is encountered. The second function close_note, returns the time when the note was turned on. */ int open_note(int chan, int pitch, int vol) { notechan[128 * chan + pitch] = Mf_currtime; notechanvol[128 * chan + pitch] = vol; return 0; } int close_note(int chan, int pitch, int *initvol) { int index, start_tick; index = 128 * chan + pitch; if (notechan[index] < 0) return -1; start_tick = notechan[index]; *initvol = notechanvol[index]; notechan[index] = -1; return start_tick; } /* mftext mode */ int prtime() { /* if(Mf_currtime >= pulses) ignore=0; if (ignore) return 1; linecount++; if(linecount > maxlines) {fclose(F); exit(0);} */ int units; units = 2; if(units==1) /*seconds*/ printf("%6.2f ",mf_ticks2sec(Mf_currtime,division,tempo)); else if (units==2) /*beats*/ printf("%6.2f ",(float) Mf_currtime/(float) division); else /*pulses*/ printf("%6ld ",Mf_currtime); return 0; } char * pitch2key(int note) { static char name[5]; char* s = name; switch(note % 12) { case 0: *s++ = 'c'; break; case 1: *s++ = 'c'; *s++ = '#'; break; case 2: *s++ = 'd'; break; case 3: *s++ = 'd'; *s++ = '#'; break; case 4: *s++ = 'e'; break; case 5: *s++ = 'f'; break; case 6: *s++ = 'f'; *s++ = '#'; break; case 7: *s++ = 'g'; break; case 8: *s++ = 'g'; *s++ = '#'; break; case 9: *s++ = 'a'; break; case 10: *s++ = 'a'; *s++ = '#'; break; case 11: *s++ = 'b'; break; } sprintf(s, "%d", (note / 12)-1); /* octave (assuming Piano C4 is 60)*/ return name; } void pitch2drum(midipitch) int midipitch; { static char *drumpatches[] = { "Acoustic Bass Drum", "Bass Drum 1", "Side Stick", "Acoustic Snare", "Hand Clap", "Electric Snare", "Low Floor Tom", "Closed Hi Hat", "High Floor Tom", "Pedal Hi-Hat", "Low Tom", "Open Hi-Hat", "Low-Mid Tom", "Hi Mid Tom", "Crash Cymbal 1", "High Tom", "Ride Cymbal 1", "Chinese Cymbal", "Ride Bell", "Tambourine", "Splash Cymbal", "Cowbell", "Crash Cymbal 2", "Vibraslap", "Ride Cymbal 2", "Hi Bongo", "Low Bongo", "Mute Hi Conga", "Open Hi Conga", "Low Conga", "High Timbale", "Low Timbale", "High Agogo", "Low Agogo", "Cabasa", "Maracas", "Short Whistle", "Long Whistle", "Short Guiro", "Long Guiro", "Claves", "Hi Wood Block", "Low Wood Block", "Mute Cuica", "Open Cuica", "Mute Triangle", "Open Triangle" }; if (midipitch >= 35 && midipitch <= 81) { printf(" (%s)",drumpatches[midipitch-35]); } } void mftxt_header (int format, int ntrks, int ldivision) { division = ldivision; printf("Header format=%d ntrks=%d division=%d\n",format,ntrks,division); } void mftxt_trackstart() { int numbytes; tracknum++; numbytes = Mf_toberead; /*if(track != 0 && tracknum != track) {ignore_bytes(numbytes); return;} */ printf("Track %d contains %d bytes\n",tracknum,numbytes); } void mftxt_noteon(chan,pitch,vol) int chan, pitch, vol; { char *key; /* if (onlychan >=0 && chan != onlychan) return; */ if (prtime()) return; key = pitch2key(pitch); printf("Note on %2d %2d (%3s) %3d",chan+1, pitch, key,vol); if (chan == 9) pitch2drum(pitch); printf("\n"); } void mftxt_noteoff(chan,pitch,vol) int chan, pitch, vol; { char *key; /* if (onlychan >=0 && chan != onlychan) return; */ if (prtime()) return; key = pitch2key(pitch); printf("Note off %2d %2d (%3s) %3d\n",chan+1,pitch, key,vol); } void mftxt_pressure(chan,pitch,press) int chan, pitch, press; { char *key; if (prtime()) return; key = pitch2key(pitch); printf("Pressure %2d %3s %3d\n",chan+1,key,press); } void mftxt_pitchbend(chan,lsb,msb) int chan, lsb, msb; { float bend; int pitchbend; /* if (onlychan >=0 && chan != onlychan) return; */ if (prtime()) return; /* [SS] 2014-01-05 2015-08-04*/ pitchbend = (msb*128 + lsb); bend = (float) (pitchbend - 8192); bend = bend/4096.0f; printf("Pitchbend %2d %d bend = %6.4f\n",chan+1,pitchbend,bend); } void mftxt_program(chan,program) int chan, program; { static char *patches[] = { "Acoustic Grand","Bright Acoustic","Electric Grand","Honky-Tonk", "Electric Piano 1","Electric Piano 2","Harpsichord","Clav", "Celesta", "Glockenspiel", "Music Box", "Vibraphone", "Marimba", "Xylophone", "Tubular Bells", "Dulcimer", "Drawbar Organ", "Percussive Organ", "Rock Organ", "Church Organ", "Reed Organ", "Accordian", "Harmonica", "Tango Accordian", "Acoustic Guitar (nylon)", "Acoustic Guitar (steel)", "Electric Guitar (jazz)", "Electric Guitar (clean)", "Electric Guitar (muted)", "Overdriven Guitar", "Distortion Guitar", "Guitar Harmonics", "Acoustic Bass", "Electric Bass (finger)", "Electric Bass (pick)", "Fretless Bass", "Slap Bass 1", "Slap Bass 2", "Synth Bass 1", "Synth Bass 2", "Violin", "Viola", "Cello", "Contrabass", "Tremolo Strings", "Pizzicato Strings", "Orchestral Strings", "Timpani", "String Ensemble 1", "String Ensemble 2", "SynthStrings 1", "SynthStrings 2", "Choir Aahs", "Voice Oohs", "Synth Voice", "Orchestra Hit", "Trumpet", "Trombone", "Tuba", "Muted Trumpet", "French Horn", "Brass Section", "SynthBrass 1", "SynthBrass 2", "Soprano Sax", "Alto Sax", "Tenor Sax", "Baritone Sax", "Oboe", "English Horn", "Bassoon", "Clarinet", "Piccolo", "Flute", "Recorder", "Pan Flute", "Blown Bottle", "Skakuhachi", "Whistle", "Ocarina", "Lead 1 (square)", "Lead 2 (sawtooth)", "Lead 3 (calliope)", "Lead 4 (chiff)", "Lead 5 (charang)", "Lead 6 (voice)", "Lead 7 (fifths)", "Lead 8 (bass+lead)", "Pad 1 (new age)", "Pad 2 (warm)", "Pad 3 (polysynth)", "Pad 4 (choir)", "Pad 5 (bowed)", "Pad 6 (metallic)", "Pad 7 (halo)", "Pad 8 (sweep)", "FX 1 (rain)", "(soundtrack)", "FX 3 (crystal)", "FX 4 (atmosphere)", "FX 5 (brightness)", "FX 6 (goblins)", "FX 7 (echoes)", "FX 8 (sci-fi)", "Sitar", "Banjo", "Shamisen", "Koto", "Kalimba", "Bagpipe", "Fiddle", "Shanai", "Tinkle Bell", "Agogo", "Steel Drums", "Woodblock", "Taiko Drum", "Melodic Tom", "Synth Drum", "Reverse Cymbal", "Guitar Fret Noise", "Breath Noise", "Seashore", "Bird Tweet", "Telephone ring", "Helicopter", "Applause", "Gunshot"}; /* if (onlychan >=0 && chan != onlychan) return; */ if (prtime()) return; printf("Program %2d %d (%s)\n",chan+1, program,patches[program]); } void mftxt_chanpressure(chan,press) int chan, press; { prtime(); printf("Chanpres %2d pressure=%d\n",chan+1,press); } void mftxt_parameter(chan,control,value) int chan, control, value; { static char *ctype[] = { "Bank Select", "Modulation Wheel", /*1*/ "Breath controller", "unknown", /*3*/ "Foot Pedal", "Portamento Time", /*5*/ "Data Entry", "Volume", /*7*/ "Balance", "unknown", /*9*/ "Pan position", "Expression", /*11*/ "Effect Control 1", "Effect Control 2", /*13*/ "unknown", "unknown", /*15*/ "Slider 1", "Slider 2", /*17*/ "Slider 3", "Slider 4", /*19*/ "unknown", "unknown", /*21*/ "unknown", "unknown", /*23*/ "unknown", "unknown", /*25*/ "unknown", "unknown", /*27*/ "unknown", "unknown", /*29*/ "unknown", "unknown", /*31*/ "Bank Select (fine)", "Modulation Wheel (fine)", /*33*/ "Breath controller (fine)", "unknown", /*35*/ "Foot Pedal (fine)", "Portamento Time (fine)", /*37*/ "Data Entry (fine)", "Volume (fine)", /*39*/ "Balance (fine)", "unknown", /*41*/ "Pan position (fine)", "Expression (fine)", /*43*/ "Effect Control 1 (fine)", "Effect Control 2 (fine)", /*45*/ "unknown", "unknown", /*47*/ "unknown", "unknown", /*49*/ "unknown", "unknown", /*51*/ "unknown", "unknown", /*53*/ "unknown", "unknown", /*55*/ "unknown", "unknown", /*57*/ "unknown", "unknown", /*59*/ "unknown", "unknown", /*61*/ "unknown", "unknown", /*63*/ "Hold Pedal", "Portamento", /*65*/ "Susteno Pedal", "Soft Pedal", /*67*/ "Legato Pedal", "Hold 2 Pedal", /*69*/ "Sound Variation", "Sound Timbre", /*71*/ "Sound Release Time", "Sound Attack Time", /*73*/ "Sound Brightness", "Sound Control 6", /*75*/ "Sound Control 7", "Sound Control 8", /*77*/ "Sound Control 9", "Sound Control 10", /*79*/ "GP Button 1", "GP Button 2", /*81*/ "GP Button 3", "GP Button 4", /*83*/ "unknown", "unknown", /*85*/ "unknown", "unknown", /*87*/ "unknown", "unknown", /*89*/ "unknown", "Effects Level", /*91*/ "Tremolo Level", "Chorus Level", /*93*/ "Celeste Level", "Phaser Level", /*95*/ "Data button increment", "Data button decrement", /*97*/ "NRP (fine)", "NRP (coarse)", /*99*/ "Registered parameter (fine)", "Registered parameter (coarse)", /*101*/ "unknown", "unknown", /*103*/ "unknown", "unknown", /*105*/ "unknown", "unknown", /*107*/ "unknown", "unknown", /*109*/ "unknown", "unknown", /*111*/ "unknown", "unknown", /*113*/ "unknown", "unknown", /*115*/ "unknown", "unknown", /*117*/ "unknown", "unknown", /*119*/ "All Sound Off", "All Controllers Off", /*121*/ "Local Keyboard (on/off)","All Notes Off", /*123*/ "Omni Mode Off", "Omni Mode On", /*125*/ "Mono Operation", "Poly Operation"}; /* if (onlychan >=0 && chan != onlychan) return; */ if (prtime()) return; printf("CntlParm %2d %s = %d\n",chan+1, ctype[control],value); } void mftxt_metatext(type,leng,mess) int type, leng; char *mess; { static char *ttype[] = { NULL, "Text Event", /* type=0x01 */ "Copyright Notice", /* type=0x02 */ "Seqnce/Track Name", "Instrument Name", /* ... */ "Lyric", "Marker", "Cue Point", /* type=0x07 */ "Unrecognized" }; int unrecognized = (sizeof(ttype)/sizeof(char *)) - 1; int len; register int n, c; register char *p = mess; if ( type < 1 || type > unrecognized ) type = unrecognized; if (prtime()) return; printf("Metatext (%s) ",ttype[type]); len = leng; if (len > 15) len = 15; for ( n=0; n */ printf( (isprint(c)||isspace(c)) ? "%c" : "\\0x%02x" , c); } if (leng>15) printf("..."); printf("\n"); } void mftxt_keysig(sf,mi) int sf, mi; { static char *major[] = {"Cb", "Gb", "Db", "Ab", "Eb", "Bb", "F", "C", "G", "D", "A", "E", "B", "F#", "C#"}; static char *minor[] = {"Abmin", "Ebmin", "Bbmin", "Fmin", "Cmin", "Gmin", "Dmin", "Amin", "Emin", "Bmin", "F#min", "C#min", "G#min"}; int index; index = sf + 7; if (prtime()) return; if (mi) printf("Metatext key signature %s (%d/%d)\n",minor[index],sf,mi); else printf("Metatext key signature %s (%d/%d)\n",major[index],sf,mi); } void mftxt_tempo(ltempo) long ltempo; { tempo = ltempo; if (prtime()) return; printf("Metatext tempo = %6.2f bpm\n",60000000.0/tempo); } void mftxt_timesig(nn,dd,cc,bb) int nn, dd, cc, bb; { int denom = 1; while ( dd-- > 0 ) denom *= 2; if (prtime()) return; printf("Metatext time signature=%d/%d\n",nn,denom); /* printf("Time signature=%d/%d MIDI-clocks/click=%d \ 32nd-notes/24-MIDI-clocks=%d\n", nn,denom,cc,bb); */ } void mftxt_smpte(hr,mn,se,fr,ff) int hr, mn, se, fr, ff; { if (prtime()) return; printf("Metatext SMPTE, %d:%d:%d %d=%d\n", hr,mn,se,fr,ff); } void mftxt_metaeot() { if (prtime()) return; printf("Meta event, end of track\n"); } void initfunc_for_midinotes() { Mf_error = error; Mf_header = txt_header; Mf_trackstart = txt_trackstart; Mf_trackend = txt_trackend; Mf_noteon = print_txt_noteon; Mf_noteoff = print_txt_noteoff; Mf_pressure = no_op3; Mf_parameter = no_op3; Mf_pitchbend = no_op3; Mf_program = no_op2; Mf_chanpressure = no_op3; Mf_sysex = no_op2; Mf_metamisc = no_op3; Mf_seqnum = no_op1; Mf_eot = no_op0; Mf_timesig = no_op4; Mf_smpte = no_op5; Mf_tempo = no_op1; Mf_keysig = no_op2; Mf_seqspecific = no_op3; Mf_text = no_op3; Mf_arbitrary = no_op2; } void initfunc_for_mftext() { Mf_error = error; Mf_header = mftxt_header; Mf_trackstart = mftxt_trackstart; Mf_trackend = txt_trackend; Mf_noteon = mftxt_noteon; Mf_noteoff = mftxt_noteoff; Mf_pressure =mftxt_pressure; Mf_parameter = mftxt_parameter; Mf_pitchbend = mftxt_pitchbend; Mf_program = mftxt_program; Mf_chanpressure = mftxt_chanpressure; Mf_sysex = no_op2; Mf_metamisc = no_op3; Mf_seqnum = no_op1; Mf_eot = mftxt_metaeot; Mf_timesig = mftxt_timesig; Mf_smpte = mftxt_smpte; Mf_tempo = mftxt_tempo; Mf_keysig = mftxt_keysig; Mf_seqspecific = no_op3; Mf_text = mftxt_metatext; Mf_arbitrary = no_op2; } void initfuncs() { Mf_error = error; Mf_header = txt_header; Mf_trackstart = txt_trackstart; Mf_trackend = txt_trackend; Mf_noteon = txt_noteon; Mf_noteoff = txt_noteoff; Mf_pressure = txt_pressure; Mf_parameter = txt_parameter; Mf_pitchbend = txt_pitchbend; Mf_program = txt_program; Mf_chanpressure = txt_chanpressure; Mf_sysex = txt_sysex; Mf_metamisc = txt_metamisc; Mf_seqnum = txt_metaseq; Mf_eot = txt_metaeot; Mf_timesig = txt_timesig; Mf_smpte = txt_smpte; Mf_tempo = txt_tempo; Mf_keysig = txt_keysig; Mf_seqspecific = txt_metaspecial; Mf_text = txt_metatext; Mf_arbitrary = txt_arbitrary; } /* Stage 2 Quantize MIDI tracks. Get key signature, time signature... */ void postprocess(trackno) /* This routine calculates the time interval before the next note */ /* called after the MIDI file has been read in */ int trackno; { struct listx* i; i = track[trackno].head; if (i != NULL) { track[trackno].startwait = i->note->time; } else { track[trackno].startwait = 0; }; while (i != NULL) { if (i->next != NULL) { i->note->dtnext = i->next->note->time - i->note->time; } else { i->note->dtnext = i->note->tplay; }; i = i->next; }; } void scannotes(trackno) int trackno; /* diagnostic routine to output notes in a track */ { struct listx* i; i = track[trackno].head; while (i != NULL) { printf("Pitch %d chan %d vel %d time %ld %ld xnum %d playnum %d\n", i->note->pitch, i->note->chan, i->note->vel, i->note->dtnext, i->note->tplay, i->note->xnum, i->note->playnum); i = i->next; }; } int xnum_to_next_nonchordal_note(fromitem,spare,quantum) struct listx* fromitem; int spare,quantum; { struct anote* jnote; struct listx* nextitem; int i,xxnum; jnote = fromitem->note; if (jnote->xnum > 0) return jnote->xnum; i = 0; nextitem = fromitem->next; while (nextitem != NULL && i < 5) { jnote = nextitem->note; xxnum = (2*(jnote->dtnext + spare + (quantum/4)))/quantum; if (xxnum > 0) return xxnum; i++; nextitem = nextitem->next; } return 0; } int quantize(trackno, xunit) /* Work out how long each note is in musical time units. * The results are placed in note.playnum */ int trackno, xunit; { struct listx* j; struct anote* this; int spare; int toterror; int quantum; int posnum,xxnum; /* fix to avoid division by zero errors in strange MIDI */ if (xunit == 0) { return(10000); }; quantum = (int) (2.*xunit/parts_per_unitlen); /* xunit assume 2 parts_per_unit */ track[trackno].startunits = (2*(track[trackno].startwait + (quantum/4)))/quantum; spare = 0; toterror = 0; j = track[trackno].head; posnum = 0; while (j != NULL) { this = j->note; /* this->xnum is the quantized inter onset time */ /* this->playnum is the quantized note length */ this->xnum = (2*(this->dtnext + spare + (quantum/4)))/quantum; this->playnum = (2*(this->tplay + (quantum/4)))/quantum; if ((this->playnum == 0) && (keep_short)) { this->playnum = 1; }; /* In the event of short rests, the inter onset time * will be larger than the note length. However, for * chords the inter onset time can be zero. */ xxnum = xnum_to_next_nonchordal_note(j,spare,quantum); if ((swallow_rests>=0) && (xxnum - this->playnum <= restsize) && xxnum > 0) { this->playnum = xxnum; }; /* this->denom = parts_per_unitlen; this variable is never used ! */ spare = spare + this->dtnext - (this->xnum*xunit/parts_per_unitlen); if (spare > 0) { toterror = toterror + spare; } else { toterror = toterror - spare; }; /* gradually forget old errors so that if xunit is slightly off, errors don't accumulate over several bars */ spare = (spare * 96)/100; this->posnum = posnum; posnum += this->xnum; j = j->next; }; return(toterror); } void guesslengths(trackno) /* work out most appropriate value for a unit of musical time */ int trackno; { int i; int trial[100]; float avlen, factor, tryx; long min; min = track[trackno].tracklen; if (track[trackno].notes == 0) { return; }; avlen = ((float)(min))/((float)(track[trackno].notes)); tryx = avlen * (float) 0.75; factor = tryx/100; for (i=0; i<100; i++) { trial[i] = quantize(trackno, (int) tryx); if ((long) trial[i] < min) { min = (long) trial[i]; xunit = (int) tryx; }; tryx = tryx + factor; }; xunit_set = 1; } int findana(maintrack, barsize) /* work out anacrusis from MIDI */ /* look for a strong beat marking the start of a bar */ int maintrack; int barsize; { int min, mincount; int place; struct listx* p; min = 0; mincount = 0; place = 0; p = track[maintrack].head; while ((p != NULL) && (place < barsize)) { if ((p->note->vel > min) && (place > 0)) { min = p->note->vel; mincount = place; }; place = place + (p->note->xnum); p = p->next; }; return(mincount); } int guessana(barbeats) int barbeats; /* try to guess length of anacrusis */ { int score[64]; int min, minplace; int i,j; if (barbeats > 64) { fatal_error("Bar size exceeds static limit of 64 units!"); }; for (j=0; jnote->pitch; max = min; totalnotes = 0; for (j=0; jnote->pitch; if (thispitch > max) { max = thispitch; } else { if (thispitch < min) { min = thispitch; }; }; n[thispitch % 12] = n[thispitch % 12] + 1; p = p->next; }; }; /* count black notes for each key */ /* assume pitch = 0 is C */ minkey = 0; minblacks = totalnotes; for (j=0; j<12; j++) { key_score[j] = n[(j+1)%12] + n[(j+3)%12] + n[(j+6)%12] + n[(j+8)%12] + n[(j+10)%12]; /* printf("Score for key %d is %d\n", j, key_score[j]); */ if (key_score[j] < minblacks) { minkey = j; minblacks = key_score[j]; }; }; /* do conversion to abc pitches */ /* Code changed to use absolute rather than */ /* relative choice of pitch for 'c' */ /* MIDDLE = (min + (max - min)/2 + 6)/12 * 12; */ /* Do last note analysis */ lastpitch = track[maintrack].tail->note->pitch; if (minkey != (lastpitch%12)) { fprintf(outhandle,"%% Last note suggests "); switch((lastpitch+12-minkey)%12) { case(2): fprintf(outhandle,"Dorian "); break; case(4): fprintf(outhandle,"Phrygian "); break; case(5): fprintf(outhandle,"Lydian "); break; case(7): fprintf(outhandle,"Mixolydian "); break; case(9): fprintf(outhandle,"minor "); break; case(11): fprintf(outhandle,"Locrian "); break; default: fprintf(outhandle,"unknown "); break; }; fprintf(outhandle,"mode tune\n"); }; /* switch to minor mode if it gives same number of accidentals */ if ((minkey != ((lastpitch+3)%12)) && (key_score[minkey] == key_score[(lastpitch+3)%12])) { minkey = (lastpitch+3)%12; }; /* switch to major mode if it gives same number of accidentals */ if ((minkey != (lastpitch%12)) && (key_score[minkey] == key_score[lastpitch%12])) { minkey = lastpitch%12; }; sharps = keysharps[minkey]; return(sharps); } /* Stage 3 output MIDI tracks in abc format */ /* head and tail of list of notes in current chord playing */ /* used while abc is being generated */ struct dlistx* chordhead; struct dlistx* chordtail; void printchordlist() /* diagnostic routine */ { struct dlistx* i; i = chordhead; printf("----CHORD LIST------\n"); while(i != NULL) { printf("pitch %d len %d\n", i->note->pitch, i->note->playnum); if (i->next == i) { fatal_error("Loopback problem!"); }; i = i->next; }; } void checkchordlist() /* diagnostic routine */ /* validates data structure */ { struct dlistx* i; int n; if ((chordhead == NULL) && (chordtail == NULL)) { return; }; if ((chordhead == NULL) && (chordtail != NULL)) { fatal_error("chordhead == NULL and chordtail != NULL"); }; if ((chordhead != NULL) && (chordtail == NULL)) { fatal_error("chordhead != NULL and chordtail == NULL"); }; if (chordhead->last != NULL) { fatal_error("chordhead->last != NULL"); }; if (chordtail->next != NULL) { fatal_error("chordtail->next != NULL"); }; i = chordhead; n = 0; while((i != NULL) && (i->next != NULL)) { if (i->next->last != i) { char msg[80]; sprintf(msg, "chordlist item %d : i->next->last!", n); fatal_error(msg); }; i = i->next; n = n + 1; }; /* checkchordlist(); */ } void addtochord(p) /* used when printing out abc */ struct anote* p; { struct dlistx* newx; struct dlistx* place; newx = (struct dlistx*) checkmalloc(sizeof(struct dlistx)); newx->note = p; newx->next = NULL; newx->last = NULL; if (chordhead == NULL) { chordhead = newx; chordtail = newx; checkchordlist(); return; }; place = chordhead; while ((place != NULL) && (place->note->pitch > p->pitch)) { place = place->next; }; if (place == chordhead) { newx->next = chordhead; chordhead->last = newx; chordhead = newx; checkchordlist(); return; }; if (place == NULL) { newx->last = chordtail; chordtail->next = newx; chordtail = newx; checkchordlist(); return; }; newx->next = place; newx->last = place->last; place->last = newx; newx->last->next = newx; checkchordlist(); } struct dlistx* removefromchord(i) /* used when printing out abc */ struct dlistx* i; { struct dlistx* newi; /* remove note from list */ if (i->last == NULL) { chordhead = i->next; } else { (i->last)->next = i->next; }; if (i->next == NULL) { chordtail = i->last; } else { (i->next)->last = i->last; }; newi = i->next; free(i); checkchordlist(); return(newi); } int findshortest(gap) /* find the first note in the chord to terminate */ int gap; { int min, v; struct dlistx* p; p = chordhead; min = gap; while (p != NULL) { v = p->note->playnum; if (v < min) { min = v; }; p = p->next; }; return(min); } void advancechord(len) /* adjust note lengths for all notes in the chord */ int len; { struct dlistx* p; p = chordhead; while (p != NULL) { if (p->note->playnum <= len) { if (p->note->playnum < len) { fatal_error("Error - note too short!"); }; /* remove note */ checkchordlist(); p = removefromchord(p); } else { /* shorten note */ p->note->playnum = p->note->playnum - len; p = p->next; }; }; } void freshline() /* if the current line of abc or text is non-empty, start a new line */ { if (midline == 1) { fprintf(outhandle,"\n"); midline = 0; }; } void printnote (struct listx *i) { printf("%ld ",i->note->time); printpitch(i->note); printfract(i->note->playnum, parts_per_unitlen); printf(" %d %d %d %d\n",i->note->xnum, i->note->playnum, i->note->posnum,i->note->splitnum); } void listnotes(int trackno, int start, int end) /* A diagnostic like scannotes. I usually call it when I am in the debugger (for example in printtrack). */ { struct listx* i; int k; i = track[trackno].head; k = 0; printf("ticks pitch xnum,playnum,posnum,splitnum\n"); while (i != NULL && k < end) { if (k >= start) printnote(i); k++; i = i->next; } } int testtrack(trackno, barbeats, anacrusis) /* print out one track as abc */ int trackno, barbeats, anacrusis; { struct listx* i; int step, gap; int barnotes; int barcount; int breakcount; breakcount = 0; chordhead = NULL; chordtail = NULL; i = track[trackno].head; gap = 0; if (anacrusis > 0) { barnotes = anacrusis; } else { barnotes = barbeats; }; barcount = 0; while((i != NULL)||(gap != 0)) { if (gap == 0) { /* add notes to chord */ addtochord(i->note); gap = i->note->xnum; i = i->next; advancechord(0); /* get rid of any zero length notes */ } else { step = findshortest(gap); if (step > barnotes) { step = barnotes; }; if (step == 0) { fatal_error("Advancing by 0 in testtrack!"); }; advancechord(step); gap = gap - step; barnotes = barnotes - step; if (barnotes == 0) { if (chordhead != NULL) { breakcount = breakcount + 1; }; barnotes = barbeats; barcount = barcount + 1; if (barcount>0 && barcount%4 ==0) { /* can't zero barcount because I use it for computing maxbarcount */ freshline(); barcount = 0; }; }; }; }; return(breakcount); } void printpitch(j) /* convert numerical value to abc pitch */ struct anote* j; { int p, po,i; p = j->pitch; if (p == -1) { fprintf(outhandle,"z"); } else { po = p % 12; if ((back[trans[p]] != p) || (key[po] == 1)) { fprintf(outhandle,"%c%c", symbol[po], atog[p]); for (i=p%12; i<256; i += 12) /* apply accidental to all octaves */ back[trans[i]] = i; } else { fprintf(outhandle,"%c", atog[p]); }; while (p >= MIDDLE + 12) { fprintf(outhandle,"'"); p = p - 12; }; while (p < MIDDLE - 12) { fprintf(outhandle,","); p = p + 12; }; }; } static void reduce(a, b) int *a, *b; { int t, n, m; /* find HCF using Euclid's algorithm */ if (*a > *b) { n = *a; m = *b; } else { n = *b; m = *a; }; while (m != 0) { t = n % m; n = m; m = t; }; *a = *a/n; *b = *b/n; } void printfract(a, b) /* print fraction */ /* used when printing abc */ int a, b; { int c, d; c = a; d = b; reduce(&c,&d); /* print out length */ if (c != 1) { fprintf(outhandle,"%d", c); }; if (d != 1) { fprintf(outhandle,"/%d", d); }; } void printchord(len) /* Print out the current chord. Any notes that haven't */ /* finished at the end of the chord are tied into the next chord. */ int len; { struct dlistx* i; i = chordhead; if (i == NULL) { /* no notes in chord */ #ifdef SPLITCODE fprintf(outhandle,"x"); #else fprintf(outhandle,"z"); #endif printfract(len, parts_per_unitlen); midline = 1; } else { if (i->next == NULL) { /* only one note in chord */ printpitch(i->note); printfract(len, parts_per_unitlen); midline = 1; if (len < i->note->playnum) { fprintf(outhandle,"-"); }; } else { fprintf(outhandle,"["); while (i != NULL) { printpitch(i->note); printfract(len, parts_per_unitlen); if (len < i->note->playnum) { fprintf(outhandle,"-"); }; if (nogr && i->next != NULL) fprintf(outhandle," "); i = i->next; }; fprintf(outhandle,"]"); midline = 1; }; }; } char dospecial(i, barnotes, featurecount) /* identify and print out triplets and broken rhythm */ struct listx* i; int* barnotes; int* featurecount; { int v1, v2, v3, vt; int xa, xb; int pnum; long total, t1, t2, t3; if ((chordhead != NULL) || (i == NULL) || (i->next == NULL) /* || (asig%3 == 0) || (asig%2 != 0) 2004/may/09 SS*/) { return(' '); }; t1 = i->note->dtnext; v1 = i->note->xnum; pnum = i->note->playnum; if ((v1 < pnum) || (v1 > 1 + pnum) || (pnum == 0)) { return(' '); }; t2 = i->next->note->dtnext; v2 = i->next->note->xnum; pnum = i->next->note->playnum; if (/*(v2 < pnum) ||*/ (v2 > 1 + pnum) || (pnum == 0) || (v1+v2 > *barnotes)) { return(' '); }; /* look for broken rhythm */ total = t1 + t2; if (total == 0L) { /* shouldn't happen, but avoids possible divide by zero */ return(' '); }; if (((v1+v2)%2 == 0) && ((v1+v2)%3 != 0)) { vt = (v1+v2)/2; if (vt == validnote(vt)) { /* do not try to break a note which cannot be legally expressed */ switch ((int) ((t1*6+(total/2))/total)) { case 2: *featurecount = 2; i->note->xnum = vt; i->note->playnum = vt; i->next->note->xnum = vt; i->next->note->playnum = vt; return('<'); break; case 4: *featurecount = 2; i->note->xnum = vt; i->note->playnum = vt; i->next->note->xnum = vt; i->next->note->playnum = vt; return('>'); break; default: break; }; }; }; /* look for triplet */ if (i->next->next != NULL) { t3 = i->next->next->note->dtnext; v3 = i->next->next->note->xnum; pnum = i->next->next->note->playnum; if ((v3 < pnum) || (v3 > 1 + pnum) || (pnum == 0) || (v1+v2+v3 > *barnotes)) { return(' '); }; if ((v1+v2+v3)%2 != 0) { return(' '); }; vt = (v1+v2+v3)/2; if ((vt%2 == 1) && (vt > 1)) { /* don't want strange fractions in triplet */ return(' '); }; total = t1+t2+t3; xa = (int) ((t1*6+(total/2))/total); xb = (int) (((t1+t2)*6+(total/2))/total); if ((xa == 2) && (xb == 4) && (vt%3 != 0) ) { *featurecount = 3; *barnotes = *barnotes + vt; i->note->xnum = vt; i->note->playnum = vt; i->next->note->xnum = vt; i->next->note->playnum = vt; i->next->next->note->xnum = vt; i->next->next->note->playnum = vt; }; }; return(' '); } int validnote(n) int n; /* work out a step which can be expressed as a musical time */ { int v; if (n <= 4) { v = n; } else { v = 4; while (v*2 <= n) { v = v*2; }; if (v + v/2 <= n) { v = v + v/2; }; }; return(v); } void handletext(t, textplace, trackno) /* print out text occuring in the body of the track */ /* The text is printed out at the appropriate place within the track */ /* In addition the function handles key signature and time */ /* signature changes that can occur in the middle of the tune. */ long t; struct tlistx** textplace; int trackno; { char* str; char ch; int type,sf,mi,nn,denom,bb; while (((*textplace) != NULL) && ((*textplace)->when <= t)) { str = (*textplace)->text; ch = *str; type = (*textplace)->type; remove_carriage_returns(str); if (((int)ch == '\\') || ((int)ch == '/')) { inkaraoke = 1; }; if ((inkaraoke == 1) && (karaoke == 1)) { switch(ch) { case ' ': fprintf(outhandle,"%s", str); midline = 1; break; case '\\': freshline(); fprintf(outhandle,"w:%s", str + 1); midline = 1; break; case '/': freshline(); fprintf(outhandle,"w:%s", str + 1); midline = 1; break; default : if (midline == 0) { fprintf(outhandle,"%%%s", str); } else { fprintf(outhandle,"-%s", str); }; break; }; } else { freshline(); ch=*(str+1); switch (type) { case 0: if (ch != '%') fprintf(outhandle,"%%%s\n", str); else fprintf(outhandle,"%s\n", str); break; case 1: /* key signature change */ sscanf(str,"%d %d",&sf,&mi); if((trackno != 0 || trackcount==1) && (active_keysig != sf)) { setupkey(sf); active_keysig=sf; } break; case 2: /* time signature change */ sscanf(str,"%d %d %d",&nn,&denom,&bb); if ((trackno != 0 || trackcount ==1) && (active_asig != nn || active_bsig != denom)) { setup_timesig(nn,denom,bb); fprintf(outhandle,"M: %d/%d\n",nn,denom); fprintf(outhandle,"L: 1/%d\n",unitlen); active_asig=nn; active_bsig=denom; } break; default: break; } } *textplace = (*textplace)->next; } } #ifdef SPLITCODE /* This function identifies irregular chords, (notes which do not exactly overlap in time). The notes in the chords are split into separate lines (split numbers). The xnum (delay) to next note is updated. */ int splitstart[10],splitend[10]; /* used in forming chords from notes*/ int lastposnum[10]; /* posnum of previous note in linked list */ int endposnum; /* posnum at last note in linked list */ struct anote* prevnote[10]; /*previous note in linked list */ struct listx* last_i[10]; /*note after finishing processing bar*/ int existingsplits[10]; /* existing splits in active bar */ struct dlistx* splitchordhead[10]; /* chordhead list for splitnum */ struct dlistx* splitchordtail[10]; /* chordtail list for splitnum */ int splitgap[10]; /* gap to next note at end of split measure */ void label_split(struct anote *note, int activesplit) { /* The function assigns a split number (activesplit), to a specific note, (*note). We also update splitstart and splitend which specifies the region in time where the another note must occur if it forms a proper chord. After assigning a split number to the note we need to update note->xnum as this indicates the gap to the next note in the same split number. The function uses a greedy algorithm. It assigns a note to the first splitnumber code which satisfies the above constraint. If it cannot find a splitnumber, a new one (voice or track) is created. It would be nice if the voices kept the high and low notes (in pitch) separate. */ note->splitnum = activesplit; splitstart[activesplit] = note->posnum; splitend[activesplit] = splitstart[activesplit] + note->playnum; if (prevnote[activesplit]) prevnote[activesplit]->xnum = note->posnum - lastposnum[activesplit]; lastposnum[activesplit] = note->posnum; prevnote[activesplit] = note; /* in case this is the last activesplit note make sure it xnum points to end of track. Otherwise it will be changed when the next activesplit note is labeled. */ note->xnum = endposnum - note->posnum; existingsplits[activesplit]++; } void label_split_voices (int trackno) { /* This function sorts all the notes in the track into separate split part. A note is placed into a separate part if it forms a chord in the current part but does not have the same onset time and same end time. If this occurs, we search for another part where this does not happen. If we can't find such a part a new part (split) is created. The heuristic used needs to be improved, so that split number 0 always contains notes and so that notes in the same pitch range or duration are given the same split number. */ int activesplit,nsplits; int done; struct listx* i; int k; int firstposnum; /* initializations */ activesplit = 0; nsplits = 0; for (k=0;k<10;k++) { splitstart[k]=splitend[k]=lastposnum[k]=0; prevnote[k] = NULL; existingsplits[k] = 0; splitgap[k]=0; } i = track[trackno].head; if (track[trackno].tail == 0x0) return; endposnum =track[trackno].tail->note->posnum + track[trackno].tail->note->playnum; if (i != NULL) label_split(i->note, activesplit); /* now label all the notes in the track */ while (i != NULL) { done =0; if (nsplits == 0) { /*no splits exist, create split number 0 */ activesplit = 0; nsplits++; i->note->splitnum = activesplit; splitstart[activesplit] = i->note->posnum; splitend[activesplit] = splitstart[activesplit] + i->note->playnum; firstposnum = splitstart[activesplit]; } else { /* do a compatibility check with the last split number */ if ( ( i->note->posnum == splitstart[activesplit] && i->note->playnum == (splitend[activesplit] - splitstart[activesplit])) || i->note->posnum >= splitend[activesplit]) { if (existingsplits[activesplit] == 0) { last_i[activesplit] = i; splitgap[activesplit] = i->note->posnum - firstposnum; } label_split(i->note, activesplit); done = 1; } /* need to search for any other compatible split numbers */ if (done == 0) for (activesplit=0;activesplitnote->posnum == splitstart[activesplit] && i->note->playnum == splitend[activesplit] - splitstart[activesplit]) || i->note->posnum >= splitend[activesplit]) { if (existingsplits[activesplit] == 0) { last_i[activesplit] = i; splitgap[activesplit] = i->note->posnum - firstposnum; } label_split(i->note,activesplit); done = 1; break; } } /* No compatible split number found. Create new split */ if (done == 0) { if(nsplits < 10) {nsplits++; activesplit = nsplits-1;} if (existingsplits[activesplit] == 0) { last_i[activesplit] = i; splitgap[activesplit] = i->note->posnum - firstposnum; } label_split(i->note,activesplit); } } /* printf("note %d links to %d %d (%d %d)\n",i->note->pitch,activesplit, i->note->posnum,splitstart[activesplit],splitend[activesplit]); */ i = i->next; } /* end while loop */ } int nextsplitnum(int splitnum) { while (splitnum < 9) { splitnum++; if (existingsplits[splitnum]) return splitnum; } return -1; } int count_splits() { int i,n; n = 0; for (i=0;i<10;i++) if (existingsplits[i]) n++; return n; } void printtrack_with_splits(trackno, anacrusis) int trackno, anacrusis; /* This function is an adaption of printtrack so that notes with separate split numbers are in separated regions in the measure. (Separated with &'s). To do this we must make multiple passes through each bar and maintain separate chordlists (in event that some chords overlap over more than one measure). */ { struct listx* i; struct tlistx* textplace; struct tlistx* textplace0; /* track 0 text storage */ int step, gap; int barnotes; int barcount; int bars_on_line; long now; char broken; int featurecount; int last_barsize,barnotes_correction; int splitnum = 0; int j; int nlines; int done; nlines= 0; label_split_voices (trackno); midline = 0; featurecount = 0; inkaraoke = 0; now = 0L; broken = ' '; for (j=0;j<10;j++) { splitchordhead[j] = NULL; splitchordtail[j] = NULL; } i = track[trackno].head; textplace = track[trackno].texthead; textplace0 = track[0].texthead; /*gap = track[trackno].startunits;*/ gap = 0; if (anacrusis > 0) { barnotes = anacrusis; barcount = -1; } else { barnotes = barsize; barcount = 0; }; bars_on_line = 0; last_barsize = barsize; active_asig = header_asig; active_bsig = header_bsig; setup_timesig(header_asig,header_bsig,header_bb); active_keysig = header_keysig; handletext(now, &textplace, trackno); splitnum = 0; chordhead = splitchordhead[splitnum]; chordtail = splitchordtail[splitnum]; gap = splitgap[splitnum]; while((i != NULL)||(gap != 0)) { if (gap == 0) { /* do triplet here */ if (featurecount == 0) { if (!no_triplets) { broken = dospecial(i, &barnotes, &featurecount); }; }; /* ignore any notes that are not in the current splitnum */ if (i->note->splitnum == splitnum) { /*printf("\nadding "); printnote(i); */ addtochord(i->note); gap = i->note->xnum; now = i->note->time; } i = i->next; advancechord(0); /* get rid of any zero length notes */ if (trackcount > 1 && trackno !=0) handletext(now, &textplace0, trackno); handletext(now, &textplace,trackno); barnotes_correction = barsize - last_barsize; barnotes += barnotes_correction; last_barsize = barsize; } else { step = findshortest(gap); if (step > barnotes) { step = barnotes; }; step = validnote(step); if (step == 0) { fatal_error("Advancing by 0 in printtrack!"); }; if (featurecount == 3) { fprintf(outhandle," (3"); }; printchord(step); if ( featurecount > 0) { featurecount = featurecount - 1; }; if ((featurecount == 1) && (broken != ' ')) { fprintf(outhandle,"%c", broken); }; advancechord(step); gap = gap - step; barnotes = barnotes - step; /* at the end of the bar we must decide whether to place a | or &. If we place a & then we have to return to the beginning of the bar and process the next split number. */ if (barnotes == 0) { /* end of bar ? */ nlines++; if (nlines > 5000) { printf("\nProbably infinite loop: aborting\n"); fprintf(outhandle,"\n\nProbably infinite loop: aborting\n"); return; } /* save state for the last splitnum before going to the next */ last_i[splitnum] = i; splitchordhead[splitnum] = chordhead; splitchordtail[splitnum] = chordtail; splitgap[splitnum] = gap; /* look for the next splitnum which contains notes in the current measure. If not, end the measure. */ done = 0; while (done != 1) { splitnum = nextsplitnum(splitnum); if (splitnum == -1) { fprintf(outhandle," | "); splitnum = nextsplitnum(splitnum); done = 1; break; } if (splitgap[splitnum] >= barsize) { splitgap[splitnum] -= barsize; continue; /* look for other splits */ } fprintf(outhandle, " & "); i = last_i[splitnum]; done = 1; } /* restore state for the next splitnum */ chordhead = splitchordhead[splitnum]; chordtail = splitchordtail[splitnum]; checkchordlist(); gap = splitgap[splitnum]; i = last_i[splitnum]; /* printf("returning to %ld ",i->note->time); printpitch(i->note); printf("\n"); */ barnotes = barsize; barcount = barcount + 1; bars_on_line++; if (barcount >0 && barcount%bars_per_staff == 0) { freshline(); bars_on_line=0; } /* can't zero barcount because I use it for computing maxbarcount */ else if(bars_on_line >= bars_per_line && i != NULL) { fprintf(outhandle," \\"); freshline(); bars_on_line=0;} } else if (featurecount == 0) { /* note grouping algorithm */ if ((barsize/parts_per_unitlen) % 3 == 0) { if ( (barnotes/parts_per_unitlen) % 3 == 0 &&(barnotes%parts_per_unitlen) == 0) { fprintf(outhandle," "); }; } else { if (((barsize/parts_per_unitlen) % 2 == 0) && (barnotes % parts_per_unitlen) == 0 && ((barnotes/parts_per_unitlen) % 2 == 0)) { fprintf(outhandle," "); }; }; } if (nogr) fprintf(outhandle," "); }; if (i == NULL) /* end of track before end of measure ? */ { last_i[splitnum] = i; splitchordhead[splitnum] = chordhead; splitchordtail[splitnum] = chordtail; splitgap[splitnum] = gap; splitnum = nextsplitnum(splitnum); if (splitnum == -1) break; chordhead = splitchordhead[splitnum]; chordtail = splitchordtail[splitnum]; gap = splitgap[splitnum]; i = last_i[splitnum]; if (barnotes != barsize) fprintf(outhandle, " & "); barnotes = barsize; } }; /* print out all extra text */ while (textplace != NULL) { handletext(textplace->when, &textplace, trackno); }; freshline(); if (barcount > maxbarcount) maxbarcount = barcount; } void printtrack_split_voice(trackno, anacrusis) /* print out one track as abc */ int trackno, anacrusis; { struct listx* i; struct tlistx* textplace; struct tlistx* textplace0; /* track 0 text storage */ int step, gap; int barnotes; int barcount; int bars_on_line; long now; char broken; int featurecount; int last_barsize,barnotes_correction; int nlines; int splitnum; int lastnote_in_split; nlines= 0; lastnote_in_split = 0; label_split_voices (trackno); midline = 0; featurecount = 0; inkaraoke = 0; now = 0L; broken = ' '; chordhead = NULL; chordtail = NULL; i = track[trackno].head; textplace = track[trackno].texthead; textplace0 = track[0].texthead; gap = track[trackno].startunits; if (anacrusis > 0) { barnotes = anacrusis; barcount = -1; } else { barnotes = barsize; barcount = 0; }; bars_on_line = 0; last_barsize = barsize; active_asig = header_asig; active_bsig = header_bsig; setup_timesig(header_asig,header_bsig,header_bb); active_keysig = header_keysig; handletext(now, &textplace, trackno); splitnum = 0; gap = splitgap[splitnum]; if (count_splits() > 1) fprintf(outhandle,"V: split%d%c\n",trackno+1,'A'+splitnum); while((i != NULL)||(gap != 0)) { if (gap == 0) { if (i->note->posnum + i->note->xnum == endposnum) lastnote_in_split = 1; /* do triplet here */ if (featurecount == 0) { if (!no_triplets) { broken = dospecial(i, &barnotes, &featurecount); }; }; /* ignore any notes that are not in the current splitnum */ if (i->note->splitnum == splitnum) { /*printf("\nadding "); printnote(i); */ addtochord(i->note); gap = i->note->xnum; now = i->note->time; } i = i->next; advancechord(0); /* get rid of any zero length notes */ if (trackcount > 1 && trackno !=0) handletext(now, &textplace0, trackno); handletext(now, &textplace,trackno); barnotes_correction = barsize - last_barsize; barnotes += barnotes_correction; last_barsize = barsize; } else { step = findshortest(gap); if (step > barnotes) { step = barnotes; }; step = validnote(step); if (step == 0) { fatal_error("Advancing by 0 in printtrack!"); }; if (featurecount == 3) { fprintf(outhandle," (3"); }; printchord(step); if ( featurecount > 0) { featurecount = featurecount - 1; }; if ((featurecount == 1) && (broken != ' ')) { fprintf(outhandle,"%c", broken); }; advancechord(step); gap = gap - step; barnotes = barnotes - step; if (barnotes == 0) { nlines++; if (nlines > 5000) { printf("\nProbably infinite loop: aborting\n"); fprintf(outhandle,"\n\nProbably infinite loop: aborting\n"); return; } fprintf(outhandle,"|"); barnotes = barsize; barcount = barcount + 1; bars_on_line++; if (barcount >0 && barcount%bars_per_staff == 0) { freshline(); bars_on_line=0; } /* can't zero barcount because I use it for computing maxbarcount */ else if(bars_on_line >= bars_per_line && i != NULL) { if (!lastnote_in_split) fprintf(outhandle," \\"); freshline(); bars_on_line=0;} } else if (featurecount == 0) { /* note grouping algorithm */ if ((barsize/parts_per_unitlen) % 3 == 0) { if ( (barnotes/parts_per_unitlen) % 3 == 0 &&(barnotes%parts_per_unitlen) == 0) { fprintf(outhandle," "); }; } else { if (((barsize/parts_per_unitlen) % 2 == 0) && (barnotes % parts_per_unitlen) == 0 && ((barnotes/parts_per_unitlen) % 2 == 0)) { fprintf(outhandle," "); }; }; } if (nogr) fprintf(outhandle," "); }; if (i == NULL && gap == 0) { i = track[trackno].head; splitnum = nextsplitnum(splitnum); lastnote_in_split = 0; if (splitnum == -1) break; gap = splitgap[splitnum]; if(barnotes != barsize) freshline(); fprintf(outhandle,"V:split%d%c\n",trackno+1,'A'+splitnum); if (anacrusis > 0) { barnotes = anacrusis; barcount = -1; } else { barnotes = barsize; barcount = 0; }; } }; /* print out all extra text */ while (textplace != NULL) { handletext(textplace->when, &textplace, trackno); }; freshline(); if (barcount > maxbarcount) maxbarcount = barcount; } #endif void printtrack(trackno, anacrusis) /* print out one track as abc */ int trackno, anacrusis; { struct listx* i; struct tlistx* textplace; struct tlistx* textplace0; /* track 0 text storage */ int step, gap; int barnotes; int barcount; int bars_on_line; long now; char broken; int featurecount; int last_barsize,barnotes_correction; midline = 0; featurecount = 0; inkaraoke = 0; now = 0L; broken = ' '; chordhead = NULL; chordtail = NULL; i = track[trackno].head; textplace = track[trackno].texthead; textplace0 = track[0].texthead; gap = track[trackno].startunits; if (anacrusis > 0) { barnotes = anacrusis; barcount = -1; } else { barnotes = barsize; barcount = 0; }; bars_on_line = 0; last_barsize = barsize; active_asig = header_asig; active_bsig = header_bsig; setup_timesig(header_asig,header_bsig,header_bb); active_keysig = header_keysig; handletext(now, &textplace, trackno); while((i != NULL)||(gap != 0)) { if (gap == 0) { /* do triplet here */ if (featurecount == 0) { if (!no_triplets) { broken = dospecial(i, &barnotes, &featurecount); }; }; /* add notes to chord */ addtochord(i->note); gap = i->note->xnum; now = i->note->time; i = i->next; advancechord(0); /* get rid of any zero length notes */ if (trackcount > 1 && trackno !=0) handletext(now, &textplace0, trackno); handletext(now, &textplace,trackno); barnotes_correction = barsize - last_barsize; barnotes += barnotes_correction; last_barsize = barsize; } else { step = findshortest(gap); if (step > barnotes) { step = barnotes; }; step = validnote(step); if (step == 0) { fatal_error("Advancing by 0 in printtrack!"); }; if (featurecount == 3) { fprintf(outhandle," (3"); }; printchord(step); if ( featurecount > 0) { featurecount = featurecount - 1; }; if ((featurecount == 1) && (broken != ' ')) { fprintf(outhandle,"%c", broken); }; advancechord(step); gap = gap - step; barnotes = barnotes - step; if (barnotes == 0) { fprintf(outhandle,"|"); barnotes = barsize; barcount = barcount + 1; bars_on_line++; if (barcount >0 && barcount%bars_per_staff == 0) { freshline(); bars_on_line=0; } /* can't zero barcount because I use it for computing maxbarcount */ else if(bars_on_line >= bars_per_line && i != NULL) { fprintf(outhandle," \\"); freshline(); bars_on_line=0;} } else if (featurecount == 0) { /* note grouping algorithm */ if ((barsize/parts_per_unitlen) % 3 == 0) { if ( (barnotes/parts_per_unitlen) % 3 == 0 &&(barnotes%parts_per_unitlen) == 0) { fprintf(outhandle," "); }; } else { if (((barsize/parts_per_unitlen) % 2 == 0) && (barnotes % parts_per_unitlen) == 0 && ((barnotes/parts_per_unitlen) % 2 == 0)) { fprintf(outhandle," "); }; }; } if (nogr) fprintf(outhandle," "); }; }; /* print out all extra text */ while (textplace != NULL) { handletext(textplace->when, &textplace, trackno); }; freshline(); if (barcount > maxbarcount) maxbarcount = barcount; } void remove_carriage_returns(char *str) { /* a carriage return might be embedded in a midi text meta-event. do not output this in the abc file or this would make a nonsyntactic abc file. */ char * loc; while (loc = (char *) strchr(str,'\r')) *loc = ' '; while (loc = (char *) strchr(str,'\n')) *loc = ' '; } void printQ() /* print out tempo for abc */ { float Tnote, freq; Tnote = mf_ticks2sec((long)((xunit*unitlen)/4), division, tempo); freq = (float) 60.0/Tnote; fprintf(outhandle,"Q:1/4=%d\n", (int) (freq+0.5)); if (summary>0) printf("Tempo: %d quarter notes per minute\n", (int) (freq + 0.5)); } void setupkey(sharps) int sharps; /* set up variables related to key signature */ { char sharp[13], flat[13], shsymbol[13], flsymbol[13]; int j, t, issharp; int minkey; for (j=0; j<12; j++) key[j] = 0; minkey = (sharps+12)%12; if (minkey%2 != 0) { minkey = (minkey+6)%12; }; strcpy(sharp, "ccddeffggaab"); strcpy(shsymbol, "=^=^==^=^=^="); if (sharps == 6) { sharp[6] = 'e'; shsymbol[6] = '^'; }; strcpy(flat, "cddeefggaabb"); strcpy(flsymbol, "=_=_==_=_=_="); /* Print out key */ if (sharps >= 0) { if (sharps == 6) { fprintf(outhandle,"K:F#"); } else { fprintf(outhandle,"K:%c", sharp[minkey] + 'A' - 'a'); }; issharp = 1; } else { if (sharps == -1) { fprintf(outhandle,"K:%c", flat[minkey] + 'A' - 'a'); } else { fprintf(outhandle,"K:%cb", flat[minkey] + 'A' - 'a'); }; issharp = 0; }; if (sharps >= 0) { fprintf(outhandle," %% %d sharps\n", sharps); } else { fprintf(outhandle," %% %d flats\n", -sharps); }; key[(minkey+1)%12] = 1; key[(minkey+3)%12] = 1; key[(minkey+6)%12] = 1; key[(minkey+8)%12] = 1; key[(minkey+10)%12] = 1; for (j=0; j<256; j++) { t = j%12; if (issharp) { atog[j] = sharp[t]; symbol[j] = shsymbol[t]; } else { atog[j] = flat[t]; symbol[j] = flsymbol[t]; }; trans[j] = 7*(j/12)+((int) atog[j] - 'a'); if (j < MIDDLE) { atog[j] = (char) (int) atog[j] + 'A' - 'a'; }; if (key[t] == 0) { back[trans[j]] = j; }; }; } /* Functions for supporting the command line user interface to midi2abc. */ int readnum(num) /* read a number from a string */ /* used for processing command line */ char *num; { int t; char *p; int neg; t = 0; neg = 1; p = num; if (*p == '-') { p = p + 1; neg = -1; }; while (((int)*p >= '0') && ((int)*p <= '9')) { t = t * 10 + (int) *p - '0'; p = p + 1; }; return neg*t; } int readnump(p) /* read a number from a string (subtly different) */ /* used for processing command line */ char **p; { int t; t = 0; while (((int)**p >= '0') && ((int)**p <= '9')) { t = t * 10 + (int) **p - '0'; *p = *p + 1; }; return t; } void readsig(a, b, sig) /* read time signature */ /* used for processing command line */ int *a, *b; char *sig; { char *p; int t; p = sig; if ((int)*p == 'C') { *a = 4; *b = 4; return; }; *a = readnump(&p); if ((int)*p != '/') { char msg[80]; sprintf(msg, "Expecting / in time signature found %c!", *p); fatal_error(msg); }; p = p + 1; *b = readnump(&p); if ((*a == 0) || (*b == 0)) { char msg[80]; sprintf(msg, "%d/%d is not a valid time signature!", *a, *b); fatal_error(msg); }; t = *b; while (t > 1) { if (t%2 != 0) { fatal_error("Bad key signature, divisor must be a power of 2!"); } else { t = t/2; }; }; } int is_power_of_two(int numb) /* checks whether numb is a power of 2 less than 256 */ { int i,k; k = 1; for (i= 0;i<8;i++) { if(numb == k) return(1); k *= 2; } return(0); } int getarg(option, argc, argv) /* extract arguments from command line */ char *option; char *argv[]; int argc; { int j, place; place = -1; for (j=0; j= argc+1) { /* [SS] 2015-02-22 */ Qval = readnum(argv[arg]); } else { Qval = 0; }; arg = getarg("-u", argc,argv); if (arg != -1) { xunit = readnum(argv[arg]); xunit_set = 1; } else { xunit = 0; xunit_set = 0; }; arg = getarg("-ppu",argc,argv); if (arg != -1) { val = readnum(argv[arg]); if (is_power_of_two(val)) parts_per_unitlen = val; else { printf("*error* -ppu parameter must be a power of 2\n"); parts_per_unitlen = 2; } } else parts_per_unitlen = 2; arg = getarg("-aul",argc,argv); if (arg != -1) { val = readnum(argv[arg]); if (is_power_of_two(val)) { unitlen = val; unitlen_set = 1;} else printf("*error* -aul parameter must be a power of 2\n"); } arg = getarg("-bps",argc,argv); if (arg != -1) bars_per_staff = readnum(argv[arg]); else { bars_per_staff=4; }; arg = getarg("-bpl",argc,argv); if (arg != -1) bars_per_line = readnum(argv[arg]); else { bars_per_line=1; }; extracta = (getarg("-xa", argc, argv) != -1); guessa = (getarg("-ga", argc, argv) != -1); guessu = (getarg("-gu", argc, argv) != -1); guessk = (getarg("-gk", argc, argv) != -1); keep_short = (getarg("-s", argc, argv) != -1); summary = getarg("-sum",argc,argv); swallow_rests = getarg("-sr",argc,argv); if (swallow_rests != -1) { restsize = readnum(argv[swallow_rests]); if(restsize <1) restsize=1; } obpl = getarg("-obpl",argc,argv); if (obpl>= 0) bars_per_line=1; if (!unitlen_set) { if ((asig*4)/bsig >= 3) { unitlen =8; } else { unitlen = 16; }; } arg = getarg("-b", argc, argv); if ((arg != -1) && (arg < argc)) { bars = readnum(argv[arg]); } else { bars = 0; }; arg = getarg("-c", argc, argv); if ((arg != -1) && (arg < argc)) { xchannel = readnum(argv[arg]) - 1; } else { xchannel = -1; }; arg = getarg("-k", argc, argv); if ((arg != -1) && (arg < argc)) { keysig = readnum(argv[arg]); if (keysig<-6) keysig = 12 - ((-keysig)%12); if (keysig>6) keysig = keysig%12; if (keysig>6) keysig = keysig - 12; ksig_set = 1; } else { keysig = -50; ksig_set = 0; }; if(guessk) ksig_set=1; arg = getarg("-o",argc,argv); if ((arg != -1) && (arg < argc)) { outhandle = efopen(argv[arg],"w"); /* open output abc file */ } else { outhandle = stdout; }; arg = getarg("-nt", argc, argv); if (arg == -1) { no_triplets = 0; } else { no_triplets = 1; }; arg = getarg("-nogr",argc,argv); if (arg != -1) nogr=1; else nogr = 0; arg = getarg("-title",argc,argv); if (arg != -1) { title = addstring(argv[arg]); } arg = getarg("-origin",argc,argv); if (arg != -1) { origin = addstring(argv[arg]); } arg = getarg("-f", argc, argv); if (arg == -1) { arg = huntfilename(argc, argv); }; if ((arg != -1) && (arg < argc)) { F = efopen(argv[arg],"rb"); /* fprintf(outhandle,"%% input file %s\n", argv[arg]); */ } else { printf("midi2abc version %s\n usage :\n",VERSION); printf("midi2abc filename \n"); printf(" -a \n"); printf(" -xa Extract anacrusis from file "); printf("(find first strong note)\n"); printf(" -ga Guess anacrusis (minimize ties across bars)\n"); printf(" -gk Guess key signature \n"); printf(" -gu Guess xunit from note duration statistics\n"); printf(" -m

X:1
T:\%\%MIDI temperamentlinear - microtone accidentals in cents
%%postscript /ft5475{M -3 3 RM 6 -6 RL 2 SLW stroke}def
%%postscript /ft35939{2 copy ft0 M -7.5 -3 RM 12 F3 (7) show}def
M:none
K:C
%%scale 1.3
V:1
%%MIDI program 17
%%MIDI temperamentlinear 1200 702 %% Pythagorian tunings
%%MIDI makechordchannels 3
"^Pure;major;chord"\
[C_22/100EG]8 y |\
"^Pythagorian;major;chord"\
[CEG]8 y ||\
"^Pure;4:5:6:7;chord"\
[C_22/100EG_141/100B]8 y |\
"^Pythagorean;7-chord"\
[CEG_B]8 y ||

A new command %%temperamentequal was introduced.
%%MIDI temperamentequal [octave_cents] [fifth_steps] [sharp_steps] This command sets a tempered scale defined by 'ndiv' equal divisions of 'octave_cents' (default is the octave = 1200 cents). The optional parameter 'fifth_steps', if provided, is an integer that defines the size of the fifth in steps of the temperament. This sets where is the note G in the temperament. When 'fifth_steps' is omited or 0 (zero), the program computes it as an approximation of the frequency ratio 3/1, minus the (possibly tempered) octave. The optional 'sharp_steps' defines the meaning of the accidentals. 'sharp_steps' is the number of steps between a natural note and a sharpened note (e.g. between =C and ^C). By default, the size of a sharp/flat deviation is based on the size of the chromatic semitone in the specified temperament: 7 fifths minus 4 octaves. The values in use in the temperament can be viewed by running abc2midi with the command-line option -v (verbose). With temperamentequal (as with temperamentlinear), microtone accidentals are interpreted as fractions of the sharp size in the specified temperament, except if they use denominator=100, which defines microtonal deviations in cents. The conventional temperament can be reset with the command temperamentnormal. See also: temperamentlinear, temperamentnormal, makechordchannels Implementation: Changes in store.c are marked with [HL] 2015-05-15 New global variable 'sharp_size' It is the the size, in pitchbend units, of the chromatic step between (e.g.) =C and ^C. (This is computed from octave and fifth sizes when using temperamentlinear or temperamentequal.) event_specific() Function changed to modify the command temperamentlinear and to add the command temperamentequal. temperamentlinear: Compute 'sharp_size'; Print information when -v (verbose option); Fix the command name in the error message. temperamentequal (new command): Compute octave_size, fifth_size, sharp_size; Temperament information when -v (Verbose option). pitchof_b() Function changed to handle microtones in user-defined temperaments. Global variable 'sharp_size' is used for that. event_microtone() Rounding instead truncation as slight improvement of precision. (MIDI bend is rough for tuning.) May 21 2015 Abc2midi drone bug: The %%MIDI drone command is ineffective. In the following example, X: 1 T:Banks and Braes M:6/8 L:1/8 S:Slow March K:HP %%MIDI program 109 %%MIDI gracedivider 4 %%MIDI drone 67 44 45 90 90 %%MIDI droneon {Gdc}d2{g}d{g}ede|\ {g}faf{gef}e2{g}d/2e/2| the %%MIDI drone 67 44 45 90 90 does not change the drone characteristics. Analysis: The drone is put in a separate MIDI track. The %%MIDI drone command is processed in the first track, and updates the elements of the drone structure. When the drone track is written starttrack() in genmidi.c, initializes the drone structure destroying any information that was recorded. Fix: initialization of the drone structure is done during compilation time. Note, if the tune has more than one %%MIDI drone command, only the last one is effective. June 01 2015 Abc2midi new feature: introducing new commands %%MIDIdef and %%MIDIx. %%MIDIdef code line links code a unique string less than 7 letters to a line of strings that normally occurs in a MIDI command. For example %%MIDIdef bnd1 bendstring 400 400 300 100 -100 300 400 400 400 link the string bnd1 to " bendstring 400 400 300 100 -100 300 400 400 400" Now you can call up the MIDI command %%MIDI bendstring 400 400 300 100 -100 300 400 400 400 using a shorthand %%MIDIx bnd1. Example: X:1 %%MIDIdef type1 bendstring 0 0 600 600 600 600 0 -600 -600 -600 -600 -600 -120 0 %%MIDIdef type2 bendstring 0 0 0 0 0 0 400 800 800 -800 -800 -400 -400 -400 %%MIDIdef inst program 67 %%MIDIdef t3 bendstring 0 0 0 0 0 500 500 600 600 -600 -600 -500 -500 T: MIDI M:2/4 L:1/2 K: D %%MIDIx inst %%MIDIx type1 !bend!A|B|\ %%MIDIx type2 !bend!C|D| This is useful when you have several different bendstrings and you wish to call them up in different places in the tune using a code. There is a limit of 20 distinct MIDIdef's in your tune. Implementation: in parseabc.c added a new function readaln which is like readstr but scans for the next word (that may contain numerics) in the input string. (The words are separated by spaces or tabs.) In store.c, added two new functions parse_mididefs(s) and expand_midix(s) for handling the %%MIDIdef and %%MIDIx commands. These functions are called in the function event_specific(). June 02 2015 continuation: added strcmp(key, "MIDIx") in event_info_key() in store.c June 07 2015 Abc2midi bug: the !bend! command does not work inside a slur. In the following example, X:1 T: slur and bend M: 2/4 L: 1/8 K: F %%MIDI bendstring 500 500 500 0 -500 -500 -500 %%MIDI program 73 !bend! D4|(!bend! F4| D4| a bend is not applied on F4. Analysis: writetrack() in genmidi.c tests whether a note is inside a slur. If it is inside a slur, both note triming and note bending were suppressed. Fix, writetrack() was modified to allow note bending inside a slur. The MIDIdef, MIDIx code word was allowed to contain up to 31 characters. All characters except white spaces are allowed inside the code word. June 08 2015 Abc2midi bug: !bend! causes tracklenth to be too small. Fix: in timestep() in queues.c, update tracklen before note_effect is called instead as after. June 16 2015 Abc2midi new feature: introducing %%MIDI expand m/n. This acts like %%MIDI trim m/n except it expands the note by this amount. Implementation: added feature EXPAND to featuretype in abc.h. In event_specific() in store.c, test for %%MIDI command 'expand' and addfeature(EXPAND,...) if found. In genmidi.c introduce new globals (expand, expand_num, and expand_denom) which are set in writetrack when feature EXPAND is detected. If the flag expand is set, then the active note is expanded. Here is a test tune. X:1 T: note expansion M: 4/4 L: 1/2 K: G %%MIDI program 52 CD|GA| %%MIDI expand 1/2 de|fe|BA| June 16 2015 Abc2midi new feature: added track identification annotation to midi file so we know whether it is a gchord, note, lyric, drum, etc track. June 30 2015 Abc2midi split voice bug: change of unit length defined by L: does not propagate to the voice overlay. eg. X:1 T: split voice bug - unit length M: 4/4 L:1/8 K: G C8 & E8|\ L:1/4 cdAB & GAEF|G4 & D4:| causes loss of synchronization starting from the second measure. Analysis: the L:1/4 does not change the unit length in the split voice and the notes GAEF and D4 are too short. Fix: in event_split_voice() in store.c set the unit length to the same length as the parent voice. July 02 2015 Abc2abc bug: the fix introduced in May 13 2015 introduced another problem. In the example X:1 T: Octave M: 2/4 L: 1/8 K: G V:1 clef=treble+8 CDEF|ABcd| Applying abc2abc returns X:1 T:Octave M:2/4 L:1/8 K:G V:1 clef=treble+8 octave=1 CDEF|ABcd| Unfortunately the added parameter octave=1 causes abcm2ps to also display the notes one octave higher. Analysis: the parameter octave=1 is useful to abc2midi as it tells the program to shift the notes up one octave when it creates the midi file; however, this is not desired when running abcm2ps. Abcm2ps uses clef=treble+8 to place an 8 above the treble clef and that is sufficient. The problems occurs in the function isclef() in parseabc.c. The function changes gotoctave to 1 when it sees treble+8. The fix on May 13 2015 forces event_voice to issue an octave=1 when it sees cgotoctave = 1. Fix: in isclef() a conditional block {} was created for all if (fileprogram == ABC2MIDI && *gotoctave != 1 && *octave != 1) statements, and *gotoctave = 1 was moved inside this block. July 08 2015 abc2midi feature: added sus4 to the list of chord names recognized. Added hint to message 'Unrecognized chord name ...". July 15 2015 abc2midi bug: abc2midi crashes (segmentation error) on %%MIDIx. In the following example: X:1 T: segmentation error M: 2/4 L: 1/8 K: G %%MIDIx crash ABCD| abc2midi fails. Analysis: abc2midi fails to detect that there is no corresponding %%MIDIdef for the code word 'crash'. Fix: the function expand_midix() now checks for this case. July 24-28 2015 abc2midi: new feature !shape! and %%MIDI controlstring. Introduced a new midi command %%MIDI controlstring n m1 m2 m3 ... where n, m1, m2, and etc are numbers between 0 and 127. %%MIDI controlstring n m1 is equivalent to the %%MIDI control command. When more than one data value m1 and etc. follow, then this defines how to shape the note following the !shape! instruction. The following example illustrates shaping the note F4 by varying the mod wheel. X:1 T: control string M: 4/4 L: 1/4 K: G %%MIDI controlstring 1 125 80 40 0 %%MIDI program 60 !shape! F4| D4|F2G2| The midi file produced will look like Header format=0 ntrks=1 division=480 Track 1 contains 115 bytes 0.00 Metatext (Text Event) note track 0.00 Metatext tempo = 120.00 bpm 0.00 Metatext key signature G (1/0) 0.00 Metatext time signature=4/4 0.00 Metatext (Seqnce/Track Name) control string 0.00 Program 1 60 (French Horn) 0.00 Note on 1 f#4 105 1.00 CntlParm 1 Modulation Wheel = 125 2.00 CntlParm 1 Modulation Wheel = 80 3.00 CntlParm 1 Modulation Wheel = 40 3.99 CntlParm 1 Modulation Wheel = 0 4.00 Note off 1 f#4 0 4.00 Note on 1 d4 105 8.00 Note off 1 d4 0 8.00 Note on 1 f#4 105 10.00 Note off 1 f#4 0 10.00 Note on 1 g4 95 12.00 Note off 1 g4 0 12.05 Meta event, end of track The whole note F# is modified in 4 equal segments. Note the !shape! does not work in combination with the !bend! command presently. Implementation: created the new function note_effect4() in queues.c The maximum number of codenames for %%MIDIdef has been increased to 200. The codename can now be as long as 31 letters. July 27 2015 - August 3 2015 abc2midi: extension of !shape! for combining %%MIDI controlstring and %%MIDI bendstring. Implementation: added a new struct eventstruct and a struct array eventlist[200]. Created new procedures note_effect5(), output_eventlist(), and compare_events(). August 4 2015 abc2midi: channel bug. The following tune plays incorrectly. X: 1 T: channel problem M: 6/8 L: 1/8 K: G %%MIDI channel 1 %%MIDI bassprog 68 %%MIDI chordprog 20 D | "G"G3 GAB | "D"ABA ABd | The melody should be played on the Acoustic Piano; instead it is played on the oboe (MIDI program 68). Analysis: The %%MIDI channel setting is redundant and causes the problem. Both the melody and the bass accompaniment use the same channel. The command %%MIDI bassprog 68 causes the melody to be played by program 68 (the oboe). The bug was introduced in March 16 2015. The variable channel_in_use[channel] was not set to 1 correctly in starttrack() in genmidi.c. August 06 2015 Fixed compile issue on Mac OS 10.10.4 in genmidi.c August 10 2015 - August 11 2015 abc2midi new feature: %%MIDI controlstring restores the controller back to its default after the shaped note is played. The default can be changed with a regular %%MIDI control command. Implementation: added a new array controldefaults[] in genmidi.c which is linked to queue.c. Updated abcguide.txt. August 18 2015 abc2midi: Support for the directive %%propagate-accidentals not | octave | pitch was extended to include the three choices described in http://abcnotation.com/wiki/abc:standard:v2.1#accidental_directives Furthermore, the default was changed to 'pitch' in compliance with the standard. Implementation: All the changes were limited to the source code store.c. The flag retain_accidentals was eliminated and the switch nopropagate_accidentals was changed to propagate_accidentals in store.c. In event_specific(), the switch propagate_accidentals is set on the basis of the directive %%propagate-accidentals, to 0, 1, or 2. In pitchof_b(), the code for propagating accidentals (including microtones) was reworked. Here is a simple test file. X:1 T:accidental M:2/4 L:1/8 K:C %%propagate-accidentals pitch ^C2c2| %%propagate-accidentals not ^C2c2|\ %%propagate-accidentals octave ^C2c2|\ %%propagate-accidentals no The c2 note is affected by only the pitch directive (default). The last %%propagate_accidentals returns an error message. August 19 2015 Abc2midi: complex time signature extension. Abc2midi now interprets M: 2+3+2/8 as M:7/8. Implementation: a small loop was added in the function readsig() in parseabc.c August 20 2015 Abc2midi new feature: introducing %%MIDI controlcombo. This allows combining two controlstrings into 1. Here is an example: X:1 T: control string combo M: 4/4 L: 1/4 K: F Q: 1/4 = 60 %%MIDI program 123 # bird tweets %expression %%MIDI controlstring 11 110 90 60 40 60 60 90 110 %%MIDI controlcombo %panning %%MIDI controlstring 10 0 0 20 40 60 80 100 120 127 127 !shape! c4 | controlstring 11 varies the expression and controlstring pans the output from the left to right speaker. The %%MIDI controlcombo command tells abc2midi that the panning controlstring should be included with the expression controlstring. Implementation: in genmidi.c, the controldata array has been converted into a two dimensional array and controlvals has been converted from a scalar to a single dimensional array. A flag controlcombo indicates whether to replace or combine the new control string. Each one dimensional component of controldata stores one of the control strings into a 'layer'. In queues.c, the function note_effect4 scans all layers for data and appends it to the eventlist[]. August 20 2015 Abc2midi new feature: If two controlstring are referenced in the %%MIDIx they will combined in the manner described above. Here is a sample file. X:1 T: control string combo M: 4/4 L: 1/4 K: F Q: 1/4 = 60 %%MIDI program 123 # bird tweets %expression %%MIDIdef expr controlstring 11 110 90 60 40 60 60 90 110 %%MIDIdef pan controlstring 10 0 0 20 40 60 80 100 120 127 127 %%MIDIx expr pan !shape! c4 |C4| Implementation: expand_midix was renamed to process_midix and the code was reworked so that it would loop through all the code words and call event_midi() to process all the %%MIDI commands that were generated. August 24 2015 abc2midi bug: the following tune was not processed correctly. X:1 T: control string bug M: 4/4 L: 1/4 K: F Q: 1/4 = 60 %%MIDI program 2 %%MIDI controlstring 11 110 !shape! c4 | %%MIDI controlstring 11 60 !shape!E4|D4| All three notes c4,E4 and D4 are played at the same time. Analysis: in note_effect5() the conditional if (j > 1) should only apply to the qsort function. August 25 2015 abc2midi bugs: the following tune was not processed correctly. X:1 T: controlstring and bendstring problems M: 4/4 L: 1/4 K: F Q: 1/4 = 120 %%MIDI program 60 # French Horn %%MIDIdef expr110 controlstring 11 110 %%MIDIdef expr60 controlstring 11 60 %%MIDI bendstring 0 2000 2000 %%MIDIx expr60 !shape! c2 c2 | The resulting midi file had two problems. The first c2 was extended in length and the pitch of the second c2 was effected by the !shape! command. Fixes: the pitchwheel was restored to its initial value at the end of the altered note. When restoring the controller to the initial state we checked whether a bend string was also processed. August 28 2015 abc2midi bug: The following file produces an artefact at the end of note. X:1 %%MIDIdef voloff100 controlstring 11 100 90 80 70 60 50 40 30 %%MIDIdef no-bend bendstring T:? C: ? M: 4/4 L: 1/4 Q:1/4=130 K: none %%propagate-accidentals not %%MIDI beat 100 95 80 1 %%MIDIdef petasth bendstring 0 0 900 900 0 -900 -900 0 -400 V:1 %%MIDI program 60 % french horn [M:3/4][I: MIDIx= petasth]!shape!A[I: MIDIx=no-bend voloff100]!shape!E2 Analysis note_effect5 restores the controller defaults before the note ends causing a transient at the end of the note. Fix: the restoration is done after the note. August 30 2015 abc2midi bug: in the following tune, X:1 %%MIDIdef voloff100 controlstring 11 100 90 80 70 60 50 40 30 %%MIDIdef no-bend bendstring T: controlstring state not initialized at start of track M: 4/4 L: 1/4 K: C %%MIDIdef petasth bendstring 0 0 900 900 0 -900 -900 0 -400 V:1 %%MIDI program 60 % french horn [I: MIDIx= petasth]!shape!A2[I: MIDIx=no-bend voloff100]!shape!E2 the voloff100 is applied to A2 despite the fact the command occurs after A2 Analysis: abc2midi creates a two track file. While it is creating the header track, controlnvals[0] was set to a nonzero value after MIDIx=no_bend voloff100 was processed and controldata[] contained appropriate data to perform the voloff100. Unfortunately, when the next track written controlnvals[0] was not reset. Fix: reset controlnvals[] August 31 2015 abc2midi bug: in the following file X: 1 %%MIDIdef slur2 bendstring 0 0 0 0 0 1000 T: last bendstring not picked up M: 4/4 L: 1/4 K: G Q: 1/4=80 %%MIDI program 42 % french horn V:1 G[I: MIDIx= slur2]!bend!A the bendstring value 1000 is not picked up Fix: in do deferred() (genmidi.c) the statement if (p* == 0) break; was moved after i = i +1; September 07 2015 Abc2midi new feature: in genmidi.c, the %%MIDI bendstring command can now accept up to 100 increments to accommodate long notes (benddata[100]); and the %%MIDI controlstring command can now accept up to 100 values to accommodate long notes (controldata[3][100]). In queues.c eventlist array was extended to 500 to handle the additional complexity. September 08 2015 Abc2midi: new commands %%MIDI vol n and %%MIDI volinc m introduced where n is a number between 0 and 127 and m is a positive or negative integer. The purpose of these commands is to provide to set the velocity of the note immediately following. All remaining notes are unaffected. The commands override the effects of %%MIDI beat, %%MIDI beatstring, %%MIDI beataccents, %%MIDI beatmod, %%MIDI nobeataccents, %%MIDI stressmodel, !ppp!, !pp!, !p!, !mp!, !mf!, !f!, !ff!, !fff!, !crescendo) for the particular note that is affected. %%MIDI vol n sets the velocity of the next note to n. %%MIDI volinc m increments (or decrements) the velocity of the next note by m, automatically ensuring that the velocity is in the range 0 to 127. For example: X: 1 T: Velocity alteration M: 4/4 L: 1/4 K: F CDEF|C\ %%MIDI volinc -30 D E [I: MIDI = vol 100] F| CDEF| By default the velocities of the notes CDEF are 105, 80, 95 and 80. (You can use the %%MIDI beat command to change these values.) The %%MIDI volinc -30, decrements the default velocity of D by 30 so its velocity is 50 instead of 80. The MIDI vol 100 command embedded in the info field, sets the velocity of F to 100. The velocities of the remaining notes in the last bar retain their defaults 105,80,95 and 80. Implementation: Introduced two global integer variables single_velocity_inc and single_velocity which are set to the default values 0 and -1 in the writetrack() in genmidi.c. These default values indicate that no alterations are to be made to the following note. Introduced new functions apply_velocity_increment_for_one_note() and set_velocity_for_one_note() which is called by noteon() in genmidi.c. The function dodeferred() in genmidi.c acts on the new %%MIDI commands and changes the default values of single_velocity_inc and single_velocity. September 08 2015 Abc2midi new feature: a different syntax can be used for changing the velocity of a single note as illustrated below. X: 1 T: Velocity alteration -different syntax M: 4/4 L: 1/4 K: F CDEF|C\ I: volinc = -30 D E [I: vol = 100] F| CDEF| The behaviour is identical to the above example. Implementation: the function event_info_key() in store.c was updated to recognize the key words vol or volinc, generate the respective %%MIDI commands, and send these commands to event_specific() for processing. September 08 2015 Abc2midi: new feature. The I: info command required to have an '=' sign following the key word, so that it could handle a group of commands such as I: MIDI = program 20 MIDI = drum d2dd 76 75 75 The purpose of the '=' sign was to allow the parser to distinguish the key word(s) (here MIDI) from the value when more than one key words appear. When only one command is embedded it should be unnecessary to include the '=' sign. The following sample illustrates the more lenient syntax that is now permitted. X:1 T: Generalized info syntax M: 2/4 L: 1/8 K: F I:vol= 60 % equal sign is optional if only key word is included % in I: field. C2 E2 | [I:vol 20] D2 F2| E2 [I:volinc = 50] C2|D2 [I:volinc -50]C2| C2 E2 |\ %%MIDI vol 20 D2 F2|E2 \ % equal sign is required if more than one key word is present I: MIDI= drum d2dd 75 76 76 MIDI = program 20 %%MIDI volinc 50 C2| C2 E2| [I:MIDI= vol 20] D2 F2| Implementation: the function event_info() in parser2.abc was updated. October 04 2015 The #ifdef _MSC_VER block was changed from #define snprintf _snprintf_s to #define sprintf _snprintf in both parseabc.c and store.c (The function _snprintf_s expects additional parameters and prevents compilation on some systems.) October 04 2015 Some problems with Makefile.in were fixed. In addition an uninstall option was introduced. October 03 2015 Abc2midi: increased the size of benddata[100] to benddata[256], controldata[MAXLAYERS][100] to controldata[MAXLAYERS][256], %%MIDI bendstring will read up to 256 values in dodeferred (genmidi.c). %%MIDI controlstring will read up to 256 values in doferred (genmidi.c) eventlist struct was increased to eventlist[1000]. October 08 2015 Edited abcmatch.c genmidi.c midi2abc.c parseabc.c store.c toabc.c in order to eliminate warnings from Microsoft Visual Studio 2010. makefiles/makefile.w32 was updated to make dynamically linked executables (instead of static). October 18 2015 Edited abcmatch.c, genmidi.c, matchsup.c, mftext.c, midi2abc.c, midicopy.c, midifile.c, parseabc.c, queues.c, store.c, stresspat.c and toabc.c to clean up all the implicit int warning messages reported by the Debian compiler. November 05 2015 abc2abc: keep 'M:C' and 'M:C|'; i.e. don't automatically change them to 'M:4/4' and 'M:2/2' % sample4.abc - this file is part of abcm2ps X:1 %%abc-version 2.0 T:testing 'common time' and 'split common time' signatures T: These should be preseved when transposing % use abc2abc generated from source including fixes from 'abcMIDI-2015.11.5_LM'. % try command: 'abc2abc common_time_sigs.abc -t 2'; % check that e.g. 'C' hasn't become '4/4'. M:C L:1/4 K:C CDEF |[M:4/4] GABc|] M:2/2 CDEF |[M:C|] GABc|] November 15 2015 Addressed the following Debian compiler warning messages reported in https://qa.debian.org/bls/packages/a/abcmidi.html I pointer-cast-size-mismatch midicopy.c:371 (alpha, arm64, kfreebsd-amd64, mips64el, ppc64, ppc64el, s390x, sparc64) I pointer-cast-size-mismatch yapstree.c:1338 (alpha, arm64, kfreebsd-amd64, mips64el, ppc64, ppc64el, s390x, sparc64) I pointer-cast-size-mismatch yapstree.c:1352 (alpha, arm64, kfreebsd-amd64, mips64el, ppc64, ppc64el, s390x, sparc64) I pointer-cast-size-mismatch yapstree.c:1513 (alpha, arm64, kfreebsd-amd64, mips64el, ppc64, ppc64el, s390x, sparc64) I pointer-cast-size-mismatch yapstree.c:2176 (alpha, arm64, kfreebsd-amd64, mips64el, ppc64, ppc64el, s390x, sparc64) W implicit-declaration abcmatch.c:1274 (alpha, arm64, armel, armhf, hppa, hurd-i386, i386, kfreebsd-amd64, kfreebsd-i386, mips, mips64el, mipsel, powerpc, ppc64, ppc64el, s390x, sh4, sparc64, x32) In yapstree.c changed (void*) to (int *) to the calls to addfeature. In midicopy.c changed the call arguments of metaseqnum from (int seq) to (char c1, char c2). In abcmatch.c added #include December 19 2015 Abc2midi: bug fix - calculation of equal temperament scale was changed on October 08 2015. It has now been restored in store.c thanks to Hudson Lacerda. December 31 2015 Abc2midi bug: The following tune causes abc2midi to crash when running with -BF parameter. X:1 T: Missing R: field M: 2/4 L: 1/8 K: G %%MIDI stressmodel 2 CDEF|ABcd| abc2midi crash.abc -BF 2 3.84 December 19 2015 abc2midi Floating point exception Fix: startfile() in store.c initializes rhythmdesignator to an empty string. apply_bf_stressfactors() in store.c ensures that rhythmdesignator is set before allowing the function to continue. The function load_stress_parameters() in stresspat.c now has an error return and reports an unidentified rhythmdesignator to apply_bf_stressfactors(). January 02 2016 Abc2midi > and < action: In the past broken notes indicated by A>B and AB A G, h --> B, and i --> D %%MIDI gchord ghighi "G" G6|G6|\ % "G5" expands to G,D so g--> G, and h --> D but i --> does not map "G5" G6|G6| i does not map producing a gap in the Alberti Bass Fix: dogchords() in genmidi.c was modified to map to the last note in the gchord chord in this situation to prevent a gap. In the above example i would also map into D. abcmidi/doc/midi2abc.10000644000000000000000000002200312564560732013454 0ustar rootroot.TH MIDI2ABC 1 "10 March 2008" .SH NAME \fBmidi2abc\fP \- program to convert MIDI format files to abc notation .SH SYNOPSIS midi2abc \-f \fIinfile\fP [\-xa] [\-ga] [\-a \fIacbeats\fP] [\-m \fItime signature\fP] [\-ppu \fiparts per unit\fP] [\-aul \fidenominator of unit length\fP] [\-gu] [\-b \fIbars\fP] [\-Q \fItempo\fP] [\-u \fipulses\fP] [\-k \fIkey\fP] [\-c \fIchannel\fP] [\-obpl] [\-bpl \fibars\fP] [\-bps \fPbars\fP] [\-o \fIfilename\fP] [\-s] [\-sr \fiunits\fP] [\-sum] [\-nt] [\-splitbars] [\-splitvoices] [\-midigram] [\-mftext] [\-nogr] [\-title \fistring\fP] [\-origin \fistring\fP] .SH DESCRIPTION \fImidi2abc\fP takes a MIDI format file and converts it to something as close as possible to abc text format. The user then has to add text fields not present in the MIDI header and possibly tidy up the abc note output. .PP The output of midi2abc is printed to the screen. To save it to a file, use the redirection operator, (e.g. \fImidi2abc \-f file.mid > file.abc\fP) or specify the output file using the \-o option. .PP Use only one or none of the options \-u \-gu, \-b and \-Q. Midi2abc normally converts the MIDI time units into quantum units normally corresponding to the abc 1/16th note or 1/32nd note. If none of these is present, the program will use the PPQN information in the MIDI header to compute the suitable conversion factor. For most MIDI files on the web, it is recommended to rely on the MIDI header information and not use any of the options other than the formatting options. .PP The program will extract the time signature information from the MIDI file if it is present. Otherwise it will assume 4/4 or you could specify it with \-m. option. .PP If the tune has an anacrusis, you can use either the \-ga or \-xa option to estimate the its length. Alternatively, you can specify its value using the \-a option. The anacrusis is specified in half unit lengths, where the unit length is defined by the L: field. For example if L: 1/8, then a quarter note would be indicated by the value 4, (4 1/16 units). .SS OPTIONS .TP .B -a \fIacbeats\fP where acbeats specifies the anacrusis in half unit lengths. .TP .B -xa extract the anacrusis from file by finding the first strong note .TP .B -ga guess the anacrusis by minimizing the number of ties across bars .TP .B -m \fItime signature\fP time signature .TP .B -b \fIbars\fP number of bars wanted in output .TP .B -Q \fItempo\fP tempo in quarter\-notes per minute .TP .B -u \fipulses\fP Allows you to specify directly the number of midi pulses per abc time unit. .TP .B -ppu \fiparts per abc unit length\fP Normally, the smallest note unit that midi2abc can extract is half the L: unit length.This is called the quantum unit. Thus for L: 1/8, midi2abc can extract 1/16 notes but not 1/32 notes. You can change this by specifying \-ppu 4 for example. The number of parts should be a power of 2. .TP .B -aul \fidenominator of abc unit length\fP Normally midi2abc chooses a unit length of 1/8 or 1/16 depending upon the time signature. For time signatures smaller than 3/4 the L: 1/16 is used and for larger time signatures L: 1/8 is used. You can specify the unit length to be used using this parameter. Thus \-aul 32 will cause midi2abc to use a unit length of 1/32 nd note. .TP .B -gu Tells midi2abc to estimate the number of midi pulses per abc time unit from the note duration or spacing in the MIDI file. .TP .B -gk Tells midi2abc to guess the key signature by minimizing the number of accidentals even if the key signature is already specified in the MIDI file. By default the key signature is the one specified in the MIDI file. If it is not specified, then the program guesses the key signature by minimizing accidentals. .TP .B -k \fIkey\fP key signature: \-6 to 6 sharps. .TP .B -c \fIchannel\fP select only this midi channel. .TP .B -f \fIinfile\fP input file in midi format .TP .B -o \fIoutput file\fP specifies the output abc file name. .TP .B -s do not discard very short notes. .TP .B -sr \fIquantum units\fP do not notate a short rest smaller than the specified size after a note. If the size (in quantum units) is zero, nothing is done. For larger values, the rest is absorbed into the preceding note. In other words, the preceding note is lengthened to include that rest. .TP .B -sum print a short summary of the input midi file. .TP .B -nt do not look for triplets or broken rhythm .TP .B -obpl Print only one bar per line instead of 4. For complex music this improves the readability and avoids some problems with some abc to postscript converters. This option is deprecated. .TP .B -nogr (No note grouping.) Inserts a space between all notes. It makes a less pretty postscript file but it is easier to edit. .TP .B -bpl \finbars\fP Print nbars of music on every line followed by a backslash. .TP .B -bps \finbars\fP When nbars have been printed (including those lines joined by a backslash continuation) go to a new line (with no backslash). .TP .B -splitbars This parameter changes the way midi2abc prints chords composed of notes of unequal length (polyphonic chords). Normally, midi2abc joins the longer notes to the notes in the following chord using ties. A more readable output, can be obtained if the measure is split into separate parts using the '&' feature in abc notation. The algorithm for dividing the notes in a polyphonic chord to separate voices (label_splits in midi2abc.c) needs some improvement. I welcome any assistance. .TP .B -splitvoices This parameter like above handles polyphonic chords by splitting an entire voice into multi voices. .TP .B -midigram When this option appears, all other options are ignored and no abc file is produced. Instead a list of all notes in the MIDI file are printed in a fixed format. Each line represents a pair of MIDI note on/off event. The line contains the on/off time of the note, its track number, channel number, midi pitch and midi velocity. The last record indicates the duration of the MIDI file in MIDI pulse units. The output is designed to go into a graphical user interface which will produce a graphical representation (piano roll). .TP .B -mftext When this option appears, all other options are ignored and no abc file is produced. Instead a list of all the MIDI commands are printed. The output is designed to go into a graphical user interface provided by runabc.tcl. .TP .B -title \fistring\fP Replaces the default title field following T: with the given string. .TP .B -origin \fistring\fP Adds an O: field with the given string. .SS FEATURES * The key is chosen so as to minimize the number of accidentals. Alternatively, the user can specify the key numerically (a positive number is the number of sharps, a negative number is minus the number of flats). .PP * Note length can be set by specifiying the total number of bars or the tempo of the piece. Alternatively the note length can be read from the file. However, by default it is deduced in a heuristic manner from the inter-note distances. This means that you do not have to use the MIDI clock as a metronome when playing in a tune from a keyboard. .PP * Barlines are automatically inserted. The user specifies the number of measures in the anacrusis before the first barline and the time signature. .PP * The program can guess how the length of the anacrusis, either by looking for the first strong note or minimizing the number of notes split by a tie across a barline. .PP * Where a note extends beyond a bar break, it is split into two tied notes. .PP * The output has 4 bars per line. .PP * Enough accidental signs are put in the music to ensure that no pitch errors occur if a barline is added or deleted. .PP * The program attempts to group notes sensibly in each bar. .PP * Triplets and broken rhythm (a>b) are supported. .PP * Chords are identified. .PP * Text information from the original MIDI file is included as comments. .PP * The \-c option can be used to select only 1 MIDI channel. Events on other channels are ignored. .SS LIMITATIONS midi2abc does not ... .PP * Supply tune title, composer or any other field apart from X: , K:, Q:, M: and L: - these must be added by hand afterwards, though they may have been included in the text of the MIDI file. .PP * Support duplets, quadruplets, other esoteric features. .PP * Support mid-tune key or time signature changes. .PP * Deduce repeats. The output is just the notes in the input file. .PP * Recover an abc tune as supplied to abc2midi. However, if you want to do this, "midi2abc \-xa \-f file.mid" comes close. .SH "SEE ALSO" abc2ps(1), abc2midi(1), abc2abc(1) .SH AUTHOR James Allwright .SH SUPPORTED Seymour Shlien .SH VERSION This man page describes midi2abc version 2.91 from March 09 2008. .SH COPYRIGHT Copyright 1999 James Allwright .PP midi2abc does not work correctly if lyrics are embedded in the same track as the notes. If you are producing the MIDI file using abc2midi, use the \-STFW option to ensure that the lyrics are put in a separate track. .PP midi2abc is supplied "as is" without any warranty. It is free software and can be used, copied, modified and distributed without fee under the terms of the GNU General Public License. abcmidi/doc/midicopy.10000644000000000000000000001114712425232236013615 0ustar rootroot.TH MIDICOPY 1 .SH NAME midicopy \- Copy selected track, channel, time interval of a MIDI file to another MIDI file .SH SYNOPSIS \fBmidicopy\fP [\fB-ver\fP] [\fB-trks\fP \fIn1,n2,..\fP]\ [\fB-xtrks\fP \fIn1,n2,..\fP]\ [\fB-chans\fP \fIn1,n2,...\fP]\ [\fB-from\fP \fIn (in midi ticks)\fP] [\fB-to\fP \fIn (in midi ticks)\fP]\ [\fB-fromsec %f\fP \fIn (in seconds)\fP] [\fB-tosec\fP \fIn (in seconds)\fP]\ [\fB-frombeat %f\fP \fIn (in beats)\fP] [\fB-tosec\fP \fIn (in beats)\fP]\ [\fB-replace\fP \fItrk,loc,val\fP] [\fB-tempo %n\fP] [\fB-speed %f\fP]\ [\fB-drumfocus\fP \fIn \fIm\fP] [\fB-mutenodrum [%d]\fP]\ [\fB-setdrumloudness\fP \fIn \fIm\fP]\ \fIinput.mid output.mid\fP .SH "DESCRIPTION" .PP .B midicopy is used to copy part of a MIDI file to another MIDI file. You can select a particular time interval, particular channels, and particular tracks or any combinations. If one or both of the run time parameters \-from or \-to are included, the program returns the playing time in seconds of the output file. Midicopy was developed by Seymour Shlien from the midifilelib distribution available from .IR http://www.harmony-central.com/MIDI/midifilelib.tar.gz . .SH OPTIONS .TP .B -ver prints version number and then exits .TP .B -trks n1,n2, etc Selects the tracks to be copied where the track numbers start from 1. If more than one track is specified, they should be separated by commas. You should always copy track 1 since by convention it contains information pertinent to all the other tracks. By default all tracks are copied unless you specify particular tracks using this run time parameter. .TP .B -xtrks n1,n2, etc Lists the tracks to exclude from copying. All other tracks are copied. This option does not work in combination with \-trks. .TP .B -chns n Like above, it specifies the MIDI channels to be copied. By default all channels are copied. Channel numbers also start from 1. .TP .B -from n The program will copy all MIDI commands starting from midi pulse number n. By default it will start from time zero or the beginning of the MIDI file. .TP .B -to n Stops copying all events after midi pulse number n. By default the file is copied to the end. .TP .B -frombeat n The program will copy all MIDI commands starting from quarter beat number n. By default it will start from time zero or the beginning of the MIDI file. .TP .B -tobeat n Stops copying all events after quarter beat number n. By default the file is copied to the end. .TP .B -fromsec n The program will copy all MIDI commands starting from time n in seconds. .TP .B -tosec n Stops copying all events after time n in seconds. These two options (\-fromsec and \-tosec) do not work accurately if the MIDI file has more than one tempo command. Only the first one is used for converting seconds into MIDI pulse units. It is therefore preferable to use the \-from and \-to options. .TP .B -replace trk,loc,val This option should be used alone. Midicopy will copy the entire file verbatim except it will replace a byte by val, where the byte is located in the specified track (trk) and specified position (loc). Commonly this function is used for changing a particular MIDI program number (instrument) associated with a channel. You need to know the byte count in the track of that parameter in order to use this function, .TP .B -tempo quarter notes/minute All tempo indications in the midi file will be replaced with the above value. .TP .B -speed factor All tempo indications in the midi file will be multiplied with this factor. Values greater than 1.0 will speed up the music while lower values slow the music. The factor is a floating point value. .TP .B -drumfocus drum-code excluded_drum_velocities The selected drum line (specified by the drum-code pitch value) is highlighted by reducing the loudness of all other drum lines to the excluded_drum_velocities value. The drum-code value must be in the range of 35 to 81 inclusive. .TP .B -mutenodrum [level] All channels which are not 9 (drum channel) are attenuated to the given level. If level is not specified, it is assumed to be zero. .TP .B -setdrumloudness n m where n is between 35 to 81 inclusive and m is the loudness between 0 and 127. The loudness of all instances of drum n are changed to m. .SH EXAMPLE .B midicopy.exe -trks 1,5 -from 2669 -to 8634 uzicko.mid fragment.mid Midicopy will copy tracks 1 and 5 starting from midi pulse position 2669 and ending at MIDI pulse position 8634. .SH "SEE ALSO" .PP .IR abcmtex "(1), " abc2abc "(1), " abc2midi "(1), " midi2abc "(1) ", yaps "(1)" .SH AUTHOR This manual page was written by Seymour Shlien. .SH VERSION This man page describes midicopy version 1.20 from October 28 2013. abcmidi/doc/mftext.10000644000000000000000000000111311020033716013267 0ustar rootroot.TH MFTEXT 1 .SH NAME mftext \- Dump a MIDI file as text .SH SYNOPSIS .BI mftext " file" .SH "DESCRIPTION" .PP .B mftext gives a verbose description of what is in a MIDI file. You may wish to use it to check the output from .BR abc2midi . It is part of the original midifilelib distribution available from .IR http://www.harmony-central.com/MIDI/midifilelib.tar.gz . .SH "SEE ALSO" .PP .IR abcmtex "(1), " abc2abc "(1), " abc2midi "(1), " midi2abc "(1)" .SH AUTHOR This manual page was written by Anselm Lingnau , for the Debian GNU/Linux system. abcmidi/doc/abcmatch.txt0000644000000000000000000002551212564557426014241 0ustar rootrootabcmatch version 1.35 January 15 2006. seymour shlien Introduction: ------------ The purpose of this program is to search for specific sequences of notes in an abc file composed of many tunes. For example, if you know a few bars of a tune, you can use this program to find the tune having this sequence and perhaps identify the tune. At a minimum, abcmatch requires two files. A template file called match.abc which contains the bars that you are searching for and a large file consisting of a hundred or more abc tunes. The program automatically loads up the match.abc file and then scans every tune in the large file. The match.abc file is a regularly formatted abc file containing the basic fields, X:, M:, L:, and K: and the body. Normally, this file is created by runabc.tcl. An example match.abc file is shown below. X:1 M:6/8 L:1/8 K:E cff f2e| As well as the sample bars, abcmatch needs to know the meter (given by M:) and the key signature (given by K:). The default note length L: should also be given if it is not 1/8. It is important that all bars be terminated with a bar line indicated by | (otherwise that bar may not be seen by the program). Abcmatch uses the key signature to know the relative position of the notes in the scale. It also uses the key signature to determine all the assumed sharps and flats. Thus the program can find matching bars in a tune transposed to another key signature (assuming the key difference is not too large). When the program finds matches, they are returned in a list that looks like this. abcmatch.exe scotjig.abc 29 30 4 30 31 4 Each line indicates a particular match made by the program. The first number, (eg. 29) indicates the relative position of the tune in the abc file. Thus in this example, it indicates that a match was found for the 29 th tune in compilation file scotjib.abc. The next number is the X: reference number of that tune, and the last number is the bar number of the matching tune. Bar numbers are counted sequentially from the start of the tune, ignoring all V: and P: indications. Thus the bar numbers may not match the ones you get when you print the tune using one of the variants of abc2ps or yaps. Though the program can be run stand alone, it is really meant to be run with a graphics user interface such as runabc.tcl (version 1.59 or higher). Most of its output is rather cryptic. In performing the match, the program ignores all guitar chords, karaoke, note decorations (eg. stacatto markings), grace notes and hornpipe rhythm indications in either the match.abc template file or in the target file. Furthermore if chords in the form of [G2c2] are embedded in the abc file, only the higher note c2 is matched. Any warnings and error messages that are normally returned by the parser are suppressed unless the run time parameter -c is included. Installation: ------------ Unless you are running the program on Microsoft's windows operating system, it will be necessary for you to build the program from sources. For windows environment, I shall provide the executable. Here is how the makefile looks. CFLAGS=-c abcmatch: parseabc.o matchsup.o abcmatch.o gcc parseabc.o matchsup.o abcmatch.o -o abcmatch.exe parseabc.o : parseabc.c abc.h gcc $(CFLAGS) abcparse.c matchsup.o : matchsup.c abc.h gcc $(CFLAGS) abcstore.c abcmatch.o : abcmatch.c abc.h gcc $(CFLAGS) abcmatch.c The program has been built using the gcc (GNU compiler) as well as Microsoft Visual C++ (with many warning messages). Operation: --------- Here is now an explanation of the program and its run time parameters. If you run abcmatch without any parameters you will see: abcmatch version 1.55 Usage : abcmatch [-options] [reference number] selects a tune -c returns error and warning messages -v selects verbose option -r resolution for matching -con pitch contour match -fixed fixed number of notes -qnt quantized pitch contour -lev use levenshtein distance -a report any matching bars (default all bars) -ign ignore simple bars -br %d only report number of matched bars when above given threshold -tp [reference number] -ver returns version number -pitch_hist pitch histogram -wpitch_hist interval weighted pitch histogram -length_hist pitch histogram -interval_hist pitch interval histogram -pitch_table separate pitch pdfs for each tune -interval_table separate interval pdfs for each tune When running this program, you must provide the name of the abc file name containing the numerous tunes. The other parameters are optional and are explained below. The -c and -v options are mainly used for debugging when the program does not do what was expected. The -ver option does nothing but return the version number of the program. (This is used to perform a sanity check when you are running it from runabc). All the remaining parameters (-r -con -a -br) control the matching process. The option -norhythm, causes the matching algorithm to ignore the length of notes in a bar, thus E3/2F/D GA2 would match EFD G2A. The option ignores -r parameter since it is now irrelevant. The option -pitch_table is used to produce a interval weighted pitch histogram for each tune in the file. If this is saved in an external file, that file could be used as a database for finding tunes with similar pitch probability density functions (pdf). The -r parameter controls how the matching criterion handles small rhythm variations in the melody. The -r option must be followed by a number which specifies the temporal resolution for the match. When the number is zero, this indicates that a perfect match should be performed, meaning that the lengths of each note in the bar must match exactly in order to be reported. For larger values a looser match will be performed as described below. Note lengths are converted into temporal units where a quarter note normally is assigned a value of 24. Therefore an eight note has a value of 12, a sixteenth has a value of 6, a half note has a value of 48 and etc. If you specify a temporal resolution of 12, then the pitch values of the notes only need to match at time units which are multiples of an eighth note. This means that the program would match the two bars C2 D2| and C C D D|. Similarly C2 D2| would also match C/D/C/D/D2|. By using a suitable value of the resolution, you can perform the matching only at the beginning of a measure or at the beginning of each beat. The -fixed option causes the program to disregard bar lines when does the matching. It allows matching of notes between tunes having different time signatures. n is a number which specifies the exact number of notes to match. For example if n is 4, the program could match |C E G E| .. with |C E|G E| Note the matcher still starts at a beginning of a given bar for both the tune and template. Normally, when the program is presented with a sequence of several bars, the program will try it match it with a matching sequence. If abcmatch is run with the -a option, then the bars are matched individually in any sequence. In other words any matching bar found is reported. The -con option specifies contour matching. In this case, the program uses the key signature only to indicate accidentals. The pitch contour is computed from the pitch difference or interval between adjacent notes. Thus C2 DE| and c2 de| and G2 AB| all have the same pitch contour. The -qnt option will use the contour matching algorithm but also quantize the intervals using the following table unison and semitone 0 minor 2nd to major 2nd 1 minor 3rd to major 3rd 2 any larger interval 3 negative numbers are descending intervals. The -tp followed by a file name and reference number allows you to substitute any tune for the template match.abc. When using this feature, the entire tune is used as a template. Abcmatch does not match the template with itself, and only bars which match bars in other tunes are reported. The -br followed by a threshold, runs the program in a brief mode designed to identify groups of tunes sharing common bars. (-br stands for brief mode; I cannot think of a better name right now.) In this mode, the program counts the numbers of bars in the test tune which are also present in match.abc. If the number of common bars is larger or equal to the threshold then the program reports the tune and the number of common bars. The program scans all the tunes in the abc file and returns a list of all the tunes which have more than a specific number of bars in common with the template, match.abc. In actual use, the program is run repeatedly by a script. For each tune in a abc file, it creates a template file called match.abc and then executes abcmatch. The outputs are displayed on the screen in a form easy to interpret. Currently, the user has no control of the matching criterion. The rhythm must match exactly and the notes are transposed to suit the key signature. In other words the -r parameter is zero independent of what is specified in the parameter list. The -pitch_hist or -length_hist runs the program in another mode. It produces a histogram of the distribution of the notes in the abc file. Thus if you type abcmatch.exe scotjig.abc -pitch_hist pitch_histogram 64 2 66 9 67 11 69 30 71 18 73 12 74 14 76 14 78 14 79 4 81 4 The pitch is indicated in midi units. Thus middle C is 60 and the pitches go up in semitone units. Following the pitch is a count of the number of times that note occurred. If you type abcmatch.exe scotjig.abc -length_hist length histogram 12 100 24 20 36 6 48 2 72 4 The program quantizes a quarter note into 24 units. Thus eighth notes have a value of 12, dotted half notes 72, etc. The program does not require the match.abc file to be present if you are computing the histograms since it does not perform any matching. abcmatch.exe scotjig.abc -interval_hist computes the histogram of the pitch interval in midi units between adjacent notes. The histogram is restricted between intervals -12 and 12 units. eg. interval_histogram -5 2 -4 3 -3 10 -2 17 -1 3 0 8 1 3 2 23 3 11 4 1 5 4 For a collection of tunes in a file, you can use -pitch_table or -interval_table to create a database for future analysis. Limits of the program --------------------- The program has some limits. For example, the abc file must have bar lines. Tied notes cannot be longer than 8 quarter notes. Specifying a too small resolution (eg. -r 1) may causes some buffers to be exceeded. When there are differences of key signatures more than 5 semitones, the program may transpose the notes in the wrong direction. Abc tunes with more than one key signature or time signature may not be processed correctly. Comment: ________ This program is designed to be a research tool to find similarities between abc tunes. I have discovered a few problems with tied notes and double or triple bar lines. abcmidi/doc/abc2midi.10000644000000000000000000004607712642211112013453 0ustar rootroot.TH ABC2MIDI 1 "27 August 2011" .SH NAME \fBabc2midi\fP \- converts abc file to MIDI file(s) .SH SYNOPSIS abc2midi \fIinfile\fP [\fIrefnum\fP] [\-c] [\-v] [\-ver] [\-t] [\-n limit] [\-CS] [\-quiet] [\-silent] [\-Q tempo] [\-NFNP] [\-NFER] [\-NGRA] [\-STFW] [\-OCC] [\-NCOM] [\-HARP] [\-BF] [\-TT] [\-o outfile] \-CSM [filename] .SH DESCRIPTION The default action is to write a MIDI file for each abc tune with the filename N.mid, where is the filestem of the abc file and N is the tune reference number. If the \-o option is used, only one file is written. This is the tune specified by the reference number or, if no reference number is given, the first tune in the file. .SH OPTIONS .TP .B \fIrefnum\fP process the tune with reference number \fIrefnum\fP .TP .B -c selects checking only .TP .B -v n selects verbose option where n is the level (optional) .TP .B -ver prints version number and exits .TP .B -t selects filenames derived from tune titles .TP .B -CS use 2:1 instead of 3:1 for broken rhythms .TP .B -quiet Suppresses some common warnings. .TP .B -silent Supresses other messages. .TP .B -n \fI X\fP limits the length of the file name stem to X characters .TP .B -Q \fI tempo\fP sets the default tempo in quarter notes per minute if it was not specified in the abc header. .TP .B -NFNP Ignore any dynamic indications !f! !ff! etc. .TP .B -NFER Ignore any fermata indications (eg H or !fermata!). .TP .B -NGRA Ignore any grace notes. .TP .B -STFW Place lyric text in separate MIDI tracks. .TP .B -NCOM Suppress some comments in the output MIDI file. .TP .B -OCC Accept old chord convention (eg +D2G2+ instead of [DG]2). .TP .B -BF BarFly mode: invokes a stress model if possible. .TP .B -HARP Roll ornaments=roll are generated for the harpist (same pitch) .TP .B -TT Changes the tuning from A = 440 Hz. .TP .B -o \fIoutfile\fP write output to \fIoutfile\fP .TP .B -CSM \fIinfile\fP load a set of custom stress modes from a file .SH FEATURES .PP * Broken rhythms (>, <), chords, n-tuples, slurring, ties, staccatto notes, repeats, in-tune tempo/length/time signature changes are all supported. .PP * R:hornpipe or r:hornpipe is recognized and note timings are adjusted to give a broken rhythm (ab is converted to a>b). .PP * Most errors in the abc input will generate a suitable error message in the output and the converter keeps going. .PP * Comments and text fields in the abc source are converted to text events in the MIDI output .PP * If guitar chords are present, they are used to generate an accompaniment in the MIDI output. .PP * If there are mis-matched repeat signs in the abc, the program attempts to fix them. However, it will not attempt this if a multi-part tune description has been used or if multiple voices are in use. .PP * Karaoke MIDI files can be generated by using the w: field to include lyrics. .PP * Nonnumeric voice id's, eg. V: soprano, as proposed for the new abc standard is accepted. .PP * Invisible rests specified by x are treated the same way as normal rests (z). .PP * Decorations may be indicated using either the deprecated notation (eg. !fermata!) or the standard version 2.0 notation (eg. +fermata+). .PP .SH LIMITATIONS * No field is inherited from above the X: field of the tune. .SH "ABC SYNTAX EXTENSIONS" * There are some extensions to the abc syntax of the form .PP %%MIDI channel n .PP These control channel and program selection, transposing and various other features of abc2midi. .PP Each of these should appear on a line by itself. All of them are allowed within the abc tune body. By using these in combination with the part notation, one can, for example, play a part transposed or in a different key. .PP The idea behind this syntax is that other programs will treat it as a comment and ignore it. .PP %%MIDI channel n .PP selects melody channel n (in the range 1-16). .PP %%MIDI program [c] n .PP selects program n (in the range 1-128) on channel c. If c is not given, the program is selected on the current melody channel. Most modern tone generators follow the General MIDI standard which defines the instrument type for each program number. .PP %%MIDI beat a b c n .PP controls the way note velocities are selected. The first note in a bar has velocity a. Other "strong" notes have velocity b and all the rest have velocity c. a, b and c must be in the range 0-128. The parameter n determines which notes are "strong". If the time signature is x/y, then each note is given a position number k = 0, 1, 2 .. x-1 within each bar. Note that the units for n are not the unit note length. If k is a multiple of n, then the note is "strong". The volume specifiers !ppp! to !fff! are equivalent to the following : .P !ppp! = %%MIDI beat 30 20 10 1 .br !pp! = %%MIDI beat 45 35 20 1 .br !p! = %%MIDI beat 60 50 35 1 .br !mp! = %%MIDI beat 75 65 50 1 .br !mf! = %%MIDI beat 90 80 65 1 .br !f! = %%MIDI beat 105 95 80 1 .br !ff! = %%MIDI beat 120 110 95 1 .br !fff! = %%MIDI beat 127 125 110 1 .PP %%MIDI beatmod n .PP Increments by n (or decrements if n is negative) the velocities a, b and c described above. The instructions !crescendo(! and !crescendo)! are equivalent to inserting a %%MIDI beatmod 15 whereever they occur. (Alternatively you can use !<(! and !<)!.) Similarly the instructions !diminuendo(! and !diminuendo)! are equivalent to %%MIDI beatmod \-15. .PP %%MIDI deltaloudness n .PP where n is a small positive number. By default the crescendo and diminuendo instructions modify the beat variables a, b, and c by 15 velocity units. This instruction allows you to set this default to value n. .PP %%MIDI nobeataccents .PP For instruments such as church organ that have no greatly emphasized beat notes, using this will force use of the 'b' velocity (see %%MIDI beat) for every note irrespective of position in the bar. This allows dynamics (ff, f, etc) to be used in the normal way. .PP %%MIDI beataccents .PP Revert to emphasizing notes the the usual way. (default) .PP %%MIDI beatstring .PP This provides an alternative way of specifying where the strong and weak stresses fall within a bar. 'f' means velocity a (normally strong), 'm' means velocity b (medium velocity) and 'p' means velocity c (soft velocity). For example, if the time signature is 7/8 with stresses on the first, fourth and sixth notes in the bar, we could use the following .PP %%MIDI beatstring fppmpmp .PP %%MIDI transpose n .PP transposes the output by the specified number of semitones. n may be positive or negative. .PP %%MIDI rtranspose n .PP Relative transpose by the specified number of semitones. i.e. %%MIDI transpose a followed by %%MIDI rtranspose b results in a transposition of a+b. %%MIDI transpose b will result in a transposition of b semitones, regardless of any previous transposition. .PP %%MIDI c n .PP specifies the MIDI pitch which corresponds to c. The default is 60. This number should normally be a multiple of 12. .PP %%MIDI grace a/b .PP sets the fraction of the next note that grace notes will take up. a must be between 1 and b-1. The grace notes may not sound natural in this approach, since the length of the individual grace notes vary with the complexity of the grace and the length of the following note. A different approach (which is now the default) assumes that the grace notes always have a fixed duration. To use the other approach you would specify, %%MIDI gracedivider b where b specifies how many parts to divide the unit length specified by the L: field command. For example if b = 4 and L: = 1/8, then every grace note would be 1/(8*4) or a 32nd note. Time would be stolen from the note to which the grace notes are applied. If that note is not long enough to handle the grace then the grace notes would be assigned 0 duration. .PP %%MIDI chordname name n1 n2 n3 n4 n5 n6 .PP Defines how to play a guitar chord called "name". n1 is usually 0 and n2, n3 to n6 give the pitches of the other notes in semitones relative to the root note. There may be fewer than 6 notes in the chord, but not more.If "name" is already defined, this command re-defines it. Unlike most other commands, chordname definitions stay in effect from where they are defined to the end of the abc file. The following illustrates how m, 7, m7 and maj7 could be set up if they were not already defined. .PP %%MIDI chordname m 0 3 7 .br %%MIDI chordname 7 0 4 7 10 .br %%MIDI chordname m7 0 3 7 10 .br %%MIDI chordname maj7 0 4 7 11 .PP %%MIDI gchord string .PP sets up how guitar chords are generated. The string is a sequence made of of z's, c's f's and b's for rests, chords, fundamental and fundamental plus chord notes respectively. This specifies how each bar is to be played. An optional length is allowed to follow the z's, c's f's and b's e.g. czf2zf3. If the abc contains guitar chords, then abc2midi automatically adds chords and fundamentals after encountering the first guitar chord. It keeps using that chord until a new chord is specified in the abc. Whenever the M: field is encountered in the abc, an appropriate default string is set : .P For 2/4 or 4/4 time default is equivalent to : %%MIDI gchord fzczfzcz .P For 3/4 time default is equivalent to : %%MIDI gchord fzczcz .P For 6/8 time default is equivalent to : %%MIDI gchord fzcfzc .P For 9/8 time default is equivalent to : %%MIDI gchord fzcfzcfzc .P The gchord command has been extended to allow you to play the individual notes comprising the guitar chord. This allows you to play broken chords or arpeggios. The new codes g,h,i,j, G,H,I,J reference the individual notes starting from the lowest note of the chord (not necessarily the root in the case of inversions). For example for the C major chord, g refers to C, h refers to E and i refers to G. For a gchord command such as, .P %%MIDI gchord ghih .P Abc2midi will arpeggiate the C major guitar chord to CEGE. The upper case letters G,H,I, and J refer to the same notes except they are transposed down one octave. Note for the first inversion of the C major chord (indicated by "C/E"), E would be the lowest note so g would reference the note E. .P Like other gchord codes, you may append a numeral indicating the duration of the note. The same rules apply as before. You can use any combination of the gchord codes, (fcbghijGHIJz). .PP %%MIDI chordprog n .PP Sets the MIDI instrument for the chords to be n. If the command includes the string octave=n where n is a number between \-2 and 2 inclusive, then this will shift the pitch of the instrument by n octaves. For example %%MIDI chordprog 10 octave=1.) .PP %%MIDI bassprog n .PP Sets the MIDI instrument for the bass notes to be n. If the command includes the string octave=n where n is a number between \-2 and 2 inclusive, then this will shift the pitch of the instrument by n octaves. For example %%MIDI bassprog 10 octave=\-1.) .PP %%MIDI chordvol n .PP Sets the volume (velocity) of the chord notes at n. .PP %%MIDI bassvol n .PP Sets the volume (velocity) of the bass notes at n. There is no corresponding melodyvol command since there are 3 velocity values for melody, set using the beat command. .PP %%MIDI gchordon .PP Turns on guitar chords (they are turned on by default at the start of a tune). .PP %%MIDI gchordoff .PP Turns off guitar chords. .PP %%MIDI droneon .PP Turns on a continuous drone (used in bagpipe music) consisting of two notes. By default the notes are A, and A,, played on a bassoon at a velocity of 80. This can be configured by the %%MIDI drone command described below. .PP %%MIDI droneoff .PP Turns off the continuous drone. .PP %%MIDI drone n1 n2 n3 n4 n5 .PP Sets the drone parameters where n1 is the MIDI program, n2 and n3 specify the MIDI pitches of the two notes in the chord, and n4 and n5 specify the MIDI velocities of the two notes. If you do not set these parameters they are by default 70 45 33 80 80. A value of zero or less indicates that the setting of this parameter should be left as it is. .PP %%MIDI drum string [drum programs] [drum velocities] .PP This sets up a drum pattern. The string determines when there is a drum beat and the drum program values determine what each drum strike sounds like. .PP e.g. %%MIDI drum d2zdd 35 38 38 100 50 50 .PP The string may contain 'd' for a drum strike or 'z' for a rest. By default a voice starts with no drum pattern and '%%MIDI drumon' is needed to enable the drumming. The drum pattern is repeated during each bar until '%%MIDI drumoff' is encountered. The %%MIDI drum command may be used within a tune to change the drum pattern. This command places the drum sounds on channel 10 and assumes your tone generator complies with the General Midi standard - if it does not, then you may hear tones instead of drum sounds. .PP In both the gchord and drum commands, the standard note length of a single note f,c,z or d is not set by the L: command. Instead it is adjusted so that the entire gchord string or drum string fits exactly into one bar. In other words the duration of each note is divided by the total duration of the string. This means that, for example, the drum string "dd" is equivalent to drum string "d4d4". You cannot currently specify fractions directly (eg. C3/2) as done in the body of the music, but it is still possible to express complex rhythms. For example, to indicate a rhythm such as (3ddd d/d/d/d, you would write the string "d4d4d4d3d3d3d3". .PP %%MIDI drumbars n .PP The %%MIDI drum line can sound quite monotonous if it is repeated each bar. To circumvent this problem a new MIDI command %%MIDI drumbars n where n is a small number will spread out the drum string over n consecutive bars. By default drumbars is set to 1 maintaining compatibility with existing abc files. You should take care that the drumstring is evenly divisible between the drumbar bars. Also the time signature should not change between bars in a drumbar unit. (Sample abc file in doc/CHANGES June 24 2008.) .PP %%MIDI gchordbars n .PP This command spreads the gchord string over n consecutive bars just like drumbars (above). (A sample is found in doc/CHANGES March 17 2009.) .PP With version 1.54 Dec 4 2004 of abc2midi, notes in chords (eg. [FAc]) are not played in the same instant but offsetted and shortened by 10 MIDI time units. Thus the first note in the chord (eg. F) is played for the full indicated time, the second note (eg. A) starts 10 MIDI units later and is shortened by the same amount and the third note starts another 10 MIDI units later and is shortened by another 10 units. This introduces an "expressivo" option and avoids the heavy attack. (This does not apply to gchords or multivoiced chords.) The amount of the delay and shortening may be configured by the MIDI command .PP %%MIDI chordattack n .PP where n is a small number. If n is zero, then abc2midi should behave as in earlier versions. The delay n is in MIDI time units where there are 480 units in a quarter note beat. The program may not run correctly if n is too large and there are short chords. .PP %%MIDI randomchordattack n .PP Like above except that the delay is a random variable uniformly distributed between 0 and n-1. .PP %%MIDI trim x/y .PP where x and y are two numbers. This command controls the articulation of notes and chords by placing silent gaps between the notes. The length of these gaps is determined by x/y and the unit length specified by the L: command. These gaps are produced by shortening the notes by the same amount. If the note is already shorter than the specified gap, then the gap is set to half the length of the note. The fraction x/y indicates a note duration in the same manner as specified in the abc file. The actual duration is based on the unit length specified by the L: field command. It is recommended that x/y be a fraction close to zero. Note trimming is disabled inside slurs as specified by parentheses. You can turn off all note trimming by setting x to 0, eg 0/1. By default, note trimming is turned off at the beginning of a tune or voice command. .PP %%MIDI expand x/y .PP where x and y are two numbers defining a fraction less than 1. This command controls the articulation of notes and chords in the reverse manner. The notes are lengthened by this fraction so they overlap the start of the next note. .PP %%MIDI drummap note midipitch .PP Please see abcguide.txt. .PP %%MIDI ptstress filename .PP This command loads file filename into abc2midi which contains the Phil Taylor stress parameters and puts abc2midi in the mode where it applies these stress parameters on every note. This model runs in opposition to the standard beat model, so the MIDI beat, beatstring, beatmod commands become ineffectual. This also means that the dynamic indications !f! !pp! etc. do not work any more. .PP There are two different implementations of the stress model. Model 1 modifies the note articulation and takes control of the MIDI trim parameters too. To revert back to the standard model, put the command %%MIDI beataccents. Model 2 modifies both the onset and ending of each note allowing a musical beat to expand or contract in time. However, the length of a musical measure should be preserved. Note if you using model 2, which the current default, you must include \-BF as one of the runtime parameters of abc2midi. .PP The model divides a bar into equal segments. For each segment, a loudness or MIDI velocity is specified and a duration multiplier is specified. If a note falls into a specific segment, it assumes the velocity of that segment and its duration is modified accordingly. If the note overlaps more than one segment, then the note assumes the average of those segment values. .PP The input file specifies the number of segments and the loudness and duration multipliers for each segment. The file has the following format. The first value is the number of segments and each line specifies the velocity and duration multiplier of the specific segment. The velocity is limited to 127 and the duration is a decimal number. The note durations is modified by varying the gap between notes, so it is not possible to extend a note. This preserves the regular tempo of the music. The program scales, the note duration indications by dividing it by the maximum value which here is 1.4. .PP %%MIDI stressmodel n .PP where n is either 1 or 2, selects the stress model implementation. .PP other %%MIDI commands such as bendvelocity, bendstring, controlstring have been introduced recently and are described in the file abcguide.txt. .SH "COMPATIBILITY WITH DRAFT STANDARD 2.0" .PP The proposed standard introduces a new copyright field using the syntax .PP %%abc-copyright (c) Copyright John Smith 2003 .PP 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. It is also copied into the Karaoke track (if it is created) as as @T field. .PP .SH SEE ALSO abc2ps(1), midi2abc(1), yaps(1). .SH AUTHOR James Allwright .SH SUPPORTED by Seymour Shlien .SH VERSION This man page describes abc2midi version 2.27 June 25 2006. .SH COPYRIGHT Copyright 1999 James Allwright .PP abc2midi is supplied "as is" without any warranty. It is free software and can be used, copied, modified and distributed without fee under the terms of the GNU General Public License. .PP More complete documentation may be found in abcguide.txt which comes with the abcMIDI distribution. abcmidi/doc/abcguide.txt0000644000000000000000000016771212562366366014252 0ustar rootrootGuide to writing abc for abc2midi --------------------------------- (Updated August 11 2015 -- %%MIDI expand, bendvelocity, bendstring, controlstring added.)) The defining document for abc is the abc version 1.6 specification which can be found at http://www.gre.ac.uk/~c.walshaw/abc2mtex/abc.txt . This document is a description of abc as interpreted by abc2midi. An abc tune consists of a header followed by a body. Each line in the header is a different field starting with a letter immediately followed by : and then the text of the field. The body of the tune contains lines of music, though it may also contain certain fields. The end of the tune is marked by a blank line (so blank lines cannot appear within the tune header or body). Comments are allowed in both the header and the body. A comment starts with a % sign and continues to the end of the line. A comment may be on a line of its own or at the end of a line of abc. The header should look something like this : X:1 T:The Rose Tree M:4/4 L:1/8 Q:1/4=120 K:G X: is the reference number (each tune in a file should have a unique reference number). T: is the title of the tune, M: is the time signature, L: is the unit note length and K: is the key signature. Q: is the tempo field. In the above example the tempo is given as 120 quarter-notes per minute. X: must be the first field and K: must be the last field in the header. It is advisable to write the fields M:, L: and Q: in that order. The reason for this is that M: can set up a unit note length which L: overrides and the tempo field Q: can be written in other forms that depend on unit note length. This order makes the meaning clear and unambiguous. The original abc specification gives a rule for computing a default value for the unit note length from the M: field. abc2midi only uses this rule for choosing a unit note length in the header if the L: field has been omitted. The tempo is usually indicated with the Q: field command, eg. Q:1/4=180 which is interpreted as 180 quarter beats per minute. In compliance with the abc standard 2.0, you may also indicate the tempo using directives such as "lento", "allegro", "vivace" etc. The following table based on http://www.music.vt.edu/musicdictionary/appendix/tempo/tempo1.html was used to translate the indications: Larghissimo 1/4=40 Moderato 1/4=104 Adagissimo 1/4=44 Allegretto 1/4=112 Lentissimo 1/4=48 Allegro 1/4=120 Largo 1/4=56 Vivace 1/4=168 Adagio 1/4=59 Vivo 1/4=180 Lento 1/4=62 Presto 1/4=192 Larghetto 1/4=66 Allegrissimo 1/4=208 Adagietto 1/4=76 Vivacissimo 1/4=220 Andante 1/4=88 Prestissimo 1/4=240 Andantino 1/4=96 Note: case is ignored (eg. ALLEGRO Allegro or allegro are treated the same). The directive must be enclosed in double quotes. Reference: http://abc.sourceforge.net/standard/abc2-draft.html#Q:%20-%20tempo Examples: X:1 T:tempo M:2/4 L:1/4 K:G Q: "Adagio" CD|EF| Q: "Adagio" 1/4=40 GA|Bc| (In the second tempo command, the 1/4=40 overrides the default 1/4=59.) The symbols M:C and M:C| give common time (4/4) and cut time (2/2) The symbol M:none omits the meter entirely (free meter). It is also possible to specify a complex meter, e.g. M:(2+3+2)/8, to make explicit which beats should be accented. The parentheses around the numerator are optional. Other fields may also appear in the header. Common ones are C: composer of the tune, D: discography, H: history of the tune, S: source, N: notes, Z: transcription note, A: area from which the tune comes, B: book and R: rhythm. Key Signature: The K: is made up of a base note A-G possibly followed by b for flat or # for sharp. This specifies a major key. A minor key can be specified by adding an m while Mixolydian and Dorian modes can be specified by adding Mix and Dor respectively e.g. K:Eb K:EDor K:EbDor The following table relates the number of sharps or flats you see on the stave to what is in the K: field : 7 sharps: C# A#m G#Mix D#Dor 6 sharps: F# D#m C#Mix G#Dor 5 sharps: B G#m F#Mix C#Dor 4 sharps: E C#m BMix F#Dor 3 sharps: A F#m EMix BDor 2 sharps: D Bm AMix EDor HP Hp 1 sharp : G Em DMix ADor 0 sharps: C Am GMix DDor 1 flat : F Dm CMix GDor 2 flats : Bb Gm FMix CDor 3 flats : Eb Cm BbMix FDor 4 flats : Ab Fm EbMix BbDor 5 flats : Db Bbm AbMix EbDor 6 flats : Gb Ebm DbMix AbDor 7 flats : Cb Abm GbMix DbDor As an extension, abc2midi also recognizes "Maj" for Major "Min" for Minor, "Phr" for Phrygian, "Lyd" for Lydian, "Aeo" for Aeolian and "Loc" for Locrian. Thus CMaj, EPhr, FLyd, AAeo and BLoc will all generate a stave with no sharps or flats. If you use one of these modes in the key signature, it is recommended that you add a comment giving the number of sharps or flats for the benefit of other people who may not be familiar with modes. e.g. K: DLoc % 3 flats The key signature may be followed by modifiers. A modifier consists of ^^, ^ =, _ or __ followed by a-g. As an example, ^g means every a should be played sharp unless otherwise marked in the music. This adds ^g to the existing key signature. For example K: G ^c^g will produce a key signature similar to A major. Following the abc draft 2.0 standard, inserting the string exp in the key signature will cause abc2midi to override the existing key signature. Thus K: A exp _b will remove the f,c and g sharps and put a b-flat instead. You may use both upper and lower case letters as key modifiers since they are distinguished by abcm2ps. Another extension of the K: field is that it can include a clef specifier an octave specifier and a transpose specifier e.g. K:G clef=soprano octave=-1 transpose=-1 The clef is recognized by typesetting programs such as yaps and abc2mps and in some situations it will cause abc2midi to transpose the notes up or down by an octave. Recognized clefs are treble, bass, baritone, tenor, alto, mezzo and soprano. There are also variants of these clefs; treble-8, tenor-8, treble+8 covering ranges which are an octave below and an octave above the normal treble clef. Other variants are not recognized at this time. No transposition is assumed for the bass clef since many abc files enter the notes with all the commas. The octave specifier is a convenience to make entering music easier. It allows the user to avoid repeatedly entering commas or apostrophes when entering a sequence of low or high notes. Both yaps and abc2midi will transpose the notes by the specified number of octaves during the parsing stage. e.g. the passage B,,, C,, D,, E,, F,, could be written more compactly as I:octave=-2 B, C D E F I:octave=0 Some instruments such as the Bb clarinet automatically transpose the written music. For example in the case of the clarinet, the music is written in the key of C but the instrument plays it in the key of Bb. For multivoiced tunes, the %%MIDI transpose indication is not that useful since it transposes all the voices by the specified amount. The transpose=n subcommand in the K: field tells abc2midi to transpose a particular voice by n semitones without affecting how it appears in the printed score. For example for the tune, X:1 T:tranposing M:1/8 L:2/4 K:C V:1 K:C transpose=-1 CDEF|GABc| V:2 K:C CDEF|GABc V:1 CDEF|GABc| V:2 CDEF|GABc Voice 1 will be played one semitone lower than indicated. These transposition features are disabled for channel 10 which is reserved for percussion instruments. Voice indication: Many multivoiced abc files now use the V: indication to specify additional information such as the clef, name of the voice (to appear in the score). Furthermore, the V: indication may occur in the header (i.e. before the first K: indication), for the sole purpose of specifying such information. Abc2midi, yaps and abc2abc now recognizes the subfields octave=, clef= and transpose= in the V: field and treats them in the same manner as if they occurred in a K: field (as discussed above). Thus the V: field may appear as V: 1 clef=treble+8 or [V: 3 transpose=3] The V: field is also recognized in both the body and header of the abc file. Note that not all abc applications may recognize these extensions, so you use them at the risk that they may not be treated as expected in some cases. Also in the event that there is a conflicting indication in either the voice or key signature field, eg. [V: 1 clef=transpose+8 octave=-1] the clef indication predominates. These transposition features are disabled for channel 10 which is reserved for percussion instruments. The Body of the Tune -------------------- Following the header is the tune. This is a textual notation for the things you might see on a stave : Notes: A note consists of a pitch specifier followed by a length. Available pitch specifiers are : C, D, E, F, G, A, B, C D E F G A B c d e f g a b c' d' e' f' g' a' b' This covers 4 octaves. abc2midi allows lower octaves to be reached by adding extra , characters and higher octaves to be reached by adding extra ' characters. However, this is not standard abc and may not be supported by other abc utilities. You can raise or lower the pitch specifier a semitone by preceding it with ^ or _ respectively. The key signature and preceding sharps, flats and barlines modify the default pitch in the same way as on a stave. Preceding a note with = generates natural pitch and ^^ and __ can be used for double sharp and double flat respectively. Microtones are indicated by following a ^ or _ with a fraction. ^/C is played as one quarter tone (i.e. half a semitone) above C. _/C is played as one quarter tone (i.e. half a semitone) below C. ^^/4F is played as 1/4 of a semitone above F#. (The microtone always follows any accidentals.) In general a microtone offset is indicated by a fraction using the same convention as note length (described below). Abcmidi uses the same microtone syntax as abcm2ps. (See features.txt in the abcm2ps distribution.) Note that unlike accidentals, microtones do not propagate across a measure. Microtones are implemented using the MIDI pitchwheel command. Since the pitchwheel affects all notes played on a specific channel, a microtone applied to any note in a chord specified by rectangular brackets, (eg. [ACE]) will apply to all the notes in the chord. Microtone accidentals override any sharpening or flattening induced by key signatures. To illustrate K: G ^/F F ^^/2F F| does the following. Even though the key of G major causes F to be sharp, the first note is F natural raised by half a semitone. This effects the next note in making it F natural instead of F#. The third note is F# raised by a half a semitone. The F# propagates to the last note making it also F#. In accordance to the General MIDI recommendations the pitch range of the pitchwheel is set to plus or minus two semitones. Therefore abc2midi cannot go beyond this range. Microtones may be placed between tied notes, producing a pitch bend effect. eg G- ^/G. Microtones have been introduced fairly recently into abcmidi (Mar 2005); so far there is very little abc notated on the web which exploits this feature. The length is in general specified by a fraction following the pitch specifier. However, the notation is made more concise by allowing much of the fraction to be omitted. C - selects a note of 1 unit note length. C2 - selects a note of 2 unit note lengths. C/2 - selects a note of 1/2 unit note length. C3/4 - selects a note of 3/4 unit note length. C/ is allowed as an abbreviation of C/2. C// is allowed as an abbreviation of C/4. However, this is not standard notation and is not allowed by all abc programs. No space is allowed within a note, but space may be used to separate notes in the tune. Rests are written by using 'z' as the pitch specifier. z3 - a rest of 3 unit note lengths. Multiple bar rests can be created using 'Zn' where n is the number of bars rest required. This is an extension to the standard syntax. Placing a dot before a note causes it to be played staccato. (.e) Placing a M before a note indicates legato. (Me) Placing a H before a note indicates a fermata. (He) Placing a T before a note indicates that this note is trilled. (Te) Placing a R before a note indicates that this note is rolled. (Re) Alternatively you may put !fermata! or !trill! before the note. Other decorations have not been implemented in this manner. The fermata may also be applied to a rest, (in order to handle multivoiced files). Combining notes Three notes of the same length can be turned into a triplet by prefixing them with (3. This has the effect of multiplying the note lengths by 2/3. A chord can be represented by bracketting the notes together within [ and ] e.g. [a2e2]. An older notation which is also supported is to use + symbols e.g. +a2e2+. The - symbol can be used to tie together notes of the same pitch e.g. a2-a; this is equivalent to a3. From version 1.4 of abc2midi, the support of tuples and chords is extended to include general tuple notation (p:q:r , [ and ] for chords and a more flexible system of interpreting chords. (p:q:r means play the next r notes at q/p of their notated value. Thus (3:2:3 is equivalent to an ordinary triplet (3 . It is possible in abc to write notes of different lengths within a chord e.g. [ab2] . In this case, abc2midi takes the length of the first note (or rest) in a chord is taken as the time before the next note is played. However, if the music is to be typeset, this notation should be avoided because the output will be ambiguous. Instead, the same effect can be achieved using tied notes e.g. [ab2] c is equivalent to [ab-] [bc]. A tie sign is always assumed to belong to the immediately previous note. A run of 2 or more different notes may be grouped together in a slur. This usually means that the notes are to be played together as smoothly as possible. In typeset music, a slur looks very similar to a tie, but in abc, ( marks the start of a slur and ) marks the end. e.g. (ABc) . abc2midi recognizes slurs, but they have no effect on the MIDI generated. Barlines and variant endings | is an ordinary barline || is a double barline :| is "repeat last section". |: is "repeat next section". :: is "repeat last and next sections". |1 or |[1 or | [1 is "first repeat ending". :|2 or :|[2 or :| [2 is "second repeat ending". |[1,3 is first and third ending :|[2,4 is second and fourth ending |] and [| are variants of ||. The notation :: is short for :| followed by |: . A tune with different ending for the first, second and third repeats has the general form: |: common body of tune |1 first ending :|2 second ending :|3 third ending || You may also use this notation to indicate that the first ending is played on the first and third repeat. For example |:common body of tune|1,3 first ending :|2 second ending :|4 forth ending| (The last variant ending should not end with a :|. In other words, this will not work correctly. |: ... |[1,2 :|.) For multivoice abc files, you should be careful that the different voices share the same repeat structure. When switching voices (assuming they are interleaved) abc2midi does not cache the repeat state. Printed music commonly misses out a start repeat at the beginning of a tune. abc2midi will try to fix up things if you miss out a start repeat in single voice music. Where a tune starts with an anacrusis, abc2midi will always fix a repeat to start at the anacrusis rather than the first barline. It is recommended that you use matching start and end repeats rather than rely on this behaviour. Missing start repeats are not supported in multiple voice music. Also, abc2midi does not allow nested repeats. However, you can use the more versatile part notation to achieve multiple repeats. It is not unusual to see music where a repeat does not coincide with the end of a bar and the number of beats is not quite correct if the piece is played exactly as written. A human player usually knows enough to correct the mistake themselves, but abc2midi will play exactly what is written, so care needs to be taken that this is corrected when the piece is transcribed to abc. Rhythm field and Broken Rhythm Notation --------------------------------------- R:hornpipe causes notes written in straight time to be played in dotted time. The symbol > can be used to achieve a similar effect. For 4/4 time this is applied to the 1/8 notes. For 2/4 time this is applied to the 1/16 notes. a>b is notated as a3/2b/2 but played as a4/3b2/3. The symbols < >> << >>> <<< have similar meanings: a>b is notated and played as a7/4b/4. a<>>b is notated and played as a15/8b/8. a<< using the %%MIDI ratio command described later. Beware that attempting "advanced" use of these symbols may mean your abc is not portable between different abc programs. If the notes on either side of the symbol are different lengths, this is reported as an error. If a and b are not simple notes, or if there are other complications, then it is safer to write the note lengths directly. Guitar chords : Anything in quotes is a guitar chord e.g. "A" "Gm" "B7" "Bm7" "D#aug" "Bbdim7" Guitar chords must use upper case A-G followed by optional # or b, then the name of a chord type e.g. "m", "aug", "7". abc2midi currently recognizes the following chord names : m, 7, m7, maj7, M7, 6, m6, aug, +, aug7, dim, dim7, 9, m9, maj9, M9, 11, dim9, sus, sus9, 7sus4, 7sus9, 5 You can also add your own; see the %%MIDI chordname command below. abc2midi automatically generates an accompaniment from the guitar chords. There are a number of default chord/fundamental rhythms for common time signatures which this uses, or you can set up your own. Lower case a-g followed by optional # or b will generate a single note, the fundamental, only. The chord notation also allows chords such as "G/B" or "G/b". The note following the / is interpreted in one of two ways: If the note following / does not exist as part of the given chord, it is added to the chord below the root note of the chord (G in the above example). If the note following / does exist in the chord, then the notes of the chord are re-arranged so that it becomes the lowest pitch note of the chord. This is known as an inversion of the chord. It does not matter whether the note following the / is upper or lower case. They are both treated the same. This notation has been extended so that finger numbers "1" "2" "3", "4" or "5" are allowed. abc2midi ignores these, but a typesetting program might support them. You may find some abc tunes that abuse this notation and use quotes for things that are not guitar chords. Usually these are tunes which have been typeset but never played by a computer. If you don't want to just delete things in quotes, you can insert one of the characters _, ^, @, < or > after the first quote e.g. "_Chorus" "_Very Loud". This causes abc2midi to ignore the following text. However, typesetting programs should recognize the first character as telling them where to print the following text. Another extension is to allow musical instructions to appear in exclamation marks e.g. !pizzicato! abc2midi currently supports the following : !ppp! !pp! !p! !mp! !mf! !f! !ff! !fff! Default volume is equivalent to !f!. In both the " " and ! ! fields, abc2midi allows multiple terms separated by semi-colons e.g. "Am;1". The !breath! instruction causes the note to be played half length followed by a rest of half its length (just like staccato). The !arpeggio! instruction affects the next chord and introduces a larger delay between the onset of each note in the chord. (See the text preceding %%MIDI chordattack in this file for more explanations.) The !crescendo(! and !crescendo)! delineate the start and end of a crescendo. Alternatively, you can use !<(! and !<)!. Abc2midi does not implement a gradual loudness increase, but instead increases the loudness at the start and end of the crescendo by a fixed amount. (See %%MIDI beatmod and %%MIDI deltaloudness for more information.) The !diminuendo(! and !diminuendo)! behave similarly but reduce the loudness. These instructions have not been implemented in yaps. !ped! and !ped-end! press and release the sustain pedal on the piano. (The notes following !ped! and preceding !ped-end! are held. This effect applies to all instruments besides the piano.) A line of music may contain any number of notes, barlines and guitar chords. Spaces may be used to separate these. Some abc fields may appear within the body of the abc tune : K: - change key L: - change unit note length M: - change meter Q: - change tempo P: - part label V: - voice label w: - words to be matched syllable by syllable to notes Each field must be on a line by itself. Part Notation ------------- A part label must be a single character in the range A - Z. e.g. P:A A parts specifier in the header can be used to define the MIDI output as some combination of the specified parts e.g. P:ABACABA You can use ( ) to repeat a part a specified number of times e.g. P:A(AB)6 is equivalent to P:AABABABABABAB. If there are no brackets, just the last part is repeated, so P:AAB3 is equicalent to P:AABBB. Dots may be inserted into the part specifier to make it easier to read e.g P:A.AB.AC If there is no parts specifier, the output is simply the parts (or just the unlabelled music) in the order in which it appears in the tune body. You may if you wish have multiple voices sounding concurrently within each part. These are indicated with V:N to indicate voice number N. e.g. V:1 V:2 and so on. A part label implicitly starts with V:1, as does the K: field which starts the tune body, so you are not allowed to place a part label within a voice. The duration of each of the voice parts must be the same for them to synchronize correctly; abc2midi will warn you if they are not! From version 1.7 onwards, abc2midi allows any voice apart from voice 1 to be completely omitted from a part. If no V: field appears after the first K:, whatever follows is assumed to belong to voice 1 (the default voice). The V: field is an extension to abc 1.5. The lines between one V:N field and the next V: field define a region belonging to voice N. Within a part, you may have more than one such region for each voice. The music for voice N within a part is all the voice N regions taken in sequence. The M:, L: and K: fields in the header apply to all voices. After the header, these fields apply only to the voice in which they appear. In previous versions of abc2midi, an L:, for example, would affect everything after it appeared up until the next L:, regardless of what voice changes there were. The Q: tempo field should only appear in voice 1 and applies to all voices. The U: abbreviation field has limited use here. You can specify an abbreviation such as U: P = !trill! and then in the body, eg. |DGAPF|, P will be replaced with !trill! Only letters between H and Z can be used. Furthermore, you can not redefine reserved letters such as H (fermata), L (unit length), M (mordent) , R (roll) , T (trill). Adding Lyrics to a Tune ----------------------- The W: field (upper case W) can be used for lyrics to be typeset separately if the abc is printed out. The w: field (lower case w) in the body of a tune supplies a line of lyrics to be matched syllable by syllable to the last line of notes. These are usually printed below the notes if the abc is typeset. abc2midi uses these to generate karaoke MIDI files. A karaoke MIDI file can contain more than one set of lyrics in separate voices; an example is shown at the end of this section. By default the lyrics are embedded in the same MIDI track as the notes. If the runtime parameter -STFW is included, then the lyrics will be placed in separate and adjoining MIDI tracks. When the karaoke MIDI file is played using an appropriate player program, the lyrics appear on the screen with the current syllable highlighted. Within the lyrics, the following symbols may be used : break between words - break between syllables within a word | advance to next bar _ indicates last syllable is to be held for another note * indicates a one note rest for the singer. ~ appears as a space but connects syllables each side into one. \- appears as - in the output \ continuation character. Next w: field is part of the same line. A rest is not matched by any lyrics. A tied note e.g. d2-d2 is treated as 2 notes (or however many parts it is written as), despite the fact that it only plays as a single note. abc2midi ignores space characters if they occur either (a) between the end of a word/syllable and a hyphen or underscore or (b) between a hyphen or underscore and the beginning of a word/syllable. However, some software incorrectly treats a hyphen as a separate word if there is a space between it and the previous syllable, so, for example, you should write go-ing and not go - ing to ensure that your abc is portable between programs. Here are some examples taken from http://abc.sourceforge.net/standard/abc2-draft.html w: syll-a-ble is aligned with three notes w: syll-a--ble is aligned with four notes w: syll-a -ble (equivalent to the previous line) w: time__ is aligned with three notes w: of~the~day is treated as one syllable (i.e. aligned with one note) but appears as three separate words The following example illustrates most of these : gf|e2dc B2A2|B2G2 E2D2|.G2.G2 GABc|d4 B2 w: Sa-ys my au-l' wan to your aul' wan\ w: Will~ye come to the Wa-x-ies dar-gle? Note that the continuation character is used in a rather strange manner. One w: field and all continuations will match one line of music, whether or not the line of music ends with a continuation character. You can think of the \ in a music line dividing that line into sections and \ in a w: field further dividing these section into sub-sections. It is possible for a music line to be followed by several w: fields. This can be used together with the part notation to create verses. The first w: field is used the first time that part is played, then the second and so on. If the tune uses repeats, these must be placed at the end of a line of music in order to make sure that the start of a w: field matches up with the repeat. Multivoiced lyrics example: X:1 T:Multivoiced lyrics M:2/4 L:1/16 K:C V:1 C4 C4 | E4 G4 | c8 |] w: 1 2 3 4 5 V:2 C4 E4 | C4 B,4 | C8 |] w: 11 12 13 14 15 BarFly stress models -------------------- If you include the run time parameter -BF in execution string, abc2midi will attempt to apply the BarFly stress model on the tune if it recognizes the rhythm designator (eg. R: jig) and if the time signature also matches the associated meter. There are two different implementations of the stress model which have different effects. (See %%MIDI ptstress below for more details.) You can specify the implementation to use by following the -BF flag with either the numeral 1 or 2. If you do not specify a model, the program will use model 2. More details can be found on http://ifdo.ca/~seymour/runabc/abcguide/abc2midi_guide.html abc2midi-specific commands (%%MIDI) ------------------------------------ abc2midi supports a number of commands of the form %%MIDI command Each of these should appear on a line by itself; however there is now provision to pass the MIDI command in an inline I: field (see CHANGES file, March 25 2005 entry.) All of them are allowed within the abc tune body. By using these in combination with the part notation, one can, for example, play a part transposed or in a different key. The idea behind this syntax is that other programs will treat it as a comment and ignore it. %%MIDI channel n selects melody channel n (in the range 1-16). %%MIDI program [c] n selects program n (in the range 1-128) on channel c. If c is not given, the program is selected on the current melody channel. Most modern tone generators follow the General MIDI standard which defines the instrument type for each program number. These instrument types are listed at the end of this document. Note that for multivoiced files, the program command is placed in the track associated with the voice previously declared. If the %%MIDI indications affect channels in other tracks, it is recommended that they are placed in the first track or first declared voice. See the note in the CHANGES file for the date January 1 2005. %%MIDI beat a b c n controls the way note velocities are selected. The first note in a bar has velocity a. Other "strong" notes have velocity b and all the rest have velocity c. a, b and c must be in the range 0-127. The parameter n determines which notes are "strong". If the time signature is x/y, then each note is given a position number k = 0, 1, 2 .. x-1 within each bar. Note that the units for n are not the unit note length. If k is a multiple of n, then the note is "strong". The volume specifiers !ppp! to !fff! are equivalent to the following : !ppp! = %%MIDI beat 30 20 10 1 !pp! = %%MIDI beat 45 35 20 1 !p! = %%MIDI beat 60 50 35 1 !mp! = %%MIDI beat 75 65 50 1 !mf! = %%MIDI beat 90 80 65 1 !f! = %%MIDI beat 105 95 80 1 !ff! = %%MIDI beat 120 110 95 1 !fff! = %%MIDI beat 127 125 110 1 %%MIDI beatmod n increments by n (or decrements if n is negative) the velocities a, b and c described above. It is also used in implementing crescendo and diminuendo (eg. !<(!, !crescendo(! etc.) %%MIDI nobeataccents For instruments such as church organ that have no greatly emphasized beat notes, using this will force use of the 'b' velocity (see %%MIDI beat) for every note irrespective of position in the bar. This allows dynamics (ff, f, etc) to be used in the normal way. %%MIDI beataccents Revert to emphasizing notes the the usual way. (default) %%MIDI deltaloudness n where n is a small positive number. By default the crescendo and dimuendo instructions modify the beat variables a, b, and c by 15 velocity units. This instruction allows you to change this default. %%MIDI beatstring This provides an alternative way of specifying where the strong and weak stresses fall within a bar. 'f' means velocity a (normally strong), 'm' means velocity b (medium velocity) and 'p' means velocity c (soft velocity). For example, if the time signature is 7/8 with stresses on the first, fourth and sixth notes in the bar, we could use the following %%MIDI beatstring fppmpmp %%MIDI transpose n transposes the output by the specified number of semitones. n may be positive or negative. %%MIDI rtranspose n Relative transpose by the specified number of semitones. i.e. %%MIDI transpose a followed by %%MIDI rtranspose b results in a transposition of a+b. %%MIDI transpose b will result in a transposition of b semitones, regardless of any previous transposition. %%MIDI c n specifies the MIDI pitch which corresponds to c. The default is 60. This number should normally be a multiple of 12. %%MIDI grace a/b sets the fraction of the next note that grace notes will take up. a must be between 1 and b-1. The grace notes may not sound natural in this approach, since the length of the individual grace notes vary with the complexity of the grace and the length of the following note. A different approach (which is now the default) assumes that the grace notes always have fixed duration specified by a fraction of the unit length. To use the other approach you would specify, %%MIDI gracedivider b where b specifies how many parts to divide the unit length specified by the L: field command. For example if b = 4 and L: = 1/8, then every grace note would be 1/(8*4) or a 32nd note. Time would be stolen from the note to which the grace note is applied. If that note is not long enough to handle the grace then the grace notes would be assigned 0 duration. %%MIDI chordname name n1 n2 n3 n4 n5 n6 Defines how to play a guitar chord called "name". n1 is usually 0 and n2, n3 to n6 give the pitches of the other notes in semitones relative to the root note. There may be fewer than 6 notes in the chord, but not more.If "name" is already defined, this command re-defines it. Unlike most other commands, chordname definitions stay in effect from where they are defined to the end of the abc file. The following illustrates how m, 7, m7 and maj7 could be set up if they were not already defined. %%MIDI chordname m 0 3 7 %%MIDI chordname 7 0 4 7 10 %%MIDI chordname m7 0 3 7 10 %%MIDI chordname maj7 0 4 7 11 %%MIDI gchord string sets up how guitar chords are generated. The string is a sequence made of of z's, c's f's and b's for rests, chords, fundamental and fundamental plus chord notes respectively. This specifies how each bar is to be played. An optional length is allowed to follow the z's, c's, f's and b's e.g. czf2zf3. If the abc contains guitar chords, then abc2midi automatically adds chords and fundamentals after encountering the first guitar chord. It keeps using that chord until a new chord is specified in the abc. Whenever the M: field is encountered in the abc, an appropriate default string is set : For 2/4 or 4/4 time default is equivalent to : %%MIDI gchord fzczfzcz For 3/4 time default is equivalent to : %%MIDI gchord fzczcz For 6/8 time default is equivalent to : %%MIDI gchord fzcfzc For 9/8 time default is equivalent to : %%MIDI gchord fzcfzcfzc Please note, that the default gchord string is reissued any time a time signature change is specified in the body of the music. This means if one of the bars has an extra beat you included a M: declaration before and after the measure, the gchord string would be reset to the default string for that time signature and not the one that you had declared. It is necessary for you to send another %%MIDI gchord declaration after the the time signature in order to set this back the way you want it. This is one of the changes introduced into abc2midi so that the accompaniment track always follows the meter of the music for the regular time signatures. The gchord command has been extended to allow you to play the individual notes comprising the guitar chord. This allows you to play broken chords or arpeggios. The new codes g,h,i,j, G,H,I,J reference the individual notes starting from the lowest note of the chord (not necessarily the root in the case of inverses). For example for the C major chord, g refers to C, h refers to E and i refers to G. For a gchord command such as, %%MIDI gchord ghih Abc2midi will arpeggiate the C major guitar chord to CEGE. The upper case letters G,H,I, and J refer to the same notes except they are transposed down one octave. Note for the first inversion of the C major chord (indicated by "C/E"), E would be the lowest note so g would reference the note E. Like other gchord codes, you may append a numeral indicating the duration of the note. The same rules apply as before. You can use any combination of the gchord codes, (fcbghijGHIJz). Another recent extension to gchords is the presence of gchords in separate voices. Here is an example: X:1 T: gchord multivoice extension M: 4/4 L: 1/4 K: G V: 1 %%MIDI gchord ghih "G" z4| z4|\ %%MIDI gchordoff z4| V:2 %%MIDI chordprog 12 %%MIDI gchord GHIHG z4|"D" z4|z4| %%MIDI chordprog n Sets the MIDI instrument for the chord notes to be n. If the command includes the string octave=n where n is a number between -2 and +2, then the chord notes will be shifted n octaves from its usual position, eg. (%%MIDI chordprog 32 octave=1). Any other descriptors will be ignored, eg (%%MIDI chordprog 0 Acoustic Piano). %%MIDI bassprog n Sets the MIDI instrument for the bass notes to be n. If the command includes the string octave=n where n is a number between -2 and +2, then the bass note will be shifted n octaves from its usual position. eg. (%%MIDI bassprog 32 octave=-1). %%MIDI chordvol n Sets the volume (velocity) of the chord notes at n. %%MIDI bassvol n Sets the volume (velocity) of the bass notes at n. There is no corresponding melodyvol command since there are 3 velocity values for melody, set using the beat command. %%MIDI gchordon Turns on guitar chords (they are turned on by default at the start of a tune). %%MIDI gchordoff Turns off guitar chords. %%MIDI fermatafixed Directs abc2midi to expand a fermata by one unit length. Thus HC3 becomes C4. %%MIDI fermataproportional This is the default. A fermata doubles the length of a note so HC3 becomes C6. %%MIDI droneon This turns on a continuous drone used in bagpipe music. The drone consists of two notes (by default A, and A,,) played on a bassoon at a MIDI loudness (velocity) 80. If you can configure the drone sound using the %%MIDI drone command described below. %%MIDI droneoff This turns off the drone. %%MIDI drone n1 n2 n3 n4 n5 Configures the drone chord. n1 = MIDI program, n2 = MIDI pitch 1, n2 = MIDI pitch 2, n4 = MIDI velocity 1, and n5 = MIDI velocity 2. By default they have already been set to 70 45 33 80 80. %%MIDI drum string [drum programs] [drum velocities] This sets up a drum pattern. The string determines when there is a drum beat and the drum program values determine what each drum strike sounds like. e.g. %%MIDI drum d2zdd 35 38 38 100 50 50 The string may contain 'd' for a drum strike or 'z' for a rest. By default a voice starts with no drum pattern. Like gchord, a command %%MIDI drumon is needed to enable the drumming. The drum pattern is repeated during each bar until a %%MIDI drumoff is encountered. The %%MIDI drum command may be used within a tune to change the drum pattern. This command places the drum sounds on channel 10 and assumes your tone generator complies with the General Midi standard - if it does not, then you may hear tones instead of drum sounds. (Note the old method of using the instruction !drum! and !nodrum! is being deprecated.) In both the gchord and drum commands, the standard note length of a single note f,c,z or d is not set by the L: command. Instead it is adjusted so that the entire gchord string or drum string fits exactly into one bar. In other words the duration of each note is divided by the total duration of the string. This means that, for example, the drum string "dd" is equivalent to drum string "d4d4". You cannot currently specify fractions directly (eg. C3/2) as done in the body of the music, but it is still possible to express complex rhythms. For example, to indicate a rhythm such as (3ddd d/d/d/d, you would write the string "d4d4d4d3d3d3d3". For reference, the percussion instruments defined in the General MIDI standard are given below. 35 Acoustic Bass Drum 59 Ride Cymbal 2 36 Bass Drum 1 60 Hi Bongo 37 Side Stick 61 Low Bongo 38 Acoustic Snare 62 Mute Hi Conga 39 Hand Clap 63 Open Hi Conga 40 Electric Snare 64 Low Conga 41 Low Floor Tom 65 High Timbale 42 Closed Hi Hat 66 Low Timbale 43 High Floor Tom 67 High Agogo 44 Pedal Hi-Hat 68 Low Agogo 45 Low Tom 69 Cabasa 46 Open Hi-Hat 70 Maracas 47 Low-Mid Tom 71 Short Whistle 48 Hi Mid Tom 72 Long Whistle 49 Crash Cymbal 1 73 Short Guiro 50 High Tom 74 Long Guiro 51 Ride Cymbal 1 75 Claves 52 Chinese Cymbal 76 Hi Wood Block 53 Ride Bell 77 Low Wood Block 54 Tambourine 78 Mute Cuica 55 Splash Cymbal 79 Open Cuica 56 Cowbell 80 Mute Triangle 57 Crash Cymbal 2 81 Open Triangle 58 Vibraslap Note you are able to change this mapping using the the MIDI command %%MIDI drummap described below. %%MIDI drummap note midipitch where the pitch of the note is notated using abc notation and midipitch is a number between 35 and 81 inclusive referring to the above table. This command is used if you are notating a drum track, i.e. a voice played on channel 10. Rather than being forced to use the note corresponding to the desired percussion instrument, (for example C (MIDI pitch 60) for hi bongo, you can use can change the mapping to use a more convenient pitch. for example to access bass drum 1 (MIDI pitch 36) you would require the note C,, which is awkward to display in common music notation. You can change the mapping to say _D using %%MIDI drummap _D 36. An example is provided in the file CHANGES (November 6 2005). %%MIDI drumbars n The %%MIDI drum line can sound quite monotonous if it is repeated each bar. To circumvent this problem a new MIDI command %%MIDI drumbars n where n is a small number will spread out the drum string over n consecutive bars. By default drumbars is set to 1 maintaining compatibility with existing abc files. You should take care that the drumstring is evenly divisible between the drumbar bars. Also the time signature should not change between bars in a drumbar unit. (Sample abc file in CHANGES June 24 2008.) %%MIDI gchordbars n This command spreads the gchord string over n consecutive bars of equal length. The gchord string should be evenly divisible by n or else the gchords will not work properly. A sample abc file is found in CHANGES March 17 2009. %%MIDI control [bass/chord] n1 n2 This generates a MIDI control event. If the word "control" is followed by "bass" or "chord", the event will be applied to the bass or chord channel, otherwise it will be applied to the current channel. n1 and n2 are numbers in the range 0-127. Generally, n1 selects a control parameter and n2 is the value to which it is set. A couple of examples : %%MIDI control 7 50 will set the main volume of the channel to 50 %%MIDI control 10 0 will set the pan parameter (left/right balance) to 0. See the manual for your MIDI tone generator to find out what control events are supported. %%MIDI portamento [bass/chord] n This will turn on the MIDI portamento controller and set the speed of sliding between pitches to n. Like %%MIDI control, if the word portamento is followed by "bass" or "chord", the event will be applied to the bass or chord channel, otherwise it will be applied to the current channel. The parameter n should be between 0 and 63. Large values imply a slow transition between pitches. I have found the resulting effect to be rather wierd, especially for large pitch intervals. %%MIDI noportamento [bass/chord] This will turn off the portamento controller (current default). %%MIDI pitchbend [bass/chord] This generates a pitchbend event on the current channel, or on the bass or chord channel as specified. The value given by the following two bytes indicates the pitch change. %%MIDI nobarlines This is a somewhat obscure option to support early music without barlines. Normally, an accidental applied to one note e.g. ^c will apply to every note at the same point in the scale until the end of the bar (so C,, C, C c c' would all be sharpened). This option turns off this behaviour, so that an accidental applies only to the next note. It should be used in the header of any tune requiring this behaviour. %%MIDI barlines This turns off the effect of %%MIDI nobarlines in the middle of a tune. This is the default behaviour assumed at the start of every tune. %%MIDI ratio n m This sets the ratio of note lengths in broken rhythm (e.g. a>b). The default behaviour is for note a to sound for twice as long as note b. This can be achieved with %%MIDI ratio 2 1 and hornpipes are commonly played with approximately this ratio. However, for other musical styles, a different ratio may be appropriate. If you are using abc2midi to export music to another program for printing, then you may wish to use a ratio of 3:1 which is how hornpipes are usually notated. This can be achieved with %%MIDI ratio 3 1 Arpegiation: With version 1.54 Dec 4 2004 of abc2midi, notes in chords (eg. [FAc]) are not played in the same instant but offsetted and shortened by 10 MIDI time units. Thus the first note in the chord (eg. F) is played for the full indicated time, the second note (eg. A) starts 10 MIDI units later and is shortened by the same amount and the third note starts another 10 MIDI units later and is shortened by another 10 units. This introduces an "expressivo" option and avoids the heavy attack. (This does not apply to gchords or multivoiced chords.) The amount of the delay and shortening may be configured by the MIDI command %%MIDI chordattack n where n is a small number. If n is zero, then abc2midi should behave as in earlier versions. The delay n is in MIDI time units where there are 480 units in a quarter note beat. The program may not run correctly if n is too large and there are short chords. %%MIDI randomchordattack n where n is a small number. This is similar to above, except the delay of each note in the chord varies randomly between 0 and n-1. Therefore each chord is played differently. Articulation: %%MIDI trim x/y where x and y are two numbers. This command controls the articulation of notes and chords by placing silent gaps between the notes. The length of these gaps is determined by x/y and the unit length specified by the L: command. These gaps are produced by shortening the notes by the same amount. If the note is already shorter than the specified gap, then the gap is set to half the length of the note. The fraction x/y indicates a note duration in the same manner as specified in the abc file. The actual duration is based on the unit length specified by the L: field command. It is recommended that x/y be a fraction close to zero. The denominator, y does not need to be a power of 2. Trimming is disabled inside slurs as indicated by parentheses. You can turn off all note trimming by setting x to 0, eg 0/1. By default, note trimming is turned off at the beginning of a tune or voice command. To avoid the problem of breaking up a music line in order to place a %%MIDI command, for example, A2 B2|\ %%MIDI drumon C2 D2| you can place the MIDI instruction inside an info field using the following syntax. A2 B2|[I:MIDI= drumon] C2 D2| The '=' following the MIDI is very important. The info field syntax allows you to place several MIDI commands in one inline block, for example [I: MIDI = program 73 MIDI=chordprog 29] (Spaces are optional.) Other examples can be seen in the file CHANGES in the following the March 25 2005 entry. Another recent extension is the allowance of drum patterns in separate voices. Here is an example: X:1 T: drum multivoice extension M: 4/4 L: 1/4 K: G V:1 %%MIDI drum dddd 45 45 45 45 70 50 60 50 %%MIDI drumon z4|z4|\ %%MIDI drumoff z4| V:2 %%MIDI drum ddddd 54 54 54 54 54 70 50 50 60 50 z4|\ %%MIDI drumon z4|z4| %%MIDI temperamentlinear octave_cents fifth_cents This command allows you to change the temperament of the scale. Octave_cents specifies the size of an octave in cents of a semitone or 1/1200 of an octave. Fifth_cents specifies in the size of a fifth (normally 700 cents). For example: %%MIDI temperament 1200.5 698.0 will produce a slightly stretched scale with narrowed fifths. More details on linear tempered scales can be found on the site http://www.xs4all.nl/~huygensf/scala/ The pitch of each note is modified using a MIDI pitchbend command to comply with the scale. In order to handle chords, each note of the chord must be played on a different MIDI channel. The normal musical scale has a temperament of %%MIDI temperamentlinear 1200 700 but to avoid unnecessary pitchbends you should restore to the normal temperament using the command %%MIDI termperamentnormal %%MIDI tuninsystem comma53 quantizes the pitches of the notes using the comma53 system where an octave is divided into 53 equally spaced tones. %%MIDI makechordchannels n If you are not modifying the temperament or inserting microtones you can ignore this command. Normally in voice chords containing microtones e.g. [_/CE_/G] will not be handled correctly because all the notes in the chord are played on the same MIDI channel. If you include the above command where n here is 2, then two separate channels will be allocated for playing the other two notes in this chord. These separate channels will be used whether the pitches of the notes are bent or not. Once you allocate those channels with this command, they are no longer available and since there are only 16 MIDI channels you can easily run out. Furthermore, you need to allocate chordchannels for any other voices which may have in voice chords. The channel allocation process will automatically propogate the program assignment (musical instrument) to the other chordchannels, so be sure you set the program before using this command. If you need to change the program assignments, you can find out the channel numbers that were assigned by running abc2midi in verbose mode using the -v command in the execution string. %%MIDI ptstress filename This command loads file filename into abc2midi which contains the Phil Taylor stress parameters and puts abc2midi in the mode where it applies these stress parameters on every note. This model runs in opposition to the standard beat model, so the MIDI beat, beatstring, beatmod commands become ineffectual. This also means that the dynamic indications !f! !pp! etc. do not work any more. There are two different implementations of the stress model. Model 1 modifies the note articulation and takes control of the MIDI trim parameters too. To revert back to the standard model, put the command %%MIDI beataccents. Model 2 modifies both the onset and ending of each note allowing a musical beat to expand or contract in time. However, the length of a musical measure should be preserved. Note if you using model 2, which the current default, you must include -BF as one of the runtime parameters of abc2midi. The model divides a bar into equal segments. For each segment, a loudness or MIDI velocity is specified and a duration multiplier is specified. If a note falls into a specific segment, it assumes the velocity of that segment and its duration is modified accordingly. If the note overlaps more than one segment, then the note assumes the average of those segment values. The input file specifies the number of segments and the loudness and duration multipliers for each segment. The file has the following format: 8 110 1.4 90 0.6 110 1.4 90 0.6 110 1.4 90 0.6 110 1.4 90 0.6 where the first value is the number of segments and each line specifies the velocity and duration multiplier of the specific segment. The velocity is limited to 127 and the duration is a decimal number. The note durations is modified by varying the gap between notes, so it is not possible to extend a note. This preserves the regular tempo of the music. The program scales, the note duration indications by dividing it by the maximum value which here is 1.4. %%MIDI stressmodel n where n is either 1 or 2, selects the stress model implementation. %%MIDI expand m/n This command,causes all the following notes be lengthened by the amount factor m/n so that they overlap the next note. Thus the next note is started at the proper time, but the prevous note ends after the beggining of the note. This overlap causes a nice effect for particular MIDI instruments such as choir voices. The %%MIDI expand function behaves in the opposite manner as the %%MIDI trim function. %%MIDI snt k pitch Since many MIDI devices do not support this function, use of this command is not recommended. The command changes the tuning of a single note using the "universal system exclusive messages". k is the MIDI pitch being retuned (a number between 0 to 127) and pitch is a floating point number representing the pitch's new value in MIDI pitch units. %%MIDI bendvelocity n1 n2 This command defines how to bend the a particular note following the !bend! decoration. The pitch of the note shifts up or down as the note is playing. n1 is the velocity of the pitch change and n2 is the acceleration (how fast the velocity changes). The bend is accomplished by modifying the MIDI pitchwheel where the 8192 is the neutral. Minimum and maximum values are 0 and 16383 correspond to two semitones shifts in either directions. The velocity and acceleration may be positive or negative. %%MIDI bendstring n1 n2 n3 n4 etc This command is a more general way for defining how a note is bent. It can also apply with !shape! decoration discussed later. The note is split into n equal segments corresponding to each of the n1, n2, etc values. The n1, n2, ... values are the increments (or decrements if they are negative) which are added to the pitchwheel value. Thus %%MIDI bendstring 1000 1000 -500 -500 will split a note into 4 parts and the pitchwheel values in each part will be 9192, 10192, 9692, and 9192. %%MIDI controlstring m n1 n2 n3 ... This command defines how the m th MIDI controller changes for the note following the !shape! decoration. The note is divided into n segments where n is the number of values following the m or controller number. n1, n2, n3, ... are the values for controller m in each segment. This allows you to shape the sound of the note. For example, by changing the modwheel or the expression. All the values m, n1, n2 are numbers between 0 and 127. Global settings for abc2midi ---------------------------- If you are creating an abc file with many tunes, abc2ps and abcm2ps allows you to declare certain settings that apply to all tunes by placing them at the beginning of the file prior to the start of the tune. Abc2midi provides this feature but presently only to a limited extent. The following MIDI commands will change the defaults for all tunes if they are placed outside of any tune. %%MIDI C ... %%MIDI nobarlines ... %%MIDI barlines ... %%MIDI fermatafixed %%MIDI fermataproportional %%MIDI ratio ... %%MIDI chordname ... %%MIDI deltaloudness ... All other MIDI commands placed outside of a tune will be ineffective and return a warning message "cannot handle this MIDI directive here" (For more details see CHANGES, May 06 2005 entry.) Any of these defaults can be changed as many times as you like provided that they are occur outside a tune which is usually delineated by a X: reference number and a blank line. Voice Splitting --------------- Abcm2ps allows a voice to separate into two or more voices in a specific bar using the symbol '&'. This feature now works in abc2midi. Abc2midi places the split voice into a separate MIDI track with intervening rests. When a voice splits, the new voice inherits the program number (musical instrument) from the parent voice. Compatibility with proposed abc standard version 2.0 ---------------------------------------------------- The proposed standard introduces a new copyright 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. It is also copied into the Karaoke track (if it is created) as as @T field. Typesetting abc --------------- If you want to typeset your abc, there are some more features of abc syntax that you need to know: If 2 notes appear consecutively with no space between them, they will be grouped together under the same beam. A space between them prevents them sharing a beam. A new line of stave music is generated by the newline at the end of a line of abc music. To suppress this, put a \ character at the end of the abc music line. An abc music line should end either at a bar line or at the space between two notes which indicates they do not share a beam. This is true whether or not the abc line ends with a \ character. Error Messages and Warnings --------------------------- abc2midi attempts to perform various checks on the abc and reports any problems via error and warning messages: A warning message indicates there is something strange in the abc - possibly an error or possibly non-standard usage. An error message means that abc2midi thinks there is definitely an error in the abc and the MIDI generated may not be correct. In a small number of cases, an error may cause abc2midi to stop. This is usually either because it has run out of memory or because there is some problem with reading or writing a file. Bar counting and checking ------------------------- Conventionally bars are numbered starting from one. If the first bar is incomplete (anacrusis), then it is counted as zero. Abc2ps and abcm2ps follows this convention but abcMIDI does not. All bars are counted starting from zero and furthermore if there is an incomplete bar just before a repeat (:| |: or ::), the bar count is not incremented. It is difficult to change this convention since abcMIDI assigns a number to the bar ahead when it sees a bar line. It would be necessary to introduce some look ahead for the first bar in the tune. If abc2midi reports a problem in a specific bar, you can use yaps with the -k option (for print bar numbers) to locate this bar. If you use another program such as abc2ps, then the bar number in the displayed or printed version may be one unit higher. The most common error seems to be a missing beat or having an extra beat in a bar. In the vicinity of a repeat, abc2midi tries to complete the first bar using the incomplete bar at the end of the repeat. If the first bar can be completed, then no warning is reported. The first bar may be complete the first time the section is played but incomplete in the second repeat. Complications occur when the left repeat symbol (|:) is missing and abc2midi has to assume it is at the beginning. More complications occur when there is a key change after the repeat or the music is split into parts A,B,C, etc. Yaps does the bar checking differently when it encounters repeats so that it may not resolve as many incomplete bars and report more warnings. The bar checking is present for providing warnings. For some music, an extra beat may be intentional and it is not marked by a meter change. If you are only printing the music, there is probably no problem; however, if you are producing a MIDI file and there is guitar (gchord) accompaniment then a break or missing beat might be noticeable. General MIDI Program Number/Instrument Name ------------------------------------------- 1. Acoustic Grand Piano 2. Bright Acoustic Piano 3. Electric Grand Piano 4. Honky-tonk Piano 5. Electric Piano 1 6. Electric Piano 2 7. Harpsichord 8. Clavi 9. Celesta 10. Glockenspiel 11. Music Box 12. Vibraphone 13. Marimba 14. Xylophone 15. Tubular Bells 16. Dulcimer 17. Drawbar Organ 18. Percussive Organ 19. Rock Organ 20. Church Organ 21. Reed Organ 22. Accordion 23. Harmonica 24. Tango Accordion 25. Acoustic Guitar (nylon) 26. Acoustic Guitar (steel) 27. Electric Guitar (jazz) 28. Electric Guitar (clean) 29. Electric Guitar (muted) 30. Overdriven Guitar 31. Distortion Guitar 32. Guitar harmonics 33. Acoustic Bass 34. Electric Bass (finger) 35. Electric Bass (pick) 36. Fretless Bass 37. Slap Bass 1 38. Slap Bass 2 39. Synth Bass 1 40. Synth Bass 2 41. Violin 42. Viola 43. Cello 44. Contrabass 45. Tremolo Strings 46. Pizzicato Strings 47. Orchestral Harp 48. Timpani 49. String Ensemble 1 50. String Ensemble 2 51. SynthStrings 1 52. SynthStrings 2 53. Choir Aahs 54. Voice Oohs 55. Synth Voice 56. Orchestra Hit 57. Trumpet 58. Trombone 59. Tuba 60. Muted Trumpet 61. French Horn 62. Brass Section 63. SynthBrass 1 64. SynthBrass 2 65. Soprano Sax 66. Alto Sax 67. Tenor Sax 68. Baritone Sax 69. Oboe 70. English Horn 71. Bassoon 72. Clarinet 73. Piccolo 74. Flute 75. Recorder 76. Pan Flute 77. Blown Bottle 78. Shakuhachi 79. Whistle 80. Ocarina 81. Lead 1 (square) 82. Lead 2 (sawtooth) 83. Lead 3 (calliope) 84. Lead 4 (chiff) 85. Lead 5 (charang) 86. Lead 6 (voice) 87. Lead 7 (fifths) 88. Lead 8 (bass + lead) 89. Pad 1 (new age) 90. Pad 2 (warm) 91. Pad 3 (polysynth) 92. Pad 4 (choir) 93. Pad 5 (bowed) 94. Pad 6 (metallic) 95. Pad 7 (halo) 96. Pad 8 (sweep) 97. FX 1 (rain) 98. FX 2 (soundtrack) 99. FX 3 (crystal) 100. FX 4 (atmosphere) 101. FX 5 (brightness) 102. FX 6 (goblins) 103. FX 7 (echoes) 104. FX 8 (sci-fi) 105. Sitar 106. Banjo 107. Shamisen 108. Koto 109. Kalimba 110. Bag pipe 111. Fiddle 112. Shanai 113. Tinkle Bell 114. Agogo 115. Steel Drums 116. Woodblock 117. Taiko Drum 118. Melodic Tom 119. Synth Drum 120. Reverse Cymbal 121. Guitar Fret Noise 122. Breath Noise 123. Seashore 124. Bird Tweet 125. Telephone Ring 126. Helicopter 127. Applause 128. Gunshot --------------------------------------------------------------------- This reference written 1995-1998 by James Allwright abcmidi/doc/yapshelp.txt0000644000000000000000000002121711020033716014273 0ustar rootroot YAPS - an abc to PostScript Converter YAPS is Yet Another abc to PostScript converter. The original converter was Michael Methfessel's abc2ps program. Another converter is abcm2ps, based on the abc2ps code. YAPS uses the library of PostScript routines from abc2ps, but the parser and other C code does not come from abc2ps. What is PostScript ? -------------------- This program is intended for converting an abc tune to high quality printed output. If yaps created an image file in, say, GIF or PNG format it would have to decide how many pixels wide and how many pixels high the final image would be. When the image was printed on a printer capable of much higher resolution, you would be able to see that the image was built up of lower resolution pixels. PostScript gets round this limitation by storing the image as a description of all the objects that will appear on the page. These descriptions are converted to pixels at the last moment, when the resolution of the printer is known. This way, you can make full use of the resolution available. If you are lucky, you may have a PostScript printer, in which case you can send the output of yaps directly to the printer. If not, there are PostScript interpreter programs available, which will turn a PostScript image into other image formats. A popular freely available PostScript interpreter is called GhostScript. Another freely available program, GSView, provides a graphical interface to GhostScript and lets you view images on-screen. For a full description of the PostScript language, see "PostScript Language Reference (third edition)" by Adobe Systems Inc. ---------------------------------------------------------------- Executing yaps with no filename will give the yaps version and the following message: Usage: yaps [] possible options are - -d : debug - display data structure -e : draw tunes with reference numbers in list list is comma-separated and may contain ranges but no spaces e.g. 1,3,7-20 -E : generate Encapsulated PostScript -l : landscape mode -M XXXxYYY : set margin sizes in points 28.3 points = 1cm, 72 points = 1 inch -N : add page numbering -k [NN] : number every bar or every NN th bar -o : specify output file -P ss : paper size; 0 is A4, 1 is US Letter or XXXxYYY to set size in points -s XX : scaling factor (default is 0.7) -V : separate voices in multi-voice tune -x : print tune number in X: field Takes an abc music file and converts it to PostScript. If no output filename is given, then by default it is the input filename but with extension .ps . YAPS features ------------- 1. Uses the abc2midi parsing code, so hopefully compatibility with abc2midi will be good. 2. Measures the width of lyric text for lyric typesetting. 3. Uses dynamically extensible data structures in most places, so you should not be restricted by compiled-in limits. 4. Multiple voices drawn with notes played at the same time aligned. 5. Supports special characters using ISO latin 1 font. Special characters are created with a TeX-like code e.g. \'E or a 3 digit octal code e.g. \315 . 6. Supports the following clefs : baritone, tenor, alto, mezzo, soprano, treble, bass. Recommended use is I:clef=bass To make it easier to enter tunes in clefs othan than treble clef, yaps supports I:octave=-1 to indicate than a C in the tune represents the note one octave below the pitch defined in the abc standard. These may be combined in one I: statement e.g. I:clef=bass octave=-2 You can also use clefs that are one, two or three octaves higher or lower than normal using e.g. treble-8, treble+15, treble-22. The clef is drawn with a small 8, 15 or 22 above or below the clef symbol. The clef= and octave= commands may also go in the K: field e.g. K:G clef=bass-8 octave=-3 Note that there is an incompatibility between the behaviour of yaps and the behaviour of abc2ps 1.3.3. abc2ps 1.3.3 does not support the I:octave=N command, but selecting certain clefs causes it to automatically transpose by several octaves. You can produce abc that works for both by following the clef change with an I:octave=N command to do the transpose that abc2ps does automatically. 7. Produces boxed part labels. 8. Supports the segno symbol with !segno! and coda with !coda! . Other musical instructions such as !fine! and !D.C.! come out as text. 9. Supports the U: field for abbreviating symbols to single characters. e.g. U:S = !segno! allows S to be used to produce the segno symbol. Currently this only allows new symbols to be defined and does not allow the existing pre-defined symbols M,L,R,H and T to be altered. 10. Supports the following abc2ps extensions to abc : %%newpage - start a new page, %%vskip N - adds vertical space of N points. If N is followed by 'cm' or 'in' the units are taken as centimetres or inches instead of points e.g. 4cm. %%text - print text %%centre (or %%center for Americans) - print centred text. If %%text or %%centre appear in the header, the text appears above the tune. %%staffsep SIZE - set vertical blank space between 2 consecutive music staves. %%titleleft N - select title placed to the left or centred. N = 1 places the title on the left while N = 0 centres it. %%titlecaps - title is displayed in upper case (capital) letters. %%textfont NAME SIZE - select font called NAME and point size SIZE for text produced by %%text or %%centre. If only NAME is given, the font stays the same size. Likewise, if '-' is given as the NAME, only the font size changes. %%titlefont NAME SIZE - select font for title. %%subtitlefont NAME SIZE - select font for titles after the first title. %%composerfont NAME SIZE - select font for words in C: and O: fields and part specifier (P: in header). %%wordsfont NAME SIZE - select font for words in W: fields. %%partsfont NAME SIZE - select font for boxed parts and !instruction! . %%vocalfont NAME SIZE - select font for words in w: fields. %%gchordfont NAME SIZE - select font for guitar chords in the music. (It is advisable not to change the font name for the last two, since the program calculates the width of strings using default fonts) %%titlespace, %%subtitlespace, %%textspace, %%composerspace, %%wordsspace, %%partsspace, %%vocalspace and %%gchordspace determine the amount of space left above the relevant type of text. Each of these should be followed by a size in points or value in centrimetres or inches. e.g. %%composerfont 3 %%titlefont 2cm 11. Supports placing of accompaniment chords either above or below the stave. %%chordsabove - places accompaniment chords above the stave (default). %%chordsbelow - places accompaniment chords below the stave. 12. Supports optional text enclosed in quotes before and after the tempo specification in the Q: field. This extension comes from abc2ps. 13. Allows highlighting notes by switching output from black to red and vice-versa using the !red! and !black! instructions. Known bugs and Limitations -------------------------- 1. Overfull lines of music are not split over multiple lines. WARNING - the -s option is now used for scaling. Selecting separate printing of each voice (which previously used -s) is now done with -V. YAPS is still under development and missing a number of features. However, it should produce acceptable output most of the time. You may want to try abc2ps or abcm2ps if you find that YAPS will not do what you want. Viewing PostScript Files from DOS --------------------------------- Here is how I arranged things so that I can view PostScript from DOS : 1. Install Ghostscript 5.10 (compiled to run under DOS). This is not totally straightforward; you have to install the fonts separately and then set the environment variable GS_LIB to a path containing the GhostScript initialization files and the fonts. 2. Install Pictview, a free image viewer. 3. Create a small batch file ps.bat containing the following line: c:\gs5.10\gs386 -r120 -sOutputFile=out.tif -sDEVICE=tiffg3 -sPAPERSIZE=a4 -dNOPAUSE -dBATCH %1 When you run this, it creates a TIFF file out.tif containing all pages in compressed format. The following commands will show you the dots for an abc file: yaps demo.abc ps demo.ps pictview out.tif Copyright (c) James Allwright 1999 (parts of the code Copyright Michael Methfessel). This code may be freely re-distributed under the terms of the GNU public license. You are encouraged to modify and redistribute it, provided this copyright notice is retained. abcmidi/doc/readme.txt0000644000000000000000000005206112642211050013704 0ustar rootrootabcMIDI : abc <-> MIDI conversion utilities midi2abc version 2.99 October 18 2015 abc2midi version 3.87 January 03 2015 abc2abc version 1.84 November 10 2015 yaps version 1.63 November 15 2015 abcmatch version 1.70 November 15 2015 midicopy version 1.22 November 15 2015 24th January 2002 Copyright James Allwright J.R.Allwright@westminster.ac.uk University of Westminster, London, UK January 2016 Seymour Shlien fy733@ncf.ca This is free software. You may copy and re-distribute it under the terms of the GNU General Public License version 2 or later, which is available from the Free Software Foundation (and elsewhere). This package is to be found on the web at http://abc.sourceforge.net/abcMIDI/ (The latest versions for the time being is found on ifdo.pugmarks.com/~seymour/runabc/top.html.) Note, if you have difficulty compiling the package because you do not have snprintf see the note in doc/CHANGES dated January 08 2005 (and also December 17 2004). These programs make use of the 'midifilelib' public domain MIDI file utilities, available from http://www.harmony-central.com/MIDI/midifilelib.tar.gz If you have the source distribution and intend to re-compile the code, read the file coding.txt. --------------------------------------------------------------------- midi2abc - program to convert MIDI format files to abc notation. This program takes a MIDI format file and converts it to something as close as possible to abc text format. The user then has to add text fields not present in the MIDI header and possibly tidy up the abc note output. Features : * The key is chosen so as to minimize the number of accidentals. Alternatively, the user can specify the key numerically (a positive number is the number of sharps, a negative number is minus the number of flats). * Note length can be set by specifiying the total number of bars or the tempo of the piece. Alternatively the note length can be read from the file. However, by default it is deduced in a heuristic manner from the inter-note distances. This means that you do not have to use the MIDI clock as a metronome when playing in a tune from a keyboard. * Barlines are automatically inserted. The user specifies the number of measures in the anacrusis before the first barline and the time signature. * The program can guess how many beats there should be in the anacrusis, either by looking for the first strong note or minimizing the number of notes split by a tie across a barline. * Where a note extends beyond a bar break, it is split into two tied notes. * The output has 4 bars per line. * Enough accidental signs are put in the music to ensure that no pitch errors occur if a barline is added or deleted. * The program attempts to group notes sensibly in each bar. * Triplets and broken rhythm (a>b) are supported. * Chords are identified. * Text information from the original MIDI file is included as comments. * The -c option can be used to select only 1 MIDI channel. Events on other channels are ignored. What midi2abc does not do : * Supply tune title, composer or any other field apart from X: , K:, Q:, M: and L: - these must be added by hand afterwards, though they may have been included in the text of the MIDI file. * Support duplets, quadruplets, other esoteric features. * Support mid-tune key or meter changes. * Deduce repeats. The output is just the notes in the input file. * Recover an abc tune as supplied to abc2midi. However, if you want to do this, "midi2abc -xa -f file.mid" comes close. midi2abc usage : midi2abc -a -xa extract anacrusis from file (find first strong note) -ga guess anacrusis (minimize ties across bars) -gk guess key signature by minimizing accidentals -gu guess the number of midi pulses per note from note duration statistics in the MIDI file -m