pianobooster-src-0.6.4b/ 0000755 0001747 0001747 00000000000 11367323540 014622 5 ustar ubuntu ubuntu pianobooster-src-0.6.4b/src/ 0000755 0001747 0001747 00000000000 11367323540 015411 5 ustar ubuntu ubuntu pianobooster-src-0.6.4b/win32/ 0000755 0001747 0001747 00000000000 11367323537 015572 5 ustar ubuntu ubuntu pianobooster-src-0.6.4b/build/ 0000755 0001747 0001747 00000000000 11367323537 015727 5 ustar ubuntu ubuntu pianobooster-src-0.6.4b/src/precompile/ 0000755 0001747 0001747 00000000000 11367323540 017550 5 ustar ubuntu ubuntu pianobooster-src-0.6.4b/src/rtmidi/ 0000755 0001747 0001747 00000000000 11367323540 016701 5 ustar ubuntu ubuntu pianobooster-src-0.6.4b/src/images/ 0000755 0001747 0001747 00000000000 11367323540 016656 5 ustar ubuntu ubuntu pianobooster-src-0.6.4b/BUILD.txt 0000644 0001747 0001747 00000006423 11303331101 016205 0 ustar ubuntu ubuntu ===============================================================================================
TO COMPILE THE SOURCE CODE IN LINUX
===============================================================================================
Ensure that the following packages 'cmake', 'libqt4-dev', 'libasound2-dev' and
'build-essential" are installed .
In the PianoBooster directory type "cd build" to change to the "build" directory
then type "cmake ../src", followed by "make". Finally as root type "make install".
To build a debug version create a dir called "debug" and change to that dir and then
type "cmake -DCMAKE_BUILD_TYPE=Debug ../src"
(Alternatively you can use qmake followed by make in the src directory.)
If you make changes to the source code then please post details on the forum.
===============================================================================================
TO COMPILE THE SOURCE CODE IN MacOSX
===============================================================================================
Install latest XCode (from Apple Developer Connection, free registration required)
Install CMake and QT libraries (either from source or via Fink or MacPorts)
Generate XCode project file, via 'cmake -G Xcode ../src'
Open the project file in XCode, set whatever options you like (universal or single architecture,
debug or release etc.) and compile
To make a self contained application bundle use QT's macdeployqt tool (included in QT 4.5.0)
If you make changes to the source code then please post details on the forum.
===============================================================================================
TO COMPILE THE SOURCE CODE IN WINDOWS
===============================================================================================
To compile in Windows install the Open Source version of Qt and CMake and optionally Geany.
When installing Qt select the option to download and install the MinGW compiler. Open the
Qt Command Prompt and then change to the "PianoBooster\build" directory and then type the
command below.
"C:\Program Files\CMake 2.6\bin\cmake.exe" -G "MinGW Makefiles" ..\src
Once this is completed type "make".
Or alternatively you can install QtCreator and then open the painobooster.pro
If you make changes to the source code then please post details on the forum.
===============================================================================================
LICENSE
===============================================================================================
Piano Booster is fully copyrighted by the author and all rights are reserved.
PianoBooster is free software (Open Source 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.
PianoBooster 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 in the file "gplv3.txt" or from the web site
.
pianobooster-src-0.6.4b/README.txt 0000644 0001747 0001747 00000007743 11303577704 016336 0 ustar ubuntu ubuntu ===============================================================================================
INTRODUCTION
===============================================================================================
Piano Booster is a MIDI file player that displays the musical notes AND teaches you how to
play the piano. You can play along to any track in the midi file and PianoBooster will
follow YOUR playing. PianoBooster makes sight reading fun!
Piano Booster is a free (Open Source) program available from:
===============================================================================================
REQUIREMENTS
===============================================================================================
To run Piano Booster you need a MIDI Piano Keyboard and a MIDI interface for the PC. (If you
don't have a MIDI keyboard you can still try out PianoBooster using the PC keyboard, 'x' is
middle C -- but a MIDI piano is recommend).
To hear the music you will need a General Midi compatible sound synthesizer. Unfortunately
the "Microsoft GS Wavetable software synthesizer" that comes with Windows XP introduces an
unacceptable delay (latency) between pressing a note and hearing the sound. For this reason
the use of "Microsoft GS Wavetable software synthesizer" is not recommend. Please see the
forum section of the PianoBooster website for possible solutions.
===============================================================================================
MIDI FILES
===============================================================================================
To run PianoBooster you will need some Midi files preferably with right and left piano
parts on channels 4 and 3. Some high quality demo MIDI files that are compatible with
PianoBooster are available on the PianoBooster download page see:
===============================================================================================
INSTRUCTIONS
===============================================================================================
Once the Piano Booster application starts up you must first setup the midi input and midi
output interface from the Setup menu. Next open a midi file ".mid" or a karaoke ".kar" file
using File/Open from the Piano Booster menu. Now choose the skill level, if you want to
just listen to the midi music -- select 'listen', to play along with a midi keyboard with
the music following your playing -- select 'follow you'. Finally click on the Play icon to
start.
It is recommended that you shut down all other programs whilst running Piano Booster so that
the scrolling notes move smoothly across the screen.
===============================================================================================
LICENSE
===============================================================================================
Piano Booster is fully copyrighted by the author and all rights are reserved.
PianoBooster is free software (Open Source 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.
PianoBooster 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 in the file "gplv3.txt" or from the web site
.
===============================================================================================
SOURCE CODE
===============================================================================================
As part of GNU General Public License the source code for PianoBooster is available from
the Source Forge site
pianobooster-src-0.6.4b/gplv3.txt 0000644 0001747 0001747 00000104513 11113100175 016404 0 ustar ubuntu ubuntu 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
.
pianobooster-src-0.6.4b/README-OSX.txt 0000755 0001747 0001747 00000010324 11164241346 016770 0 ustar ubuntu ubuntu ===============================================================================================
INTRODUCTION
===============================================================================================
Piano Booster is a MIDI file player that displays the musical notes AND teaches you how to
play the piano. You can play along to any track in the midi file and PianoBooster will
follow YOUR playing. PianoBooster makes sight reading fun!
Piano Booster is a free (Open Source) program available from:
===============================================================================================
REQUIREMENTS
===============================================================================================
To run Piano Booster you need a MIDI Piano Keyboard and a MIDI-USB interface if the keyboard
does not have a USB interface. (If you don't have a MIDI keyboard you can still try out
PianoBooster using the computer's keyboard, 'x' is middle C).
To hear music from the computer you will need a General Midi compatible sound synthesizer.
While there are many possible choices for the Mac (Timidity, FluidSynth or an external MIDI
Synth), the easiest way is to use SimplSynth, which can be obtained for free (MIT license)
from:
This must be started before Pianobooster, and also allows to load custom Soundfonts.
===============================================================================================
MIDI FILES
===============================================================================================
To run PianoBooster you will need some Midi files preferably with right and left piano
parts on channels 4 and 3. Some high quality demo MIDI files that are compatible with
PianoBooster are available on the PianoBooster download page see:
===============================================================================================
INSTRUCTIONS
===============================================================================================
Double Click on the DMG file containing PianoBooster, then just drag the pianobooster.app
file wherever you wish (/Application folder is suggested).
Once the Piano Booster application starts up you must first setup the midi input and midi
output interface from the Setup menu. Next open a midi file ".mid" or a karaoke ".kar" file
using File/Open from the Piano Booster menu. Now choose the skill level, if you want to
just listen to the midi music -- select 'listen', to play along with a midi keyboard with
the music following your playing -- select 'follow you'. Finally click on the Play icon to
start.
It is recommended that you shut down all other programs whilst running Piano Booster so that
the scrolling notes move smoothly across the screen.
===============================================================================================
LICENSE
===============================================================================================
Piano Booster is fully copyrighted by the author and all rights are reserved.
PianoBooster is free software (Open Source 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.
PianoBooster 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 in the file "gplv3.txt" or from the web site
.
===============================================================================================
SOURCE CODE
===============================================================================================
As part of GNU General Public License the source code for PianoBooster is available from
the Source Forge site
pianobooster-src-0.6.4b/license.txt 0000644 0001747 0001747 00000001357 11303577704 017016 0 ustar ubuntu ubuntu Copyright (c) 2008,2009 L. J. Barman, all rights reserved
The PianoBooster application
PianoBooster 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.
PianoBooster 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 PianoBooster. If not, see .
pianobooster-src-0.6.4b/src/pianobooster.ico 0000755 0001747 0001747 00000001376 11303067705 020621 0 ustar ubuntu ubuntu ( @ DDDDDDD DDDDDDD""""""""B""""""""""""""b""""b"" DDDDDDD DDDDDDD DDDDDDD A DDDDDDD Gw DDDDDDD wx DDDDDDD&h""""""""B"""""b""""b"" xw wxDDDDDD wwx wwwtDDDDD `wwwxDDDDD wwwwDDUTDD wwwDEDD wxD]D""""""""""""""""""""""b DDD]T DDDD]D DDDDDUTD DDDDDDD DDDDDDD DDDDDDD""""""""b""""b""""""""""b""""b"" DDDDDDD DDDDDDD DDDDDDD DDDDDDD pianobooster-src-0.6.4b/src/GuiMidiSetupDialog.cpp 0000644 0001747 0001747 00000017432 11303577704 021617 0 ustar ubuntu ubuntu /*!
@file GuiMidiSetupDialog.cpp
@brief xxx.
@author L. J. Barman
Copyright (c) 2008-2009, L. J. Barman, all rights reserved
This file is part of the PianoBooster application
PianoBooster 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.
PianoBooster 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 PianoBooster. If not, see .
*/
#include
#include "GuiMidiSetupDialog.h"
GuiMidiSetupDialog::GuiMidiSetupDialog(QWidget *parent)
: QDialog(parent)
{
m_song = 0;
m_settings = 0;
setupUi(this);
m_latencyFix = 0;
m_latencyChanged = false;
m_midiChanged = false;
midiSetupTabWidget->setCurrentIndex(0);
#if !PB_USE_FLUIDSYNTH
midiSetupTabWidget->removeTab(1);
#endif
setWindowTitle("Midi Setup");
}
void GuiMidiSetupDialog::init(CSong* song, CSettings* settings)
{
m_song = song;
m_settings = settings;
// Check inputs.
QString portName;
int i = 0;
m_latencyFix = m_song->getLatencyFix();
midiInputCombo->addItem(tr("None (PC Keyboard)"));
midiInputCombo->addItems(song->getMidiPortList(CMidiDevice::MIDI_INPUT));
// Check outputs.
midiOutputCombo->addItem(tr("None"));
midiOutputCombo->addItems(song->getMidiPortList(CMidiDevice::MIDI_OUTPUT));
i = midiInputCombo->findText(m_settings->value("Midi/Input").toString());
if (i!=-1)
midiInputCombo->setCurrentIndex(i);
i = midiOutputCombo->findText(m_settings->value("Midi/Output").toString());
if (i!=-1)
midiOutputCombo->setCurrentIndex(i);
sampleRateCombo->addItem("44100");
sampleRateCombo->addItem("22050");
i = sampleRateCombo->findText(m_settings->value("Fliudsynth/SampleRate").toString());
if (i!=-1)
sampleRateCombo->setCurrentIndex(i);
//midiSettingsSetnum
updateMidiInfoText();
}
void GuiMidiSetupDialog::updateMidiInfoText()
{
QString str;
midiInfoText->clear();
if (midiInputCombo->currentIndex() == 0)
midiInfoText->append("If you don't have a MIDI keyboard you can use the PC keyboard; 'X' is middle C.");
else if (midiInputCombo->currentText().startsWith("Midi Through", Qt::CaseInsensitive))
midiInfoText->append("The use of Midi Through is not recommended!");
else
midiInfoText->append("Midi Input Device: " + midiInputCombo->currentText() +"");
if (midiOutputCombo->currentText() == "None")
midiInfoText->append("No Sound Output Device selected; Choose a Midi Output Device ");
else if (midiOutputCombo->currentText().startsWith("Midi Through", Qt::CaseInsensitive))
midiInfoText->append("The use of Midi Through is not recommended!");
else if (midiOutputCombo->currentText().startsWith("Microsoft GS Wavetable SW Synth", Qt::CaseInsensitive))
midiInfoText->append("Note: the Microsoft SW Synth introduces an unwanted delay!");
else
midiInfoText->append("Midi Output Device: " + midiOutputCombo->currentText() +"");
latencyFixLabel->setText(tr("%1 mSec").arg(m_latencyFix));
updateFluidInfoText();
}
void GuiMidiSetupDialog::on_midiInputCombo_activated (int index)
{
m_midiChanged = true;
updateMidiInfoText();
}
void GuiMidiSetupDialog::on_midiOutputCombo_activated (int index)
{
m_midiChanged = true;
updateMidiInfoText();
}
void GuiMidiSetupDialog::on_latencyFixButton_clicked ( bool checked )
{
bool ok;
int latencyFix = QInputDialog::getInteger(this, tr("Enter a value for the latency fix in milliseconds"),
tr(
"The latency fix works by running the music ahead of what you
"
"are playing to counteract the delay within the sound generator.
"
"You will need a piano with speakers that are turned up.
"
"Enter the time in milliseconds for the delay (1000 mSec = 1 sec)
"
"(For the Microsoft GS Wavetable SW Synth try a value of 150)
"
"If you are not sure enter a value of zero."),
m_latencyFix, 0, 1000, 50, &ok);
if (ok)
{
m_latencyFix = latencyFix;
m_latencyChanged = true;
updateMidiInfoText();
}
}
void GuiMidiSetupDialog::accept()
{
m_settings->setValue("Midi/Input", midiInputCombo->currentText());
m_song->openMidiPort(CMidiDevice::MIDI_INPUT, midiInputCombo->currentText() );
if (midiInputCombo->currentText().startsWith("None"))
CChord::setPianoRange(PC_KEY_LOWEST_NOTE, PC_KEY_HIGHEST_NOTE);
else
CChord::setPianoRange(m_settings->value("Keyboard/LowestNote", 0).toInt(),
m_settings->value("Keyboard/HighestNote", 127).toInt());
if (m_latencyChanged == false || m_midiChanged == true)
{
m_settings->setValue("Midi/Output", midiOutputCombo->currentText());
m_song->openMidiPort(CMidiDevice::MIDI_OUTPUT, midiOutputCombo->currentText() );
m_settings->updateWarningMessages();
}
m_settings->setValue("Midi/Latency", m_latencyFix);
m_song->setLatencyFix(m_latencyFix);
m_song->regenerateChordQueue();
if (m_latencyChanged)
{
if( m_latencyFix> 0)
{
int rightSound = m_settings->value("Keyboard/RightSound", Cfg::defaultRightPatch()).toInt();
m_settings->setValue("Keyboard/RightSoundPrevious", rightSound); // Save the current right sound
// Mute the Piano if we are using the latency fix;
m_settings->setValue("Keyboard/RightSound", 0);
m_song->setPianoSoundPatches( -1, -2); // -1 means no sound and -2 means ignore this parameter
}
else
{
int previousRightSound = m_settings->value("Keyboard/RightSoundPrevious", Cfg::defaultRightPatch()).toInt();
m_settings->setValue("Keyboard/RightSound", previousRightSound);
m_song->setPianoSoundPatches(previousRightSound, -2); // -2 means ignore this parameter
}
}
this->QDialog::accept();
}
void GuiMidiSetupDialog::updateFluidInfoText()
{
QStringList soundFontNames = m_settings->getFluidSoundFontNames();
soundFontList->clear();
for (int i=0; i < soundFontNames.count(); i++)
{
int n = soundFontNames.at(i).lastIndexOf("/");
soundFontList->addItem(soundFontNames.at(i).mid(n+1));
}
bool fontLoaded = (soundFontList->count() > 0) ? true : false;
fluidRemoveButton->setEnabled(fontLoaded);
fluidAddButton->setEnabled(soundFontList->count() < 2 ? true : false);
fluidSettingsGroupBox->setEnabled(fontLoaded);
}
void GuiMidiSetupDialog::on_fluidAddButton_clicked ( bool checked )
{
QString lastSoundFont;
QStringList sfList = m_settings->getFluidSoundFontNames();
if (sfList.size() > 0)
lastSoundFont = sfList.last();
QString soundFontName = QFileDialog::getOpenFileName(this,tr("Open SoundFont2 File for fluid synth"),
lastSoundFont, tr("SoundFont2 Files (*.sf2)"));
if (!soundFontName.isEmpty())
m_settings->addFluidSoundFontName(soundFontName);
updateFluidInfoText();
}
void GuiMidiSetupDialog::on_fluidRemoveButton_clicked ( bool checked )
{
}
pianobooster-src-0.6.4b/src/Util.h 0000644 0001747 0001747 00000004241 11272026477 016504 0 ustar ubuntu ubuntu /*********************************************************************************/
/*!
@file Util.h
@brief xxxx.
@author L. J. Barman
Copyright (c) 2008-2009, L. J. Barman, all rights reserved
This file is part of the PianoBooster application
PianoBooster 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.
PianoBooster 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 PianoBooster. If not, see .
*/
/*********************************************************************************/
#ifndef __UTIL_H__
#define __UTIL_H__
#include
#include
#include
using namespace std;
#define MAX_MIDI_CHANNELS 16
#define MIDDLE_C 60
#define MIDI_OCTAVE 12
#define MIDI_BOTTOM_C (MIDDLE_C - MIDI_OCTAVE*2)
#define MIDI_TOP_C (MIDDLE_C + MIDI_OCTAVE*2)
#define MAX_MIDI_NOTES 128
typedef unsigned char byte;
#define arraySize(a) (sizeof(a)/sizeof(a[0])) /* Returns (at compile time) the number of elements in an array */
#define ppDEBUG(args) ppLogDebug args
typedef enum
{
PB_LOG_error,
PB_LOG_warn,
PB_LOG_info,
PB_LOG_verbose,
} logLevel_t;
void fatal(const char *msg, ...);
void ppLogTrace(const char *msg, ...);
void ppLogDebug(const char *msg, ...);
void ppLog(logLevel_t level, const char *msg, ...);
void ppLogInfo(const char *msg, ...);
void ppLogWarn(const char *msg, ...);
void ppLogError(const char *msg, ...);
void ppTiming(const char *msg, ...);
#define SPEED_ADJUST_FACTOR 1000
#define deltaAdjust(delta) ((delta)/SPEED_ADJUST_FACTOR )
void benchMarkInit();
void benchMark(unsigned int id, QString message);
void benchMarkResults();
#endif //__UTIL_H__
pianobooster-src-0.6.4b/src/Score.h 0000644 0001747 0001747 00000007253 11367323106 016642 0 ustar ubuntu ubuntu /*********************************************************************************/
/*!
@file Score.h
@brief xxx.
@author L. J. Barman
Copyright (c) 2008-2009, L. J. Barman, all rights reserved
This file is part of the PianoBooster application
PianoBooster 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.
PianoBooster 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 PianoBooster. If not, see .
*/
/*********************************************************************************/
#ifndef _SCORE_H_
#define _SCORE_H_
#include "Scroll.h"
#include "Piano.h"
#include "Settings.h"
class CScore : public CDraw
{
public:
CScore(CSettings* settings);
~CScore();
void init();
//! add a midi event to be analysed and displayed on the score
void midiEventInsert(CMidiEvent event)
{ size_t i;
for (i=0; i < arraySize(m_scroll); i++)
{
m_scroll[i]->midiEventInsert(event);
}
}
//! first check if there is space to add a midi event
int midiEventSpace()
{
size_t i;
int minSpace;
int space;
minSpace = 1000;
for (i=0; i< arraySize(m_scroll); i++) // this maybe slow
{
space = m_scroll[i]->midiEventSpace();
if (space < minSpace)
minSpace = space;
}
return minSpace;
}
void transpose(int semitones)
{ size_t i;
for (i=0; i< arraySize(m_scroll); i++)
m_scroll[i]->transpose(semitones);
}
void reset()
{ size_t i;
for (i=0; i< arraySize(m_scroll); i++)
m_scroll[i]->reset();
}
void drawScrollingSymbols(bool show = true)
{ size_t i;
for (i=0; i< arraySize(m_scroll); i++)
m_scroll[i]->drawScrollingSymbols(show);
}
void scrollDeltaTime(int ticks)
{ size_t i;
for (i=0; i< arraySize(m_scroll); i++)
m_scroll[i]->scrollDeltaTime(ticks);
}
void setRatingObject(CRating* rating)
{
m_rating = rating;
}
CPiano* getPianoObject() { return m_piano;}
void setPlayedNoteColour(int note, CColour colour, int wantedDelta, int pianistTimming = NOT_USED)
{
m_scroll[m_activeScroll]->setPlayedNoteColour(note, colour, wantedDelta, pianistTimming);
}
void setActiveChannel(int channel)
{
int newActiveSroll;
if (channel < 0 || channel >= static_cast(arraySize(m_scroll)))
return;
newActiveSroll = channel;
if (m_activeScroll != newActiveSroll)
{
m_scroll[m_activeScroll]->showScroll(false);
m_activeScroll = newActiveSroll;
m_scroll[m_activeScroll]->showScroll(true);
}
}
void refreshScroll() { m_scroll[m_activeScroll]->refresh(); }
void setDisplayHand(whichPart_t hand)
{
CDraw::setDisplayHand(hand);
refreshScroll();
}
void drawScore();
void drawScroll(bool refresh);
protected:
CPiano* m_piano;
private:
CRating* m_rating;
CScroll* m_scroll[MAX_MIDI_CHANNELS];
int m_activeScroll;
GLuint m_scoreDisplayListId;
GLuint m_stavesDisplayListId;
};
#endif // _SCORE_H_
pianobooster-src-0.6.4b/src/GuiSidePanel.h 0000644 0001747 0001747 00000010777 11303063627 020104 0 ustar ubuntu ubuntu /*********************************************************************************/
/*!
@file GuiSidePanel.h
@brief xxxx.
@author L. J. Barman
Copyright (c) 2008-2009, L. J. Barman, all rights reserved
This file is part of the PianoBooster application
PianoBooster 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.
PianoBooster 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 PianoBooster. If not, see .
*/
/*********************************************************************************/
#ifndef __GUISIDEPANEL_H__
#define __GUISIDEPANEL_H__
#include
#include "Song.h"
#include "Score.h"
#include "TrackList.h"
#include "Settings.h"
#include "ui_GuiSidePanel.h"
class GuiTopBar;
class GuiSidePanel : public QWidget, private Ui::GuiSidePanel
{
Q_OBJECT
public:
GuiSidePanel(QWidget *parent, CSettings* settings);
void init(CSong* songObj, CTrackList* trackList, GuiTopBar* topBar);
void refresh();
void loadBookList();
void setBookName(QString bookName);
void setSongName(QString songName);
int getSongIndex() {return songCombo->currentIndex();}
void setSongIndex(int index){songCombo->setCurrentIndex(index);}
void setCurrentHand(QString hand);
void setActiveHand(whichPart_t hand)
{
if (hand == PB_PART_right) rightHandRadio->setChecked(true);
if (hand == PB_PART_both) bothHandsRadio->setChecked(true);
if (hand == PB_PART_left) leftHandRadio->setChecked(true);
}
void nextSong(int amount)
{
int n = songCombo->currentIndex() + amount;
if (n < 0 || n >= songCombo->count())
return;
songCombo->setCurrentIndex(n);
on_songCombo_activated(n);
}
private slots:
void on_songCombo_activated (int index);
void on_bookCombo_activated (int index);
void on_rightHandRadio_toggled (bool checked);
void on_bothHandsRadio_toggled (bool checked);
void on_leftHandRadio_toggled (bool checked);
void on_trackListWidget_currentRowChanged(int currentRow) {
if (m_trackList){
m_trackList->currentRowChanged(currentRow);
autoSetMuteYourPart();
}
}
void on_boostSlider_valueChanged(int value) {
if (m_song) m_song->boostVolume(value);
}
void on_pianoSlider_valueChanged(int value) {
if (m_song) m_song->pianoVolume(value);
}
void on_listenRadio_toggled (bool checked)
{
if (!m_song || !checked) return;
m_song->setPlayMode(PB_PLAY_MODE_listen);
}
void on_followYouRadio_toggled (bool checked)
{
if (!m_song || !checked) return;
m_song->setPlayMode(PB_PLAY_MODE_followYou);
}
void on_playAlongRadio_toggled (bool checked)
{
if (!m_song || !checked) return;
m_song->setPlayMode(PB_PLAY_MODE_playAlong);
}
void on_muteYourPartCheck_toggled (bool checked)
{
if (m_song) m_song->mutePianistPart(checked);
}
void setTrackRightHandPart() {
int row = trackListWidget->currentRow();
int otherRow = m_trackList->getHandTrackIndex(PB_PART_left);
if (otherRow == row) otherRow = -1;
m_trackList->setActiveHandsIndex(otherRow, row);
trackListWidget->setCurrentRow(row);
m_song->refreshScroll();
}
void setTrackLeftHandPart() {
int row = trackListWidget->currentRow();
int otherRow = m_trackList->getHandTrackIndex(PB_PART_right);
if (otherRow == row) otherRow = -1;
m_trackList->setActiveHandsIndex(row, otherRow);
trackListWidget->setCurrentRow(row);
m_song->refreshScroll();
}
void clearTrackPart() {
int row = trackListWidget->currentRow();
m_trackList->setActiveHandsIndex( -1, -1);
trackListWidget->setCurrentRow(row);
m_song->refreshScroll();
}
private:
void autoSetMuteYourPart();
CSong* m_song;
CScore* m_score;
CTrackList* m_trackList;
GuiTopBar* m_topBar;
CSettings* m_settings;
QWidget *m_parent;
};
#endif //__GUISIDEPANEL_H__
pianobooster-src-0.6.4b/src/MidiDeviceRt.h 0000755 0001747 0001747 00000004672 11232414516 020101 0 ustar ubuntu ubuntu /*********************************************************************************/
/*!
@file MidiDeviceRt.h
@brief xxxxxx.
@author L. J. Barman
Copyright (c) 2008-2009, L. J. Barman, all rights reserved
This file is part of the PianoBooster application
PianoBooster 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.
PianoBooster 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 PianoBooster. If not, see .
*/
/*********************************************************************************/
#ifndef __MIDI_DEVICE_RT_H__
#define __MIDI_DEVICE_RT_H__
#include "MidiDeviceBase.h"
#include "rtmidi/RtMidi.h"
class CMidiDeviceRt : public CMidiDeviceBase
{
virtual void init();
//! add a midi event to be played immediately
virtual void playMidiEvent(const CMidiEvent & event);
virtual int checkMidiInput();
virtual CMidiEvent readMidiInput();
virtual QStringList getMidiPortList(midiType_t type);
virtual bool openMidiPort(midiType_t type, QString portName);
virtual void closeMidiPort(midiType_t type, int index);
// based on the fluid synth settings
virtual int midiSettingsSetStr(QString name, QString str);
virtual int midiSettingsSetNum(QString name, double val);
virtual int midiSettingsSetInt(QString name, int val);
virtual QString midiSettingsGetStr(QString name);
virtual double midiSettingsGetNum(QString name);
virtual int midiSettingsGetInt(QString name);
public:
CMidiDeviceRt();
~CMidiDeviceRt();
private:
RtMidiOut *m_midiout;
RtMidiIn *m_midiin;
// 0 for input, 1 for output
int m_midiPorts[2]; // select which MIDI output port to open
std::vector m_inputMessage;
unsigned char m_savedRawBytes[40]; // Raw data is used for used for a SYSTEM_EVENT
unsigned int m_rawDataIndex;
};
#endif //__MIDI_DEVICE_RT_H__
pianobooster-src-0.6.4b/src/StavePosition.h 0000644 0001747 0001747 00000013643 11266324061 020375 0 ustar ubuntu ubuntu /*********************************************************************************/
/*!
@file StavePosition.h
@brief xxxxxx.
@author L. J. Barman
Copyright (c) 2008-2009, L. J. Barman, all rights reserved
This file is part of the PianoBooster application
PianoBooster 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.
PianoBooster 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 PianoBooster. If not, see .
*/
/*********************************************************************************/
#ifndef __STAVE_POS_H__
#define __STAVE_POS_H__
#include "Util.h"
#include "Chord.h"
#include
typedef struct {
int pianoNote; // 1 is Middle C, 2 is D
int accidental;
} staveLookup_t;
#define NOT_USED 0x7fffffff
#define MAX_STAVE_INDEX 16
#define MIN_STAVE_INDEX -16
//----------------------------------------------------------------------------
// CStavePos
//----------------------------------------------------------------------------
//! @brief Calculates the position on the stave from the stave index number.
class CStavePos
{
public:
////////////////////////////////////////////////////////////////////////////////
//! @brief The default constructor.
CStavePos()
{
m_staveIndex = 0;
m_accidental = 0;
setHand(PB_PART_none);
};
////////////////////////////////////////////////////////////////////////////////
//! @brief Constructs the Stave position object.
//! @param hand the top (right hand) or the bottom the (left hand) see @ref whichPart_t.
//! @param index the save index number: 0 central line, 5 = top line, -5 the bottom line.
//! @param accidental Indicates an accidental 0 = none, 1=sharp, -1 =flat.
CStavePos(whichPart_t hand, int index, int accidental = 0)
{
m_staveIndex = index;
m_accidental = accidental;
setHand(hand);
};
////////////////////////////////////////////////////////////////////////////////
//! @brief Sets which stave the note will appear on
//! @param hand the top (right hand) or the bottom the (left hand) see @ref whichPart_t.
void setHand(whichPart_t hand)
{
m_hand = hand;
m_offsetY = getStaveCenterY();
if (m_hand == PB_PART_right)
m_offsetY += staveCentralOffset();
else if (m_hand == PB_PART_left)
m_offsetY -= staveCentralOffset();
}
void notePos(whichPart_t hand, int midiNote);
////////////////////////////////////////////////////////////////////////////////
//! @brief Sets which stave the note will appear on
//! return The position on the stave.
float getPosY()
{
return verticalNoteSpacing() * m_staveIndex + m_offsetY ;
}
float getPosYAccidental() {
int accidental = m_accidental;
if (accidental == 2) accidental = 1;
else if (accidental == -2) accidental = -1;
return getPosY() + accidental*verticalNoteSpacing()/2;
}
float getPosYRelative() { return getPosY() - m_staveCenterY;} // get the Y position relative to the stave centre
////////////////////////////////////////////////////////////////////////////////
//! @brief The accidental
//! return 0 = none, 1=sharp, -1 =flat, 2=natural.
int getAccidental() {return m_accidental;}
int getStaveIndex() {return m_staveIndex;}
whichPart_t getHand() {return m_hand;}
static float getVerticalNoteSpacing(){return verticalNoteSpacing();}
static float getStaveCenterY(){return m_staveCenterY;}
static void setStaveCenterY(float y) { m_staveCenterY = y; }
static void setKeySignature(int key, int majorMinor);
static int getKeySignature() {return m_KeySignature;}
static void setStaveCentralOffset(float gap) { m_staveCentralOffset = gap; }
static float verticalNoteSpacing() {return 7;}
static float staveHeight() {return verticalNoteSpacing() * 8;}
static float staveCentralOffset() {return m_staveCentralOffset;}
// convert the midi note to the note name A B C D E F G
static staveLookup_t midiNote2Name(int midiNote);
static const staveLookup_t* getstaveLookupTable(int key);
// do we show a sharp or a flat for this key signature
// returns 0 = none, 1=sharp, -1 =flat, 2=natural (# Key) , -2=natural (b Key)
static int getStaveAccidental(int midiNote)
{
return m_staveLookUpTable[midiNote%12].accidental;
}
// returns 0 = none, 1=above, -1 =below, (a natural is either above or below)
static int getStaveAccidentalDirection(int midiNote)
{
int accidentalDirection = getStaveAccidental(midiNote);
if (accidentalDirection == 2) // A natural so change to above
accidentalDirection = 1;
else if (accidentalDirection == -2) // A natural so change to below
accidentalDirection = -1;
return accidentalDirection;
}
private:
// fixme TODO This could be improved as the calculations could a done in the constructor
char m_staveIndex; // 0 central line, 5 = top line, -5 the bottom line,
int m_accidental; // 0 = none, 1=sharp, -1 =flat, 2=natural
float m_offsetY;
whichPart_t m_hand;
static int m_KeySignature;
static int m_KeySignatureMajorMinor;
static const staveLookup_t* m_staveLookUpTable;
static float m_staveCentralOffset;
static float m_staveCenterY;
};
#endif //__STAVE_POS_H__
pianobooster-src-0.6.4b/src/Piano.h 0000644 0001747 0001747 00000004363 11201535320 016622 0 ustar ubuntu ubuntu /*********************************************************************************/
/*!
@file Piano.h
@brief xxxx.
@author L. J. Barman
Copyright (c) 2008-2009, L. J. Barman, all rights reserved
This file is part of the PianoBooster application
PianoBooster 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.
PianoBooster 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 PianoBooster. If not, see .
*/
/*********************************************************************************/
#ifndef __PIANO_H__
#define __PIANO_H__
#include "Draw.h"
#include "Chord.h"
#include "Settings.h"
typedef struct {
float posY;
float posYOriginal;
int type; // not used
int pitch;
} noteNameItem_t;
class CPiano : protected CDraw
{
public:
CPiano(CSettings* settings) : CDraw(settings)
{
}
void drawPianoInput();
void addPianistNote(whichPart_t part, int note, bool good);
bool removePianistNote(int note);
int pianistAllNotesDown(); // Counts the number of notes the pianist has down
int pianistBadNotesDown();
void clear();
private:
void spaceNoteBunch(unsigned int bottomIndex, unsigned int topIndex);
void drawPianoInputLines(CChord* chord, CColour colour, int lineLength);
void drawPianoInputNoteNames();
void spaceNoteNames();
void addNoteNameItem(float posY, int pitch, int type);
void removeNoteNameItem(int pitch);
void noteNameListClear();
noteNameItem_t m_noteNameList[20];
unsigned int m_noteNameListLength;
CChord m_goodChord; // The coloured note lines that appear on the score when the pianist plays
CChord m_badChord;
};
#endif //__PIANO_H__
pianobooster-src-0.6.4b/src/Symbol.h 0000644 0001747 0001747 00000012146 11303063627 017030 0 ustar ubuntu ubuntu /*********************************************************************************/
/*!
@file Symbol.h
@brief A single musical symbols (eg note, rest, slur) that can appear on the page.
@author L. J. Barman
Copyright (c) 2008-2009, L. J. Barman, all rights reserved
This file is part of the PianoBooster application
PianoBooster 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.
PianoBooster 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 PianoBooster. If not, see .
*/
/*********************************************************************************/
#ifndef _SYMBOL_H_
#define _SYMBOL_H_
#include "Util.h"
#include "Cfg.h"
#include "StavePosition.h"
typedef enum
{
PB_SYMBOL_none,
PB_SYMBOL_note,
PB_SYMBOL_drum,
PB_SYMBOL_gClef, // The Treble Clef
PB_SYMBOL_fClef, // The Base Clef
PB_SYMBOL_sharp,
PB_SYMBOL_flat,
PB_SYMBOL_natural,
PB_SYMBOL_barLine,
PB_SYMBOL_barMarker,
PB_SYMBOL_beatMarker,
PB_SYMBOL_playingZone,
PB_SYMBOL_theEnd
} musicalSymbol_t;
typedef enum {
PB_ACCIDENTAL_MODIFER_noChange,
PB_ACCIDENTAL_MODIFER_suppress,
PB_ACCIDENTAL_MODIFER_force // force a natural/accidental to be played
} accidentalModifer_t;
#define BEAT_MARKER_OFFSET 20 // used to ensure that beat markers are drawn under the note by drawing them early
class CSymbol
{
public:
////////////////////////////////////////////////////////////////////////////////
//@brief constructors
CSymbol(musicalSymbol_t type, whichPart_t hand, int midiNote, int midiDuration = 0)
{
init();
m_symbolType = type;
m_midiNote = midiNote;
m_hand = hand;
m_midiDuration = midiDuration;
m_stavePos.notePos(hand, midiNote);
}
CSymbol()
{
init();
}
CSymbol(musicalSymbol_t type, CStavePos stavePos, CColour colour = Cfg::noteColour())
{
init();
m_symbolType = type;
m_stavePos = stavePos;
m_colour = colour;
m_hand = stavePos.getHand();
}
////////////////////////////////////////////////////////////////////////////////
//@brief Get the type of symbol
musicalSymbol_t getType(){return m_symbolType;}
////////////////////////////////////////////////////////////////////////////////
//@brief how long is the note
int getMidiDuration(){return m_midiDuration;}
////////////////////////////////////////////////////////////////////////////////
//@brief returns the midi note number
int getNote(){return m_midiNote;}
////////////////////////////////////////////////////////////////////////////////
//@brief returns the midi note number
whichPart_t getHand(){return m_hand;}
////////////////////////////////////////////////////////////////////////////////
//@brief get the Stave Position
CStavePos getStavePos(){return m_stavePos;}
void setColour(CColour colour){ m_colour = colour;}
CColour getColour(){return m_colour;}
void setPianistTiming(int timing){ m_pianistTiming = timing;}
int getPianistTiming(){ return m_pianistTiming; }
void transpose(int amount)
{
if (m_symbolType == PB_SYMBOL_note)
{
m_midiNote += amount;
m_stavePos.notePos(m_hand, m_midiNote); // The save position has now moved
}
}
void setIndex(int index, int total)
{
m_index = index;
m_total = total;
}
int getNoteIndex() { return m_index; }
int getNoteTotal() { return m_total; }
////////////////////////////////////////////////////////////////////////////////
//! @brief The accidental
//! return 0 = none, 1=sharp, -1 =flat, 2=natural.
int getAccidental() {
return getStavePos().getAccidental();
}
void setAccidentalModifer(accidentalModifer_t value) {m_accidentalModifer = value;}
accidentalModifer_t getAccidentalModifer() {return m_accidentalModifer;}
private:
void init()
{
m_symbolType = PB_SYMBOL_none;
m_midiNote = 0;
m_hand = PB_PART_none;
m_midiDuration = 0;
m_pianistTiming = NOT_USED;
setIndex(0,0);
m_accidentalModifer = PB_ACCIDENTAL_MODIFER_noChange;
}
CStavePos m_stavePos;
musicalSymbol_t m_symbolType;
byte m_midiNote;
accidentalModifer_t m_accidentalModifer; // Used to suppress the second sharp in the same bar
unsigned long m_midiDuration;
whichPart_t m_hand;
CColour m_colour;
int m_pianistTiming;
int m_index; // the number of the note per hand starting from the bottom.
int m_total; // the number of the notes per hand;
};
#endif // _SYMBOL_H_
pianobooster-src-0.6.4b/src/GuiKeyboardSetupDialog.cpp 0000644 0001747 0001747 00000013266 11301345653 022470 0 ustar ubuntu ubuntu /*********************************************************************************/
/*!
@file GuiKeyboardSetupDialog.cpp
@brief xxxx.
@author L. J. Barman
Copyright (c) 2008-2009, L. J. Barman, all rights reserved
This file is part of the PianoBooster application
PianoBooster 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.
PianoBooster 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 PianoBooster. If not, see .
*/
/*********************************************************************************/
#include
#include "GuiKeyboardSetupDialog.h"
#include "rtmidi/RtMidi.h"
GuiKeyboardSetupDialog::GuiKeyboardSetupDialog(QWidget *parent)
: QDialog(parent)
{
m_song = 0;
setupUi(this);
setWindowTitle(tr("Piano Keyboard Settings"));
}
void GuiKeyboardSetupDialog::init(CSong* song, CSettings* settings)
{
m_song = song;
m_settings = settings;
// Check inputs.
QString programName;
int i;
i = 0;
while (true)
{
programName = CTrackList::getProgramName(i);
if (programName.isEmpty())
break;
rightSoundCombo->addItem(programName);
wrongSoundCombo->addItem(programName);
i++;
}
int program = m_settings->value("Keyboard/RightSound", Cfg::defaultRightPatch()).toInt();
rightSoundCombo->setCurrentIndex(program);
program = m_settings->value("Keyboard/WrongSound", Cfg::defaultWrongPatch()).toInt();
wrongSoundCombo->setCurrentIndex(program);
int lowestNote = m_settings->value("Keyboard/LowestNote", "0").toInt();
int highestNote = m_settings->value("Keyboard/HighestNote", "127").toInt();
QString midiInputName = m_settings->value("Midi/I/nput").toString();
if (midiInputName.startsWith("None", Qt::CaseInsensitive))
{
lowestNote = PC_KEY_LOWEST_NOTE;
highestNote = PC_KEY_HIGHEST_NOTE;
lowestNoteEdit->setEnabled(false);
highestNoteEdit->setEnabled(false);
resetButton->setEnabled(false);
}
lowestNoteEdit->setText(QString().setNum(lowestNote));
highestNoteEdit->setText(QString().setNum(highestNote));
updateInfoText();
rightVolumeLabel->hide(); // fixme Hide for now
rightVolumeSpin->hide();
wrongVolumeLabel->hide();
wrongVolumeSpin->hide();
}
void GuiKeyboardSetupDialog::updateInfoText()
{
QString str;
keyboardInfoText->clear();
int lowestNote = lowestNoteEdit->text().toInt();
int highestNote = highestNoteEdit->text().toInt();
lowestNote = qBound(0, lowestNote, 127);
highestNote = qBound(0, highestNote, 127);
lowestNoteEdit->setText(QString().setNum(lowestNote));
highestNoteEdit->setText(QString().setNum(highestNote));
int noteRange = highestNote - lowestNote;
keyboardInfoText->append("Choose the right and wrong sound for your playing.");
if (!lowestNoteEdit->isEnabled())
str.sprintf("You can use the PC keyboard instead of a MIDI keyboard; 'x' is middle C.");
else if (noteRange > 0)
str.sprintf("Your keyboard range is octaves %d and semitones %d; 60 is middle C.",
noteRange/MIDI_OCTAVE, noteRange%MIDI_OCTAVE);
else
str.sprintf("Oops, you have 0 notes on your keyboard!");
keyboardInfoText->append(str);
}
void GuiKeyboardSetupDialog::keyPressEvent ( QKeyEvent * event )
{
if (event->text().length() == 0)
return;
if (event->isAutoRepeat() == true)
return;
int c = event->text().toAscii().at(0);
m_song->pcKeyPress( c, true);
}
void GuiKeyboardSetupDialog::keyReleaseEvent ( QKeyEvent * event )
{
if (event->isAutoRepeat() == true)
return;
if (event->text().length() == 0)
return;
int c = event->text().toAscii().at(0);
m_song->pcKeyPress( c, false);
}
void GuiKeyboardSetupDialog::accept()
{
m_settings->setValue("Keyboard/RightSound", rightSoundCombo->currentIndex());
m_settings->setValue("Keyboard/WrongSound", wrongSoundCombo->currentIndex());
m_settings->setValue("Keyboard/RightSoundPrevious", rightSoundCombo->currentIndex());
int lowestNote = lowestNoteEdit->text().toInt();
int highestNote = highestNoteEdit->text().toInt();
lowestNote = qBound(0, lowestNote, 127);
highestNote = qBound(0, highestNote, 127);
CChord::setPianoRange(lowestNote, highestNote);
if (lowestNoteEdit->isEnabled())
{
m_settings->setValue("Keyboard/LowestNote", lowestNote);
m_settings->setValue("Keyboard/HighestNote", highestNote);
}
m_song->testWrongNoteSound(false);
m_song->regenerateChordQueue();
this->QDialog::accept();
}
void GuiKeyboardSetupDialog::reject()
{
m_song->testWrongNoteSound(false);
m_song->setPianoSoundPatches(m_settings->value("Keyboard/RightSound", Cfg::defaultRightPatch()).toInt() - 1,
m_settings->value("Keyboard/WrongSound", Cfg::defaultWrongPatch()).toInt() - 1, true);
this->QDialog::reject();
}
pianobooster-src-0.6.4b/src/Conductor.h 0000644 0001747 0001747 00000022524 11303063627 017524 0 ustar ubuntu ubuntu /*********************************************************************************/
/*!
@file Conductor.h
@brief The realtime midi engine. Send notes to the midi device and responds to the midi keyboard.
@author L. J. Barman
Copyright (c) 2008-2009, L. J. Barman, all rights reserved
This file is part of the PianoBooster application
PianoBooster 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.
PianoBooster 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 PianoBooster. If not, see .
*/
/*********************************************************************************/
#ifndef __CONDUCTOR_H__
#define __CONDUCTOR_H__
#include "MidiEvent.h"
#include "Queue.h"
#include "MidiDevice.h"
#include "Cfg.h"
#include "Chord.h"
#include "Rating.h"
#include "Tempo.h"
#include "Bar.h"
class CScore;
class CPiano;
class CSettings;
typedef enum {
PB_FOLLOW_searching,
PB_FOLLOW_earlyNotes,
PB_FOLLOW_waiting
} followState_t;
enum {
PB_PLAY_MODE_listen,
PB_PLAY_MODE_followYou,
PB_PLAY_MODE_playAlong
};
typedef int playMode_t;
typedef enum {
PB_STOP_POINT_MODE_automatic,
PB_STOP_POINT_MODE_onTheBeat,
PB_STOP_POINT_MODE_afterTheBeat
} stopPointMode_t;
/*!
* @brief xxxxx.
*/
class CConductor : public CMidiDevice
{
public:
CConductor();
~CConductor();
void init(CScore * scoreWin, CSettings* settings);
//! add a midi event to be analysed and played
void midiEventInsert(CMidiEvent event);
//! first check if there is space to add a midi event
int midiEventSpace();
//! add a chord to be played by the pianist
void chordEventInsert(CChord chord) {m_wantedChordQueue->push(chord);}
//! first check if there is space to add a chord event
int chordEventSpace() { return m_wantedChordQueue->space();}
void rewind();
void realTimeEngine(int mSecTicks);
void playMusic(bool start);
bool playingMusic() {return m_playing;}
float getSpeed() {return m_tempo.getSpeed();}
void setSpeed(float speed)
{
m_tempo.setSpeed(speed);
m_leadLagAdjust = m_tempo.mSecToTicks( -getLatencyFix() );
}
void setLatencyFix(int latencyFix)
{
m_latencyFix = latencyFix;
m_leadLagAdjust = m_tempo.mSecToTicks( -getLatencyFix());
}
int getLatencyFix() { return m_latencyFix; }
void muteChannel(int channel, bool state);
void mutePart(int channel, bool state);
void transpose(int transpose);
int getTranspose() {return m_transpose;}
int getSkill() {return m_skill;}
void setSkill(int skill)
{
m_skill = skill;
if (m_skill > 5)
m_skill = 5;
if (m_skill < 0)
m_skill = 0;
}
void pianistInput(CMidiEvent inputNote);
void setPlayMode(playMode_t mode)
{
m_playMode = mode;
if (m_playMode < 0 ) m_playMode = 0;
if (m_playMode > 2 ) m_playMode = 2;
if ( m_playMode == PB_PLAY_MODE_listen )
resetWantedChord();
activatePianistMutePart();
outputBoostVolume();
}
int getBoostVolume() {return m_boostVolume;}
void boostVolume(int boostVolume)
{
m_boostVolume = boostVolume;
if (m_boostVolume < -100 ) m_boostVolume = -100;
if (m_boostVolume > 100 ) m_boostVolume = 100;
outputBoostVolume();
}
int getPianoVolume() {return m_pianoVolume;}
void pianoVolume(int pianoVolume)
{
m_pianoVolume = pianoVolume;
if (m_pianoVolume < -100 ) m_pianoVolume = -100;
if (m_pianoVolume > 100 ) m_pianoVolume = 100;
outputBoostVolume();
}
static playMode_t getPlayMode() {return m_playMode;}
CChord getWantedChord() {return m_wantedChord;}
void setActiveHand(whichPart_t hand);
void setActiveChannel(int channel);
int getActiveChannel(){return m_activeChannel;}
void setPianistChannels(int goodChan, int badChan){
m_pianistGoodChan = goodChan;
m_pianistBadChan = badChan;
}
bool hasPianistKeyboardChannel(int chan) { return (m_pianistGoodChan == chan || m_pianistBadChan == chan ) ? true : false;}
CRating* getRating(){return &m_rating;}
// You MUST clear the time sig to 0 first before setting an new start time Sig
void setTimeSig(int top, int bottom) { m_bar.setTimeSig(top, bottom);}
void getTimeSig(int *top, int *bottom) {m_bar.getTimeSig(top, bottom);}
void testWrongNoteSound(bool enable);
// -1 means no sound -2 means ignore this parameter
void setPianoSoundPatches(int rightSound, int wrongSound, bool update = false){
m_cfg_rightNoteSound = rightSound;
if ( wrongSound != -2)
m_cfg_wrongNoteSound = wrongSound;
if (update)
updatePianoSounds();
}
void setEventBits(eventBits_t bits) { m_realTimeEventBits |= bits; } // don't change the other bits
// set to true to force the score to be redrawn
void forceScoreRedraw(){ setEventBits( EVENT_BITS_forceFullRedraw); }
int getBarNumber(){ return m_bar.getBarNumber();}
double getCurrentBarPos(){ return m_bar.getCurrentBarPos();}
void setPlayFromBar(double bar){ m_bar.setPlayFromBar(bar);}
void setPlayUptoBar(double bar){ m_bar.setPlayUptoBar(bar);}
double getPlayUptoBar(){ return m_bar.getPlayUptoBar();}
void setLoopingBars(double bars){ m_bar.setLoopingBars(bars);}
double getLoopingBars(){ return m_bar.getLoopingBars();}
void mutePianistPart(bool state);
bool cfg_timingMarkersFlag;
stopPointMode_t cfg_stopPointMode;
protected:
CScore* m_scoreWin;
CSettings* m_settings;
CQueue* m_songEventQueue;
CQueue* m_wantedChordQueue;
eventBits_t m_realTimeEventBits; //used to signal real time events to the caller of task()
void outputSavedNotes();
void activatePianistMutePart();
void resetWantedChord();
bool validatePianistNote( const CMidiEvent& inputNote);
bool validatePianistChord();
bool seekingBarNumber() { return m_bar.seekingBarNumber();}
private:
void allSoundOff();
void resetAllChannels();
void outputBoostVolume();
void outputPianoVolume();
void channelSoundOff(int channel);
void findSplitPoint();
void fetchNextChord();
void playTransposeEvent(CMidiEvent event);
void outputSavedNotesOff();
void findImminentNotesOff();
void updatePianoSounds();
void followPlaying();
void missedNotesColour(CColour colour);
int calcBoostVolume(int chan, int volume);
void addDeltaTime(int ticks);
int m_playingDeltaTime;
int m_chordDeltaTime;
bool m_playing;
int m_transpose; // the number of semitones to transpose the music
followState_t m_followState;
followState_t getfollowState()
{
if ( m_playMode == PB_PLAY_MODE_listen )
return PB_FOLLOW_searching;
return m_followState;
}
CRating m_rating;
CQueue* m_savedNoteQueue;
CQueue* m_savedNoteOffQueue;
CMidiEvent m_nextMidiEvent;
bool m_muteChannels[MAX_MIDI_CHANNELS];
bool isChannelMuted(int chan)
{
if (chan < 0 || chan >= MAX_MIDI_CHANNELS)
return true;
return m_muteChannels[chan];
}
void setFollowSkillAdvanced(bool enable);
CPiano* m_piano;
CBar m_bar;
int m_leadLagAdjust; // Synchronise the sound the the video
int m_silenceTimeOut; // used to create silence if the student stops for toooo long
CChord m_wantedChord; // The chord the pianist needs to play
CChord m_savedwantedChord; // A copy of the wanted chord complete with both left and right parts
CChord m_goodPlayedNotes; // The good notes the pianist plays
CTempo m_tempo;
int m_pianistSplitPoint; // Defines which notes go in the base and treble clef
bool m_followSkillAdvanced;
int m_lastSound;
int m_stopPoint; // Were we stop the music if the pianist is late
int m_cfg_rightNoteSound;
int m_cfg_wrongNoteSound;
int m_pianistGoodChan;
int m_pianistBadChan;
int m_cfg_earlyNotesPoint; // don't press the note too early
int m_cfg_stopPointAdvanced; // Were we stop the music if the pianist is late
int m_cfg_stopPointBeginner; // Were we stop the music if the pianist is late
int m_cfg_imminentNotesOffPoint;
int m_cfg_playZoneEarly; // when playing along
int m_cfg_playZoneLate;
int m_pianistTiming; //measure whether the pianist is playing early or late
bool m_followPlayingTimeOut; // O dear, the student is too slow
bool m_testWrongNoteSound;
int m_boostVolume;
int m_pianoVolume;
int m_activeChannel; // The current part that is being displayed (used for boost and activatePianistMutePart)
int m_savedMainVolume[MAX_MIDI_CHANNELS];
static playMode_t m_playMode;
int m_skill;
bool m_mutePianistPart;
int m_latencyFix; // Try to fix the latency (put the time in msec, 0 disables it)
};
#endif //__CONDUCTOR_H__
pianobooster-src-0.6.4b/src/Cfg.h 0000644 0001747 0001747 00000012112 11304221574 016251 0 ustar ubuntu ubuntu /*********************************************************************************/
/*!
@file Cfg.h
@brief Contains all the configuration Information.
@author L. J. Barman
Copyright (c) 2008-2009, L. J. Barman, all rights reserved
This file is part of the PianoBooster application
PianoBooster 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.
PianoBooster 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 PianoBooster. If not, see .
*/
/*********************************************************************************/
#ifndef __CFG_H__
#define __CFG_H__
#define OPTION_BENCHMARK_TEST 0
#if OPTION_BENCHMARK_TEST
#define BENCHMARK_INIT() benchMarkInit()
#define BENCHMARK(id,mesg) benchMark(id,mesg)
#define BENCHMARK_RESULTS() benchMarkResults()
#else
#define BENCHMARK_INIT()
#define BENCHMARK(id,mesg)
#define BENCHMARK_RESULTS()
#endif
class CColour
{
public:
CColour() { red = green = blue = 0; }
CColour(double r, double g, double b)
{
red = static_cast(r);
green = static_cast(g);
blue = static_cast(b);
}
float red, green, blue;
bool operator==(CColour colour)
{
if (red == colour.red && green == colour.green && blue == colour.blue)
return true;
return false;
}
};
/*!
* @brief Contains all the configuration Information.
*/
class Cfg
{
public:
static float staveStartX() {return 20;}
static float staveEndX() {return m_staveEndX;}
static float playZoneX() {return scrollStartX() + ( staveEndX() - scrollStartX())* 0.4f;}
static float clefX() {return staveStartX() + 20;}
static float timeSignatureX() {return clefX() + 25;}
static float keySignatureX() {return timeSignatureX() + 25;}
static float scrollStartX() {return keySignatureX() + 64;}
static float pianoX() {return 25;}
static float staveThickness() {return 1;}
static int playZoneEarly() {return m_playZoneEarly;}
static int playZoneLate() {return m_playZoneLate;}
static int silenceTimeOut() {return 8000;} // the time in msec before everything goes quiet
static int chordNoteGap() {return 10;} // all notes in a cord must be spaced less than this a gap
static int chordMaxLength() {return 20;} // the max time between the start and end of a cord
static CColour menuColour() {return CColour(0.1, 0.6, 0.6);}
static CColour menuSelectedColour(){return CColour(0.7, 0.7, 0.1);}
static CColour staveColour() {return CColour(0.1, 0.7, 0.1);} // green
static CColour staveColourDim() {return CColour(0.15, 0.40, 0.15);} // grey
static CColour noteColour() {return CColour(0.1, 0.9, 0.1);} // green
static CColour noteColourDim() {return CColour(0.25, 0.45, 0.25);} // green
//static CColour playedGoodColour() {return CColour(0.6, 0.6, 1.0);} // grey
static CColour playedGoodColour() {return CColour(0.5, 0.6, 1.0);} // purple 0.6, 0.6, 1.0
static CColour playedBadColour() {return CColour(0.8, 0.3, 0.8);} // orange 0.7, 0.0, 0.0
static CColour playedStoppedColour() {return CColour(1.0, 0.8, 0.0);} // bright orange
static CColour backgroundColour() {return CColour(0.0, 0.0, 0.0);} // black
static CColour barMarkerColour() {return CColour(0.3, 0.25, 0.25);} // grey
static CColour beatMarkerColour() {return CColour(0.25, 0.2, 0.2);} // grey
static CColour pianoGoodColour() {return playedGoodColour();}
static CColour pianoBadColour() {return CColour(1.0, 0.0, 0.0);}
static CColour noteNameColour() {return CColour(1.0, 1.0, 1.0);}
static void setStaveEndX(float x)
{
m_staveEndX = x;
}
static int getAppX(){return m_appX;}
static int getAppY(){return m_appY;}
static int getAppWidth(){return m_appWidth;}
static int getAppHeight(){return m_appHeight;}
static void setAppDimentions(int x, int y,int width, int height)
{
m_appX = x;
m_appY = y;
m_appWidth = width;
m_appHeight = height;
}
static int defaultWrongPatch() {return 7;} // Starts at 1
static int defaultRightPatch() {return 1;} // Starts at 1
static int logLevel;
static bool quickStart;
static bool experimentalTempo;
static int experimentalSwapInterval;
private:
static float m_staveEndX;
static int m_appX, m_appY, m_appWidth, m_appHeight;
static const int m_playZoneEarly;
static const int m_playZoneLate;
};
#endif //__CFG_H__
pianobooster-src-0.6.4b/src/Scroll.h 0000644 0001747 0001747 00000007151 11303063627 017021 0 ustar ubuntu ubuntu /*********************************************************************************/
/*!
@file Scroll.h
@brief The Design.
@author L. J. Barman
Copyright (c) 2008-2009, L. J. Barman, all rights reserved
This file is part of the PianoBooster application
PianoBooster 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.
PianoBooster 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 PianoBooster. If not, see .
*/
/*********************************************************************************/
#ifndef __SCROLL_H__
#define __SCROLL_H__
#include "Draw.h"
#include "Song.h"
#include "Queue.h"
#define QUEUE_LENGTH 1000
class CSettings;
class CScroll : public CDraw
{
public:
CScroll(int id, CSettings* settings) : CDraw(settings)
{
m_id = id;
m_symbolID = 0;
m_notation = new CNotation();
m_scrollQueue = new CQueue(QUEUE_LENGTH);
reset();
m_show = false;
m_noteSpacingFactor = 1.0;
m_ppqnFactor = 1.0;
m_transpose = 0;
}
~CScroll()
{
delete m_scrollQueue;
delete m_notation;
}
void reset();
void scrollDeltaTime(int ticks);
void transpose(int transpose);
void refresh();
void setPlayedNoteColour(int note, CColour colour, int wantedDelta, int pianistTimming);
void setChannel(int chan)
{
m_notation->setChannel( chan );
}
//! add a midi event to be analysed and displayed on the score
void midiEventInsert(CMidiEvent event) { m_notation->midiEventInsert(event);}
//! first check if there is space to add a midi event
int midiEventSpace() { return m_notation->midiEventSpace(); }
void drawScrollingSymbols(bool show);
void showScroll(bool show);
private:
class CSlotDisplayList : public CSlot
{
public:
CSlotDisplayList(): m_displayListId(0){};
CSlotDisplayList(const CSlot &slot, GLuint displayListId, GLuint nextDisplayListId);
GLuint m_displayListId; // the open GL display list id for this slot
GLuint m_nextDisplayListId; // and this points to the next one
};
void compileSlot(CSlotDisplayList info);
bool validPianistChord(int index);
bool insertSlots();
void removeSlots();
void removeEarlyTimingMakers();
int findWantedChord(int note, CColour colour, int wantedDelta);
int m_id; // There are lots of these class running but each class has a unique id
CNotation *m_notation;
int m_deltaHead;
int m_deltaTail;
GLuint m_symbolID; // the next Display List name (or ID) to use
CSlot m_headSlot; // The next slot to be put in at the head of the queue;
int m_transpose;
int m_wantedIndex; // The index number of the wanted call in the scrollQueue
int m_wantedDelta; // The running delta time of the wanted chord
CQueue* m_scrollQueue; // The current active display list of notes/chords on the screen
bool m_show; // set to true to show on the screen
float m_noteSpacingFactor;
float m_ppqnFactor; // if PulsesPerQuarterNote is 96 then the factor is 1.0
};
#endif //__SCROLL_H__
pianobooster-src-0.6.4b/src/Settings.cpp 0000755 0001747 0001747 00000026300 11303577704 017724 0 ustar ubuntu ubuntu /*!
@file Settings.cpp
@brief Save all the settings for the programme in the right place.
@author L. J. Barman
Copyright (c) 2008-2009, L. J. Barman, all rights reserved
This file is part of the PianoBooster application
PianoBooster 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.
PianoBooster 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 PianoBooster. If not, see .
*/
/*!
* The following attributes are save in the pb.cfg xml file
* BOOK:
* name the name of the book
* lastsong the name of the last song played so it can be restored
*
* SONG:
* name
* hand
* leftHandMidiChannel
* rightHandMidiChannel
*
* HAND:
* speed
*
*/
#include
#include
#include "Settings.h"
#include "GuiTopBar.h"
#include "GuiSidePanel.h"
#include "QtWindow.h"
#include "ReleaseNote.txt"
#define OPTION_DEBUG_SETTINGS 0
#if OPTION_DEBUG_SETTINGS
#define debugSettings(args) qDebug args
#else
#define debugSettings(args)
#endif
CSettings::CSettings(QtWindow *mainWindow) : QSettings(CSettings::IniFormat, CSettings::UserScope, "PianoBooster", "Piano Booster"),
m_mainWindow(mainWindow)
{
// It is all done in the initialisation list
m_advancedMode = false;
m_pianistActive = false;
m_noteNamesEnabled = value("Score/NoteNames", true ).toBool();
CNotation::setCourtesyAccidentals(value("Score/CourtesyAccidentals", false ).toBool());
}
void CSettings::setDefaultValue(const QString & key, const QVariant & value )
{
if (contains(key)) // Do not change the value if it already set
return;
setValue(key, value);
}
void CSettings::init(CSong* song, GuiSidePanel* sidePanel, GuiTopBar* topBar)
{
m_song = song;
m_guiSidePanel = sidePanel;
m_guiTopBar = topBar;
// Set defualt values
setValue("PianoBooster/Version",PB_VERSION);
setDefaultValue("ShortCuts/LeftHand", "F2");
setDefaultValue("ShortCuts/BothHands","F3");
setDefaultValue("ShortCuts/RightHand","F4");
setDefaultValue("ShortCuts/PlayFromStart","space");
setDefaultValue("ShortCuts/PlayPause","P");
setDefaultValue("ShortCuts/Faster","=");
setDefaultValue("ShortCuts/Slower","-");
setDefaultValue("ShortCuts/NextSong","]");
setDefaultValue("ShortCuts/PreviousSong","[");
}
void CSettings::setNoteNamesEnabled(bool value) {
m_noteNamesEnabled = value;
setValue("Score/NoteNames", value );
}
void CSettings::setCourtesyAccidentals(bool value) {
CNotation::setCourtesyAccidentals(value);
setValue("Score/CourtesyAccidentals", value );
}
// Open a document if it exists or else create it (also delete an duplicates
QDomElement CSettings::openDomElement(QDomElement parent, const QString & elementName, const QString & attributeName)
{
QDomElement wantedElement;
debugSettings(("openDomElement1 %s %s %s", qPrintable(parent.tagName()), qPrintable(elementName), qPrintable(elementName)));
// There should be only a single element without a name
// there should be lots of elemens but only one with this tag name
QDomNode n = parent.firstChild();
while(!n.isNull())
{
QDomElement e = n.toElement(); // try to convert the node to an element.
debugSettings(("openDomElement2 tagName %s %s", qPrintable(e.tagName()), qPrintable(elementName)));
if(!e.isNull() && e.tagName() == elementName)
{
if (attributeName.isEmpty() || e.attribute("name") == attributeName)
{
debugSettings(("openDomElement3 ragName %s %s", qPrintable(e.attribute("name")), qPrintable(attributeName)));
if (wantedElement.isNull())
wantedElement = e; // we have found a match
else
parent.removeChild(e); // remove unwanted duplicates
}
}
n = n.nextSibling();
}
if (wantedElement.isNull())
{
// Create the element because it does not exsist
wantedElement = m_domDocument.createElement(elementName);
if (!attributeName.isEmpty() )
wantedElement.setAttribute("name", attributeName);
parent.appendChild(wantedElement);
}
return wantedElement;
}
void CSettings::loadHandSettings()
{
if (m_domSong.isNull())
return;
m_domHand = openDomElement(m_domSong, "hand", partToHandString(m_song->getActiveHand()));
//m_guiTopBar->setSpeed(m_domHand.attribute("speed", "100" ).toInt());
}
void CSettings::saveHandSettings()
{
//m_domHand.setAttribute("speed", m_guiTopBar->getSpeed());
}
void CSettings::loadSongSettings()
{
m_domSong = openDomElement(m_domBook, "song", m_currentSongName);
m_guiSidePanel->setCurrentHand(m_domSong.attribute("hand", "both" ));
m_guiTopBar->setSpeed(m_domSong.attribute("speed", "100" ).toInt());
// -1 means none and -2 means not set
int left = m_domSong.attribute("leftHandMidiChannel", "-2").toInt();
int right = m_domSong.attribute("rightHandMidiChannel", "-2").toInt();
CNote::setChannelHands(left, right);
loadHandSettings();
}
void CSettings::saveSongSettings()
{
m_domSong.setAttribute("hand", partToHandString(m_song->getActiveHand()));
m_domSong.setAttribute("speed", m_guiTopBar->getSpeed());
saveHandSettings();
}
void CSettings::loadBookSettings()
{
QDomElement root = m_domDocument.documentElement();
m_domBook = openDomElement(root, "book");
QString lastSong = m_domBook.attribute("lastsong");
if (!lastSong.isEmpty() && m_currentSongName.isEmpty())
m_currentSongName = lastSong;
}
void CSettings::saveBookSettings()
{
if (!m_currentBookName.isEmpty())
m_domBook.setAttribute("name", m_currentBookName);
if (!m_currentSongName.isEmpty())
m_domBook.setAttribute("lastsong", m_currentSongName);
saveSongSettings();
}
void CSettings::loadXmlFile()
{
m_domDocument.documentElement().clear();
m_domDocument.clear();
m_domBook.clear();
m_domSong.clear();
m_domHand.clear();
QFile file(m_bookPath + getCurrentBookName() + '/' + "pb.cfg");
if (file.open(QIODevice::ReadOnly))
{
if (!m_domDocument.setContent(&file)) {
ppLogError("Cannot setContent on XLM file");
}
file.close();
}
QDomElement root = m_domDocument.documentElement();
if (root.tagName() != "pianobooster")
{
m_domDocument.clear();
QDomComment comment = m_domDocument.createComment("Piano Booster Configuration file");
m_domDocument.appendChild(comment);
root = m_domDocument.createElement("pianobooster");
m_domDocument.appendChild(root);
}
loadBookSettings();
}
// save the xml
void CSettings::saveXmlFile()
{
saveBookSettings();
const int IndentSize = 4;
QFile file(m_bookPath + getCurrentBookName() + '/' + "pb.cfg");
// don't save the config file unless the user really is using the system
if (m_pianistActive == false && file.exists() == false)
return;
m_pianistActive = false;
if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
{
ppLogError("Cannot save xml file %s", qPrintable(file.fileName()));
return;
}
QTextStream out(&file);
m_domDocument.save(out, IndentSize);
file.close();
}
void CSettings::openSongFile(const QString & filename)
{
if (!QFile::exists(filename))
{
ppLogWarn( "File does not exists %s", qPrintable(filename));
return;
}
QDir dirBooks;
QString currentSongName;
if (filename.isEmpty())
{
dirBooks.setPath( QDir::homePath());
}
else
{
dirBooks.setPath(filename);
currentSongName = dirBooks.dirName();
dirBooks.cdUp();
m_currentBookName = dirBooks.dirName();
dirBooks.cdUp();
}
m_bookPath = dirBooks.path() + '/';
m_currentSongName = currentSongName;
m_guiSidePanel->loadBookList();
updateWarningMessages();
}
void CSettings::setActiveHand(whichPart_t hand)
{
saveHandSettings();
m_song->setActiveHand(hand);
loadHandSettings();
}
QStringList CSettings::getSongList()
{
debugSettings(("getSongList %s + %s", qPrintable(getCurrentBookName()), qPrintable(m_bookPath)));
QDir dirSongs = QDir(m_bookPath + getCurrentBookName());
dirSongs.setFilter(QDir::Files);
QStringList fileNames = dirSongs.entryList();
QStringList songNames;
for (int i = 0; i < fileNames.size(); i++)
{
if ( fileNames.at(i).endsWith(".mid", Qt::CaseInsensitive ) ||
fileNames.at(i).endsWith(".midi", Qt::CaseInsensitive ) ||
fileNames.at(i).endsWith(".kar", Qt::CaseInsensitive ) )
{
songNames += fileNames.at(i);
}
}
return songNames;
}
QStringList CSettings::getBookList()
{
QDir dirBooks( m_bookPath);
dirBooks.setFilter(QDir::Dirs | QDir::NoDotAndDotDot);
return dirBooks.entryList();
}
void CSettings::writeSettings()
{
if (QFile::exists(getCurrentSongLongFileName() ))
setValue("CurrentSong", getCurrentSongLongFileName());
saveXmlFile();
}
void CSettings::loadSettings()
{
QString songName = value("CurrentSong").toString();
if (!songName.isEmpty())
openSongFile( songName );
updateWarningMessages();
}
void CSettings::setCurrentSongName(const QString & name)
{
if (name.isEmpty())
return;
saveSongSettings();
m_currentSongName = name;
debugSettings(("setCurrentSongName %s -- %s", qPrintable(name), qPrintable(getCurrentSongLongFileName())));
setValue("CurrentSong", getCurrentSongLongFileName());
m_song->loadSong(getCurrentSongLongFileName());
loadSongSettings();
m_guiSidePanel->refresh();
m_guiTopBar->refresh(true);
m_mainWindow->setWindowTitle("Piano Booster - " + m_song->getSongTitle());
}
void CSettings::setCurrentBookName(const QString & name, bool clearSongName)
{
if (name.isEmpty())
return;
if (!m_currentBookName.isEmpty() && m_currentBookName != name)
saveXmlFile();
m_currentBookName = name;
if (clearSongName)
m_currentSongName.clear();
debugSettings(("setCurrentBookName %s --- %s ", qPrintable(name), qPrintable(getCurrentSongLongFileName())));
loadXmlFile();
}
void CSettings::setChannelHands(int left, int right)
{
CNote::setChannelHands(left, right);
m_domSong.setAttribute("leftHandMidiChannel", left);
m_domSong.setAttribute("rightHandMidiChannel", right);
m_guiSidePanel->refresh();
}
void CSettings::updateWarningMessages()
{
if (!m_song->validMidiOutput())
m_warningMessage = tr("NO MIDI OUTPUT DEVICE: Use menu Setup/Midi Setup ...");
else if (m_currentSongName.isEmpty())
m_warningMessage = tr("NO MIDI FILE LOADED: Use menu File/Open ...");
else
m_warningMessage.clear();
}
pianobooster-src-0.6.4b/src/Chord.cpp 0000644 0001747 0001747 00000012250 11303577704 017157 0 ustar ubuntu ubuntu /*********************************************************************************/
/*!
@file Chord.cpp
@brief Reads ahead from the songdata and collects chords to be matched.
@author L. J. Barman
Copyright (c) 2008-2009, L. J. Barman, all rights reserved
This file is part of the PianoBooster application
PianoBooster 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.
PianoBooster 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 PianoBooster. If not, see .
*/
/*********************************************************************************/
#include "Chord.h"
#include "Cfg.h"
int CNote::m_leftHandChannel = -2;
int CNote::m_rightHandChannel = -2;
whichPart_t CNote::m_activeHand = PB_PART_both;
int CChord::m_cfg_highestPianoNote = 127; // The highest note on the users piano keyboard;
int CChord::m_cfg_lowestPianoNote = 0;
whichPart_t CNote::findHand(int midiNote, int midiChannel, int whichChannel, whichPart_t whichPart)
{
whichPart_t hand = PB_PART_none;
// exit if it is not for this channel
if (midiChannel != whichChannel)
{
// return none if this is not being used with the other hand.
if (CNote::hasPianoPart(whichChannel) == false || CNote::hasPianoPart(midiChannel) == false)
return PB_PART_none;
}
if (midiChannel == CNote::rightHandChan())
hand = PB_PART_right;
else if (midiChannel == CNote::leftHandChan())
hand = PB_PART_left;
else
{
if (midiChannel == whichChannel)
{
if (midiNote >= MIDDLE_C)
hand = PB_PART_right;
else
hand = PB_PART_left;
}
}
if (whichPart == PB_PART_left && hand == PB_PART_right)
hand = PB_PART_none;
if (whichPart == PB_PART_right && hand == PB_PART_left)
hand = PB_PART_none;
return hand;
}
void CChord::addNote(whichPart_t part, int note, int duration)
{
if (m_length >= MAX_CHORD_NOTES)
{
ppDEBUG(("Over the chord note limit"));
return;
}
if (searchChord(note)) // don't add duplicates
return;
m_notes[m_length] = CNote(part, note, duration);
m_length++;
}
void CNote::setChannelHands(int left, int right)
{
m_leftHandChannel = left;
m_rightHandChannel = right;
}
//////////////// CChord /////////////////////
bool CChord::removeNote(int note)
{
int i;
bool noteFound = false;
for (i = 0; i < MAX_CHORD_NOTES; i++)
{
if (i >= m_length)
break;
if (noteFound == false)
{
if (getNote(i).pitch() == note)
noteFound = true;
}
else
{
// shove everything else up to remove the note
m_notes[i-1] = getNote(i);
}
}
if (noteFound)
m_length--;
return noteFound;
}
bool CChord::searchChord(int note, int transpose)
{
int i;
for (i = 0; i < m_length; i++)
{
if (getNote(i).pitch() + transpose == note)
return true;
}
return false;
}
int CChord::trimOutOfRangeNotes(int transpose)
{
int i;
int removedNotes = 0;
for (i = 0; i < MAX_CHORD_NOTES; i++)
{
if (i >= m_length)
break;
if (!isNotePlayable(getNote(i).pitch(), transpose) || !isHandPlayable(getNote(i).part()))
removedNotes++; // remove the note
else if (removedNotes)
{
// shove everything else up to remove the note
m_notes[i-removedNotes] = getNote(i);
}
}
m_length -= removedNotes;
return m_length;
}
bool CFindChord::findChord(CMidiEvent midi, int channel, whichPart_t part)
{
bool foundChord = false;
if (midi.type() == MIDI_PB_EOF)
{
if (m_currentChord.length() > 0)
{
m_completeChord = m_currentChord;
foundChord = true;
}
return foundChord;
}
m_noteGapTime += midi.deltaTime();
if ((m_noteGapTime >= m_cfg_ChordNoteGap || m_cordSpanGapTime > m_cfg_ChordMaxLength)
&& m_currentChord.length() > 0 )
{
foundChord = true;
m_completeChord = m_currentChord;
m_currentChord.clear();
}
if (midi.type() == MIDI_NOTE_ON)
{
whichPart_t hand = CNote::findHand( midi, channel, part );
if ( hand != PB_PART_none)
{
m_currentChord.addNote(hand, midi.note());
m_currentChord.setDeltaTime(m_noteGapTime + m_currentChord.getDeltaTime());
if (m_currentChord.length() <= 1)
m_cordSpanGapTime = 0;
else
m_cordSpanGapTime += m_noteGapTime; // measure the span of the cord
m_noteGapTime = 0;
}
}
return foundChord;
}
pianobooster-src-0.6.4b/src/CMakeLists.txt 0000644 0001747 0001747 00000015147 11304041717 020153 0 ustar ubuntu ubuntu # Cmake File for Piano Booster
# for the debug build type cmake -DCMAKE_BUILD_TYPE=Debug
SET(CMAKE_BUILD_TYPE Release)
SET(CMAKE_VERBOSE_MAKEFILE OFF)
SET(USE_FLUIDSYNTH OFF)
# The inplace directory is mainly for windows builds
# SET(FLUIDSYNTH_INPLACE_DIR C:/download/misc/ljb/fluidsynth-1.0.9)
SET(FLUIDSYNTH_INPLACE_DIR /home/louis/build/fluidsynth-1.0.9)
# Testing precompiled headers it does not work -- leave as OFF.
SET(USE_PCH OFF)
cmake_minimum_required(VERSION 2.4)
if(COMMAND cmake_policy)
cmake_policy(SET CMP0003 NEW)
endif(COMMAND cmake_policy)
IF(WIN32)
MESSAGE("GUI system is WIN32 ${CMAKE_GENERATOR}")
SET(CMAKE_COLOR_MAKEFILE OFF)
ENDIF(WIN32)
# set project's name
PROJECT( pianobooster )
# enable warnings
ADD_DEFINITIONS(-Wall)
# by default only QtCore and QtGui modules are enabled
# other modules must be enabled like this:
SET(QT_USE_QTOPENGL TRUE)
SET(QT_USE_QTXML TRUE)
FIND_PACKAGE( OpenGL REQUIRED )
# this command finds Qt4 libraries and sets all required variables
# note that it's Qt4, not QT4 or qt4
FIND_PACKAGE( Qt4 REQUIRED )
# add some useful macros and variables
# (QT_USE_FILE is a variable defined by FIND_PACKAGE( Qt4 ) that contains a path to CMake script)
INCLUDE( ${QT_USE_FILE} )
IF (USE_PCH)
INCLUDE(precompile/PCHSupport_26.cmake)
INCLUDE_DIRECTORIES( precompile .)
ENDIF(USE_PCH)
# Add in the link libraries for each operating system
IF(${CMAKE_SYSTEM} MATCHES "Linux")
#FIND_PACKAGE(PkgConfig REQUIRED)
#PKG_CHECK_MODULES(ALSA REQUIRED alsa>=1.0)
#IF(ALSA_FOUND)
ADD_DEFINITIONS(-D__LINUX_ALSASEQ__)
LINK_LIBRARIES (asound)
#ELSE(ALSA_FOUND)
# MESSAGE(FATAL_ERROR "Please install the 'libasound2-dev' package and then try again")
#ENDIF(ALSA_FOUND)
ENDIF(${CMAKE_SYSTEM} MATCHES "Linux")
IF(${CMAKE_SYSTEM} MATCHES "Windows")
# FIND_PACKAGE(WINDRES REQUIRED)
ADD_DEFINITIONS(-D__WINDOWS_MM__ -D_WIN32)
LINK_LIBRARIES(winmm opengl32)
ENDIF(${CMAKE_SYSTEM} MATCHES "Windows")
IF(${CMAKE_SYSTEM} MATCHES "Darwin")
ADD_DEFINITIONS(-D__MACOSX_CORE__)
LINK_LIBRARIES("-framework CoreMidi -framework CoreAudio -framework CoreFoundation -framework OpenGL")
ENDIF(${CMAKE_SYSTEM} MATCHES "Darwin")
IF(USE_FLUIDSYNTH)
ADD_DEFINITIONS(-DPB_USE_FLUIDSYNTH)
MESSAGE("Building using fluidsynth")
SET( PB_BASE_SRCS MidiDeviceFluidSynth.cpp )
IF(FLUIDSYNTH_INPLACE_DIR)
INCLUDE_DIRECTORIES(${FLUIDSYNTH_INPLACE_DIR}/include/)
IF(WIN32)
LINK_LIBRARIES( ${FLUIDSYNTH_INPLACE_DIR}/src/.libs/libfluidsynth.dll.a)
ENDIF(WIN32)
IF(UNIX)
LINK_LIBRARIES(${FLUIDSYNTH_INPLACE_DIR}/src/.libs/libfluidsynth.so)
ENDIF(UNIX)
ELSEIF(FLUIDSYNTH_INPLACE_DIR)
LINK_LIBRARIES( fluidsynth)
ENDIF(FLUIDSYNTH_INPLACE_DIR)
ENDIF(USE_FLUIDSYNTH)
# we need this to be able to include headers produced by uic in our code
# (CMAKE_BINARY_DIR holds a path to the build directory, while INCLUDE_DIRECTORIES() works just like INCLUDEPATH from qmake)
INCLUDE_DIRECTORIES( ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_BINARY_DIR} ${OPENGL_INCLUDE_DIR} )
# tell CMake what libraries our executable needs,
# luckily FIND_PACKAGE prepared QT_LIBRARIES variable for us:
LINK_LIBRARIES( ${QT_LIBRARIES} )
SET(PB_BASE_SRCS MidiFile.cpp MidiTrack.cpp Song.cpp Conductor.cpp Util.cpp
Chord.cpp Tempo.cpp MidiDevice.cpp MidiDeviceRt.cpp rtmidi/RtMidi.cpp ${PB_BASE_SRCS})
SET(PB_BASE_HDR MidiFile.h MidiTrack.h Song.h Conductor.h Rating.h Util.h
Chord.h Tempo.h MidiDevice.h rtmidi/RtMidi.h)
# with SET() command you can change variables or define new ones
# here we define PIANOBOOSTER_SRCS variable that contains a list of all .cpp files
# note that we don't need \ at the end of line
SET( PIANOBOOSTER_SRCS
QtMain.cpp
QtWindow.cpp
GuiTopBar.cpp
GuiSidePanel.cpp
GuiMidiSetupDialog.cpp
GuiKeyboardSetupDialog.cpp
GuiPreferencesDialog.cpp
GuiSongDetailsDialog.cpp
GuiLoopingPopup.cpp
GlView.cpp
${PB_BASE_SRCS}
StavePosition.cpp
Score.cpp
Cfg.cpp
Piano.cpp
Draw.cpp
Scroll.cpp
Notation.cpp
TrackList.cpp
Rating.cpp
Bar.cpp
Settings.cpp
Merge.cpp
#Band.cpp
pianobooster.rc
pianobooster.ico
# precompile.h
)
# another list, this time it includes all header files that should be treated with moc
SET( PIANOBOOSTER_MOC_HDRS
QtWindow.h
GlView.h
GuiTopBar.h
GuiSidePanel.h
GuiMidiSetupDialog.h
GuiKeyboardSetupDialog.h
GuiPreferencesDialog.h
GuiSongDetailsDialog.h
GuiLoopingPopup.h
)
# some .ui files
SET( PIANOBOOSTER_UIS
./GuiTopBar.ui
./GuiSidePanel.ui
./GuiMidiSetupDialog.ui
./GuiKeyboardSetupDialog.ui
./GuiPreferencesDialog.ui
./GuiSongDetailsDialog.ui
./GuiLoopingPopup.ui
)
# and finally an resource file
SET( PIANOBOOSTER_RCS
./application.qrc
)
# this command will generate rules that will run rcc on all files from PIANOBOOSTER_RCS
# in result PIANOBOOSTER_RC_SRCS variable will contain paths to files produced by rcc
QT4_ADD_RESOURCES( PIANOBOOSTER_RC_SRCS ${PIANOBOOSTER_RCS} )
# this will run uic on .ui files:
QT4_WRAP_UI( PIANOBOOSTER_UI_HDRS ${PIANOBOOSTER_UIS} )
# and finally this will run moc:
QT4_WRAP_CPP( PIANOBOOSTER_MOC_SRCS ${PIANOBOOSTER_MOC_HDRS} )
# here we instruct CMake to build "pianobooster" executable from all of the source files
IF(APPLE)
ADD_EXECUTABLE( pianobooster MACOSX_BUNDLE ${PIANOBOOSTER_SRCS}
${PIANOBOOSTER_MOC_SRCS} ${PIANOBOOSTER_RC_SRCS}
${PIANOBOOSTER_UI_HDRS})
ENDIF(APPLE)
IF(UNIX)
ADD_EXECUTABLE( pianobooster pianobooster.rc ${PIANOBOOSTER_SRCS}
${PIANOBOOSTER_MOC_SRCS} ${PIANOBOOSTER_RC_SRCS}
${PIANOBOOSTER_UI_HDRS} )
ENDIF(UNIX)
IF(WIN32)
ADD_EXECUTABLE( pianobooster WIN32 pianobooster.rc ${PIANOBOOSTER_SRCS}
${PIANOBOOSTER_MOC_SRCS} ${PIANOBOOSTER_RC_SRCS}
${PIANOBOOSTER_UI_HDRS} )
ENDIF(WIN32)
SET_TARGET_PROPERTIES(pianobooster PROPERTIES LINK_FLAGS "-mwindows")
IF (USE_PCH)
ADD_PRECOMPILED_HEADER( pianobooster ${CMAKE_CURRENT_SOURCE_DIR}/precompile/precompile.h )
ENDIF (USE_PCH)
INSTALL( FILES pianobooster.desktop DESTINATION share/applications )
INSTALL(TARGETS pianobooster RUNTIME DESTINATION bin)
#INSTALL( index.docbook INSTALL_DESTINATION ${HTML_INSTALL_DIR}/en SUBDIR kmidimon )
INSTALL( FILES ../README.txt DESTINATION share/doc/pianobooster )
INSTALL ( FILES images/pianobooster.png DESTINATION share/pixmaps )
pianobooster-src-0.6.4b/src/GuiPreferencesDialog.h 0000644 0001747 0001747 00000003077 11303577704 021622 0 ustar ubuntu ubuntu /*********************************************************************************/
/*!
@file GuiPreferencesDialog.h
@brief xxxx.
@author L. J. Barman
Copyright (c) 2008-2009, L. J. Barman, all rights reserved
This file is part of the PianoBooster application
PianoBooster 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.
PianoBooster 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 PianoBooster. If not, see .
*/
/*********************************************************************************/
#ifndef __GUIPREFERENCESDIALOG_H__
#define __GUIPREFERENCESDIALOG_H__
#include
#include "Song.h"
#include "Settings.h"
#include "ui_GuiPreferencesDialog.h"
class CGLView;
class GuiPreferencesDialog : public QDialog, private Ui::GuiPreferencesDialog
{
Q_OBJECT
public:
GuiPreferencesDialog(QWidget *parent = 0);
void init(CSong* song, CSettings* settings, CGLView* glView);
private slots:
void accept();
private:
CSettings* m_settings;
CSong* m_song;
CGLView *m_glView;
};
#endif //__GUIPREFERENCESDIALOG_H__
pianobooster-src-0.6.4b/src/Notation.cpp 0000644 0001747 0001747 00000024521 11303577704 017717 0 ustar ubuntu ubuntu /*********************************************************************************/
/*!
@file Notation.cpp
@brief xxx.
@author L. J. Barman
Copyright (c) 2008-2009, L. J. Barman, all rights reserved
This file is part of the PianoBooster application
PianoBooster 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.
PianoBooster 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 PianoBooster. If not, see .
*/
/*********************************************************************************/
#include "Notation.h"
#include "Cfg.h"
#define OPTION_DEBUG_NOTATION 0
#if OPTION_DEBUG_NOTATION
#define ppDEBUG_NOTATION(args) ppLogDebug args
#else
#define ppDEBUG_NOTATION(args)
#endif
#define MERGESLOT_NOTE_INDEX 0
#define MERGESLOT_BEATMARK_INDEX 1
bool CSlot::addSymbol(CSymbol symbol)
{
int i;
if (m_length >= MAX_SYMBOLS)
return false;
// Sort the entries low to high
for (i = m_length - 1; i >= 0; i--)
{
if (m_symbols[i].getNote() <= symbol.getNote())
{
// don't add duplicates
if (m_symbols[i].getNote() == symbol.getNote() &&
m_symbols[i].getType() == symbol.getType() &&
m_symbols[i].getHand() == symbol.getHand())
return true;
break;
}
// move the previous entry up one possition
m_symbols[i+1] = m_symbols[i];
}
m_symbols[i+1] = symbol;
m_length++;
return true;
}
// find
void CSlot::analyse()
{
int i;
int rightIndex = 0;
int leftIndex = 0;
int rightTotal = 0;
int leftTotal = 0;
for (i = 0; i < m_length; i++)
{
if (m_symbols[i].getType() == PB_SYMBOL_note)
{
if (m_symbols[i].getHand() == PB_PART_right)
rightTotal++;
else if (m_symbols[i].getHand() == PB_PART_left)
leftTotal++;
}
}
for (i = 0; i < m_length; i++)
{
if (m_symbols[i].getType() == PB_SYMBOL_note)
{
if (m_symbols[i].getHand() == PB_PART_right)
m_symbols[i].setIndex(rightIndex++, rightTotal);
else if (m_symbols[i].getHand() == PB_PART_left)
m_symbols[i].setIndex(leftIndex++, leftTotal );
}
}
}
bool CNotation::m_cfg_displayCourtesyAccidentals = false;
///////////////////////////////////////////////////////////////////////////
CSlot CNotation::nextBeatMarker()
{
const int cfg_barGap = CMidiFile::ppqnAdjust(30);
CSlot slot;
m_beatPerBarCounter++;
if (m_beatPerBarCounter >= m_bar.getTimeSigTop())
m_beatPerBarCounter = -1;
if (m_beatPerBarCounter == -1) // Sneak in a bar line
slot.setSymbol( m_bar.getBeatLength() - cfg_barGap, CSymbol( PB_SYMBOL_barLine, PB_PART_both, 0 ));
else if (m_beatPerBarCounter == 0)
slot.setSymbol( cfg_barGap, CSymbol( PB_SYMBOL_barMarker, PB_PART_both, 0 ));
else
slot.setSymbol( m_bar.getBeatLength(), CSymbol( PB_SYMBOL_beatMarker, PB_PART_both, 0 ));
return slot;
}
int CNotation::nextMergeSlot()
{
size_t i;
CSlot nearestSlot;
size_t nearestIndex;
nearestSlot = m_mergeSlots[0];
nearestIndex = 0;
for( i = 1; i < arraySize(m_mergeSlots); i++)
{
// find the slot with the lowest delta time
if (m_mergeSlots[i].getDeltaTime() < nearestSlot.getDeltaTime())
{
nearestSlot = m_mergeSlots[i];
nearestIndex = i;
}
}
// Now subtract the delta time from all the others
for( i = 0; i < arraySize(m_mergeSlots); i++)
{
if (i == nearestIndex)
continue;
m_mergeSlots[i].addDeltaTime( -nearestSlot.getDeltaTime() );
}
return nearestIndex;
}
accidentalModifer_t CNotation::detectSuppressedNatural(int note)
{
if (note <= 0 || note +1 >= MAX_MIDI_NOTES)
return PB_ACCIDENTAL_MODIFER_noChange;
accidentalModifer_t modifer = PB_ACCIDENTAL_MODIFER_noChange;
while (m_earlyBarChangeDelta >= m_bar.getBarLength())
{
m_earlyBarChangeDelta -= m_bar.getBarLength();
m_earlyBarChangeCounter++;
}
CNoteState * pNoteState = &m_noteState[note];
CNoteState * pBackLink = pNoteState->getBackLink();
int direction = -CStavePos::getStaveAccidentalDirection(note);
ppDEBUG_NOTATION(("Note %d %d %d", note, direction, pBackLink));
// check if this note has occurred in this bar before
if (pNoteState->getBarChange() == m_earlyBarChangeCounter)
{
if (pBackLink)
{
ppDEBUG_NOTATION(("Force %d", note));
modifer = PB_ACCIDENTAL_MODIFER_force;
}
else if (direction != 0 && m_cfg_displayCourtesyAccidentals == false)
{
ppDEBUG_NOTATION(("Suppress %d %d", note, direction));
modifer = PB_ACCIDENTAL_MODIFER_suppress;
}
}
if (direction != 0)
{
// we are display a accidental so force the note above (or below) to display
m_noteState[note + direction].setBackLink(pNoteState); // point back to this note
m_noteState[note + direction].setBarChange(m_earlyBarChangeCounter);
ppDEBUG_NOTATION(("setting backlink %d %d", note + direction, direction));
}
if (pBackLink)
{
pNoteState->setBackLink(0);
pBackLink->setBarChange(-1); // this prevents further suppression on the original note
}
pNoteState->setBarChange(m_earlyBarChangeCounter);
return modifer;
}
void CNotation::findNoteSlots()
{
CMidiEvent midi;
CSlot slot;
while (true)
{
// Check that some body has put in some events for us
if (m_midiInputQueue->length() == 0)
break;
midi = m_midiInputQueue->pop();
m_currentDeltaTime += midi.deltaTime();
m_earlyBarChangeDelta += midi.deltaTime();
if (midi.type() == MIDI_PB_chordSeparator || midi.type() == MIDI_PB_EOF)
{
if (m_currentSlot.length() > 0)
{
// the cord separator arrives very late so we are behind the times
m_currentSlot.analyse();
m_slotQueue->push(m_currentSlot);
m_currentSlot.clear();
}
if (midi.type() == MIDI_PB_EOF)
{
slot.setSymbol(0, CSymbol( PB_SYMBOL_theEnd, PB_PART_both, 0 ));
m_slotQueue->push(slot);
}
break;
}
else if (midi.type() == MIDI_PB_timeSignature)
m_bar.setTimeSig(midi.data1(), midi.data2());
else if (midi.type() == MIDI_PB_keySignature)
CStavePos::setKeySignature(midi.data1(), midi.data2());
else if (midi.type() == MIDI_NOTE_ON)
{
whichPart_t hand = CNote::findHand( midi, m_displayChannel, PB_PART_both );
if (hand != PB_PART_none)
{
musicalSymbol_t symbolType;
if (midi.channel() == MIDI_DRUM_CHANNEL)
symbolType = PB_SYMBOL_drum;
else
symbolType = PB_SYMBOL_note;
CSymbol symbol(symbolType, hand, midi.note());
symbol.setColour(Cfg::noteColour());
// check if this note has occurred in this bar before
symbol.setAccidentalModifer(detectSuppressedNatural(midi.note()));
if (m_currentSlot.addSymbol(symbol) == false) {
ppLogWarn("[%d] Over the Max symbols limit", m_displayChannel + 1);
}
m_currentSlot.addDeltaTime(m_currentDeltaTime);
m_currentDeltaTime = 0;
if (hand == PB_PART_left)
{
if (midi.note() < MIDI_BOTTOM_C)
m_currentSlot.setAv8Left(MIDI_OCTAVE);
}
}
}
}
}
CSlot CNotation::nextNoteSlot()
{
// only if the slot queue is empty should we try to find some more
if (m_slotQueue->length() == 0)
findNoteSlots();
if (m_slotQueue->length() > 0)
return m_slotQueue->pop();
else
return CSlot(); // this is an empty slot which means end of file
}
CSlot CNotation::nextSlot()
{
int mergeIdx;
CSlot slot;
if (m_mergeSlots[MERGESLOT_BEATMARK_INDEX].length() == 0)
{
// load up the two slots on start up
m_mergeSlots[MERGESLOT_NOTE_INDEX] = nextNoteSlot();
m_mergeSlots[MERGESLOT_BEATMARK_INDEX] = nextBeatMarker();
// This inserts the beat marksers into the queue early (so they get drawn underneath)
m_mergeSlots[MERGESLOT_BEATMARK_INDEX].addDeltaTime(
-CMidiFile::getPulsesPerQuarterNote() * BEAT_MARKER_OFFSET / DEFAULT_PPQN);
}
if (m_mergeSlots[0].getSymbolType(0) == PB_SYMBOL_theEnd)
return m_mergeSlots[0];
mergeIdx = nextMergeSlot();
slot = m_mergeSlots[mergeIdx];
if (mergeIdx == 0)
m_mergeSlots[mergeIdx] = nextNoteSlot();
else
m_mergeSlots[mergeIdx] = nextBeatMarker();
return slot;
}
void CNotation::midiEventInsert(CMidiEvent event)
{
if (m_findScrollerChord.findChord(event, m_displayChannel, PB_PART_both ) == true)
{
// the Score works differently we just send down a chord separator
CMidiEvent separator;
separator.chordSeparator(event);
m_midiInputQueue->push(separator);
}
m_midiInputQueue->push(event);
}
void CNotation::reset()
{
const int cfg_earlBarLead = CMidiFile::ppqnAdjust(8);
size_t i;
m_currentDeltaTime = 0;
m_midiInputQueue->clear();
m_slotQueue->clear();
for( i = 0; i < arraySize(m_mergeSlots); i++)
m_mergeSlots[i].clear();
m_currentSlot.clear();
m_beatPerBarCounter=0;
m_earlyBarChangeCounter = 0;
m_earlyBarChangeDelta = cfg_earlBarLead; // We want to detect the bar change early
m_bar.reset();
m_findScrollerChord.reset();
for( i = 0; i < MAX_MIDI_NOTES; i++)
{
m_noteState[i].clear();
}
}
pianobooster-src-0.6.4b/src/MidiEvent.h 0000644 0001747 0001747 00000015776 11251536777 017500 0 ustar ubuntu ubuntu /*********************************************************************************/
/*!
@file MidiEvent.h
@brief xxxxx.
@author L. J. Barman
Copyright (c) 2008-2009, L. J. Barman, all rights reserved
This file is part of the PianoBooster application
PianoBooster 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.
PianoBooster 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 PianoBooster. If not, see .
*/
/*********************************************************************************/
#ifndef __MIDI_EVENT_H__
#define __MIDI_EVENT_H__
#include "Util.h"
#define MIDI_NOTE_OFF 0x80 /* MIDI voice messages */
#define MIDI_NOTE_ON 0x90
#define MIDI_NOTE_PRESSURE 0xA0 //POLY_AFTERTOUCH: 3 bytes
#define MIDI_CONTROL_CHANGE 0xB0
#define MIDI_PROGRAM_CHANGE 0xC0
#define MIDI_CHANNEL_PRESSURE 0xD0 //AFTERTOUCH: 2 bytes
#define MIDI_PITCH_BEND 0xE0
#define MIDI_SYSTEM_EVENT 0xF0
#define MIDI_SUSTAIN 0x40
#define MIDI_MAIN_VOLUME 0x07
#define MIDI_RESET_ALL_CONTROLLERS 121
#define MIDI_ALL_SOUND_OFF 120
#define MIDI_ALL_NOTES_OFF 123 //0x7B channel mode message
// now define some of our own events
#define MIDI_NONE 0x0ff0
#define MIDI_ERROR 0x0ff1
#define MIDI_PB_EOF 0x0ff2
#define MIDI_PB_chordSeparator 0x0ff3 // All the notes (note on) between these counts as one chord
#define MIDI_PB_tempo 0x0ff4
#define MIDI_PB_timeSignature 0x0ff5
#define MIDI_PB_keySignature 0x0ff6
#define MIDI_PB_collateRawMidiData 0x0ff7
#define MIDI_PB_outputRawMidiData 0x0ff8 // Raw data is used for used for a SYSTEM_EVENT
/*===================================*/
/* */
/* Standard MIDI file events */
/* */
/*===================================*/
#define MIDI_SYSEXEVENT 0xF0
#define METAEVENT 0xFF
#define METASEQN 0
#define METATEXT 1
#define METACOPYR 2
#define METATNAME 3
#define METAINAME 4
#define METALYRIC 5
#define METAMARKER 6
#define METACUEPT 7
#define METACHANPFX 0x20
#define METAEOT 0x2F
#define METATEMPO 0x51
#define METASMPTEOFF 0x54
#define METATIMESIG 0x58
#define METAKEYSIG 0x59
#define METASEQEVENT 0x7F
#define MIDI_DRUM_CHANNEL (10-1)
#define MAX_MIDI_CHANNELS 16 // There are always at most 16 midi channels
#define GM_PIANO_PATCH 0 // The default grand piano sound
/*!
* @brief xxxxx.
*/
class CMidiEvent
{
public:
CMidiEvent()
{
clear();
}
void clear()
{
m_type = MIDI_NONE;
m_deltaTime = 0;
m_channel = 0;
m_note = 0;
m_velocity = 0;
}
int deltaTime(){return m_deltaTime;}
void addDeltaTime(int delta){m_deltaTime +=delta;}
void setDeltaTime(int delta){m_deltaTime = delta;}
////////////////////////////////////////////////////////////////////////////////
//@brief returns the midi note number
int note() const {return m_note;}
int programme() const {return m_note;}
int channel() const {return m_channel;}
void setChannel(int chan){m_channel = chan;}
int velocity() const {return m_velocity;}
int type() const {return m_type;}
void setType(int type){m_type = type;}
void transpose(int amount) {m_note += amount;}
int data1() const {return m_note;} // Meta data is stored here
int data2() const {return m_velocity;}
void setDatat2(int value) {m_velocity = value;}
void noteOffEvent( int deltaTime, int channel, int note, int velocity)
{
m_type = MIDI_NOTE_OFF;
m_deltaTime = deltaTime;
m_channel = channel;
m_note = note;
m_velocity = velocity;
}
void noteOnEvent( int deltaTime, int channel, int note, int velocity)
{
m_type = MIDI_NOTE_ON;
m_deltaTime = deltaTime;
m_channel = channel;
m_note = note;
m_velocity = velocity;
}
void notePressure( int deltaTime, int channel, int data1, int data2)
{
m_type = MIDI_NOTE_PRESSURE; //POLY_AFTERTOUCH: 3 bytes
m_deltaTime = deltaTime;
m_channel = channel;
m_note = data1;
m_velocity = data2;
}
void programChangeEvent( int deltaTime, int channel, int program)
{
m_type = MIDI_PROGRAM_CHANGE;
m_deltaTime = deltaTime;
m_channel = channel;
m_note = program;
m_velocity = 0;
}
void controlChangeEvent( int deltaTime, int channel, int data1, int data2)
{
m_type = MIDI_CONTROL_CHANGE;
m_deltaTime = deltaTime;
m_channel = channel;
m_note = data1;
m_velocity = data2;
}
void channelPressure( int deltaTime, int channel, int data1)
{
m_type = MIDI_CHANNEL_PRESSURE; //AFTERTOUCH: 2 bytes
m_deltaTime = deltaTime;
m_channel = channel;
m_note = data1;
m_velocity = 0;
}
void pitchBendEvent( int deltaTime, int channel, int data1, int data2)
{
m_type = MIDI_PITCH_BEND;
m_deltaTime = deltaTime;
m_channel = channel;
m_note = data1;
m_velocity = data2;
}
void chordSeparator(CMidiEvent &event)
{
m_type = MIDI_PB_chordSeparator;
m_note = 0;
m_channel = event.channel();
m_deltaTime = 0;
m_velocity = 0;
}
void metaEvent( int deltaTime, int type, int data1, int data2)
{
m_type = type;
m_deltaTime = deltaTime;
m_channel = 0;
m_note = data1;
m_velocity = data2;
}
// Raw data is used for used for a SYSTEM_EVENT
void collateRawByte( int deltaTime, int nextByte)
{
m_type = MIDI_PB_collateRawMidiData;
m_deltaTime = deltaTime;
m_note = nextByte;
m_velocity = 0;
}
// Raw data is used for used for a SYSTEM_EVENT
void outputCollatedRawBytes(int deltaTime)
{
m_type = MIDI_PB_outputRawMidiData;
m_deltaTime = deltaTime;
m_note = 0;
m_velocity = 0;
}
void printDetails()
{
ppTiming("chan %2d type %2X note %3d", channel(), type(), note() );
}
private:
int m_type;
int m_deltaTime;
int m_channel;
int m_note;
int m_velocity;
};
#endif //__MIDI_EVENT_H__
pianobooster-src-0.6.4b/src/Queue.h 0000644 0001747 0001747 00000005405 11303063627 016647 0 ustar ubuntu ubuntu /*********************************************************************************/
/*!
@file Queue.h
@brief xxxx.
@author L. J. Barman
Copyright (c) 2008-2009, L. J. Barman, all rights reserved
This file is part of the PianoBooster application
PianoBooster 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.
PianoBooster 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 PianoBooster. If not, see .
*/
/*********************************************************************************/
#ifndef __QUEUE_H__
#define __QUEUE_H__
#include
// A Queue or circular buffer also also call a FIFO a First In First Out buffer
// different threads could be running each end of the queue
//
template
class CQueue
{
public:
explicit CQueue(int size)
{
m_size = size;
m_buffer = new TYPE[size];
clear();
}
~CQueue()
{
delete [] m_buffer;
}
void clear()
{
m_count = m_head = m_tail=0;
}
void push(TYPE c)
{
if (!space())
{
assert(false);
return;
}
m_buffer[m_head++] = c;
if (m_head >= m_size)
m_head = 0;
// This must be last if a different thread is using pop()
m_count++;
}
TYPE pop()
{
TYPE c;
if (!length())
{
assert(false);
return m_buffer[m_tail];
}
c = m_buffer[m_tail++];
if (m_tail >= m_size)
m_tail = 0;
// This must be last if a different thread is using push()
m_count--;
return c;
}
TYPE * indexPtr(int index)
{
int offset;
if (index >= length())
{
assert(false);
return &m_buffer[m_head];
}
offset = m_tail + index;
if (offset >= m_size)
offset -= m_size;
return &m_buffer[offset];
}
TYPE index(int index){ return *indexPtr(index);}
int length() {return m_count;}
int space() {return m_size - m_count;}
private:
TYPE * m_buffer;
int m_size;
int m_head;
int m_tail;
// this should be atomic operation when two different threads are at each end of the queue
volatile int m_count;
};
#endif //__QUEUE_H__
pianobooster-src-0.6.4b/src/pianobooster.rc 0000755 0001747 0001747 00000000103 11240341260 020425 0 ustar ubuntu ubuntu IDI_ICON1 ICON DISCARDABLE "pianobooster.ico"
pianobooster-src-0.6.4b/src/Song.h 0000644 0001747 0001747 00000004677 11301345653 016503 0 ustar ubuntu ubuntu /*********************************************************************************/
/*!
@file Song.h
@brief xxx.
@author L. J. Barman
Copyright (c) 2008-2009, L. J. Barman, all rights reserved
This file is part of the PianoBooster application
PianoBooster 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.
PianoBooster 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 PianoBooster. If not, see .
*/
/*********************************************************************************/
#ifndef __SONG_H__
#define __SONG_H__
#include
#include "Notation.h"
#include "Conductor.h"
#include "TrackList.h"
#define PC_KEY_LOWEST_NOTE 58
#define PC_KEY_HIGHEST_NOTE 75
class CSong : public CConductor
{
public:
CSong()
{
CStavePos::setKeySignature( NOT_USED, 0 );
m_midiFile = new CMidiFile;
m_trackList = new CTrackList;
reset();
}
~CSong()
{
delete m_midiFile;
delete m_trackList;
}
void reset()
{
m_reachedMidiEof = false;
m_findChord.reset();
}
void init(CScore * scoreWin, CSettings* settings);
eventBits_t task(int ticks);
bool pcKeyPress(int key, bool down);
void loadSong(const QString &filename);
void regenerateChordQueue();
void rewind();
void playFromStartBar()
{
rewind();
playMusic(true);
}
void setActiveHand(whichPart_t hand);
whichPart_t getActiveHand(){return CNote::getActiveHand();}
void setActiveChannel(int part);
void setPlayMode(playMode_t mode);
CTrackList* getTrackList() {return m_trackList;}
void refreshScroll();
QString getSongTitle() {return m_songTitle;}
private:
void midiFileInfo();
CMidiFile * m_midiFile;
CFindChord m_findChord;
bool m_reachedMidiEof;
CChord m_fakeChord; // the chord played with the tab key
CTrackList* m_trackList;
QString m_songTitle;
};
#endif // __SONG_H__
pianobooster-src-0.6.4b/src/Bar.h 0000644 0001747 0001747 00000010502 11277632044 016266 0 ustar ubuntu ubuntu /*********************************************************************************/
/*!
@file Bar.h
@brief xxx.
@author L. J. Barman
Copyright (c) 2008-2009, L. J. Barman, all rights reserved
This file is part of the PianoBooster application
PianoBooster 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.
PianoBooster 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 PianoBooster. If not, see .
*/
/*********************************************************************************/
#ifndef __BAR_H__
#define __BAR_H__
#include "MidiFile.h"
// The event bits can be ORed together
#define EVENT_BITS_playingStopped 0x0001 //set when we reach the end of piece
#define EVENT_BITS_forceFullRedraw 0x0002 // force the whole screen to be redrawn
#define EVENT_BITS_forceRatingRedraw 0x0004 // force the score to be redrawn
#define EVENT_BITS_newBarNumber 0x0008 // force the bar number to be redrawn
#define EVENT_BITS_UptoBarReached 0x0010 // Used for looping when playing between two bars.
typedef unsigned long eventBits_t;
// controls the bar numbers
class CBar
{
public:
CBar() { reset(); }
// You MUST clear the time sig to 0 first before setting an new start Time Signature
// at the start of the piece of music
void setTimeSig(int top, int bottom);
int getTimeSigTop() {return m_currentTimeSigTop;} // The Numerator
int getBeatLength() {return m_beatLength;}
int getBarLength() {return m_barLength;} // in ppqn
void setPlayFromBar(double bar);
void setPlayFromBar(int bar, int beat = 0, int ticks = 0);
void reset() {
setTimeSig( 0 , 0);
m_playFromBar = 0.0;
m_playUptoBar = 0.0;
m_loopingBars = 0.0;
m_seekingBarNumber = false;
m_flushTicks = false;
m_eventBits = 0;
setupEnableFlags();
}
void setPlayUptoBar(double bar);
double getPlayUptoBar(){ return m_playUptoBar;}
void setLoopingBars(double bars);
double getLoopingBars(){ return m_loopingBars;}
void rewind() {
int top = m_startTimeSigTop;
int bottom = m_startTimeSigBottom;
setTimeSig( 0 , 0);
setTimeSig(top, bottom);
checkGotoBar();
}
void getTimeSig(int *top, int *bottom) {
*top = m_currentTimeSigTop;
*bottom = m_currentTimeSigBottom;
}
//return true if bar number has changed
int addDeltaTime(int ticks);
//
int getBarNumber(){ return m_barCounter;}
double getCurrentBarPos() { return m_barCounter + static_cast(m_beatCounter)/m_currentTimeSigBottom +
static_cast(m_deltaTime)/(m_beatLength * m_currentTimeSigBottom * SPEED_ADJUST_FACTOR); }
bool seekingBarNumber() { return m_seekingBarNumber;}
// get and reset the current bar event bits
eventBits_t readEventBits() {
eventBits_t bits = m_eventBits;
m_eventBits = 0;
return bits;
}
int goToBarNumer();
private:
void checkGotoBar();
void setupEnableFlags()
{
m_enableLooping = (m_loopingBars > 0.0)?true:false;
m_enablePlayFromBar = (m_enableLooping || m_playFromBar > 0.0)?true:false;
}
int m_deltaTime;
int m_beatLength; //in ppqn ticks
int m_barLength; // m_beatLength * getTimeSigTop() (also in ppqn ticks)
int m_startTimeSigTop; // The time Sig at the start of the piece
int m_startTimeSigBottom;
int m_currentTimeSigTop; // The current time Sig at the start of the piece
int m_currentTimeSigBottom;
int m_barCounter;
int m_beatCounter;
double m_playFromBar;
double m_playUptoBar;
double m_loopingBars;
int m_playFromBeat;
int m_playFromTicks;
bool m_seekingBarNumber;
bool m_flushTicks;
eventBits_t m_eventBits;
bool m_enableLooping;
bool m_enablePlayFromBar;
};
#endif // __BAR_H__
pianobooster-src-0.6.4b/src/MidiDeviceRt.cpp 0000755 0001747 0001747 00000017273 11277632044 020444 0 ustar ubuntu ubuntu /*********************************************************************************/
/*!
@file MidiDeviceRt.cpp
@brief MidiDeviceRt talks to the MidiRt Real Time Version.
@author L. J. Barman
Copyright (c) 2008-2009, L. J. Barman, all rights reserved
This file is part of the PianoBooster application
PianoBooster 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.
PianoBooster 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 PianoBooster. If not, see .
*/
/*********************************************************************************/
#include "MidiDeviceRt.h"
CMidiDeviceRt::CMidiDeviceRt()
{
m_midiout = new RtMidiOut();
m_midiin = new RtMidiIn();
m_midiPorts[0] = -1;
m_midiPorts[1] = -1;
m_rawDataIndex = 0;
}
CMidiDeviceRt::~CMidiDeviceRt()
{
delete m_midiout;
delete m_midiin;
}
void CMidiDeviceRt::init()
{
}
QStringList CMidiDeviceRt::getMidiPortList(midiType_t type)
{
unsigned int nPorts;
QString name;
RtMidi* midiDevice;
QStringList portNameList;
if (type == MIDI_INPUT)
midiDevice = m_midiin;
else
midiDevice = m_midiout;
nPorts = midiDevice->getPortCount();
for(unsigned int i=0; i< nPorts; i++)
{
name = midiDevice->getPortName(i).c_str();
if (name.startsWith("RtMidi"))
continue;
portNameList << name;
}
return portNameList;
}
bool CMidiDeviceRt::openMidiPort(midiType_t type, QString portName)
{
unsigned int nPorts;
QString name;
RtMidi* midiDevice;
if (portName.length() == 0)
return false;
int dev;
if (type == MIDI_INPUT)
{
midiDevice = m_midiin;
dev = 0;
}
else
{
midiDevice = m_midiout;
dev = 1;
}
nPorts = midiDevice->getPortCount();
for(unsigned int i=0; i< nPorts; i++)
{
name = midiDevice->getPortName(i).c_str();
if (name == portName) // Test for a match
{
if (m_midiPorts[dev] >= 0)
midiDevice->closePort();
m_midiPorts[dev] = i;
m_rawDataIndex = 0;
midiDevice->openPort( i );
return true;
}
}
return false;
}
void CMidiDeviceRt::closeMidiPort(midiType_t type, int index)
{
if (type == MIDI_INPUT)
m_midiin->closePort();
else
m_midiout->closePort();
}
//! add a midi event to be played immediately
void CMidiDeviceRt::playMidiEvent(const CMidiEvent & event)
{
if (m_midiPorts[1] < 0)
return;
unsigned int channel;
std::vector message;
channel = event.channel() & 0x0f;
switch(event.type())
{
case MIDI_NOTE_OFF: // NOTE_OFF
message.push_back( channel | MIDI_NOTE_OFF );
message.push_back( event.note());
message.push_back( event.velocity());
break;
case MIDI_NOTE_ON: // NOTE_ON
message.push_back( channel | MIDI_NOTE_ON );
message.push_back( event.note());
message.push_back( event.velocity());
break;
case MIDI_NOTE_PRESSURE: //POLY_AFTERTOUCH: 3 bytes
message.push_back( channel | MIDI_NOTE_PRESSURE);
message.push_back( event.data1());
message.push_back( event.data2());
break;
case MIDI_CONTROL_CHANGE: //CONTROL_CHANGE:
message.push_back( channel | MIDI_CONTROL_CHANGE);
message.push_back( event.data1());
message.push_back( event.data2());
break;
case MIDI_PROGRAM_CHANGE: //PROGRAM_CHANGE:
message.push_back( channel | MIDI_PROGRAM_CHANGE);
message.push_back( event.programme());
break;
case MIDI_CHANNEL_PRESSURE: //AFTERTOUCH: 2 bytes only
message.push_back( channel | MIDI_CHANNEL_PRESSURE);
message.push_back( event.data1());
break;
case MIDI_PITCH_BEND: //PITCH_BEND:
message.push_back( channel | MIDI_PITCH_BEND);
message.push_back( event.data1());
message.push_back( event.data2());
break;
case MIDI_PB_collateRawMidiData: //used for a SYSTEM_EVENT
if (m_rawDataIndex < arraySize(m_savedRawBytes))
m_savedRawBytes[m_rawDataIndex++] = event.data1();
return; // Don't output any thing yet so just return
case MIDI_PB_outputRawMidiData: //used for a SYSTEM_EVENT
for (size_t i = 0; i < m_rawDataIndex; i++)
message.push_back( m_savedRawBytes[i]);
m_rawDataIndex = 0;
break;
}
m_midiout->sendMessage( &message );
//event.printDetails(); // useful for debugging
}
// Return the number of events waiting to be read from the midi device
int CMidiDeviceRt::checkMidiInput()
{
if (m_midiPorts[0] < 0)
return 0;
m_midiin->getMessage( &m_inputMessage );
return m_inputMessage.size();
}
// reads the real midi event
CMidiEvent CMidiDeviceRt::readMidiInput()
{
CMidiEvent midiEvent;
unsigned int channel;
channel = m_inputMessage[0] & 0x0f;
switch (m_inputMessage[0] & 0xf0 )
{
case MIDI_NOTE_ON:
if (m_inputMessage[2] != 0 )
midiEvent.noteOnEvent(0, channel, m_inputMessage[1], m_inputMessage[2]);
else
midiEvent.noteOffEvent(0,channel, m_inputMessage[1], m_inputMessage[2]);
break;
case MIDI_NOTE_OFF:
midiEvent.noteOffEvent(0, channel, m_inputMessage[1], m_inputMessage[2]);
break;
case MIDI_NOTE_PRESSURE: //MIDI_CMD_NOTE_PRESSURE: //POLY_AFTERTOUCH:
// fixme fill in the blanks
//midi_input_bytes[midi_input_length++] = channel | MIDI_CMD_NOTE_PRESSURE;
//midi_input_bytes[midi_input_length++] = ev->data.note.note;
//midi_input_bytes[midi_input_length++] = ev->data.note.velocity;
break;
case MIDI_CONTROL_CHANGE: //CONTROL_CHANGE:
midiEvent.controlChangeEvent(0, channel, m_inputMessage[1], m_inputMessage[2]);
break;
case MIDI_PROGRAM_CHANGE: //PROGRAM_CHANGE:
//midiEvent.programChangeEvent(0, ev->data.control.channel, ev->data.control.value);
break;
case MIDI_CHANNEL_PRESSURE: //AFTERTOUCH:
// fixme fill in the blanks
//midi_input_bytes[midi_input_length++] = ev->data.control.channel | MIDI_CMD_CHANNEL_PRESSURE;
//midi_input_bytes[midi_input_length++] = ev->data.control.value;
break;
case MIDI_PITCH_BEND: //PITCH_BEND:
// fixme fill in the blanks
//midi_input_bytes[midi_input_length++] = ev->data.control.channel | MIDI_CMD_CHANNEL_PRESSURE;
//midi_input_bytes[midi_input_length++] = ev->data.control.value;
break;
}
m_inputMessage.clear();
return midiEvent;
}
int CMidiDeviceRt::midiSettingsSetStr(QString name, QString str)
{
return 0;
}
int CMidiDeviceRt::midiSettingsSetNum(QString name, double val)
{
return 0;
}
int CMidiDeviceRt::midiSettingsSetInt(QString name, int val)
{
return 0;
}
QString CMidiDeviceRt::midiSettingsGetStr(QString name)
{
return QString();
}
double CMidiDeviceRt::midiSettingsGetNum(QString name)
{
return 0.0;
}
int CMidiDeviceRt::midiSettingsGetInt(QString namel)
{
return 0;
}
pianobooster-src-0.6.4b/src/MidiTrack.cpp 0000644 0001747 0001747 00000031761 11303601311 017755 0 ustar ubuntu ubuntu /*********************************************************************************/
/*!
@file MidiTrack.cpp
@brief xxxx.
@author L. J. Barman
Copyright (c) 2008-2009, L. J. Barman, all rights reserved
This file is part of the PianoBooster application
PianoBooster 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.
PianoBooster 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 PianoBooster. If not, see .
*/
/*********************************************************************************/
#include
#include "MidiTrack.h"
#include "Util.h"
#include "StavePosition.h"
#define OPTION_DEBUG_TRACK 0
#if OPTION_DEBUG_TRACK
#define ppDEBUG_TRACK(args) ppDebugTrack args
#else
#define ppDEBUG_TRACK(args)
#endif
int CMidiTrack::m_logLevel;
CMidiTrack::CMidiTrack(fstream& file, int no) :m_file(file), m_trackNumber(no)
{
m_trackEventQueue = 0;
m_savedRunningStatus = 0;
m_trackLengthCounter = 0;
m_deltaTime = 0;
midiFailReset();
int i;
m_trackName.clear();
m_trackLengthCounter = 8;
for ( i=0; i < 4; i++)
{
if (m_file.get() !="MTrk"[i] )
{
ppLogError("No valid Midi tracks");
errorFail(SMF_CORRUPTED_MIDI_FILE);
return;
}
}
m_trackLengthCounter = readDWord();
ppDEBUG_TRACK((9, "Track Length %d", m_trackLengthCounter));
m_filePos = m_file.tellg();
m_trackLength = m_trackLengthCounter + 8; // 4 bytes for the "MTrk" + 4 bytes for the track length
m_trackEventQueue = new CQueue(m_trackLength/3); // The minimum bytes per event is 3
}
void CMidiTrack::ppDebugTrack(int level, const char *msg, ...)
{
va_list ap;
if (level =3)
errorFail(SMF_END_OF_FILE);
}
}
#if OPTION_DEBUG_TRACK
if (value > 400)
ppDEBUG_TRACK((2,"Large variable length data %d", value));
#endif
return ( value );
}
string CMidiTrack::readTextEvent()
{
dword_t length;
string text;
length = readVarLen();
if (length >= 100)
{
ppLogError("Text Event too large %d", length);
errorFail(SMF_END_OF_FILE);
return text;
}
while (length--)
{
if (failed() == true)
return text;
text += readByte();
}
return text;
}
dword_t CMidiTrack::readDataEvent(int expectedLength)
{
int length;
dword_t data;
length = readByte();
if (length != expectedLength)
{
errorFail(SMF_CORRUPTED_MIDI_FILE);
return 0;
}
data = 0;
while (length--)
{
data <<= 8;
data |= readByte();
}
return data;
}
void CMidiTrack::ignoreSysexEvent(byte_t data)
{
word_t length;
if (data >= 127)
{
// this could be a variable length word
ppLogWarn("SysexEvent, is too long %d", data);
errorFail(SMF_CORRUPTED_MIDI_FILE);
return;
}
else
length = data;
while (length-- > 0 )
{
if (failed() == true)
return;
readByte();
}
}
/* Time Signature */
void CMidiTrack::readTimeSignatureEvent()
{
byte_t len;
byte_t timeSigNumerator;
byte_t timeSigDenominator;
CMidiEvent event;
byte_t b3, b4;
len = readVarLen();
if (len!=4)
{
errorFail(SMF_CORRUPTED_MIDI_FILE);
return;
}
timeSigNumerator = readByte(); // The number on the top
timeSigDenominator = readByte(); // the number on the bottom
if (timeSigDenominator >= 5)
{
errorFail(SMF_CORRUPTED_MIDI_FILE);
return;
}
if (timeSigNumerator > 20)
{
errorFail(SMF_CORRUPTED_MIDI_FILE);
return;
}
len = (1<push(event);
ppDEBUG_TRACK((4,"Key Signature %d/%d metronome %d quarter %d", timeSigNumerator, 1<(readByte()); // force sign conversion The key sig 0=middle C
majorKey =readByte(); // Major or Minor
if (keySig >= 7 || keySig <= -7 )
{
errorFail(SMF_CORRUPTED_MIDI_FILE);
return;
}
event.metaEvent(readDelaTime(), MIDI_PB_keySignature, keySig, majorKey);
m_trackEventQueue->push(event);
ppDEBUG_TRACK((4,"Key Signature %d maj/min %d", keySig, majorKey));
if (CStavePos::getKeySignature() == NOT_USED)
CStavePos::setKeySignature(event.data1(), event.data2());
}
void CMidiTrack::readMetaEvent(byte_t type)
{
string text;
dword_t data;
if (failed() == true)
return;
CMidiEvent event;
switch (type)
{
case METASEQN: /* Sequence Number */
data = readDataEvent(2);
ppDEBUG_TRACK((3,"Sequence Number %lu", data));
break;
case METACOPYR: /* Copyright Notice */
text = readTextEvent();
ppDEBUG_TRACK((3,"Copyright %s", text.c_str()));
break;
case METATNAME: /* Seq/Track Name */
text = readTextEvent();
m_trackName = QString(text.c_str());
ppDEBUG_TRACK((3,"Seq/Track Name %s", text.c_str()));
break;
case METAINAME: /* Instrument */
text = readTextEvent();
ppDEBUG_TRACK((2,"Instrument %s", text.c_str()));
break;
case METAEOT: /* End of Track */
readVarLen();
ppDEBUG_TRACK((2,"End of Track"));
break;
case METATEMPO: /* Set Tempo */
{
register byte b1,b2, b3;
int tempo;
b1 = readVarLen();
if (b1 != 3)
{
errorFail(SMF_CORRUPTED_MIDI_FILE);
break;
}
b1 = readByte();
b2 = readByte();
b3 = readByte();
tempo = b1 << 16 | b2 << 8 | b3; // microseconds per quarter-note#
event.metaEvent(readDelaTime(), MIDI_PB_tempo, tempo, 0);
m_trackEventQueue->push(event);
ppDEBUG_TRACK((2,"Set Tempo %d", tempo));
break;
}
case METATIMESIG: /* Time Signature */
readTimeSignatureEvent();
break;
case METAKEYSIG: /* Key Signature */
readKeySignatureEvent();
break;
case METATEXT: /* Text Event */
text = readTextEvent();
ppDEBUG_TRACK((2,"Text %s", text.c_str()));
break;
case METALYRIC: /* Lyric */
text = readTextEvent();
ppDEBUG_TRACK((2,"Lyric %s", text.c_str()));
break;
case METAMARKER:
text = readTextEvent();
ppDEBUG_TRACK((2,"METAMARKER %s", text.c_str()));
break;
case METACUEPT:
text = readTextEvent();
ppDEBUG_TRACK((2,"METACUEPT %s", text.c_str()));
break;
case METACHANPFX: /* Midi Channel Prefix */
data = readDataEvent(1);
ppDEBUG_TRACK((2,"MIDI Channel Prefix %lu", data));
break;
case METASMPTEOFF: /* SMPTE Offset */
text = readTextEvent();
ppDEBUG_TRACK((2,"SMPTE Offset %s", text.c_str()));
break;
case METASEQEVENT: /* sequencer Specific */
text = readTextEvent();
ppDEBUG_TRACK((2,"sequencer Specific %s", text.c_str()));
break;
case 0x21: /* MIDI Port */
data = readDataEvent(1);
ppDEBUG_TRACK((2,"MIDI Port %lu", data));
break;
case 0x09: // meta type
text = readTextEvent();
ppDEBUG_TRACK((2,"midi meta event 0x%02x %s", type, text.c_str()));
break;
default: /* Unknown meta type */
text = readTextEvent();
ppLogWarn("unknown midi meta event 0x%02x %s", type, text.c_str());
//errorFail(SMF_UNKNOW_EVENT);
break;
}
}
void CMidiTrack::decodeSystemMessage( byte_t status, byte_t data1 )
{
switch ( status )
{
case MIDI_SYSEXEVENT: /* System exclusive Transmitted */
case 0xf7: /* System exclusive Not transmitted */
ppDEBUG_TRACK((2,"SYSEXEVENT xx"));
/*ignore_sysex_event();*/
ignoreSysexEvent(data1);
break;
case METAEVENT:
readMetaEvent(data1);
break;
default:
ppDEBUG_TRACK((99,"UNKNOWN"));
ignoreSysexEvent(data1);
errorFail(SMF_UNKNOW_EVENT);
break;
}
}
void CMidiTrack::decodeMidiEvent()
{
CMidiEvent event;
byte_t c;
byte_t status, data1, data2;
int channel;
m_deltaTime += readVarLen();
c = readByte();
if ((c & 0x80) == 0 )
{
status = m_savedRunningStatus;
data1 = c;
}
else
{
status = c;
m_savedRunningStatus = status;
data1=readByte();
}
channel = status & 0x0f;
switch ( status & 0xf0 )
{
case MIDI_NOTE_OFF: /* Note off */
data2 = readByte();
event.noteOffEvent(readDelaTime(), channel, data1, data2);
m_trackEventQueue->push(event);
ppDEBUG_TRACK((1,"Chan %d Note off", channel + 1));
break;
case MIDI_NOTE_ON: /* Note on */
data2 = readByte();
if (data2 != 0 )
{
event.noteOnEvent(readDelaTime(), channel, data1, data2);
ppDEBUG_TRACK((1,"Chan %d note on %d",channel + 1, data1));
}
else
{
event.noteOffEvent(readDelaTime(),channel, data1, 0);
ppDEBUG_TRACK((1,"Chan %d note OFF %d",channel + 1, data1));
}
m_trackEventQueue->push(event);
break;
case MIDI_NOTE_PRESSURE : /* Key pressure After touch (POLY_AFTERTOUCH) 3 bytes */
data2 = readByte();
event.notePressure(readDelaTime(), channel, data1, data2);
m_trackEventQueue->push(event);
ppDEBUG_TRACK((2,"Chan %d After touch", channel + 1));
break;
case MIDI_PROGRAM_CHANGE : /* program change */
event.programChangeEvent(readDelaTime(), channel, data1);
m_trackEventQueue->push(event);
ppDEBUG_TRACK((2,"Chan %d Program change %d", channel + 1, data1 + 1));
break;
case MIDI_CONTROL_CHANGE : /* Control Change */
data2 = readByte();
event.controlChangeEvent(readDelaTime(), channel, data1, data2);
m_trackEventQueue->push(event);
ppDEBUG_TRACK((2,"Chan %d Control Change %d %d", channel + 1, data1, data2));
break;
case MIDI_CHANNEL_PRESSURE: /* Channel Pressure (AFTERTOUCH)*/
event.channelPressure(readDelaTime(), channel, data1);
m_trackEventQueue->push(event);
ppDEBUG_TRACK((2,"Chan %d Channel Pressure", channel + 1));
break;
case MIDI_PITCH_BEND: /* Pitch bend */
data2 = readByte();
event.pitchBendEvent(readDelaTime(), channel, data1, data2);
m_trackEventQueue->push(event);
ppDEBUG_TRACK((2,"Chan %d Pitch bend",channel + 1));
break;
case MIDI_SYSEXEVENT : /* System EX */
decodeSystemMessage(status, data1);
m_savedRunningStatus=0;
break;
}
}
void CMidiTrack::decodeTrack()
{
CMidiEvent event;
m_file.seekg(m_filePos, ios::beg);
while (true)
{
if (m_trackLengthCounter== 0)
break;
if (m_trackEventQueue->space() <= 1)
{
ppLogError("Out of Space");
break;
}
decodeMidiEvent();
if (failed() == true)
break;
}
m_filePos = m_file.tellg();
}
pianobooster-src-0.6.4b/src/Piano.cpp 0000644 0001747 0001747 00000016637 11277632044 017202 0 ustar ubuntu ubuntu /*********************************************************************************/
/*!
@file Piano.cpp
@brief xxx.
@author L. J. Barman
Copyright (c) 2008-2009, L. J. Barman, all rights reserved
This file is part of the PianoBooster application
PianoBooster 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.
PianoBooster 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 PianoBooster. If not, see .
*/
/*********************************************************************************/
#include
#include "Util.h"
#include "Piano.h"
#include "Cfg.h"
#include "StavePosition.h"
#include "Settings.h"
#define PIANO_LINE_LENGTH_LONG 64
#define PIANO_LINE_LENGTH_SHORT 48
static const float minNameGap = 14.0;
void CPiano::spaceNoteBunch(unsigned int bottomIndex, unsigned int topIndex)
{
unsigned int midPoint;
int i;
float lastY;
float gap;
int range;
range = topIndex - bottomIndex;
if (range <= 1)
return;
midPoint = range/2 + bottomIndex;
if (range%2 == 0) // test for an even number of notes
{
gap = m_noteNameList[midPoint].posY - m_noteNameList[midPoint -1].posY;
if (gap < minNameGap)
{
gap = (minNameGap - gap)/2;
m_noteNameList[midPoint].posY += gap; // then move the middle two notes apart by the same amout
m_noteNameList[midPoint-1].posY -= gap;
}
}
lastY = m_noteNameList[midPoint].posY;
// Search from the middle upwards
for (i = midPoint + 1; i < static_cast(topIndex); i++)
{
gap = m_noteNameList[i].posY - lastY;
// If the gap is too small make it bigger
if (gap < minNameGap)
m_noteNameList[i].posY = lastY + minNameGap;
lastY = m_noteNameList[i].posY;
}
lastY = m_noteNameList[midPoint].posY;
// now go the other way
for (i = midPoint - 1; i >= 0; i--)
{
gap = lastY - m_noteNameList[i].posY;
if (gap < minNameGap)
m_noteNameList[i].posY = lastY - minNameGap;
lastY = m_noteNameList[i].posY;
}
}
void CPiano::drawPianoInputNoteNames()
{
unsigned int i;
if (m_noteNameListLength >8) // too many notes so don't name any of them
return;
for (i = 0; i < m_noteNameListLength; i++)
{
drawNoteName(m_noteNameList[i].pitch, Cfg::playZoneX() - PIANO_LINE_LENGTH_SHORT - 14, m_noteNameList[i].posY, m_noteNameList[i].type);
}
}
void CPiano::drawPianoInputLines(CChord* chord, CColour colour, int lineLength)
{
int i;
drColour(colour);
CStavePos stavePos;
for ( i = 0; i < chord->length(); i++)
{
int pitch = chord->getNote(i).pitch();
stavePos.notePos(chord->getNote(i).part(), pitch);
glLineWidth (3.0);
if (stavePos.getAccidental() != 0)
{
glEnable (GL_LINE_STIPPLE);
glLineStipple (1, 0x0f0f); /* dashed */
glLineWidth (3.0);
}
float posY;
posY = stavePos.getPosYAccidental();
oneLine(Cfg::playZoneX() - lineLength, posY, Cfg::playZoneX(), posY);
glDisable (GL_LINE_STIPPLE);
}
}
void CPiano::spaceNoteNames()
{
unsigned int bottomIndex;
unsigned int topIndex;
bool foundBunch = false;
m_noteNameList[0].posY = m_noteNameList[0].posYOriginal;
if (m_noteNameListLength <= 1)
return;
bottomIndex = m_noteNameListLength;
topIndex = 0;
foundBunch = false;
for (unsigned int i=1; i < m_noteNameListLength; i++)
{
m_noteNameList[i].posY = m_noteNameList[i].posYOriginal;
if (m_noteNameList[i].posY - m_noteNameList[i-1].posY < minNameGap)
{
if (bottomIndex>i) bottomIndex = i;
if (topIndex= arraySize(m_noteNameList))
return;
noteNameItem.posY = noteNameItem.posYOriginal = posY;
noteNameItem.type = type;
noteNameItem.pitch = pitch;
// Sort the entries low to high
for (i = m_noteNameListLength - 1; i >= 0; i--)
{
if (m_noteNameList[i].pitch <= pitch)
break;
// move the previous entry up one position
m_noteNameList[i+1] = m_noteNameList[i];
}
if (m_noteNameList[i].pitch == pitch)
return; // ignore duplicates
m_noteNameList[i+1] = noteNameItem;
m_noteNameListLength++;
spaceNoteNames();
}
void CPiano::addPianistNote(whichPart_t part, int note, bool good)
{
CStavePos stavePos;
float posY;
stavePos.notePos(part, note);
if (stavePos.getStaveIndex() >= MAX_STAVE_INDEX || stavePos.getStaveIndex() <= MIN_STAVE_INDEX )
return;
if (good == true)
m_goodChord.addNote(part, note);
else
m_badChord.addNote(part, note);
posY = stavePos.getPosYAccidental();
addNoteNameItem(posY, note, 0);
}
void CPiano::removeNoteNameItem(int pitch)
{
unsigned int i;
bool foundMatch = false;
for (i=0; i < m_noteNameListLength; i++)
{
if (foundMatch == true)
m_noteNameList[i-1] = m_noteNameList[i]; // found a match so move every thing else up
if (m_noteNameList[i].pitch == pitch)
foundMatch = true;
}
if (m_noteNameListLength>0 && foundMatch)
m_noteNameListLength--;
spaceNoteNames();
}
// returns true only if the note is in the bad note list
bool CPiano::removePianistNote(int note)
{
removeNoteNameItem( note);
m_goodChord.removeNote(note);
return m_badChord.removeNote(note);
}
void CPiano::noteNameListClear()
{
m_noteNameListLength = 0;
}
// Counts the number of notes the pianist has down
int CPiano::pianistAllNotesDown()
{
return m_goodChord.length() + m_badChord.length();
}
int CPiano::pianistBadNotesDown()
{
return m_badChord.length();
}
void CPiano::clear()
{
m_goodChord.clear();
m_badChord.clear();
noteNameListClear();
}
void CPiano::drawPianoInput()
{
bool showNoteName = m_settings->showNoteNames();
int lineLength = (showNoteName) ? PIANO_LINE_LENGTH_SHORT : PIANO_LINE_LENGTH_LONG;
if (m_goodChord.length() > 0)
drawPianoInputLines(&m_goodChord, Cfg::pianoGoodColour(), lineLength);
if (m_badChord.length() > 0)
drawPianoInputLines(&m_badChord, Cfg::pianoBadColour(), lineLength);
if (showNoteName)
drawPianoInputNoteNames();
}
pianobooster-src-0.6.4b/src/application.qrc 0000644 0001747 0001747 00000000740 11136625566 020433 0 ustar ubuntu ubuntu
images/Logo32x32.png
images/copy.png
images/cut.png
images/flag.png
images/new.png
images/open.png
images/paste.png
images/play-from-start.png
images/play.png
images/save.png
images/stop.png
pianobooster-src-0.6.4b/src/Chord.h 0000644 0001747 0001747 00000013032 11251536777 016632 0 ustar ubuntu ubuntu /*********************************************************************************/
/*!
@file Chord.h
@brief Find the all the chords in a piece of music.
@author L. J. Barman
Copyright (c) 2008-2009, L. J. Barman, all rights reserved
This file is part of the PianoBooster application
PianoBooster 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.
PianoBooster 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 PianoBooster. If not, see .
*/
/*********************************************************************************/
#ifndef __CHORD_H__
#define __CHORD_H__
#include
#include "Cfg.h"
#include "MidiFile.h"
#include "Queue.h"
////////////////////////////////////////////////////////////////////////////////
//! @brief The part for each hand uses a different midi channel
typedef enum
{
PB_PART_both = 200, // keep well clear of real midi channels
PB_PART_right,
PB_PART_left,
PB_PART_accump,
PB_PART_all,
PB_PART_none,
} whichPart_t;
#define MAX_CHORD_NOTES 20 // The maximum notes in a chord well we only have 10 fingers
class CNote
{
public:
CNote()
{
m_part = PB_PART_none;
m_pitch = 0;
m_duration = 0;
}
CNote(whichPart_t part, int note, int duration = 0)
{
m_part = part;
m_pitch = note;
m_duration = duration;
}
void transpose(int amount)
{
m_pitch += amount;
}
int pitch() {return m_pitch;}
whichPart_t part() {return m_part;}
void setPart(whichPart_t part) {m_part = part;}
static whichPart_t findHand(int midiNote, int midiChannel, int whichChannel, whichPart_t whichPart);
static whichPart_t findHand(CMidiEvent midi, int channel, whichPart_t part)
{
return findHand(midi.note(), midi.channel(), channel, part);
}
static void setChannelHands(int left, int right);
static void setActiveHand(whichPart_t hand){m_activeHand = hand;}
static whichPart_t getActiveHand(){return m_activeHand;}
static int rightHandChan() {return m_rightHandChannel;}
static int leftHandChan() {return m_leftHandChannel;}
static int bothHandsChan() {return m_leftHandChannel;}
static int getHandChannel(whichPart_t whichPart) { return (whichPart == PB_PART_right) ? m_rightHandChannel : m_leftHandChannel;}
static bool hasPianoPart(int chan) { return (m_leftHandChannel == chan || m_rightHandChannel == chan ) ? true : false;}
private:
whichPart_t m_part;
int m_pitch;
int m_duration;
static int m_leftHandChannel;
static int m_rightHandChannel;
static whichPart_t m_activeHand;
};
class CNoteRange
{
public:
int highestNote; // The highest note in the range (often on the users piano keyboard)
int lowestNote;
};
class CChord
{
public:
CChord()
{
clear();
}
CNote getNote(int index) {return m_notes[index];}
int length() {return m_length;}
void setDeltaTime(int delta) {m_deltaTime = delta;}
int getDeltaTime() {return m_deltaTime;}
void clear() { m_length = 0; m_deltaTime = 0;}
void addNote(whichPart_t part, int note, int duration = 0);
bool removeNote(int note);
bool searchChord(int note, int transpose = 0);
int trimOutOfRangeNotes(int transpose);
void transpose(int amount)
{
for (int i = 0; i < m_length; i++)
{
m_notes[i].transpose(amount);
}
}
static void setPianoRange(int lowestNote, int highestNote ){
m_cfg_highestPianoNote = highestNote; // The highest note on the users piano keyboard;
m_cfg_lowestPianoNote = lowestNote;
}
static bool isNotePlayable(int note, int transpose )
{
note += transpose;
if (note >= m_cfg_lowestPianoNote && note <= m_cfg_highestPianoNote)
return true;
return false;
}
static bool isHandPlayable(whichPart_t hand)
{
if (CNote::getActiveHand() == PB_PART_both)
return true;
if (CNote::getActiveHand() == hand)
return true;
return false;
}
private:
int m_deltaTime;
CNote m_notes[MAX_CHORD_NOTES];
int m_length;
static int m_cfg_highestPianoNote; // The highest note on the users piano keyboard;
static int m_cfg_lowestPianoNote;
};
// Define a chord
class CFindChord
{
public:
CFindChord()
{
reset();
}
void reset()
{
m_noteGapTime = 0;
m_cordSpanGapTime = 0;
m_completeChord.clear();
m_currentChord.clear();
m_cfg_ChordNoteGap = CMidiFile::ppqnAdjust(Cfg::chordNoteGap());
m_cfg_ChordMaxLength = CMidiFile::ppqnAdjust(Cfg::chordMaxLength());
}
CChord getChord()
{
CChord chord;
chord = m_completeChord;
m_completeChord.clear();
return chord;
}
bool findChord(CMidiEvent midi, int channel, whichPart_t part);
private:
int m_noteGapTime;
int m_cordSpanGapTime;
CChord m_currentChord;
CChord m_completeChord;
int m_cfg_ChordNoteGap;
int m_cfg_ChordMaxLength;
};
#endif // __CHORD_H__
pianobooster-src-0.6.4b/src/ReleaseNote.txt 0000644 0001747 0001747 00000005446 11367323106 020367 0 ustar ubuntu ubuntu #define PB_VERSION "0.6.4b"
/*
v0.6.4b: (2 May 2010)
- Fixed Segfault in Pianobooster 0.6.4 (karmic racb) on lucid lynx ubuntu
v0.6.4: (28 November 2009)
- Added note names for beginners (to be used with a piano note name cut-out.)
- Added assignable left and right midi channels.
- Improved the MIDI timing accuracy.
- Greatly reduced the memory footprint.
- Reduced the CPU load.
- Reduced the screen flicker (recommend setting screen refresh rate to 60Hz
and for Intel Graphic chips updating the drivers).
- Added keyboard shortcuts. These are - speed up/down, play from start,
play/pause, next previous song, left right both hands.
- Remembers the song settings in a configuration file called "pb.cfg".
These are the midi channels, speed, left right or both hands.
- Now works well Ubuntu 9.10 and Intel graphic chips.
(Those with Ubuntu 9.04 and Intel should upgrade to 9.10 and this version)
- Fixed various startup issues.
- Now correctly displays repeated accidentals in one bar..
- Added the option to display courtesy accidentals.
- Added a simple help page.
- Added an installer for windows.
- Make install now works for Linux.
- Now works with small screens eg an EEE-701 (for Trev)
v0.6.2: (01 April 2009)
- added "" as instrument sound.
- when setting a latency fix of >0 the instrument is automatically set to 'None'
- turn all the sound off when exiting the program.
- Added looping to continually play between to bars.
- Added the option to change the follow mode stop point.
- Automatically switches the follow mode stop point if you are playing well enough.
- Added a logo to the source tree in "images/logo64x64.png"
v0.6.1: (11 March 2009)
- Added a play from bar (so you can start from playing any bar)
- Added a latency fix for high latency sound generators (e.g. the windows GS software synth)
(requires a piano keyboard _with_ it's own speakers/sound generator)
- Added the ability to "mute your part when playing" along.
- May have reduced the flickering especially on windows with a low spec machine
- Added a piano volume slider (so you can adjust the volume of your piano with compared
to the accompaniment)
- Added an icon for the Piano Booster main window.
- Fix a bug when swapping hands in the middle of a piece.
- Fix a bug left or right now correctly dim the other stave.
- Added start-up checks that Open GL is present.
- Fix the pulse of sound when stopping the music
- Added "timing markers" which show when the pianist pressed the note.
- Changed the build so that it now works on the Mac (thanks to Christian)
v0.5.1: (1 January 2009)
- fixed the windows file open bug
- changed the default wrong note sound to Harpsichord
- changed the wrong note sound to use a separate midi channel.
- on Windows removed the dos console
v0.5.0: (28 November 2008)
- first release
*/
pianobooster-src-0.6.4b/src/MidiDeviceBase.h 0000755 0001747 0001747 00000004464 11232414516 020365 0 ustar ubuntu ubuntu /*********************************************************************************/
/*!
@file MidiDevice.h
@brief xxxxxx.
@author L. J. Barman
Copyright (c) 2008-2009, L. J. Barman, all rights reserved
This file is part of the PianoBooster application
PianoBooster 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.
PianoBooster 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 PianoBooster. If not, see .
*/
/*********************************************************************************/
#ifndef __MIDI_DEVICE_BASE_H__
#define __MIDI_DEVICE_BASE_H__
#include
#include "Util.h"
/*!
* @brief xxxxx.
*/
#include "MidiEvent.h"
class CMidiDeviceBase
{
public:
virtual void init() = 0;
//! add a midi event to be played immediately
virtual void playMidiEvent(const CMidiEvent & event) = 0;
virtual int checkMidiInput() = 0;
virtual CMidiEvent readMidiInput() = 0;
typedef enum {MIDI_INPUT, MIDI_OUTPUT} midiType_t;
virtual QStringList getMidiPortList(midiType_t type) = 0;
virtual bool openMidiPort(midiType_t type, QString portName) = 0;
virtual void closeMidiPort(midiType_t type, int index) = 0;
// based on the fluid synth settings
virtual int midiSettingsSetStr(QString name, QString str) = 0;
virtual int midiSettingsSetNum(QString name, double val) = 0;
virtual int midiSettingsSetInt(QString name, int val) = 0;
virtual QString midiSettingsGetStr(QString name) = 0;
virtual double midiSettingsGetNum(QString name) = 0;
virtual int midiSettingsGetInt(QString name) = 0;
//you should always have a virtual destructor when using virtual functions
virtual ~CMidiDeviceBase() {};
private:
};
#endif //__MIDI_DEVICE_H__
pianobooster-src-0.6.4b/src/GuiTopBar.h 0000644 0001747 0001747 00000004455 11303063627 017423 0 ustar ubuntu ubuntu /*********************************************************************************/
/*!
@file GuiTopBar.cpp
@brief xxxx.
@author L. J. Barman
Copyright (c) 2008-2009, L. J. Barman, all rights reserved
This file is part of the PianoBooster application
PianoBooster 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.
PianoBooster 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 PianoBooster. If not, see .
*/
/*********************************************************************************/
#ifndef __GUITOPBAR_H__
#define __GUITOPBAR_H__
#include
#include "Song.h"
#include "Score.h"
#include "TrackList.h"
#include "Settings.h"
#include "ui_GuiTopBar.h"
class GuiTopBar : public QWidget, private Ui::GuiTopBar
{
Q_OBJECT
public:
GuiTopBar(QWidget *parent, CSettings* settings);
void init(CSong* songObj, CTrackList* trackList);
void refresh(bool reset);
void setPlayButtonState(bool checked, bool atTheEnd = false);
void setSpeed(int value){ speedSpin->setValue(value); }
int getSpeed(){return speedSpin->value();}
public slots:
void on_playFromStartButton_clicked(bool clicked);
void on_playButton_clicked(bool clicked);
private slots:
void on_speedSpin_valueChanged(int speed);
void on_startBarSpin_valueChanged(double bar);
void on_transposeSpin_valueChanged(int value);
void on_keyCombo_activated(int index);
void on_majorCombo_activated(int index)
{
reloadKeyCombo((index == 0)?true:false);
}
void on_saveBarButton_clicked(bool clicked);
void on_loopingBarsPopupButton_clicked(bool clicked);
private:
bool eventFilter(QObject *obj, QEvent *event);
void reloadKeyCombo(bool major);
CSong* m_song;
CSettings* m_settings;
bool m_atTheEndOfTheSong;
};
#endif //__GUITOPBAR_H__
pianobooster-src-0.6.4b/src/GuiKeyboardSetupDialog.ui 0000644 0001747 0001747 00000024454 11113115032 022307 0 ustar ubuntu ubuntu
GuiKeyboardSetupDialog
0
0
501
348
501
16777215
Dialog
-
Setup Your Piano Keyboard
-
0
0
16777215
60
false
true
-
-
Right Notes
-
-
sound:
-
200
0
-
volume:
-
-
%
1
200
100
-
Qt::Horizontal
40
20
-
Test
-
Wrong Notes
-
-
sound:
-
0
0
200
0
-
volume:
-
-
%
1
200
100
-
Qt::Horizontal
40
20
-
Test
-
Keyboard Note Range
-
Lowest Note:
-
60
16777215
The note number between 0 and 127
000;
-
Qt::Horizontal
40
20
-
Highest Note:
-
60
16777215
The note number between 0 and 127
000;
-
Qt::Horizontal
40
20
-
Reset
-
Qt::Horizontal
QDialogButtonBox::Cancel|QDialogButtonBox::NoButton|QDialogButtonBox::Ok
buttonBox
accepted()
GuiKeyboardSetupDialog
accept()
248
254
157
274
buttonBox
rejected()
GuiKeyboardSetupDialog
reject()
316
260
286
274
pianobooster-src-0.6.4b/src/GuiSongDetailsDialog.cpp 0000644 0001747 0001747 00000006607 11301345653 022124 0 ustar ubuntu ubuntu /*!
@file GuiSongDetailsDialog.cpp
@brief xxx.
@author L. J. Barman
Copyright (c) 2008-2009, L. J. Barman, all rights reserved
This file is part of the PianoBooster application
PianoBooster 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.
PianoBooster 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 PianoBooster. If not, see .
*/
#include
#include "GuiSongDetailsDialog.h"
#include "GlView.h"
GuiSongDetailsDialog::GuiSongDetailsDialog(QWidget *parent)
: QDialog(parent)
{
setupUi(this);
m_song = 0;
m_settings = 0;
m_trackList = 0;
setWindowTitle("Song Details");
}
void GuiSongDetailsDialog::init(CSong* song, CSettings* settings)
{
m_song = song;
m_settings = settings;
m_trackList = m_song->getTrackList();
leftHandChannelCombo->addItem(tr("No channel assigned"));
leftHandChannelCombo->addItems(m_trackList->getAllChannelProgramNames(true));
rightHandChannelCombo->addItem(tr("No channel assigned"));
rightHandChannelCombo->addItems(m_trackList->getAllChannelProgramNames(true));
leftHandChannelCombo->setCurrentIndex(m_trackList->getHandTrackIndex(PB_PART_left) + 1);
rightHandChannelCombo->setCurrentIndex(m_trackList->getHandTrackIndex(PB_PART_right) +1);
updateSongInfoText();
}
void GuiSongDetailsDialog::updateSongInfoText()
{
QString str;
songInfoText->clear();
bool activateOkButton = false;
if (leftHandChannelCombo->currentIndex() != 0 && leftHandChannelCombo->currentIndex() == rightHandChannelCombo->currentIndex())
songInfoText->append("The left and rignt hand channels must be different");
else if ((leftHandChannelCombo->currentIndex() == 0 && rightHandChannelCombo->currentIndex() != 0 ) ||
(rightHandChannelCombo->currentIndex() == 0 && leftHandChannelCombo->currentIndex() != 0 ) )
songInfoText->append("Both left and rignt hand channels must be none to disable this feature");
else
{
songInfoText->append("Set the MIDI Channels to be used for left and right hand piano parts:");
songInfoText->append("the left hand piano part is using MIDI Channels 1");
songInfoText->append("the right hand piano part is using MIDI Channels 1");
activateOkButton = true;
}
buttonBox->button(QDialogButtonBox::Ok)->setEnabled(activateOkButton);
}
void GuiSongDetailsDialog::on_leftHandChannelCombo_activated (int index)
{
updateSongInfoText();
}
void GuiSongDetailsDialog::on_rightHandChannelCombo_activated (int index)
{
updateSongInfoText();
}
void GuiSongDetailsDialog::accept()
{
m_trackList->setActiveHandsIndex(leftHandChannelCombo->currentIndex() -1, rightHandChannelCombo->currentIndex() -1);
this->QDialog::accept();
}
pianobooster-src-0.6.4b/src/Notation.h 0000644 0001747 0001747 00000013122 11303063627 017351 0 ustar ubuntu ubuntu /*********************************************************************************/
/*!
@file Notation.h
@brief xxx.
@author L. J. Barman
Copyright (c) 2008-2009, L. J. Barman, all rights reserved
This file is part of the PianoBooster application
PianoBooster 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.
PianoBooster 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 PianoBooster. If not, see .
*/
/*********************************************************************************/
#ifndef __NOTATION_H__
#define __NOTATION_H__
#include
#include "MidiFile.h"
#include "Queue.h"
#include "Symbol.h"
#include "Chord.h"
#include "Bar.h"
#define MAX_SYMBOLS 20 // The maximum number of symbols that can be stored in one slot
class CSlot
{
public:
CSlot()
{
clear();
}
void clear()
{
m_length = 0;
m_deltaTime = 0;
m_av8Left = 0;
m_av8Right = 0;
m_maxLeftEdge = 0;
}
CSymbol getSymbol(int index) {return m_symbols[index];}
musicalSymbol_t getSymbolType(int index) {return m_symbols[index].getType();}
int length() {return m_length;}
void setDeltaTime(int delta) {m_deltaTime = delta;}
void addDeltaTime(int delta) {m_deltaTime += delta;}
int getDeltaTime() {return m_deltaTime;}
int getLeftSideDeltaTime() {return m_deltaTime + m_maxLeftEdge;}
void setAv8Left(int val) {m_av8Left = val;}
int getAv8Left() {return m_av8Left;}
// return false on error
bool addSymbol(CSymbol symbol);
void analyse();
void setSymbol(int delta, CSymbol symbol)
{
clear();
setDeltaTime(delta);
addSymbol(symbol);
}
void transpose(int amount)
{
for (int i = 0; i < m_length; i++)
{
m_symbols[i].transpose(amount);
}
}
void setNoteColour(int note, CColour colour )
{
for (int i = 0; i < m_length; i++)
{
if (note == m_symbols[i].getNote() || note == 0)
m_symbols[i].setColour(colour);
}
}
void setNoteTimming(int note, int timing)
{
for (int i = 0; i < m_length; i++)
{
if (note == m_symbols[i].getNote() || note == 0)
m_symbols[i].setPianistTiming(timing);
}
if (timing < m_maxLeftEdge)
m_maxLeftEdge = timing;
}
void clearAllNoteTimmings()
{
for (int i = 0; i < m_length; i++)
{
m_symbols[i].setPianistTiming(NOT_USED);
}
m_maxLeftEdge = 0;
}
protected:
private:
int m_deltaTime;
CSymbol m_symbols[MAX_SYMBOLS];
int m_length;
int m_av8Left;
int m_av8Right;
int m_maxLeftEdge; // the furthest the note will appear on the left hand edge (used when removing the note)
};
// remembers the state of a running accidental
// Don't display the accidental twice in the same bar
class CNoteState
{
public:
CNoteState()
{
clear();
}
void clear()
{
m_barChangeCounter = -1;
m_accidentalState = PB_ACCIDENTAL_MODIFER_noChange;
m_noteLength = 0;
m_backLink = 0;
}
void setBarChange(int value){m_barChangeCounter = value;}
int getBarChange(){return m_barChangeCounter;}
void setAccidentalState(accidentalModifer_t value){m_accidentalState = value;}
accidentalModifer_t getAccidentalState(){return m_accidentalState;}
void setBackLink(CNoteState * link){m_backLink = link;}
CNoteState * getBackLink(){return m_backLink;}
private:
int m_barChangeCounter;
accidentalModifer_t m_accidentalState;
int m_noteLength; // Used to determine the note length
CNoteState* m_backLink;
};
// Define a chord
class CNotation
{
public:
CNotation()
{
m_midiInputQueue = new CQueue(1000);
m_slotQueue = new CQueue(200);
reset();
m_displayChannel = 0;
}
~CNotation()
{
delete m_midiInputQueue;
delete m_slotQueue;
}
void reset();
void setChannel(int channel) {m_displayChannel = channel;}
CSlot nextSlot();
void midiEventInsert(CMidiEvent event);
int midiEventSpace() { return m_midiInputQueue->space();}
static void setCourtesyAccidentals(bool setting){m_cfg_displayCourtesyAccidentals = setting;}
static bool displayCourtesyAccidentals(){return m_cfg_displayCourtesyAccidentals; }
private:
CSlot nextBeatMarker();
int nextMergeSlot();
void findNoteSlots();
CSlot nextNoteSlot();
accidentalModifer_t detectSuppressedNatural(int note);
CQueue* m_slotQueue; // Queue of symbol slots that have not been read yet
CQueue* m_midiInputQueue; // A Queue of midi events
CSlot m_currentSlot;
int m_currentDeltaTime;
int m_beatPerBarCounter;
int m_earlyBarChangeCounter;
int m_earlyBarChangeDelta; // Counts the ppqn in one bar
CSlot m_mergeSlots[2];
int m_displayChannel;
CFindChord m_findScrollerChord;
CBar m_bar;
CNoteState m_noteState[MAX_MIDI_NOTES];
static bool m_cfg_displayCourtesyAccidentals;
};
#endif // __NOTATION_H__
pianobooster-src-0.6.4b/src/Conductor.cpp 0000644 0001747 0001747 00000064046 11304041717 020061 0 ustar ubuntu ubuntu /*********************************************************************************/
/*!
@file Conductor.cpp
@brief xxxx.
@author L. J. Barman
Copyright (c) 2008-2009, L. J. Barman, all rights reserved
This file is part of the PianoBooster application
PianoBooster 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.
PianoBooster 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 PianoBooster. If not, see .
*/
/*********************************************************************************/
#define OPTION_DEBUG_CONDUCTOR 0
#if OPTION_DEBUG_CONDUCTOR
#define ppDEBUG_CONDUCTOR(args) ppLogDebug args
#else
#define ppDEBUG_CONDUCTOR(args)
#endif
#include "Conductor.h"
#include "Score.h"
#include "Piano.h"
#include "Cfg.h"
playMode_t CConductor::m_playMode = PB_PLAY_MODE_listen;
CConductor::CConductor()
{
int i;
m_scoreWin = 0;
m_piano = 0;
m_songEventQueue = new CQueue(1000);
m_wantedChordQueue = new CQueue(1000);
m_savedNoteQueue = new CQueue(200);
m_savedNoteOffQueue = new CQueue(200);
m_playing = false;
m_transpose = 0;
m_latencyFix = 0;
m_leadLagAdjust = 0;
setSpeed(1.0);
setLatencyFix(0);
m_boostVolume = 0;
m_pianoVolume = 0;
m_activeChannel = 0;
m_skill = 0;
m_silenceTimeOut = 0;
m_realTimeEventBits = 0;
m_mutePianistPart = false;
setPianistChannels(1-1,2-1);
cfg_timingMarkersFlag = false;
cfg_stopPointMode = PB_STOP_POINT_MODE_automatic;
setPianoSoundPatches(1-1, 7-1); // 6-1
m_tempo.setSavedwantedChord(&m_savedwantedChord);
for ( i = 0; i < MAX_MIDI_CHANNELS; i++)
{
m_muteChannels[i] = false;
}
rewind();
testWrongNoteSound(false);
}
CConductor::~CConductor()
{
delete m_songEventQueue;
delete m_wantedChordQueue;
delete m_savedNoteQueue;
delete m_savedNoteOffQueue;
}
//! add a midi event to be analysed and displayed on the score
void CConductor::midiEventInsert(CMidiEvent event)
{
m_songEventQueue->push(event);
}
//! first check if there is space to add a midi event
int CConductor::midiEventSpace()
{
return m_songEventQueue->space();
}
void CConductor::channelSoundOff(int channel)
{
if (channel < 0 || channel >= MAX_MIDI_CHANNELS)
{
return;
}
CMidiEvent midi;
midi.controlChangeEvent(0, channel, MIDI_ALL_NOTES_OFF, 0);
playMidiEvent(midi);
// remove the sustain pedal as well
midi.controlChangeEvent(0, channel, MIDI_SUSTAIN, 0);
playMidiEvent(midi);
}
void CConductor::allSoundOff()
{
int channel;
for ( channel = 0; channel < MAX_MIDI_CHANNELS; channel++)
{
if (channel != m_pianistGoodChan)
channelSoundOff(channel);
}
m_savedNoteQueue->clear();
m_savedNoteOffQueue->clear();
}
void CConductor::resetAllChannels()
{
int channel;
CMidiEvent midi;
for ( channel = 0; channel < MAX_MIDI_CHANNELS; channel++)
{
midi.controlChangeEvent(0, channel, MIDI_RESET_ALL_CONTROLLERS, 0);
playMidiEvent(midi);
}
}
void CConductor::muteChannel(int channel, bool state)
{
if (channel < 0 || channel >= MAX_MIDI_CHANNELS)
return;
m_muteChannels[ channel] = state;
if (state == true)
channelSoundOff(channel); // fixme this is called too often
}
void CConductor::mutePart(int part, bool state)
{
int channel;
if ( part < MAX_MIDI_CHANNELS)
{
muteChannel(part, state);
return;
}
for ( channel = 0; channel < MAX_MIDI_CHANNELS; channel++)
{
muteChannel( channel, state);
}
if (state == true)
channelSoundOff(channel);
}
/* calculate the new solo_volume */
int CConductor::calcBoostVolume(int channel, int volume)
{
int returnVolume;
bool activePart;
if (volume == -1)
volume = m_savedMainVolume[channel];
else
m_savedMainVolume[channel] = volume;
returnVolume = volume;
activePart = false;
if (CNote::hasPianoPart(m_activeChannel))
{
if (m_playMode == PB_PLAY_MODE_listen) // only boost one hand in listen mode
{
if (channel == CNote::leftHandChan() && CNote::getActiveHand() != PB_PART_right)
activePart = true;
if (channel == CNote::rightHandChan() && CNote::getActiveHand() != PB_PART_left)
activePart = true;
}
else // otherwise always boost both hands
{
if ( CNote::hasPianoPart(channel))
activePart = true;
}
}
else
{
if (channel == m_activeChannel)
activePart= true;
}
if (channel == m_activeChannel)
activePart= true;
//if (channel == 5) activePart= true; // for debugging
if (activePart)
{
if (returnVolume == 0 )
; /* Don't adjust the volume if zero */
else if (m_boostVolume < 0 )
returnVolume = (returnVolume * (m_boostVolume + 100)) / 100;
else
returnVolume += m_boostVolume;
}
else
{
if (m_boostVolume > 0)
returnVolume = (returnVolume * (100 - m_boostVolume)) / 100;
}
// The piano volume can reduce the volume of the music
if (m_pianoVolume>0)
returnVolume = (returnVolume * (100 - m_pianoVolume)) / 100;;
if (returnVolume > 127)
returnVolume = 127;
return returnVolume;
}
/* send boost volume by adjusting all channels */
void CConductor::outputBoostVolume()
{
int chan;
for ( chan =0; chan 12)
m_transpose = 12;
if (m_transpose < -12)
m_transpose = -12;
m_scoreWin->transpose(m_transpose);
}
}
void CConductor::activatePianistMutePart()
{
mutePart(PB_PART_all, false);
if (m_playMode != PB_PLAY_MODE_listen && m_mutePianistPart == true)
{
if (CNote::hasPianoPart(m_activeChannel))
{
if (CNote::getActiveHand() == PB_PART_both || CNote::getActiveHand() == PB_PART_left)
mutePart(CNote::leftHandChan(), true);
if (CNote::getActiveHand() == PB_PART_both || CNote::getActiveHand() == PB_PART_right)
mutePart(CNote::rightHandChan(), true);
}
else
mutePart(m_activeChannel, true);
}
}
void CConductor::mutePianistPart(bool state)
{
m_mutePianistPart = state;
activatePianistMutePart();
}
void CConductor::setActiveHand(whichPart_t hand)
{
if (CNote::getActiveHand() == hand)
return;
CNote::setActiveHand(hand);
activatePianistMutePart();
outputBoostVolume();
m_wantedChord = m_savedwantedChord;
if (m_wantedChord.trimOutOfRangeNotes(m_transpose)==0)
fetchNextChord();
int note;
int i;
// Reset the note colours
for(i = 0; i < m_savedwantedChord.length(); i++)
{
note = m_savedwantedChord.getNote(i).pitch();
m_scoreWin->setPlayedNoteColour(note, Cfg::noteColour(), m_chordDeltaTime);
}
for(i = 0; i < m_wantedChord.length(); i++)
{
note = m_wantedChord.getNote(i).pitch();
m_scoreWin->setPlayedNoteColour(note, Cfg::playedStoppedColour(), m_chordDeltaTime);
}
findSplitPoint();
forceScoreRedraw();
}
void CConductor::setActiveChannel(int channel)
{
m_activeChannel = channel;
outputBoostVolume();
resetWantedChord();
fetchNextChord();
activatePianistMutePart();
}
void CConductor::outputPianoVolume()
{
CMidiEvent event;
int volume = 127;
// if piano volume is between -100 and 0 reduce the volume accordingly
if (m_pianoVolume < 0)
volume = (volume * (100 + m_pianoVolume)) / 100;
event.controlChangeEvent(0, m_pianistGoodChan, MIDI_MAIN_VOLUME, volume);
playMidiEvent(event); // Play the midi note or event
event.controlChangeEvent(0, m_pianistBadChan, MIDI_MAIN_VOLUME, volume);
playMidiEvent(event); // Play the midi note or event
}
void CConductor::updatePianoSounds()
{
CMidiEvent event;
if (m_cfg_rightNoteSound>=0) // ignore if set to -1 ("None")
{
event.programChangeEvent(0, m_pianistGoodChan, m_cfg_rightNoteSound);
playMidiEvent( event );
}
if (m_cfg_wrongNoteSound>=0)
{
event.programChangeEvent(0, m_pianistBadChan, m_cfg_wrongNoteSound);
playMidiEvent( event );
}
}
void CConductor::testWrongNoteSound(bool enable)
{
m_testWrongNoteSound = enable;
updatePianoSounds();
}
void CConductor::playMusic(bool start)
{
m_playing = start;
allSoundOff();
if (start)
{
resetAllChannels();
activatePianistMutePart();
testWrongNoteSound(false);
if (seekingBarNumber())
resetWantedChord();
/*
const unsigned char gsModeEnterData[] = {0xf0, 0x41, 0x10, 0x42, 0x12, 0x40, 0x00, 0x7f, 0x00, 0x41, 0xf7};
for (size_t i = 0; i < arraySize(gsModeEnterData); i++)
{
event.collateRawByte(0, gsModeEnterData[i]);
playMidiEvent(event);
}
event.outputCollatedRawBytes(0);
playMidiEvent(event);
*/
}
}
void CConductor::playTransposeEvent(CMidiEvent event)
{
if (m_transpose != 0 && event.channel() != MIDI_DRUM_CHANNEL &&
(event.type() == MIDI_NOTE_ON || event.type() == MIDI_NOTE_OFF) )
event.transpose(m_transpose);
if (event.type() == MIDI_NOTE_ON && isChannelMuted(event.channel()) == true &&
CChord::isNotePlayable(event.note(), m_transpose) == true)
return; // mute the note by not playing it
// boost any volume events
if (event.type() == MIDI_CONTROL_CHANGE && event.data1() == MIDI_MAIN_VOLUME)
event.setDatat2(calcBoostVolume(event.channel(), event.data2() ));
// Don't output note on if we are seeking to bar
if (!seekingBarNumber())
playMidiEvent(event); // Play the midi note or event
else
{
if (event.type() == MIDI_PROGRAM_CHANGE || event.type() == MIDI_CONTROL_CHANGE)
playMidiEvent(event); // Play the midi note or event
}
}
void CConductor::outputSavedNotes()
{
// The saved notes off are note needed any more
// (as the are also in the savedNoteQueue
m_savedNoteOffQueue->clear();
// output any the saved up notes
while (m_savedNoteQueue->length() > 0)
playTransposeEvent(m_savedNoteQueue->pop());
}
void CConductor::resetWantedChord()
{
m_wantedChord.clear();
ppDEBUG_CONDUCTOR(("resetWantedChord m_chordDeltaTime %d m_playingDeltaTime %d", m_chordDeltaTime, m_playingDeltaTime ));
m_followPlayingTimeOut = false;
m_chordDeltaTime = m_playingDeltaTime;
m_pianistTiming = m_chordDeltaTime;
m_pianistSplitPoint = MIDDLE_C;
outputSavedNotes();
m_followState = PB_FOLLOW_searching;
}
// switch modes if we are playing well enough (i.e. don't slow down if we are playing late)
void CConductor::setFollowSkillAdvanced(bool enable)
{
if (m_settings==0 || m_scoreWin == 0)
return;
m_settings-> setAdvancedMode(enable);
if (getLatencyFix() > 0)
{
// behave differently if we are using the latency fix
m_cfg_earlyNotesPoint = m_cfg_imminentNotesOffPoint; //disable the early notes
}
if (cfg_stopPointMode == PB_STOP_POINT_MODE_onTheBeat)
enable = false;
if (cfg_stopPointMode == PB_STOP_POINT_MODE_afterTheBeat)
enable = true;
m_followSkillAdvanced = enable;
m_stopPoint = (enable) ? m_cfg_stopPointAdvanced: m_cfg_stopPointBeginner ;
}
void CConductor::findSplitPoint()
{
// find the split point
int lowestTreble = MIDDLE_C + 37;
int highestBase = MIDDLE_C - 37;
CNote note;
// Find where to put the split point
for(int i = 0; i < m_wantedChord.length(); i++)
{
note = m_wantedChord.getNote(i);
if (note.part() == PB_PART_right && note.pitch() < lowestTreble)
lowestTreble = note.pitch();
if (note.part() == PB_PART_left && note.pitch() > highestBase)
highestBase = note.pitch();
}
//put the split point in the middle
m_pianistSplitPoint = ((lowestTreble + highestBase) /2 ) + m_transpose;
}
void CConductor::fetchNextChord()
{
m_followState = PB_FOLLOW_searching;
m_followPlayingTimeOut = false;
outputSavedNotes();
do // Remove notes or chords that are out of our range
{
if (m_wantedChordQueue->length() == 0)
{
m_wantedChord.clear();
m_pianistSplitPoint = MIDDLE_C;
return;
}
m_wantedChord = m_wantedChordQueue->pop();
m_savedwantedChord = m_wantedChord;
m_chordDeltaTime -= m_wantedChord.getDeltaTime() * SPEED_ADJUST_FACTOR;
m_pianistTiming = m_chordDeltaTime;
}
while (m_wantedChord.trimOutOfRangeNotes(m_transpose)==0);
// now find the split point
findSplitPoint();
}
bool CConductor::validatePianistNote( const CMidiEvent & inputNote)
{
if ( m_chordDeltaTime <= -m_cfg_playZoneEarly)
return false;
return m_wantedChord.searchChord(inputNote.note(), m_transpose);
}
bool CConductor::validatePianistChord()
{
if (m_piano->pianistBadNotesDown() >= 2)
return false;
if (m_skill>=3)
{
if (m_goodPlayedNotes.length() == m_wantedChord.length())
return true;
}
else
{
if (m_goodPlayedNotes.length() >= 1)
return true;
}
return false;
}
void CConductor::pianistInput(CMidiEvent inputNote)
{
bool goodSound = true;
if (m_testWrongNoteSound)
goodSound = false;
if (inputNote.type() == MIDI_NOTE_ON)
{
whichPart_t hand;
hand = (inputNote.note() >= m_pianistSplitPoint)? PB_PART_right : PB_PART_left;
if ( validatePianistNote(inputNote) == true)
{
m_goodPlayedNotes.addNote(hand, inputNote.note());
m_piano->addPianistNote(hand, inputNote.note(),true);
int pianistTiming = ( cfg_timingMarkersFlag && m_followSkillAdvanced) ? m_pianistTiming : NOT_USED;
m_scoreWin->setPlayedNoteColour(inputNote.note(),
(!m_followPlayingTimeOut)? Cfg::playedGoodColour():Cfg::playedBadColour(),
m_chordDeltaTime, pianistTiming);
if (validatePianistChord() == true)
{
if (m_chordDeltaTime < 0)
m_tempo.removePlayingTicks(-m_chordDeltaTime);
m_goodPlayedNotes.clear();
fetchNextChord();
// count the good notes so that the live percentage looks OK
m_rating.totalNotes(m_wantedChord.length());
m_rating.calculateAccuracy();
m_settings->pianistActive();
if (m_rating.isAccuracyGood() || m_playMode == PB_PLAY_MODE_playAlong)
setFollowSkillAdvanced(true); // change the skill level only when they are good enough
else
setFollowSkillAdvanced(false);
setEventBits( EVENT_BITS_forceRatingRedraw);
}
}
else
{
if (m_playing == true)
{
goodSound = false;
m_piano->addPianistNote(hand, inputNote.note(), false);
m_rating.wrongNotes(1);
}
else
m_piano->addPianistNote(hand, inputNote.note(), true);
}
}
else if (inputNote.type() == MIDI_NOTE_OFF)
{
if (m_piano->removePianistNote(inputNote.note()) == true)
goodSound = false;
bool hasNote = m_goodPlayedNotes.removeNote(inputNote.note());
if (hasNote)
m_scoreWin->setPlayedNoteColour(inputNote.note(),
(!m_followPlayingTimeOut)? Cfg::noteColour():Cfg::playedStoppedColour(),
m_chordDeltaTime);
outputSavedNotesOff();
}
if (goodSound == true || m_cfg_wrongNoteSound < 0)
{
if (m_cfg_rightNoteSound >= 0) // don't play anything if the sound is set to -1 (none)
{
inputNote.setChannel(m_pianistGoodChan);
playMidiEvent( inputNote );
}
}
else
{
inputNote.setChannel(m_pianistBadChan);
playMidiEvent( inputNote );
}
/*
// use the same channel for the right and wrong note
int pianoSound = (goodSound == true) ? m_cfg_rightNoteSound : m_cfg_wrongNoteSound;
if (pianoSound != m_lastSound)
{
m_lastSound = pianoSound;
CMidiEvent midiSound;
midiSound.programChangeEvent(0,inputNote.channel(),pianoSound);
playMidiEvent( midiSound );
}
*/
}
void CConductor::addDeltaTime(int ticks)
{
m_scoreWin->scrollDeltaTime(ticks);
m_playingDeltaTime += ticks;
m_chordDeltaTime +=ticks;
}
void CConductor::followPlaying()
{
if ( m_playMode == PB_PLAY_MODE_listen )
return;
if (m_wantedChord.length() == 0)
fetchNextChord();
if (m_wantedChord.length() == 0)
return;
if (seekingBarNumber())
{
if (deltaAdjust(m_chordDeltaTime) > -m_stopPoint )
fetchNextChord();
}
else if ( m_playMode == PB_PLAY_MODE_followYou)
{
if (deltaAdjust(m_chordDeltaTime) > -m_cfg_earlyNotesPoint )
m_followState = PB_FOLLOW_earlyNotes;
if (deltaAdjust(m_chordDeltaTime) > -m_stopPoint )
{
m_followState = PB_FOLLOW_waiting;
// Throw away the time past the stop point (by adding a negative ticks)
addDeltaTime( -m_stopPoint*SPEED_ADJUST_FACTOR - m_chordDeltaTime);
}
}
else // m_playMode == PB_PLAY_MODE_playAlong
{
if (m_chordDeltaTime > m_cfg_playZoneLate )
{
missedNotesColour(Cfg::playedStoppedColour());
fetchNextChord();
m_rating.lateNotes(m_wantedChord.length() - m_goodPlayedNotes.length());
setEventBits( EVENT_BITS_forceRatingRedraw);
}
}
}
void CConductor::outputSavedNotesOff()
{
while (m_savedNoteOffQueue->length() > 0)
playTransposeEvent(m_savedNoteOffQueue->pop()); // Output the saved note off events
}
// untangle the sound in case there is any notes off just after we have stopped
void CConductor::findImminentNotesOff()
{
int i;
CMidiEvent event;
int aheadDelta = 0;
i = 0;
event = m_nextMidiEvent;
while (deltaAdjust(m_playingDeltaTime) + aheadDelta > m_cfg_imminentNotesOffPoint)
{
if (event.type() == MIDI_NOTE_OFF )
m_savedNoteOffQueue->push(event);
if ( i >= m_songEventQueue->length())
break;
event = m_songEventQueue->index(i);
aheadDelta -= event.deltaTime();
i++;
}
}
void CConductor::missedNotesColour(CColour colour)
{
int i;
CNote note;
for (i = 0; i < m_wantedChord.length(); i++)
{
note = m_wantedChord.getNote(i);
if (m_goodPlayedNotes.searchChord(note.pitch(),m_transpose) == false)
m_scoreWin->setPlayedNoteColour(note.pitch() + m_transpose, colour, m_chordDeltaTime);
}
}
void CConductor::realTimeEngine(int mSecTicks)
{
int type;
int ticks; // Midi ticks
//mSecTicks = 2; // for debugging only
ticks = m_tempo.mSecToTicks(mSecTicks);
if (!m_followPlayingTimeOut)
m_pianistTiming += ticks;
while (checkMidiInput() > 0)
pianistInput(readMidiInput());
if (getfollowState() == PB_FOLLOW_waiting )
{
if (m_silenceTimeOut > 0)
{
m_silenceTimeOut -= mSecTicks;
if (m_silenceTimeOut <= 0)
{
allSoundOff();
m_silenceTimeOut = 0;
}
}
m_tempo.insertPlayingTicks(ticks);
if (m_pianistTiming > m_cfg_playZoneLate)
{
if (m_followPlayingTimeOut == false)
{
m_followPlayingTimeOut = true;
m_tempo.clearPlayingTicks();
m_rating.lateNotes(m_wantedChord.length() - m_goodPlayedNotes.length());
setEventBits( EVENT_BITS_forceRatingRedraw);
missedNotesColour(Cfg::playedStoppedColour());
findImminentNotesOff();
// Don't keep any saved notes off if there are no notes down
if (m_piano->pianistAllNotesDown() == 0)
outputSavedNotesOff();
m_silenceTimeOut = Cfg::silenceTimeOut();
}
}
return;
}
m_silenceTimeOut = 0;
if (m_playing == false)
return;
if (seekingBarNumber())
ticks = 0;
m_tempo.adjustTempo(&ticks);
ticks = m_bar.addDeltaTime(ticks);
if (seekingBarNumber())
ticks = m_bar.goToBarNumer();
setEventBits( m_bar.readEventBits());
#if OPTION_DEBUG_CONDUCTOR
if (m_realTimeEventBits | EVENT_BITS_newBarNumber)
{
ppDEBUG_CONDUCTOR(("m_savedNoteQueue %d m_playingDeltaTime %d",m_savedNoteQueue->space() , m_playingDeltaTime ));
ppDEBUG_CONDUCTOR(("getfollowState() %d %d %d",getfollowState() , m_leadLagAdjust, m_songEventQueue->length() ));
}
#endif
addDeltaTime(ticks);
followPlaying();
while ( m_playingDeltaTime >= m_leadLagAdjust)
{
type = m_nextMidiEvent.type();
if (m_songEventQueue->length() == 0 && type == MIDI_PB_EOF)
{
ppLogInfo("The End of the song");
setEventBits(EVENT_BITS_playingStopped);
m_playing = false;
break;
}
if (type == MIDI_PB_tempo)
{
m_tempo.setMidiTempo(m_nextMidiEvent.data1());
m_leadLagAdjust = m_tempo.mSecToTicks( -getLatencyFix() );
}
else if (type == MIDI_PB_timeSignature)
{
m_bar.setTimeSig(m_nextMidiEvent.data1(), m_nextMidiEvent.data2());
ppLogDebug("Midi Time Signature %d/%d", m_nextMidiEvent.data1(),m_nextMidiEvent.data2());
}
else if ( type != MIDI_NONE ) // this marks the end of the piece of music
{
int channel = m_nextMidiEvent.channel();
// Is this this channel_muted
if (!hasPianistKeyboardChannel(channel))
{
if (getfollowState() >= PB_FOLLOW_earlyNotes &&
m_playMode == PB_PLAY_MODE_followYou &&
!seekingBarNumber() &&
m_followSkillAdvanced == false)
{
// Save up the notes until the pianist presses the right key
if (m_savedNoteQueue->space()>0)
m_savedNoteQueue->push(m_nextMidiEvent);
else
ppLogWarn("Warning the m_savedNoteQueue is full");
if (type == MIDI_NOTE_OFF)
{
if (m_savedNoteOffQueue->space()>0)
m_savedNoteOffQueue->push(m_nextMidiEvent);
else
ppLogDebug("Warning the m_savedNoteOffQueue is full");
}
}
else
{
playTransposeEvent(m_nextMidiEvent); // Play the midi note or event
ppDEBUG_CONDUCTOR(("playEvent() chan %d type %d note %d", m_nextMidiEvent.channel() , m_nextMidiEvent.type() , m_nextMidiEvent.note(), m_songEventQueue->length() ));
}
}
}
if (m_songEventQueue->length() > 0)
m_nextMidiEvent = m_songEventQueue->pop();
else
{
ppDEBUG_CONDUCTOR(("no data in song queue"));
m_nextMidiEvent.clear();
break;
}
m_playingDeltaTime -= m_nextMidiEvent.deltaTime() * SPEED_ADJUST_FACTOR;
followPlaying();
}
}
void CConductor::rewind()
{
int chan;
for ( chan = 0; chan < MAX_MIDI_CHANNELS; chan++)
{
m_savedMainVolume[chan] = 100;
}
m_lastSound = -1;
m_rating.reset();
m_playingDeltaTime = 0;
m_tempo.reset();
m_songEventQueue->clear();
m_savedNoteQueue->clear();
m_savedNoteOffQueue->clear();
m_wantedChordQueue->clear();
m_nextMidiEvent.clear();
m_bar.rewind();
m_goodPlayedNotes.clear(); // The good notes the pianist plays
if (m_piano)
m_piano->clear();
resetWantedChord();
setFollowSkillAdvanced(false);
m_cfg_earlyNotesPoint = CMidiFile::ppqnAdjust(15); // was 10 playZoneEarly
m_cfg_stopPointBeginner = CMidiFile::ppqnAdjust(-0); //was -3; // stop just after the beat
m_cfg_stopPointAdvanced = CMidiFile::ppqnAdjust(-15); //was -3; // stop just after the beat
m_cfg_imminentNotesOffPoint = CMidiFile::ppqnAdjust(-15); // look ahead and find an Notes off coming up
// Annie song 25
m_cfg_playZoneEarly = CMidiFile::ppqnAdjust(Cfg::playZoneEarly()) * SPEED_ADJUST_FACTOR; // when playing along
m_cfg_playZoneLate = CMidiFile::ppqnAdjust(Cfg::playZoneLate()) * SPEED_ADJUST_FACTOR;
}
void CConductor::init(CScore * scoreWin, CSettings* settings)
{
int channel;
m_scoreWin = scoreWin;
m_settings = settings;
setFollowSkillAdvanced(false);
m_followState = PB_FOLLOW_searching;
this->CMidiDevice::init();
for ( channel = 0; channel < MAX_MIDI_CHANNELS; channel++)
muteChannel(channel, false);
assert(m_scoreWin);
if (m_scoreWin)
{
m_scoreWin->setRatingObject(&m_rating);
m_piano = m_scoreWin->getPianoObject();
}
rewind();
}
pianobooster-src-0.6.4b/src/Scroll.cpp 0000644 0001747 0001747 00000024521 11303063627 017354 0 ustar ubuntu ubuntu /*********************************************************************************/
/*!
@file Scroll.c
@brief xxx.
@author L. J. Barman
Copyright (c) 2008-2009, L. J. Barman, all rights reserved
This file is part of the PianoBooster application
PianoBooster 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.
PianoBooster 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 PianoBooster. If not, see .
*/
/*********************************************************************************/
#include "Cfg.h"
#include "Scroll.h"
//#define NOTE_AHEAD_GAP 50
//#define NOTE_BEHIND_GAP 14
#define NOTE_AHEAD_GAP 22 // the notes on the left hand side of the score
#define NOTE_BEHIND_GAP 14
void CScroll::compileSlot(CSlotDisplayList info)
{
int i;
if (m_show == false || info.m_displayListId == 0)
return;
glNewList (info.m_displayListId, GL_COMPILE);
glTranslatef (info.getDeltaTime() * m_noteSpacingFactor, 0.0, 0.0); /* move position */
info.transpose(m_transpose);
CStavePos stavePos;
int av8Left = info.getAv8Left();
for (i=0; i < info.length(); i++)
{
stavePos.notePos(info.getSymbol(i).getHand(), info.getSymbol(i).getNote());
//ppLogTrace ("compileSlot len %d id %2d next %2d time %2d type %2d note %2d", info.length(), info.m_displayListId,
//info.m_nextDisplayListId, info.getDeltaTime(), info.getSymbol(i).getType(), info.getSymbol(i).getNote());
drawSymbol(info.getSymbol(i), 0.0, stavePos.getPosYRelative()); // we add this back when drawing this symbol
}
glCallList (info.m_nextDisplayListId); /* Automatically draw the next slot even if it is not there yet */
glEndList ();
}
/*! Insert a symbol into the display list
* @return false when we have run out of symbols
*/
bool CScroll::insertSlots()
{
GLuint nextListId = 0;
if (m_headSlot.length() == 0)
m_headSlot = m_notation->nextSlot();
if (m_headSlot.length() == 0 || m_headSlot.getSymbolType(0) == PB_SYMBOL_theEnd) // this means we have reached the end of the file
return false;
while (true)
{
float headDelta = deltaAdjust(m_deltaHead) * m_noteSpacingFactor;
float slotDetlta = Cfg::staveEndX() - Cfg::playZoneX() - m_headSlot.getDeltaTime() * m_noteSpacingFactor - NOTE_BEHIND_GAP;
if (headDelta > slotDetlta)
break;
if (m_show)
{
if (m_symbolID == 0)
m_symbolID = glGenLists (1);
nextListId = glGenLists (1);
}
else
{
nextListId = m_symbolID = 0;
}
CSlotDisplayList info(m_headSlot, m_symbolID, nextListId);
m_deltaHead += info.getDeltaTime() * SPEED_ADJUST_FACTOR;
compileSlot(info);
m_scrollQueue->push(info);
m_symbolID = nextListId;
m_headSlot = m_notation->nextSlot();
if (m_headSlot.length() == 0 || m_headSlot.getSymbolType(0) == PB_SYMBOL_theEnd) // this means we have reached the end of the file
return false;
}
return true;
}
void CScroll::removeEarlyTimingMakers()
{
float delta = deltaAdjust(m_deltaTail) * m_noteSpacingFactor + Cfg::playZoneX() - Cfg::scrollStartX() - NOTE_AHEAD_GAP;
// only look a few steps (10) into the scroll queue
for (int i = 0; i < 10 && i < m_scrollQueue->length(); i++ )
{
if (delta < -(m_scrollQueue->index(i).getLeftSideDeltaTime() * m_noteSpacingFactor))
{
m_scrollQueue->indexPtr(i)->clearAllNoteTimmings();
compileSlot(m_scrollQueue->index(i));
}
delta += m_scrollQueue->index(i).getDeltaTime() * m_noteSpacingFactor;
}
}
void CScroll::removeSlots()
{
while (m_scrollQueue->length() > 0)
{
if (deltaAdjust(m_deltaTail) * m_noteSpacingFactor > -Cfg::playZoneX() + Cfg::scrollStartX() + NOTE_AHEAD_GAP -(m_scrollQueue->index(0).getLeftSideDeltaTime() * m_noteSpacingFactor) )
break;
CSlotDisplayList info = m_scrollQueue->pop();
m_deltaTail += info.getDeltaTime() * SPEED_ADJUST_FACTOR;
//ppLogTrace("Remove slot id %2d time %2d type %2d note %2d", info.m_displayListId, info.getDeltaTime(), info.getSymbol(0).getType(), info.getSymbol(0).getNote());
if (info.m_displayListId)
glDeleteLists( info.m_displayListId, 1);
if (m_wantedIndex > 0)
m_wantedIndex--; // also the Chord has moved down one place
else
{
m_wantedIndex = 0;
m_wantedDelta = m_deltaTail;
}
}
}
//! Draw all the symbols that we have in the list
void CScroll::drawScrollingSymbols(bool show)
{
insertSlots(); // new symbols at the end of the score
removeSlots(); // delete old symbols no longer required
removeEarlyTimingMakers();
if (show == false) // Just update the queue only
return;
if (m_scrollQueue->length() == 0 || m_scrollQueue->indexPtr(0)->m_displayListId == 0)
return;
glPushMatrix();
glTranslatef (Cfg::playZoneX() + deltaAdjust(m_deltaTail) * m_noteSpacingFactor, CStavePos::getStaveCenterY(), 0.0);
BENCHMARK(8, "glTranslatef");
if (m_scrollQueue->length() > 0)
glCallList (m_scrollQueue->indexPtr(0)->m_displayListId);
BENCHMARK(9, "glCallList");
glPopMatrix();
}
void CScroll::scrollDeltaTime(int ticks)
{
m_deltaHead -= ticks;
m_deltaTail -= ticks;
m_wantedDelta -= ticks;
}
bool CScroll::validPianistChord(int index)
{
CSlot* pSlot = m_scrollQueue->indexPtr(index);
assert(pSlot->length()!=0);
if (pSlot->getSymbol(0).getType() == PB_SYMBOL_note)
{
if (m_displayHand == PB_PART_both)
return true;
//eventually we need two slot queues one for each hand
for (int i = 0; i < pSlot->length(); i++)
{
if (pSlot->getSymbol(i).getHand() == m_displayHand)
return true;
}
}
return false;
}
int CScroll::findWantedChord(int note, CColour colour, int wantedDelta)
{
if (colour == Cfg::playedBadColour()) // fixme should be an enum
return m_wantedIndex;
{
while ( m_wantedIndex + 1 < m_scrollQueue->length())
{
if ((m_wantedDelta + m_scrollQueue->indexPtr(m_wantedIndex)->getDeltaTime() * SPEED_ADJUST_FACTOR) >= -wantedDelta)
{
if (validPianistChord(m_wantedIndex) == true)
break;
}
m_wantedDelta += m_scrollQueue->indexPtr(m_wantedIndex)->getDeltaTime() * SPEED_ADJUST_FACTOR;
m_wantedIndex++;
}
}
return m_wantedIndex;
}
void CScroll::setPlayedNoteColour(int note, CColour colour, int wantedDelta, int pianistTimming)
{
int index;
if (m_wantedIndex >= m_scrollQueue->length())
return;
index = findWantedChord(note, colour, wantedDelta);
note -= m_transpose;
m_scrollQueue->indexPtr(index)->setNoteColour(note, colour);
if (pianistTimming != NOT_USED)
{
pianistTimming = deltaAdjust(pianistTimming) * DEFAULT_PPQN / CMidiFile::getPulsesPerQuarterNote();
m_scrollQueue->indexPtr(index)->setNoteTimming(note, pianistTimming);
}
compileSlot(m_scrollQueue->index(index));
}
void CScroll::refresh()
{
int i;
if (m_show == false)
return;
for ( i = 0; i < m_scrollQueue->length(); i++)
compileSlot(m_scrollQueue->index(i));
}
void CScroll::transpose(int transpose)
{
if (m_transpose == transpose)
return;
m_transpose = transpose;
refresh();
}
void CScroll::showScroll(bool show)
{
int i;
GLuint nextListId = 0;
m_show = show;
if (show == true)
{
if (m_symbolID == 0)
m_symbolID = glGenLists (1);
// add in the missing GL display list
for ( i = 0; i < m_scrollQueue->length(); i++)
{
//assert (m_scrollQueue->indexPtr(i)->m_displayListId == 0);
nextListId = glGenLists (1);
m_scrollQueue->indexPtr(i)->m_displayListId = m_symbolID;
m_scrollQueue->indexPtr(i)->m_nextDisplayListId = nextListId;
m_symbolID = nextListId;
}
// And now compile the slot (remember that each slot points to the next one)
for ( i = 0; i < m_scrollQueue->length(); i++)
{
compileSlot(m_scrollQueue->index(i));
}
}
else
{
// Remove all the gl items
for ( i = 0; i < m_scrollQueue->length(); i++)
{
if (m_scrollQueue->indexPtr(i)->m_displayListId != 0 && m_scrollQueue->indexPtr(i)->m_displayListId != nextListId)
glDeleteLists(m_scrollQueue->index(i).m_displayListId, 1);
m_scrollQueue->indexPtr(i)->m_displayListId = 0;
nextListId = m_scrollQueue->indexPtr(i)->m_nextDisplayListId;
m_scrollQueue->indexPtr(i)->m_nextDisplayListId = 0;
if (nextListId != 0)
glDeleteLists(nextListId, 1);
}
if (m_symbolID != 0)
glDeleteLists(m_symbolID, 1);
m_symbolID = 0;
}
}
CScroll::CSlotDisplayList::CSlotDisplayList(const CSlot& slot, GLuint displayListId, GLuint nextDisplayListId) : CSlot(slot),
m_displayListId(displayListId), m_nextDisplayListId(nextDisplayListId)
{
// It is all done in the initialisation list
}
void CScroll::reset()
{
int i;
m_wantedIndex = 0;
m_wantedDelta = 0;
m_deltaHead = m_deltaTail = 0;
m_notation->reset();
m_headSlot.clear();
for ( i = 0; i < m_scrollQueue->length(); i++)
{
if (m_scrollQueue->index(i).m_displayListId)
glDeleteLists(m_scrollQueue->index(i).m_displayListId, 1);
}
if (m_symbolID != 0)
glDeleteLists(m_symbolID, 1);
m_symbolID = 0;
m_scrollQueue->clear();
m_ppqnFactor = static_cast(DEFAULT_PPQN) / CMidiFile::getPulsesPerQuarterNote();
m_noteSpacingFactor = m_ppqnFactor * HORIZONTAL_SPACING_FACTOR;
}
pianobooster-src-0.6.4b/src/GlView.cpp 0000644 0001747 0001747 00000026072 11367323106 017317 0 ustar ubuntu ubuntu /*********************************************************************************/
/*!
@file GlView.cpp
@brief xxxx
@author L. J. Barman
Copyright (c) 2008-2009, L. J. Barman, all rights reserved
This file is part of the PianoBooster application
PianoBooster 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.
PianoBooster 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 PianoBooster. If not, see .
*/
/*********************************************************************************/
#include
#include
#include
#include "QtWindow.h"
#include "GlView.h"
#include "Cfg.h"
#include "Draw.h"
// This defines the PB Open GL frame per seconds.
// Try to make sure this runs a bit faster than the screen refresh rate of 60z (or 16.6 msec)
#define SCREEN_FRAME_RATE 12 // That 12 msec or 83.3 frames per second
CGLView::CGLView(QtWindow* parent, CSettings* settings)
: QGLWidget(parent)
{
m_qtWindow = parent;
m_settings = settings;
m_rating = 0;
m_fullRedrawFlag = true;
m_forcefullRedraw = 0;
m_forceRatingRedraw = 0;
m_forceBarRedraw = 0;
m_backgroundColour = QColor(0, 0, 0);
m_song = new CSong();
m_score = new CScore(m_settings);
m_displayUpdateTicks = 0;
m_cfg_openGlOptimise = true;
m_eventBits = 0;
BENCHMARK_INIT();
}
CGLView::~CGLView()
{
makeCurrent();
delete m_song;
delete m_score;
m_titleHeight = 0;
}
QSize CGLView::minimumSizeHint() const
{
return QSize(50, 50);
}
QSize CGLView::sizeHint() const
{
return QSize(200, 400); //fixme this does not work
}
void CGLView::paintGL()
{
BENCHMARK(2, "enter");
m_displayUpdateTicks = 0;
if (m_fullRedrawFlag)
m_forcefullRedraw = m_forceRatingRedraw = m_forceBarRedraw = REDRAW_COUNT;
if (m_forcefullRedraw) // clear the screen only if we are doing a full redraw
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
//BENCHMARK(3, "glLoadIdentity");
drawDisplayText();
BENCHMARK(4, "drawDisplayText");
drawAccurracyBar();
BENCHMARK(5, "drawAccurracyBar");
drawBarNumber();
BENCHMARK(6, "drawBarNumber");
if (m_forcefullRedraw)
m_score->drawScore();
drawTimeSignature();
updateMidiTask();
m_score->drawScroll(m_forcefullRedraw);
BENCHMARK(10, "drawScroll");
if (m_forcefullRedraw) m_forcefullRedraw--;
BENCHMARK(11, "exit");
BENCHMARK_RESULTS();
}
void CGLView::drawTimeSignature()
{
if (Cfg::quickStart)
return;
if (m_forcefullRedraw == 0)
return;
float x,y;
int topNumber, bottomNumber;
if (m_song == 0) return;
m_song->getTimeSig(&topNumber, &bottomNumber);
if (topNumber == 0 ) return;
char bufferTop[10], bufferBottom[10];
sprintf(bufferTop, "%d", topNumber);
sprintf(bufferBottom, "%d", bottomNumber);
x = Cfg::timeSignatureX();
CDraw::drColour ((CDraw::getDisplayHand() != PB_PART_left) ? Cfg::noteColour() : Cfg::noteColourDim());
y = CStavePos(PB_PART_right, 0).getPosY() + 5;
renderText(x,y, 0, bufferTop, m_timeSigFont);
y = CStavePos(PB_PART_right, -3).getPosY() - 2;
renderText(x,y, 0, bufferBottom, m_timeSigFont);
CDraw::drColour ((CDraw::getDisplayHand() != PB_PART_right) ? Cfg::noteColour() : Cfg::noteColourDim());
y = CStavePos(PB_PART_left, 0).getPosY() + 5;
renderText(x,y, 0, bufferTop, m_timeSigFont);
y = CStavePos(PB_PART_left, -3).getPosY() - 2;
renderText(x,y, 0, bufferBottom, m_timeSigFont);
}
void CGLView::drawAccurracyBar()
{
if (m_song->getPlayMode() == PB_PLAY_MODE_listen || !m_settings->getWarningMessage().isEmpty())
return;
if (m_forceRatingRedraw == 0)
return;
m_forceRatingRedraw--;
float accuracy;
CColour colour;
float y = Cfg::getAppHeight() - 14;
const float x = 120;
const int width = 360;
const int lineWidth = 8/2;
m_rating->calculateAccuracy();
accuracy = m_rating->getAccuracyValue();
colour = m_rating->getAccuracyColour();
CDraw::drColour (colour);
glRectf(x, y - lineWidth, x + width * accuracy, y + lineWidth);
CDraw::drColour (Cfg::backgroundColour());
glRectf(x + width * accuracy, y - lineWidth, x + width, y + lineWidth);
glLineWidth (1);
CDraw::drColour (CColour(1.0, 1.0, 1.0));
glBegin(GL_LINE_LOOP);
glVertex2f (x, y + lineWidth);
glVertex2f (x+ width, y + lineWidth);
glVertex2f (x + width, y - lineWidth);
glVertex2f (x, y - lineWidth);
glEnd();
}
void CGLView::drawDisplayText()
{
if (m_rating == 0)
{
m_rating = m_song->getRating();
return; // don't run this func the first time it is called
}
if (Cfg::quickStart)
return;
if (m_forcefullRedraw == 0)
return;
int y = Cfg::getAppHeight() - 14;
if (!m_settings->getWarningMessage().isEmpty())
{
glColor3f(1.0,0.0,0.0);
renderText(30, y-4, 0, m_settings->getWarningMessage(), m_timeRatingFont);
return;
}
glColor3f(1.0,1.0,1.0);
if (m_song->getPlayMode() != PB_PLAY_MODE_listen)
renderText(30, y-4,0 ,"Accuracy:", m_timeRatingFont);
if (m_titleHeight < 45 )
return;
y = Cfg::getAppHeight() - m_titleHeight;
renderText(30, y+6, 0,"Song: " + m_song->getSongTitle(), m_timeRatingFont);
/*
char buffer[100];
sprintf(buffer, "Notes %d wrong %d Late %d Score %4.1f%%",
m_rating->totalNoteCount(), m_rating->wrongNoteCount(),
m_rating->lateNoteCount(), m_rating->rating());
renderText(10,20, buffer, m_timeRatingFont);
*/
}
void CGLView::drawBarNumber()
{
if (m_forceBarRedraw == 0 || Cfg::quickStart)
return;
m_forceBarRedraw--;
float y = Cfg::getAppHeight() - m_titleHeight - 34;
float x = 30;
//CDraw::drColour (Cfg::backgroundColour());
//CDraw::drColour (Cfg::noteColourDim());
//glRectf(x+30+10, y-2, x + 80, y + 16);
glColor3f(1.0,1.0,1.0);
renderText(x, y, 0,"Bar: " + QString::number(m_song->getBarNumber()), m_timeRatingFont);
}
void CGLView::resizeGL(int width, int height)
{
const int maxSoreWidth = 1024;
const int staveEndGap = 20;
const int heightAboveStave = static_cast(CStavePos::verticalNoteSpacing() * MAX_STAVE_INDEX);
const int heightBelowStave = static_cast(CStavePos::verticalNoteSpacing() * - MIN_STAVE_INDEX);
const int minTitleHeight = 20;
const int minStaveGap = 120;
int staveGap;
int maxSoreHeight;
int space = height - (heightAboveStave + heightBelowStave + minTitleHeight + minStaveGap);
//m_titleHeight = qBound(minTitleHeight, minTitleHeight + space/2, 70);
// staveGap = qBound(minStaveGap, minStaveGap+ space/2, static_cast(CStavePos::staveHeight() * 3));
if (height < 430) // So it works on an eeepc 701 (for Trev)
{
staveGap = minStaveGap;
m_titleHeight = minTitleHeight;
}
else
{
staveGap = static_cast(CStavePos::staveHeight() * 3);
m_titleHeight = 60;
}
maxSoreHeight = heightAboveStave + heightBelowStave + staveGap + m_titleHeight;
int sizeX = qMin(width, maxSoreWidth);
int sizeY = qMin(height, maxSoreHeight);
int x = (width - sizeX)/2;
int y = (height - sizeY)/2;
y = (height - sizeY) - 5;
x = 0;
glViewport (x, y, sizeX, sizeY);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, sizeX, 0, sizeY, -1.0, 1.0);
glMatrixMode(GL_MODELVIEW);
CStavePos::setStaveCenterY(sizeY - maxSoreHeight/2 - m_titleHeight/2);
Cfg::setAppDimentions(x, y, sizeX, sizeY);
Cfg::setStaveEndX(sizeX - staveEndGap);
CStavePos::setStaveCentralOffset(staveGap/2);
CDraw::forceCompileRedraw();
}
void CGLView::mousePressEvent(QMouseEvent *event)
{
}
void CGLView::mouseMoveEvent(QMouseEvent *event)
{
}
void CGLView::initializeGL()
{
CColour colour = Cfg::backgroundColour();
glClearColor (colour.red, colour.green, colour.blue, 0.0);
glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
glShadeModel (GL_FLAT);
//glEnable(GL_TEXTURE_2D); // Enable Texture Mapping
//from initCheck();
glShadeModel(GL_FLAT);
//glEnable(GL_DEPTH_TEST);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
//glGenTextures(1, &texName);
//glBindTexture(GL_TEXTURE_2D, texName);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
//enableAntialiasedLines();
m_timeSigFont = QFont("Arial", 22 );
m_timeRatingFont = QFont("Arial", 12 );
Cfg::setStaveEndX(400); //This value get changed by the resizeGL func
m_song->setActiveHand(PB_PART_both);
if (!Cfg::quickStart)
{
renderText(10,10,QString("~"), m_timeRatingFont); //fixme this is a work around for a QT bug.
renderText(10,10,QString("~"), m_timeSigFont); //this is a work around for a QT bug.
}
setFocusPolicy(Qt::ClickFocus);
m_score->init();
// increased the tick time for Midi handling
m_timer.start(4, this ); // was 12
m_realtime.start();
//startMediaTimer(12, this );
}
void CGLView::updateMidiTask()
{
int ticks;
ticks = m_realtime.restart();
m_displayUpdateTicks += ticks;
m_eventBits |= m_song->task(ticks);
}
void CGLView::timerEvent(QTimerEvent *event)
{
BENCHMARK(0, "timer enter");
if (event->timerId() != m_timer.timerId())
{
QWidget::timerEvent(event);
return;
}
updateMidiTask();
BENCHMARK(1, "m_song task");
if (m_displayUpdateTicks < SCREEN_FRAME_RATE)
return;
m_displayUpdateTicks = 0;
if (m_eventBits != 0)
{
if ((m_eventBits & EVENT_BITS_UptoBarReached) != 0)
m_song->playFromStartBar();
if ((m_eventBits & EVENT_BITS_forceFullRedraw) != 0)
m_forcefullRedraw = m_forceRatingRedraw = m_forceBarRedraw = REDRAW_COUNT;
if ((m_eventBits & EVENT_BITS_forceRatingRedraw) != 0)
m_forceRatingRedraw = REDRAW_COUNT;
if ((m_eventBits & EVENT_BITS_newBarNumber) != 0)
m_forcefullRedraw = m_forceRatingRedraw = m_forceBarRedraw = REDRAW_COUNT; // fixme this did not work so redraw everything
m_qtWindow->songEventUpdated(m_eventBits);
m_eventBits = 0;
}
if(m_cfg_openGlOptimise)
m_fullRedrawFlag = false;
else
m_fullRedrawFlag = true;
glDraw();
//update();
m_fullRedrawFlag = true;
BENCHMARK(19, "timer exit");
}
void CGLView::mediaTimerEvent(int ticks)
{
}
pianobooster-src-0.6.4b/src/GuiSongDetailsDialog.ui 0000644 0001747 0001747 00000007110 11277632044 021752 0 ustar ubuntu ubuntu
GuiSongDetailsDialog
0
0
388
265
Dialog
-
-
Song Details
-
MIDI Channels for left and right hand piano parts:
false
-
-
Right Hand MIDI Channel:
-
0
0
180
0
-
Left Hand MIDI Channel:
-
0
0
150
0
-
Qt::Horizontal
QDialogButtonBox::Cancel|QDialogButtonBox::Ok
buttonBox
accepted()
GuiSongDetailsDialog
accept()
248
254
157
274
buttonBox
rejected()
GuiSongDetailsDialog
reject()
316
260
286
274
pianobooster-src-0.6.4b/src/pianobooster.desktop 0000644 0001747 0001747 00000000364 11304041717 021505 0 ustar ubuntu ubuntu [Desktop Entry]
Name=Piano Booster
Comment=A MIDI file player that teaches you how to play the piano
GenericName=Piano Teacher
Exec=pianobooster
Icon=pianobooster
Terminal=false
Type=Application
Categories=Music;Education;
MimeType=audio/midi;
pianobooster-src-0.6.4b/src/Rating.h 0000644 0001747 0001747 00000004355 11163466052 017015 0 ustar ubuntu ubuntu /*********************************************************************************/
/*!
@file Rating.h
@brief The generates a score on how well the pianist is doing.
@author L. J. Barman
Copyright (c) 2008-2009, L. J. Barman, all rights reserved
This file is part of the PianoBooster application
PianoBooster 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.
PianoBooster 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 PianoBooster. If not, see .
*/
/*********************************************************************************/
#ifndef __RATING_H__
#define __RATING_H__
#include "Util.h"
#include "Cfg.h"
class CRating
{
public:
CRating()
{
reset();
}
void reset();
void totalNotes(int count) { m_totalNotesCount += count;}
void wrongNotes(int count) { m_wrongNoteCount += count;}
void lateNotes(int count) { m_lateNoteCount += count;}
int totalNoteCount() {return m_totalNotesCount;}
int wrongNoteCount() {return m_wrongNoteCount;}
int lateNoteCount() {return m_lateNoteCount;}
double rating()
{
double percent = 100;
if (m_totalNotesCount > 0)
percent = ((m_totalNotesCount - m_lateNoteCount) * 100.0) /m_totalNotesCount;
return percent;
}
void calculateAccuracy();
float getAccuracyValue(){ return m_currentAccuracy; }
CColour getAccuracyColour() { return m_currentColour; }
bool isAccuracyGood() { return m_goodAccuracyFlag; }
private:
int m_totalNotesCount;
int m_previousNoteCount;
int m_lateNoteCount;
int m_previousLateNoteCount;
int m_wrongNoteCount;
float m_currentAccuracy;
float m_factor;
CColour m_currentColour;
bool m_goodAccuracyFlag;
};
#endif //__RATING_H__
pianobooster-src-0.6.4b/src/Tempo.h 0000644 0001747 0001747 00000005740 11277632044 016656 0 ustar ubuntu ubuntu /*********************************************************************************/
/*!
@file Tempo.h
@brief Tries to automatically calculate the tempo.
@author L. J. Barman
Copyright (c) 2008-2009, L. J. Barman, all rights reserved
This file is part of the PianoBooster application
PianoBooster 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.
PianoBooster 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 PianoBooster. If not, see .
*/
/*********************************************************************************/
#ifndef __TEMPO_H__
#define __TEMPO_H__
#include "MidiEvent.h"
#include "MidiFile.h"
#include "Chord.h"
// Define a chord
class CTempo
{
public:
CTempo()
{
m_savedwantedChord = 0;
reset();
}
void setSavedwantedChord(CChord * savedwantedChord) { m_savedwantedChord = savedwantedChord; }
void reset()
{
m_midiTempo = 1000000 * 120 / 60;// 120 beats per minute is the default
m_jumpAheadDelta = 0;
}
void setMidiTempo(int tempo)
{
m_midiTempo = float (tempo) * DEFAULT_PPQN / CMidiFile::getPulsesPerQuarterNote();
ppLogWarn("Midi Tempo %f %d", m_midiTempo, CMidiFile::getPulsesPerQuarterNote());
}
void setSpeed(float speed)
{
// limit the allowed speed
if (speed > 2.0f)
speed = 2.0f;
if (speed < 0.1f)
speed = 0.1f;
m_userSpeed = speed;
}
float getSpeed() {return m_userSpeed;}
int mSecToTicks(int mSec)
{
return static_cast(mSec * m_userSpeed * 100000000.0 /m_midiTempo);
}
void insertPlayingTicks(int ticks)
{
m_jumpAheadDelta -= ticks;
if (m_jumpAheadDelta < CMidiFile::ppqnAdjust(-10)*SPEED_ADJUST_FACTOR)
m_jumpAheadDelta = CMidiFile::ppqnAdjust(-10)*SPEED_ADJUST_FACTOR;
}
void removePlayingTicks(int ticks)
{
if (m_cfg_maxJumpAhead != 0)
m_jumpAheadDelta = ticks;
}
void clearPlayingTicks()
{
m_jumpAheadDelta = 0;
}
void adjustTempo(int * ticks);
static void enableFollowTempo(bool enable);
private:
float m_userSpeed; // controls the speed of the piece playing
float m_midiTempo; // controls the speed of the piece playing
int m_jumpAheadDelta;
static int m_cfg_maxJumpAhead;
static int m_cfg_followTempoAmount;
CChord *m_savedwantedChord; // A copy of the wanted chord complete with both left and right parts
};
#endif // __TEMPO_H__
pianobooster-src-0.6.4b/src/MidiFile.h 0000644 0001747 0001747 00000004622 11266324061 017245 0 ustar ubuntu ubuntu /*********************************************************************************/
/*!
@file MidiFile.h
@brief xxxxx.
@author L. J. Barman
Copyright (c) 2008-2009, L. J. Barman, all rights reserved
This file is part of the PianoBooster application
PianoBooster 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.
PianoBooster 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 PianoBooster. If not, see .
*/
/////////////////////////////////////////////////////////////////////////////
#ifndef __MIDIFILE_H__
#define __MIDIFILE_H__
#include
#include
#include "MidiEvent.h"
#include "MidiTrack.h"
#include "Merge.h"
#define DEFAULT_PPQN 96 /* Standard value for pulse per quarter note */
using namespace std;
#define MAX_TRACKS 40
// Reads data from a standard MIDI file
class CMidiFile : public CMerge
{
public:
CMidiFile()
{
size_t i;
midiError(SMF_NO_ERROR);
m_ppqn = DEFAULT_PPQN;
setSize(MAX_TRACKS);
for (i = 0; i < arraySize(m_tracks); i++)
m_tracks[i] = 0;
}
void openMidiFile(string filename);
int readWord(void);
int readHeader(void);
void rewind();
static int getPulsesPerQuarterNote(){return m_ppqn;}
static int ppqnAdjust(float value) {
return static_cast((value * static_cast(CMidiFile::getPulsesPerQuarterNote()))/DEFAULT_PPQN );
}
QString getSongTitle() {return m_songTitle;}
void setLogLevel(int level){CMidiTrack::setLogLevel(level);}
midiErrors_t getMidiError() { return m_midiError;}
private:
bool checkMidiEventFromStream(int streamIdx);
CMidiEvent fetchMidiEventFromStream(int streamIdx);
void midiError(midiErrors_t error) {m_midiError = error;}
fstream m_file;
static int m_ppqn;
midiErrors_t m_midiError;
CMidiTrack* m_tracks[MAX_TRACKS];
QString m_songTitle;
};
#endif // __MIDIFILE_H__
pianobooster-src-0.6.4b/src/GuiTopBar.ui 0000644 0001747 0001747 00000012103 11303063627 017576 0 ustar ubuntu ubuntu
GuiTopBar
0
0
839
34
0
0
0
34
524287
524287
Form
QLayout::SetMaximumSize
0
0
-
6
QLayout::SetFixedSize
-
Start playing music from the start
:/images/play-from-start.png:/images/play-from-start.png
24
24
false
-
Start and stop playing music
:/images/play.png:/images/play.png
24
24
false
-
Speed:
-
-
Key:
-
-
-
Transpose:
-
-
12
24
true
Qt::DownArrow
-
Start Bar:
-
1
999.899999999999977
-
Save this Bar Number
:/images/flag.png:/images/flag.png
24
24
-
Qt::Horizontal
0
30
pianobooster-src-0.6.4b/src/GuiPreferencesDialog.cpp 0000644 0001747 0001747 00000005015 11303577704 022147 0 ustar ubuntu ubuntu /*!
@file GuiPreferencesDialog.cpp
@brief xxx.
@author L. J. Barman
Copyright (c) 2008-2009, L. J. Barman, all rights reserved
This file is part of the PianoBooster application
PianoBooster 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.
PianoBooster 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 PianoBooster. If not, see .
*/
#include
#include "GuiPreferencesDialog.h"
#include "GlView.h"
GuiPreferencesDialog::GuiPreferencesDialog(QWidget *parent)
: QDialog(parent)
{
setupUi(this);
m_song = 0;
m_settings = 0;
m_glView = 0;
setWindowTitle("Preferences");
}
void GuiPreferencesDialog::init(CSong* song, CSettings* settings, CGLView * glView)
{
m_song = song;
m_settings = settings;
m_glView = glView;
videoOptimiseCheck->setChecked(m_glView->m_cfg_openGlOptimise);
timingMarkersCheck->setChecked(m_song->cfg_timingMarkersFlag);
showNoteNamesCheck->setChecked(m_settings->isNoteNamesEnabled());
courtesyAccidentalsCheck->setChecked(m_settings->displayCourtesyAccidentals());
followStopPointCombo->addItem("Automatic (Recommended)");
followStopPointCombo->addItem("On the Beat");
followStopPointCombo->addItem("After the Beat");
followStopPointCombo->setCurrentIndex(m_song->cfg_stopPointMode);
}
void GuiPreferencesDialog::accept()
{
m_glView->m_cfg_openGlOptimise = videoOptimiseCheck->isChecked();
m_settings->setValue("Display/OpenGlOptimise", m_glView->m_cfg_openGlOptimise );
m_song->cfg_timingMarkersFlag = timingMarkersCheck->isChecked();
m_settings->setValue("Score/TimingMarkers", m_song->cfg_timingMarkersFlag );
m_settings->setNoteNamesEnabled( showNoteNamesCheck->isChecked());
m_settings->setCourtesyAccidentals( courtesyAccidentalsCheck->isChecked());
m_song->cfg_stopPointMode = static_cast (followStopPointCombo->currentIndex());
m_settings->setValue("Score/StopPointMode", m_song->cfg_stopPointMode );
m_song->refreshScroll();
this->QDialog::accept();
}
pianobooster-src-0.6.4b/src/pianobooster.pro 0000755 0001747 0001747 00000006157 11303577704 020656 0 ustar ubuntu ubuntu #CONFIG += USE_FLUIDSYNTH
CONFIG += release
USE_FLUIDSYNTH {
# Note The FLUIDSYNTH_INPLACE_DIR dir is used mainly used when compiling on windows
# You normally do not need to set it
#FLUIDSYNTH_INPLACE_DIR = ../../fluidsynth-1.0.9
message(building using fluidsynth)
DEFINES += PB_USE_FLUIDSYNTH
}
CONFIG += precompile_header
PRECOMPILED_HEADER = precompile/precompile.h
HEADERS = precompile/precompile.h \
QtWindow.h \
GlView.h \
GuiTopBar.h \
GuiSidePanel.h \
GuiMidiSetupDialog.h \
GuiKeyboardSetupDialog.h \
GuiPreferencesDialog.h \
GuiSongDetailsDialog.h \
GuiLoopingPopup.h
FORMS = GuiTopBar.ui \
GuiSidePanel.ui \
GuiMidiSetupDialog.ui \
GuiKeyboardSetupDialog.ui \
GuiPreferencesDialog.ui \
GuiSongDetailsDialog.ui \
GuiLoopingPopup.ui
RESOURCES = application.qrc
SOURCES = QtMain.cpp \
QtWindow.cpp \
GuiTopBar.cpp \
GuiSidePanel.cpp \
GuiMidiSetupDialog.cpp \
GuiKeyboardSetupDialog.cpp \
GuiPreferencesDialog.cpp \
GuiSongDetailsDialog.cpp \
GuiLoopingPopup.cpp \
GlView.cpp \
MidiFile.cpp \
MidiTrack.cpp \
Song.cpp \
Conductor.cpp \
Util.cpp \
Chord.cpp \
Tempo.cpp \
MidiDevice.cpp \
MidiDeviceRt.cpp \
rtmidi/RtMidi.cpp \
StavePosition.cpp \
Score.cpp \
Cfg.cpp \
Piano.cpp \
Draw.cpp \
Scroll.cpp \
Notation.cpp \
TrackList.cpp \
Rating.cpp \
Bar.cpp \
Settings.cpp \
Merge.cpp \
RC_FILE = pianobooster.rc
INCLUDEPATH += rtmidi
OBJECTS_DIR = tmp
win32 {
DEFINES += __WINDOWS_MM__ _WIN32
LIBS += libwinmm
}
unix {
DEFINES += __LINUX_ALSASEQ__
LIBS += -lasound
}
USE_FLUIDSYNTH {
SOURCES += MidiDeviceFluidSynth.cpp
!isEmpty(FLUIDSYNTH_INPLACE_DIR) {
!exists( $${FLUIDSYNTH_INPLACE_DIR}/include/fluidsynth.h ) {
error( "No $${FLUIDSYNTH_INPLACE_DIR}/include/fluidsynth.h file found" )
}
message(fluidsynth FLUIDSYNTH_INPLACE_DIR = $${FLUIDSYNTH_INPLACE_DIR})
INCLUDEPATH += $${FLUIDSYNTH_INPLACE_DIR}/include/
win32:LIBS += $${FLUIDSYNTH_INPLACE_DIR}/src/.libs/libfluidsynth.dll.a
unix:LIBS += $${FLUIDSYNTH_INPLACE_DIR}/src/.libs/libfluidsynth.a
}
}
QT += xml opengl
# enable the console window
#QT+=testlib
unix {
isEmpty( PREFIX ) { PREFIX = /usr/local }
target.path = $$PREFIX/bin
desktop.path = $$PREFIX/share/applications
desktop.files = pianobooster.desktop
pixmaps.path = $$PREFIX/share/pixmaps
pixmaps.files = images/pianobooster.png
docs.path = $$PREFIX/share/doc/pianobooster
docs.files = ../README.txt
INSTALLS += target desktop pixmaps docs
}
pianobooster-src-0.6.4b/src/QtWindow.h 0000644 0001747 0001747 00000011433 11304221574 017333 0 ustar ubuntu ubuntu /*!
@file QtWindow.h
@brief xxx.
@author L. J. Barman
Copyright (c) 2008-2009, L. J. Barman, all rights reserved
This file is part of the PianoBooster application
PianoBooster 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.
PianoBooster 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 PianoBooster. If not, see .
*/
#ifndef __QT_WINDOW_H__
#define __QT_WINDOW_H__
#include
#include "Song.h"
#include "Score.h"
#include "GuiMidiSetupDialog.h"
#include "GuiKeyboardSetupDialog.h"
#include "GuiSidePanel.h"
#include "GuiTopBar.h"
#include "GuiPreferencesDialog.h"
#include "GuiSongDetailsDialog.h"
#include "GuiLoopingPopup.h"
#include "Settings.h"
class CGLView;
class QAction;
class QMenu;
class QSlider;
class QPushButton;
class QtWindow : public QMainWindow
{
Q_OBJECT
public:
QtWindow();
~QtWindow();
void songEventUpdated(int eventBits)
{
if ((eventBits & EVENT_BITS_playingStopped) != 0)
m_topBar->setPlayButtonState(false, true);
}
private slots:
void open();
void help();
void website();
void about();
void keyboardShortcuts();
void showMidiSetup()
{
GuiMidiSetupDialog midiSetupDialog(this);
midiSetupDialog.init(m_song, m_settings);
midiSetupDialog.exec();
}
void showPreferencesDialog()
{
GuiPreferencesDialog preferencesDialog(this);
preferencesDialog.init(m_song, m_settings, m_glWidget);
preferencesDialog.exec();
}
void showSongDetailsDialog()
{
GuiSongDetailsDialog songDetailsDialog(this);
songDetailsDialog.init(m_song, m_settings);
songDetailsDialog.exec();
}
void showKeyboardSetup()
{
GuiKeyboardSetupDialog keyboardSetup(this);
keyboardSetup.init(m_song, m_settings);
keyboardSetup.exec();
}
void toggleSidePanel()
{
m_sidePanel->setVisible(!m_sidePanel->isVisible());
}
void enableFollowTempo()
{
CTempo::enableFollowTempo(Cfg::experimentalTempo);
}
void disableFollowTempo()
{
CTempo::enableFollowTempo(false);
}
void on_rightHand() { m_sidePanel->setActiveHand(PB_PART_right); }
void on_bothHands() { m_sidePanel->setActiveHand(PB_PART_both); }
void on_leftHand() { m_sidePanel->setActiveHand(PB_PART_left); }
void on_playFromStart() {
if(m_song->playingMusic())
m_topBar->on_playButton_clicked(true); // Stop the music first if playing
else
m_topBar->on_playFromStartButton_clicked(true);
}
void on_playPause() { m_topBar->on_playButton_clicked(true); }
void on_faster() {
float speed = m_song->getSpeed() + 0.04;
m_song->setSpeed(speed);
speed = m_song->getSpeed();
m_topBar->setSpeed(static_cast(speed*100 + 0.5));
}
void on_slower() {
float speed = m_song->getSpeed() - 0.04;
m_song->setSpeed(speed);
speed = m_song->getSpeed();
m_topBar->setSpeed(static_cast(speed*100 + 0.5));
}
void on_nextSong() { m_sidePanel->nextSong(+1); }
void on_previousSong() { m_sidePanel->nextSong(-1); }
protected:
void closeEvent(QCloseEvent *event);
void keyPressEvent ( QKeyEvent * event );
void keyReleaseEvent ( QKeyEvent * event );
private:
void decodeCommandLine();
int decodeIntegerParam(QString arg, int defaultParam);
void decodeMidiFileArg(QString arg);
QString displayShortCut(QString code, QString description);
void addShortcutAction(const QString & key, const char * method);
void displayUsage();
void createActions();
void createMenus();
void readSettings();
void writeSettings();
CSettings* m_settings;
GuiSidePanel *m_sidePanel;
GuiTopBar *m_topBar;
CGLView *m_glWidget;
QAction *m_openAct;
QAction *m_exitAct;
QAction *m_aboutAct;
QAction *m_shortcutAct;
QAction *m_songPlayAct;
QAction *m_setupMidiAct;
QAction *m_setupKeyboardAct;
QAction *m_toggleSidePanelAct;
QAction *m_setupPreferencesAct;
QAction *m_songDetailsAct;
QMenu *m_fileMenu;
QMenu *m_viewMenu;
QMenu *m_songMenu;
QMenu *m_setupMenu;
QMenu *m_helpMenu;
CSong* m_song;
CScore* m_score;
};
#endif // __QT_WINDOW_H__
pianobooster-src-0.6.4b/src/MidiDeviceFluidSynth.h 0000644 0001747 0001747 00000004653 11232414516 021601 0 ustar ubuntu ubuntu /*********************************************************************************/
/*!
@file MidiDeviceFluidSynth.h
@brief xxxxxx.
@author L. J. Barman
Copyright (c) 2008-2009, L. J. Barman, all rights reserved
This file is part of the PianoBooster application
PianoBooster 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.
PianoBooster 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 PianoBooster. If not, see .
*/
/*********************************************************************************/
#ifndef __MIDI_DEVICE_FLUIDSYNTH_H__
#define __MIDI_DEVICE_FLUIDSYNTH_H__
#include "MidiDeviceBase.h"
#include
class CMidiDeviceFluidSynth : public CMidiDeviceBase
{
virtual void init();
//! add a midi event to be played immediately
virtual void playMidiEvent(const CMidiEvent & event);
virtual int checkMidiInput();
virtual CMidiEvent readMidiInput();
virtual QStringList getMidiPortList(midiType_t type);
virtual bool openMidiPort(midiType_t type, QString portName);
virtual void closeMidiPort(midiType_t type, int index);
// based on the fluid synth settings
virtual int midiSettingsSetStr(QString name, QString str);
virtual int midiSettingsSetNum(QString name, double val);
virtual int midiSettingsSetInt(QString name, int val);
virtual QString midiSettingsGetStr(QString name);
virtual double midiSettingsGetNum(QString name);
virtual int midiSettingsGetInt(QString name);
public:
CMidiDeviceFluidSynth();
~CMidiDeviceFluidSynth();
private:
unsigned char m_savedRawBytes[40]; // Raw data is used for used for a SYSTEM_EVENT
unsigned int m_rawDataIndex;
fluid_settings_t* m_fluidSettings;
fluid_synth_t* m_synth;
fluid_audio_driver_t* m_audioDriver;
int m_soundFontId;
};
#endif //__MIDI_DEVICE_FLUIDSYNTH_H__
pianobooster-src-0.6.4b/src/MidiTrack.h 0000644 0001747 0001747 00000007521 11303063627 017433 0 ustar ubuntu ubuntu /*********************************************************************************/
/*!
@file MidiTrack.h
@brief xxxx.
@author L. J. Barman
Copyright (c) 2008-2009, L. J. Barman, all rights reserved
This file is part of the PianoBooster application
PianoBooster 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.
PianoBooster 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 PianoBooster. If not, see .
*/
/*********************************************************************************/
#ifndef __MIDITRACK_H__
#define __MIDITRACK_H__
#include
#include
#include
#include "Queue.h"
#include "MidiEvent.h"
using namespace std;
typedef enum
{
SMF_NO_ERROR,
SMF_CANNOT_OPEN_FILE,
SMF_CORRUPTED_MIDI_FILE,
SMF_UNKNOW_EVENT,
SMF_ERROR_TOO_MANY_TRACK,
SMF_END_OF_FILE
} midiErrors_t;
typedef unsigned char byte_t;
typedef unsigned short word_t;
typedef unsigned long dword_t;
// Reads data from a standard MIDI file
class CMidiTrack
{
public:
CMidiTrack(fstream& file, int no);
~CMidiTrack()
{
delete m_trackEventQueue;
}
int readDelaTime()
{
int deltaTime = m_deltaTime;
m_deltaTime = 0;
return deltaTime;
}
dword_t getTrackLength() {return m_trackLength;}
void decodeTrack();
bool failed() { return (m_midiError != SMF_NO_ERROR) ? true : false;}
midiErrors_t getMidiError() { return m_midiError;}
int length() {return m_trackEventQueue->length();}
CMidiEvent pop() {return m_trackEventQueue->pop();}
QString getTrackName() {return m_trackName;}
static void setLogLevel(int level){m_logLevel = level;}
private:
void errorFail(midiErrors_t error)
{
if (m_midiError != SMF_NO_ERROR || error != SMF_NO_ERROR)
{
m_midiError = error;
if (m_midiError != SMF_NO_ERROR)
ppLogError("Midi error %d", m_midiError);
}
}
void midiFailReset() { m_midiError = SMF_NO_ERROR;}
void ppDebugTrack(int level, const char *msg, ...);
byte_t readByte(void)
{
int c;
if (m_trackLengthCounter != 0 )
{
c = m_file.get();
if (m_file.fail() == true)
errorFail(SMF_END_OF_FILE);
m_trackLengthCounter--;
}
else
c = 0;
return c;
}
word_t readWord(void)
{
word_t value;
value = (readByte()&0x0ff) <<8 ;
value |= readByte()&0x0ff;
return value;
}
dword_t readDWord(void)
{
dword_t value;
value = (readWord()&0x0ffff) <<16 ;
value |= readWord()&0x0ffff;
return value;
}
void decodeMidiEvent();
dword_t readVarLen();
string readTextEvent();
dword_t readDataEvent(int expectedLength);
void readMetaEvent(byte_t type);
void ignoreSysexEvent(byte_t data);
void readTimeSignatureEvent();
void readKeySignatureEvent();
void decodeSystemMessage( byte_t status, byte_t data1 );
fstream& m_file;
int m_trackNumber;
streampos m_filePos;
dword_t m_trackLength;
dword_t m_trackLengthCounter;
CQueue* m_trackEventQueue;
int m_savedRunningStatus;
int m_deltaTime;
midiErrors_t m_midiError;
QString m_trackName;
static int m_logLevel;
};
#endif // __MIDITRACK_H__
pianobooster-src-0.6.4b/src/MidiDevice.h 0000644 0001747 0001747 00000004562 11301345653 017570 0 ustar ubuntu ubuntu /*********************************************************************************/
/*!
@file MidiDevice.h
@brief xxxxxx.
@author L. J. Barman
Copyright (c) 2008-2009, L. J. Barman, all rights reserved
This file is part of the PianoBooster application
PianoBooster 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.
PianoBooster 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 PianoBooster. If not, see .
*/
/*********************************************************************************/
#ifndef __MIDI_DEVICE_H__
#define __MIDI_DEVICE_H__
#include "Util.h"
/*!
* @brief xxxxx.
*/
#include "MidiEvent.h"
#include "MidiDeviceBase.h"
class CMidiDevice : public CMidiDeviceBase
{
public:
CMidiDevice();
~CMidiDevice();
void init();
//! add a midi event to be played immediately
void playMidiEvent(const CMidiEvent & event);
int checkMidiInput();
CMidiEvent readMidiInput();
bool validMidiOutput() { return m_validOutput; }
QStringList getMidiPortList(midiType_t type);
bool openMidiPort(midiType_t type, QString portName);
void closeMidiPort(midiType_t type, int index);
// based on the fluid synth settings
virtual int midiSettingsSetStr(QString name, QString str);
virtual int midiSettingsSetNum(QString name, double val);
virtual int midiSettingsSetInt(QString name, int val);
virtual QString midiSettingsGetStr(QString name);
virtual double midiSettingsGetNum(QString name);
virtual int midiSettingsGetInt(QString name);
private:
CMidiDeviceBase* m_rtMidiDevice;
#if PB_USE_FLUIDSYNTH
CMidiDeviceBase* m_fluidSynthMidiDevice;
#endif
CMidiDeviceBase* m_selectedMidiInputDevice;
CMidiDeviceBase* m_selectedMidiOutputDevice;
bool m_validOutput;
};
#endif //__MIDI_DEVICE_H__
pianobooster-src-0.6.4b/src/GuiSongDetailsDialog.h 0000644 0001747 0001747 00000003304 11301345653 021560 0 ustar ubuntu ubuntu /*********************************************************************************/
/*!
@file GuiSongDetailsDialog.h
@brief xxxx.
@author L. J. Barman
Copyright (c) 2008-2009, L. J. Barman, all rights reserved
This file is part of the PianoBooster application
PianoBooster 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.
PianoBooster 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 PianoBooster. If not, see .
*/
/*********************************************************************************/
#ifndef __GUISONGDETAILSDIALOG_H__
#define __GUISONGDETAILSDIALOG_H__
#include
#include "Song.h"
#include "Settings.h"
#include "ui_GuiSongDetailsDialog.h"
class CGLView;
class GuiSongDetailsDialog : public QDialog, private Ui::GuiSongDetailsDialog
{
Q_OBJECT
public:
GuiSongDetailsDialog(QWidget *parent = 0);
void init(CSong* song, CSettings* settings);
private slots:
void accept();
void on_leftHandChannelCombo_activated (int index);
void on_rightHandChannelCombo_activated (int index);
private:
void updateSongInfoText();
CSettings* m_settings;
CSong* m_song;
CTrackList* m_trackList;
};
#endif //__GUISONGDETAILSDIALOG_H__
pianobooster-src-0.6.4b/src/Song.cpp 0000644 0001747 0001747 00000016447 11303601311 017020 0 ustar ubuntu ubuntu /*********************************************************************************/
/*!
@file Song.cpp
@brief xxxxx.
@author L. J. Barman
Copyright (c) 2008-2009, L. J. Barman, all rights reserved
This file is part of the PianoBooster application
PianoBooster 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.
PianoBooster 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 PianoBooster. If not, see .
*/
/*********************************************************************************/
#include "Song.h"
#include "Score.h"
void CSong::init(CScore * scoreWin, CSettings* settings)
{
CNote::setChannelHands(-2, -2); // -2 for not set -1 for none
this->CConductor::init(scoreWin, settings);
setActiveHand(PB_PART_both);
setPlayMode(PB_PLAY_MODE_followYou);
setSpeed(1.0);
setSkill(3);
}
void CSong::loadSong(const QString & filename)
{
CNote::setChannelHands(-2, -2); // -2 for not set -1 for none
m_songTitle = filename;
int index = m_songTitle.lastIndexOf("/");
if (index >= 0)
m_songTitle = m_songTitle.right( m_songTitle.length() - index - 1);
QString fn = filename;
#ifdef _WIN32
fn = fn.replace('/','\\');
#endif
m_midiFile->setLogLevel(3);
m_midiFile->openMidiFile(string(fn.toAscii()));
ppLogInfo("Opening song %s", string(fn.toAscii()).c_str());
transpose(0);
midiFileInfo();
m_midiFile->setLogLevel(99);
playMusic(false);
rewind();
setPlayFromBar(0.0);
setLoopingBars(0.0);
setEventBits(EVENT_BITS_playingStopped);
if (!m_midiFile->getSongTitle().isEmpty())
m_songTitle = m_midiFile->getSongTitle();
}
// read the file ahead to collect info about the song first
void CSong::midiFileInfo()
{
m_trackList->clear();
setTimeSig(0,0);
CStavePos::setKeySignature( NOT_USED, 0 );
// Read the next events to find the active channels
CMidiEvent event;
while ( true )
{
event = m_midiFile->readMidiEvent();
m_trackList->examineMidiEvent(event);
if (event.type() == MIDI_PB_timeSignature)
{
setTimeSig(event.data1(),event.data2());
}
if (event.type() == MIDI_PB_EOF)
break;
}
}
void CSong::rewind()
{
m_midiFile->rewind();
this->CConductor::rewind();
m_scoreWin->reset();
reset();
forceScoreRedraw();
}
void CSong::setActiveHand(whichPart_t hand)
{
if (hand < PB_PART_both)
hand = PB_PART_both;
if (hand > PB_PART_left)
hand = PB_PART_left;
this->CConductor::setActiveHand(hand);
m_scoreWin->setDisplayHand(hand);
}
void CSong::setActiveChannel(int chan)
{
this->CConductor::setActiveChannel(chan);
m_scoreWin->setActiveChannel(chan);
regenerateChordQueue();
}
void CSong::setPlayMode(playMode_t mode)
{
regenerateChordQueue();
this->CConductor::setPlayMode(mode);
forceScoreRedraw();
}
void CSong::regenerateChordQueue()
{
int i;
int length;
CMidiEvent event;
m_wantedChordQueue->clear();
m_findChord.reset();
length = m_songEventQueue->length();
for (i = 0; i < length; i++)
{
event = m_songEventQueue->index(i);
// Find the next chord
if (m_findChord.findChord(event, getActiveChannel(), PB_PART_both) == true)
chordEventInsert( m_findChord.getChord() ); // give the Conductor the chord event
}
resetWantedChord();
}
void CSong::refreshScroll()
{
m_scoreWin->refreshScroll();
forceScoreRedraw();
}
eventBits_t CSong::task(int ticks)
{
realTimeEngine(ticks);
while (true)
{
if (m_reachedMidiEof == true)
goto exitTask;
while (true)
{
// Check that there is space
if (midiEventSpace() <= 10 || chordEventSpace() <= 10)
break;
// and that the Score has space also
if (m_scoreWin->midiEventSpace() <= 100)
break;
// Read the next events
CMidiEvent event = m_midiFile->readMidiEvent();
//ppLogTrace("Song event delta %d type 0x%x chan %d Note %d", event.deltaTime(), event.type(), event.channel(), event.note());
// Find the next chord
if (m_findChord.findChord(event, getActiveChannel(), PB_PART_both) == true)
chordEventInsert( m_findChord.getChord() ); // give the Conductor the chord event
// send the events to the other end
m_scoreWin->midiEventInsert(event);
// send the events to the other end
midiEventInsert(event);
if (event.type() == MIDI_PB_EOF)
{
m_reachedMidiEof = true;
break;
}
}
// carry on with the data until we reach the bar we want
if (seekingBarNumber() && m_reachedMidiEof == false && playingMusic())
{
realTimeEngine(0);
m_scoreWin->drawScrollingSymbols(false); // don't display any thing just remove from the queue
}
else
break;
}
exitTask:
eventBits_t eventBits = m_realTimeEventBits;
m_realTimeEventBits = 0;
return eventBits;
}
static const struct pcNote_s
{
int key;
int note;
} pcNoteLookup[] =
{
{ 'a', PC_KEY_LOWEST_NOTE },
{ 'z', 59 }, // B
{ 'x', 60 }, // Middle C
{ 'd', 61 },
{ 'c', 62 }, // D
{ 'f', 63 },
{ 'v', 64 }, // E
{ 'b', 65 }, // F
{ 'h', 66 },
{ 'n', 67 }, // G
{ 'j', 68 },
{ 'm', 69 }, // A
{ 'k', 70 },
{ ',', 71 }, // B
{ '.', 72 }, // C
{ ';', 73 },
{ '/', 74 }, // D
{ '\'', PC_KEY_HIGHEST_NOTE },
};
// Fakes a midi piano keyboard using the PC keyboard
bool CSong::pcKeyPress(int key, bool down)
{
int i;
size_t j;
CMidiEvent midi;
const int cfg_pcKeyVolume = 64;
const int cfg_pcKeyChannel = 1-1;
if (key == '\t') // the tab key on the PC fakes good notes
{
if (down)
m_fakeChord = getWantedChord();
for (i = 0; i < m_fakeChord.length(); i++)
{
if (down)
midi.noteOnEvent(0, cfg_pcKeyChannel, m_fakeChord.getNote(i).pitch() + getTranspose(), cfg_pcKeyVolume);
else
midi.noteOffEvent(0, cfg_pcKeyChannel, m_fakeChord.getNote(i).pitch() + getTranspose(), cfg_pcKeyVolume);
pianistInput(midi);
}
return true;
}
for (j = 0; j < arraySize(pcNoteLookup); j++)
{
if ( key==pcNoteLookup[j].key)
{
if (down)
midi.noteOnEvent(0, cfg_pcKeyChannel, pcNoteLookup[j].note, cfg_pcKeyVolume);
else
midi.noteOffEvent(0, cfg_pcKeyChannel, pcNoteLookup[j].note, cfg_pcKeyVolume);
pianistInput(midi);
return true;
}
}
//printf("pcKeyPress %d %d\n", m_pcNote, key);
return false;
}
pianobooster-src-0.6.4b/src/GuiLoopingPopup.h 0000644 0001747 0001747 00000003011 11163466052 020655 0 ustar ubuntu ubuntu /*********************************************************************************/
/*!
@file GuiLoopingPopup.h
@brief xxxx.
@author L. J. Barman
Copyright (c) 2008-2009, L. J. Barman, all rights reserved
This file is part of the PianoBooster application
PianoBooster 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.
PianoBooster 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 PianoBooster. If not, see .
*/
/*********************************************************************************/
#ifndef __GUILOOPINGPOPUP_H__
#define __GUILOOPINGPOPUP_H__
#include
#include "Song.h"
#include "ui_GuiLoopingPopup.h"
class CGLView;
class GuiLoopingPopup : public QWidget, private Ui::GuiLoopingPopup
{
Q_OBJECT
public:
GuiLoopingPopup(QWidget *parent = 0);
void init(CSong* song);
private slots:
void on_loopBarsSpin_valueChanged(double bars);
void closeEvent(QCloseEvent *event);
private:
void updateInfo();
CSong* m_song;
};
#endif //__GUILOOPINGPOPUP_H__
pianobooster-src-0.6.4b/src/TrackList.h 0000644 0001747 0001747 00000005070 11240341260 017451 0 ustar ubuntu ubuntu /*********************************************************************************/
/*!
@file TrackList.h
@brief xxxx.
@author L. J. Barman
Copyright (c) 2008-2009, L. J. Barman, all rights reserved
This file is part of the PianoBooster application
PianoBooster 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.
PianoBooster 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 PianoBooster. If not, see .
*/
/*********************************************************************************/
#ifndef __TRACK_LIST_H__
#define __TRACK_LIST_H__
#include
#include
#include
#include "MidiEvent.h"
#include "Chord.h"
#define CONVENTION_LEFT_HAND_CHANNEL (3-1)
#define CONVENTION_RIGHT_HAND_CHANNEL (4-1)
class CSong;
class CSettings;
class CTrackListItem
{
public:
int midiChannel;
};
class CTrackList
{
public:
CTrackList()
{
m_song = 0;
m_settings = 0;
clear();
}
void init(CSong* songObj, CSettings* settings);
void refresh();
void clear();
void currentRowChanged(int currentRow);
void examineMidiEvent(CMidiEvent event);
bool pianoPartConvetionTest();
int guessKeySignature(int chanA, int chanB);
// The programme name now starts at 1 with 0 = "(none)"
static QString getProgramName(int program);
QStringList getAllChannelProgramNames(bool raw=false);
int getActiveItemIndex();
int getActiveHandIndex(whichPart_t whichPart);
// set the midi channels to use for the left and right hand piano parts
void setActiveHandsIndex(int leftIndex, int rightIndex);
int getHandTrackIndex(whichPart_t whichPart);
void changeListWidgetItemView(unsigned int index, QListWidgetItem* listWidgetItem);
private:
QString getChannelProgramName(int chan);
CSong* m_song;
CSettings* m_settings;
QList m_trackQtList;
bool m_midiActiveChannels[MAX_MIDI_CHANNELS];
int m_midiFirstPatchChannels[MAX_MIDI_CHANNELS];
int m_noteFrequency[MAX_MIDI_CHANNELS][MAX_MIDI_NOTES];
};
#endif //__TRACK_LIST_H__
pianobooster-src-0.6.4b/src/Bar.cpp 0000644 0001747 0001747 00000007333 11266324061 016624 0 ustar ubuntu ubuntu /*********************************************************************************/
/*!
@file Bar.cpp
@brief xxx.
@author L. J. Barman
Copyright (c) 2008-2009, L. J. Barman, all rights reserved
This file is part of the PianoBooster application
PianoBooster 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.
PianoBooster 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 PianoBooster. If not, see .
*/
/*********************************************************************************/
#include "Bar.h"
#define OPTION_DEBUG_BAR 0
#if OPTION_DEBUG_BAR
#define ppDEBUG_BAR(args) ppLogDebug args
#else
#define ppDEBUG_BAR(args)
#endif
void CBar::setTimeSig(int top, int bottom)
{
m_currentTimeSigTop = top;
m_currentTimeSigBottom = bottom;
if (bottom == 0 || m_startTimeSigBottom == 0) {
m_startTimeSigTop = top;
m_startTimeSigBottom = bottom;
if (bottom == 0 )
{
m_currentTimeSigTop = 4;
m_currentTimeSigBottom = 4;
m_deltaTime = 0;
m_beatCounter = 0;
m_barCounter = 0;
}
}
m_beatLength = (CMidiFile::getPulsesPerQuarterNote() *4)/ m_currentTimeSigBottom;
m_barLength = m_beatLength * getTimeSigTop();
}
int CBar::addDeltaTime(int ticks)
{
if (m_flushTicks == true && ticks != 0) // ignore this set of ticks
{
ppDEBUG_BAR(("addDeltaTime m_flushTicks ticks %d", ticks));
m_flushTicks = false;
return 0;
}
m_deltaTime +=ticks;
if (ticks && m_enablePlayFromBar)
checkGotoBar();
while (m_deltaTime > m_beatLength * SPEED_ADJUST_FACTOR)
{
m_deltaTime -= m_beatLength * SPEED_ADJUST_FACTOR;
m_beatCounter++;
if (m_beatCounter >= m_currentTimeSigTop)
{
m_barCounter++;
m_beatCounter=0;
ppLogWarn("Bar number %d", m_barCounter);
m_eventBits |= EVENT_BITS_newBarNumber;
}
}
return ticks;
}
int CBar::goToBarNumer()
{
int ticks;
ticks = static_cast((m_playFromBar - getCurrentBarPos()) * m_beatLength * SPEED_ADJUST_FACTOR + 1);
addDeltaTime(ticks);
return ticks;
}
void CBar::checkGotoBar()
{
double currentBar = getCurrentBarPos();
ppDEBUG_BAR(("checkGotoBar currentBarPos %.1f", currentBar));
if (currentBar < m_playFromBar )
m_seekingBarNumber = true;
else
{
if (m_seekingBarNumber == true)
m_flushTicks = true; // now throw away ticks before we start the music
m_seekingBarNumber = false;
if (m_enableLooping && currentBar > m_playUptoBar )
m_eventBits |= EVENT_BITS_UptoBarReached;
}
}
void CBar::setPlayFromBar(double bar)
{
m_playFromBar = bar;
m_playUptoBar = m_playFromBar + m_loopingBars;
setupEnableFlags();
checkGotoBar();
}
void CBar::setPlayFromBar(int bar, int beat, int ticks)
{
double playFromBar = bar;
setPlayFromBar( playFromBar);
}
void CBar::setPlayUptoBar(double endBar)
{
setLoopingBars(endBar - m_playUptoBar);
}
void CBar::setLoopingBars(double bars)
{
if (bars < 0.0)
bars = 0;
m_loopingBars = bars;
m_playUptoBar = m_playFromBar + m_loopingBars;
setupEnableFlags();
checkGotoBar();
}
pianobooster-src-0.6.4b/src/GuiHighScoreWindow.ui 0000644 0001747 0001747 00000002550 11113115032 021442 0 ustar ubuntu ubuntu
GuiPreferences
0
0
578
399
Form
-
High Scores
-
-
-
-
Your Name:
-
-
Qt::Horizontal
40
20
pianobooster-src-0.6.4b/src/GlView.h 0000644 0001747 0001747 00000004661 11303577704 016771 0 ustar ubuntu ubuntu /*********************************************************************************/
/*!
@file GlView.h
@brief xxx
@author L. J. Barman
Copyright (c) 2008-2009, L. J. Barman, all rights reserved
This file is part of the PianoBooster application
PianoBooster 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.
PianoBooster 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 PianoBooster. If not, see .
*/
/*********************************************************************************/
#ifndef __GLVIEW_H__
#define __GLVIEW_H__
#include
#include
#include
#include "Song.h"
#include "Score.h"
#include "Settings.h"
//#include "rtmidi/RtTimer.h"
class Window;
class CGLView : public QGLWidget//, RtTimer
{
Q_OBJECT
public:
CGLView(QtWindow *parent, CSettings* settings);
~CGLView();
QSize minimumSizeHint() const;
QSize sizeHint() const;
CSong* getSongObject() {return m_song;}
CScore* getScoreObject() {return m_score;}
void init();
bool m_cfg_openGlOptimise;
protected:
void timerEvent(QTimerEvent *event);
void mediaTimerEvent(int ticks);
void initializeGL();
void paintGL();
void resizeGL(int width, int height);
void mousePressEvent(QMouseEvent *event);
void mouseMoveEvent(QMouseEvent *event);
private:
void drawDisplayText();
void drawTimeSignature();
void drawAccurracyBar();
void drawBarNumber();
void updateMidiTask();
QColor m_backgroundColour;
QtWindow* m_qtWindow; // The parent Window
CSettings* m_settings;
CSong* m_song;
CScore* m_score;
QBasicTimer m_timer;
QTime m_realtime;
int m_displayUpdateTicks;
CRating* m_rating;
QFont m_timeSigFont;
QFont m_timeRatingFont;
bool m_fullRedrawFlag;
int m_forcefullRedraw;
int m_forceRatingRedraw;
int m_forceBarRedraw;
int m_titleHeight;
eventBits_t m_eventBits;
};
#endif // __GLVIEW_H__
pianobooster-src-0.6.4b/src/Merge.cpp 0000644 0001747 0001747 00000005617 11241352764 017166 0 ustar ubuntu ubuntu /*********************************************************************************/
/*!
@file Merge.cpp
@brief Merge Midi Events from multiple streams into a single stream.
@author L. J. Barman
Copyright (c) 2008-2009, L. J. Barman, all rights reserved
This file is part of the PianoBooster application
PianoBooster 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.
PianoBooster 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 PianoBooster. If not, see .
*/
/////////////////////////////////////////////////////////////////////////////
#include "Merge.h"
void CMerge::initMergedEvents()
{
int i;
for( i = 0; i < m_mergeEvents.size(); i++)
{
m_mergeEvents[i].clear();
if (checkMidiEventFromStream(i) )
m_mergeEvents[i] = fetchMidiEventFromStream(i);
}
}
int CMerge::nextMergedEvent()
{
int nearestIndex = 0;
int i;
CMidiEvent* nearestEvent;
int deltaTime;
nearestEvent = 0;
// find the first active slot
for( i = 0; i < m_mergeEvents.size(); i++)
{
if (m_mergeEvents[i].type() != MIDI_NONE)
{
nearestEvent = &m_mergeEvents[i];
nearestIndex = i;
break;
}
}
if (nearestEvent == 0)
return 0;
// now search the remaining active slots
for( i = nearestIndex + 1; i < m_mergeEvents.size(); i++)
{
if (m_mergeEvents[i].type() != MIDI_NONE)
{
// find the slot with the lowest delta time
if (m_mergeEvents[i].deltaTime() < nearestEvent->deltaTime())
{
nearestEvent = &m_mergeEvents[i];
nearestIndex = i;
}
}
}
deltaTime = -nearestEvent->deltaTime();
// Now subtract the delta time from all the others
for( i = 0; i < m_mergeEvents.size(); i++)
{
if (i == nearestIndex)
continue;
if (m_mergeEvents[i].type() != MIDI_NONE)
m_mergeEvents[i].addDeltaTime( deltaTime );
}
return nearestIndex;
}
CMidiEvent CMerge::readMidiEvent()
{
int mergeIdx;
CMidiEvent event;
mergeIdx = nextMergedEvent();
event = m_mergeEvents[mergeIdx];
m_mergeEvents[mergeIdx].clear();
if (checkMidiEventFromStream(mergeIdx) )
m_mergeEvents[mergeIdx] = fetchMidiEventFromStream(mergeIdx);
if (event.type() == MIDI_NONE)
event.setType(MIDI_PB_EOF);
return event;
}
pianobooster-src-0.6.4b/src/GuiMidiSetupDialog.h 0000644 0001747 0001747 00000003613 11303063627 021252 0 ustar ubuntu ubuntu /*********************************************************************************/
/*!
@file GuiMidiSetupDialog.h
@brief xxxx.
@author L. J. Barman
Copyright (c) 2008-2009, L. J. Barman, all rights reserved
This file is part of the PianoBooster application
PianoBooster 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.
PianoBooster 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 PianoBooster. If not, see .
*/
/*********************************************************************************/
#ifndef __GUIMIDISETUPDIALOG_H__
#define __GUIMIDISETUPDIALOG_H__
#include
#include "Song.h"
#include "Settings.h"
#include "ui_GuiMidiSetupDialog.h"
class GuiMidiSetupDialog : public QDialog, private Ui::GuiMidiSettingsDialog
{
Q_OBJECT
public:
GuiMidiSetupDialog(QWidget *parent = 0);
void init(CSong* song, CSettings* settings);
private slots:
void accept();
void on_midiInputCombo_activated (int index);
void on_midiOutputCombo_activated (int index);
void on_latencyFixButton_clicked ( bool checked );
void on_fluidAddButton_clicked ( bool checked );
void on_fluidRemoveButton_clicked ( bool checked );
private:
void updateMidiInfoText();
void updateFluidInfoText();
CSettings* m_settings;
CSong* m_song;
int m_latencyFix;
bool m_latencyChanged;
bool m_midiChanged;
};
#endif //__GUIMIDISETUPDIALOG_H__
pianobooster-src-0.6.4b/src/Draw.cpp 0000644 0001747 0001747 00000062402 11301345653 017013 0 ustar ubuntu ubuntu /*********************************************************************************/
/*!
@file Draw.cpp
@brief xxxxx.
@author L. J. Barman
Copyright (c) 2008-2009, L. J. Barman, all rights reserved
This file is part of the PianoBooster application
PianoBooster 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.
PianoBooster 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 PianoBooster. If not, see .
*/
/*********************************************************************************/
#include "Draw.h"
#include "Cfg.h"
#include "Settings.h"
typedef unsigned int guint;
typedef unsigned char guint8;
whichPart_t CDraw::m_displayHand;
int CDraw::m_forceCompileRedraw;
void CDraw::oneLine(float x1, float y1, float x2, float y2)
{
glBegin(GL_LINES);
glVertex2f ((x1),(y1));
glVertex2f ((x2),(y2));
glEnd();
//ppLogTrace("oneLine %f %f %f %f", x1, y1, x2, y2);
}
void CDraw::drawStaveExtentsion(CSymbol symbol, float x, int noteWidth, bool playable)
{
int index;
index = symbol.getStavePos().getStaveIndex();
if (index < 6 && index > -6)
return;
index = index & ~1; // Force index to be even
whichPart_t hand = symbol.getStavePos().getHand();
if (playable)
drColour(Cfg::staveColour());
else
drColour(Cfg::staveColourDim());
glLineWidth (Cfg::staveThickness());
glBegin(GL_LINES);
while (index >= 6 || index <= -6)
{
glVertex2f (x - noteWidth/2 - 4, CStavePos(hand, index).getPosYRelative());
glVertex2f (x + noteWidth/2 + 4, CStavePos(hand, index).getPosYRelative());
// Move the index closer to the stave centre
if (index > 0)
index -= 2;
else
index += 2;
}
glEnd();
}
#define scaleGlVertex(xa, xb, ya, yb) glVertex2f( ((xa) * 1.2) + (xb), ((ya) * 1.2) + (yb))
void CDraw::drawNoteName(int midiNote, float x, float y, int type)
{
// Ignore note that are too high
if (midiNote > MIDI_TOP_C + 6)
return;
staveLookup_t item = CStavePos::midiNote2Name(midiNote);
drColour(Cfg::noteNameColour());
glLineWidth (1.0);
if (item.accidental != 0)
{
const float accidentalOffset = 10;
x += accidentalOffset/2;
if (item.accidental == 1)
{
glBegin(GL_LINES);
// letterSharp4
scaleGlVertex( -1.317895, x, 5.794585, y); // 1
scaleGlVertex( -1.265845, x, -6.492455, y); // 2
scaleGlVertex( 1.252305, x, 6.492455, y); // 3
scaleGlVertex( 1.322655, x, -5.422335, y); // 4
scaleGlVertex( -2.645765, x, 1.967805, y); // 5
scaleGlVertex( 2.648325, x, 3.625485, y); // 6
scaleGlVertex( -2.648325, x, -3.306965, y); // 7
scaleGlVertex( 2.596205, x, -1.675765, y); // 8
glEnd();
}
else
{
glBegin(GL_LINE_STRIP);
// letterFlat
scaleGlVertex( -2.52933, x, 6.25291, y); // 1
scaleGlVertex( -2.50344, x, -6.25291, y); // 2
scaleGlVertex( 0.76991, x, -3.63422, y); // 3
scaleGlVertex( 2.07925, x, -1.67021, y); // 4
scaleGlVertex( 2.52933, x, 0.25288, y); // 5
scaleGlVertex( 1.42458, x, 1.07122, y); // 6
scaleGlVertex( -0.53943, x, 0.90755, y); // 7
scaleGlVertex( -2.46252, x, -1.01554, y); // 8
scaleGlVertex( -2.50344, x, -1.67021, y); // 9
glEnd();
}
x -= accidentalOffset;
}
switch(item.pianoNote)
{
case 1:
glBegin(GL_LINE_STRIP);
// letterC
scaleGlVertex( 3.513445, x, 2.17485, y); // 1
scaleGlVertex( 1.880175, x, 4.47041, y); // 2
scaleGlVertex( -1.598825, x, 4.4321, y); // 3
scaleGlVertex( -3.692215, x, 2.26571, y); // 4
scaleGlVertex( -3.702055, x, -1.88958, y); // 5
scaleGlVertex( -1.630675, x, -4.47041, y); // 6
scaleGlVertex( 1.932545, x, -4.44064, y); // 7
scaleGlVertex( 3.702055, x, -1.88554, y); // 8
glEnd();
break;
case 2:
glBegin(GL_LINE_STRIP);
// letterD
scaleGlVertex( -3.30696, x, 4.31878, y); // 1
scaleGlVertex( -3.3428, x, -4.31878, y); // 2
scaleGlVertex( 0.9425, x, -4.28164, y); // 3
scaleGlVertex( 3.31415, x, -1.42302, y); // 4
scaleGlVertex( 3.3428, x, 1.66626, y); // 5
scaleGlVertex( 0.70825, x, 4.31317, y); // 6
scaleGlVertex( -3.22083, x, 4.29495, y); // 7
glEnd();
break;
case 3: // E
glBegin(GL_LINE_STRIP);
// letterE2
scaleGlVertex( 2.966065, x, 4.416055, y); // 1
scaleGlVertex( -3.007275, x, 4.403495, y); // 2
scaleGlVertex( -3.037615, x, -4.416055, y); // 3
scaleGlVertex( 3.037615, x, -4.415435, y); // 4
glEnd();
glBegin(GL_LINES);
scaleGlVertex( 3.011705, x, 0.197675, y); // 5
scaleGlVertex( -2.990845, x, 0.196615, y); // 6
glEnd();
break;
case 4: // F
glBegin(GL_LINE_STRIP);
// letterF2
scaleGlVertex( -2.55172, x, -4.434285, y); // 1
scaleGlVertex( -2.51956, x, 4.433665, y); // 2
scaleGlVertex( 2.39942, x, 4.434285, y); // 3
glEnd();
glBegin(GL_LINES);
scaleGlVertex( 2.58143, x, 0.244465, y); // 4
scaleGlVertex( -2.58143, x, 0.243405, y); // 5
glEnd();
break;
case 5:
glBegin(GL_LINE_STRIP);
// letterG
scaleGlVertex( 0.58123, x, -0.34005, y); // 1
scaleGlVertex( 3.66047, x, -0.48722, y); // 2
scaleGlVertex( 3.70461, x, -3.23595, y); // 3
scaleGlVertex( 1.96234, x, -4.41694, y); // 4
scaleGlVertex( -0.96712, x, -4.57846, y); // 5
scaleGlVertex( -3.70461, x, -2.29011, y); // 6
scaleGlVertex( -3.67245, x, 2.14034, y); // 7
scaleGlVertex( -1.25347, x, 4.57846, y); // 8
scaleGlVertex( 1.90018, x, 4.55293, y); // 9
scaleGlVertex( 3.54236, x, 2.38612, y); // 10
glEnd();
break;
case 6: // A
glBegin(GL_LINE_STRIP);
// letterA2
scaleGlVertex( -3.91146, x, -4.907395, y); // 1
scaleGlVertex( 0.06571, x, 4.907395, y); // 2
scaleGlVertex( 3.91146, x, -4.803315, y); // 3
glEnd();
glBegin(GL_LINES);
scaleGlVertex( 2.60111, x, -1.400435, y); // 4
scaleGlVertex( -2.56175, x, -1.357305, y); // 5
glEnd();
break;
case 7:
glBegin(GL_LINE_STRIP);
// letterB
scaleGlVertex( 1.038555, x, 0.105285, y); // 1
scaleGlVertex( -3.001935, x, 0.121925, y); // 2
scaleGlVertex( -3.027615, x, 4.417905, y); // 3
scaleGlVertex( 1.325925, x, 4.451255, y); // 4
scaleGlVertex( 2.737985, x, 3.048615, y); // 5
scaleGlVertex( 2.721765, x, 1.366235, y); // 6
scaleGlVertex( 1.022635, x, 0.120235, y); // 7
scaleGlVertex( 3.026015, x, -1.282295, y); // 8
scaleGlVertex( 3.027615, x, -3.046285, y); // 9
scaleGlVertex( 1.176815, x, -4.451255, y); // 10
scaleGlVertex( -2.981475, x, -4.445735, y); // 11
scaleGlVertex( -3.021355, x, 0.176035, y); // 12
glEnd();
break;
default:
glBegin(GL_LINES);
glVertex2f( 3 + x, -15 + y); // 1
glVertex2f( 3 + x, 8 + y); // 2
glVertex2f( -3 + x, -8 + y); // 3
glVertex2f( -3 + x, 15 + y); // 4
glVertex2f( 3 + x, 8 + y); // 5
glVertex2f( -3 + x, 2 + y); // 6
glVertex2f( 3 + x, -2 + y); // 7
glVertex2f( -3 + x, -8 + y); // 8
glEnd();
break;
}
}
void CDraw::drawStaveNoteName(CSymbol symbol, float x, float y)
{
if ( symbol.getNoteIndex() + 1 != symbol.getNoteTotal())
return;
if (m_settings->showNoteNames() == false)
return;
y += CStavePos::getVerticalNoteSpacing()*2 +3;
drawNoteName(symbol.getNote(), x, y, true);
}
void CDraw::checkAccidental(CSymbol symbol, float x, float y)
{
int accidental;
const int xGap = 16;
accidental = symbol.getStavePos().getAccidental();
if (symbol.getAccidentalModifer() == PB_ACCIDENTAL_MODIFER_suppress)
accidental = 0; // Suppress the accidental if it is the same bar
if (symbol.getAccidentalModifer() == PB_ACCIDENTAL_MODIFER_force)
{
// Force the display of an accidental including naturals if it is the same bar
accidental = CStavePos::midiNote2Name(symbol.getNote()).accidental;
if (accidental == 0)
accidental = 2;
}
if (accidental != 0)
{
//drColour (Cfg::lineColour());
if (accidental == 1)
drawSymbol(CSymbol(PB_SYMBOL_sharp, symbol.getStavePos()), x - xGap, y);
else if (accidental == -1)
drawSymbol(CSymbol(PB_SYMBOL_flat, symbol.getStavePos()), x - xGap, y);
else
drawSymbol(CSymbol(PB_SYMBOL_natural, symbol.getStavePos()), x - xGap, y);
}
}
void CDraw::drawSymbol(CSymbol symbol, float x, float y)
{
CColour colour = symbol.getColour();
bool playable = true;
if (m_displayHand != symbol.getHand() && m_displayHand != PB_PART_both)
{
if (colour == Cfg::noteColour())
colour = Cfg::noteColourDim();
if (colour == Cfg::staveColour())
colour = Cfg::staveColourDim();
playable = false;
}
switch (symbol.getType())
{
case PB_SYMBOL_gClef: // The Treble Clef
y += 4;
drColour(colour);
glLineWidth (3.0);
glBegin(GL_LINE_STRIP);
glVertex2f( -0.011922 + x, -16.11494 + y); // 1
glVertex2f( -3.761922 + x, -12.48994 + y); // 2
glVertex2f( -4.859633 + x, -8.85196 + y); // 3
glVertex2f( -4.783288 + x, -5.42815 + y); // 4
glVertex2f( -0.606711 + x, -1.11108 + y); // 5
glVertex2f( 5.355545 + x, 0.48711 + y); // 6
glVertex2f( 10.641104 + x, -1.6473 + y); // 7
glVertex2f( 14.293812 + x, -6.18241 + y); // 8
glVertex2f( 14.675578 + x, -11.42744 + y); // 9
glVertex2f( 12.550578 + x, -17.30244 + y); // 10
glVertex2f( 7.912166 + x, -20.944 + y); // 11
glVertex2f( 3.049705 + x, -21.65755 + y); // 12
glVertex2f( -1.711005 + x, -21.36664 + y); // 13
glVertex2f( -6.283661 + x, -19.66739 + y); // 14
glVertex2f( -10.123329 + x, -16.79162 + y); // 15
glVertex2f( -13.363008 + x, -12.28184 + y); // 16
glVertex2f( -14.675578 + x, -5.79969 + y); // 17
glVertex2f( -13.66821 + x, 0.20179 + y); // 18
glVertex2f( -10.385341 + x, 6.27562 + y); // 19
glVertex2f( 5.539491 + x, 20.32671 + y); // 20
glVertex2f( 10.431588 + x, 28.20584 + y); // 21
glVertex2f( 11.00141 + x, 34.71585 + y); // 22
glVertex2f( 9.204915 + x, 39.62875 + y); // 23
glVertex2f( 7.854166 + x, 42.08262 + y); // 24
glVertex2f( 5.481415 + x, 42.66649 + y); // 25
glVertex2f( 3.57972 + x, 41.4147 + y); // 26
glVertex2f( 1.507889 + x, 37.35642 + y); // 27
glVertex2f( -0.381338 + x, 31.14317 + y); // 28
glVertex2f( -0.664306 + x, 25.51354 + y); // 29
glVertex2f( 8.296044 + x, -32.22694 + y); // 30
glVertex2f( 8.050507 + x, -36.6687 + y); // 31
glVertex2f( 6.496615 + x, -39.52999 + y); // 32
glVertex2f( 3.368583 + x, -41.7968 + y); // 33
glVertex2f( 0.253766 + x, -42.66649 + y); // 34
glVertex2f( -3.599633 + x, -42.23514 + y); // 35
glVertex2f( -8.098754 + x, -39.46637 + y); // 36
glVertex2f( -9.463279 + x, -35.49796 + y); // 37
glVertex2f( -7.08037 + x, -31.36512 + y); // 38
glVertex2f( -3.336421 + x, -31.14057 + y); // 39
glVertex2f( -1.360313 + x, -34.07738 + y); // 40
glVertex2f( -1.608342 + x, -37.11828 + y); // 41
glVertex2f( -5.729949 + x, -39.24759 + y); // 42
glVertex2f( -7.480646 + x, -36.2136 + y); // 43
glVertex2f( -6.826918 + x, -33.36919 + y); // 44
glVertex2f( -4.069083 + x, -32.9226 + y); // 45
glVertex2f( -3.040669 + x, -34.433 + y); // 46
glVertex2f( -3.737535 + x, -36.38759 + y); // 47
glVertex2f( -5.496558 + x, -36.97633 + y); // 48
glVertex2f( -5.295932 + x, -34.01951 + y); // 49
glEnd();
break;
case PB_SYMBOL_fClef: // The Base Clef
drColour(colour);
glLineWidth (3.0);
glBegin(GL_LINE_STRIP);
glVertex2f( -15.370325 + x, -17.42068 + y); // 1
glVertex2f( -7.171025 + x, -13.75432 + y); // 2
glVertex2f( -2.867225 + x, -10.66642 + y); // 3
glVertex2f( 0.925165 + x, -7.03249 + y); // 4
glVertex2f( 4.254425 + x, -0.65527 + y); // 5
glVertex2f( 4.762735 + x, 7.77848 + y); // 6
glVertex2f( 2.693395 + x, 13.92227 + y); // 7
glVertex2f( -1.207935 + x, 16.80317 + y); // 8
glVertex2f( -5.526425 + x, 17.42068 + y); // 9
glVertex2f( -10.228205 + x, 15.65609 + y); // 10
glVertex2f( -13.453995 + x, 10.7128 + y); // 11
glVertex2f( -13.133655 + x, 5.43731 + y); // 12
glVertex2f( -9.475575 + x, 3.00714 + y); // 13
glVertex2f( -5.846445 + x, 4.72159 + y); // 14
glVertex2f( -5.395545 + x, 9.72918 + y); // 15
glVertex2f( -8.850025 + x, 11.64372 + y); // 16
glVertex2f( -11.519385 + x, 10.35816 + y); // 17
glVertex2f( -11.706365 + x, 6.8704 + y); // 18
glVertex2f( -9.463505 + x, 5.01391 + y); // 19
glVertex2f( -7.172075 + x, 5.81649 + y); // 20
glVertex2f( -7.189565 + x, 8.62975 + y); // 21
glVertex2f( -9.175055 + x, 9.82019 + y); // 22
glVertex2f( -10.696425 + x, 8.08395 + y); // 23
glVertex2f( -8.843065 + x, 6.66726 + y); // 24
glVertex2f( -8.995775 + x, 8.71136 + y); // 25
glEnd();
glBegin(GL_POLYGON);
glVertex2f( 10 + x, 14 + y); // 26
glVertex2f( 14 + x, 14 + y); // 27
glVertex2f( 14 + x, 10 + y); // 28
glVertex2f( 10 + x, 10 + y); // 29
glVertex2f( 10 + x, 14 + y); // 30
glEnd();
glBegin(GL_POLYGON);
glVertex2f( 10 + x, 4 + y); // 31
glVertex2f( 14 + x, 4 + y); // 32
glVertex2f( 14 + x, 0 + y); // 33
glVertex2f( 10 + x, 0 + y); // 34
glVertex2f( 10 + x, 4 + y); // 35
glEnd();
break;
case PB_SYMBOL_note:
//ppLogTrace("PB_SYMBOL_note x %f y %f", x, y);
if (!CChord::isNotePlayable(symbol.getNote(), 0))
{
colour = Cfg::noteColourDim();
playable = false;
}
drawStaveExtentsion(symbol, x, 16, playable);
drColour(colour);
glBegin(GL_POLYGON);
glVertex2f(-7.0 + x, 2.0 + y); // 1
glVertex2f(-5.0 + x, 4.0 + y); // 2
glVertex2f(-1.0 + x, 6.0 + y); // 3
glVertex2f( 4.0 + x, 6.0 + y); // 4
glVertex2f( 7.0 + x, 4.0 + y); // 5
glVertex2f( 7.0 + x, 1.0 + y); // 6
glVertex2f( 6.0 + x, -2.0 + y); // 7
glVertex2f( 4.0 + x, -4.0 + y); // 8
glVertex2f( 0.0 + x, -6.0 + y); // 9
glVertex2f(-4.0 + x, -6.0 + y); // 10
glVertex2f(-8.0 + x, -3.0 + y); // 11
glVertex2f(-8.0 + x, -0.0 + y); // 12
glEnd();
checkAccidental(symbol, x, y);
break;
case PB_SYMBOL_drum:
if (!CChord::isNotePlayable(symbol.getNote(), 0))
colour = Cfg::noteColourDim();
drColour(colour);
glLineWidth (3.0);
glBegin(GL_LINES);
glVertex2f( 5.0 + x,-5.0 + y);
glVertex2f(-5.0 + x, 5.0 + y);
glVertex2f(-5.0 + x,-5.0 + y);
glVertex2f( 5.0 + x, 5.0 + y);
glEnd();
checkAccidental(symbol, x, y);
break;
case PB_SYMBOL_sharp:
glLineWidth (2.0);
glBegin(GL_LINES);
glVertex2f(-2.0 + x, -14.0 + y);
glVertex2f(-2.0 + x, 14.0 + y);
glVertex2f( 2.0 + x, -13.0 + y);
glVertex2f( 2.0 + x, 15.0 + y);
glVertex2f(-5.0 + x, 4.0 + y);
glVertex2f( 5.0 + x, 7.0 + y);
glVertex2f(-5.0 + x, -6.0 + y);
glVertex2f( 5.0 + x, -3.0 + y);
glEnd();
break;
case PB_SYMBOL_flat:
glLineWidth (2.0);
glBegin(GL_LINE_STRIP);
glVertex2f(-4.0 + x, 17.0 + y); // 1
glVertex2f(-4.0 + x, -6.0 + y); // 2
glVertex2f( 2.0 + x, -2.0 + y); // 3
glVertex2f( 5.0 + x, 2.0 + y); // 4
glVertex2f( 5.0 + x, 4.0 + y); // 5
glVertex2f( 3.0 + x, 5.0 + y); // 6
glVertex2f( 0.0 + x, 5.0 + y); // 7
glVertex2f(-4.0 + x, 2.0 + y); // 8
glEnd();
break;
case PB_SYMBOL_natural:
glLineWidth (2.0);
glBegin(GL_LINES);
glVertex2f( 3 + x, -15 + y); // 1
glVertex2f( 3 + x, 8 + y); // 2
glVertex2f( -3 + x, -8 + y); // 3
glVertex2f( -3 + x, 15 + y); // 4
glVertex2f( 3 + x, 8 + y); // 5
glVertex2f( -3 + x, 2 + y); // 6
glVertex2f( 3 + x, -2 + y); // 7
glVertex2f( -3 + x, -8 + y); // 8
glEnd();
break;
case PB_SYMBOL_barLine:
x += BEAT_MARKER_OFFSET * HORIZONTAL_SPACING_FACTOR; // the beat markers where entered early so now move them correctly
glLineWidth (4.0);
drColour ((m_displayHand == PB_PART_left) ? Cfg::staveColourDim() : Cfg::staveColour());
oneLine(x, CStavePos(PB_PART_right, 4).getPosYRelative(), x, CStavePos(PB_PART_right, -4).getPosYRelative());
drColour ((m_displayHand == PB_PART_right) ? Cfg::staveColourDim() : Cfg::staveColour());
oneLine(x, CStavePos(PB_PART_left, 4).getPosYRelative(), x, CStavePos(PB_PART_left, -4).getPosYRelative());
break;
case PB_SYMBOL_barMarker:
x += BEAT_MARKER_OFFSET * HORIZONTAL_SPACING_FACTOR; // the beat markers where entered early so now move them correctly
glLineWidth (5.0);
drColour(Cfg::barMarkerColour());
oneLine(x, CStavePos(PB_PART_right, m_beatMarkerHeight).getPosYRelative(), x, CStavePos(PB_PART_left, -m_beatMarkerHeight).getPosYRelative());
glDisable (GL_LINE_STIPPLE);
break;
case PB_SYMBOL_beatMarker:
x += BEAT_MARKER_OFFSET * HORIZONTAL_SPACING_FACTOR; // the beat markers where entered early so now move them correctly
glLineWidth (4.0);
drColour(Cfg::beatMarkerColour());
oneLine(x, CStavePos(PB_PART_right, m_beatMarkerHeight).getPosYRelative(), x, CStavePos(PB_PART_left, -m_beatMarkerHeight).getPosYRelative());
glDisable (GL_LINE_STIPPLE);
break;
case PB_SYMBOL_playingZone:
{
float topY = CStavePos(PB_PART_right, m_beatMarkerHeight).getPosY();
float bottomY = CStavePos(PB_PART_left, -m_beatMarkerHeight).getPosY();
float early = Cfg::playZoneEarly() * HORIZONTAL_SPACING_FACTOR;
float late = Cfg::playZoneLate() * HORIZONTAL_SPACING_FACTOR;
//glColor3f (0.7, 1.0, 0.7);
glColor3f (0.0, 0.0, 0.3);
glRectf(x-late, topY, x + early, bottomY);
glLineWidth (2.0);
glColor3f (0.0, 0.0, 0.8);
oneLine(x, topY, x, bottomY );
glLineWidth (1.0);
glColor3f (0.0, 0.0, 0.6);
oneLine(x-late, topY, x-late, bottomY );
oneLine(x+early, topY, x+early, bottomY );
}
break;
default:
ppDEBUG(("ERROR drawSymbol unhandled symbol\n"));
break;
}
if (symbol.getType() == PB_SYMBOL_note)
{
float pianistX = symbol.getPianistTiming();
if ( pianistX != NOT_USED)
{
pianistX = x + pianistX * HORIZONTAL_SPACING_FACTOR;
drColour(CColour(1.0, 1.0, 1.0));
glLineWidth (2.0);
glBegin(GL_LINES);
glVertex2f( 4.0 + pianistX, 4.0 + y);
glVertex2f(-5.0 + pianistX,-5.0 + y);
glVertex2f( 4.0 + pianistX,-4.0 + y); // draw pianist note timing markers
glVertex2f(-5.0 + pianistX, 5.0 + y);
glEnd();
}
if ( playable )
drawStaveNoteName(symbol, x, y);
}
}
void CDraw::drawSymbol(CSymbol symbol, float x)
{
drawSymbol(symbol, x, symbol.getStavePos().getPosY());
}
void CDraw::drawStaves(float startX, float endX)
{
int i;
glLineWidth (Cfg::staveThickness());
/* select colour for all lines */
drColour ((m_displayHand != PB_PART_left) ? Cfg::staveColour() : Cfg::staveColourDim());
glBegin(GL_LINES);
for (i = -4; i <= 4; i+=2 )
{
CStavePos pos = CStavePos(PB_PART_right, i);
glVertex2f (startX, pos.getPosY());
glVertex2f (endX, pos.getPosY());
}
drColour ((m_displayHand != PB_PART_right) ? Cfg::staveColour() : Cfg::staveColourDim());
for (i = -4; i <= 4; i+=2 )
{
CStavePos pos = CStavePos(PB_PART_left, i);
glVertex2f (startX, pos.getPosY());
glVertex2f (endX, pos.getPosY());
}
glEnd();
}
void CDraw::drawKeySignature(int key)
{
const int sharpLookUpRight[] = { 4, 1, 5, 2,-1, 3, 0};
const int sharpLookUpLeft[] = { 2,-1, 3, 0,-3, 1,-2};
const int flatLookUpRight[] = { 0, 3,-1, 2,-2, 1,-3};
const int flatLookUpLeft[] = {-2, 1,-3, 0,-4,-1,-5};
const int gapX = 11;
CStavePos pos;
size_t i;
if (key == NOT_USED)
return;
i = 0;
while (key != 0 )
{
if (key > 0)
{
if (i < arraySize(sharpLookUpRight))
{
drColour ((m_displayHand != PB_PART_left) ? Cfg::noteColour() : Cfg::noteColourDim());
pos = CStavePos(PB_PART_right, sharpLookUpRight[i]);
drawSymbol( CSymbol(PB_SYMBOL_sharp, pos), Cfg::keySignatureX() + gapX*i );
}
if (i < arraySize(sharpLookUpLeft))
{
drColour ((m_displayHand != PB_PART_right) ? Cfg::noteColour() : Cfg::noteColourDim());
pos = CStavePos(PB_PART_left, sharpLookUpLeft[i]);
drawSymbol( CSymbol(PB_SYMBOL_sharp, pos), Cfg::keySignatureX() + gapX*i );
}
key--;
}
else
{
if (i < arraySize(flatLookUpRight))
{
drColour ((m_displayHand != PB_PART_left) ? Cfg::noteColour() : Cfg::noteColourDim());
pos = CStavePos(PB_PART_right, flatLookUpRight[i]);
drawSymbol( CSymbol(PB_SYMBOL_flat, pos), Cfg::keySignatureX() + gapX*i );
}
if (i < arraySize(flatLookUpLeft))
{
drColour ((m_displayHand != PB_PART_right) ? Cfg::noteColour() : Cfg::noteColourDim());
pos = CStavePos(PB_PART_left, flatLookUpLeft[i]);
drawSymbol( CSymbol(PB_SYMBOL_flat, pos), Cfg::keySignatureX() + gapX*i );
}
key++;
}
i++;
}
}
pianobooster-src-0.6.4b/src/GuiTopBar.cpp 0000644 0001747 0001747 00000015400 11277632044 017753 0 ustar ubuntu ubuntu /*********************************************************************************/
/*!
@file GuiTopBar.cpp
@brief xxxx.
@author L. J. Barman
Copyright (c) 2008-2009, L. J. Barman, all rights reserved
This file is part of the PianoBooster application
PianoBooster 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.
PianoBooster 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 PianoBooster. If not, see .
*/
/*********************************************************************************/
#include
#include "GuiTopBar.h"
#include "TrackList.h"
#include "GuiLoopingPopup.h"
GuiTopBar::GuiTopBar(QWidget *parent, CSettings* settings)
: QWidget(parent), m_settings(settings)
{
m_atTheEndOfTheSong = false;
m_song = 0;
setupUi(this);
parent->installEventFilter(this);
speedSpin->setMaximum(200);
speedSpin->setMinimum(20);
speedSpin->setSuffix(" %");
speedSpin->setSingleStep(2);
speedSpin->setValue(100);
transposeSpin->setMaximum(12);
transposeSpin->setMinimum(-12);
majorCombo->addItem("Major");
majorCombo->addItem("Minor");
setMaximumHeight(30);
setMaximumSize(QSize(16777215, 30));
}
void GuiTopBar::init(CSong* songObj, CTrackList* trackList)
{
m_song = songObj;
reloadKeyCombo(true);
}
void GuiTopBar::refresh(bool reset)
{
if (reset == true)
{
majorCombo->setCurrentIndex(0);
reloadKeyCombo(true);
transposeSpin->setValue(0);
startBarSpin->setValue(0);
}
int index = 0;
if (m_song)
index = CStavePos::getKeySignature() + 6;
if (index >= 0 && index < keyCombo->count())
keyCombo->setCurrentIndex(index);
}
void GuiTopBar::reloadKeyCombo(bool major)
{
keyCombo->clear();
if (major)
{
keyCombo->addItem("Gb"); // -6
keyCombo->addItem("Db"); // -5
keyCombo->addItem("Ab"); // -4
keyCombo->addItem("Eb"); // -3
keyCombo->addItem("Bb"); // -2
keyCombo->addItem("F "); // -1
keyCombo->addItem("C"); // 0
keyCombo->addItem("G "); // 1
keyCombo->addItem("D "); // 2
keyCombo->addItem("A "); // 3
keyCombo->addItem("E "); // 4
keyCombo->addItem("B "); // 5
keyCombo->addItem("F#"); // 6
}
else
{
keyCombo->addItem("Eb");
keyCombo->addItem("Bb");
keyCombo->addItem("F");
keyCombo->addItem("C");
keyCombo->addItem("G");
keyCombo->addItem("D ");
keyCombo->addItem("A");
keyCombo->addItem("E ");
keyCombo->addItem("B ");
keyCombo->addItem("F#");
keyCombo->addItem("G#");
keyCombo->addItem("C#");
keyCombo->addItem("D#");
}
refresh(false);
}
void GuiTopBar::on_keyCombo_activated(int index)
{
CStavePos::setKeySignature(index - 6, 0);
m_song->refreshScroll();
}
void GuiTopBar::on_transposeSpin_valueChanged(int value)
{
unsigned int i; //C Db D Eb E F F# G Ab A Bb B
const int nextKey[] = { 0, -5, 2, -3, 4, -1, 6, 1, -4, 3, -2, 5};
if (!m_song) return;
int diff = value - m_song->getTranspose();
int oldValue = CStavePos::getKeySignature();
if (oldValue == -6)
oldValue = 6; // if key is Eb change to D#
// Find the old value in the table
for (i=0; i < arraySize(nextKey); i++)
{
if (oldValue == nextKey[i])
break;
}
int newValue = nextKey[(diff + i + arraySize(nextKey)) % arraySize(nextKey) ];
CStavePos::setKeySignature( newValue, 0 );
newValue += 6;
keyCombo->setCurrentIndex(newValue);
if (newValue >= 0 && newValue < keyCombo->count())
keyCombo->setCurrentIndex(newValue);
m_song->transpose(value);
m_song->forceScoreRedraw();
}
void GuiTopBar::setPlayButtonState(bool checked, bool atTheEnd)
{
if (atTheEnd)
m_atTheEndOfTheSong = true;
playButton->setChecked(checked);
if (checked)
{
playButton->setIcon(QIcon(":/images/stop.png"));
playButton->setToolTip("");
playFromStartButton->setToolTip("");
}
else
{
playButton->setIcon(QIcon(":/images/play.png"));
playButton->setToolTip("Start and stop playing music");
playFromStartButton->setToolTip("Playing music from the beginning");
}
}
void GuiTopBar::on_playButton_clicked(bool clicked)
{
if (!m_song) return;
if (m_atTheEndOfTheSong)
m_song->rewind();
m_atTheEndOfTheSong = false;
bool start = !m_song->playingMusic();
m_song->playMusic(start);
setPlayButtonState(start);
}
void GuiTopBar::on_playFromStartButton_clicked(bool clicked)
{
if (!m_song) return;
m_atTheEndOfTheSong = false;
m_song->playFromStartBar();
setPlayButtonState(true);
}
void GuiTopBar::on_speedSpin_valueChanged(int speed)
{
if (!m_song) return;
m_song->setSpeed(speed/100.0);
}
void GuiTopBar::on_startBarSpin_valueChanged(double bar)
{
if (!m_song) return;
// Stop the muisc playing
m_song->playMusic(false);
setPlayButtonState(false);
m_song->setPlayFromBar( bar);
}
void GuiTopBar::on_saveBarButton_clicked(bool clicked)
{
if (!m_song) return;
double barNumber = m_song->getCurrentBarPos();
startBarSpin->setValue(barNumber);
}
void GuiTopBar::on_loopingBarsPopupButton_clicked(bool clicked)
{
if (!m_song) return;
m_song->playMusic(false);
setPlayButtonState(false);
QPoint pos = mapToGlobal(loopingBarsPopupButton->pos()) ;
pos.ry() += loopingBarsPopupButton->height() + 2;
pos.rx() += -5; // Tweak the position slightly
GuiLoopingPopup *loopingPopup = new GuiLoopingPopup(loopingBarsPopupButton);
loopingPopup->init(m_song);
loopingPopup->move (pos);
loopingPopup->show();
}
bool GuiTopBar::eventFilter(QObject *obj, QEvent *event)
{
if (event->type() == QEvent::KeyPress) {
QKeyEvent *keyEvent = static_cast(event);
if (keyEvent->key()==Qt::Key_Up) {
speedSpin->stepUp();
return true;
} else if (keyEvent->key()==Qt::Key_Down) {
speedSpin->stepDown();
return true;
} else {
return false;
}
} else {
// it's not a key event, lets do standard event processing
return QObject::eventFilter(obj, event);
}
}
pianobooster-src-0.6.4b/src/GuiLoopingPopup.ui 0000644 0001747 0001747 00000004042 11162534502 021043 0 ustar ubuntu ubuntu
GuiLoopingPopup
0
0
157
70
0
0
Form
-
0
QLayout::SetMinimumSize
2
4
-
0
0
Repeat Bars:
-
62
16777215
true
1
99.900000000000006
-
End bar
pianobooster-src-0.6.4b/src/QtMain.cpp 0000644 0001747 0001747 00000002514 11273420557 017312 0 ustar ubuntu ubuntu /****************************************************************************
Copyright (c) 2008-2009, L. J. Barman, all rights reserved
This file is part of the PianoBooster application
PianoBooster 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.
PianoBooster 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 PianoBooster. If not, see .
****************************************************************************/
#include
#include
#include "QtWindow.h"
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
if (!QGLFormat::hasOpenGL()) {
QMessageBox::information(0, "OpenGL support",
"This system does not support OpenGL which is needed to run Piano Booster.");
return -1;
}
QtWindow window;
window.show();
return app.exec();
}
pianobooster-src-0.6.4b/src/Tempo.cpp 0000644 0001747 0001747 00000003637 11303577704 017215 0 ustar ubuntu ubuntu /*********************************************************************************/
/*!
@file Tempo.cpp
@brief Tries to automatically calculate the tempo.
@author L. J. Barman
Copyright (c) 2008-2009, L. J. Barman, all rights reserved
This file is part of the PianoBooster application
PianoBooster 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.
PianoBooster 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 PianoBooster. If not, see .
*/
/*********************************************************************************/
#include "Tempo.h"
int CTempo::m_cfg_followTempoAmount = 0;
int CTempo::m_cfg_maxJumpAhead = 0;
void CTempo::enableFollowTempo(bool enable)
{
if (enable)
{
m_cfg_maxJumpAhead = 1;
m_cfg_followTempoAmount = 1;
}
else
{
m_cfg_maxJumpAhead = 0;
m_cfg_followTempoAmount = 0;
}
}
void CTempo::adjustTempo(int * ticks)
{
if (m_jumpAheadDelta && m_cfg_maxJumpAhead && m_savedwantedChord)
{
if (m_jumpAheadDelta > 0)
*ticks += m_jumpAheadDelta;
// Automatically adjust the speed
m_userSpeed = m_userSpeed + m_userSpeed * m_jumpAheadDelta * 0.00002;
if (m_userSpeed> 2.0) m_userSpeed = 2.0;
if (m_userSpeed < 0.2) m_userSpeed = 0.2;
printf("%03.0f %5d\r",m_userSpeed *100, m_jumpAheadDelta );
fflush(stdout);
m_jumpAheadDelta = 0;
}
}
pianobooster-src-0.6.4b/src/Rating.cpp 0000644 0001747 0001747 00000006624 11163466052 017351 0 ustar ubuntu ubuntu /*********************************************************************************/
/*!
@file Rating.cpp
@brief The generates a score on how well the pianist is doing.
@author L. J. Barman
Copyright (c) 2008-2009, L. J. Barman, all rights reserved
This file is part of the PianoBooster application
PianoBooster 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.
PianoBooster 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 PianoBooster. If not, see .
*/
/*********************************************************************************/
#include "Rating.h"
#include "Conductor.h"
void CRating::reset()
{
m_totalNotesCount = 0;
m_wrongNoteCount = 0;
m_lateNoteCount = 0;
m_currentAccuracy = 0.5;
m_previousNoteCount = -1;
m_previousLateNoteCount = 0;
m_factor = 2.0;
m_goodAccuracyFlag = false;
}
void CRating::calculateAccuracy()
{
int direction = 0;
if (m_previousNoteCount != m_totalNotesCount)
{
m_previousNoteCount = m_totalNotesCount;
direction = 1;
}
if (m_previousLateNoteCount != m_lateNoteCount)
{
m_previousLateNoteCount = m_lateNoteCount;
direction = -1;
}
if (direction != 0)
{
typedef struct
{
float value;
float stepUp;
float stepDown;
CColour colour;
} accuracyItem_t;
const accuracyItem_t accuracyTable[] =
{
{1.00, 0.01, -0.08, CColour(0.5, 0.5, 1.0)}, // Only the colour is used on the top score
{0.75, 0.01, -0.07, CColour(0.7, 0.3, 1.0)},
{0.50, 0.01, -0.05, CColour(1.0, 0.6, 0.4)},
{0.25, 0.01, -0.03, CColour(1.0, 0.3, 1.0)},
{0.0 , 0.015, -0.02, CColour(1.0, 0.4, 0.2)}
};
size_t i;
for (i = 0; i< arraySize(accuracyTable); i++)
{
if (m_currentAccuracy >= accuracyTable[i].value || i+1 == arraySize(accuracyTable))
{
float stepAmount = (direction > 0) ? accuracyTable[i].stepUp : accuracyTable[i].stepDown;
if (stepAmount < 0 && CConductor::getPlayMode() == PB_PLAY_MODE_playAlong)
stepAmount = accuracyTable[i].stepUp + accuracyTable[i].stepDown;
m_currentAccuracy += stepAmount *m_factor;
break;
}
}
if (m_currentAccuracy < 0) m_currentAccuracy = 0;
if (m_currentAccuracy > 1) m_currentAccuracy = 1;
m_goodAccuracyFlag = false;
for (i = 0; i< arraySize(accuracyTable); i++)
{
if (m_currentAccuracy >= accuracyTable[i].value || i+1 == arraySize(accuracyTable))
{
m_currentColour = accuracyTable[i].colour;
if (m_currentAccuracy >= accuracyTable[ 1 ].value) // the second row in the table
m_goodAccuracyFlag = true;
break;
}
}
}
}
pianobooster-src-0.6.4b/src/GuiMidiSetupDialog.ui 0000644 0001747 0001747 00000027443 11244520357 021451 0 ustar ubuntu ubuntu
GuiMidiSettingsDialog
0
0
465
369
Dialog
-
QTabWidget::Rounded
1
MIDI input && output
-
Qt::Vertical
QSizePolicy::Expanding
396
28
-
Select the MIDI devices
-
0
0
16777215
100
false
true
-
QLayout::SetMinimumSize
-
Midi Input Device:
Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
Midi Output Device:
Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
Qt::Vertical
QSizePolicy::Expanding
396
28
FluidSynth
-
Sound Fonts
-
-
-
-
Add
-
Remove
-
Qt::Vertical
20
40
-
Settings
-
-
150
0
-
Audio Device:
Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
Master Gain:
Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
Audio Driver:
Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
Sample Rate:
Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
Bufer Size
Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
Buffer counts
Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
Reverb
-
Chorus
Latency Fix
40
120
121
29
Latency
200
130
195
17
0 (msec)
Qt::AlignCenter
-
Qt::Horizontal
QDialogButtonBox::Cancel|QDialogButtonBox::Ok
buttonBox
midiSetupTabWidget
buttonBox
accepted()
GuiMidiSettingsDialog
accept()
248
254
157
274
buttonBox
rejected()
GuiMidiSettingsDialog
reject()
316
260
286
274
pianobooster-src-0.6.4b/src/MidiFile.cpp 0000644 0001747 0001747 00000010213 11273657337 017606 0 ustar ubuntu ubuntu /* oooOOO MidiFile.cpp OOOooo
* Reads a Standard MIDI File
Copyright (c) 1993, 2008-2009, L. J. Barman, all rights reserved
This file is part of the PianoBooster application
PianoBooster 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.
PianoBooster 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 PianoBooster. If not, see .
*/
#include
#include
#include
#include "MidiFile.h"
int CMidiFile::m_ppqn = DEFAULT_PPQN;
/* Read 16 bits from the Standard MIDI file */
int CMidiFile::readWord(void)
{
int value;
value = (m_file.get()&0x0ff) <<8 ;
value |= m_file.get()&0x0ff;
return value;
}
int CMidiFile::readHeader(void)
{
size_t i;
int c;
for ( i=0; i < 4; i++)
{
c = m_file.get();
if (c !="MThd"[i] )
{
midiError(SMF_CORRUPTED_MIDI_FILE);
return 0;
}
}
/* length */
if ( readWord() != 0)
{
midiError(SMF_CORRUPTED_MIDI_FILE);
return 0;
}
if ( readWord() != 6)
{
midiError(SMF_CORRUPTED_MIDI_FILE);
return 0;
}
readWord(); /* midi file format */
i = readWord(); /* ntrks (see Standard MIDI File Spec) */
m_ppqn=readWord(); /* division */
ppLogInfo("Tracks %d PPQN %d", i, m_ppqn);
if (i == 0)
{
midiError(SMF_CORRUPTED_MIDI_FILE);
return 0;
}
return i;
}
void CMidiFile::openMidiFile(string filename)
{
if (m_file.is_open())
m_file.close();
m_file.clear(); // clear any errors
m_file.open(filename.c_str(), ios_base::in | ios_base::binary);
if (m_file.fail() == true)
{
QMessageBox::warning(0, "Midi File Error",
"Cannot open \"" + QString(filename.c_str()) + "\"");
midiError(SMF_CANNOT_OPEN_FILE);
return;
}
rewind();
if (getMidiError() != SMF_NO_ERROR)
QMessageBox::warning(0, "Midi File Error",
"Midi file\"" + QString(filename.c_str()) + "\" is corrupted");
}
void CMidiFile::rewind()
{
size_t ntrks;
size_t trk;
dword_t trackLength;
streampos filePos;
midiError(SMF_NO_ERROR);
m_ppqn = DEFAULT_PPQN;
m_file.seekg (0, ios::beg);
ntrks = readHeader();
if (ntrks == 0)
{
midiError(SMF_CORRUPTED_MIDI_FILE);
ppLogError("Zero tracks in SMF file");
return;
}
if (ntrks > arraySize(m_tracks))
{
midiError(SMF_ERROR_TOO_MANY_TRACK);
ppLogError("Too many tracks in SMF file");
return;
}
for (trk = 0; trk < arraySize(m_tracks); trk++)
{
if (m_tracks[trk]!= 0)
{
delete (m_tracks[trk]);
m_tracks[trk] = 0;
}
}
filePos = m_file.tellg();
for (trk = 0; trk < ntrks; trk++)
{
m_tracks[trk] = new CMidiTrack(m_file, trk);
trackLength = m_tracks[trk]->getTrackLength();
m_tracks[trk]->decodeTrack();
if (m_tracks[trk]->failed())
{
midiError(m_tracks[trk]->getMidiError());
break;
}
//now move onto the next track
filePos += trackLength;
m_file.seekg (filePos, ios::beg);
}
m_songTitle = m_tracks[0]->getTrackName();
initMergedEvents();
}
bool CMidiFile::checkMidiEventFromStream(int streamIdx)
{
if (streamIdx < 0 || streamIdx >= MAX_TRACKS)
{
assert("streamIdx out of range");
return false;
}
if (m_tracks[streamIdx] != 0 && m_tracks[streamIdx]->length() > 0)
return true;
return false;
}
CMidiEvent CMidiFile::fetchMidiEventFromStream(int streamIdx)
{
return m_tracks[streamIdx]->pop();
}
pianobooster-src-0.6.4b/src/GuiPreferencesDialog.ui 0000644 0001747 0001747 00000011020 11304041717 021762 0 ustar ubuntu ubuntu
GuiPreferencesDialog
0
0
362
267
Dialog
-
Score Settings
-
-
0
0
Timing Markers
-
Follow stop point:
-
0
0
QComboBox::AdjustToContents
-
Qt::Horizontal
40
20
-
Show Note Names
-
Qt::Horizontal
40
20
-
Courtesy Accidentals
-
Video Settings
-
Video optimisation
-
Qt::Horizontal
QDialogButtonBox::Cancel|QDialogButtonBox::Ok
buttonBox
accepted()
GuiPreferencesDialog
accept()
248
254
157
274
buttonBox
rejected()
GuiPreferencesDialog
reject()
316
260
286
274
pianobooster-src-0.6.4b/src/pianobooster.icns 0000755 0001747 0001747 00000007255 11156045502 021002 0 ustar ubuntu ubuntu icns is32
'
!
C :
QH Uvpdă e+g] _tyVW % LWDgE9
WukA A3
IETdEH GFGFF%(7
>+B@MLMOLLI?NDBe}v_&+04;ecL
r3 hab $HgMIIMMALLwe F4 OOTUO AM@MM&0
TNNMRQM
WQPPTRQ
'
>:89:d;9 ! MGFFKFF
YPPJJSK USM_t <5-f` %c}ºF ! JWM