abcm2ps-7.8.9/Changes 0000644 0001750 0001750 00000104215 12417252216 012460 0 ustar jef jef ---- Version 7.8.9 - 14/10/14 ----
Fix crash when %%combinevoices on beamed notes since 7.8.7
(reported by David Lacroix).
Fix bad start/stop of ties since 7.8.4.
Fix possible crash with %%alignbars.
Fix crash when tune starting with grace note in the middle voice
of a 3-voices staff.
---- Version 7.8.8 - 14/08/29 ----
Fix loss of indentation since 7.8.4
(reported by David Lacroix).
Fix bad stem direction in lowest voice when invisible and visible rests
at a same time in a measure since 7.8.4
(reported by Eric Reinbold).
Fix crash when multi-rest at start of a second voice of a staff.
---- Version 7.8.7 - 14/08/09 ----
Fix crash when %%combinevoices and different beaming.
Always remove the invisible rests at start of tune when L:auto.
Fix some compilation warnings
(reported by Daniel Branning).
Fix bad split of tune into music lines (imported from 8.1.5)
(reported by Stephen West).
Fix bad horizontal offset of rests alone in a measure
(reported by Stephen West).
---- Version 7.8.6 - 14/07/17 ----
Fix lack of source last character in syntax errors.
Fix double information about the titles/subtitles in the PostScript
output for (external) index generation since 7.8.5
(reported by Tim Macdonald).
Fix double interpretation of '.' in "!p!.(c"
(reported by David Lacroix).
Fix the size of font of the page header/footer, broken in 7.8.5
(reported by Francis Stevens).
---- Version 7.8.5 - 14/07/01 ----
Add more information about the titles/subtitles in the PostScript
output for (external) index generation
(asked by Tim Macdonald).
Add Δ (delta) in the known glyphs
(asked by Chuck Boody).
Fix some bad 'Line overfull' messages when automatic line break.
Fix bad interval between staff systems according to %%staffsep
(reported by Eric Reinbold and David Lacroix).
Fix bad %%header/%%footer vertical offsets.
Don't put the last music line on a new page when page overflow on W:.
---- Version 7.8.4 - 14/06/18 ----
Fix clash of voice name with staff when new voice after %%staves.
Fix bad indentation when more staves further in the tune.
Set the ties closer to the notes.
Fix bad handling of '|' when first character in w:
(reported by Alex Scheutzow).
Check the floating voices in %%score/%%staves.
Fix bad stem direction when %%combinevoices.
Fix crash when measure bar numbering and less notes in the upper staff
(reported by : J.Joao Almeida).
Fix too big syntax error messages
(reported by David Lacroix).
Fix bad horizontal offset of full rests in voice overlay
(reported by J.C.L.).
---- Version 7.8.3 - 14/05/23 ----
Fix too wide space between text paragraphs when not fill or justify.
Fix crash when utf-8 and latin characters in a same file
(reported by Henry Bley-Vroman).
Change internal fonts to 'serif' on SVG output.
Forbid rests in grace note sequences.
Fix crash when rest in grace note sequence.
Fix direction of ties in chords with odd number of notes.
Fix bad direction of beam stub when last note with !beambr1! / !beambr2!
(reported by David Lacroix).
Fix crash when only P: or Q: in a generation sequence
(reported by Henry Bley-Vroman).
---- Version 7.8.2 - 14/05/05 ----
Fix non-function of %%voice inside %%tune since some 7.5.x
(reported by Gerhard Schacherl).
Fix small internal problem with decorations.
Fix position of accent marks (!>!)
(reported by Paul Rosen).
Fix bad margins when tune inside %%multicol
(reported by A.B. Steen).
Don't draw repeat brackets when bar between 2 staves.
Fix lack of EOS in some internal strings
(fixed by Olivier Levon).
Fix bad guitar chord / annotation when '\' inside.
Fix double transposition of 2 octaves when both %%abc2pscompat
and octave= in K:/V:.
Fix compilation warnings on MAC
(reported by Chuck Boody).
---- Version 7.8.1 - 14/04/02 ----
Fix bad text justication with PostScript output
(reported by Gerhard Schacherl).
Fix loss of positions (decorations, lyrics..) when described in format file
(reported by John Taylor).
Fix loss of tie at end of line
(reported by David Lacroix).
Fix loss of vertical space above the staves (%%staffsep) since 7.6.10
(reported by David Lacroix).
---- Version 7.8.0 - 14/03/26 ----
Fix bad buffer size when blank after '-k'.
Fix time shift when L:auto and multi-rests in 2nd voices.
Fix bad %%abcm2ps and %%abc-charset when redefined inside previous tune.
Fix loss of time signature when empty staff system at start of tune.
Add 'forall', 'search' and string comparison to the mini PS interpreter
(asked by Chuck Boody for easynotes.fmt).
Fix bad handling of %%abcm2ps.
Fix bad tie when %%combinevoices and chord behind measure bar and other symbol.
---- Version 7.7.2 - 14/03/07 ----
Fix loss of parameters after '--abcm2ps x' in command line.
Fix loss of lyric word when note as last music line symbol.
Fix bad handling of multi-rests when L:auto.
Fix bad vertical of rests when no notes in voice and clef != treble.
Fix lack of time signature at start of line when %%timewarn.
Fix %%stretchstaff which did not work.
Fix %%parskipfac for non fill/justified texts.
Fix %%infoline in some cases.
Fix %%combinevoices 0 and the rests.
Fix %%break which could not be put in the tune header.
Fix bad generation when SVG output of justified text.
Fix bad %%voice filtering.
Remove option '-u' (abs2pscompat in command line).
Fix bad 'M' decoration when abc2pscompat.
Fix bad duration of notes when grace notes and L:auto.
Fix bad behaviour of '%%gstemdir 3' when at start of n-plet
(reported by David Lacroix).
---- Version 7.7.1 - 14/02/18 ----
Fix crash when decoration at start of tune
(reported by Jean-Luc Zins).
---- Version 7.7.0 - 14/02/17 ----
Fix bad indentation when new name of a voice appearing later in the
music line.
Fix bad rest offset when in 2nd voice and longer than notes of 1st voice.
Fix bad tie when combinevoices and chord behind measure bar.
Change again the behaviour of %%staffnonote.
Set correct vertical space for elements of invisible staves.
Don't output errors when w: found in ignored voice (not in %%staves).
Add option 'opposite' in %%gstemdir
(requested by David Lacroix).
Fix documentation about the default value of %%staffnonote.
Add line number in more 'Too many words..' error messages.
Fix compilation warning.
---- Version 7.6.10 - 14/01/23 ----
Fix crash with rests in previous release
(reported by David Lacroix).
---- Version 7.6.9 - 14/01/23 ----
Change the function name to 'fraction of tone' instead of 'fraction of
semitone' when no 'microscale=', but '%%micronewps 1'
!!compatibility!!.
Add line number when 'Too many words in lyric line' error
(reported by Seymour Shlien).
Fix bad PS functions when K: with explicit list of microtone accidentals.
Include glyphs for microscale=4.
Set %%micronewps when 'microscale=' in K: or V:.
Fix erroneous 'bad tie' when tie at end of line and clef change
in the upper voice.
Do %%tablature work again.
Fix clash of rest with notes when rest between notes since 7.6.8
(reported by David Lacroix).
Change the behaviour of %%staffnonote
(asked by Atte André Jensen and Steve West).
Fix crash when last music line contains only invisible rests
and %%cfmt.measurenb >= 0.
---- Version 7.6.8 - 13/11/21 ----
Don't display the staves which contain only invisible rests.
Keep the brace staff systems when '%%staffnonote 0' and
at least one staff has some notes.
Have better ties when clef or staff change.
Have better vertical offset of rests in multi-voice tunes
(reported by Eric Reinbold).
Fix bad slur endpoint when above/below a tuplet.
Have better display of mixed slurs and tuplets
(asked by David Lacroix).
Accept %%bgcolor for .xhtml output.
Adjust the offset of elements in empty staves when '%%staffnonote 0'.
Fix bad handling of tuplets with %%combinevoices, sometimes
giving a program crash.
Permit output to stdout with option '-v'.
---- Version 7.6.7 - 13/11/03 ----
Fix again bad tag in XHTML output
(reported by David Lacroix).
---- Version 7.6.6 - 13/11/03 ----
Add page/sequence information in the SVG headers.
Fix bad tag in XHTML output
(reported by David Lacroix).
---- Version 7.6.5 - 13/11/02 ----
Fix bad SVG/XHTML output when '--' in the command line.
Put program information in XHTML header only.
---- Version 7.6.4 - 13/11/01 ----
Add more information in svg images (program, command line,
title for building index).
Set no margin for XHTML printing.
Adjust the scale of the SVG images.
---- Version 7.6.3 - 13/10/25 ----
Fix loss of line break when %%postscript at start of line.
Fix bad SVG output when 'show' before 'stroke' or 'fill'
(reported by David Lacroix).
Fix bad position of elements built from PostScript code with 'ltr'
in SVG rendering.
(reported by David Lacroix).
Update config.guess and config.sub from http://git.savannah.gnu.org/
(asked by Deepak C Shetty and Snehal).
Add 'color="black"' in tag.
Fix bad font of string starting with non-ascii character (PS output)
(reported by David Lacroix).
---- Version 7.6.2 - 13/10/18 ----
Fix bad tie when ending note is combined with previous voice
(reported by Brian J. Dumont).
Fix loss of gchord/annotation when combine voices and
both notes have guitar chord/annotation
(reported by Atte André Jensen).
Fix bad dash lines with SVG output
(reported by David Lacroix).
Accept XML character references in texts.
Fix bad glyph names of characters greater than latin2
(reported by David Lacroix).
---- Version 7.6.1 - 13/10/16 ----
Fix bad staff system when %%staves with floating voices.
Permit unlimited PS elements in SVG rendering.
Fix memory overflow with PS 'getinterval' in SVG rendering.
Fix loss of tempo when tune starts with invisible symbol (n-plet, P:..).
Don't raise errors when "%%writefields w 0" and "+:xxx" lines of w:.
Accept a string in 'cvx' for SVG output.
Fix tuplet number vertical offset when slur starting/ending on a same note
(reported by David Lacroix).
Set a correct approximate width of the unicode characters of which
the ending bits are ASCII control characters
(reported by Mike Scott).
Adjust the SVG output closer to PS:
- greater font sizes,
- smaller note heads,
- thiner staff lines and stems.
Update documentation about %%continueall.
---- Version 7.6.0 - 13/08/20 ----
Add build with ninja-build and clang.
Fix %%staves parsing problem which could give bad PS output.
%%glyph added.
Change PS utf-8 handling !!compatibility!!.
---- Version 7.5.8 - 13/08/07 ----
Fix bad offset of rests when under the duration of an upper voice
(reported by David Lacroix).
Check '!' as linebreak only when does a linebreak.
Accept latin names of guitar chords on %%transpose.
Fix loss of lyrics under staff when %%alignbars.
Do %%clip without start work again.
Fix bad PS output when many lines in program command line.
Apply L:auto to all voices when declared in the tune header.
Fix L:auto when duration of auto measure > M: duration.
Add more explanations in the file format.txt
(thanks to Seymour Shlien).
---- Version 7.5.7 - 13/07/16 ----
Fix bad horizontal offset of EPS images
(reported by Gerhard Schacherl).
Fix bad clef change when 2 voices on the staff and invisible rests.
Add 'L:auto'.
Better vertical offset of rests when many voices per staff
(reported by David Lacroix).
Fix bad staff on multi-rest expansion when the voice goes later
to an other staff.
Fix bad line break when asked before a bar.
Do %%clip work again.
Fix bad music line breaks with %%break after generation restart.
Fix bad music line breaks with %%barperline and generation restart
(reported by David Lacroix).
Add the command line option '-k'.
Fix bad horizontal offset of stems in SVG output.
---- Version 7.5.6 - 13/06/17 ----
Have better horizontal spacing when music line is too much shrunk.
Fix bad horizontal spacing when high long notes before measure bars
(reported by Mike Scott).
Handle more than 2 unison notes in chords
(asked by Hudson Flávio Meneses Lacerda).
Remove the shift of volume decorations which does not work well
(reported by Jean-Luc Zins).
Fix crash when beam to a repeated sequence
(reported by Søren Bak Vestergaard).
Fix abnormal slur when tuplet or slur over a repeated sequence
(reported by Søren Bak Vestergaard).
---- Version 7.5.5 - 13/06/06 ----
Fix bad position of shifted volume decorations
(reported by David Lacroix).
Fix bad %%transpose of more than one octave down.
Extend %%shiftunison
(asked by David Lacroix).
Keep the natural accidentals when transposing K:none
(reported by David Lacroix).
Fix bad handling of %%splittune
(reported by Gerhard Schacherl).
Allow back text insertion commands in tune header.
Put the measure number a bit higher when at start of line with
a key signature with sharps.
Look to the next note for B stem direction when at start of bar
(requested by Mike Scott).
---- Version 7.5.4 - 13/05/27 ----
Fix abnormal note shift when inverted voices in the staff
since previous release.
Accept %%ps the same as %%postscript
(asked by David Lacroix).
Fix crash with grace notes since previous release
(reported by David Lacroix).
Fix again bad accidentals of 2nd notes in a measure when transposing K:none
(reported by David Lacroix).
---- Version 7.5.3 - 13/05/24 ----
Fix clash of stem and note when bigger stem due to beam
(reported by Hudson Flávio Meneses Lacerda).
Permit %%break in tune header (i.e. out of %%tune).
Fix abnormal error when %%tune folowed by %%break.
Have less width of explicit key signature with same accidentals at octave.
Better handling of %%staffbreak.
Fix lack of staves after %%staves and new staves.
Fix bad line splitting with measure repeat
(reported by Gerhard Schacherl).
Fix bad vertical offset of tune on auto newpage
(reported by Gerhard Schacherl).
Fix the behaviour of "\n" in guitar chord since version 7.x.x
(reported by Gerhard Schacherl).
Don't raise error when %%textfont in tune header.
Have smaller stems in some cases when the voices are inverted on a staff.
Fix loss of deco/stem position/direction when declared in V:
after T: / %%vskip / ...
(reported by Colin Hume).
Don't set natural accidentals when transposing K:none.
Fix bad accidentals of 2nd notes in a measure when transposing K:none
(reported by David Lacroix).
Have half ties when clef or staff change
(reported by David Webber).
Don't shift a voice when no overlap with the previous one.
Don't have one head when unison and different dots
(reported by Hudson Flávio Meneses Lacerda).
Center the repeat measure signs.
Don't have any slur starting from measure repeat signs
(reported by Søren Bak Vestergaard).
Have a longer tie when the ending note is shifted.
Vertically center the rests when alone in a staff
(reported by Hudson Flávio Meneses Lacerda).
Shift on the left the volume decorations (ff, pp..) when under a note
with a stem down
(asked by Hudson Flávio Meneses Lacerda).
Fix loss of rest when %%combinevoices >= 0 and invisible 1st rest.
Extend %%combinevoices and remove %%comball.
Put the dot decorations on the stems
(asked by Hudson Flávio Meneses Lacerda).
Have a better tie vertical offset
(asked by Hudson Flávio Meneses Lacerda).
Fix loss of position/direction commands when after K: or T: inside tune
(reported by Hudson Flávio Meneses Lacerda).
Fix loss of tempo when 'y' at start of tune in secondary voice
(reported by Hudson Flávio Meneses Lacerda).
Don't allow text insertion commands in tune header.
Fix bad horizontal offset of stem when unison and shifted note head
(reported by Hudson Flávio Meneses Lacerda).
Fix nested tuplets vertical offset when slurs
(reported by Hudson Flávio Meneses Lacerda).
Fix a crash when tune with only repeat bars
(reported by Colin Hume).
Fix a crash when K:none and %%transpose
(reported by David Lacroix).
---- Version 7.5.2 - 13/03/22 ----
Fix bad display when %%combinevoice + %%comball and imbricated chords.
Have wider horizontal space at end of music line when no bar.
Fix a crash on explicit music break without a bar
since previous version
(reported by Hudson Flávio Meneses Lacerda).
Define the page format in the PS output.
This fixes page size problems when converting PS to PDF
(asked by Martin Tarenskeen).
Fix a loop when a tune ends with Z, a bar and a chord
(reported by Hudson Flávio Meneses Lacerda).
Check the number of measures of X/Z (multi-rests).
---- Version 7.5.1 - 13/03/17 ----
Fix some clashes of accidentals when same notes in 2 voices on the same staff
(reported by Hudson Flávio Meneses Lacerda).
Fix loss of line at end of %%tune/%%voice
(reported by Hudson Flávio Meneses Lacerda).
Fix bad handling of many %%voice's in %%tune
(reported by Hudson Flávio Meneses Lacerda).
Fix bad horizontal space when note with stem up followed by note
with stem down
(reported by Hudson Flávio Meneses Lacerda).
Fix bad accidentals of tied notes when transpose with K:none
(reported by David Lacroix).
Have smaller vertical space for !emphasis! (accent)
(asked by Hudson Flávio Meneses Lacerda).
Have thicker slurs
(asked by Hudson Flávio Meneses Lacerda).
Have one more beam in feathered beams
(asked by Hudson Flávio Meneses Lacerda).
Fix bad note head when !beam-rall! on quavers
(reported by Hudson Flávio Meneses Lacerda).
Replace the clef of V: in case of voice filter with %%clef
(reported by Hudson Flávio Meneses Lacerda).
Fix bad handling of %%score/%%staves when found after %%voice
(reported by Hudson Flávio Meneses Lacerda).
Fix bad handling of %%beginxx/%%endxx with different abcm2ps
pseudo-comment prefixes.
(reported by Hudson Flávio Meneses Lacerda).
Fix bad music line cut when less notes in the master voice
and no bar at end of line
(reported by Hudson Flávio Meneses Lacerda).
Add 'true' and 'false' in the PS to SVG interpreter
(asked by Hudson Flávio Meneses Lacerda).
Fix bad PS output when 2 empty lines at end of a justified text sequence
(reported by Hudson Flávio Meneses Lacerda).
Fix crash when %%clef in %%voice
(reported by Hudson Flávio Meneses Lacerda).
Fix overlay voice inheritance (%%transpose and glyph placements).
Apply %%transpose in tune header or after first K: to all voices.
---- Version 7.5.0 - 13/03/01 ----
Fix loss of multi-rest when alone in a music line.
Fix clash of rests when 3 voices per staff
(reported by David Lacroix).
Fix loss of %%clef after first K:.
Implement "^8" and "_8" in clef= and %%clef.
Fix abnormal subtitle output when T: found outside of tune
(reported by Henry Bley-Vroman).
Fix bad transposition of chords
(reported by Jean-Luc Zins).
Don't scale the measure numbers when the first staff is scaled
(asked by Hudson Flávio Meneses Lacerda).
!! Accept 'clef=F' as 'clef=F,' !!
(needed for ABC 2.1.1).
Handle many times 'repeat 2 measures'
(asked by Atte André Jensen).
Permit a measure repeat to be at start of music line
(asked by Atte André Jensen).
Fix crash when measure repeat at start of music line
(reported by Atte André Jensen).
Don't output error when info-like 'x:' found outside of tune.
---- Version 7.4.2 - 13/02/13 ----
Fix bad vertical offset of Q: when %%text after first K:.
Extend %%abcm2ps with up to 3 characters.
Don't output the words after tune on %%leftmargin/rightmargin/scale.
Fix bad horizontal place of the tune title when %%leftmargin after K:
(reported by Tim Goetze).
!! Don't start anymore a tune on T: !!
(asked by Henry Bley-Vroman).
Handle %%stafflines after %%score.
Add missing definitions for Microsoft Visual Basic
(reported by Jean-Luc Zins).
Fix bad test of buffer overflow on command options
(reported by Jean-Luc Zins).
Remove extra invisible staff when %%score before %%vskip
(reported by Tim Goetze).
Fix bad warning message when "P: K: Q:" at end of line
(reported by Jean-Luc Zins).
Fix bad tune selection when many files in the command line
(reported by Larry).
Fix lack of slurs when beam on 2 staves
(reported by David Lacroix).
Fix abnormal natural signs after some %%transpose
(reported by Jean-Luc Zins).
---- Version 7.4.1 - 13/02/11 ----
Better error messages when error found at end of ABC line.
Warn on deprecated syntaxes of Q:
(asked by Chuck Boody).
Fix double slurs when beam on 2 staves
(reported by David Lacroix).
Extend %%repeat for working with many voices
(reported by Atte André Jensen).
---- Version 7.4.0 - 13/01/29 ----
Do better transposition of microtonal tunes
(asked by David Lacroix).
Fix bad vertical offset of some decorations (dot, tenuto) when inverted
stems and multi-voice
(reported by David Lacroix).
Use the glyphs of the simple accidentals of PS fonts instead of internal ones
when they exist.
!! Always use UTF-8 characters for simple accidentals (sharp, flat, natural)
in PS output !! (see the new insertion of ellipsis in sample.abc)
Fix double tie when beam continued on next line
(reported by David Lacroix).
Extend the %%voicescale possible values to [0.6 .. 1.5].
---- Version 7.3.5 - 13/01/15 ----
Fix crash when "%%gchord hidden".
---- Version 7.3.4 - 13/01/08 ----
%%abcm2ps added.
Bad octave in overlay voices when "octave=" in main voice
(reported by Colin Hume).
Let more slurs under the tuplets
(asked by David Lacroix).
Don't keep the K:'s with same key signature when %%keywarn is set
(reported by Henry Bley-Vroman).
---- Version 7.3.3 - 12/12/14 ----
Remove some example files from the distribution.
Draw the staves with spaces ('y') only and "%%staffnonote 1".
Fix %%alignbars which was broken in 7.2.1.
Set as tune global some info fields (K:, M: and Q:) and pseudo-comments
after the first K: and middle-tune T:.
Better note shifts of 3rd voice of a same staff.
Change %%shiftunisson to %%shiftunison.
In unison, shift the note with a down stem
(reported by Paolo Minazzi).
Fix bad output file when note head decoration since 7.3.2.
%%voicescale added.
Fix loss of %%indent since 7.2.2
(reported by David Lacroix).
Remove the horizontal space of empty key signatures
(reported by David Lacroix).
Fix bad beam at end of voice overlay since 7.3.0
(reported by David Lacroix).
---- Version 7.3.2 - 12/12/07 ----
Don't do a page break after the tune title when %%scale after 1st K:.
Fix clash of beams with grace notes when down stems.
Display better slurs on grace notes with down stems.
Fix abnormal error on w: ending with '\' (continuation).
Fix loss of tempo (Q: in tune header) when %%scale/%%rightmargin/...
after first K:.
Fix again clash of slurs with decorations/tuplets/...
Fix bad slurs when inside the staff since 7.3.0
(reported by David Lacroix).
Fix %%select when tunes have blank lines (%%begintext..)
(reported by Henry Bley-Vroman).
---- Version 7.3.1 - 12/11/28 ----
Fix left width of heads in flute.fmt.
Fix the documentation about flute.fmt.
Do %%ornament work.
Add "hidden" in %%dynamic, %%gchord, %%ornament, %%vocal and %%volume.
Don't do an error on the information field "r:".
Fix no output when lack of "%%multicol end"
(reported by Henry Bley-Vroman).
Fix crash on "%%multicol end" with -E or -g.
Handle "%% endxx" (space after %%)
(reported by Henry Bley-Vroman).
Check again if not enough words in lyrics (w:)
(asked by Steve West).
Handle ties from notes to grace notes
(asked by David Lacroix).
Fix bad width of hole on %%staffbreak multi-voice.
Fix bad offset of the slurs since previous version
(reported by David Lacroix).
Don't display a key signature on %%transpose from K:none
(reported by David Lacroix).
---- Version 7.3.0 - 12/11/17 ----
Don't let annotations move the next key or time signature to the right.
Fix lack of key/time warnings at end of line
(reported by Jean-Luc Zins).
Don't continue beaming in voice overlay
(reported by Jean-Luc Zins).
Don't shift notes with guitar chord after repeat bracket with long text
(reported by Norman Bearon).
Fix bad ties from grace notes
(reported by David Lacroix).
!! Change %%stretchlast to a floating point value. !!
Fix clash of slurs with decorations/tuplets/...
(reported by John Walsh).
---- Version 7.2.2 - 12/11/07 ----
Fix bad bars between staves with %%score.
Fix bad explicit line breaks after notes.
Don't try to stretch the last music line when %%stretchlast 0
(reported by Chuck Boody).
Fix too much space above the staff when scaled staff and P: or Q:.
Fix left indentation when empty staves and %%staffnonote.
Fix bad offset of measure numbers when 1st staff empty and %%staffnonote.
Fix bad offset of measure numbers when 1st staff is scaled
(reported by Hudson Flávio Meneses Lacerda).
Change default value of %%hyphencont to 1
(asked by David Webber).
Don't draw repeat brackets when bar between 2 staves
(reported by David Webber).
---- Version 7.2.1 - 12/10/30 ----
Fix crash when centered decoration under staff at start of new staff system.
Add %%breaklimit.
Change the internal algorithm of automatic line breaking.
(reported by Steve West).
Fix loss of gchord/annot or bad font when scaled staves
(reported by Hudson Flávio Meneses Lacerda).
Fix bad vertical offset of lyrics when scaled staves and slurs in lower voice.
Fix bad horizontal offset of lyrics on scaled staves.
Handle the line breaks of the top voice only.
Add %%staffscale and %%stafflines.
Fix bad handling of '=' in M:none.
Fix bad handling of %%barsperline when M:none
(reported by David Lacroix).
---- Version 7.2.0 - 12/10/25 ----
Fix crash when mid-staff decoration in new voice at start of line
(reported by David Lacroix).
Add "ignore" as special U: value.
Extend %%linebreak to * ; ? and @.
!! Put the output annotations (-A) after the symbols. !!
Add more symbols in output annotations (-A).
Adjust the width scale of all fonts when set in %%font.
Fix "error w: without music" in secondary voices when ABC version >= 2.1
(reported by Frédéric Aupépin).
---- Version 7.1.3 - 12/10/18 ----
Fix bad slur vertical offsets on scaled staves.
Fix loss of key/time warning when preceeded by %%stave
(reported by Mike Scott).
Fix bad left side of staff systems when some %%score in the line.
Handle the line breaks of all primary voices.
Fix internal linkage errors.
Fix error "w: without music" when Q: in tune header
(reported by Frédéric Aupépin).
Fix bad line width after some decorations in SVG output.
Bad measure number after time signature change
(reported by Jean-Luc Zins).
Bad clef when P: or Q: between first K: and %%staves
followed by K: or V: with a clef != treble
(reported by Jean-Luc Zins).
---- Version 7.1.2 - 12/10/09 ----
Treat "%%writefield M 0".
Add %%dblrepbar and draw :|: and :||: as ::
(asked by Nils Liberg).
Fix bad parsing of the "%abc-" at start of file.
Do more control of ties between two different notes.
Add %%keywarn
(asked by John Chambers).
Fix clash of subtitle and guitar chord since 7.1.1.
Fix bad staff key signature when "| $ [P:] [K:] |"
(reported by John Chambers).
Fix bad staff key/time signatures when P: or Q: before K:/M: in tune
(reported by John Chambers).
Fix crash when %%continueall and music line cut on a bar with !beamon!
(also when %%breakoneoln 0) and handle beams on two music lines
(reported by Guido Gonzato).
---- Version 7.1.1 - 12/09/29 ----
Convert multi-rests of one measure to rests
(reported by David Webber).
Move the decorations to the last rest on multi-rest expand
(reported by David Webber).
Remove the test messages 'y_set i:-xx'.
May change the guitar chord position (%%gchord) inside the tunes
(and internal change of guitar chord / annotation handling).
Add %%user.
Add !beam-accel! and !beam-rall!
(asked by Hudson Flávio Meneses Lacerda).
Reduce a bit the space before the measure bars.
---- Version 7.1.0 - 12/09/13 ----
Fix bad accidentals when clef one octave higher or lower than normal.
Add a letter to select a repeated measure in tune selection
(asked by Hudson Flávio Meneses Lacerda).
Fix bad music position in tune selection (%%break / %%clip)
(reported by Hudson Flávio Meneses Lacerda).
Fix lack of tune selection (%%break / %%clip) of the first measures (0 and 1)
(reported by Hudson Flávio Meneses Lacerda).
Remove extra vertical space between staves after a staff with no note
(reported by Chuck Boody).
Add "%%tune end" and authorize blank lines in %%tune sequences
!! compatibility !!
(asked by Hudson Flávio Meneses Lacerda).
Change %%acccancel to %%cancelkey !! compatibility !!.
Accept time signatures as "M:5 ((2+3)/4)" and "M:5 (2/4+3/4)".
Display the parenthesis of "M:7/8 (3+2+2)"
(reported by Guido Gonzato).
---- Version 7.0.16 - 12/09/06 ----
Fix bad measure numbering when contbarnb and "y" between "|" and "[number"
(reported by Hudson Flávio Meneses Lacerda).
Fix clash of measure numbering with key signature.
Add 'microscale= in K: and V:.
Fix bad handling of '/symbol' for "cvx" in the mini PS interpreter.
Add %%micronewps.
Fix abnormal new music line when Q: or P: followed by [V:x] and grace notes.
Fix loss of tempo when second voice starting with grace notes
(reported by Wim Rotty).
---- Version 7.0.15 - 12/08/27 ----
Fix %%transpose ignored in file or tune header
(reported by David Webber).
Fix octave= ignored when no clef= in K: and V:
(reported by Alex Scheutzow).
Add %%acccancel.
---- Version 7.0.14 - 12/07/22 ----
Fix crash with floating point sensitive machines as ARM.
Remove the 'title only' selection in %%select.
Extend the %%tune filter to the whole tune header.
Fix bad file date in header/footer ('$d') when %%format in the ABC file
(reported by D. Glenn Arthur Jr.).
---- Version 7.0.13 - 12/06/17 ----
Fix array overflow on %%writefields Q.
Fix bad note heads when both normal and percussion voices in a same staff
(reported by Frédéric Boulanger).
Don't transpose the percussion voices.
Fix bad expansion of 'Xn' when multi-staves
(reported by Jose Joao Dias de Almeida).
---- Version 7.0.12 - 12/06/10 ----
Fix bad tie when at end of repeat and start of new repeat ("c- :|2 c")
(reported by Nils Liberg).
Fix crash when PS code at end of line since 7.0.11
(reported by David Lacroix).
Fix loss of next lyric lines when error found in a w: line
(reported by Nils Liberg).
---- Version 7.0.11 - 12/06/02 ----
Better hyphen in lyrics lines when big space between notes
(reported by Nils Liberg).
Fix presence of tempo when "%%writefields Q 0" before first K:
(reported by Nils Liberg).
Fix abnormal line with one note when line cut should be on a clef change
(reported by Alex Scheutzow).
Fix presence of meter at start of line when empty voice.
Don't remove '%%' in %%beginps/%%endps sequences.
Fix array overflow and possible crash with empty %%beginxxx/%endxxx
(reported by Nils Liberg).
---- Version 7.0.10 - 12/05/28 ----
Extend %%voice to any options.
Fix crash when K: without more symbol at end of tune
(reported by Nils Liberg).
Add %%stemdir, %%gstemdir and %%clef.
Fix clash of '8' in clef with octave +/-8
(reported by David Lacroix).
---- Version 7.0.9 - 12/05/23 ----
Fix program loop when width of measure bigger than staff width.
Fix bad last measure bar position again
(reported by many people).
Fix loss of music line break when line ending with grace note(s),
note and no bar
(reported by John Chambers).
---- Version 7.0.8 - 12/05/21 ----
Fix loss of paragraph break on empty lines.
Fix crash in %%begintext with fill/justify and pango on an empty line.
Fix bad offset of lyrics after tune when new page
(reported by Christian Schnarr).
Fix bad last measure bar position since 7.0.6.
Handle 'X' (invisible multi-rest).
Don't do "titletrim" when the length of last word of the title
is greater than 4.
Fix lack of tempo at start of tune when "%%writefields Q 0" is declared
further in the tune.
---- Version 7.0.7 - 12/05/16 ----
Fix bad line numbers in errors and svg annotations
(reported by Nils Liberg).
---- Version 7.0.6 - 12/05/13 ----
Fix lack of key signature when K: + clef inside music line.
Fix lack of accidentals when spaces in the accidental list of K:.
Fix placement errors when scaled voice or staff
(reported by D. Glenn Arthur Jr.).
Don't put a measure bar at end of line when the measure is incomplete
(reported by Christian Schnarr).
Fix ps2pdf error when unknown UTF-8 characters
(reported by Nils Liberg).
---- Version 7.0.5 - 12/04/30 ----
Update the documentation: there is no %%ignore
(reported-by D. Glenn Arthur Jr.).
Bad offset of %%EPS since version 5.x.x
(reported-by D. Glenn Arthur Jr.).
Handle more lowercase to uppercase letters when %%titlecaps
(reported by Christian Schnarr).
---- Version 7.0.4 - 12/03/31 ----
Fix loss of music after abc 2.0 continuation ('\').
Fix a loss of voices when appearing in a new %%staves/%%score.
Handle the ABC 2.1 "w:" behaviour (with "+:").
Fix misplaced part (P:) when followed by K:, or M:
(reported by Richard Walker).
Accept 'K' in %%titleformat and (text) notes after tune.
Crash when misplaced dble repeat bar in second voice at end of tune
(reported by Simon Wascher).
Fix X: value in title when ', The' at end of T:
(reported by Paul Hardy).
---- Version 7.0.3 - 12/03/03 ----
Don't print the tempo in tune when '%%writefields Q 0'
(reported by Martin Tarenskeen).
Let less space at end of line when key signature change.
Fix a scanning problem with the command line parameter '--header'.
Update the %%staves/%%score in tune(s) when defined in %%tune.
---- Version 7.0.2 - 12/02/21 ----
Don't add the %%transpose values
(reported by Alex Scheutzow).
Accept empty K: as K:none.
Fix lack of key signature change when exp accidental list of the same size.
Fix bad slur on grace notes when staffscale != 1
(reported by Pete Showman).
Treat 'I:' as '%%' (accept I:abc-include and I:abc-charset).
Ignore %%sep and %%vskip when global and -E or -g.
Accept any format parameter in %%tune sequences.
Fix crash when some output needed in format files by ignoring %%text...
Stop %%tune/%%voice options on empty lines.
Fix %%abc2pscompat again.
Fix some errors "??? buffer not empty:".
Fix vertical offset problems on page breaks with %%multicol.
Fix bad page header when %%multicol outside and inside tunes.
Don't use pango when only accidentals in string
(reported by John Collins).
Ignore %%writefields when outputting %%titleformat
(reported by Pete S).
Reset the default standard title format when %%titleformat is empty.
---- Version 7.0.1 - 12/02/06 ----
Fix loss of music when voices disappear and reappear by %%score
(reported by John Collins).
Fix some warnings in slre.c compilation
(reported by Chuck Boody).
Add %%custos.
Fix some cases of error "Line too much shrunk".
Bad computation of the page height letting to much space in (portrait)
or going out of (landscape) the bottom of the page when
using %%multicol.
---- Version 7.0.0 - 12/02/02 ----
Permit more pseudo-comments to be defined at command-line level.
Add %%tune, %%voice, %%break, %%clip and %%select.
Add tune selection with '-e' by regular expression.
Permit the clefs to go under or above the notes/rests.
Creation from abcm2ps version 6.6.4.
abcm2ps-7.8.9/INSTALL 0000644 0001750 0001750 00000003312 11336716162 012216 0 ustar jef jef --- abcm2ps installation ---
Unix(-like) systems
===================
This version uses the GNU 'autoconf' package, so, after untarring the
sources, run:
./configure
make
and then, as root, do:
make install
The 'abcm2ps' command should work if '/usr/local/bin' is in your path
(try 'abcm2ps -h' for a list of the command line options).
You may change some compile options at configure level. To know which,
run:
configure --help
Windows or MAC systems
======================
Change the file 'config.h' according to your preferences, compile all
the '.c' files using an ANSI C compiler, and link them together. The
resulting binary file should run immediately from where it has been
generated. You may then move it at any place you want.
Testing
=======
To test the program, run it with one of the .abc files as the command
line argument:
abcm2ps sample
The resulting file, 'Out.ps', may be displayed using a PostScript
previewer such as ghostscript, or may be sent directly to a PostScript
printer, or indirectly to a simple printer using a postscript filter.
About the 'pango' library
=========================
abcm2ps now uses the 'pango' library to render texts with non latin
characters. If you don't have such texts, you don't need this library.
In Unix(-like) systems, at configure time, the pango generation elements
are searched by pkg-config in the gdk-2.0 library. If this library or
pkg_config are not found, the rendering of non latin characters with
pango will be disabled, but this rendering may be done by other means,
especially by CMap (see the file chinese.abc). Note also that, when
pango is defined, it may be disabled at command line level by
'--pango 0' (you may try it with chinese.abc).
abcm2ps-7.8.9/License 0000644 0001750 0001750 00000043076 07005373333 012502 0 ustar jef jef GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
675 Mass Ave, Cambridge, MA 02139, USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
Appendix: How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
Copyright (C) 19yy
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., 675 Mass Ave, Cambridge, MA 02139, USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) 19yy name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Library General
Public License instead of this License.
abcm2ps-7.8.9/Makefile 0000644 0001750 0001750 00000007422 12417252344 012631 0 ustar jef jef # Makefile source for abcm2ps
VERSION = 7.8.9
CC = gcc
INSTALL = /usr/bin/install -c
INSTALL_DATA = ${INSTALL} -m 644
INSTALL_PROGRAM = ${INSTALL}
CPPFLAGS = -DHAVE_CONFIG_H -I.
CPPPANGO =
CFLAGS = -g -O2 -Wall -pipe
LDFLAGS = -lm
prefix = /usr/local
exec_prefix = ${prefix}
srcdir = .
bindir = ${exec_prefix}/bin
libdir = ${exec_prefix}/lib
datadir = ${prefix}/share
docdir = /usr/local/doc
# unix
OBJECTS=abc2ps.o \
abcparse.o buffer.o deco.o draw.o format.o front.o glyph.o music.o parse.o \
slre.o subs.o svg.o syms.o
abcm2ps: $(OBJECTS)
$(CC) $(CFLAGS) -o $@ $(OBJECTS) $(LDFLAGS)
$(OBJECTS): abcparse.h config.h Makefile
abc2ps.o buffer.o deco.o draw.o format.o front.o glyph.o music.o parse.o \
subs.o svg.o syms.o: abc2ps.h
abc2ps.o front.o: front.h
front.o parse.o slre.o: slre.h
subs.o: subs.c
$(CC) $(CFLAGS) $(CPPFLAGS) $(CPPPANGO) -c -o $@ $<
abcmfe: front.c front.h slre.h
$(CC) $(CFLAGS) -DMAIN -o $@ $< slre.o
DOCFILES=$(addprefix $(srcdir)/,Changes License README *.abc *.eps *.txt)
install: abcm2ps
mkdir -p $(bindir); \
mkdir -p $(datadir)/abcm2ps; \
mkdir -p $(docdir)/abcm2ps; \
$(INSTALL_PROGRAM) abcm2ps $(bindir)
for f in $(srcdir)/*.fmt; do \
$(INSTALL_DATA) $$f $(datadir)/abcm2ps; \
done
for f in $(DOCFILES); do \
$(INSTALL_DATA) $$f $(docdir)/abcm2ps; \
done
uninstall:
echo "uninstalling..."; \
rm -f $(bindir)/abcm2ps; \
rm -rf $(datadir)/abcm2ps; \
rm -rf $(docdir)/abcm2ps
DIST_FILES = \
abcm2ps-$(VERSION)/Changes \
abcm2ps-$(VERSION)/INSTALL \
abcm2ps-$(VERSION)/License \
abcm2ps-$(VERSION)/Makefile \
abcm2ps-$(VERSION)/Makefile.in \
abcm2ps-$(VERSION)/README \
abcm2ps-$(VERSION)/abc2ps.c \
abcm2ps-$(VERSION)/abc2ps.h \
abcm2ps-$(VERSION)/abcparse.c \
abcm2ps-$(VERSION)/abcparse.h \
abcm2ps-$(VERSION)/accordion.abc \
abcm2ps-$(VERSION)/build.ninja \
abcm2ps-$(VERSION)/buffer.c \
abcm2ps-$(VERSION)/chinese.abc \
abcm2ps-$(VERSION)/configure \
abcm2ps-$(VERSION)/configure.in \
abcm2ps-$(VERSION)/config.h \
abcm2ps-$(VERSION)/config.h.in \
abcm2ps-$(VERSION)/config.guess \
abcm2ps-$(VERSION)/config.sub \
abcm2ps-$(VERSION)/deco.c \
abcm2ps-$(VERSION)/deco.abc \
abcm2ps-$(VERSION)/draw.c \
abcm2ps-$(VERSION)/features.txt \
abcm2ps-$(VERSION)/flute.fmt \
abcm2ps-$(VERSION)/format.c \
abcm2ps-$(VERSION)/format.txt \
abcm2ps-$(VERSION)/front.c \
abcm2ps-$(VERSION)/front.h \
abcm2ps-$(VERSION)/glyph.c \
abcm2ps-$(VERSION)/install.sh \
abcm2ps-$(VERSION)/landscape.fmt \
abcm2ps-$(VERSION)/music.c \
abcm2ps-$(VERSION)/musicfont.fmt \
abcm2ps-$(VERSION)/newfeatures.abc \
abcm2ps-$(VERSION)/options.txt \
abcm2ps-$(VERSION)/parse.c \
abcm2ps-$(VERSION)/sample.abc \
abcm2ps-$(VERSION)/sample2.abc \
abcm2ps-$(VERSION)/sample3.abc \
abcm2ps-$(VERSION)/sample3.eps \
abcm2ps-$(VERSION)/sample4.abc \
abcm2ps-$(VERSION)/sample5.abc \
abcm2ps-$(VERSION)/slre.c \
abcm2ps-$(VERSION)/slre.h \
abcm2ps-$(VERSION)/subs.c \
abcm2ps-$(VERSION)/svg.c \
abcm2ps-$(VERSION)/syms.c \
abcm2ps-$(VERSION)/tight.fmt \
abcm2ps-$(VERSION)/voices.abc
dist:
ln -s . abcm2ps-$(VERSION); \
tar -zcvf abcm2ps-$(VERSION).tar.gz $(DIST_FILES); \
rm abcm2ps-$(VERSION)
zip-dist:
ln -s . abcm2ps-$(VERSION); \
zip -r abcm2ps-$(VERSION).zip $(DIST_FILES); \
rm abcm2ps-$(VERSION)
zip: abcm2ps.exe
strip abcm2ps.exe; \
cd ..; zip -r abcm2ps-$(VERSION).zip \
abcm2ps-$(VERSION)/abcm2ps.exe \
abcm2ps-$(VERSION)/License \
abcm2ps-$(VERSION)/Changes \
abcm2ps-$(VERSION)/INSTALL \
abcm2ps-$(VERSION)/sample3.eps \
abcm2ps-$(VERSION)/*.abc \
abcm2ps-$(VERSION)/*.fmt \
abcm2ps-$(VERSION)/*.txt ; cd -
EXAMPLES = accordion.ps \
chinese.ps \
deco.ps \
newfeatures.ps \
sample.ps \
sample2.ps \
sample3.ps \
sample4.ps \
sample5.ps \
voices.ps
test: $(EXAMPLES)
%.ps: %.abc
./abcm2ps -O $@ $<
clean:
rm -f *.o $(EXAMPLES) # *.obj
abcm2ps-7.8.9/Makefile.in 0000644 0001750 0001750 00000007434 12243365635 013246 0 ustar jef jef # Makefile source for abcm2ps
VERSION = @VERSION@
CC = @CC@
INSTALL = @INSTALL@
INSTALL_DATA = @INSTALL_DATA@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
CPPFLAGS = @DEFS@ @CPPFLAGS@ -I.
CPPPANGO = @CPPPANGO@
CFLAGS = @CFLAGS@
LDFLAGS = @LDFLAGS@ -lm
prefix = @prefix@
exec_prefix = @exec_prefix@
srcdir = @srcdir@
VPATH = @srcdir@
bindir = @bindir@
libdir = @libdir@
datadir = @datarootdir@
docdir = @prefix@/doc
# unix
OBJECTS=abc2ps.o \
abcparse.o buffer.o deco.o draw.o format.o front.o glyph.o music.o parse.o \
slre.o subs.o svg.o syms.o
abcm2ps: $(OBJECTS)
$(CC) $(CFLAGS) -o $@ $(OBJECTS) $(LDFLAGS)
$(OBJECTS): abcparse.h config.h Makefile
abc2ps.o buffer.o deco.o draw.o format.o front.o glyph.o music.o parse.o \
subs.o svg.o syms.o: abc2ps.h
abc2ps.o front.o: front.h
front.o parse.o slre.o: slre.h
subs.o: subs.c
$(CC) $(CFLAGS) $(CPPFLAGS) $(CPPPANGO) -c -o $@ $<
abcmfe: front.c front.h slre.h
$(CC) $(CFLAGS) -DMAIN -o $@ $< slre.o
DOCFILES=$(addprefix $(srcdir)/,Changes License README *.abc *.eps *.txt)
install: abcm2ps
mkdir -p $(bindir); \
mkdir -p $(datadir)/abcm2ps; \
mkdir -p $(docdir)/abcm2ps; \
$(INSTALL_PROGRAM) abcm2ps $(bindir)
for f in $(srcdir)/*.fmt; do \
$(INSTALL_DATA) $$f $(datadir)/abcm2ps; \
done
for f in $(DOCFILES); do \
$(INSTALL_DATA) $$f $(docdir)/abcm2ps; \
done
uninstall:
echo "uninstalling..."; \
rm -f $(bindir)/abcm2ps; \
rm -rf $(datadir)/abcm2ps; \
rm -rf $(docdir)/abcm2ps
DIST_FILES = \
abcm2ps-$(VERSION)/Changes \
abcm2ps-$(VERSION)/INSTALL \
abcm2ps-$(VERSION)/License \
abcm2ps-$(VERSION)/Makefile \
abcm2ps-$(VERSION)/Makefile.in \
abcm2ps-$(VERSION)/README \
abcm2ps-$(VERSION)/abc2ps.c \
abcm2ps-$(VERSION)/abc2ps.h \
abcm2ps-$(VERSION)/abcparse.c \
abcm2ps-$(VERSION)/abcparse.h \
abcm2ps-$(VERSION)/accordion.abc \
abcm2ps-$(VERSION)/build.ninja \
abcm2ps-$(VERSION)/buffer.c \
abcm2ps-$(VERSION)/chinese.abc \
abcm2ps-$(VERSION)/configure \
abcm2ps-$(VERSION)/configure.in \
abcm2ps-$(VERSION)/config.h \
abcm2ps-$(VERSION)/config.h.in \
abcm2ps-$(VERSION)/config.guess \
abcm2ps-$(VERSION)/config.sub \
abcm2ps-$(VERSION)/deco.c \
abcm2ps-$(VERSION)/deco.abc \
abcm2ps-$(VERSION)/draw.c \
abcm2ps-$(VERSION)/features.txt \
abcm2ps-$(VERSION)/flute.fmt \
abcm2ps-$(VERSION)/format.c \
abcm2ps-$(VERSION)/format.txt \
abcm2ps-$(VERSION)/front.c \
abcm2ps-$(VERSION)/front.h \
abcm2ps-$(VERSION)/glyph.c \
abcm2ps-$(VERSION)/install.sh \
abcm2ps-$(VERSION)/landscape.fmt \
abcm2ps-$(VERSION)/music.c \
abcm2ps-$(VERSION)/musicfont.fmt \
abcm2ps-$(VERSION)/newfeatures.abc \
abcm2ps-$(VERSION)/options.txt \
abcm2ps-$(VERSION)/parse.c \
abcm2ps-$(VERSION)/sample.abc \
abcm2ps-$(VERSION)/sample2.abc \
abcm2ps-$(VERSION)/sample3.abc \
abcm2ps-$(VERSION)/sample3.eps \
abcm2ps-$(VERSION)/sample4.abc \
abcm2ps-$(VERSION)/sample5.abc \
abcm2ps-$(VERSION)/slre.c \
abcm2ps-$(VERSION)/slre.h \
abcm2ps-$(VERSION)/subs.c \
abcm2ps-$(VERSION)/svg.c \
abcm2ps-$(VERSION)/syms.c \
abcm2ps-$(VERSION)/tight.fmt \
abcm2ps-$(VERSION)/voices.abc
dist:
ln -s . abcm2ps-$(VERSION); \
tar -zcvf abcm2ps-$(VERSION).tar.gz $(DIST_FILES); \
rm abcm2ps-$(VERSION)
zip-dist:
ln -s . abcm2ps-$(VERSION); \
zip -r abcm2ps-$(VERSION).zip $(DIST_FILES); \
rm abcm2ps-$(VERSION)
zip: abcm2ps.exe
strip abcm2ps.exe; \
cd ..; zip -r abcm2ps-$(VERSION).zip \
abcm2ps-$(VERSION)/abcm2ps.exe \
abcm2ps-$(VERSION)/License \
abcm2ps-$(VERSION)/Changes \
abcm2ps-$(VERSION)/INSTALL \
abcm2ps-$(VERSION)/sample3.eps \
abcm2ps-$(VERSION)/*.abc \
abcm2ps-$(VERSION)/*.fmt \
abcm2ps-$(VERSION)/*.txt ; cd -
EXAMPLES = accordion.ps \
chinese.ps \
deco.ps \
newfeatures.ps \
sample.ps \
sample2.ps \
sample3.ps \
sample4.ps \
sample5.ps \
voices.ps
test: $(EXAMPLES)
%.ps: %.abc
./abcm2ps -O $@ $<
clean:
rm -f *.o $(EXAMPLES) # *.obj
abcm2ps-7.8.9/README 0000644 0001750 0001750 00000005121 12024034430 012027 0 ustar jef jef --- abcm2ps version 7.x.x ---
Overview
========
abcm2ps is a program which converts music tunes from ABC format to
PostScript or SVG. Based on abc2ps version 1.2.5 (see Contacts below),
it was developped mainly to print barock organ scores which have
independant voices played on one or many keyboards and a pedal-board
(the 'm' of abcm2ps stands for many or multi staves/voices).
Features
========
The main features of abcm2ps are quite the same as the abc2ps ones,
but they are closer to the ABC standard 2.0 (draft IV - 14/8/2003):
http://abc.sourceforge.net/standard/abc2-draft.html
Installation and usage
======================
The installation procedure is described in the file INSTALL.
Basically, the program usage is:
abcm2ps [options] file1 [file1_options] file2 [file2_options] ...
where file1, file2, .. are the ABC input files. This will generate
a Postscript file (default name: 'Out.ps' - run 'abcm2ps -h' to
know the list of the command line options).
Documentation
=============
- options.txt contains the list of the command line options.
- format.txt contains the list of the format parameters.
- features.txt lists the differences from the current ABC standard.
Differences with abc2ps
=======================
- the algorithms relative to voice and staff handling are different and
may give better or worse results depending on the tunes.
- abcm2ps does not print the list of tunes and has different filtering
functions. On the command line:
- '-o' is implicit
- '-e' accepts only one parameter.
- '-C', '-R', '-S', '-T' don't exist anymore. If you want such
filtering, you should to use some external script or program
instead.
- There is no interactive mode ('-i').
- The scale is global (it was restricted to the music part in abc2ps).
- The characters '\\' don't do a line break.
- In landscape format, the values of 'pagewidth' and 'pageheight'
are internally exchanged, so there is no need to set them explicitely.
- The format 'staffwidth' is obsolete. Use 'pagewidth' instead.
- Look also in the file 'sample.abc' for other incompatibilities.
Limits
======
Many limits may be changed at compilation time (number of voices, staves,
..).
Contacts
========
The primary abcm2ps site is:
http://moinejf.free.fr/
Guido Gonzatto maintains Win32 and RedHat binaries and some more
documentation at:
http://abcplus.sourceforge.net/
abc2ps was developped by Michael Methfessel:
http://www.ihp-ffo.de/~msm/
mailto:msm@ihp-ffo.de
To know more about the ABC notation, have a look at:
http://abcnotation.com/
For any comment:
mailto:moinejf (at) free (dot) fr
abcm2ps-7.8.9/abc2ps.c 0000644 0001750 0001750 00000053644 12314505364 012515 0 ustar jef jef /*
* abcm2ps: a program to typeset tunes written in ABC format using PostScript
*
* Copyright (C) 1998-2014 Jean-François Moine (http://moinejf.free.fr)
*
* Adapted from abc2ps-1.2.5:
* Copyright (C) 1996,1997 Michael Methfessel (msm@ihp-ffo.de)
*
* 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, see .
*/
#include
#include
#include
#include
#include
#include
#include
#ifdef linux
#include
#endif
#include "abc2ps.h"
#include "front.h"
/* -- global variables -- */
INFO info;
unsigned char deco[256];
struct SYMBOL *sym; /* (points to the symbols of the current voice) */
int tunenum; /* number of current tune */
int pagenum = 1; /* current page in output file */
/* switches modified by command line flags: */
int quiet; /* quiet mode */
int secure; /* secure mode */
int annotate; /* output source references */
int pagenumbers; /* write page numbers */
int epsf; /* for EPSF (1) or SVG (2) output */
int svg; /* SVG (1) or XML (2 - HTML + SVG) output */
int showerror; /* show the errors */
char outfn[FILENAME_MAX]; /* output file name */
int file_initialized; /* for output file */
FILE *fout; /* output file */
char *in_fname; /* current input file name */
time_t mtime; /* last modification time of the input file */
static time_t fmtime; /* " " of all files */
int s_argc; /* command line arguments */
char **s_argv;
struct tblt_s *tblts[MAXTBLT];
struct cmdtblt_s cmdtblts[MAXCMDTBLT];
int ncmdtblt;
/* -- local variables -- */
static char abc_fn[FILENAME_MAX]; /* buffer for ABC file name */
static char *styd = DEFAULT_FDIR; /* format search directory */
static int def_fmt_done = 0; /* default format read */
static struct SYMBOL notitle;
/* memory arena (for clrarena, lvlarena & getarena) */
#define MAXAREAL 3 /* max area levels:
* 0; global, 1: tune, 2: generation */
#define AREANASZ 8192 /* standard allocation size */
#define MAXAREANASZ 0x20000 /* biggest allocation size */
static int str_level; /* current arena level */
static struct str_a {
struct str_a *n; /* next area */
char *p; /* pointer in area */
int r; /* remaining space in area */
int sz; /* size of str[] */
char str[2]; /* start of memory area */
} *str_r[MAXAREAL], *str_c[MAXAREAL]; /* root and current area pointers */
/* -- local functions -- */
static void read_def_format(void);
static void treat_file(char *fn, char *ext);
static FILE *open_ext(char *fn, char *ext)
{
FILE *fp;
char *p;
if ((fp = fopen(fn, "rb")) != NULL)
return fp;
if ((p = strrchr(fn, DIRSEP)) == NULL)
p = fn;
if (strrchr(p, '.') != NULL)
return NULL;
strcat(p, ".");
strcat(p, ext);
if ((fp = fopen(fn, "rb")) != NULL)
return fp;
return NULL;
}
/* -- open a file for reading -- */
FILE *open_file(char *fn, /* file name */
char *ext, /* file type */
char *rfn) /* returned real file name */
{
FILE *fp;
char *p;
int l;
/* if there was some ABC file, try its directory */
if (in_fname && in_fname != fn
&& (p = strrchr(in_fname, DIRSEP)) != NULL) {
l = p - in_fname + 1;
strncpy(rfn, in_fname, l);
strcpy(&rfn[l], fn);
if ((fp = open_ext(rfn, ext)) != NULL)
return fp;
}
/* try locally */
strcpy(rfn, fn);
if ((fp = open_ext(rfn, ext)) != NULL)
return fp;
/* try a format in the format directory */
if (*ext != 'f' || *styd == '\0')
return NULL;
l = strlen(styd) - 1;
if (styd[l] == DIRSEP)
sprintf(rfn, "%s%s", styd, fn);
else
sprintf(rfn, "%s%c%s", styd, DIRSEP, fn);
return open_ext(rfn, ext);
}
/* -- read a whole input file -- */
/* the real/full file name is put in tex_buf[] */
static char *read_file(char *fn, char *ext)
{
size_t fsize;
FILE *fin;
char *file;
if (*fn == '\0') {
strcpy(tex_buf, "stdin");
fsize = 0;
file = malloc(8192);
for (;;) {
int l;
l = fread(&file[fsize], 1, 8192, stdin);
fsize += l;
if (l != 8192)
break;
file = realloc(file, fsize + 8192);
}
if (ferror(stdin) != 0) {
free(file);
return 0;
}
if (fsize % 8192 == 0)
file = realloc(file, fsize + 2);
time(&fmtime);
} else {
struct stat sbuf;
fin = open_file(fn, ext, tex_buf);
if (!fin)
return NULL;
if (fseek(fin, 0L, SEEK_END) < 0) {
fclose(fin);
return NULL;
}
fsize = ftell(fin);
rewind(fin);
if ((file = malloc(fsize + 2)) == NULL) {
fclose(fin);
return NULL;
}
if (fread(file, 1, fsize, fin) != fsize) {
fclose(fin);
free(file);
return NULL;
}
fstat(fileno(fin), &sbuf);
memcpy(&fmtime, &sbuf.st_mtime, sizeof fmtime);
fclose(fin);
}
file[fsize] = '\0';
return file;
}
/* call back to handle %%format/%%abc-include - see front.c */
static void include_cb(unsigned char *fn)
{
char abc_fn_sav[FILENAME_MAX];
strcpy(abc_fn_sav, abc_fn);
treat_file((char *) fn, "fmt");
strcpy(abc_fn, abc_fn_sav);
}
/* -- treat an input file and generate the ABC file -- */
static void treat_file(char *fn, char *ext)
{
struct abctune *t;
char *file, *file2;
int file_type, l;
static int nbfiles;
if (nbfiles > 2) {
error(1, 0, "Too many included files");
return;
}
/* initialize if not already done */
if (!fout)
read_def_format();
/* read the file into memory */
/* the real/full file name is in tex_buf[] */
if ((file = read_file(fn, ext)) == NULL) {
if (strcmp(fn, "default.fmt") != 0) {
error(1, NULL, "Cannot read the input file '%s'", fn);
#if defined(unix) || defined(__unix__)
perror(" read_file");
#endif
}
return;
}
if (!quiet)
fprintf(stderr, "File %s\n", tex_buf);
/* convert the strings */
l = strlen(tex_buf);
if (strcmp(&tex_buf[l - 3], ".ps") == 0) {
file_type = FE_PS;
frontend((unsigned char *) "%%beginps\n", 0);
} else if (strcmp(&tex_buf[l - 4], ".fmt") == 0) {
file_type = FE_FMT;
} else {
file_type = FE_ABC;
strcpy(abc_fn, tex_buf);
in_fname = abc_fn;
mtime = fmtime;
}
nbfiles++;
file2 = (char *) frontend((unsigned char *) file, file_type);
nbfiles--;
free(file);
if (file_type == FE_PS) /* PostScript file */
file2 = (char *) frontend((unsigned char *) "%%endps", 0);
if (nbfiles > 0) /* if %%format */
return; /* don't free the preprocessed buffer */
// memcpy(&deco_tune, &deco_glob, sizeof deco_tune);
if (file_type == FE_ABC) { /* if ABC file */
// if (!epsf)
// open_output_file();
clrarena(1); /* clear previous tunes */
}
t = abc_parse(file2);
free(file2);
front_init(0, 0, include_cb); /* reinit the front-end */
if (!t) {
if (file_type == FE_ABC)
error(1, NULL, "File '%s' is empty!", tex_buf);
return;
}
while (t) {
if (t->first_sym) /*fixme:last tune*/
do_tune(t); /* generate */
t = t->next;
}
/* abc_free(t); (useless) */
}
/* -- read the default format -- */
static void read_def_format(void)
{
if (def_fmt_done)
return;
def_fmt_done = 1;
treat_file("default.fmt", "fmt");
}
/* -- set extension on a file name -- */
void strext(char *fn, char *ext)
{
char *p, *q;
if ((p = strrchr(fn, DIRSEP)) == NULL)
p = fn;
if ((q = strrchr(p, '.')) == NULL)
strcat(p, ".");
else
q[1] = '\0';
strcat(p, ext);
}
/* -- write the program version -- */
static void display_version(int full)
{
fputs("abcm2ps-" VERSION " (" VDATE ")\n", stderr);
if (!full)
return;
fputs("Compiled: " __DATE__ "\n"
"Options:"
#ifdef A4_FORMAT
" A4_FORMAT"
#endif
#ifdef DECO_IS_ROLL
" DECO_IS_ROLL"
#endif
#ifdef HAVE_PANGO
" PANGO"
#endif
#if !defined(A4_FORMAT) && !defined(DECO_IS_ROLL) && !defined(HAVE_PANGO)
" NONE"
#endif
"\n", stderr);
if (styd[0] != '\0')
fprintf(stderr, "Default format directory: %s\n", styd);
}
/* -- display usage and exit -- */
static void usage(void)
{
display_version(0);
printf( "ABC to Postscript translator.\n"
"Usage: abcm2ps [options] file [file_options] ..\n"
"where:\n"
" file input ABC file, or '-'\n"
" options and file_options:\n"
" .output file options:\n"
" -E produce EPSF output, one tune per file\n"
" -g produce SVG output, one tune per file\n"
" -v produce SVG output, one page per file\n"
" -X produce SVG output in one XHTML file\n"
" -O fff set outfile name to fff\n"
" -O = make outfile name from infile/title\n"
" -i indicate where are the errors\n"
" -k kk size of the PS output buffer in Kibytes\n"
" .output formatting:\n"
" -s xx set scale factor to xx\n"
" -w xx set staff width (cm/in/pt)\n"
" -m xx set left margin (cm/in/pt)\n"
" -d xx set staff separation (cm/in/pt)\n"
" -a xx set max shrinkage to xx (between 0 and 1)\n"
" -F foo read format file \"foo.fmt\"\n"
" -D bar look for format files in directory \"bar\"\n"
" .output options:\n"
" -l landscape mode\n"
" -I xx indent 1st line (cm/in/pt)\n"
" -x add xref numbers in titles\n"
" -M don't output the lyrics\n"
" -N n set page numbering mode to n=\n"
" 0=off 1=left 2=right 3=even left,odd right 4=even right,odd left\n"
" -1 write one tune per page\n"
" -G no slur in grace notes\n"
" -j n[b] number the measures every n bars (or on the left if n=0)\n"
" if 'b', display in a box\n"
" -b n set the first measure number to n\n"
" -f have flat beams\n"
" -T n[v] output the tablature 'n' for voice 'v' / all voices\n"
" .line breaks:\n"
" -c auto line break\n"
" -B n break every n bars\n"
" .input file selection/options:\n"
" -e pattern\n"
" tune selection\n"
" .help/configuration:\n"
" -V show program version\n"
" -h show this command summary\n"
" -H show the format parameters\n"
" -S secure mode\n"
" -q quiet mode\n");
exit(EXIT_SUCCESS);
}
#ifdef linux
/* -- where is the default format directory -- */
static void wherefmtdir(void)
{
char exe[512], *p;
FILE *f;
int l;
if ((l = readlink("/proc/self/exe", exe, sizeof exe)) <= 0)
return;
if ((p = strrchr(exe, '/')) == NULL)
return;
p++;
if (p > &exe[5] && strncmp(p - 5, "/bin", 4) == 0) {
strcpy(p - 4, "share/abcm2ps/");
p += -4 + 14;
}
/* else, assume this is the source directory */
/* check if a format file is present */
strcpy(p, "tight.fmt");
if ((f = fopen(exe, "r")) == NULL)
return;
fclose(f);
/* change the format directory */
p[-1] = '\0';
styd = strdup(exe);
}
#endif
/* -- parse the tablature command ('-T n[v]') -- */
static struct cmdtblt_s *cmdtblt_parse(char *p)
{
struct cmdtblt_s *cmdtblt;
short val;
if (ncmdtblt >= MAXCMDTBLT) {
error(1, NULL, "++++ Too many '-T'");
return NULL;
}
if (*p == '\0')
val = -1;
else {
val = *p++ - '0' - 1;
if ((unsigned) val > MAXTBLT) {
error(1, NULL, "++++ Bad tablature number in '-T'\n");
return 0;
}
}
cmdtblt = &cmdtblts[ncmdtblt++];
cmdtblt->index = val;
cmdtblt->vn = p;
return cmdtblt;
}
/* set a command line option */
static void set_opt(char *w, char *v)
{
static char prefix = '%'; /* pseudo-comment prefix */
if (!v)
v = "";
if (strlen(w) + strlen(v) >= TEX_BUF_SZ - 10) {
error(1, NULL, "Command line '%s' option too long", w);
return;
}
sprintf(tex_buf, /* this buffer is available */
"%%%c%s %s lock\n", prefix, w, v);
if (strcmp(w, "abcm2ps") == 0)
prefix = *v;
frontend((unsigned char *) tex_buf, 0);
}
/* -- main program -- */
int main(int argc, char **argv)
{
unsigned j;
char *p, c, *aaa;
if (argc <= 1)
usage();
/* set the global flags */
s_argc = argc;
s_argv = argv;
aaa = NULL;
while (--argc > 0) {
argv++;
p = *argv;
if (*p != '-' || p[1] == '-') {
if (*p == '+' && p[1] == 'F') /* +F : no default format */
def_fmt_done = 1;
continue;
}
while ((c = *++p) != '\0') { /* '-xxx' */
switch (c) {
case 'E':
svg = 0; /* EPS */
epsf = 1;
break;
case 'g':
svg = 0; /* SVG one file per tune */
epsf = 2;
break;
case 'h':
usage(); /* no return */
case 'q':
quiet = 1;
break;
case 'S':
secure = 1;
break;
case 'V':
display_version(1);
return EXIT_SUCCESS;
case 'v':
svg = 1; /* SVG one file per pagee */
epsf = 0;
break;
case 'X':
svg = 2; /* SVG/XHTML */
epsf = 0;
break;
case 'k':
if (p[1] == '\0') {
if (--argc <= 0) {
error(1, NULL, "No value for '-k' - aborting");
return EXIT_FAILURE;
}
aaa = *++argv;
} else {
aaa = p + 1;
p += strlen(p) - 1;
}
break;
default:
if (strchr("aBbDdeFfIjmNOsTw", c)) /* if with arg */
p += strlen(p) - 1; /* skip */
break;
}
}
}
if (!quiet)
display_version(0);
/* initialize */
outfn[0] = '\0';
clrarena(0); /* global */
clrarena(1); /* tunes */
clrarena(2); /* generation */
if (aaa) { /* '-k' output buffer size */
int kbsz;
sscanf(aaa, "%d", &kbsz);
init_outbuf(kbsz);
} else {
init_outbuf(0);
}
abc_init(getarena, /* alloc */
0, /* free */
(void (*)(int level)) lvlarena, /* new level */
sizeof(struct SYMBOL) - sizeof(struct abcsym),
0); /* don't keep comments */
// memset(&info, 0, sizeof info);
info['T' - 'A'] = ¬itle;
notitle.as.text = "T:";
set_format();
reset_deco();
front_init(0, 0, include_cb);
#ifdef linux
/* if not set, try to find where is the default format directory */
if (styd[0] == '\0')
wherefmtdir();
#endif
#ifdef HAVE_PANGO
pg_init();
#endif
/* parse the arguments - finding a new file, treat the previous one */
argc = s_argc;
argv = s_argv;
while (--argc > 0) {
argv++;
p = *argv;
if ((c = *p) == '\0')
continue;
if (c == '-') {
int i;
if (p[1] == '\0') { /* '-' alone */
if (in_fname) {
treat_file(in_fname, "abc");
frontend((unsigned char *) "select\n", 0);
}
in_fname = ""; /* read from stdin */
continue;
}
i = strlen(p) - 1;
if (p[i] == '-'
&& p[1] != '-'
//fixme: 'e' may be preceded by other options
&& p[1] != 'e'
&& p[i -1] != 'O')
c = '+'; /* switch off flags with '-x-' */
}
if (c == '+') { /* switch off flags with '+' */
while (*++p != '\0') {
switch (*p) {
case '-':
break;
case 'B':
cfmt.barsperstaff = 0;
lock_fmt(&cfmt.barsperstaff);
break;
case 'c':
cfmt.continueall = 0;
lock_fmt(&cfmt.continueall);
break;
case 'F':
// def_fmt_done = 1;
break;
case 'G':
cfmt.graceslurs = 1;
lock_fmt(&cfmt.graceslurs);
break;
case 'i':
showerror = 0;
break;
case 'j':
cfmt.measurenb = -1;
lock_fmt(&cfmt.measurenb);
break;
case 'l':
cfmt.landscape = 0;
lock_fmt(&cfmt.landscape);
break;
case 'M':
cfmt.fields[1] = 1 << ('w' - 'a');
lock_fmt(&cfmt.fields);
break;
case 'N':
pagenumbers = 0;
break;
case 'O':
outfn[0] = '\0';
break;
case 'T': {
struct cmdtblt_s *cmdtblt;
aaa = p + 1;
if (*aaa == '\0') {
if (argc > 1
&& argv[1][0] != '-') {
aaa = *++argv;
argc--;
}
} else {
while (p[1] != '\0') /* stop */
p++;
if (*p == '-')
*p-- = '\0'; /* (not clean) */
}
cmdtblt = cmdtblt_parse(aaa);
if (cmdtblt != 0)
cmdtblt->active = 0;
break;
}
case 'x':
cfmt.fields[0] &= ~(1 << ('X' - 'A'));
lock_fmt(&cfmt.fields);
break;
case '0':
cfmt.splittune = 0;
lock_fmt(&cfmt.splittune);
break;
case '1':
cfmt.oneperpage = 0;
lock_fmt(&cfmt.oneperpage);
break;
default:
error(1, NULL,
"++++ Cannot switch off flag: +%c",
*p);
break;
}
}
continue;
}
if (c == '-') { /* interpret a flag with '-' */
if (p[1] == '-') { /* long argument */
p += 2;
if (--argc <= 0) {
error(1, NULL, "No argument for '--'");
return EXIT_FAILURE;
}
argv++;
set_opt(p, *argv);
continue;
}
while ((c = *++p) != '\0') {
switch (c) {
/* simple flags */
case 'A':
annotate = 1;
break;
case 'c':
cfmt.continueall = 1;
lock_fmt(&cfmt.continueall);
break;
case 'E':
break;
case 'f':
cfmt.flatbeams = 1;
lock_fmt(&cfmt.flatbeams);
break;
case 'G':
cfmt.graceslurs = 0;
lock_fmt(&cfmt.graceslurs);
break;
case 'g':
break;
case 'H':
if (!fout) {
read_def_format();
make_font_list();
}
print_format();
return EXIT_SUCCESS;
case 'i':
showerror = 1;
break;
case 'l':
cfmt.landscape = 1;
lock_fmt(&cfmt.landscape);
break;
case 'M':
cfmt.fields[1] &= ~(1 << ('w' - 'a'));
lock_fmt(&cfmt.fields);
break;
case 'q':
case 'S':
break;
case 'v':
case 'X':
break;
case 'x':
cfmt.fields[0] |= 1 << ('X' - 'A');
lock_fmt(&cfmt.fields);
break;
case '0':
cfmt.splittune = 1;
lock_fmt(&cfmt.splittune);
break;
case '1':
cfmt.oneperpage = 1;
lock_fmt(&cfmt.oneperpage);
break;
/* flag with optional parameter */
case 'N':
if (p[1] == '\0'
&& (argc <= 1
|| !isdigit((unsigned) argv[1][0]))) {
pagenumbers = 2; /* old behaviour */
break;
}
/* fall thru */
/* flags with parameter.. */
case 'a':
case 'B':
case 'b':
case 'D':
case 'd':
case 'e':
case 'F':
case 'I':
case 'j':
case 'k':
case 'L':
case 'm':
case 'O':
case 's':
case 'T':
case 'w':
aaa = p + 1;
if (*aaa == '\0') {
aaa = *++argv;
if (--argc <= 0
|| (*aaa == '-' && c != 'O')) {
error(1, NULL,
"Missing parameter after '-%c' - aborting",
c);
return EXIT_FAILURE;
}
} else {
p += strlen(p) - 1; /* stop */
}
if (strchr("BbfjkNs", c)) { /* check num args */
for (j = 0; j < strlen(aaa); j++) {
if (!strchr("0123456789.",
aaa[j])) {
if (aaa[j] == 'b'
&& aaa[j + 1] == '\0'
&& c == 'j')
break;
error(1, NULL,
"Invalid parameter <%s> for flag -%c",
aaa, c);
return EXIT_FAILURE;
}
}
}
switch (c) {
case 'a':
set_opt("maxshrink", aaa);
break;
case 'B':
set_opt("barsperstaff", aaa);
break;
case 'b':
set_opt("measurefirst", aaa);
break;
case 'D':
styd = aaa;
break;
case 'd':
set_opt("staffsep", aaa);
break;
case 'e':
set_opt("select", aaa);
break;
case 'F':
treat_file(aaa, "fmt");
break;
case 'I':
set_opt("indent", aaa);
break;
case 'j':
sscanf(aaa, "%d", &cfmt.measurenb);
lock_fmt(&cfmt.measurenb);
if (aaa[strlen(aaa) - 1] == 'b')
cfmt.measurebox = 1;
else
cfmt.measurebox = 0;
lock_fmt(&cfmt.measurebox);
break;
case 'k':
break;
case 'm':
set_opt("leftmargin", aaa);
break;
case 'N':
sscanf(aaa, "%d", &pagenumbers);
if ((unsigned) pagenumbers > 4) {
error(1, NULL,
"'-N' value %s - changed to 2",
aaa);
pagenumbers = 2;
}
break;
case 'O':
if (strlen(aaa) >= sizeof outfn) {
error(1, NULL, "'-O' too large - aborting");
exit(EXIT_FAILURE);
}
strcpy(outfn, aaa);
break;
case 's':
set_opt("scale", aaa);
break;
case 'T': {
struct cmdtblt_s *cmdtblt;
cmdtblt = cmdtblt_parse(aaa);
if (cmdtblt)
cmdtblt->active = 1;
break;
}
case 'w':
set_opt("staffwidth", aaa);
break;
}
break;
default:
error(1, NULL,
"Unknown flag: -%c ignored", c);
break;
}
}
continue;
}
if (in_fname) {
treat_file(in_fname, "abc");
frontend((unsigned char *) "select\n", 0);
}
in_fname = p;
}
if (in_fname)
treat_file(in_fname, "abc");
if (multicol_start != 0) { /* lack of %%multicol end */
error(1, NULL, "Lack of %%%%multicol end");
multicol_start = 0;
buffer_eob();
if (!info['X' - 'A']
&& !epsf)
write_buffer();
}
if (!epsf && !fout) {
error(1, NULL, "No input file specified");
return EXIT_FAILURE;
}
close_output_file();
return severity == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
}
/* -- arena routines -- */
void clrarena(int level)
{
struct str_a *a_p;
if ((a_p = str_r[level]) == NULL) {
str_r[level] = a_p = malloc(sizeof *str_r[0] + AREANASZ - 2);
a_p->sz = AREANASZ;
a_p->n = 0;
}
str_c[level] = a_p;
a_p->p = a_p->str;
a_p->r = sizeof a_p->str;
}
int lvlarena(int level)
{
int old_level;
old_level = str_level;
str_level = level;
return old_level;
}
/* The area is 8 bytes aligned to handle correctly int and pointers access
* on some machines as Sun Sparc. */
void *getarena(int len)
{
char *p;
struct str_a *a_p;
a_p = str_c[str_level];
len = (len + 7) & ~7; /* align at 64 bits boundary */
if (len > a_p->r) {
if (len > MAXAREANASZ) {
error(1, NULL,
"getarena - data too wide %d - aborting",
len);
exit(EXIT_FAILURE);
}
if (len > AREANASZ) { /* big allocation */
struct str_a *a_n;
a_n = a_p->n;
a_p->n = malloc(sizeof *str_r[0] + len - 2);
a_p->n->n = a_n;
a_p->n->sz = len;
} else if (a_p->n == 0) { /* standard allocation */
a_p->n = malloc(sizeof *str_r[0] + AREANASZ - 2);
a_p->n->n = 0;
a_p->n->sz = AREANASZ;
}
str_c[str_level] = a_p = a_p->n;
a_p->p = a_p->str;
a_p->r = a_p->sz;
}
p = a_p->p;
a_p->p += len;
a_p->r -= len;
return p;
}
abcm2ps-7.8.9/abc2ps.h 0000644 0001750 0001750 00000050673 12316602053 012514 0 ustar jef jef /* -- general macros -- */
#include
#include
#include "config.h"
#include "abcparse.h"
#define OUTPUTFILE "Out.ps" /* standard output file */
#ifndef WIN32
#define DIRSEP '/'
#else
#define DIRSEP '\\'
#endif
#define CM * 28.35 /* factor to transform cm to pt */
#define PT /* factor to transform pt to pt */
#define IN * 72.0 /* factor to transform inch to pt */
/* basic page dimensions */
#ifdef A4_FORMAT
#define PAGEHEIGHT (29.7 CM)
#define PAGEWIDTH (21.0 CM)
#define MARGIN (1.8 CM)
#else
#define PAGEHEIGHT (11.0 IN)
#define PAGEWIDTH (8.5 IN)
#define MARGIN (0.7 IN)
#endif
/* -- macros controlling music typesetting -- */
#define STEM_YOFF 1.0 /* offset stem from note center */
#define STEM_XOFF 3.5
#define STEM 20 /* default stem height */
#define STEM_MIN 16 /* min stem height under beams */
#define STEM_MIN2 14 /* ... for notes with two beams */
#define STEM_MIN3 12 /* ... for notes with three beams */
#define STEM_MIN4 10 /* ... for notes with four beams */
#define STEM_CH_MIN 14 /* min stem height for chords under beams */
#define STEM_CH_MIN2 10 /* ... for notes with two beams */
#define STEM_CH_MIN3 9 /* ... for notes with three beams */
#define STEM_CH_MIN4 9 /* ... for notes with four beams */
#define BEAM_DEPTH 3.2 /* width of a beam stroke */
#define BEAM_OFFSET 0.25 /* pos of flat beam relative to staff line */
#define BEAM_SHIFT 5.0 /* shift of second and third beams */
/* To align the 4th beam as the 1st: shift=6-(depth-2*offset)/3 */
#define BEAM_FLATFAC 0.6 /* factor to decrease slope of long beams */
#define BEAM_THRESH 0.06 /* flat beam if slope below this threshold */
#define BEAM_SLOPE 0.5 /* max slope of a beam */
#define BEAM_STUB 6.0 /* length of stub for flag under beam */
#define SLUR_SLOPE 1.0 /* max slope of a slur */
#define DOTSHIFT 5 /* dot shift when up flag on note */
#define GSTEM 14 /* grace note stem length */
#define GSTEM_XOFF 1.6 /* x offset for grace note stem */
#define BETA_C 0.1 /* max expansion for flag -c */
#define BETA_X 1.0 /* max expansion before complaining */
#define VOCPRE 0.4 /* portion of vocals word before note */
#define GCHPRE 0.4 /* portion of guitar chord before note */
/* -- Parameters for note spacing -- */
/* fnn multiplies the spacing under a beam, to compress the notes a bit */
#define fnnp 0.9
/* -- macros for program internals -- */
#define STRL1 256 /* string length for file names */
#define MAXSTAFF 16 /* max staves */
#define BSIZE 512 /* buffer size for one input string */
#define BREVE (BASE_LEN * 2) /* double note (square note) */
#define SEMIBREVE BASE_LEN /* whole note */
#define MINIM (BASE_LEN / 2) /* half note (white note) */
#define CROTCHET (BASE_LEN / 4) /* quarter note (black note) */
#define QUAVER (BASE_LEN / 8) /* 1/8 note */
#define SEMIQUAVER (BASE_LEN / 16) /* 1/16 note */
#define MAXFONTS 30 /* max number of fonts */
#define T_LEFT 0
#define T_JUSTIFY 1
#define T_FILL 2
#define T_CENTER 3
#define T_SKIP 4
#define T_RIGHT 5
#define YSTEP 128 /* number of steps for y offsets */
extern unsigned char deco[256];
struct FONTSPEC {
int fnum; /* index to font tables in format.c */
float size;
float swfac;
};
extern char *fontnames[MAXFONTS]; /* list of font names */
/* lyrics */
#define LY_HYPH 0x10 /* replacement character for hyphen */
#define LY_UNDER 0x11 /* replacement character for underscore */
#define MAXLY 16 /* max number of lyrics */
struct lyl {
struct FONTSPEC *f; /* font */
float w; /* width */
float s; /* shift / note */
char t[1]; /* word */
};
struct lyrics {
struct lyl *lyl[MAXLY]; /* ptr to lyric lines */
};
/* guitar chord / annotations */
#define MAXGCH 8 /* max number of guitar chords / annotations */
struct gch {
char type; /* ann. char, 'g' gchord, 'r' repeat, '\0' end */
unsigned char idx; /* index in as.text */
unsigned char font; /* font */
char box; /* 1 if in box */
float x, y; /* x y offset / note + (top or bottom) of staff */
float w; /* width */
};
/* positions / directions */
/* 0: auto, 1: above/up (SL_ABOVE), 2: below/down (SL_BELOW)
* 3: hidden (SL_AUTO) or opposite for gstemdir */
#define SL_HIDDEN SL_AUTO
struct posit_s {
unsigned short dyn:2; /* %%dynamic */
unsigned short gch:2; /* %%gchord */
unsigned short orn:2; /* %%ornament */
unsigned short voc:2; /* %%vocal */
unsigned short vol:2; /* %%volume */
unsigned short std:2; /* %%stemdir */
unsigned short gsd:2; /* %%gstemdir */
};
/* music element */
struct SYMBOL { /* struct for a drawable symbol */
struct abcsym as; /* abc symbol !!must be the first field!! */
struct SYMBOL *next, *prev; /* voice linkage */
struct SYMBOL *ts_next, *ts_prev; /* time linkage */
struct SYMBOL *extra; /* extra symbols (grace notes, tempo... */
unsigned char type; /* symbol type */
#define NO_TYPE 0 /* invalid type */
#define NOTEREST 1 /* valid symbol types */
#define SPACE 2
#define BAR 3
#define CLEF 4
#define TIMESIG 5
#define KEYSIG 6
#define TEMPO 7
#define STAVES 8
#define MREST 9
#define PART 10
#define GRACE 11
#define FMTCHG 12
#define TUPLET 13
#define STBRK 14
#define CUSTOS 15
#define NSYMTYPES 16
unsigned char voice; /* voice (0..nvoice) */
unsigned char staff; /* staff (0..nstaff) */
unsigned char nhd; /* number of notes in chord - 1 */
int dur; /* main note duration */
signed char pits[MAXHD]; /* pitches for notes */
int time; /* starting time */
unsigned int sflags; /* symbol flags */
#define S_EOLN 0x0001 /* end of line */
#define S_BEAM_ST 0x0002 /* beam starts here */
#define S_BEAM_BR1 0x0004 /* 2nd beam must restart here */
#define S_BEAM_BR2 0x0008 /* 3rd beam must restart here */
#define S_BEAM_END 0x0010 /* beam ends here */
#define S_OTHER_HEAD 0x0020 /* don't draw any note head */
#define S_IN_TUPLET 0x0040 /* in a tuplet */
#define S_TREM2 0x0080 /* tremolo on 2 notes */
#define S_RRBAR 0x0100 /* right repeat bar (when bar) */
#define S_XSTEM 0x0200 /* cross-staff stem (when note) */
#define S_BEAM_ON 0x0400 /* continue beaming */
#define S_SL1 0x0800 /* some chord slur start */
#define S_SL2 0x1000 /* some chord slur end */
#define S_TI1 0x2000 /* some chord tie start */
#define S_PERC 0x4000 /* percussion */
#define S_RBSTOP 0x8000 /* repeat bracket stop */
#define S_FEATHERED_BEAM 0x00010000 /* feathered beam */
#define S_REPEAT 0x00020000 /* sequence / measure repeat */
#define S_NL 0x00040000 /* start of new music line */
#define S_SEQST 0x00080000 /* start of vertical sequence */
#define S_SECOND 0x00100000 /* symbol on a secondary voice */
#define S_FLOATING 0x00200000 /* symbol on a floating voice */
#define S_NOREPBRA 0x00400000 /* don't print the repeat bracket */
#define S_TREM1 0x00800000 /* tremolo on 1 note */
#define S_TEMP 0x01000000 /* temporary symbol */
#define S_SHIFTUNISON_1 0x02000000 /* %%shiftunison 1 */
#define S_SHIFTUNISON_2 0x04000000 /* %%shiftunison 2 */
struct posit_s posit; /* positions / directions */
signed char stem; /* 1 / -1 for stem up / down */
signed char nflags; /* number of note flags when > 0 */
char dots; /* number of dots */
unsigned char head; /* head type */
#define H_FULL 0
#define H_EMPTY 1
#define H_OVAL 2
#define H_SQUARE 3
signed char multi; /* multi voice in the staff (+1, 0, -1) */
signed char nohdix; /* no head index (for unison) */
short u; /* auxillary information:
* - CLEF: small clef
* - KEYSIG: old key signature
* - BAR: new bar number
* - TUPLET: tuplet format
* - NOTE: tremolo number / feathered beam
* - FMTCHG (format change): subtype */
#define PSSEQ 0 /* postscript sequence */
#define SVGSEQ 1 /* SVG sequence */
#define REPEAT 2 /* repeat sequence or measure
* doty: # measures if > 0
* # notes/rests if < 0
* nohdix: # repeat */
float x; /* x offset */
signed char y; /* y offset of note head */
signed char ymn, ymx, yav; /* min, max, avg note head y offset */
float xmx; /* max h-pos of a head rel to top
* width when STBRK */
float xs, ys; /* coord of stem end / bar height */
float wl, wr; /* left, right min width */
float space; /* natural space before symbol */
float shrink; /* minimum space before symbol */
float xmax; /* max x offset */
float shhd[MAXHD]; /* horizontal shift for heads */
float shac[MAXHD]; /* horizontal shift for accidentals */
struct gch *gch; /* guitar chords / annotations */
struct lyrics *ly; /* lyrics */
signed char doty; /* NOTEREST: y pos of dot when voices overlap
* STBRK: forced
* FMTCHG REPEAT: infos */
};
/* bar types !tied to abcparse.h! */
#define B_SINGLE B_BAR /* | single bar */
#define B_DOUBLE 0x11 /* || thin double bar */
#define B_THIN_THICK 0x13 /* |] thick at section end */
#define B_THICK_THIN 0x21 /* [| thick at section start */
#define B_LREP 0x14 /* |: left repeat bar */
#define B_RREP 0x41 /* :| right repeat bar */
#define B_DREP 0x44 /* :: double repeat bar */
#define B_DASH 0x04 /* : dashed bar */
extern unsigned short *micro_tb; /* ptr to the microtone table of the tune */
struct FORMAT { /* struct for page layout */
float pageheight, pagewidth;
float topmargin, botmargin, leftmargin, rightmargin;
float topspace, wordsspace, titlespace, subtitlespace, partsspace;
float composerspace, musicspace, vocalspace, textspace;
float breaklimit, maxshrink, lineskipfac, parskipfac, stemheight;
float indent, infospace, slurheight, notespacingfactor, scale;
float staffsep, sysstaffsep, maxstaffsep, maxsysstaffsep, stretchlast;
int abc2pscompat, alignbars, aligncomposer, autoclef;
int barsperstaff, breakoneoln, bstemdown, cancelkey;
int combinevoices, contbarnb, continueall, custos;
int dblrepbar, dynalign, flatbeams;
int infoline, gchordbox, graceslurs, gracespace, hyphencont;
int keywarn, landscape, linewarn;
int measurebox, measurefirst, measurenb, micronewps, microscale;
int oneperpage;
#ifdef HAVE_PANGO
int pango;
#endif
int partsbox, pdfmark;
int setdefl, shiftunison, splittune, squarebreve;
int staffnonote, straightflags, stretchstaff;
int textoption, titlecaps, titleleft, titletrim;
int timewarn, transpose, tuplets;
char *bgcolor, *dateformat, *header, *footer, *titleformat;
#define FONT_UMAX 5 /* max number of user fonts */
#define ANNOTATIONFONT 5
#define COMPOSERFONT 6
#define FOOTERFONT 7
#define GCHORDFONT 8
#define HEADERFONT 9
#define HISTORYFONT 10
#define INFOFONT 11
#define MEASUREFONT 12
#define PARTSFONT 13
#define REPEATFONT 14
#define SUBTITLEFONT 15
#define TEMPOFONT 16
#define TEXTFONT 17
#define TITLEFONT 18
#define VOCALFONT 19
#define VOICEFONT 20
#define WORDSFONT 21
#define FONT_DYN 22 /* index of dynamic fonts (gch, an, ly) */
#define FONT_DYNX 12 /* number of dynamic fonts */
#define FONT_MAX (FONT_DYN+FONT_DYNX) /* whole number of fonts */
struct FONTSPEC font_tb[FONT_MAX];
char ndfont; /* current index of dynamic fonts */
unsigned char gcf, anf, vof; /* fonts for guitar chords,
* annotations and lyrics */
unsigned int fields[2]; /* info fields to print
*[0] is 'A'..'Z', [1] is 'a'..'z' */
struct posit_s posit;
};
extern struct FORMAT cfmt; /* current format */
extern struct FORMAT dfmt; /* global format */
typedef struct SYMBOL *INFO[26]; /* information fields ('A' .. 'Z') */
extern INFO info;
extern char *outbuf; /* output buffer.. should hold one tune */
extern char *mbf; /* where to PUTx() */
extern int use_buffer; /* 1 if lines are being accumulated */
extern int outft; /* last font in the output file */
extern int tunenum; /* number of current tune */
extern int pagenum; /* current page number */
extern int nbar; /* current measure number */
extern int in_page;
extern int defl; /* decoration flags */
#define DEF_NOST 0x01 /* long deco with no start */
#define DEF_NOEN 0x02 /* long deco with no end */
#define DEF_STEMUP 0x04 /* stem up (1) or down (0) */
/* switches modified by flags: */
extern int quiet; /* quiet mode */
extern int secure; /* secure mode */
extern int annotate; /* output source references */
extern int pagenumbers; /* write page numbers */
extern int epsf; /* EPSF (1) / SVG (2) output */
extern int svg; /* SVG (1) or XML (2 - HTML + SVG) output */
extern int showerror; /* show the errors */
extern char outfn[FILENAME_MAX]; /* output file name */
extern char *in_fname; /* current input file name */
extern time_t mtime; /* last modification time of the input file */
extern int file_initialized; /* for output file */
extern FILE *fout; /* output file */
#define MAXTBLT 8
struct tblt_s {
char *head; /* PS head function */
char *note; /* PS note function */
char *bar; /* PS bar function */
float wh; /* width of head */
float ha; /* height above the staff */
float hu; /* height under the staff */
short pitch; /* pitch when no associated 'w:' / 0 */
char instr[2]; /* instrument pitch */
};
extern struct tblt_s *tblts[MAXTBLT];
#define MAXCMDTBLT 4 /* max number of -T in command line */
struct cmdtblt_s {
short index; /* tablature number */
short active; /* activate or not */
char *vn; /* voice name */
};
extern struct cmdtblt_s cmdtblts[MAXCMDTBLT];
extern int ncmdtblt;
extern int s_argc; /* command line arguments */
extern char **s_argv;
struct STAFF_S {
struct clef_s clef; /* base clef */
char forced_clef; /* explicit clef */
char empty; /* no symbol on this staff */
short botbar, topbar; /* bottom and top of bar */
float y; /* y position */
float top[YSTEP], bot[YSTEP]; /* top/bottom y offsets */
};
extern struct STAFF_S staff_tb[MAXSTAFF];
extern int nstaff; /* (0..MAXSTAFF-1) */
struct VOICE_S {
struct VOICE_S *next; /* link */
struct SYMBOL *sym; /* associated symbols */
struct SYMBOL *last_sym; /* last symbol while scanning */
struct SYMBOL *lyric_start; /* start of lyrics while scanning */
char id[VOICE_ID_SZ]; /* voice id */
char *nm; /* voice name */
char *snm; /* voice subname */
char *bar_text; /* bar text at start of staff when bar_start */
struct gch *bar_gch; /* bar text */
struct SYMBOL *tie; /* note with ties of previous line */
struct SYMBOL *rtie; /* note with ties before 1st repeat bar */
struct tblt_s *tblts[2]; /* tablatures */
float scale; /* scale */
int time; /* current time (parsing) */
struct clef_s clef; /* current clef */
struct key_s key; /* current key signature */
struct meter_s meter; /* current time signature */
struct key_s ckey; /* key signature while parsing */
struct key_s okey; /* original key signature (parsing) */
unsigned hy_st; /* lyrics hyphens at start of line (bit array) */
unsigned ignore:1; /* ignore this voice (%%staves) */
unsigned forced_clef:1; /* explicit clef */
unsigned second:1; /* secondary voice in a brace/parenthesis */
unsigned floating:1; /* floating voice in a brace system */
unsigned bar_repeat:1; /* bar at start of staff is a repeat bar */
unsigned norepbra:1; /* don't display the repeat brackets */
unsigned have_ly:1; /* some lyrics in this voice */
unsigned new_name:1; /* redisplay the voice name */
unsigned space:1; /* have a space before the next note (parsing) */
unsigned perc:1; /* percussion */
unsigned auto_len:1; /* auto L: (parsing) */
short wmeasure; /* measure duration (parsing) */
short transpose; /* transposition (parsing) */
short bar_start; /* bar type at start of staff / 0 */
struct posit_s posit; /* positions / directions */
signed char octave; /* octave (parsing) */
signed char clone; /* duplicate from this voice number */
signed char over; /* overlay of this voice number */
unsigned char staff; /* staff (0..n-1) */
unsigned char cstaff; /* staff (parsing) */
unsigned char slur_st; /* slurs at start of staff */
};
extern struct VOICE_S voice_tb[MAXVOICE]; /* voice table */
extern struct VOICE_S *first_voice; /* first_voice */
extern struct SYMBOL *tsfirst; /* first symbol in the time linked list */
extern struct SYMBOL *tsnext; /* next line when cut */
extern float realwidth; /* real staff width while generating */
#define NFLAGS_SZ 10 /* size of note flags tables */
#define C_XFLAGS 5 /* index of crotchet in flags tables */
extern float space_tb[NFLAGS_SZ]; /* note spacing */
struct SYSTEM { /* staff system */
struct SYSTEM *next;
short top_voice; /* first voice in the staff system */
short nstaff;
struct {
short flags;
#define OPEN_BRACE 0x01
#define CLOSE_BRACE 0x02
#define OPEN_BRACKET 0x04
#define CLOSE_BRACKET 0x08
#define OPEN_PARENTH 0x10
#define CLOSE_PARENTH 0x20
#define STOP_BAR 0x40
#define FL_VOICE 0x80
#define OPEN_BRACE2 0x0100
#define CLOSE_BRACE2 0x0200
#define OPEN_BRACKET2 0x0400
#define CLOSE_BRACKET2 0x0800
char empty;
char dum;
struct clef_s clef;
float sep, maxsep;
} staff[MAXSTAFF];
struct {
signed char range;
unsigned char staff;
char second;
char dum;
float sep, maxsep;
struct clef_s clef;
} voice[MAXVOICE];
};
struct SYSTEM *cursys; /* current staff system */
/* -- external routines -- */
/* abc2ps.c */
void clrarena(int level);
int lvlarena(int level);
void *getarena(int len);
void strext(char *fid, char *ext);
/* buffer.c */
void a2b(char *fmt, ...)
#ifdef __GNUC__
__attribute__ ((format (printf, 1, 2)))
#endif
;
void block_put(void);
void buffer_eob(void);
void marg_init(void);
void bskip(float h);
void check_buffer(void);
void init_outbuf(int kbsz);
void close_output_file(void);
void close_page(void);
float get_bposy(void);
void write_buffer(void);
int (*output)(FILE *out, const char *fmt, ...)
#ifdef __GNUC__
__attribute__ ((format (printf, 2, 3)))
#endif
;
void write_eps(void);
/* deco.c */
void deco_add(char *text);
void deco_cnv(struct deco *dc, struct SYMBOL *s, struct SYMBOL *prev);
unsigned char deco_intern(unsigned char deco);
unsigned char deco_define(char *name);
void deco_update(struct SYMBOL *s, float dx);
float deco_width(struct SYMBOL *s);
void draw_all_deco(void);
int draw_deco_head(int deco, float x, float y, int stem);
void draw_all_deco_head(struct SYMBOL *s, float x, float y);
void draw_deco_near(void);
void draw_deco_note(void);
void draw_deco_staff(void);
float draw_partempo(int staff, float top);
void draw_measnb(void);
void reset_deco(void);
void set_defl(int new_defl);
float tempo_width(struct SYMBOL *s);
void write_tempo(struct SYMBOL *s,
int beat,
float sc);
float y_get(int staff,
int up,
float x,
float w);
void y_set(int staff,
int up,
float x,
float w,
float y);
/* draw.c */
void draw_sym_near(void);
void draw_all_symb(void);
float draw_systems(float indent);
void output_ps(struct SYMBOL *s, int state);
void putf(float f);
void putx(float x);
void puty(float y);
void putxy(float x, float y);
void set_scale(struct SYMBOL *s);
void set_sscale(int staff);
/* format.c */
void define_fonts(void);
int get_textopt(char *p);
int get_font_encoding(int ft);
void interpret_fmt_line(char *w, char *p, int lock);
void lock_fmt(void *fmt);
void make_font_list(void);
FILE *open_file(char *fn,
char *ext,
char *rfn);
void print_format(void);
void set_font(int ft);
void set_format(void);
void set_voice_param(struct VOICE_S *p_voice, int state, char *w, char *p);
struct tblt_s *tblt_parse(char *p);
/* glyph.c */
char *glyph_out(char *p);
void glyph_add(char *p);
/* music.c */
void output_music(void);
void reset_gen(void);
void unlksym(struct SYMBOL *s);
/* parse.c */
extern float multicol_start;
void do_tune(struct abctune *t);
void identify_note(struct SYMBOL *s,
int len,
int *p_head,
int *p_dots,
int *p_flags);
void sort_pitch(struct SYMBOL *s, int combine);
struct SYMBOL *sym_add(struct VOICE_S *p_voice,
int type);
/* subs.c */
void bug(char *msg, int fatal);
void error(int sev, struct SYMBOL *s, char *fmt, ...);
float scan_u(char *str);
float cwid(unsigned short c);
void get_str_font(int *cft, int *dft);
void set_str_font(int cft, int dft);
#ifdef HAVE_PANGO
void pg_init(void);
void pg_reset_font(void);
#endif
void put_history(void);
void put_words(struct SYMBOL *words);
void str_font(int ft);
#define A_LEFT 0
#define A_CENTER 1
#define A_RIGHT 2
#define A_LYRIC 3
#define A_GCHORD 4
#define A_ANNOT 5
#define A_GCHEXP 6
void str_out(char *p, int action);
void put_str(char *str, int action);
float tex_str(char *s);
extern char tex_buf[]; /* result of tex_str() */
#define TEX_BUF_SZ 512
char *trim_title(char *p, struct SYMBOL *title);
void user_ps_add(char *s, char use);
void user_ps_write(void);
void write_title(struct SYMBOL *s);
void write_heading(struct abctune *t);
void write_user_ps(void);
void write_text(char *cmd, char *s, int job);
/* svg.c */
void define_svg_symbols(char *title, int num, float w, float h);
int svg_output(FILE *out, const char *fmt, ...)
#ifdef __GNUC__
__attribute__ ((format (printf, 2, 3)))
#endif
;
void svg_write(char *buf, int len);
void svg_close();
/* syms.c */
void define_font(char *name, int num, int enc);
void define_symbols(void);
abcm2ps-7.8.9/abcparse.c 0000644 0001750 0001750 00000167101 12360265111 013107 0 ustar jef jef /*
* Generic ABC parser.
*
* Copyright (C) 1998-2014 Jean-François Moine
* Adapted from abc2ps, Copyright (C) 1996, 1997 Michael Methfessel
*
* 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, Suite 500, Boston, MA 02110-1335 USA
*/
#include "config.h"
#include
#include
#include
#include
#include "abcparse.h"
/* interface */
static void *(*alloc_f)(int size);
static void (*free_f)(void *);
static void (*level_f)(int level);
static int client_sz;
static int keep_comment;
/* global values */
char *deco_tb[128]; /* decoration names */
int severity; /* error severity */
static int abc_vers; /* abc version */
static short abc_state; /* parse state */
static short ulen; /* unit note length set by M: or L: */
static short meter; /* upper value of time sig for n-plets */
static unsigned char microscale; /* current microtone scale */
static signed char vover; /* voice overlay (1: single bar, -1: multi-bar */
static char lyric_started; /* lyric started */
static char *gchord; /* guitar chord */
static struct deco dc; /* decorations */
static struct abcsym *deco_start; /* 1st note of the line for d: / s: */
static struct abcsym *deco_cont; /* current symbol when d: / s: continuation */
static unsigned short *p_micro; /* ptr to the microtone table of the tune */
#define VOICE_NAME_SZ 64 /* max size of a voice name */
static char *file; /* remaining abc file */
static int linenum; /* current source line number */
static int colnum; /* current source column number */
static char *abc_line; /* line being parsed */
static struct abcsym *last_sym; /* last symbol for errors */
static short nvoice; /* number of voices (0..n-1) */
static struct { /* voice table and current pointer */
char id[VOICE_ID_SZ]; /* voice ID */
struct abcsym *last_note; /* last note or rest */
short ulen; /* unit note length */
unsigned char microscale; /* microtone scale */
unsigned char mvoice; /* main voice when voice overlay */
} voice_tb[MAXVOICE], *curvoice;
/* char table for note line parsing */
#define CHAR_BAD 0
#define CHAR_IGN 1
#define CHAR_NOTE 2
#define CHAR_REST 3
#define CHAR_ACC 4
#define CHAR_GR_ST 5
#define CHAR_DECO 6
#define CHAR_GCHORD 7
#define CHAR_BSLASH 8
#define CHAR_OBRA 9
#define CHAR_BAR 10
#define CHAR_OPAR 11
#define CHAR_VOV 12
#define CHAR_SPAC 13
#define CHAR_MINUS 14
#define CHAR_CPAR 15
#define CHAR_BRHY 16
#define CHAR_DECOS 17
#define CHAR_SLASH 18
#define CHAR_GR_EN 19
#define CHAR_LINEBREAK 20
static char char_tb[256] = {
0, 0, 0, 0, 0, 0, 0, 0, /* 00 - 07 */
0, CHAR_SPAC, CHAR_LINEBREAK, 0, 0, 0, 0, 0, /* 08 - 0f */
0, 0, 0, 0, 0, 0, 0, 0, /* 10 - 17 */
0, 0, 0, 0, 0, 0, 0, 0, /* 18 - 1f */
CHAR_SPAC, CHAR_DECOS, CHAR_GCHORD, CHAR_BAD, /* (sp) ! " # */
CHAR_BAD, CHAR_BAD, CHAR_VOV, CHAR_BAD, /* $ % & ' */
CHAR_OPAR, CHAR_CPAR, CHAR_BAD, CHAR_DECOS, /* ( ) * + */
CHAR_BAD, CHAR_MINUS, CHAR_DECO, CHAR_SLASH, /* , - . / */
CHAR_BAD, CHAR_BAD, CHAR_BAD, CHAR_BAD, /* 0 1 2 3 */
CHAR_BAD, CHAR_BAD, CHAR_BAD, CHAR_BAD, /* 4 5 6 7 */
CHAR_BAD, CHAR_BAD, CHAR_BAR, CHAR_BAD, /* 8 9 : ; */
CHAR_BRHY, CHAR_ACC, CHAR_BRHY, CHAR_BAD, /* < = > ? */
CHAR_BAD, CHAR_NOTE, CHAR_NOTE, CHAR_NOTE, /* @ A B C */
CHAR_NOTE, CHAR_NOTE, CHAR_NOTE, CHAR_NOTE, /* D E F G */
CHAR_DECO, CHAR_DECO, CHAR_DECO, CHAR_DECO, /* H I J K */
CHAR_DECO, CHAR_DECO, CHAR_DECO, CHAR_DECO, /* L M N O */
CHAR_DECO, CHAR_DECO, CHAR_DECO, CHAR_DECO, /* P Q R S */
CHAR_DECO, CHAR_DECO, CHAR_DECO, CHAR_DECO, /* T U V W */
CHAR_REST, CHAR_DECO, CHAR_REST, CHAR_OBRA, /* X Y Z [ */
CHAR_BSLASH, CHAR_BAR, CHAR_ACC, CHAR_ACC, /* \ ] ^ _ */
CHAR_IGN, CHAR_NOTE, CHAR_NOTE, CHAR_NOTE, /* ` a b c */
CHAR_NOTE, CHAR_NOTE, CHAR_NOTE, CHAR_NOTE, /* d e f g */
CHAR_DECO, CHAR_DECO, CHAR_DECO, CHAR_DECO, /* h i j k */
CHAR_DECO, CHAR_DECO, CHAR_DECO, CHAR_DECO, /* l m n o */
CHAR_DECO, CHAR_DECO, CHAR_DECO, CHAR_DECO, /* p q r s */
CHAR_DECO, CHAR_DECO, CHAR_DECO, CHAR_DECO, /* t u v w */
CHAR_REST, CHAR_REST, CHAR_REST, CHAR_GR_ST, /* x y z { */
CHAR_BAR, CHAR_GR_EN, CHAR_DECO, CHAR_BAD, /* | } ~ (del) */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 80 - 8f */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 90 - 9f */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* a0 - af */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* b0 - bf */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* c0 - cf */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* d0 - df */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* e0 - ef */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* f0 - ff */
};
static const char all_notes[] = "CDEFGABcdefgab";
static char *get_line(void);
static char *parse_len(char *p,
int *p_len);
static char *parse_basic_note(char *p,
int *pitch,
int *length,
int *accidental,
int *stemless);
static int parse_info(struct abctune *t,
char *p,
char *comment);
static char *parse_gchord(char *p);
static int parse_line(struct abctune *t,
char *p);
static char *parse_note(struct abctune *t,
char *p,
int flags);
static void syntax(char *msg, char *q);
static void vover_new(void);
/* -- abcMIDI like errors -- */
static void print_error(char *s, int col)
{
if (col >= 0)
fprintf(stderr, "Error in line %d.%d: %s\n", linenum, col, s);
else
fprintf(stderr, "Error in line %d: %s\n", linenum, s);
}
/* -- delete an ABC symbol -- */
void abc_delete(struct abcsym *as)
{
switch (as->type) {
case ABC_T_INFO:
switch (as->text[0]) {
case 'Q':
if (as->u.tempo.str1)
free_f(as->u.tempo.str1);
if (as->u.tempo.value)
free_f(as->u.tempo.value);
if (as->u.tempo.str2)
free_f(as->u.tempo.str2);
break;
case 'V':
if (as->u.voice.fname)
free_f(as->u.voice.fname);
if (as->u.voice.nname)
free_f(as->u.voice.nname);
break;
}
break;
}
if (as->text)
free_f(as->text);
if (as->comment)
free_f(as->comment);
if (as->prev)
as->prev->next = as->next;
if (as->next)
as->next->prev = as->prev;
if (as->tune->first_sym == as)
as->tune->first_sym = as->next;
if (as->tune->last_sym == as)
as->tune->last_sym = as->prev;
free_f(as);
}
/* -- free the memory areas of all tunes -- */
void abc_free(struct abctune *t)
{
struct abctune *tn;
struct abcsym *s, *sn;
if (!free_f)
return;
for (;;) {
if (!t)
break;
s = t->first_sym;
/* free the associated symbols */
for (;;) {
sn = s->next;
abc_delete(s);
if ((s = sn) == NULL)
break;
}
/* free the tune */
tn = t->next;
free_f(t);
t = tn;
}
}
/* -- initialize the parser -- */
void abc_init(void *alloc_f_api(int size),
void free_f_api(void *ptr),
void level_f_api(int level),
int client_sz_api,
int keep_comment_api)
{
if (alloc_f) {
fprintf(stderr, "abc_init already initialized\n");
return;
}
alloc_f = alloc_f_api;
free_f = free_f_api;
level_f = level_f_api;
client_sz = client_sz_api;
keep_comment = keep_comment_api;
}
/* -- insert an ABC description -- */
void abc_insert(char *file_api,
struct abcsym *s)
{
struct abctune *t;
char *p;
/* initialize */
file = file_api;
if (level_f)
level_f(abc_state != ABC_S_GLOBAL);
abc_state = ABC_S_TUNE;
linenum = 0;
t = s->tune;
t->last_sym = s;
/* scan till end of description */
for (;;) {
if ((p = get_line()) == NULL)
break; /* done */
if (*p == '\0')
break; /* blank line --> done */
/*fixme-insert: don't accept X:*/
/* parse the music line */
if (parse_line(t, p))
break;
}
}
/* -- new symbol -- */
struct abcsym *abc_new(struct abctune *t,
char *text,
char *comment)
{
struct abcsym *s;
s = alloc_f(sizeof *s + client_sz);
memset(s, 0, sizeof *s + client_sz);
s->tune = t;
if (text) {
s->text = alloc_f(strlen(text) + 1);
strcpy(s->text, text);
}
if (comment) {
s->comment = alloc_f(strlen(comment) + 1);
strcpy(s->comment, comment);
}
if (!t->last_sym) {
t->first_sym = s;
} else {
if ((s->next = t->last_sym->next) != NULL)
s->next->prev = s;
t->last_sym->next = s;
s->prev = t->last_sym;
}
last_sym = t->last_sym = s;
s->state = abc_state;
s->linenum = linenum;
s->colnum = colnum;
return s;
}
/* get the ABC version */
static void get_vers(char *p)
{
int i, j,k;
i = j = k = 0;
if (sscanf(p, "%d.%d.%d", &i, &j, &k) != 3)
if (sscanf(p, "%d.%d", &i, &j) != 2)
sscanf(p, "%d", &i);
abc_vers = (i << 16) + (j << 8) + k;
}
/* -- parse an ABC file -- */
struct abctune *abc_parse(char *file_api)
{
struct abctune *first_tune = NULL;
struct abctune *t, *last_tune;
/* saved global variables */
int g_abc_vers, g_ulen, g_microscale;
char *p;
char g_char_tb[128];
/* initialize */
file = file_api;
t = NULL;
abc_state = ABC_S_GLOBAL;
if (level_f)
level_f(0);
linenum = 0;
last_tune = NULL;
g_abc_vers = g_ulen = g_microscale = 0; /* (have gcc happy) */
/* scan till end of file */
for (;;) {
if ((p = get_line()) == NULL) {
if (abc_state == ABC_S_HEAD) {
syntax("Unexpected EOF in header definition",
p);
severity = 1;
}
if (t)
t->abc_vers = abc_vers;
if (abc_state != ABC_S_GLOBAL) {
abc_vers = g_abc_vers;
ulen = g_ulen;
microscale = g_microscale;
memcpy(char_tb, g_char_tb, sizeof g_char_tb);
}
break; /* done */
}
/* start a new tune if not done */
if (!t) {
if (*p == '\0')
continue;
t = alloc_f(sizeof *t);
memset(t, 0 , sizeof *t);
if (!last_tune)
first_tune = t;
else
last_tune->next = t;
last_tune = t;
p_micro = t->micro_tb;
meter = 0;
}
/* parse the music line */
switch (parse_line(t, p)) {
case 2: /* start of tune */
g_abc_vers = abc_vers;
g_ulen = ulen;
g_microscale = microscale;
memcpy(g_char_tb, char_tb, sizeof g_char_tb);
break;
case 1: /* end of tune */
t->abc_vers = abc_vers;
abc_state = ABC_S_GLOBAL;
t = NULL;
abc_vers = g_abc_vers;
ulen = g_ulen;
microscale = g_microscale;
memcpy(char_tb, g_char_tb, sizeof g_char_tb);
if (level_f)
level_f(0);
if (dc.n > 0)
syntax("Decoration without symbol", 0);
dc.n = dc.h = dc.s = 0;
break;
}
}
return first_tune;
}
/* -- cut off after % and remove trailing blanks -- */
static char *decomment_line(char *p)
{
char *q, c, *comment = NULL;
q = p;
for (;;) {
c = *p;
if (c == '\0')
break;
if (c == '\\') {
p++;
if (*p == '\0')
return 0;
p++;
continue;
}
if (c == '%') {
if (keep_comment) {
comment = p + 1;
break;
}
break;
}
if (c == '"') {
for (;;) {
p++;
if (*p == '\0')
break;
if (*p == '"' && p[-1] != '\\') {
p++;
break;
}
}
} else {
p++;
}
}
/* remove the trailing blanks */
while (p > q) {
c = *--p;
if (!isspace((unsigned char) c)) {
p[1] = '\0';
break;
}
}
return comment;
}
/* -- treat the broken rhythm '>' and '<' -- */
static void broken_rhythm(struct note *note,
int num) /* >0: do dot, <0: do half */
{
int l, m, n;
num *= 2;
if (num > 0) {
if (num == 6)
num = 8;
n = num * 2 - 1;
for (m = 0; m <= note->nhd; m++)
note->lens[m] = (note->lens[m] * n) / num;
} else {
n = -num;
if (n == 6)
n = 8;
for (m = 0; m <= note->nhd; m++)
note->lens[m] /= n;
}
l = note->lens[0];
for (m = 1; m <= note->nhd; m++)
if (note->lens[m] < l)
l = note->lens[m];
}
/* -- check for the '!' as end of line (ABC2Win) -- */
static int check_nl(char *p)
{
while (*p != '\0') {
switch (*p++) {
case '!':
return 0;
case '|':
case '[':
case ':':
case ']':
case ' ':
case '\t':
return 1;
}
}
return 1;
}
/* -- parse extra K: or V: definitions (clef, octave and microscale -- */
static char *parse_extra(char *p,
char **p_name,
char **p_middle,
char **p_lines,
char **p_scale,
char **p_octave)
{
for (;;) {
if (strncmp(p, "clef=", 5) == 0
|| strncmp(p, "bass", 4) == 0
|| strncmp(p, "treble", 6) == 0
|| strncmp(p, "alto", 4) == 0
|| strncmp(p, "tenor", 5) == 0
|| strncmp(p, "perc", 4) == 0) {
if (*p_name)
syntax("Double clef name", p);
*p_name = p;
} else if (strncmp(p, "microscale=", 11) == 0) {
int i;
i = atoi(p + 11);
if (i < 4 || i > 256)
syntax("Invalid value in microscale=", p);
else
microscale = i;
} else if (strncmp(p, "middle=", 7) == 0
|| strncmp(p, "m=", 2) == 0) {
if (*p_middle)
syntax("Double clef middle", p);
*p_middle = p + (p[1] == '=' ? 2 : 7);
} else if (strncmp(p, "octave=", 7) == 0) {
if (*p_octave)
syntax("Double octave=", p);
*p_octave = p + 7;
} else if (strncmp(p, "stafflines=", 11) == 0) {
if (*p_lines)
syntax("Double stafflines", p);
*p_lines = p + 11;
} else if (strncmp(p, "staffscale=", 11) == 0) {
if (*p_scale)
syntax("Double staffscale", p);
*p_scale = p + 11;
} else if (strncmp(p, "transpose=", 10) == 0
|| strncmp(p, "t=", 2) == 0) {
; /* ignored */
} else {
break;
}
while (!isspace((unsigned char) *p) && *p != '\0')
p++;
while (isspace((unsigned char) *p))
p++;
if (*p == '\0')
break;
}
return p;
}
/* -- parse a decoration 'xxx' -- */
static char *get_deco(char *p,
unsigned char *p_deco)
{
char *q, sep, **t;
unsigned i, l;
*p_deco = 0;
q = p;
sep = q[-1];
if (char_tb[(unsigned char) sep] == CHAR_DECOS) {
if (sep == '+') {
if (*p == '+' && p[1] == '+')
p++; /* special case "+++" */
}
} else {
sep = '\0'; /* Barfly U: */
}
while (*p != sep) {
if (*p == '\0') {
syntax("Decoration not terminated", q);
return p;
}
p++;
}
l = p - q;
if (*p == sep)
p++;
for (i = 1, t = &deco_tb[1];
*t && i < 128;
i++, t++) {
if (strlen(*t) == l
&& strncmp(*t, q, l) == 0) {
*p_deco = i + 128;
return p;
}
}
/* new decoration */
if (i < 128) {
if (level_f && abc_state != ABC_S_GLOBAL)
level_f(0);
*t = alloc_f(l + 1);
if (level_f && abc_state != ABC_S_GLOBAL)
level_f(1);
memcpy(*t, q, l);
(*t)[l] = '\0';
*p_deco = i + 128;
} else {
syntax("Too many decoration types", q);
}
return p;
}
/* -- parse a list of accidentals (K:) -- */
static char *parse_acc(char *p,
struct abcsym *s)
{
int pit, len, acc, nostem;
unsigned nacc;
if (s->u.key.empty == 2)
syntax("cannot have 'none' and a list of accidentals", p);
nacc = 0;
for (;;) {
if (nacc >= sizeof s->u.key.pits) {
syntax("Too many accidentals", p);
break;
}
p = parse_basic_note(p, &pit, &len, &acc, &nostem);
s->u.key.pits[nacc] = pit;
s->u.key.accs[nacc++] = acc;
while (isspace((unsigned char) *p))
p++;
if (*p == '\0')
break;
if (*p != '^' && *p != '_' && *p != '=')
break;
}
s->u.key.microscale = microscale;
if (s->u.key.empty != 2)
s->u.key.nacc = nacc;
return p;
}
/* -- parse a clef (K: or V:) -- */
static void parse_clef(struct abcsym *s,
char *name,
char *middle,
char *lines,
char *scale)
{
int clef = -1;
int transpose = 0;
int clef_line = 2;
char *warn = NULL;
char str[80];
str[0] = '\0';
if (name && strncmp(name, "clef=", 5) == 0) {
name += 5;
switch (*name) {
case '\"':
name = get_str(str, name, sizeof str);
s->u.clef.name = alloc_f(strlen(str) + 1);
strcpy(s->u.clef.name, str);
clef = TREBLE;
break;
case 'g':
warn = name;
transpose = -7;
case 'G':
clef = TREBLE;
break;
case 'f':
warn = name;
transpose = -14;
clef = BASS;
clef_line = 4;
break;
case 'F':
if (name[1] == ',') /* abc2.1.1 clef=F == clef=F, */
transpose = -7;
clef = BASS;
clef_line = 4;
break;
case 'c':
warn = name;
transpose = -7;
case 'C':
clef = ALTO;
clef_line = 3;
break;
case 'P':
clef = PERC;
break;
}
if (clef >= 0) {
name++;
if (*name == ',' || *name== '\'')
warn = name;
while (*name == ',') {
transpose += 7;
name++;
}
while (*name == '\'') {
transpose -= 7;
name++;
}
}
}
if (name && clef < 0) {
if (!strncmp(name, "bass", 4)) {
clef = BASS;
clef_line = 4;
s->u.clef.check_pitch = 1;
name += 4;
} else if (!strncmp(name, "treble", 6)) {
clef = TREBLE;
name += 6;
} else if (!strncmp(name, "alto", 4)
|| !strncmp(name, "tenor", 5)) {
clef = ALTO;
clef_line = *name == 'a' ? 3 : 4;
s->u.clef.check_pitch = 1;
if (*name == 'a')
name += 4;
else
name += 5;
} else if (!strncmp(name, "perc", 4)) {
clef = PERC;
name += 4;
} else if (strncmp(name, "none", 4) == 0) {
clef = TREBLE;
s->u.clef.invis = 1;
s->flags |= ABC_F_INVIS;
name += 4;
} else {
syntax("Unknown clef", name);
}
}
if (clef >= 0) {
switch (*name) {
case '1':
case '2':
case '3':
case '4':
case '5':
clef_line = *name++ - '0';
break;
}
if (name[1] == '8') {
switch (*name) {
case '^':
transpose -= 7;
case '+':
s->u.clef.octave = 1;
break;
case '_':
transpose += 7;
case '-':
s->u.clef.octave = -1;
break;
}
}
}
if (middle) {
int pit, len, acc, nostem, l;
static const char line_tb[7] =
{ALTO, TREBLE, ALTO, BASS, ALTO, BASS, ALTO};
warn = middle;
/* 'middle=' */
parse_basic_note(middle, &pit, &len, &acc, &nostem);
if (clef < 0)
clef = line_tb[(pit + 7) % 7];
switch (clef) {
default:
l = 20 + 4;
break;
case ALTO:
l = 16 + 4;
break;
case BASS:
l = 12 + 4;
break;
}
clef_line = (l - pit + 28) % 7;
if (clef_line & 1) {
syntax("Bad 'middle' value for the clef", middle);
pit++;
}
clef_line = clef_line / 2 + 1;
transpose = l - (clef_line - 1) * 2 - pit;
s->u.clef.check_pitch = 0;
}
s->u.clef.type = clef;
s->u.clef.line = clef_line;
s->u.clef.transpose = transpose;
s->u.clef.stafflines = -1;
s->u.clef.staffscale = 0;
if (lines) {
int l;
l = atoi(lines);
if ((unsigned) l < 10)
s->u.clef.stafflines = l;
else
syntax("Bad value of stafflines", lines);
}
if (scale) {
float sc;
sc = atof(scale);
if (sc >= 0.5 && sc <= 3)
s->u.clef.staffscale = sc;
else
syntax("Bad value of staffscale", scale);
}
if (warn) {
int sev_sav;
sev_sav = severity;
syntax("Warning: Deprecated or non-standard item", warn);
severity = sev_sav;
}
}
/* get the octave= value */
static int parse_octave(char *p)
{
int oct;
if (p) {
oct = 1;
if (*p == '-') {
oct = -1;
p++;
}
if (*p >= '0' && *p <= '4')
return oct * (*p - '0');
syntax("Bad octave value", p);
}
return NO_OCTAVE;
}
/* -- parse a 'K:' -- */
static void parse_key(char *p,
struct abcsym *s)
{
int sf, mode;
char *clef_name, *clef_middle, *clef_lines, *clef_scale;
char *p_octave;
if (*p == '\0') {
s->u.key.empty = 2;
return;
}
if (strncasecmp(p, "none", 4) == 0) {
s->u.key.empty = 2;
p += 4;
while (isspace((unsigned char) *p))
p++;
if (*p == '\0')
return;
}
clef_name = clef_middle = clef_lines = clef_scale = NULL;
p_octave = NULL;
p = parse_extra(p, &clef_name, &clef_middle, &clef_lines,
&clef_scale, &p_octave);
sf = 0;
mode = MAJOR;
switch (*p++) {
case 'F': sf = -1; break;
case 'B': sf++;
case 'E': sf++;
case 'A': sf++;
case 'D': sf++;
case 'G': sf++;
case 'C': break;
case 'H':
if (*p == 'P') {
mode = BAGPIPE;
p++;
} else if (*p == 'p') {
mode = BAGPIPE + 1;
sf = 2;
p++;
} else {
syntax("Unknown bagpipe-like key", p);
}
break;
case '^':
case '_':
case '=':
p--; /* explicit accidentals */
break;
case '\0':
if (s->u.key.empty == 0)
s->u.key.empty = 1;
p--;
break;
default:
p--;
if (s->u.key.empty != 2)
syntax("Key not recognized", p);
break;
}
if (*p == '#') {
sf += 7;
p++;
} else if (*p == 'b') {
sf -= 7;
p++;
}
while (*p != '\0') {
while (isspace((unsigned char) *p))
p++;
if (*p == '\0')
break;
p = parse_extra(p, &clef_name, &clef_middle, &clef_lines,
&clef_scale, &p_octave);
if (*p == '\0')
break;
switch (*p) {
case 'a':
case 'A':
if (strncasecmp(p, "aeo", 3) == 0) {
sf -= 3;
mode = 5;
break;
}
goto unk;
case 'd':
case 'D':
if (strncasecmp(p, "dor", 3) == 0) {
sf -= 2;
mode = 1;
break;
}
goto unk;
case 'e':
case 'E':
if (strncasecmp(p, "exp", 3) == 0) {
s->u.key.exp = 1;
break;
}
goto unk;
case 'i':
case 'I':
if (strncasecmp(p, "ion", 3) == 0) {
mode = 0;
break;
}
goto unk;
case 'l':
case 'L':
if (strncasecmp(p, "loc", 3) == 0) {
sf -= 5;
mode = 6;
break;
}
if (strncasecmp(p, "lyd", 3) == 0) {
sf += 1;
mode = 3;
break;
}
goto unk;
case 'm':
case 'M':
if (strncasecmp(p, "maj", 3) == 0)
break;
if (strncasecmp(p, "mix", 3) == 0) {
sf -= 1;
mode = 4;
break;
}
if (strncasecmp(p, "min", 3) == 0
|| !isalpha((unsigned char) p[1])) { /* 'm' alone */
sf -= 3;
mode = MINOR;
break;
}
goto unk;
case 'p':
case 'P':
if (strncasecmp(p, "phr", 3) == 0) {
sf -= 4;
mode = 2;
break;
}
goto unk;
case '^':
case '_':
case '=':
p = parse_acc(p, s); /* explicit accidentals */
continue;
default:
unk:
syntax("Unknown token in key specifier", p);
while (!isspace((unsigned char) *p) && *p != '\0')
p++;
continue;
}
while (isalpha((unsigned char) *p))
p++;
}
if (sf > 7 || sf < -7) {
syntax("Too many sharps/flats", p);
if (sf > 0)
sf -= 12;
else
sf += 12;
}
s->u.key.sf = sf;
s->u.key.mode = mode;
s->u.key.octave = parse_octave(p_octave);
if (clef_name || clef_middle || clef_lines || clef_scale) {
s = abc_new(s->tune, NULL, NULL);
s->type = ABC_T_CLEF;
parse_clef(s, clef_name, clef_middle, clef_lines,
clef_scale);
}
}
/* -- set default length from 'L:' -- */
static char *get_len(char *p,
struct abcsym *s)
{
int l1, l2, d;
char *error_txt = NULL;
if (strcmp(p, "auto") == 0) { /* L:auto */
s->u.length.base_length = -1;
return error_txt;
}
l1 = 0;
l2 = 1;
if (sscanf(p, "%d /%d ", &l1, &l2) != 2
|| l1 == 0) {
s->u.length.base_length = ulen ? ulen : BASE_LEN / 8;
return "Bad unit note length: unchanged";
}
if (l2 == 0) {
error_txt = "Bad length divisor, set to 4";
l2 = 4;
}
d = BASE_LEN / l2;
if (d * l2 != BASE_LEN) {
error_txt = "Length incompatible with BASE, using 1/8";
d = BASE_LEN / 8;
} else {
d *= l1;
if (l1 != 1
|| (l2 & (l2 - 1))) {
error_txt = "Incorrect unit note length, using 1/8";
d = BASE_LEN / 8;
}
}
s->u.length.base_length = d;
return error_txt;
}
/* -- get a new line from the current file in memory -- */
static char *get_line(void)
{
int l;
char *p, *q;
p = file;
if (*p == '\0')
return 0;
abc_line = p;
linenum++;
/* handle %%begin .. %%end */
if (strncmp(p, "%%begin", 7) == 0) {
for (;;) {
while (*p != '\0'
&& *p != '\n')
p++;
if (*p == '\0') {
syntax("No %%end after %%begin", 0);
break;
}
linenum++;
p++;
if (strncmp(p, "%%end", 5) == 0) {
p[-1] = '\0';
while (*p != '\0'
&& *p != '\n')
p++;
if (*p != '\0')
*p++ = '\0';
break;
}
}
file = p;
return abc_line;
}
/* set the end of line and
* memorize the beginning of the next line */
while (*p != '\0'
&& *p != '\n')
p++;
if (*p != '\0')
*p++ = '\0';
file = p;
/* special case for continuation lines in ABC version 2.0 */
if (abc_vers == (2 << 16)) {
p = abc_line;
for (;;) {
while (*p != '\0') {
if (*p == '"') {
for (;;) {
p++;
if (*p == '\0')
break;
if (*p == '"' && p[-1] != '\\') {
p++;
break;
}
}
continue;
}
if (*p == '\\'
&& p[1] != '\\'
&& p[1] != '%') {
q = p + 1;
while (isspace((unsigned char) *q))
q++;
if (*q == '\0' || *q == '%')
break;
p = q;
continue;
}
p++;
}
if (*p == '\0')
break;
/* continuation found */
q = file;
if (*q == '\0')
break;
linenum++;
while (*q != '\0'
&& *q != '\n')
q++;
l = q - file;
memmove(p, file, l); /* concatenate */
p[l] = '\0';
if (*q == '\0')
break;
file = q + 1;
}
}
return abc_line;
}
/* -- parse a 'M:' -- */
static char *parse_meter(char *p,
struct abcsym *s)
{
int m1, m2, d, wmeasure, nm, in_parenth;
unsigned i;
char *q;
static char *top_err = "Cannot identify meter top";
if (*p == '\0')
return "Empty meter string";
nm = 0;
in_parenth = 0;
wmeasure = 0;
m1 = 0;
if (strncmp(p, "none", 4) == 0) {
p += 4; /* no meter */
} else while (*p != '\0') {
if (*p == '=')
break;
if (nm >= MAX_MEASURE)
return "Too many values in M:";
switch (*p) {
case 'C':
s->u.meter.meter[nm].top[0] = *p++;
if (*p == '|')
s->u.meter.meter[nm].top[1] = *p++;
m1 = 4;
m2 = 4;
break;
case 'c':
case 'o':
if (*p == 'c')
m1 = 4;
else
m1 = 3;
m2 = 4;
s->u.meter.meter[nm].top[0] = *p++;
if (*p == '.')
s->u.meter.meter[nm].top[1] = *p++;
break;
case '(':
if (p[1] == '(') { /* "M:5/4 ((2+3)/4)" */
in_parenth = 1;
s->u.meter.meter[nm++].top[0] = *p++;
}
q = p + 1;
while (*q != '\0') {
if (*q == ')' || *q == '/')
break;
q++;
}
if (*q == ')' && q[1] == '/') { /* "M:5/4 (2+3)/4" */
p++; /* remove the parenthesis */
continue;
} /* "M:5 (2+3)" */
/* fall thru */
case ')':
in_parenth = *p == '(';
s->u.meter.meter[nm++].top[0] = *p++;
continue;
default:
if (sscanf(p, "%d", &m1) != 1
|| m1 <= 0)
return top_err;
i = 0;
m2 = 2; /* default when no bottom value */
for (;;) {
while (isdigit((unsigned char) *p)
&& i < sizeof s->u.meter.meter[0].top)
s->u.meter.meter[nm].top[i++] = *p++;
if (*p == ')') {
if (p[1] != '/')
break;
p++;
}
if (*p == '/') {
p++;
if (sscanf(p, "%d", &m2) != 1
|| m2 <= 0)
return "Cannot identify meter bottom";
i = 0;
while (isdigit((unsigned char) *p)
&& i < sizeof s->u.meter.meter[0].bot)
s->u.meter.meter[nm].bot[i++] = *p++;
break;
}
if (*p != ' ' && *p != '+')
break;
if (*p == '\0' || p[1] == '(') /* "M:5 (2/4+3/4)" */
break;
if (i < sizeof s->u.meter.meter[0].top)
s->u.meter.meter[nm].top[i++] = *p++;
if (sscanf(p, "%d", &d) != 1
|| d <= 0)
return top_err;
if (p[-1] == ' ') {
if (d > m1)
m1 = d;
} else {
m1 += d;
}
}
break;
}
if (!in_parenth)
wmeasure += m1 * BASE_LEN / m2;
nm++;
if (*p == ' ')
p++;
else if (*p == '+')
s->u.meter.meter[nm++].top[0] = *p++;
}
meter = m1;
if (*p == '=') {
if (sscanf(++p, "%d/%d", &m1, &m2) != 2
|| m1 <= 0
|| m2 <= 0)
return "Cannot identify meter explicit duration";
wmeasure = m1 * BASE_LEN / m2;
s->u.meter.expdur = 1;
}
s->u.meter.wmeasure = wmeasure;
s->u.meter.nmeter = nm;
/* if in the header, change the unit note length */
if (abc_state == ABC_S_HEAD && ulen == 0) {
if (wmeasure >= BASE_LEN * 3 / 4
|| wmeasure == 0)
ulen = BASE_LEN / 8;
else
ulen = BASE_LEN / 16;
}
return 0;
}
/* -- get a possibly quoted string -- */
char *get_str(char *d, /* destination */
char *s, /* source */
int maxlen) /* max length */
{
char c;
maxlen--; /* have place for the EOS */
while (isspace((unsigned char) *s))
s++;
if (*s == '"') {
s++;
while ((c = *s) != '\0') {
if (c == '"') {
s++;
break;
}
if (c == '\\') {
if (--maxlen > 0)
*d++ = c;
c = *++s;
}
if (--maxlen > 0)
*d++ = c;
s++;
}
} else {
while ((c = *s) != '\0') {
if (isspace((unsigned char) c))
break;
if (--maxlen > 0)
*d++ = c;
s++;
}
}
*d = '\0';
while (isspace((unsigned char) *s))
s++;
return s;
}
/* -- parse a tempo (Q:) -- */
static char *parse_tempo(char *p,
struct abcsym *s)
{
int l;
char *q, str[80];
/* string before */
if (*p == '"') {
p = get_str(str, p, sizeof str);
s->u.tempo.str1 = alloc_f(strlen(str) + 1);
strcpy(s->u.tempo.str1, str);
}
/* beat */
if (*p == 'C' || *p == 'c'
|| *p == 'L' || *p == 'l') {
int len;
p++;
if (*p != '=')
goto inval;
p = parse_len(p + 1, &len);
if (len <= 0)
goto inval;
s->u.tempo.length[0] = len * ulen / BASE_LEN;
while (isspace((unsigned char) *p))
p++;
if (abc_vers >= (2 << 16))
syntax("Deprecated Q: value", p);
} else if (isdigit((unsigned char) *p) && strchr(p, '/') != 0) {
unsigned i;
i = 0;
while (isdigit((unsigned char) *p)) {
int top, bot, n;
if (sscanf(p, "%d /%d%n", &top, &bot, &n) != 2
|| bot <= 0)
goto inval;
l = (BASE_LEN * top) / bot;
if (l <= 0
|| i >= sizeof s->u.tempo.length
/ sizeof s->u.tempo.length[0])
goto inval;
s->u.tempo.length[i++] = l;
p += n;
while (isspace((unsigned char) *p))
p++;
}
}
/* tempo value ('Q:beat=value' or 'Q:value') */
if (*p == '=') {
p++;
while (isspace((unsigned char) *p))
p++;
}
if (*p != '\0' && *p != '"') {
q = p;
while (*p != '"' && *p != '\0')
p++;
while (isspace((unsigned char) p[-1]))
p--;
l = p - q;
s->u.tempo.value = alloc_f(l + 1);
strncpy(s->u.tempo.value, q, l);
s->u.tempo.value[l] = '\0';
while (isspace((unsigned char) *p))
p++;
}
/* string after */
if (*p == '"') {
p = get_str(str, p, sizeof str);
s->u.tempo.str2 = alloc_f(strlen(str) + 1);
strcpy(s->u.tempo.str2, str);
}
if (!s->u.tempo.str1 && !s->u.tempo.str2
&& s->u.tempo.length[0] == 0) {
if (s->u.tempo.value == 0)
return "Empty tempo";
if (abc_vers >= (2 << 16))
syntax("Deprecated Q: value", p);
}
return 0;
inval:
return "Invalid tempo";
}
/* -- get a user defined symbol (U:) -- */
static char *get_user(char *p,
struct abcsym *s)
{
unsigned char c;
char *value;
c = (unsigned char) *p++;
if (c == '\\') {
c = (unsigned char) *p++;
switch (c) {
case 'n':
c = '\n';
break;
case 't':
c = '\t';
break;
}
}
switch (char_tb[c]) {
default:
return "Bad decoration character";
case CHAR_DECO:
break;
case CHAR_BAD:
case CHAR_IGN:
case CHAR_SPAC:
case CHAR_DECOS:
case CHAR_LINEBREAK:
char_tb[c] = CHAR_DECO;
break;
}
s->u.user.symbol = c;
/* skip '=' */
while (isspace((unsigned char) *p) || *p == '=')
p++;
if (char_tb[(unsigned char) *p] == CHAR_DECOS)
p++;
/*fixme: 'U: = "text"' is not treated */
get_deco(p, &s->u.user.value);
/* treat special pseudo decorations */
value = deco_tb[s->u.user.value - 128];
if (strcmp(value, "beambreak") == 0)
char_tb[c] = CHAR_SPAC;
else if (strcmp(value, "ignore") == 0)
char_tb[c] = CHAR_IGN;
else if (strcmp(value, "nil") == 0
|| strcmp(value, "none") == 0)
char_tb[c] = CHAR_BAD;
else
return 0;
s->u.user.value = 0; /* not a decoration */
return 0;
}
/* -- parse the voice parameters (V:) -- */
static char *parse_voice(char *p,
struct abcsym *s)
{
int voice;
char *error_txt = NULL;
char name[VOICE_NAME_SZ];
char *clef_name, *clef_middle, *clef_lines, *clef_scale;
char *p_octave;
signed char *p_stem;
static struct kw_s {
char *name;
short len;
short index;
} kw_tb[] = {
{"name=", 5, 0},
{"nm=", 3, 0},
{"subname=", 8, 1},
{"sname=", 6, 1},
{"snm=", 4, 1},
{"merge", 5, 2},
{"up", 2, 3},
{"down", 4, 4},
{"stem=", 5, 5},
{"gstem=", 6, 6},
{"auto", 4, 7},
{"dyn=", 4, 8},
{"lyrics=", 7, 9},
{"scale=", 6, 10},
{"gchord=", 7, 11},
{0}
};
struct kw_s *kw;
/* save the parameters of the previous voice */
curvoice->ulen = ulen;
curvoice->microscale = microscale;
if (voice_tb[0].id[0] == '\0') {
switch (s->prev->type) {
case ABC_T_EOLN:
case ABC_T_NOTE:
case ABC_T_REST:
case ABC_T_BAR:
/* the previous voice was implicit (after K:) */
voice_tb[0].id[0] = '1';
break;
}
}
{
char *id, sep;
id = p;
while (isalnum((unsigned char) *p) || *p == '_')
p++;
sep = *p;
*p = '\0';
if (voice_tb[0].id[0] == '\0') {
voice = 0; /* first voice */
} else {
for (voice = 0; voice <= nvoice; voice++) {
if (strcmp(id, voice_tb[voice].id) == 0)
goto found;
}
if (voice >= MAXVOICE) {
syntax("Too many voices", id);
voice--;
}
}
nvoice = voice;
strncpy(voice_tb[voice].id, id, sizeof voice_tb[voice].id - 1);
voice_tb[voice].mvoice = voice;
found:
strcpy(s->u.voice.id, voice_tb[voice].id);
*p = sep;
}
curvoice = &voice_tb[voice];
s->u.voice.voice = voice;
/* if in tune, set the voice parameters */
if (abc_state == ABC_S_TUNE) {
ulen = curvoice->ulen;
microscale = curvoice->microscale;
}
/* parse the other parameters */
clef_name = clef_middle = clef_lines = clef_scale = NULL;
p_octave = NULL;
p_stem = &s->u.voice.stem;
for (;;) {
while (isspace((unsigned char) *p))
p++;
if (*p == '\0')
break;
p = parse_extra(p, &clef_name, &clef_middle, &clef_lines,
&clef_scale, &p_octave);
if (*p == '\0')
break;
for (kw = kw_tb; kw->name; kw++) {
if (strncmp(p, kw->name, kw->len) == 0)
break;
}
if (!kw->name) {
while (!isspace((unsigned char) *p) && *p != '\0')
p++; /* ignore unknown keywords */
continue;
}
p += kw->len;
switch (kw->index) {
case 0: /* name */
p = get_str(name, p, VOICE_NAME_SZ);
s->u.voice.fname = alloc_f(strlen(name) + 1);
strcpy(s->u.voice.fname, name);
break;
case 1: /* subname */
p = get_str(name, p, VOICE_NAME_SZ);
s->u.voice.nname = alloc_f(strlen(name) + 1);
strcpy(s->u.voice.nname, name);
break;
case 2: /* merge */
s->u.voice.merge = 1;
break;
case 3: /* up */
*p_stem = 1;
break;
case 4: /* down */
*p_stem = -1;
break;
case 5: /* stem= */
p_stem = &s->u.voice.stem;
break;
case 6: /* gstem= */
p_stem = &s->u.voice.gstem;
break;
case 7: /* auto */
*p_stem = 2;
break;
case 8: /* dyn= */
p_stem = &s->u.voice.dyn;
break;
case 9: /* lyrics= */
p_stem = &s->u.voice.lyrics;
break;
case 10: { /* scale= */
float sc;
sc = atof(p);
if (sc >= 0.5 && sc <= 2)
s->u.voice.scale = sc;
else
error_txt = "Bad value for voice scale";
while (!isspace((unsigned char) *p) && *p != '\0')
p++;
break;
}
case 11: /* gchord= */
p_stem = &s->u.voice.gchord;
break;
}
}
s->u.voice.octave = parse_octave(p_octave);
if (clef_name || clef_middle || clef_lines || clef_scale) {
s = abc_new(s->tune, NULL, NULL);
s->type = ABC_T_CLEF;
parse_clef(s, clef_name, clef_middle, clef_lines,
clef_scale);
}
return error_txt;
}
/* -- parse a bar -- */
static char *parse_bar(struct abctune *t,
char *p)
{
struct abcsym *s;
int bar_type;
char repeat_value[32];
p--;
bar_type = 0;
for (;;) {
switch (*p++) {
case '|':
bar_type <<= 4;
bar_type |= B_BAR;
continue;
case '[':
bar_type <<= 4;
bar_type |= B_OBRA;
continue;
case ']':
bar_type <<= 4;
bar_type |= B_CBRA;
continue;
case ':':
bar_type <<= 4;
bar_type |= B_COL;
continue;
default:
break;
}
break;
}
p--;
/* if the last element is '[', it may start
* a chord, an embedded header or an other bar */
if ((bar_type & 0x0f) == B_OBRA && bar_type != B_OBRA
&& *p != ' ') {
bar_type >>= 4;
p--;
}
if (bar_type == (B_OBRA << 8) + (B_BAR << 4) + B_CBRA) /* [|] */
bar_type = (B_OBRA << 4) + B_CBRA; /* [] */
/* curvoice->last_note = NULL; */
if (vover > 0) {
curvoice = &voice_tb[curvoice->mvoice];
vover = 0;
}
s = abc_new(t, gchord, NULL);
if (gchord) {
if (free_f)
free_f(gchord);
gchord = NULL;
}
s->type = ABC_T_BAR;
s->u.bar.type = bar_type;
if (dc.n > 0) {
memcpy(&s->u.bar.dc, &dc, sizeof s->u.bar.dc);
dc.n = dc.h = dc.s = 0;
}
if (!lyric_started) {
lyric_started = 1;
s->flags |= ABC_F_LYRIC_START;
}
if (!isdigit((unsigned char) *p) /* if not a repeat bar */
&& (*p != '"' || p[-1] != '[')) /* ('["' only) */
return p;
if (*p == '"') {
p = get_str(repeat_value, p, sizeof repeat_value);
} else {
char *q;
q = repeat_value;
while (isdigit((unsigned char) *p)
|| *p == ','
|| *p == '-'
|| (*p == '.' && isdigit((unsigned char) p[1]))) {
if (q < &repeat_value[sizeof repeat_value - 1])
*q++ = *p++;
else
p++;
}
*q = '\0';
}
if (bar_type != B_OBRA
|| s->text) {
s = abc_new(t, repeat_value, NULL);
s->type = ABC_T_BAR;
s->u.bar.type = B_OBRA;
} else {
s->text = alloc_f(strlen(repeat_value) + 1);
strcpy(s->text, repeat_value);
}
s->u.bar.repeat_bar = 1;
return p;
}
/* -- parse note or rest with pitch and length -- */
/* in case of error, 'accidental' is set to -1 */
static char *parse_basic_note(char *p,
int *pitch,
int *length,
int *accidental,
int *stemless)
{
int pit, len, acc, nostem;
acc = pit = nostem = 0;
/* look for accidental sign */
switch (*p) {
case '^':
p++;
if (*p == '^') {
p++;
acc = A_DS;
} else {
acc = A_SH;
}
break;
case '=':
p++;
acc = A_NT;
break;
case '_':
p++;
if (*p == '_') {
p++;
acc = A_DF;
} else {
acc = A_FT;
}
break;
}
/* look for microtone value */
if (acc != 0
&& (isdigit((unsigned char) *p)
|| (*p == '/' && microscale == 0))) {
int n, d;
char *q;
n = d = 1;
if (*p != '/') {
n = strtol(p, &q, 10);
p = q;
}
if (*p == '/') {
p++;
if (!isdigit((unsigned char) *p)) {
d = 2;
} else {
d = strtol(p, &q, 10);
p = q;
}
}
if (microscale == 0) {
d--;
d += (n - 1) << 8; /* short [ (n-1) | (d-1) ] */
for (n = 1; n < MAXMICRO; n++) {
if (p_micro[n] == d)
break;
if (p_micro[n] == 0) {
p_micro[n] = d;
break;
}
}
if (n == MAXMICRO) {
syntax("Too many microtone accidentals", p);
n = 0;
}
}
acc += (n << 3);
}
/* get the pitch */
{
char *p_n;
p_n = strchr(all_notes, *p);
if (!p_n) {
syntax(acc ? "Missing note after accidental"
: "Not a note", p);
acc = -1;
if (*p == '\0')
p--;
} else {
pit = p_n - all_notes + 16;
}
p++;
}
while (*p == '\'') { /* eat up following ' chars */
pit += 7;
p++;
}
while (*p == ',') { /* eat up following , chars */
pit -= 7;
p++;
}
if (*p == '0') {
nostem = 1;
p++;
}
p = parse_len(p, &len);
*pitch = pit;
*length = len;
*accidental = acc;
*stemless = nostem;
return p;
}
/* -- parse the decorations of notes and bars -- */
char *parse_deco(char *p,
struct deco *deco)
{
int n;
unsigned char c, d;
n = deco->n;
for (;;) {
c = (unsigned char) *p++;
if (char_tb[c] != CHAR_DECO && char_tb[c] != CHAR_DECOS)
break;
if (char_tb[c] == CHAR_DECOS) {
p = get_deco(p, &d);
c = d;
}
if (n >= MAXDC)
syntax("Too many decorations for the note", p);
else if (c != 0)
deco->t[n++] = c;
}
deco->n = n;
return p - 1;
}
/* -- parse a decoration line (d: or s:) -- */
static char *parse_decoline(char *p)
{
struct abcsym *is;
unsigned char d;
int n;
if ((is = deco_cont) == NULL)
is = deco_start;
else
deco_cont = NULL;
/* scan the decoration line */
while (*p != '\0') {
while (isspace((unsigned char) *p))
p++;
if (*p == '\0')
break;
switch (*p) {
case '|':
while (is && (is->type != ABC_T_BAR
|| is->u.bar.type == B_OBRA))
is = is->next;
if (!is) {
syntax("Not enough bar lines for deco line", p);
return NULL;
}
is = is->next;
p++;
continue;
case '*':
while (is && is->type != ABC_T_NOTE)
is = is->next;
if (!is) {
syntax("Not enough notes for deco line", p);
return NULL;
}
is = is->next;
p++;
continue;
case '\\':
if (p[1] == '\0') {
if (!is)
return "Not enough notes for deco line";
deco_cont = is;
return NULL;
}
syntax("'\\' ignored", p);
p++;
continue;
case '"':
p = parse_gchord(p + 1);
break;
default:
if (char_tb[(unsigned char) *p] == CHAR_DECOS)
p = get_deco(p + 1, &d);
else
d = (unsigned char) *p++;
break;
}
/* store the decoration / gchord/annotation in the next note */
while (is && (is->type != ABC_T_NOTE
|| (is->flags & ABC_F_GRACE)))
is = is->next;
if (!is)
return "Not enough notes for deco line";
if (gchord) {
if (is->text) {
char *gch;
n = strlen(is->text);
gch = alloc_f(n + strlen(gchord) + 2);
strcpy(gch, is->text);
gch[n] = '\n';
strcpy(gch + n + 1, gchord);
if (free_f) {
free_f(gchord);
free_f(is->text);
}
gchord = gch;
}
is->text = gchord;
gchord = NULL;
} else {
n = is->u.note.dc.n;
if (n >= MAXDC) {
syntax("Too many decorations for the note", p);
} else if (d != 0) {
is->u.note.dc.t[n] = d;
is->u.note.dc.n = n + 1;
}
}
is = is->next;
}
return NULL;
}
/* -- parse a guitar chord / annotation -- */
static char *parse_gchord(char *p)
{
char *q;
int l, l2;
q = p;
while (*p != '"') {
if (*p == '\\')
p++;
if (*p == '\0') {
syntax("No end of guitar chord", p);
break;
}
p++;
}
l = p - q;
if (gchord) {
char *gch;
/* many guitar chords: concatenate with '\n' */
l2 = strlen(gchord);
gch = alloc_f(l2 + 1 + l + 1);
strcpy(gch, gchord);
gch[l2++] = '\n';
strncpy(&gch[l2], q, l);
gch[l2 + l] = '\0';
if (free_f)
free_f(gchord);
gchord = gch;
} else {
gchord = alloc_f(l + 1);
strncpy(gchord, q, l);
gchord[l] = '\0';
}
if (*p != '\0')
p++;
return p;
}
/* -- parse a note length -- */
static char *parse_len(char *p,
int *p_len)
{
int len, fac;
char *q;
len = BASE_LEN;
if (isdigit((unsigned char) *p)) {
len *= strtol(p, &q, 10);
if (len <= 0) {
syntax("Bad length", p);
len = BASE_LEN;
}
p = q;
}
fac = 1;
while (*p == '/') {
p++;
if (isdigit((unsigned char) *p)) {
fac *= strtol(p, &q, 10);
if (fac == 0) {
syntax("Bad length divisor", p - 1);
fac = 1;
}
p = q;
} else {
fac *= 2;
}
}
if (len % fac)
syntax("Bad length divisor", p - 1);
len /= fac;
*p_len = len;
return p;
}
/* -- parse a ABC line -- */
/* return 1 on end of tune, and 2 on start of new tune */
static int parse_line(struct abctune *t,
char *p)
{
struct abcsym *s;
char *comment, *q, c;
struct abcsym *last_note_sav = NULL;
struct deco dc_sav;
int i, flags, flags_sav = 0, slur;
static char qtb[10] = {0, 1, 3, 2, 3, 0, 2, 0, 3, 0};
colnum = 0;
switch (*p) {
case '\0': /* blank line */
switch (abc_state) {
case ABC_S_GLOBAL:
case ABC_S_HEAD: /*fixme: may have blank lines in headers?*/
if (keep_comment || abc_state == ABC_S_GLOBAL) {
if (t->last_sym
&& t->last_sym->type != ABC_T_NULL) {
s = abc_new(t, NULL, NULL);
s->type = ABC_T_NULL;
}
}
return 0;
}
return 1;
case '%':
if (p[1] == '@') { /* line number - see front.c */
linenum = atol(p + 2);
if (linenum == 0 && strncmp(file, "%abc-", 5) == 0)
get_vers(file + 5);
return 0;
}
if (p[1] == '%') {
if (strncmp(p + 2, "begin", 5) != 0)
comment = decomment_line(p + 2);
else
comment = NULL;
s = abc_new(t, p, comment);
s->type = ABC_T_PSCOM;
p += 2; /* skip '%%' */
if (strncasecmp(p, "abc-version ", 12) == 0) {
get_vers(p + 12);
return 0;
}
if (strncasecmp(p, "decoration ", 11) == 0) {
p += 11;
while (isspace((unsigned char) *p))
p++;
switch (*p) {
case '!':
char_tb['!'] = CHAR_DECOS;
char_tb['+'] = CHAR_BAD;
break;
case '+':
char_tb['+'] = CHAR_DECOS;
char_tb['!'] = CHAR_BAD;
break;
}
return 0;
}
if (strncasecmp(p, "linebreak ", 10) == 0) {
for (i = 0; i < sizeof char_tb; i++) {
if (char_tb[i] == CHAR_LINEBREAK)
char_tb[i] = i != '!' ?
CHAR_BAD :
CHAR_DECOS;
}
p += 10;
for (;;) {
while (isspace((unsigned char) *p))
p++;
if (*p == '\0')
break;
switch (*p) {
case '!':
case '$':
case '*':
case ';':
case '?':
case '@':
char_tb[(unsigned char) *p++]
= CHAR_LINEBREAK;
break;
case '<':
if (strcmp(p, "") == 0)
return 0;
if (strcmp(p, "") == 0) {
char_tb['\n'] = CHAR_LINEBREAK;
p += 5;
break;
}
/* fall thru */
default:
if (strcmp(p, "lock") != 0)
syntax("Invalid character in %%%%linebreak",
p);
return 0;
}
}
return 0;
}
if (strncasecmp(p, "user ", 5) == 0) {
p += 5;
while (isspace((unsigned char) *p))
p++;
get_user(p, s);
return 0;
}
return 0;
}
/* fall thru */
case '\\': /* abc2mtex specific lines */
if (keep_comment) {
s = abc_new(t, p, NULL);
s->type = ABC_T_NULL;
}
return 0; /* skip */
}
comment = decomment_line(p);
/* header fields */
if (p[1] == ':'
&& *p != '|' && *p != ':') { /* not '|:' nor '::' */
int new_tune;
new_tune = parse_info(t, p, comment);
/* handle BarFly voice definition */
/* 'V:n ' */
if (*p != 'V'
|| abc_state != ABC_S_TUNE)
return new_tune; /* (normal return) */
c = p[strlen(p) - 1];
if (c != '|' && c != ']')
return new_tune;
while (!isspace((unsigned char) *p) && *p != '\0')
p++;
while (isspace((unsigned char) *p))
p++;
}
if (abc_state != ABC_S_TUNE) {
if (keep_comment) {
s = abc_new(t, p, comment);
s->type = ABC_T_NULL;
}
return 0;
}
flags = 0;
if (abc_vers <= (2 << 16))
lyric_started = 0;
deco_start = deco_cont = NULL;
slur = 0;
while (*p != '\0') {
colnum = p - abc_line;
switch (char_tb[(unsigned char) *p++]) {
case CHAR_GCHORD: /* " */
if (flags & ABC_F_GRACE)
goto bad_char;
p = parse_gchord(p);
break;
case CHAR_GR_ST: /* '{' */
if (flags & ABC_F_GRACE)
goto bad_char;
last_note_sav = curvoice->last_note;
curvoice->last_note = NULL;
memcpy(&dc_sav, &dc, sizeof dc);
dc.n = dc.h = dc.s = 0;
flags_sav = flags;
flags = ABC_F_GRACE;
if (*p == '/') {
flags |= ABC_F_SAPPO;
p++;
}
break;
case CHAR_GR_EN: /* '}' */
if (!(flags & ABC_F_GRACE))
goto bad_char;
t->last_sym->flags |= ABC_F_GR_END;
curvoice->last_note = last_note_sav;
memcpy(&dc, &dc_sav, sizeof dc);
flags = flags_sav;
break;
case CHAR_DECOS:
if (p[-1] == '!'
&& char_tb['\n'] == CHAR_LINEBREAK
&& check_nl(p)) {
s = abc_new(t, NULL, NULL); /* abc2win EOL */
s->type = ABC_T_EOLN;
s->u.eoln.type = 2;
break;
}
/* fall thru */
case CHAR_DECO:
if (p[-1] == '.') {
if (*p == '(' || *p == '-' || *p == ')')
break;
if (*p == '|') {
p = parse_bar(t, p + 1);
t->last_sym->u.bar.dotted = 1;
break;
}
}
p = parse_deco(p - 1, &dc);
dc.h = dc.s = dc.n;
break;
case CHAR_LINEBREAK:
s = abc_new(t, NULL, NULL);
s->type = ABC_T_EOLN;
// s->u.eoln.type = 0;
break;
case CHAR_ACC:
case CHAR_NOTE:
case CHAR_REST:
p = parse_note(t, p - 1, flags);
flags &= ABC_F_GRACE;
t->last_sym->u.note.slur_st = slur;
slur = 0;
if (t->last_sym->u.note.lens[0] > 0) /* if not space */
curvoice->last_note = t->last_sym;
break;
case CHAR_SLASH: /* '/' */
if (flags & ABC_F_GRACE)
goto bad_char;
q = p;
while (*q == '/')
q++;
if (char_tb[(unsigned char) *q] != CHAR_BAR)
goto bad_char;
s = abc_new(t, NULL, NULL);
s->type = ABC_T_MREP;
s->u.bar.type = 0;
s->u.bar.len = q - p + 1;
syntax("Non standard measure repeat syntax", p - 1);
p = q;
break;
case CHAR_BSLASH: /* '\\' */
if (*p == '\0')
break;
syntax("'\\' ignored", p - 1);
break;
case CHAR_OBRA: /* '[' */
if (*p == '|' || *p == ']' || *p == ':'
|| isdigit((unsigned char) *p) || *p == '"'
|| *p == ' ') {
if (flags & ABC_F_GRACE)
goto bad_char;
p = parse_bar(t, p);
break;
}
if (p[1] != ':') {
p = parse_note(t, p - 1, flags); /* chord */
flags &= ABC_F_GRACE;
t->last_sym->u.note.slur_st = slur;
slur = 0;
curvoice->last_note = t->last_sym;
break;
}
/* embedded header */
#if 0
/*fixme:OK for [I:staff n], ?? for other headers*/
if (flags & ABC_F_GRACE)
goto bad_char;
#endif
while (p[2] == ' ') { /* remove the spaces */
p[2] = ':';
p[1] = *p;
p++;
}
c = ']';
q = p;
while (*p != '\0' && *p != c)
p++;
if (*p == '\0') {
syntax("Escape sequence [..] not closed", q);
c = '\0';
} else {
*p = '\0';
}
parse_info(t, q, NULL);
*p = c;
if (c != '\0')
p++;
break;
case CHAR_BAR: /* '|', ':' or ']' */
if (flags & ABC_F_GRACE)
goto bad_char;
p = parse_bar(t, p);
break;
case CHAR_OPAR: /* '(' */
if (isdigit((unsigned char) *p)) {
int pplet, qplet, rplet;
pplet = strtol(p, &q, 10);
if (pplet <= 1) {
syntax("Invalid 'p' in tuplet", p);
pplet = 0;
}
p = q;
if ((unsigned) pplet < sizeof qtb / sizeof qtb[0])
qplet = qtb[pplet];
else
qplet = qtb[0];
rplet = pplet;
if (*p == ':') {
p++;
if (isdigit((unsigned char) *p)) {
qplet = strtol(p, &q, 10);
p = q;
}
if (*p == ':') {
p++;
if (isdigit((unsigned char) *p)) {
rplet = strtol(p, &q, 10);
p = q;
}
}
}
if (pplet == 0)
break;
if (rplet < 1) {
syntax("Invalid 'r' in tuplet", p);
break;
}
if (qplet == 0)
qplet = meter % 3 == 0 ? 3 : 2;
s = abc_new(t, NULL, NULL);
s->type = ABC_T_TUPLET;
s->u.tuplet.p_plet = pplet;
s->u.tuplet.q_plet = qplet;
s->u.tuplet.r_plet = rplet;
s->flags |= flags;
break;
}
if (*p == '&') {
if (flags & ABC_F_GRACE)
goto bad_char;
p++;
if (vover != 0) {
syntax("Nested voice overlay", p - 1);
break;
}
s = abc_new(t, NULL, NULL);
s->type = ABC_T_V_OVER;
s->u.v_over.type = V_OVER_S;
s->u.v_over.voice = curvoice - voice_tb;
vover = -1; /* multi-bars */
break;
}
slur <<= 3;
if (p[-2] == '.' && dc.n == 0)
slur |= SL_DOTTED;
switch (*p) {
case '\'':
slur += SL_ABOVE;
p++;
break;
case ',':
slur += SL_BELOW;
p++;
break;
default:
slur += SL_AUTO;
break;
}
break;
case CHAR_CPAR: /* ')' */
switch (t->last_sym->type) {
case ABC_T_NOTE:
case ABC_T_REST:
break;
default:
goto bad_char;
}
t->last_sym->u.note.slur_end++;
break;
case CHAR_VOV: /* '&' */
if (flags & ABC_F_GRACE)
goto bad_char;
if (*p != ')'
|| vover == 0) { /*??*/
if (!curvoice->last_note) {
syntax("Bad start of voice overlay", p);
break;
}
s = abc_new(t, NULL, NULL);
s->type = ABC_T_V_OVER;
/*s->u.v_over.type = V_OVER_V; */
vover_new();
s->u.v_over.voice = curvoice - voice_tb;
if (vover == 0)
vover = 1; /* single bar */
break;
}
p++;
vover = 0;
s = abc_new(t, NULL, NULL);
s->type = ABC_T_V_OVER;
s->u.v_over.type = V_OVER_E;
s->u.v_over.voice = curvoice->mvoice;
curvoice->last_note = NULL; /* ?? */
curvoice = &voice_tb[curvoice->mvoice];
break;
case CHAR_SPAC: /* ' ' and '\t' */
flags |= ABC_F_SPACE;
break;
case CHAR_MINUS: { /* '-' */
int tie_pos;
if (!curvoice->last_note
|| curvoice->last_note->type != ABC_T_NOTE)
goto bad_char;
if (p[-2] == '.' && dc.n == 0)
tie_pos = SL_DOTTED;
else
tie_pos = 0;
switch (*p) {
case '\'':
tie_pos += SL_ABOVE;
p++;
break;
case ',':
tie_pos += SL_BELOW;
p++;
break;
default:
tie_pos += SL_AUTO;
break;
}
for (i = 0; i <= curvoice->last_note->u.note.nhd; i++) {
if (curvoice->last_note->u.note.ti1[i] == 0)
curvoice->last_note->u.note.ti1[i] = tie_pos;
else if (curvoice->last_note->u.note.nhd == 0)
syntax("Too many ties", p);
}
break;
}
case CHAR_BRHY: /* '>' and '<' */
if (!curvoice->last_note)
goto bad_char;
i = 1;
while (*p == p[-1]) {
i++;
p++;
}
if (i > 3) {
syntax("Bad broken rhythm", p - 1);
i = 3;
}
if (p[-1] == '<')
i = -i;
broken_rhythm(&curvoice->last_note->u.note, i);
curvoice->last_note->u.note.brhythm = i;
break;
case CHAR_IGN: /* '*' & '`' */
break;
default:
bad_char:
syntax((flags & ABC_F_GRACE)
? "Bad character in grace note sequence"
: "Bad character",
p - 1);
break;
}
}
/*fixme: may we have grace notes across lines?*/
if (flags & ABC_F_GRACE) {
syntax("EOLN in grace note sequence", p - 1);
if (curvoice->last_note)
curvoice->last_note->flags |= ABC_F_GR_END;
curvoice->last_note = last_note_sav;
memcpy(&dc, &dc_sav, sizeof dc);
}
/* add eoln */
s = abc_new(t, NULL, NULL);
s->type = ABC_T_EOLN;
if (flags & ABC_F_SPACE)
s->flags |= ABC_F_SPACE;
if (p[-1] == '\\'
|| char_tb['\n'] != CHAR_LINEBREAK)
s->u.eoln.type = 1; /* no break */
return 0;
}
/* -- parse a note or a rest -- */
static char *parse_note(struct abctune *t,
char *p,
int flags)
{
struct abcsym *s;
char *q;
int pit, len, acc, nostem, chord, j, m;
if (flags & ABC_F_GRACE) { /* in a grace note sequence */
s = abc_new(t, NULL, NULL);
} else {
s = abc_new(t, gchord, NULL);
if (gchord) {
if (free_f)
free_f(gchord);
gchord = NULL;
}
}
s->type = ABC_T_NOTE;
s->flags |= flags;
if (!lyric_started) {
lyric_started = 1;
s->flags |= ABC_F_LYRIC_START;
}
if (*p != 'X' && *p != 'Z'
&& !(flags & ABC_F_GRACE)) {
if (!deco_start)
deco_start = s;
}
/* rest */
switch (*p) {
case 'X':
case 'Z': /* multi-rest */
s->type = ABC_T_MREST;
if (*p == 'X')
s->flags |= ABC_F_INVIS;
p++;
len = 1;
if (isdigit((unsigned char) *p)) {
len = strtol(p, &q, 10);
if (len == 0 && len > 100) {
syntax("Bad number of measures", p);
len = 1;
}
p = q;
}
s->u.bar.type = 0;
s->u.bar.len = len;
goto add_deco;
case 'y': /* space (BarFly) */
s->type = ABC_T_REST;
s->flags |= ABC_F_INVIS;
p++;
if (isdigit((unsigned char) *p)) { /* number of points */
s->u.note.lens[1] = strtol(p, &q, 10);
p = q;
} else {
s->u.note.lens[1] = -1;
}
goto add_deco;
case 'x': /* invisible rest */
s->flags |= ABC_F_INVIS;
/* fall thru */
case 'z':
s->type = ABC_T_REST;
p = parse_len(p + 1, &len);
s->u.note.lens[0] = len * ulen / BASE_LEN;
goto do_brhythm;
}
chord = 0;
q = p;
if (*p == '[') { /* '[..]' = chord */
chord = 1;
p++;
}
/* get pitch, length and possible accidental */
m = 0;
nostem = 0;
for (;;) {
int tmp;
if (chord) {
if (m >= MAXHD) {
syntax("Too many notes in chord", p);
m--;
}
tmp = 0;
if (*p == '.') {
tmp = SL_DOTTED;
p++;
}
if (*p == '(') {
p++;
switch (*p) {
case '\'':
tmp += SL_ABOVE;
p++;
break;
case ',':
tmp += SL_BELOW;
p++;
break;
default:
tmp += SL_AUTO;
break;
}
s->u.note.sl1[m] = (s->u.note.sl1[m] << 3)
+ tmp;
}
}
tmp = dc.n;
p = parse_deco(p, &dc); /* note head decorations */
if (dc.n != tmp) {
if (dc.n - tmp >= 8) {
syntax("Too many decorations on this head", p);
tmp = dc.n - 7;
}
s->u.note.decs[m] = (tmp << 3) + dc.n - tmp;
dc.s = dc.n;
}
p = parse_basic_note(p, &pit, &len, &acc, &tmp);
if (!(flags & ABC_F_GRACE))
len = len * ulen / BASE_LEN;
else
len /= 8; /* for grace note alone */
s->u.note.pits[m] = pit;
s->u.note.lens[m] = len;
s->u.note.accs[m] = acc;
nostem |= tmp;
if (chord) {
for (;;) {
if (*p == '.') {
if (p[1] != '-')
break;
p++;
}
if (*p == '-') {
switch (p[1]) {
case '\'':
s->u.note.ti1[m] = SL_ABOVE;
p++;
break;
case ',':
s->u.note.ti1[m] = SL_BELOW;
p++;
break;
default:
s->u.note.ti1[m] = SL_AUTO;
break;
}
} else if (*p == ')') {
s->u.note.sl2[m]++;
} else {
break;
}
p++;
}
}
if (acc >= 0) /* if no error */
m++; /* normal case */
if (!chord)
break;
if (*p == ']') {
p++;
if (*p == '0') {
nostem |= 1;
p++;
}
if (*p == '/' || isdigit((unsigned char) *p)) {
p = parse_len(p, &len);
s->u.note.chlen = len;
for (j = 0; j < m; j++) {
tmp = len * s->u.note.lens[j];
s->u.note.lens[j] = tmp / BASE_LEN;
}
}
break;
}
if (*p == '\0') {
syntax("Chord not closed", q);
break;
}
}
if (nostem)
s->flags |= ABC_F_STEMLESS;
if (m == 0) /* if no note (or error) */
goto err;
s->u.note.microscale = microscale;
s->u.note.nhd = m - 1;
do_brhythm:
if (curvoice->last_note
&& curvoice->last_note->u.note.brhythm != 0)
broken_rhythm(&s->u.note,
-curvoice->last_note->u.note.brhythm);
add_deco:
if (dc.n > 0) {
memcpy(s->type != ABC_T_MREST ? &s->u.note.dc
: &s->u.bar.dc,
&dc, sizeof dc);
dc.n = dc.h = dc.s = 0;
}
/* forbid rests in grace note sequences */
if (s->type != ABC_T_NOTE && (flags & ABC_F_GRACE)) {
syntax("Not a note in grace note sequence", p);
goto err;
}
return p;
err:
if ((t->last_sym = s->prev) == NULL) {
t->first_sym = NULL;
} else {
s->prev->next = NULL;
s->prev->flags |= (s->flags & ABC_F_ERROR);
}
return p;
}
/* -- parse an information field -- */
/* return 2 on start of new tune */
static int parse_info(struct abctune *t,
char *p,
char *comment)
{
struct abcsym *s;
char info_type = *p;
char *error_txt = NULL;
s = abc_new(t, p, comment);
s->type = ABC_T_INFO;
p += 2;
switch (info_type) {
case 'd':
case 's':
if (abc_state == ABC_S_GLOBAL)
break;
if (!deco_start) {
error_txt = "Erroneous 'd:'/'s:'";
break;
}
error_txt = parse_decoline(p);
break;
case 'K':
if (abc_state == ABC_S_GLOBAL)
break;
parse_key(p, s);
if (abc_state == ABC_S_HEAD) {
int i;
abc_state = ABC_S_TUNE;
if (ulen == 0)
ulen = BASE_LEN / 8;
for (i = MAXVOICE; --i >= 0; )
voice_tb[i].ulen = ulen;
lyric_started = 0;
}
break;
case 'L':
error_txt = get_len(p, s);
if (s->u.length.base_length > 0)
ulen = s->u.length.base_length;
break;
case 'M':
error_txt = parse_meter(p, s);
break;
case 'Q':
error_txt = parse_tempo(p, s);
break;
case 'U':
error_txt = get_user(p, s);
break;
case 'V':
if (abc_state == ABC_S_GLOBAL)
break;
error_txt = parse_voice(p, s);
break;
case 'X':
memset(voice_tb, 0, sizeof voice_tb);
nvoice = 0;
curvoice = &voice_tb[0];
abc_state = ABC_S_HEAD;
if (level_f)
level_f(1);
return 2;
}
if (error_txt)
syntax(error_txt, p);
return 0;
}
/* -- print a syntax error message -- */
static void syntax(char *msg,
char *q)
{
int n, len, m1, m2, pp;
int maxcol = 73;
severity = 1;
n = q - abc_line;
len = strlen(abc_line);
if ((unsigned) n > (unsigned) len)
n = -1;
print_error(msg, n);
if (n < 0) {
if (q && *q != '\0')
fprintf(stderr, " (near '%s')\n", q);
return;
}
m1 = 0;
m2 = len;
if (m2 > maxcol) {
if (n < maxcol) {
m2 = maxcol;
} else {
m1 = n - 20;
m2 = m1 + maxcol;
if (m2 > len)
m2 = len;
}
}
fprintf(stderr, "%4d ", linenum);
pp = 6;
if (m1 > 0) {
fprintf(stderr, "...");
pp += 3;
}
fprintf(stderr, "%.*s", m2 - m1, &abc_line[m1]);
if (m2 < len)
fprintf(stderr, "...");
fprintf(stderr, "\n");
if ((unsigned) n < 200)
fprintf(stderr, "%*s\n", n + pp - m1, "^");
if (last_sym)
last_sym->flags |= ABC_F_ERROR;
}
/* -- switch to a new voice overlay -- */
static void vover_new(void)
{
int voice, mvoice;
mvoice = curvoice->mvoice;
for (voice = curvoice - voice_tb + 1; voice <= nvoice; voice++)
if (voice_tb[voice].mvoice == mvoice)
break;
if (voice > nvoice) {
if (nvoice >= MAXVOICE) {
syntax("Too many voices", 0);
return;
}
nvoice = voice;
voice_tb[voice].id[0] = '&';
voice_tb[voice].mvoice = mvoice;
}
voice_tb[voice].ulen = curvoice->ulen;
voice_tb[voice].microscale = curvoice->microscale;
curvoice = &voice_tb[voice];
}
abcm2ps-7.8.9/abcparse.h 0000644 0001750 0001750 00000016571 12314503216 013120 0 ustar jef jef /*++
* Declarations for abcparse.c.
*
*-*/
#define MAXVOICE 32 /* max number of voices */
#define MAXHD 8 /* max heads in a chord */
#define MAXDC 45 /* max decorations per note/chord/bar */
#define MAXMICRO 32 /* max microtone values (5 bits in accs[]) */
#define BASE_LEN 1536 /* basic note length (semibreve or whole note - same as MIDI) */
#define VOICE_ID_SZ 16 /* max size of the voice identifiers */
/* accidentals */
enum accidentals {
A_NULL, /* none */
A_SH, /* sharp */
A_NT, /* natural */
A_FT, /* flat */
A_DS, /* double sharp */
A_DF /* double flat */
};
/* bar types - 4 bits per symbol */
#define B_BAR 1 /* | */
#define B_OBRA 2 /* [ */
#define B_CBRA 3 /* ] */
#define B_COL 4 /* : */
/* slur/tie types (3 bits) */
#define SL_ABOVE 0x01
#define SL_BELOW 0x02
#define SL_AUTO 0x03
#define SL_DOTTED 0x04 /* (modifier bit) */
/* note structure */
struct deco { /* decorations */
char n; /* whole number of decorations */
char h; /* start of head decorations */
char s; /* start of decorations from s: (d:) */
unsigned char t[MAXDC]; /* decoration type */
};
struct note { /* note or rest */
signed char pits[MAXHD]; /* pitches */
short lens[MAXHD]; /* note lengths (# pts in [1] if space) */
unsigned char accs[MAXHD]; /* code for accidentals & index in micro_tb */
unsigned char sl1[MAXHD]; /* slur start per head */
char sl2[MAXHD]; /* number of slur end per head */
char ti1[MAXHD]; /* flag to start tie here */
unsigned char decs[MAXHD]; /* head decorations (index: 5 bits, len: 3 bits) */
short chlen; /* chord length */
char nhd; /* number of notes in chord - 1 */
unsigned char slur_st; /* slurs starting here (2 bits array) */
char slur_end; /* number of slurs ending here */
signed char brhythm; /* broken rhythm */
unsigned char microscale; /* microtone denominator - 1 */
struct deco dc; /* decorations */
};
/* symbol definition */
struct abctune;
struct abcsym {
struct abctune *tune; /* tune */
struct abcsym *next, *prev; /* next / previous symbol */
char type; /* symbol type */
#define ABC_T_NULL 0
#define ABC_T_INFO 1 /* (text[0] gives the info type) */
#define ABC_T_PSCOM 2
#define ABC_T_CLEF 3
#define ABC_T_NOTE 4
#define ABC_T_REST 5
#define ABC_T_BAR 6
#define ABC_T_EOLN 7
#define ABC_T_MREST 8 /* multi-measure rest */
#define ABC_T_MREP 9 /* measure repeat */
#define ABC_T_V_OVER 10 /* voice overlay */
#define ABC_T_TUPLET 11
char state; /* symbol state in file/tune */
#define ABC_S_GLOBAL 0 /* global */
#define ABC_S_HEAD 1 /* in header (after X:) */
#define ABC_S_TUNE 2 /* in tune (after K:) */
unsigned short flags;
#define ABC_F_ERROR 0x0001 /* error around this symbol */
#define ABC_F_INVIS 0x0002 /* invisible symbol */
#define ABC_F_SPACE 0x0004 /* space before a note */
#define ABC_F_STEMLESS 0x0008 /* note with no stem */
#define ABC_F_LYRIC_START 0x0010 /* may start a lyric here */
#define ABC_F_GRACE 0x0020 /* grace note */
#define ABC_F_GR_END 0x0040 /* end of grace note sequence */
#define ABC_F_SAPPO 0x0080 /* short appoggiatura */
unsigned short colnum; /* ABC source column number */
int linenum; /* ABC source line number */
char *fn; /* ABC source file name */
char *text; /* main text (INFO, PSCOM),
* guitar chord (NOTE, REST, BAR) */
char *comment; /* comment part (when keep_comment) */
union { /* type dependent part */
struct key_s { /* K: info */
signed char sf; /* sharp (> 0) flats (< 0) */
char empty; /* clef alone if 1, 'none' if 2 */
char exp; /* exp (1) or mod (0) */
char mode; /* mode */
/* 0: Ionian, 1: Dorian, 2: Phrygian, 3: Lydian, 4: Mixolydian
* 5: Aeolian, 6: Locrian, 7: major, 8:minor, 9: HP, 10: Hp */
#define MAJOR 7
#define MINOR 8
#define BAGPIPE 9 /* bagpipe when >= 8 */
signed char nacc; /* number of explicit accidentals */
/* (-1) if no accidental */
signed char octave; /* 'octave=' */
#define NO_OCTAVE 10 /* no 'octave=' */
unsigned char microscale; /* microtone denominator - 1 */
signed char pits[8];
unsigned char accs[8];
} key;
struct { /* L: info */
int base_length; /* basic note length */
} length;
struct meter_s { /* M: info */
short wmeasure; /* duration of a measure */
unsigned char nmeter; /* number of meter elements */
char expdur; /* explicit measure duration */
#define MAX_MEASURE 6
struct {
char top[8]; /* top value */
char bot[2]; /* bottom value */
} meter[MAX_MEASURE];
} meter;
struct { /* Q: info */
char *str1; /* string before */
short length[4]; /* up to 4 note lengths */
char *value; /* tempo value */
char *str2; /* string after */
} tempo;
struct { /* V: info */
char id[VOICE_ID_SZ]; /* voice ID */
char *fname; /* full name */
char *nname; /* nick name */
float scale; /* != 0 when change */
unsigned char voice; /* voice number */
signed char octave; /* 'octave=' - same as in K: */
char merge; /* merge with previous voice */
signed char stem; /* have stems up or down (2 = auto) */
signed char gstem; /* have grace stems up or down (2 = auto) */
signed char dyn; /* have dynamic marks above or below the staff */
signed char lyrics; /* have lyrics above or below the staff */
signed char gchord; /* have gchord above or below the staff */
} voice;
struct { /* bar, mrest or mrep */
int type;
char repeat_bar;
char len; /* len if mrest or mrep */
char dotted;
struct deco dc; /* decorations */
} bar;
struct clef_s { /* clef (and staff!) */
char *name; /* PS drawing function */
float staffscale; /* != 0 when change */
signed char stafflines; /* >= 0 when change */
signed char type; /* no clef if < 0 */
#define TREBLE 0
#define ALTO 1
#define BASS 2
#define PERC 3
char line;
signed char octave;
signed char transpose;
char invis;
char check_pitch; /* check if old abc2ps transposition */
} clef;
struct note note; /* note, rest */
struct { /* user defined accent */
unsigned char symbol;
unsigned char value;
} user;
struct {
char type; /* 0: end of line
* 1: continuation ('\')
* 2: line break ('!') */
} eoln;
struct { /* voice overlay */
char type;
#define V_OVER_V 0 /* & */
#define V_OVER_S 1 /* (& */
#define V_OVER_E 2 /* &) */
unsigned char voice;
} v_over;
struct { /* tuplet */
char p_plet, q_plet, r_plet;
} tuplet;
} u;
};
/* tune definition */
struct abctune {
struct abctune *next; /* next tune */
struct abcsym *first_sym; /* first symbol */
struct abcsym *last_sym; /* last symbol */
int abc_vers; /* ABC version = (H << 16) + (M << 8) + L */
void *client_data; /* client data */
unsigned short micro_tb[MAXMICRO]; /* microtone values [ (n-1) | (d-1) ] */
};
#ifdef WIN32
#define strcasecmp stricmp
#define strncasecmp strnicmp
#endif
#if defined(__cplusplus)
extern "C" {
#endif
extern char *deco_tb[];
extern int severity;
void abc_delete(struct abcsym *as);
void abc_free(struct abctune *first_tune);
void abc_init(void *alloc_f_api(int size),
void free_f_api(void *ptr),
void level_f_api(int level),
int client_sz_api,
int keep_comment_api);
void abc_insert(char *file_api,
struct abcsym *s);
struct abcsym *abc_new(struct abctune *t,
char *p,
char *comment);
struct abctune *abc_parse(char *file_api);
char *get_str(char *d,
char *s,
int maxlen);
char *parse_deco(char *p,
struct deco *deco);
#if defined(__cplusplus)
}
#endif
abcm2ps-7.8.9/accordion.abc 0000644 0001750 0001750 00000004451 11654555736 013615 0 ustar jef jef % tablature examples
% --- diatonic accordion
%%beginps
% length x y n accordh - accordion tablature header with 2 or 3 lines
/accordh{
% /Times-Roman 14 selectfont
/nlines exch def
.8 SLW
gsave 20 add T /w exch def
0 0 M w 0 RL
0 3 M w 0 RL
0 21 M w 0 RL
0 39 M w 0 RL
nlines 2 eq{
0 42 M w 0 RL
stroke
/barh 42 def
3 7 M (T:) show
3 25 M (P:) show
}{
0 57 M w 0 RL
0 60 M w 0 RL
stroke
/barh 60 def
3 7 M (B/a:) show
3 25 M (T:) show
3 43 M (P:) show
}ifelse
grestore
}!
% string x y n accordn - accordion tablature
/accordn{
-18 mul add barh add 3 add M showc
}!
/accordb{
0 eq{20 add M 0 barh RL stroke}
{pop pop}ifelse pop}!
%%endps
X:3
T:Andro à Patrice Corbel
N: validé 03/05/01 -- 04/08/02
R:Andro
O:Bretagne
M:4/4
K:Am
%%tablature 70 accordh accordn accordb
"A"A2 cA "F" aAce | "G"dGBd "C"e4 | "F"fedc "G"B2 AB |1 "F"cABc "E"B4 :|2 "F"cABc "A"A4 :|\
w: * * * * * * * 8 6 7 8 7' * * * * * * * * * * * 7 * * * * *
w: 7 8 7 11 7 8 9 * * * * * 8' 9 7' 8 6' 7 6' 8 7 6' 8 * 8 7 6' 8 7
"A"A2 GF "E"E3 B | "E"c2 d2 "C"e4 | "F"fedc "G"B2 AB |1 "F"cABc "E"B4 :|2 "F"cABc "A"A4 :|
w: * 6 * 4' 7 6' 8 7' * * * * * * * * * * * 7 * * * * *
w: 7 * 4' * * * * * 8' 9 7' 8 6' 7 6' 8 7 6' 8 * 8 7 6' 8 7
X:51
T:Jeune fille de quinze ans (50-51-52)
T:Une fille de rose
N: rev. 01/06/01
R:hanter dro
C:trad
A:Bretagne
O:France
M:3/4
L:1/8
Q:100
K:Am
%%tablature 90 accordh accordn accordb
|: "Am" ee/f/ "Am" ed "Am" c2 | "Am" ed/c/ "G" Bd "Am" cA | "Am" ee/f/ "Am" ed "Am" c2 |1 "Am" ed/c/ "G" BG "Em" E2 :|2 "Am" ed/c/ "G" BG "Am" A2 |
w: * * * * * * | * * * 7 8 * * | * * * * * * | * * * 7 6 4'| * * * 7 6 *
w: 9 9 8' 9 7' 8 | 9 7' 8 * * 8 7 | 9 9 8' 9 7' 8 | 9 7' 8 * * * | 9 7' 8 * * 7
w: A a * A a A~~a | A a * G g E e | A a * A a A~~a | A a * G g E~~e | A a * G g E~~e |
|: "Am" AA/B/ "Am" cd "C" e2 | "G" de/f/ "F" af "Am" e2 | "Am" cd/e/ "F" fe "G" d2 |1 "G" Bc/d/ "Em" cB "Em" cB :|2 "G" Bc/d/ "Em" cB "Am" A2 ||
w: * * * * * 7' | 8 7' * * * * | * * * * * 8 | 7 6' 8 6' 7 6' 7 | 7 6' 8 6' 7 *
w: 7 7 6' 8 7' * | * * 8' 9' 8' 9 | 8 7' 9 8' 9 * | * * * * * * * | * * * * * 7
w: A a * A a C~c | G g * F f A~a | A a * F f G~g | G g * E e E e | G g * E e A~a |
abcm2ps-7.8.9/build.ninja 0000644 0001750 0001750 00000005774 12417252362 013321 0 ustar jef jef # rules for ninja (ninja-build)
VERSION = 7.8.9
cflags = -g -O2 -Wall -pipe -DHAVE_CONFIG_H -I.
#cflags = -g -Wall -pipe -DHAVE_CONFIG_H -I.
ldflags = -lm
rule cc
# command = gcc $cflags -c $in -o $out
command = clang $cflags -c $in -o $out
# -mcpu=iwmmxt
# -mcpu=iwmmxt2
# -mthumb -march=armv7-a
rule ld
# command = cc $ldflags -o $out $in
command = clang $ldflags -o $out $in
build abc2ps.o: cc abc2ps.c | config.h abcparse.h abc2ps.h front.h
build abcparse.o: cc abcparse.c | config.h abcparse.h
build buffer.o: cc buffer.c | config.h abcparse.h abc2ps.h
build deco.o: cc deco.c | config.h abcparse.h abc2ps.h
build draw.o: cc draw.c | config.h abcparse.h abc2ps.h
build format.o: cc format.c | config.h abcparse.h abc2ps.h
build front.o: cc front.c | config.h abcparse.h abc2ps.h front.h slre.h
build glyph.o: cc glyph.c | config.h abcparse.h abc2ps.h
build music.o: cc music.c | config.h abcparse.h abc2ps.h
build parse.o: cc parse.c | config.h abcparse.h abc2ps.h
build slre.o: cc slre.c | slre.h
build subs.o: cc subs.c | config.h abcparse.h abc2ps.h
build svg.o: cc svg.c | config.h abcparse.h abc2ps.h
build syms.o: cc syms.c | config.h abcparse.h abc2ps.h
build abcm2ps: ld abc2ps.o abcparse.o buffer.o deco.o draw.o format.o front.o $
glyph.o music.o parse.o slre.o subs.o svg.o syms.o
default abcm2ps
rule dist_tar
command = ln -s . abcm2ps-$VERSION; $
tar -zcvf $out $
abcm2ps-$VERSION/Changes $
abcm2ps-$VERSION/INSTALL $
abcm2ps-$VERSION/License $
abcm2ps-$VERSION/Makefile $
abcm2ps-$VERSION/Makefile.in $
abcm2ps-$VERSION/README $
abcm2ps-$VERSION/abc2ps.c $
abcm2ps-$VERSION/abc2ps.h $
abcm2ps-$VERSION/abcparse.c $
abcm2ps-$VERSION/abcparse.h $
abcm2ps-$VERSION/accordion.abc $
abcm2ps-$VERSION/build.ninja $
abcm2ps-$VERSION/buffer.c $
abcm2ps-$VERSION/chinese.abc $
abcm2ps-$VERSION/configure $
abcm2ps-$VERSION/configure.in $
abcm2ps-$VERSION/config.h $
abcm2ps-$VERSION/config.h.in $
abcm2ps-$VERSION/config.guess $
abcm2ps-$VERSION/config.sub $
abcm2ps-$VERSION/deco.c $
abcm2ps-$VERSION/deco.abc $
abcm2ps-$VERSION/draw.c $
abcm2ps-$VERSION/features.txt $
abcm2ps-$VERSION/flute.fmt $
abcm2ps-$VERSION/format.c $
abcm2ps-$VERSION/format.txt $
abcm2ps-$VERSION/front.c $
abcm2ps-$VERSION/front.h $
abcm2ps-$VERSION/glyph.c $
abcm2ps-$VERSION/install.sh $
abcm2ps-$VERSION/landscape.fmt $
abcm2ps-$VERSION/music.c $
abcm2ps-$VERSION/musicfont.fmt $
abcm2ps-$VERSION/newfeatures.abc $
abcm2ps-$VERSION/options.txt $
abcm2ps-$VERSION/parse.c $
abcm2ps-$VERSION/sample.abc $
abcm2ps-$VERSION/sample2.abc $
abcm2ps-$VERSION/sample3.abc $
abcm2ps-$VERSION/sample3.eps $
abcm2ps-$VERSION/sample4.abc $
abcm2ps-$VERSION/sample5.abc $
abcm2ps-$VERSION/slre.c $
abcm2ps-$VERSION/slre.h $
abcm2ps-$VERSION/subs.c $
abcm2ps-$VERSION/svg.c $
abcm2ps-$VERSION/syms.c $
abcm2ps-$VERSION/tight.fmt $
abcm2ps-$VERSION/voices.abc;$
rm abcm2ps-$VERSION
build abcm2ps-$VERSION.tar.gz: dist_tar
build dist: phony abcm2ps-$VERSION.tar.gz
abcm2ps-7.8.9/buffer.c 0000644 0001750 0001750 00000052414 12355567026 012616 0 ustar jef jef /*
* Postscript buffering functions.
*
* This file is part of abcm2ps.
*
* Copyright (C) 1998-2014 Jean-François Moine
* Adapted from abc2ps, Copyright (C) 1996,1997 Michael Methfessel
*
* 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, Suite 500, Boston, MA 02110-1335 USA
*/
#include
#include
#include
#include
#ifdef WIN32
#define snprintf _snprintf
#endif
#include "abc2ps.h"
#define BUFFLN 80 /* max number of lines in output buffer */
static int ln_num; /* number of lines in buffer */
static float ln_pos[BUFFLN]; /* vertical positions of buffered lines */
static char *ln_buf[BUFFLN]; /* buffer location of buffered lines */
static float ln_lmarg[BUFFLN]; /* left margin of buffered lines */
static float ln_scale[BUFFLN]; /* scale of buffered lines */
static signed char ln_font[BUFFLN]; /* font of buffered lines */
static float cur_lmarg = 0; /* current left margin */
static float min_lmarg, max_rmarg; /* margins for -E/-g */
static float cur_scale = 1.0; /* current scale */
static float maxy; /* remaining vertical space in page */
static float bposy; /* current position in buffered data */
static int nepsf; /* counter for -E/-g output files */
static int nbpages; /* number of pages in the output file */
static int outbufsz; /* size of outbuf */
static char outfnam[FILENAME_MAX]; /* internal file name for open/close */
static struct FORMAT *p_fmt; /* current format while treating a new page */
int (*output)(FILE *out, const char *fmt, ...);
int in_page; /* filling a PostScript page */
char *outbuf; /* output buffer.. should hold one tune */
char *mbf; /* where to a2b() */
int use_buffer; /* 1 if lines are being accumulated */
/* -- cut off extension on a file identifier -- */
static void cutext(char *fid)
{
char *p;
if ((p = strrchr(fid, DIRSEP)) == NULL)
p = fid;
if ((p = strrchr(p, '.')) != NULL)
*p = '\0';
}
/* -- open the output file -- */
static void open_fout(void)
{
int i;
char fnm[FILENAME_MAX];
strcpy(fnm, outfn);
i = strlen(fnm) - 1;
if (i < 0) {
strcpy(fnm, svg ? "Out.xhtml" : OUTPUTFILE);
#if 1
} else if (i != 0 || fnm[0] != '-') {
#else
} else if (i == 0 && fnm[0] == '-') {
if (svg == 1) {
error(1, 0, "Cannot use stdout with '-v' - abort");
exit(EXIT_FAILURE);
}
} else {
#endif
if (fnm[i] == '=') {
char *p;
if ((p = strrchr(in_fname, DIRSEP)) == 0)
p = in_fname;
else
p++;
/*fixme: should check if there is a DIRSEP at the end of fnm*/
strcpy(&fnm[i], p);
strext(fnm, svg ? "xhtml" : "ps");
} else if (fnm[i] == DIRSEP) {
strcpy(&fnm[i + 1], OUTPUTFILE);
}
#if 0
/*fixme: fnm may be a directory*/
else ...
#endif
}
if (svg == 1
&& (i != 0 || fnm[0] != '-')) {
cutext(fnm);
i = strlen(fnm) - 1;
if (strncmp(fnm, outfnam, i) != 0)
nepsf = 0;
sprintf(&fnm[i + 1], "%03d.svg", ++nepsf);
} else if (strcmp(fnm, outfnam) == 0) {
return; /* same output file */
}
close_output_file();
strcpy(outfnam, fnm);
if (i != 0 || fnm[0] != '-') {
if ((fout = fopen(fnm, "w")) == NULL) {
error(1, NULL, "Cannot create output file %s - abort", fnm);
exit(EXIT_FAILURE);
}
} else {
fout = stdout;
}
}
/* -- convert a date -- */
static void cnv_date(time_t *ltime)
{
char buf[TEX_BUF_SZ];
tex_str(cfmt.dateformat);
strcpy(buf, tex_buf);
strftime(tex_buf, TEX_BUF_SZ, buf, localtime(ltime));
}
/* initialize the min/max margin values */
/* (used only with eps -E and svg -g) */
void marg_init(void)
{
min_lmarg = cfmt.pagewidth;
max_rmarg = cfmt.pagewidth;
}
/* -- initialize the postscript file (PS or EPS) -- */
static void init_ps(char *str)
{
time_t ltime;
unsigned i;
char version[32];
if (epsf) {
cur_lmarg = min_lmarg - 10;
fprintf(fout, "%%!PS-Adobe-2.0 EPSF-2.0\n"
"%%%%BoundingBox: 0 0 %.0f %.0f\n",
(p_fmt->landscape ? p_fmt->pageheight : p_fmt->pagewidth)
- cur_lmarg - max_rmarg + 10,
-bposy);
marg_init();
} else {
if (!fout)
open_fout();
fprintf(fout, "%%!PS-Adobe-2.0\n");
fprintf(fout, "%%%%BoundingBox: 0 0 %.0f %.0f\n",
p_fmt->pagewidth,
p_fmt->pageheight);
}
fprintf(fout, "%%%%Title: %s\n", str);
time(<ime);
#ifndef WIN32
strftime(tex_buf, TEX_BUF_SZ, "%b %e, %Y %H:%M", localtime(<ime));
#else
strftime(tex_buf, TEX_BUF_SZ, "%b %#d, %Y %H:%M", localtime(<ime));
#endif
fprintf(fout, "%%%%Creator: abcm2ps-" VERSION "\n"
"%%%%CreationDate: %s\n", tex_buf);
if (!epsf)
fprintf(fout, "%%%%Pages: (atend)\n");
fprintf(fout, "%%%%LanguageLevel: 3\n"
"%%%%EndComments\n"
"%%CommandLine:");
for (i = 1; i < (unsigned) s_argc; i++) {
char *p, *q;
int space;
p = s_argv[i];
space = strchr(p, ' ') != NULL || strchr(p, '\n') != NULL;
fputc(' ', fout);
if (space)
fputc('\'', fout);
for (;;) {
q = strchr(p, '\n');
if (!q)
break;
fprintf(fout, " %.*s\n%%", (int) (q - p), p);
p = q + 1;
}
fprintf(fout, "%s", p);
if (space)
fputc('\'', fout);
}
fprintf(fout, "\n\n");
if (epsf)
fprintf(fout, "save\n");
strcpy(version, "/creator [(abcm2ps) " VERSION "] def");
for (i = 0; i < strlen(version); i++) {
if (version[i] == '.')
version[i] = ' ';
}
fprintf(fout, "%%%%BeginSetup\n"
"/!{bind def}bind def\n"
"/bdef{bind def}!\n" /* for compatibility */
"/T/translate load def\n"
"/M/moveto load def\n"
"/RM/rmoveto load def\n"
"/L/lineto load def\n"
"/RL/rlineto load def\n"
"/C/curveto load def\n"
"/RC/rcurveto load def\n"
"/SLW/setlinewidth load def\n"
"/defl 0 def\n" /* decoration flags - see deco.c for values */
"/dlw{0.7 SLW}!\n"
"%s\n", version);
define_symbols();
output = fprintf;
user_ps_write();
define_fonts();
if (!epsf)
fprintf(fout, "/setpagedevice where{pop\n"
" <>setpagedevice}if\n",
p_fmt->pagewidth, p_fmt->pageheight);
fprintf(fout, "%%%%EndSetup\n");
file_initialized = 1;
}
/* -- initialize the svg file (option '-g') -- */
static void init_svg(char *str)
{
cur_lmarg = min_lmarg - 10;
output = svg_output;
#if 1 //fixme:test
if (file_initialized)
fprintf(stderr, "??? init_svg: file_initialized");
#endif
define_svg_symbols(str, nepsf,
(p_fmt->landscape ? p_fmt->pageheight : p_fmt->pagewidth)
- cur_lmarg - max_rmarg + 10,
-bposy);
file_initialized = 1;
user_ps_write();
}
static void close_fout(void)
{
long m;
if (fout == stdout)
goto out2;
if (quiet)
goto out1;
m = ftell(fout);
if (epsf || svg == 1)
fprintf(stderr, "Output written on %s (%ld bytes)\n",
outfnam, m);
else
fprintf(stderr,
"Output written on %s (%d page%s, %d title%s, %ld bytes)\n",
outfnam,
nbpages, nbpages == 1 ? "" : "s",
tunenum, tunenum == 1 ? "" : "s",
m);
out1:
fclose(fout);
out2:
fout = NULL;
file_initialized = 0;
}
/* -- close the output file -- */
/* epsf is always null */
void close_output_file(void)
{
if (!fout)
return;
if (multicol_start != 0) { /* if no '%%multicol end' */
error(1, NULL, "No \"%%%%multicol end\"");
multicol_start = 0;
write_buffer();
}
if (tunenum == 0)
error(0, NULL, "No tunes written to output file");
close_page();
if (!svg) {
fprintf(fout, "%%%%Trailer\n"
"%%%%Pages: %d\n"
"%%EOF\n", nbpages);
close_fout();
} else if (svg == 2) {
fputs("