abcm2ps-8.14.17 0000755 0000000 0000000 00000000000 14754371067 0012536 5 ustar 00nobody nobody abcm2ps-8.14.17/COPYING 0000644 0000000 0000000 00000104513 14754371067 0013654 0 ustar 00nobody nobody GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc.
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. 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
them 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 prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. 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.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey 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;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If 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 convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU 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 that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
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.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
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.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
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
state 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)
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 3 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 .
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
Copyright (C)
This program 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, your program's commands
might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
.
The GNU 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 Lesser General
Public License instead of this License. But first, please read
.
abcm2ps-8.14.17/INSTALL 0000644 0000000 0000000 00000006600 14754371067 0013650 0 ustar 00nobody nobody --- abcm2ps installation ---
Getting the source files
========================
abcm2ps is now distributed from a GitHub repository.
You may get the source files either as a `tar.gz` or `.zip` file from
https://github.com/leesavide/abcm2ps.git
or by cloning the repository with 'git'
https://github.com/leesavide/abcm2ps.git
(you may use `--depth=1` if you don't want the full `git` history)
Unix(-like) systems
===================
After getting the source files, or after updating them by 'git pull',
you must generate the configuration files using the local script 'configure'.
The configuration variables and their default values are:
CC=gcc
CFLAGS="-g -O2 -Wall -pipe"
srcdir=.
prefix=/usr/local
INSTALL="/usr/bin/install -c"
INSTALL_DATA='${INSTALL} -m 644'
INSTALL_PROGRAM='${INSTALL}'
exec_prefix='${prefix}'
bindir='${exec_prefix}/bin'
libdir='${exec_prefix}/lib'
datarootdir='${prefix}/share'
docdir='${prefix}/doc'
mandir='${datarootdir$/man'
DEFAULT_FDIR="$prefix/share/abcm2ps"
The script 'configure' first tries to read the file 'custom'
in which you may set your own values (Bourne shell syntax).
For example, if you prefer to use 'clang' instead of 'gcc',
the file 'custom' would contain the single line:
CC=clang
then, you do:
./configure
The script 'configure' may also get the values of the variables from
the command line. These settings must start with '--':
./configure --CC=clang
If you want to use the 'pango' library, install the development files
for pango and freetype2, as well as the pkg-config tool prior running
'configure'.
In addition to the usual C build tools (mainly, gcc and make), you
will require the rst2man tool from the python-docutils package.
Creating the binary is done by a standard call to 'make'.
An alternate option for this creation is to use 'ninja' (ninja-build) or
'samurai'. These programs use the file 'build.ninja' which may be custumized.
Windows or pre-OS X Mac systems
===============================
You must create the file 'config.h' from the 'config.h.in' skeleton.
Then, the abcm2ps binary must be created by compiling all the '.c' files
and by linking 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.
Note: I don't know how to do file mapping (mmap) in ms-windows, so,
you must comment the line containing 'HAVE_MMAP' in config.h.
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 zathura, or it may be sent directly
to a PostScript printer, or indirectly to a simple printer using
a postscript filter.
OSX/macOS users can view PostScript natively with the system default
Preview app.
Windows users can use GSView.
About the 'pango' library
=========================
abcm2ps may use the 'pango' library to render texts with non latin
characters on PostScript output. If you have no such texts or
if you do only SVG/(X)HTML output, 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. Note also that, when pango is defined, it may be
disabled at command line level by '--pango 0'.
abcm2ps-8.14.17/Makefile.in 0000644 0000000 0000000 00000003263 14754371067 0014666 0 ustar 00nobody nobody # Makefile source for abcm2ps
CC = @CC@
INSTALL = @INSTALL@
INSTALL_DATA = @INSTALL_DATA@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
CPPFLAGS = @CPPFLAGS@
CFLAGS = @CFLAGS@
LDFLAGS = @LDFLAGS@
LDLIBS = @LDLIBS@
prefix = @prefix@
exec_prefix = @exec_prefix@
srcdir = @srcdir@
VPATH = @srcdir@
bindir = $(DESTDIR)@bindir@
datadir = $(DESTDIR)@datarootdir@
docdir = $(DESTDIR)@docdir@
mandir = $(DESTDIR)@mandir@
build: abcm2ps abcm2ps.1
# unix
OBJECTS=abcm2ps.o \
abcparse.o buffer.o deco.o draw.o format.o front.o glyph.o music.o parse.o \
subs.o svg.o syms.o
abcm2ps: $(OBJECTS)
$(OBJECTS): abcm2ps.h config.h Makefile
abcm2ps.1: abcm2ps.rst
if [ -x "$$(command -v rst2man)" ]; then\
rst2man $< $@;\
else\
cp $< $@;\
fi
install: build
mkdir -p $(bindir)
$(INSTALL_PROGRAM) abcm2ps $(bindir)
mkdir -p $(datadir)/abcm2ps
$(INSTALL_DATA) $(srcdir)/*.fmt $(datadir)/abcm2ps
mkdir -p $(docdir)/abcm2ps/examples
$(INSTALL_DATA) $(srcdir)/README.md $(docdir)/abcm2ps
$(INSTALL_DATA) $(srcdir)/*.abc $(docdir)/abcm2ps/examples
$(INSTALL_DATA) $(srcdir)/*.eps $(docdir)/abcm2ps/examples
$(INSTALL_DATA) $(srcdir)/*.html $(docdir)/abcm2ps/examples
mkdir -p $(mandir)/man1
$(INSTALL_DATA) abcm2ps.1 $(mandir)/man1
uninstall:
echo "uninstalling..."
rm -f $(bindir)/abcm2ps
rm -fr $(datadir)/abcm2ps
rm -fr $(docdir)/abcm2ps
rm -f $(mandir)/man1/abcm2ps.1
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 $@ $<
mostlyclean:
rm -f *.o $(EXAMPLES)
clean: mostlyclean
rm -f abcm2ps abcm2ps.1
distclean: clean
rm -f config.h Makefile
abcm2ps-8.14.17/README.md 0000644 0000000 0000000 00000003763 14754371067 0014105 0 ustar 00nobody nobody
# abcm2ps
### Overview
abcm2ps is a C program which converts music tunes from the ABC music notation
to PostScript or SVG.
Based on [abc2ps](https://github.com/methf/abc2ps),
the Postscript generator for ABC music notation by Michael Methfessel,
abcm2ps was first developped to print barock organ scores that have independant
voices played on one or many keyboards and a pedal-board
(the 'm' of abcm2ps stands for many or multi staves/voices).
Since this time, it has evolved so it can render many more music types.
Note that this program is at end of life. Its successor is
[abc2svg](https://chiselapp.com/user/moinejf/repository/abc2svg).
### Features
The features of abcm2ps are based on the
[ABC draft 2.2 (February 2013)](http://abcnotation.com/wiki/abc:standard:v2.2).
The differences are listed in the
[abcm2ps/abc2svg documentation](http://moinejf.free.fr/abcm2ps-doc/features.html).
### Installation and usage
The installation procedure is described in the file INSTALL.
To build the program with default settings run
```
./configure
make
```
Basically, the program usage is:
abcm2ps [options] file1 [file1_options] file2 [file2_options] ...
where file1, file2, .. are the ABC input files.
This generates a Postscript file (default name: `Out.ps`).
Run `abcm2ps -h` to know the list of the command line options.
### Documentation
- The file abcm2ps.rst describes all command-line options.
When `abcm2ps` is installed, this file may be displayed by `man abcm2ps`.
- The features and format parameters are described in
[abcm2ps-doc](http://moinejf.free.fr/abcm2ps-doc/index.html).
### Links
Author's page: [http://moinejf.free.fr/](http://moinejf.free.fr/)
To know more about the ABC music notation, have a look at
[abcnotation](https://abcnotation.com/).
Guido Gonzato maintains many abcm2ps binaries and more documentation at
[abcplus](https://abcplus.sourceforge.net/).
abcm2ps-8.14.17/abcm2ps.c 0000644 0000000 0000000 00000060064 14754371067 0014316 0 ustar 00nobody nobody /*
* abcm2ps: a program to typeset tunes written in ABC format
* using PostScript or SVG
*
* Copyright (C) 1998-2019 Jean-François Moine (http://moinejf.free.fr)
*
* Adapted from abc2ps
* Copyright (C) 1996-1998 Michael Methfessel (https://github.com/methf/abc2ps/)
*
* abcm2ps is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*/
#include
#include
#include
#include
#include
#include "abcm2ps.h"
#ifdef HAVE_MMAP
#include
#include
#elif defined(linux)
#include
#endif
/* -- global variables -- */
INFO info;
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 */
int pagenum_nr = 1; /* current page (non-resettable) */
/* 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; /* 1: EPSF, 2: SVG, 3: embedded ABC */
int svg; /* 1: SVG, 2: XHTML */
int showerror; /* show the errors */
int pipeformat = 0; /* format for bagpipes regardless of key */
char outfn[FILENAME_MAX]; /* output file name */
int file_initialized; /* for output file */
FILE *fout; /* output file */
char *in_fname; /* top level 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 *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 0x4000 /* 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 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 -- */
/* return the real/full file name 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;
}
/* -- treat an input file and generate the ABC file -- */
static void treat_file(char *fn, char *ext)
{
char *file;
char *abc_fn;
int file_type, l;
/* initialize if not already done */
if (!fout) {
read_def_format();
if (strcmp(fn, tex_buf) == 0)
return; // if xx.default.fmt, done
}
/* read the file into memory */
/* the real/full file name is put 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;
}
abc_fn = strdup(tex_buf);
if (!quiet)
fprintf(strcmp(outfn, "-") == 0 ? stderr : stdout,
"File %s\n", abc_fn);
/* convert the strings */
l = strlen(abc_fn);
if (strcmp(&abc_fn[l - 3], ".ps") == 0) {
file_type = FE_PS;
} else if (strcmp(&abc_fn[l - 4], ".fmt") == 0) {
file_type = FE_FMT;
} else {
file_type = FE_ABC;
// in_fname = abc_fn;
mtime = fmtime;
}
frontend((unsigned char *) file, file_type,
abc_fn, 0);
free(file);
if (file_type == FE_PS) /* PostScript file */
frontend((unsigned char *) "%%endps", FE_ABC,
abc_fn, 0);
if (file_type == FE_ABC) /* if ABC file */
clrarena(1); /* clear previous tunes */
}
/* call back to handle %%format/%%abc-include - see front.c */
void include_file(unsigned char *fn)
{
static int nbfiles;
if (nbfiles > 2) {
error(1, NULL, "Too many included files");
return;
}
nbfiles++;
treat_file((char *) fn, "fmt");
nbfiles--;
}
/* -- treat an ABC input file and generate the music -- */
/* this function also treats ABC in XHTML */
static void treat_abc_file(char *fn)
{
FILE *fin;
char *file, *file_tmp;
char *abc_fn, *p, *q;
size_t fsize, l, l2;
int linenum;
#ifdef HAVE_MMAP
int fd;
#endif
lvlarena(0);
parse.abc_state = ABC_S_GLOBAL;
if (epsf != 3) {
treat_file(fn, "abc"); /* not '-z' */
return;
}
if (*fn == '\0') {
error(1, NULL, "cannot use stdin with -z - aborting");
exit(EXIT_FAILURE);
}
fin = open_file(fn, "abc", tex_buf);
if (!fin)
goto err;
if (fseek(fin, 0L, SEEK_END) < 0) {
fclose(fin);
goto err;
}
fsize = ftell(fin);
rewind(fin);
#ifdef HAVE_MMAP
fd = fileno(fin);
file = mmap(NULL, fsize, PROT_READ, MAP_PRIVATE, fd, 0);
if (!file)
goto err;
#else
file = malloc(fsize);
if (!file)
goto err;
if (fread(file, 1, fsize, fin) != fsize) {
free(file);
goto err;
}
fclose(fin);
#endif
/* copy the HTML/XML/XHTML file and generate the music */
abc_fn = strdup(tex_buf);
l = fsize;
p = file;
linenum = 0;
while (l > 0) {
/* search the start of ABC lines */
#if 1
for (q = p, l2 = l - 10; l2 > 0; l2--, q++) {
if (strncmp(q, "\n%abc", 5) == 0
// || strncmp(q, "\n%%", 3) == 0
|| strncmp(q, "\nX:", 3) == 0)
break;
}
#else
for (q = p, l2 = l - 5; l2 > 0; l2--, q++)
if (strncmp(q, "", 5) == 0)
break;
#endif
if (l2 <= 0) {
fwrite(p, 1, l, fout);
break;
}
q++;
fwrite(p, 1, q - p, fout);
l -= q - p;
while (p != q) {
if (*p++ == '\n')
linenum++;
}
/* search the end of ABC lines */
for (q = p, l2 = l - 10; l2 > 0; l2--, q++)
if (*q == '\n' && q[1] == '<')
break;
if (l2 <= 0) {
error(1, NULL, "no end of ABC sequence");
q += 9;
// break;
}
q++;
/* must copy ... :( */
l2 = q - p;
file_tmp = malloc(l2 + 1);
if (!file_tmp) {
error(1, NULL, "out of memory");
break;
}
memcpy(file_tmp, p, l2);
file_tmp[l2] = '\0';
frontend((unsigned char *) file_tmp, FE_ABC,
abc_fn, linenum);
free(file_tmp);
clrarena(1); /* clear previous tunes */
file_initialized = -1; /* don't put
before first image */
l -= q - p;
while (p != q) {
if (*p++ == '\n')
linenum++;
}
}
#ifdef HAVE_MMAP
munmap(file, fsize);
fclose(fin);
#else
free(file);
#endif
return;
err:
error(1, NULL, "input file %s error %s - aborting", fn, strerror(errno));
exit(EXIT_FAILURE);
}
/* -- 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)
{
FILE *log = strcmp(outfn, "-") == 0 ? stderr : stdout;
fputs("abcm2ps-" VERSION " (" VDATE ")\n", log);
if (!full)
return;
fputs("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", log);
if (styd[0] != '\0')
fprintf(log, "Default format directory: %s\n", styd);
}
/* -- display usage and exit -- */
static void usage(void)
{
display_version(0);
printf( "ABC to Postscript/SVG 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"
" -z produce SVG output from embedded ABC\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"
" -p format for bagpipes regardless of key\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, FE_ABC,
"cmd_line", 0);
}
/* -- main program -- */
int main(int argc, char **argv)
{
unsigned j;
char *p, c, *aaa;
if (argc <= 1)
usage();
outfn[0] = '\0';
init_outbuf(64);
/* 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':
quiet = 1; // don't output the version
break;
case 'h':
usage(); /* no return */
case 'p':
pipeformat = 1; /* format for bagpipe regardless of key */
break;
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 page */
epsf = 0;
break;
case 'X':
svg = 2; /* SVG/XHTML */
epsf = 0;
break;
case 'k': {
int kbsz;
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;
}
sscanf(aaa, "%d", &kbsz);
init_outbuf(kbsz);
break;
}
case 'O':
if (p[1] == '\0') {
if (--argc <= 0) {
error(1, NULL, "No value for '-O' - aborting");
return EXIT_FAILURE;
}
aaa = *++argv;
} else {
aaa = p + 1;
p += strlen(p) - 1;
}
if (strlen(aaa) >= sizeof outfn) {
error(1, NULL, "'-O' too large - aborting");
return EXIT_FAILURE;
}
strcpy(outfn, aaa);
break;
case 'z':
epsf = 3; /* ABC embedded in XML */
svg = 0;
break;
default:
if (strchr("aBbDdeFfIjmNOsTw", c)) /* if with arg */
p += strlen(p) - 1; /* skip */
break;
}
}
}
if (!quiet)
display_version(0);
/* initialize */
clrarena(0); /* global */
clrarena(1); /* tunes */
clrarena(2); /* generation */
// memset(&info, 0, sizeof info);
info['T' - 'A'] = ¬itle;
notitle.text = "T:";
set_format();
init_deco();
#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
/* if ABC embedded in XML, open the output file */
if (epsf == 3) {
open_fout();
read_def_format();
}
/* 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_abc_file(in_fname);
frontend((unsigned char *) "select\n", FE_FMT,
"cmd_line", 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();
do_tune();
}
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 'p':
case 'q':
case 'S':
break;
case 'v':
case 'X':
case 'z':
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_abc_file(in_fname);
frontend((unsigned char *) "select\n", FE_FMT,
"cmd_line", 0);
}
in_fname = p;
}
if (in_fname)
treat_abc_file(in_fname);
if (multicol_start != 0) { /* lack of %%multicol end */
error(1, NULL, "Lack of %%%%multicol end");
multicol_start = 0;
buffer_eob(0);
if (!info['X' - 'A']
&& !epsf)
write_buffer();
}
if (!epsf && !fout) {
error(1, NULL, "Nothing to generate!");
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 = NULL;
}
str_c[level] = a_p;
a_p->p = a_p->str;
a_p->r = a_p->sz;
}
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 = NULL;
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-8.14.17/abcm2ps.h 0000644 0000000 0000000 00000072615 14754371067 0014330 0 ustar 00nobody nobody /* -- general macros -- */
#include
#include
#include "config.h"
#define MAXVOICE 32 /* max number of voices */
#define MAXHD 8 /* max heads in a chord */
#define MAXDC 32 /* max decorations per symbol */
#define MAXMICRO 32 /* max microtone values (5 bits in accs[]) */
#define DC_NAME_SZ 128 /* size of the decoration name table */
#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 /* : */
#define B_SINGLE 0x01 /* | 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 */
/* slur/tie types (4 bits) */
#define SL_ABOVE 0x01
#define SL_BELOW 0x02
#define SL_HIDDEN 0x03 /* also opposite for gstemdir */
#define SL_AUTO 0x04
#define SL_DOTTED 0x08 /* (modifier bit) */
#define OUTPUTFILE "Out.ps" /* standard output file */
#ifndef WIN32
#define DIRSEP '/'
#else
#define DIRSEP '\\'
#define strcasecmp stricmp
#define strncasecmp _strnicmp
#define strdup _strdup
#define snprintf _snprintf
#ifdef _MSC_VER
#define fileno _fileno
#endif
#endif
#define CM * 37.8 /* factor to transform cm to pt */
#define MM * 3.78 /* factor to transform mm to pt */
#define PT /* factor to transform pt to pt */
#define IN * 96.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 21 /* default stem height = one octave */
#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 7.0 /* length of stub for flag under beam */
#define SLUR_SLOPE 1.0 /* max slope of a slur */
#define GSTEM 15 /* grace note stem length */
#define GSTEM_XOFF 2.3 /* 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 32 /* 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 */
struct decos { /* decorations */
char n; /* whole number of decorations */
struct {
unsigned char t; /* decoration index */
signed char m; /* index in chord when note / -1 */
} tm[MAXDC];
};
struct note_map { /* note mapping */
struct note_map *next; /* note linkage */
char type; /* map type */
#define MAP_ONE 0
#define MAP_OCT 1
#define MAP_KEY 2
#define MAP_ALL 3
signed char pit; /* note pitch and accidental */
unsigned char acc;
char *heads; /* comma separated list of note heads */
int color; /* color */
signed char print_pit; /* print pitch */
unsigned char print_acc; /* print acc */
};
struct map { /* voice mapping */
struct map *next; /* name linkage */
char *name;
struct note_map *notes; /* mapping of the notes */
};
extern struct map *maps; /* note mappings */
struct note { /* note head */
int len; /* note duration (# pts in [1] if space) */
signed char pit; /* absolute pitch from source - used for ties and map */
unsigned char acc; /* code for accidental & index in micro_tb */
unsigned char sl1; /* slur start */
char sl2; /* number of slur ends */
char ti1; /* flag to start tie here */
char hlen; /* length of the head string */
char invisible; /* alternate note head */
float shhd; /* horizontal head shift (#pts if space) */
float shac; /* horizontal accidental shift */
char *head; /* head */
int color; /* heads when note mapping */
};
struct notes { /* note chord or rest */
struct note notes[MAXHD]; /* note heads */
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 */
float sdx; /* x offset of the stem */
struct decos dc; /* decorations */
};
extern int severity;
extern 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[256]; /* word (dummy size) */
};
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 - see SL_xxx */
struct posit_s {
unsigned short dyn:4; /* %%dynamic */
unsigned short gch:4; /* %%gchord */
unsigned short orn:4; /* %%ornament */
unsigned short voc:4; /* %%vocal */
unsigned short vol:4; /* %%volume */
unsigned short std:4; /* %%stemdir */
unsigned short gsd:4; /* %%gstemdir */
};
/* music element */
struct SYMBOL { /* struct for a drawable symbol */
struct SYMBOL *abc_next, *abc_prev; /* source linkage */
struct SYMBOL *next, *prev; /* voice linkage */
struct SYMBOL *ts_next, *ts_prev; /* time linkage */
struct SYMBOL *extra; /* extra symbols (grace notes, tempo... */
char abc_type; /* ABC 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
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 */
signed char pits[MAXHD]; /* pitches / clef */
int dur; /* main note duration */
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_CLEF_AUTO 0x0020 /* auto clef (when clef) */
#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 // end of repeat bracket
#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 */
#define S_NEW_SY 0x08000000 /* staff system change (%%staves) */
#define S_RBSTART 0x10000000 // start of repeat bracket
#define S_OTTAVA 0x20000000 // ottava decoration (start or stop)
struct posit_s posit; /* positions / directions */
signed char stem; /* 1 / -1 for stem up / down */
signed char combine; /* voice combine */
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 nohdi1; /* no head index (for unison) / nb of repeat */
signed char nohdi2;
signed char doty; /* NOTEREST: y pos of dot when voices overlap
* STBRK: forced
* FMTCHG REPEAT: infos */
short aux; /* 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
* nohdi1: # repeat */
int color;
float x; /* x offset */
signed char y; /* y offset of note head */
signed char ymn, ymx; /* min, max, note head y offset */
signed char mid; // y offset of the staff middle line
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 */
struct gch *gch; /* guitar chords / annotations */
struct lyrics *ly; /* lyrics */
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 */
#define ABC_F_RBSTART 0x0100 // start of repeat bracket and mark
#define ABC_F_RBSTOP 0x0200 // end of repeat bracket and mark
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) */
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 */
char instr; /* specific instrument */
#define K_HP 1 /* bagpipe */
#define K_Hp 2
#define K_DRUM 3 /* percussion */
signed char nacc; /* number of explicit accidentals */
signed char cue; /* cue voice (scale 0.7) */
signed char octave; /* 'octave=' */
#define NO_OCTAVE 10 /* no 'octave=' */
unsigned char microscale; /* microtone denominator - 1 */
char clef_delta; /* clef delta */
char key_delta; // tonic base
char *stafflines;
float staffscale;
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 16
struct {
char top[8]; /* top value */
char bot[2]; /* bottom value */
} meter[MAX_MEASURE];
} meter;
struct { /* Q: info */
char *str1; /* string before */
short beats[4]; /* up to 4 beats */
short circa; /* "ca. " */
short tempo; /* number of beats per mn or */
short new_beat; /* old beat */
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 */
signed char cue; /* cue voice (scale 0.7) */
char *stafflines;
float staffscale;
} voice;
struct { /* bar, mrest or mrep */
int type;
char repeat_bar;
char len; /* len if mrest or mrep */
char dotted;
struct decos dc; /* decorations */
} bar;
struct clef_s { /* clef */
char *name; /* PS drawing function */
signed char type;
#define TREBLE 0
#define ALTO 1
#define BASS 2
#define PERC 3
#define AUTOCLEF 4
char line;
signed char octave; /* '+8' / '-8' */
signed char transpose; /* if '^8' / '_8' */
char invis; /* clef 'none' */
char check_pitch; /* check if old abc2ps transposition */
} clef;
struct notes 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;
};
/* parse definition */
struct parse {
struct SYMBOL *first_sym; /* first symbol */
struct SYMBOL *last_sym; /* last symbol */
int abc_vers; /* ABC version = (H << 16) + (M << 8) + L */
char *deco_tb[DC_NAME_SZ]; /* decoration names */
unsigned short micro_tb[MAXMICRO]; /* microtone values [ (n-1) | (d-1) ] */
int abc_state; /* parser state */
};
extern struct parse parse;
#define FONT_UMAX 10 /* max number of user fonts 0..9 */
enum e_fonts {
ANNOTATIONFONT = FONT_UMAX,
COMPOSERFONT,
FOOTERFONT,
GCHORDFONT,
HEADERFONT,
HISTORYFONT,
INFOFONT,
MEASUREFONT,
PARTSFONT,
REPEATFONT,
SUBTITLEFONT,
TEMPOFONT,
TEXTFONT,
TITLEFONT,
VOCALFONT,
VOICEFONT,
WORDSFONT,
FONT_DYN /* 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 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 gutter, indent, infospace, slurheight, tieheight, notespacingfactor, scale;
float staffsep, sysstaffsep, maxstaffsep, maxsysstaffsep, stretchlast;
float staffscale; // (treated in parse.c)
int abc2pscompat, alignbars, aligncomposer, autoclef;
int barsperstaff, breakoneoln, bstemdown, cancelkey, capo;
int combinevoices, contbarnb, continueall, custos;
int dblrepbar, decoerr, dynalign, flatbeams, flatbeamgracing, infoline;
int gchordbox, graceslurs, graceword,gracespace, hyphencont;
int keywarn, landscape, linewarn;
int measurebox, measurefirst, measurenb;
int nedo, oneperpage;
#ifdef HAVE_PANGO
int pango;
#endif
int partsbox, pdfmark;
int rbdbstop, rbmax, rbmin;
int setdefl, shiftunison, splittune, squarebreve;
int staffnonote, straightflags, stretchstaff;
int textoption, titlecaps, titleleft, titletrim;
int timewarn, transpose, tuplets;
char *bgcolor, *dateformat, *header, *footer, *header2, *footer2, *titleformat;
char *musicfont;
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 int outbufsz; /* size of outbuf */
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 pagenum_nr; /* current page (non-resettable) */
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; /* 1: EPSF, 2: SVG, 3: embedded ABC */
extern int svg; /* 1: SVG, 2: XHTML */
extern int showerror; /* show the errors */
extern int pipeformat; /* format for bagpipes */
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 SYMBOL *s_clef; /* clef at start of music line */
char empty; /* no symbol on this staff */
char *stafflines;
float staffscale;
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 {
char id[VOICE_ID_SZ]; /* voice id */
/* generation */
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 *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 SYMBOL *s_clef; /* clef at end of music line */
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 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 ottava; /* !8va(! ... (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 */
signed char combine; /* voice combine */
int color;
char *stafflines;
float staffscale;
/* parsing */
struct SYMBOL *last_note; /* last note or rest */
char *map_name;
int ulen; /* unit note length */
unsigned char microscale; /* microtone scale */
unsigned char mvoice; /* main voice when voice overlay */
};
extern struct VOICE_S *curvoice; /* current voice while parsing */
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 */
extern float hw_tb[]; // width of note heads
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
#define MASTER_VOICE 0x1000
char empty;
char *stafflines;
float staffscale;
// 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];
};
extern struct SYSTEM *cursys; /* current staff system */
/* -- external routines -- */
/* abcm2ps.c */
void include_file(unsigned char *fn);
void clrarena(int level);
int lvlarena(int level);
void *getarena(int len);
void strext(char *fid, char *ext);
/* abcparse.c */
void abc_parse(char *p, char *fname, int linenum);
void abc_eof(void);
char *get_str(char *d,
char *s,
int maxlen);
char *parse_acc_pit(char *p,
int *pit,
int *acc);
/* buffer.c */
void a2b(char *fmt, ...)
#ifdef __GNUC__
__attribute__ ((format (printf, 1, 2)))
#endif
;
void block_put(void);
void buffer_eob(int eot);
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 open_fout(void);
void write_buffer(void);
extern 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 decos *dc, struct SYMBOL *s, struct SYMBOL *prev);
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_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 init_deco(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 color);
struct SYMBOL *prev_scut(struct SYMBOL *s);
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);
void set_color(int color);
/* format.c */
void define_fonts(void);
int get_textopt(char *p);
int get_font_encoding(int ft);
int get_bool(char *p);
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);
/* front.c */
#define FE_ABC 0
#define FE_FMT 1
#define FE_PS 2
void frontend(unsigned char *s,
int ftype,
char *fname,
int linenum);
/* 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(void);
void identify_note(struct SYMBOL *s,
int len,
int *p_head,
int *p_dots,
int *p_flags);
void sort_pitch(struct SYMBOL *s);
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, int type);
float cwid(unsigned char 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(void);
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);
void svg_def_id(char *id, int idsz);
void svg_font_switch(void);
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-8.14.17/abcm2ps.rst 0000644 0000000 0000000 00000044461 14754371067 0014707 0 ustar 00nobody nobody ..
Process this file with rst2man from python-docutils
to generate a nroff manual page
=======
abcm2ps
=======
--------------------------------------------------
translate ABC music notation to PostScript or SVG
--------------------------------------------------
SYNOPSIS
========
``abcm2ps`` [global_options] ABC_file [file_options] ...
DESCRIPTION
===========
``abcm2ps`` translates tunes written in
the ABC music notation format to customary sheet music scores in
PostScript or SVG. It is based on ``abc2ps`` 1.2.5 and was
developed mainly to print Baroque organ scores that have
independent voices played on multiple keyboards and a
pedal-board. The program has since been extended to support
various other notation conventions in use for sheet music.
Options given immediately after the command name apply to
the run as a whole; options given after an ABC file name apply
to that file.
Formatting parameters can also be set in "format files" and
in the ABC files themselves.
OPTIONS
=======
The list of the command line options may be known running::
abcm2ps -h
The options may be grouped when they have no argument, but the
last one (ex: ``-lnGI20``).
The options may be disabled when starting with '+' or ending with '-'
(ex: ``+MT1`` is the same as ``-MT1-``).
The general output format is the last found in the command line.
It may be:
-E for Encapsulated PostScript, one file per tune
-g for SVG, one file per tune
-v for SVG, one file per page
-X for XHTML+SVG
-z for (X)HTML+SVG with (X)HTML+ABC input
(see below for more information)
List of the options
-------------------
\-
Read the abc file from stdin.
\--
Set the parameter to .
This has the same effect as a format parameter
directly in the source file.
-a
Maximal horizontal compression when staff breaks are
chosen automatically. Must be a float between 0 and 1.
This correspond to the ``%%maxshrink``
formatting parameter (default: 0.65).
-A
This option inserts reference elements in the PostScript
or SVG output.
-B , +B
Try to typeset bars on each staff line.
This corresponds to the ``%%barsperstaff`` formatting parameter.
-b
Start measure numbering at .
This corresponds to the ``%%measurefirst`` formatting parameter.
-c, +c
The continuation symbol is implicitly appended to each
music line. This amounts to automatic line breaking.
This corresponds to the ``%%continueall`` formatting parameter.
-D
Search the format files in the directory .
-d
Set the vertical interstaff space to .
This corresponds to the ``%%staffsep`` formatting parameter
(default: 46pt).
-E
Produce EPS output instead of simple PS.
In this mode, each tune goes to a different file which
name is "nnn.eps" or ".eps" (see option '-O')
- 'nnn' is a sequence number incremented at each tune
Output to stdout is forbidden.
EPS files are normally embedded into Postscript documents,
but they may be a way to generate graphical images. For
example, using GhostScript::
abcm2ps voices -Ee7
gs -sDEVICE=pngmono -r80 -g590x174 \
-dBATCH -dNOPAUSE \
-sOutputFile=quitolis.png Out001.eps
\(the values for -g are the values of the bounding box in
the .eps, multiplied by (80 / 72), where 80 is the value
for -r, and 72 is the default resolution)
-e [ ] [ ]
Select which tunes from an ABC file to print.
is either a comma-separated list of tune
numbers (as per the ``X:`` header), or a regular expression
which will be matched against the tune headers as a whole.
The ``-e`` option must occur after an ABC file
name and applies to that file.
Ranges of tune numbers may be specified like ``-``;
may be omitted which means
"all remaining tunes until the end of file". Note that
filtering may cause problems, e.g., with global (non-tune)
definitions in the ABC file.
This corresponds to the ``%%select`` formatting parameter.
-F , +F
Read the format (or PostScript) file .
When omitted, the default type of a format file is '.fmt'.
In the form '+F', the default format file ('default.fmt') is not
read.
-f
Enable flat beams (useful for bagpipe tunes).
This corresponds to the ``%%flatbeams`` formatting parameter.
-G, +G
Omit slurs on grace notes.
This corresponds to the ``%%graceslurs`` formatting parameter.
-g
Produce SVG output instead of EPS.
In this mode each tune goes to a different file which name
is 'Outnnn.svg' (see option '-O').
If the output is stdout (option '-O-'), all the SVG images
are output without XML header.
-H
Display the current format values.
-h
Quick help, equivalent to "abcm2ps" without any arguments.
This also shows the default settings for some parameters.
-I
Indent the first line of the tune by (default: 0).
This corresponds to the ``%%indent`` formatting parameter.
-i, +i
Insert a red cercle around the errors in the PostScript output.
-j [b], +j
Output a measure number every measures.
If is 0, the measure number appears at the left of each staff.
The trailing ``b`` causes a box to be drawn
around each measure number (default: no measure numbering).
This corresponds to the ``%%measurenb`` formatting parameter.
-k
Set the size of the PostScript output buffer in Kibytes.
Setting this value to a higher value permits the
generation of big tunes with -E or -g. The default value is 64.
-l, +l
Generate landscape output.
This corresponds to the ``%%landscape`` formatting parameter.
-M, +M
Suppress lyrics.
See the ``%%writefields w`` formatting parameter.
-m
Set the left margin to (default: 1.8cm).
This corresponds to the ``%%leftmargin`` formatting parameter.
-N , +N
Number the pages.
indicates the mode:
0
no page numbers
1
at top left
2
at top right
3
at top left on even pages, top right on odd pages
4
at top right on even pages, top left on odd pages
For compatibility with previous versions, '+N' is the same as
'-N0', and '-N' is the same as '-N2'.
If a header is defined ("%%header"), this option is ignored.
-n, +n
Include notes and history from ABC tune ``N:`` fields.
See the ``%%writehistory N`` formatting parameter.
-O [ ] [ ], +O
Define the output file directory and/or name.
The directory must end with the directory separator
('/' for unix/windows, '\\' for mac).
By default, the output file goes to the current directory
with the name:
'Out.ps' for PS,
'Outnnn.eps' for EPS (see option '-E'),
'Outnnn.svg' for SVG (see options '-g' and '-v') or
'Out.xhtml' for XHTML+SVG (see options '-X' and '-z').
'nnn' is a sequence number.
When is present, it is the name of the file, or it
replaces "Out" in the file name.
If is '=', it is replaced by the name of the ABC
source file (not for '-z').
If is '-', the result is output to stdout (not for EPS).
'+O' resets the output file directory and name to their defaults.
-p
Bagpipe format.
When present, format output for bagpipe regardless of key.
-q
Quiet mode.
When present, only the errors are shown.
-s
Set the page scale factor to . Note that the header
and footer are not scaled (default: 0.75).
This corresponds to the ``%%scale`` formatting parameter.
-S
Secure mode.
When present, file inclusion (%%format and %%EPS) and PostScript
injection (%%beginps and %%postscript) are disabled.
-T [ ], +T [ [ ] ]
Activate or deactivate tablature drawing.
- is the tablature number as defined in ``%%tablature``.
There may be only 8 different tablatures.
- is the voice name, full name or subname as found in V:.
When absent, apply to all voices.
Up to 4 such commands may be defined.
Ex: '-T1flute +T2'
-V
Show the version number.
-v
Produce SVG output instead of simple PS.
In this mode each page goes to a different file which name
is 'Outnnn.svg' (see option '-O').
-w
Adjust the right margin such that the staff width
is (default: none).
This corresponds to the ``%%staffwidth`` formatting parameter.
-X
Produce XML+SVG output instead of simple PS.
The default file name is 'Out.xhtml' (see option '-O').
-x, +x
Include the ``X:`` tune number in the title.
This corresponds to the ``%%writefields`` formatting parameter.
-z
Produce SVG images from ABC embedded in markup language files
(HTML, XHTML..).
The source file is copied to the output file and the ABC sequences
are converted to SVG images.
The ABC sequences start by either ``%abc..`` or ``X:..``
and stop on the first markup tag (``<..``).
The generation creates one image per block, i.e. a music line
or a text block. For a same rendering as the other SVG generation
(-g, -v or -X), don't forget to set the line space to null, for
example enclosing the ABC sequences by::
..
There can be only one output file.
Note that the default output file is 'Out.xhtml', so, don't
forget to change the file type if you generate HTML (.html)
or XML (.xml) files.
See "sample8.html" for a source example.
-0, +0
Split tunes across page breaks if necessary.
This corresponds to the ``%%splittune`` formatting parameter.
-1, +1
Output one tune per page.
This corresponds to the ``%%oneperpage`` formatting parameter.
ADDITIONAL FEATURES
===================
Clefs
Clefs can be given in ``K:`` and ``V:`` headers.
The full syntax is::
clef=[+8|-8]
"clef=" can be omitted when the is a clef name.
denotes the clef type. It may be:
- A note pitch (``G``, ``C``, or ``F``)
The pitch indicates which clef is meant:
``G`` is the treble clef,
``C`` the alto clef and
``F`` the bass clef.
It also gives the name of the note that appears
on the clef's line.
- A clef name
The available clef names are
``treble`` (clef gives the pitch for ``G``),
``alto`` or ``tenor`` (``C``), and
``bass`` (``F``).
- ``perc`` or ``P``
In percussion mode, accidentals change the glyphs used for
note heads. By default, sharp notes are drawn as "x" and
flat notes as circled "x".
This may be changed by redefining the PostScript functions
``pshhd`` and ``pflhd``.
- ``none``
No clef will be displayed.
The gives the number of
the line within the staff that the base clef will be written
on. The default values are 2 for the treble clef, 3 for the
alto clef, and 4 for the tenor and bass clefs.
The "+8" and "-8"
options draw an 8 above or below the staff, respectively.
When no clef is specified, clef changes
between "bass"
and "treble" will be inserted
automatically.
Multi-voice typesetting
Multiple voices may be defined within the header or the
tune using::
V: ...
where is a word consisting of letters and digits only
(like "violin1"). In the tune body, the
following notes refer to this voice until
another "V:" is encountered.
A can be one of:
* "clef="...
See above
* "name=" or "nm="
The will be
displayed at the beginning of the first staff. It can
contain "\\n" sequences
which will force line breaks. If it contains
whitespace it must be double-quoted.
* "subname=" or "snm="
The will be displayed at the beginning of all staves
except for the first. It can
contain "\\n" sequences
which will force line breaks. If it contains
whitespace it must be double-quoted.
* "merge"
The voice goes on the same staff as the previous voice.
* "up" or "down"
Forces the direction of the stems for the voice.
* "dyn=up" or "dyn=down" or "dyn=auto"
Forces positioning of dynamic marks (above or
below the staff) or reverts to automatic positioning
(the default).
* "gstem=up" or "gstem=down" or "gstem=auto"
Forces the direction of the stems of grace
notes (always up or always down) or reverts to
automatic positioning (the default).
* "stem=auto"
Reverts to automatic positioning of note stems
(up or down) (the default).
* "lyrics=up" or "lyrics=down" or "lyrics=auto"
Places lyrics above or below the staff or
reverts to automatic positioning (the default)
* "gchord=up" or "gchord=down"
Places guitar chords above (the default) or below the staff.
* "stafflines="
Sets the number of lines on the staff in question. (default: 5)
* "staffscale="
Sets the scale of the associated staff up to 3. (default: 1)
All other definitions are ignored.
Definition of the staff system
By default, each voice goes on its own
staff. The ``%%staves ``
pseudo-comment can be used to control staff
assignment. The
consists of voice names (from ``V:``) and pairs of
parentheses, braces or brackets.
- When a voice name is not within a pair of
special characters, it goes on a separate staff.
- For voice names enclosed in brackets, a bracket
is displayed at the beginning of each line that joins
the staves of the voices in question.
- For voice names enclosed in braces, all the
voices go on two staves (keyboard score). There can be
at most four voices between a single pair of braces.
- For voice names enclosed in parentheses, all the
voices appear on a single staff.
The ``|`` character prevents measure bars from
being drawn between two staves.
If ``%%staves`` occurs in a tune, all the
voices not mentioned will not be output at all.
The ``%%score`` directive occurs in the ABC
draft 2.0 standard and is similar to
the ``%%staves`` specification described
above. The rules are:
- Voice names within parentheses form a "voice
group" and go on a single staff. A voice name that is
not within parentheses forms its own voice group and
goes on a staff by itself.
- Voice groups within braces form a "voice block"
and are preceded by a big brace in the output. This is
especially useful for keyboard music.
- Voice groups or voice blocks within brackets
form a "voice block" and will be preceded by a big
bracket in the output.
- If a ``|`` character occurs between two
voice groups or voice blocks, the bar lines in all of
the associated staves will be continuous.
- A single voice surrounded by two voice groups
can be preceded by an asterisk to make it into a
"floating" voice. This means that, for each note of the
voice, a separate decision is made whether it is printed
on the preceding or the following voice group's staff.
- Voices that appear in the tune body but not in
the ``%%score`` directive will not be output at
all. If there is no ``%%score`` directive, each
voice will be output on its own staff.
- A ``%%score`` directive inside a tune
resets the mechanism so voices can be removed or added.
Voice overlay
You can add notes to a staff without introducing a
complete extra voice by using the ampersand
(``&``). A single measure can be split into two voices like::
|F2A2Bc&F2c2bc|
The ``(&...&...&)`` construction allows splitting multiple
measures::
|!f!(&GG``.
SEE ALSO
========
A brief introduction referencing further documentation is
installed in /abcm2ps/README.md.
The ABC music notation is at http://abcnotation.com/.
Especially, you may find a discussion of differences with the
ABC standard at http://moinejf.free.fr/abcm2ps-doc/features.html
and a list of formatting options at http://moinejf.free.fr/abcm2ps-doc/.
AUTHOR
======
``abcm2ps`` was written by Jean-François Moine
starting from ``abc2ps`` by Michael Methfessel.
Parts of this manual have been written by Anselm Lingnau
for the ``Debian`` system.
Permission is granted to copy, distribute and/or modify this
document as long as its origin is not misrepresented.
abcm2ps-8.14.17/abcparse.c 0000644 0000000 0000000 00000156572 14754371067 0014561 0 ustar 00nobody nobody /*
* Generic ABC parser.
*
* This file is part of abcm2ps.
*
* Copyright (C) 1998-2025 Jean-François Moine (http://moinejf.free.fr)
* Adapted from abc2ps, Copyright (C) 1996-1998 Michael Methfessel
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*/
#include "config.h"
#include
#include
#include
#include
#include "abcm2ps.h"
/* global values */
int severity; /* error severity */
static int 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 decos dc; /* decorations */
static struct SYMBOL *deco_start; /* 1st note of the line for d: / s: */
static struct SYMBOL *deco_cont; /* current symbol when d: / s: continuation */
static int g_abc_vers, g_ulen, g_microscale;
static char g_char_tb[128];
static char *g_deco_tb[128]; /* global decoration names */
static unsigned short g_micro_tb[MAXMICRO]; /* global microtone values */
static char *abc_fn; /* current source file name */
static int linenum; /* current source line number */
static int colnum; /* current source column number */
static char *abc_line; /* line being parsed */
static struct SYMBOL *last_sym; /* last symbol for errors */
static short nvoice; /* number of voices (0..n-1) */
struct VOICE_S *curvoice; /* current voice while parsing */
struct parse parse;
/* char table for note line parsing */
#define CHAR_BAD 0
#define CHAR_IGN 1
#define CHAR_NOTE 2
#define CHAR_GR_ST 3
#define CHAR_DECO 4
#define CHAR_GCHORD 5
#define CHAR_BSLASH 6
#define CHAR_OBRA 7
#define CHAR_BAR 8
#define CHAR_OPAR 9
#define CHAR_VOV 10
#define CHAR_SPAC 11
#define CHAR_MINUS 12
#define CHAR_CPAR 13
#define CHAR_BRHY 14
#define CHAR_DECOS 15
#define CHAR_SLASH 16
#define CHAR_GR_EN 17
#define CHAR_LINEBREAK 18
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_NOTE, 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_NOTE, CHAR_DECO, CHAR_NOTE, CHAR_OBRA, /* X Y Z [ */
CHAR_BSLASH, CHAR_BAR, CHAR_NOTE, CHAR_NOTE, /* \ ] ^ _ */
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_NOTE, CHAR_NOTE, CHAR_NOTE, 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 int parse_info(char *p);
static char *parse_gchord(char *p);
static int parse_line(char *p);
static char *parse_note(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, "%s:%d:%d: error: %s\n", abc_fn, linenum, col, s);
else
fprintf(stderr, "%s:%d: error: %s\n", abc_fn, linenum, s);
}
/* -- new symbol -- */
static struct SYMBOL *abc_new(int type, char *text)
{
struct SYMBOL *s;
s = getarena(sizeof(struct SYMBOL));
memset(s, 0, sizeof(struct SYMBOL));
if (text) {
s->text = getarena(strlen(text) + 1);
strcpy(s->text, text);
}
if (!parse.last_sym) {
parse.first_sym = s;
} else {
if ((s->abc_next = parse.last_sym->abc_next) != NULL)
s->abc_next->abc_prev = s;
parse.last_sym->abc_next = s;
s->abc_prev = parse.last_sym;
}
last_sym = parse.last_sym = s;
s->abc_type = type;
s->state = parse.abc_state;
s->fn = abc_fn;
s->linenum = linenum;
s->colnum = colnum;
return s;
}
/* -- parse an ABC line -- */
void abc_parse(char *p, char *fname, int ln)
{
abc_fn = fname;
linenum = ln;
abc_line = p;
/* parse the music line */
switch (parse_line(p)) {
case 2: /* start of tune (X:) */
g_abc_vers = parse.abc_vers;
g_ulen = ulen;
g_microscale = microscale;
meter = 2;
memcpy(g_char_tb, char_tb, sizeof g_char_tb);
memcpy(g_deco_tb, parse.deco_tb, sizeof g_deco_tb);
memcpy(g_micro_tb, parse.micro_tb, sizeof g_micro_tb);
break;
case 1: /* end of tune */
if (parse.first_sym) {
do_tune();
parse.first_sym = parse.last_sym = NULL;
}
parse.abc_state = ABC_S_GLOBAL;
parse.abc_vers = g_abc_vers;
ulen = g_ulen;
microscale = g_microscale;
memcpy(char_tb, g_char_tb, sizeof g_char_tb);
memcpy(parse.deco_tb, g_deco_tb, sizeof parse.deco_tb);
memcpy(parse.micro_tb, g_micro_tb, sizeof parse.micro_tb);
lvlarena(0);
if (dc.n > 0)
syntax("Decoration without symbol", 0);
dc.n = 0;
break;
}
}
/* treat the end of file */
void abc_eof(void)
{
// if (parse.abc_state == ABC_S_HEAD)
// severity = 1;
do_tune();
parse.first_sym = parse.last_sym = NULL;
if (parse.abc_state != ABC_S_GLOBAL) {
parse.abc_vers = g_abc_vers;
ulen = g_ulen;
microscale = g_microscale;
memcpy(char_tb, g_char_tb, sizeof g_char_tb);
}
}
/* -- treat the broken rhythm '>' and '<' -- */
static void broken_rhythm(struct SYMBOL *s,
int num) /* >0: do dot, <0: do half */
{
struct notes *notes = &s->u.note;
int l, m, n;
num *= 2;
if (num > 0) {
if (num == 6)
num = 8;
n = num * 2 - 1;
for (m = 0; m <= s->nhd; m++)
notes->notes[m].len = (notes->notes[m].len * n) / num;
} else {
n = -num;
if (n == 6)
n = 8;
for (m = 0; m <= s->nhd; m++)
notes->notes[m].len /= n;
}
l = notes->notes[0].len;
for (m = 1; m <= s->nhd; m++)
if (notes->notes[m].len < l)
l = notes->notes[m].len;
}
/* -- 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_stlines,
char **p_scale,
char **p_octave,
char **p_cue,
char **p_map)
{
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
|| strncmp(p, "uscale=", 7) == 0) {
int i;
p += p[0] == 'm' ? 11 : 7;
i = atoi(p);
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) {
int l;
char *q;
if (*p_stlines)
syntax("Double stafflines", p);
p += 11;
if (isdigit((unsigned char) *p)) {
switch (atoi(p)) {
case 0: *p_stlines = "..."; break;
case 1: *p_stlines = "..|"; break;
case 2: *p_stlines = ".||"; break;
case 3: *p_stlines = ".|||"; break;
case 4: *p_stlines = "||||"; break;
case 5: *p_stlines = "|||||"; break;
case 6: *p_stlines = "||||||"; break;
case 7: *p_stlines = "|||||||"; break;
case 8: *p_stlines = "||||||||"; break;
default:
syntax("Bad number of lines", p);
break;
}
} else {
q = p;
while (!isspace((unsigned char) *p) && *p != '\0')
p++;
l = p - q;
*p_stlines = getarena(l + 1);
strncpy(*p_stlines, q, l);
(*p_stlines)[l] = '\0';
}
} else if (strncmp(p, "staffscale=", 11) == 0) {
if (*p_scale)
syntax("Double staffscale", p);
*p_scale = p + 11;
} else if (strncmp(p, "cue=", 4) == 0) {
if (*p_cue)
syntax("Double cue", p);
*p_cue = p + 4;
} else if (strncmp(p, "map=", 4) == 0) {
if (*p_map)
syntax("Double map", p);
*p_map = p + 4;
// } else if (strncmp(p, "transpose=", 10) == 0
// || strncmp(p, "t=", 2) == 0) {
// ; /* ignored - abcMIDI */
} 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_dc)
{
char *q, sep, **t;
unsigned i, l;
*p_dc = 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 = &parse.deco_tb[1];
*t && i < DC_NAME_SZ;
i++, t++) {
if (strlen(*t) == l
&& strncmp(*t, q, l) == 0) {
*p_dc = i + 128;
return p;
}
}
/* new decoration */
if (i < DC_NAME_SZ) {
// if (parse.abc_state != ABC_S_GLOBAL)
// lvlarena(0);
*t = getarena(l + 1);
// if (parse.abc_state != ABC_S_GLOBAL)
// lvlarena(1);
memcpy(*t, q, l);
(*t)[l] = '\0';
*p_dc = i + 128;
} else {
syntax("Too many decoration types", q);
}
return p;
}
/* -- parse a list of accidentals (K:) -- */
static char *parse_acc(char *p,
struct SYMBOL *s)
{
int pit = 0, acc;
unsigned nacc;
nacc = 0;
for (;;) {
if (nacc >= sizeof s->u.key.pits) {
syntax("Too many accidentals", p);
break;
}
p = parse_acc_pit(p, &pit, &acc);
if (acc < 0)
break;
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 SYMBOL *s,
char *name,
char *middle)
{
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 = getarena(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;
clef_line = 3;
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;
clef_line = 3;
name += 4;
} else if (!strncmp(name, "auto", 4)) {
clef = AUTOCLEF;
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);
clef = TREBLE;
}
}
if (clef >= 0) {
if (isdigit((unsigned char) *name))
clef_line = *name++ - '0';
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 = 0, acc, l;
static const char line_tb[7] =
{ALTO, TREBLE, ALTO, BASS, ALTO, BASS, ALTO};
warn = middle;
/* 'middle=' */
parse_acc_pit(middle, &pit, &acc);
if (acc < 0) // if error
pit = 22;
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;
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 SYMBOL *s)
{
int sf, empty, instr;
// int mode;
char *clef_name, *clef_middle, *clef_stlines, *clef_scale;
char *p_octave, *p_cue, *p_map;
// set important default values
// s->u.key.stafflines = "|||||";
s->u.key.octave = NO_OCTAVE;
if (*p == '\0') {
s->u.key.empty = 1;
return;
}
sf = 0;
// mode = 0;
empty = 0;
instr = 0;
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') {
instr = K_HP;
p++;
} else if (*p == 'p') {
instr = K_Hp;
sf = 2;
p++;
} else {
syntax("Unknown bagpipe-like key", p);
}
break;
case 'P':
instr = K_DRUM;
p++;
break;
case 'n':
if (strncmp(p, "one", 3) == 0) { // none
empty = 2;
p += 3;
while (isspace((unsigned char) *p))
p++;
if (*p == '\0') {
s->u.key.empty = empty;
return;
}
break;
}
// fall thru
default:
p--;
empty = 1;
break;
}
s->u.key.empty = empty;
if (!empty) {
if (*p == '#') {
sf += 7;
p++;
} else if (*p == 'b') {
sf -= 7;
p++;
}
while (isspace((unsigned char) *p))
p++;
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 '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 = 5;
break;
}
goto unk;
case 'p':
case 'P':
if (strncasecmp(p, "phr", 3) == 0) {
sf -= 4;
// mode = 2;
break;
}
goto unk;
default:
unk:
empty = 1; // (local value)
break;
}
if (!empty) {
while (isalpha((unsigned char) *p))
p++;
while (isspace((unsigned char) *p))
p++;
}
// [exp] accidentals
if (strncmp(p, "exp ", 4) == 0) {
p += 4;
while (isspace((unsigned char) *p))
p++;
if (*p == '\0')
syntax("no accidental after 'exp'", p);
s->u.key.exp = 1;
}
if (s->u.key.exp && strncmp(p, "none", 4) == 0) {
sf = 0;
p += 4;
while (isspace((unsigned char) *p))
p++;
} else switch (*p) {
case '^':
case '_':
case '=':
p = parse_acc(p, s); /* accidentals */
break;
}
}
if (sf > 7 || sf < -7) {
syntax("Too many sharps/flats", p);
if (sf > 0)
sf -= 12;
else
sf += 12;
}
// extra parameters
clef_name = clef_middle = clef_stlines = clef_scale = NULL;
p_octave = p_cue = p_map = NULL;
parse_extra(p, &clef_name, &clef_middle, &clef_stlines,
&clef_scale, &p_octave, &p_cue, &p_map);
s->u.key.sf = sf;
// s->u.key.mode = mode;
s->u.key.instr = instr;
s->u.key.octave = parse_octave(p_octave);
if (p_cue) {
if (strncmp(p_cue, "on", 2) == 0)
s->u.key.cue = 1;
else
s->u.key.cue = -1;
}
if (clef_stlines)
s->u.key.stafflines = clef_stlines;
if (clef_scale) {
float sc;
sc = atof(clef_scale);
if (sc >= 0.5 && sc <= 3)
s->u.key.staffscale = sc;
else
syntax("Bad value of staffscale", clef_scale);
}
if (clef_name || clef_middle) {
s = abc_new(ABC_T_CLEF, NULL);
parse_clef(s, clef_name, clef_middle);
}
if (p_map) {
strcpy(tex_buf, "%%voicemap ");
get_str(&tex_buf[11], p_map, TEX_BUF_SZ - 12);
abc_new(ABC_T_PSCOM, tex_buf);
}
}
/* -- set default length from 'L:' -- */
static char *get_len(char *p,
struct SYMBOL *s)
{
int l1, l2, d;
char *error_txt = NULL;
if (strcmp(p, "auto") == 0) { /* L:auto */
ulen = 15120; // 2*2*2*2*3*3*3*5*7
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;
}
/* -- parse a 'M:' -- */
static char *parse_meter(char *p,
struct SYMBOL *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;
m1 = 0;
if (strncmp(p, "none", 4) == 0) {
p += 4; /* no meter */
wmeasure = 1; /* simplify measure numbering and MREST conversion */
} else {
wmeasure = 0;
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;
}
if (wmeasure > BASE_LEN * 16 || wmeasure < 0)
return "Too big meter value";
s->u.meter.wmeasure = wmeasure;
s->u.meter.nmeter = nm;
/* in the tune header, change the unit note length */
if (parse.abc_state == ABC_S_HEAD && ulen == 0) {
if (wmeasure >= BASE_LEN * 3 / 4
|| wmeasure <= 1)
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 SYMBOL *s)
{
char c, str[80];
int i, l, n, top, bot;
/* string before */
if (*p == '"') {
p = get_str(str, p, sizeof str);
s->u.tempo.str1 = getarena(strlen(str) + 1);
strcpy(s->u.tempo.str1, str);
}
/* beat */
if (*p == 'C' || *p == 'c'
|| *p == 'L' || *p == 'l') {
s->u.tempo.beats[0] = ulen;
if (parse.abc_vers >= (2 << 16))
syntax("Deprecated Q: value", p);
p++;
while (isspace((unsigned char) *p))
p++;
if (*p != '=')
goto inval;
c = '=';
p--;
} else if (isdigit((unsigned char) *p)) {
if (strchr(p, '/') != NULL) {
i = 0;
while (isdigit((unsigned char) *p)) {
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.beats
/ sizeof s->u.tempo.beats[0])
goto inval;
s->u.tempo.beats[i++] = l;
p += n;
while (isspace((unsigned char) *p))
p++;
}
c = *p;
if (c != '=')
goto inval;
} else {
s->u.tempo.beats[0] = ulen;
if (parse.abc_vers >= (2 << 16))
syntax("Deprecated Q: value", p);
c = '=';
p--;
}
} else {
c = '\0';
}
/* tempo value */
if (c == '=') {
p++;
if (strncmp(p, "ca. ", 4) == 0) {
s->u.tempo.circa = 1;
p += 4;
}
if (sscanf(p, "%d/%d%n", &top, &bot, &n) == 2) {
if (bot <= 0)
goto inval;
l = (BASE_LEN * top) / bot;
if (l <= 0)
goto inval;
s->u.tempo.new_beat = l;
} else {
if (sscanf(p, "%d%n", &top, &n) != 1)
goto inval;
s->u.tempo.tempo = top;
}
p += n;
while (isspace((unsigned char) *p))
p++;
}
/* string after */
if (*p == '"') {
p = get_str(str, p, sizeof str);
s->u.tempo.str2 = getarena(strlen(str) + 1);
strcpy(s->u.tempo.str2, str);
}
return 0;
inval:
return "Invalid tempo";
}
/* -- get a user defined symbol (U:) -- */
static char *get_user(char *p,
struct SYMBOL *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);
if (!s->u.user.value)
return 0;
/* treat special pseudo decorations */
value = parse.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 SYMBOL *s)
{
int voice;
char *error_txt = NULL;
char *clef_name, *clef_middle, *clef_stlines, *clef_scale;
char *p_octave, *p_cue, *p_map;
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->abc_prev->abc_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 (parse.abc_state == ABC_S_TUNE) {
ulen = curvoice->ulen;
microscale = curvoice->microscale;
}
/* parse the other parameters */
clef_name = clef_middle = clef_stlines = clef_scale = NULL;
p_octave = p_cue = p_map = 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_stlines,
&clef_scale, &p_octave, &p_cue, &p_map);
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(tex_buf, p, TEX_BUF_SZ);
s->u.voice.fname = getarena(strlen(tex_buf) + 1);
strcpy(s->u.voice.fname, tex_buf);
break;
case 1: /* subname */
p = get_str(tex_buf, p, TEX_BUF_SZ);
s->u.voice.nname = getarena(strlen(tex_buf) + 1);
strcpy(s->u.voice.nname, tex_buf);
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 (p_cue) {
if (strncmp(p_cue, "on", 2) == 0)
s->u.voice.cue = 1;
else
s->u.voice.cue = -1;
}
if (clef_stlines)
s->u.voice.stafflines = clef_stlines;
// else
// s->u.voice.stafflines = "|||||";
if (clef_scale) {
float sc;
sc = atof(clef_scale);
if (sc >= 0.5 && sc <= 3)
s->u.voice.staffscale = sc;
else
syntax("Bad value of staffscale", clef_scale);
}
if (clef_name || clef_middle) {
s = abc_new(ABC_T_CLEF, NULL);
parse_clef(s, clef_name, clef_middle);
}
if (p_map) {
strcpy(tex_buf, "%%voicemap ");
get_str(&tex_buf[11], p_map, TEX_BUF_SZ - 12);
abc_new(ABC_T_PSCOM, tex_buf);
}
return error_txt;
}
/* -- parse a bar -- */
static char *parse_bar(char *p)
{
struct SYMBOL *s;
char *q;
int bar_type, i;
char repeat_value[32];
q = --p; // keep the first char
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(ABC_T_BAR, gchord);
if (gchord)
gchord = NULL;
/* handle the repeat sequences */
if (bar_type == B_COL) {
bar_type = B_BAR;
s->u.bar.dotted = 1;
} else {
if (*q == ']') { /* repeat bar stop */
i = p - q - 1;
if (i > 0) /* remove the starting ']' */
s->u.bar.type &= (1 << (i * 4)) - 1;
s->flags |= ABC_F_RBSTOP;
s->sflags |= S_RBSTOP;
} else if ((bar_type & 0x0f) == B_COL /* left or */
|| *q == ':') { /* right repeat bar */
s->flags |= ABC_F_RBSTOP;
s->sflags |= S_RBSTOP;
if (*q == ':') /* right repeat bar */
s->sflags |= S_RRBAR;
}
}
s->u.bar.type = bar_type;
if (dc.n > 0) {
memcpy(&s->u.bar.dc, &dc, sizeof s->u.bar.dc);
dc.n = 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(ABC_T_BAR, repeat_value);
s->u.bar.type = B_OBRA;
} else {
s->text = getarena(strlen(repeat_value) + 1);
strcpy(s->text, repeat_value);
}
s->u.bar.repeat_bar = 1;
s->flags |= ABC_F_RBSTART | ABC_F_RBSTOP;
s->sflags |= S_RBSTART | S_RBSTOP;
return p;
}
// parse the note accidental and pitch
char *parse_acc_pit(char *p,
int *pit,
int *acc)
{
/* 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;
default:
*acc = 0;
}
/* 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;
}
} else {
d = 256; // assume a temperament equal
}
if (microscale == 0) {
d--;
d += (n - 1) << 8; /* short [ (n-1) | (d-1) ] */
if (d == 0) {
n = MAXMICRO - 1;
} else {
for (n = 1; n < MAXMICRO; n++) {
if (parse.micro_tb[n] == d)
break;
if (parse.micro_tb[n] == 0) {
parse.micro_tb[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 || *p == '\0') {
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++;
}
return p;
}
/* -- parse the decorations of notes and bars -- */
static char *parse_deco(char *p,
struct decos *deco,
int m) /* note index / -1 */
{
int n;
unsigned char t;
n = deco->n;
for (;;) {
t = (unsigned char) *p++;
if (char_tb[t] != CHAR_DECO && char_tb[t] != CHAR_DECOS)
break;
if (char_tb[t] == CHAR_DECOS)
p = get_deco(p, &t);
if (n >= MAXDC) {
syntax("Too many decorations for the note", p);
} else if (t != 0) {
deco->tm[n].t = t;
deco->tm[n++].m = m;
}
}
deco->n = n;
return p - 1;
}
/* -- parse a decoration line (d: or s:) -- */
static char *parse_decoline(char *p)
{
struct SYMBOL *is;
unsigned char t;
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->abc_type != ABC_T_BAR
|| is->u.bar.type == B_OBRA))
is = is->abc_next;
if (!is) {
syntax("Not enough bar lines for deco line", p);
return NULL;
}
is = is->abc_next;
p++;
continue;
case '*':
while (is && is->abc_type != ABC_T_NOTE)
is = is->abc_next;
if (!is) {
syntax("Not enough notes for deco line", p);
return NULL;
}
is = is->abc_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, &t);
else
t = (unsigned char) *p++;
break;
}
/* store the decoration and gchord/annotation in the next note */
while (is && (is->abc_type != ABC_T_NOTE
|| (is->flags & ABC_F_GRACE)))
is = is->abc_next;
if (!is)
return "Not enough notes for deco line";
if (gchord) {
if (is->text) {
char *gch;
n = strlen(is->text);
gch = getarena(n + strlen(gchord) + 2);
strcpy(gch, is->text);
gch[n] = '\n';
strcpy(gch + n + 1, gchord);
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 (t != 0) {
is->u.note.dc.tm[n].t = t;
is->u.note.dc.tm[n].m = -1;
is->u.note.dc.n = ++n;
}
}
is = is->abc_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 = getarena(l2 + 1 + l + 1);
strcpy(gch, gchord);
gch[l2++] = '\n';
strncpy(&gch[l2], q, l);
gch[l2 + l] = '\0';
gchord = gch;
} else {
gchord = getarena(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 dur_u,
int *p_len)
{
int len, fac;
int err = 0;
char *q;
len = dur_u;
if (isdigit((unsigned char) *p)) {
len *= strtol(p, &q, 10);
p = q;
}
if (*p == '/') {
if (isdigit((unsigned char) p[1])) {
fac = strtol(p + 1, &q, 10);
p = q;
if (fac == 0 || (fac & (fac - 1)))
err = 1;
else
len /= fac;
} else {
while (*p == '/') {
if (len & 1)
err = 1;
len /= 2;
p++;
}
}
if (err || !len) {
syntax("Bad length divisor", p - 1);
len = dur_u;
}
}
if (len <= 0 || len > 10000) {
syntax("Bad length", p);
len = dur_u;
}
*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(char *p)
{
struct SYMBOL *s;
char *q, c;
char *dot = NULL;
struct SYMBOL *last_note_sav = NULL;
struct decos 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 (parse.abc_state) {
case ABC_S_GLOBAL:
if (parse.last_sym
&& parse.last_sym->abc_type != ABC_T_NULL)
abc_new(ABC_T_NULL, NULL);
case ABC_S_HEAD: /*fixme: may have blank lines in headers?*/
return 0;
}
return 1;
case '%':
if (p[1] == '%') {
s = abc_new(ABC_T_PSCOM, p);
p += 2; /* skip '%%' */
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 (strncmp(p, "", 6) == 0)
return 0;
if (strncmp(p, "", 5) == 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, "microscale ", 11) == 0) {
int v;
p += 11;
while (isspace((unsigned char) *p))
p++;
sscanf(p, "%d", &v);
if (v < 4 || v >= 256 || v & 1)
syntax("Invalid value in %%microscale", p);
else
microscale = v;
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 */
return 0; /* skip */
}
/* header fields */
if (p[1] == ':'
&& *p != '|' && *p != ':') { /* not '|:' nor '::' */
int new_tune;
new_tune = parse_info(p);
/* handle BarFly voice definition */
/* 'V:n ' */
if (*p != 'V'
|| parse.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 (parse.abc_state != ABC_S_TUNE)
return 0;
/* music */
flags = 0;
if (parse.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 = 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;
parse.last_sym->flags |= ABC_F_GR_END;
if (dc.n != 0)
syntax("Decoration ignored", p);
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(ABC_T_EOLN, NULL); /* abc2win EOL */
s->u.eoln.type = 2;
break;
}
/* fall thru */
case CHAR_DECO:
if (p[-1] == '.') {
if (*p == '(' || *p == '-') {
dot = p;
break;
}
// if (*p == '|') {
// p = parse_bar(p + 1);
// parse.last_sym->u.bar.dotted = 1;
// break;
// }
}
p = parse_deco(p - 1, &dc, -1);
break;
case CHAR_LINEBREAK:
s = abc_new(ABC_T_EOLN, NULL);
// s->u.eoln.type = 0;
break;
case CHAR_NOTE:
p = parse_note(p - 1, flags);
flags &= ABC_F_GRACE;
if (slur && parse.last_sym->u.note.notes[0].len) {
parse.last_sym->u.note.slur_st = slur;
slur = 0;
}
break;
case CHAR_SLASH: /* '/' */
if (flags & ABC_F_GRACE)
goto bad_char;
if (char_tb[(unsigned char) p[-1]] != CHAR_BAR)
goto bad_char;
q = p;
while (*q == '/')
q++;
if (char_tb[(unsigned char) *q] != CHAR_BAR)
goto bad_char;
s = abc_new(ABC_T_MREP, NULL);
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(p);
break;
}
if (p[1] != ':') {
p = parse_note(p - 1, flags); /* chord */
flags &= ABC_F_GRACE;
if (slur && parse.last_sym->u.note.notes[0].len) {
parse.last_sym->u.note.slur_st = slur;
slur = 0;
}
break;
}
/* embedded information field */
#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(q);
*p = c;
if (c != '\0')
p++;
break;
case CHAR_BAR: /* '|', ':' or ']' */
if (flags & ABC_F_GRACE)
goto bad_char;
p = parse_bar(p);
break;
case CHAR_OPAR: /* '(' */
if (*p > '0' && *p <= '9') {
int pplet, qplet, rplet;
pplet = strtol(p, &q, 10);
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 (rplet < 1) {
syntax("Invalid 'r' in tuplet", p);
break;
}
if (pplet >= 128 || qplet >= 128 || rplet >= 128) {
syntax("Invalid 'p:q:r' in tuplet", p);
break;
}
if (qplet == 0)
qplet = meter % 3 == 0 ? 3 : 2;
s = abc_new(ABC_T_TUPLET, NULL);
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(ABC_T_V_OVER, NULL);
s->u.v_over.type = V_OVER_S;
s->u.v_over.voice = curvoice - voice_tb;
vover = -1; /* multi-bars */
break;
}
slur <<= 4;
if (p == dot + 1 && 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 (parse.last_sym->abc_type) {
case ABC_T_NOTE:
case ABC_T_REST:
break;
default:
goto bad_char;
}
parse.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(ABC_T_V_OVER, NULL);
/*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(ABC_T_V_OVER, NULL);
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->abc_type != ABC_T_NOTE)
goto bad_char;
if (p == dot + 1 && 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->nhd; i++) {
if (curvoice->last_note->u.note.notes[i].ti1 == 0)
curvoice->last_note->u.note.notes[i].ti1 = tie_pos;
else if (curvoice->last_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;
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(ABC_T_EOLN, NULL);
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(char *p,
int flags)
{
struct SYMBOL *s;
char *q;
int pit = 0, len, acc, nostem, chord, j, m, n;
if (flags & ABC_F_GRACE) { /* in a grace note sequence */
s = abc_new(ABC_T_NOTE, NULL);
} else {
s = abc_new(ABC_T_NOTE, gchord);
if (gchord)
gchord = NULL;
}
s->flags |= flags;
s->u.note.notes[0].color = -1;
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;
}
chord = 0;
/* rest */
switch (*p) {
case 'X':
s->flags |= ABC_F_INVIS;
case 'Z': /* multi-rest */
s->abc_type = ABC_T_MREST;
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->abc_type = ABC_T_REST;
s->flags |= ABC_F_INVIS;
p++;
if (isdigit((unsigned char) *p) /* number of points */
|| *p == '-') { /* accept negative offset... */
len = strtol(p, &q, 10);
if (len < -100 || len > 100) {
syntax("Bad width of y (space)", p);
len = 10;
}
p = q;
} else {
len = 10; // default
}
s->u.note.notes[0].shhd = len;
goto add_deco;
case 'x': /* invisible rest */
s->flags |= ABC_F_INVIS;
/* fall thru */
case 'z':
s->abc_type = ABC_T_REST;
p = parse_len(p + 1, ulen, &len);
s->u.note.notes[0].len = len;
goto do_brhythm;
case '[': /* '[..]' = chord */
chord = 1;
p++;
break;
}
q = p;
/* get pitch, length and possible accidental */
m = 0;
nostem = 0;
for (;;) {
if (chord) {
if (m >= MAXHD) {
syntax("Too many notes in chord", p);
m--;
}
n = 0;
if (*p == '.') {
n = SL_DOTTED;
p++;
}
if (*p == '(') {
p++;
switch (*p) {
case '\'':
n += SL_ABOVE;
p++;
break;
case ',':
n += SL_BELOW;
p++;
break;
default:
n += SL_AUTO;
break;
}
s->u.note.notes[m].sl1 = (s->u.note.notes[m].sl1 << 3)
+ n;
}
}
p = parse_deco(p, &dc, m); /* note head decorations */
p = parse_acc_pit(p, &pit, &acc);
if (*p == '0') {
nostem = 1;
p++;
}
p = parse_len(p, (flags & ABC_F_GRACE) ?
BASE_LEN / 8 : // for grace note alone
ulen,
&len);
s->u.note.notes[m].pit = pit;
s->pits[m] = pit;
s->u.note.notes[m].len = len;
s->u.note.notes[m].acc = acc;
s->u.note.notes[m].color = -1;
if (chord) {
for (;;) {
if (*p == '.') {
if (p[1] != '-')
break;
p++;
}
if (*p == '-') {
switch (p[1]) {
case '\'':
s->u.note.notes[m].ti1 = SL_ABOVE;
p++;
break;
case ',':
s->u.note.notes[m].ti1 = SL_BELOW;
p++;
break;
default:
s->u.note.notes[m].ti1 = SL_AUTO;
break;
}
} else if (*p == ')') {
s->u.note.notes[m].sl2++;
} 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, ulen, &len);
for (j = 0; j < m; j++) {
s->u.note.notes[j].len =
len * s->u.note.notes[j].len / ulen;
}
}
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->nhd = m - 1;
do_brhythm:
if (curvoice->last_note
&& curvoice->last_note->u.note.brhythm != 0) {
broken_rhythm(curvoice->last_note,
curvoice->last_note->u.note.brhythm);
broken_rhythm(s, -curvoice->last_note->u.note.brhythm);
}
add_deco:
if (dc.n > 0) {
memcpy(s->abc_type != ABC_T_MREST ? &s->u.note.dc
: &s->u.bar.dc,
&dc, sizeof dc);
dc.n = 0;
}
/* forbid rests in grace note sequences */
if (s->abc_type != ABC_T_NOTE && (flags & ABC_F_GRACE)) {
syntax("Not a note in grace note sequence", p);
goto err;
}
if (s->u.note.notes[0].len > 0) /* if not space */
curvoice->last_note = s;
return p;
err:
if ((parse.last_sym = s->abc_prev) == NULL) {
parse.first_sym = NULL;
} else {
s->abc_prev->abc_next = NULL;
s->abc_prev->flags |= (s->flags & ABC_F_ERROR);
}
return p;
}
/* -- parse an information field -- */
/* return 2 on start of new tune */
static int parse_info(char *p)
{
struct SYMBOL *s;
char info_type = *p;
char *error_txt = NULL;
s = abc_new(ABC_T_INFO, p);
p += 2;
switch (info_type) {
case 'd':
case 's':
if (parse.abc_state == ABC_S_GLOBAL)
break;
if (!deco_start) {
error_txt = "Erroneous 'd:'/'s:'";
break;
}
error_txt = parse_decoline(p);
break;
case 'K':
if (parse.abc_state == ABC_S_GLOBAL)
break;
parse_key(p, s);
if (parse.abc_state == ABC_S_HEAD) {
int i;
parse.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 (parse.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;
parse.abc_state = ABC_S_HEAD;
lvlarena(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-8.14.17/accordion.abc 0000644 0000000 0000000 00000004450 14754371067 0015230 0 ustar 00nobody nobody % 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-8.14.17/bravura.abc 0000644 0000000 0000000 00000004727 14754371067 0014740 0 ustar 00nobody nobody % example of musical symbols by Bravura
% --- definitions for SVG output ---
%%beginsvg
%%endsvg
% --- definitions for PostScript output ---
%%beginps nosvg
/brace{/Bravura 24 selectfont
gsave
T -7.5 0 M -.042 mul 3 exch scale
/uniE000 glyphshow
grestore}!
/tclef{/Bravura 24 selectfont M -8 6 RM/uniE050 glyphshow}!
/cclef{/Bravura 24 selectfont M -8 12 RM/uniE05C glyphshow}!
/bclef{/Bravura 24 selectfont M -8 18 RM/uniE062 glyphshow}!
/csig{/Bravura 24 selectfont M -5 12 RM/uniE08A glyphshow}!
/ft0{/Bravura 24 selectfont M -2 0 RM/uniE260 glyphshow}!
/nt0{/Bravura 24 selectfont M -2 0 RM/uniE261 glyphshow}!
/sh0{/Bravura 24 selectfont M -2 0 RM/uniE262 glyphshow}!
/dsh0{/Bravura 24 selectfont M -2 0 RM/uniE263 glyphshow}!
/dft0{/Bravura 24 selectfont M -3 0 RM/uniE264 glyphshow}!
/turn{/Bravura 24 selectfont M -4 0 RM/uniE567 glyphshow}!
%%endps
abcm2ps-8.14.17/buffer.c 0000644 0000000 0000000 00000055060 14754371067 0014240 0 ustar 00nobody nobody /*
* Postscript buffering functions.
*
* This file is part of abcm2ps.
*
* Copyright (C) 1998-2019 Jean-François Moine
* Adapted from abc2ps, Copyright (C) 1996-1998 Michael Methfessel
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*/
#include
#include
#include
#include
#include "abcm2ps.h"
#define PPI_96_72 0.75 // convert page format to 72 PPI
#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 max_rmarg; /* margins for -E/-g */
static float cur_scale = 1.0; /* current scale */
static float maxy; /* usable vertical space in page */
static float remy; /* 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 */
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 */
int (*output)(FILE *out, const char *fmt, ...)
#ifdef __GNUC__
__attribute__ ((format (printf, 2, 3)))
#endif
;
/* -- 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 -- */
void open_fout(void)
{
int i;
char fnm[FILENAME_MAX];
strcpy(fnm, outfn);
i = strlen(fnm) - 1;
if (i < 0) {
strcpy(fnm, svg || epsf > 1 ? "Out.xhtml" : OUTPUTFILE);
} else if (i != 0 || fnm[0] != '-') {
if (fnm[i] == '=' && in_fname) {
char *p;
if ((p = strrchr(in_fname, DIRSEP)) == NULL)
p = in_fname;
else
p++;
strcpy(&fnm[i], p);
strext(fnm, svg || epsf > 1 ? "xhtml" : "ps");
} else if (fnm[i] == DIRSEP) {
strcpy(&fnm[i + 1],
svg || epsf > 1 ? "Out.xhtml" : 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)
{
cur_lmarg = max_rmarg = 0;
}
/* -- initialize the postscript file (PS or EPS) -- */
static void init_ps(char *str)
{
time_t ltime;
unsigned i;
char version[] = "/creator [(abcm2ps) " VERSION "] def";
if (epsf) {
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) * PPI_96_72,
-bposy * PPI_96_72);
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 * PPI_96_72,
p_fmt->pageheight * PPI_96_72);
}
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");
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"
" <pagewidth * PPI_96_72,
p_fmt->pageheight * PPI_96_72);
if (cfmt.gutter)
fprintf(fout,
"\n /BeginPage{1 and 0 eq{%.1f 0 T}{%.1f 0 T}ifelse}bind\n ",
cfmt.gutter, -cfmt.gutter);
fprintf(fout, ">>setpagedevice}if\n");
}
fprintf(fout, "%%%%EndSetup\n");
file_initialized = 1;
}
/* -- initialize the svg file (option '-g') -- */
static void init_svg(char *str)
{
output = svg_output;
#if 1 //fixme:test
if (file_initialized > 0)
fprintf(stderr, "??? init_svg: file_initialized\n");
#endif
define_svg_symbols(str, nepsf,
(p_fmt->landscape ? p_fmt->pageheight : p_fmt->pagewidth)
- cur_lmarg - max_rmarg,
-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)
printf("Output written on %s (%ld bytes)\n",
outfnam, m);
else
printf("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();
switch (svg) {
case 0: /* PS */
if (epsf == 0)
fprintf(fout, "%%%%Trailer\n"
"%%%%Pages: %d\n"
"%%EOF\n", nbpages);
close_fout();
break;
case 2: /* -X */
fputs("