DELETED COPYING Index: COPYING ================================================================== --- COPYING +++ COPYING @@ -1,674 +0,0 @@ - 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 -. Index: Makefile ================================================================== --- Makefile +++ Makefile @@ -1,49 +1,33 @@ -PROG = fex -VER = 2.0 -CC ?= gcc -DEPS = x11 cairo fftw3 sndfile -DEFS = -DPROGRAM_NAME=${PROG} -DPROGRAM_VER=${VER} -CFLAGS += $(shell pkg-config --cflags ${DEPS}) ${DEFS} -LDLIBS += $(shell pkg-config --libs ${DEPS}) -lm -lXpm -PREFIX ?= /usr -MODULES = config fex fft spectro wave xlib -HEADERS = fex.h -MANPAGES = fex.1 fex-help.1 -VPATH = src:doc +PROG = fex +VER = 3.0pre +PREFIX ?= /usr +CC = g++ +CONFFILE ?= ${PREFIX}/share/${PROG}/${PROG}rc +DEFS = -DPROGRAM_NAME=${PROG} -DPROGRAM_VER=${VER} -DDEFAULT_CONFIG=${CONFFILE} +CPPFLAGS ?= -D_FORTIFY_SOURCE=2 +CXXFLAGS ?= -march=native -O2 -pipe -fstack-protector-strong -Wstack-protector +LDFLAGS ?= -Wl,-O1,--sort-common,--as-needed,-z,relro +CXXFLAGS += $(shell pkg-config --cflags sfml-all fftw3) -std=c++11 ${DEFS} +LDLIBS += $(shell pkg-config --libs sfml-all fftw3) +MODULES = config fex fft spectrogram +MANPAGES = ${PROG}.1 ${PROG}rc.5 +VPATH = src ${PROG}: ${MODULES:%=%.o} -xlib.o: xlib.c xlib_toolwin.c xlib_events.c xlib_actions.c ${HEADERS} - -config.o: config.c config.h ${HEADERS} - -%.o: %.c ${HEADERS} +%.o: %.cpp %.hpp install: ${PROG} - @install -Dm755 ${PROG} ${DESTDIR}${PREFIX}/bin/${PROG} - @install -Dm755 src/${PROG}-gtk ${DESTDIR}${PREFIX}/bin/${PROG}-gtk - @install -Dm644 doc/${PROG}.1 ${DESTDIR}${PREFIX}/share/man/man1/${PROG}.1 - @install -Dm644 doc/${PROG}-help.1 ${DESTDIR}${PREFIX}/share/man/man1/${PROG}-help.1 - @mkdir -p ${DESTDIR}${PREFIX}/share/${PROG} - @install -Dm644 share/config ${DESTDIR}${PREFIX}/share/${PROG}/config - @install -Dm644 share/icon.png ${DESTDIR}${PREFIX}/share/pixmaps/${PROG}.png - @install -Dm644 share/${PROG}.desktop ${DESTDIR}${PREFIX}/share/applications/${PROG}.desktop - -${MANPAGES}: fex%.1: fex%-1.tex - @latex2man $< doc/$@ - -man: ${MANPAGES} + @echo ${PROG}-${VER} is not a release candidate and is not suitable for installation clean: - @rm -f ${MODULES:%=%.o} + @rm -rf ${PROG}-*.tar.gz + @rm -rf ${MODULES:%=%.o} distclean: clean - @rm -f ${PROG} ${PROG}-${VER}.tar.gz + @rm -rf ${PROG} -moreclean: distclean - @cd doc && rm -f ${MANPAGES} - -dist: distclean +tarball: distclean @tar -czf ${PROG}-${VER}.tar.gz * -.PHONY: clean dist distclean man +.PHONY: clean distclean install tarball ADDED Makefile.win Index: Makefile.win ================================================================== --- Makefile.win +++ Makefile.win @@ -0,0 +1,44 @@ +PROG = fex +VER = 3.0pre +PREFIX ?= /usr +CC = i686-w64-mingw32-c++ +CXX = i686-w64-mingw32-c++ +CONFFILE ?= ${PREFIX}/share/${PROG}/${PROG}rc +DEFS = -DPROGRAM_NAME=${PROG} -DPROGRAM_VER=${VER} -DDEFAULT_CONFIG=${CONFFILE} +CPPFLAGS ?= -D_FORTIFY_SOURCE=2 +CXXFLAGS ?= -O2 -pipe --param=ssp-buffer-size=4 +LDFLAGS ?= -Wl,-O1,--sort-common,--as-needed +CXXFLAGS += $(shell i686-w64-mingw32-pkg-config --cflags fftw3) -std=c++11 ${DEFS} +LDLIBS += $(shell i686-w64-mingw32-pkg-config --libs fftw3) $(shell pkg-config --libs sfml-all) +MODULES = config fex fft spectrogram +MANPAGES = ${PROG}.1 ${PROG}rc.5 +VPATH = src + +${PROG}: ${MODULES:%=%.o} + +%.o: %.cpp %.hpp + +clean: + @rm -rf ${PROG}-*.tar.gz + @rm -rf ${MODULES:%=%.o} + +distclean: clean + @rm -rf ${PROG} *.tar.gz + +tarball: distclean + @tar -czf ${PROG}-${VER}.tar.gz * + +bundle: ${PROG} + @mv ${PROG} ${PROG}.exe + @cp /usr/i686-w64-mingw32/bin/libfftw3-3.dll ./ + @cp /usr/i686-w64-mingw32/bin/libfftw3f-3.dll ./ + @cp /usr/i686-w64-mingw32/bin/libfftw3l-3.dll ./ + @cp /usr/i686-w64-mingw32/bin/sfml-audio-2.dll ./ + @cp /usr/i686-w64-mingw32/bin/sfml-graphics-2.dll ./ + @cp /usr/i686-w64-mingw32/bin/sfml-network-2.dll ./ + @cp /usr/i686-w64-mingw32/bin/sfml-system-2.dll ./ + @cp /usr/i686-w64-mingw32/bin/sfml-window-2.dll ./ + @tar -czf ${PROG}-${VER}-win32.tar.gz ${PROG}.exe *.dll + @rm -f *.dll + +.PHONY: clean distclean tarball bundle Index: README.md ================================================================== --- README.md +++ README.md @@ -1,13 +1,8 @@ -#FEX - -The Frequency Excursion Calculator - -##Description - -FEX is a spectrographic analysis tool for bioacoustic signals. - -Further details will be described in an upcoming publication. - - - - + +2016.02.16 SFML branch is now minimally functional but not feature complete, +well tested, or at all documented. The brave are free to tinker with it. +Anyone with experience building for Windows is invited to fix my massively +broken windows Makefile(s). + +2016.01.10 Branch created to test SFML. This branch is not yet ready for use. +Please use Master branch. ADDED TODO Index: TODO ================================================================== --- TODO +++ TODO @@ -0,0 +1,18 @@ + +x Add eraser function to spectrogram module + - needs testing +- Too many "magic numbers" for eraser sizes... +x Implement config file reading + * offloaded to pyfex + * fex only uses command line parameters + * this makes porting across platforms easier + * at least for me: I have no idea where a Win user would keep config files. +- Complete the python front end + x Parse config (ini) file to pass CLI parameters to fex binary + - Show file selection dialogs for chosing songs, and saving data + - Make either UI agnostic, or seperate versions for GTK, QT, etc + - Are there Win / Mac native python dialog APIs? + - Or do these need to use GTK/QT or Tk/Wx/... + - Need input from python coders (pull requests welcomed!) + + DELETED doc/fex-1.tex Index: doc/fex-1.tex ================================================================== --- doc/fex-1.tex +++ doc/fex-1.tex @@ -1,117 +0,0 @@ -\documentclass{latex2man} - -\begin{Name}{1}{fex}{Jesse McClure}{Frequency Excusion}{FEX --- The frequency excursion calculator} - -\Prog{Fex} - The frequency excursion calculator - -\end{Name} - -\section{Synopsis} - -\Prog{fex} - [\Opt{-l}|\Opt{--long}] - [\Opt{-v}|\Opt{--version}] - [\Opt{-v}|\Opt{--version}] - \Arg{} - -\Prog{fex-gtk} - [\Opt{-l}|\Opt{--long}] - \Arg{} - [\Arg{} ...] - - -\section{Description} - -\Prog{Fex} is a bioacoustic analysis tool for calculating the frequency -excursion of an audio recording of bird songs or other sound waves. - -\Prog{Fex-gtk} is a wrapper script for fex that facilitates batch -processing of large numbers of wave files. \Prog{Fex-gtk} can be -provided a list of file names, or can be run with no parameters to -provide a dialog window to select input wave files. \Prog{Fex} will be -run on each input file, and the results can either be stored to a data -file or displayed in a dialog window upon completion. - -\Prog{Fex-gtk} is also the executable target of \File{fex.desktop} to -allow for drag-and-drop operation of \Prog{fex}. The desktop file can -accept any number of wave files as a drop target. - -\section{Options} - -\begin{description} -\item[\Opt{-l}|\Opt{--long}] - Provide three column output specifying the path length, path - duration, and frequency excursion (calculated as path length over - duration). Default is to provide only the frequency excursion value. -\item[\Opt{-h}|\Opt{--help}] - Print help message and exit. -\item[\Opt{-v}|\Opt{--version}] - Print version information and exit. -\end{description} - -\section{Configuration} -\Prog{Fex} is configured via a runtime configuration file read from one -of -\File{\$XDG\_CONFIG\_HOME/fex/config}, -\File{\$HOME/.config/fex/config}, -\File{\$HOME/.fexrc}, or -\File{/usr/share/fex/config}. - -Read the example configuration file at \File{/usr/share/fex/config} for -a complete description of the available options. Those listed below are -only the most likely to be changed. Settings not listed below should be -changed only with caution. - -\subsection{Settings} - -The options below are configured with the following format: - -\Opt{set} \Arg{option} = \Arg{value} - -\begin{description} -\item[\Opt{threshold}] - Amplitude at which points can be considered part of the signal - in dB below the maximum amplitude. -\item[\Opt{floor}] - Sound floor for the spectrogram display - in dB below the maximum amplitude. -\item[\Opt{bandpass}] - Hi pass and low pass filter values in kHz. -\end{description} - - -\subsection{Colors} - -Colors are configured with the following format where each setting is a -floating point value between 0.00 and 1.00: - -\Opt{color} \Arg{element} = \Arg{Red} \Arg{Green} \Arg{Blue} \Arg{Alpha} -\Arg{Width} - -\begin{description} -\item[\Opt{spectrogram}] - Background spectrogram -\item[\Opt{threshold}] - Points above the current threshold -\item[\Opt{points}] - Points included in the current frequency excursion calculation -\item[\Opt{lines}] - Lines connecting the peak points -\end{description} - -\section{See Also} - -\Opt{fex-help}(1) - -\URL{http://wiki.behaviorenterprises.com/index.php?title=Frequency_Excursion} - -\section{Author} -Copyright \copyright 2013-2014 Jesse McClure \\ -License GPLv3: GNU GPL version 3 \URL{http://gnu.org/licenses/gpl.html} \\ -This is free software: you are free to change and redistribute it. \\ -There is NO WARRANTY, to the extent permitted by law. - -Submit bug reports via the website: \\ -\URL{http://behaviorenterprises.com/?page=software\&package=fex} - -\LatexManEnd DELETED doc/fex-help-1.tex Index: doc/fex-help-1.tex ================================================================== --- doc/fex-help-1.tex +++ doc/fex-help-1.tex @@ -1,85 +0,0 @@ -\documentclass{latex2man} - -\begin{Name}{1}{fex}{Jesse McClure}{Frequency Excusion Controls}{FEX --- The frequency excursion calculator} - -\Prog{Fex} can be readily controlled with either the keyboard or a mouse -with a two-axis scroll wheel. - -\end{Name} - -\section{Directional Commands} - -Direction commands are specified by holding a modifier key and -indicating the direction with a mouse scroll wheel, the home row -directional keys (h k j l), or cursor arrow keys. - -\begin{Table}{5} -\\\hline -\Opt{Modifiers} & - \Opt{Up} & \Opt{Down} & \Opt{Left} & \Opt{Right} \\\hline -\Arg{None} & - scroll & scroll & scroll & scroll \\ -& - up & down & left & right \\ -\\ -\Arg{Control} & - zoom & zoom & - & - \\ -& - in & out & & & \\ -\\ -\Arg{Alt} & - bigger & smaller & narrow & wider \\ -& - eraser & eraser & eraser & eraser \\ -\\ -\Arg{Shift} & - bigger & smaller & narrower & wider \\ -& - points & points & lines & lines \\ -\\ -\Arg{Control+Shift} & - fewer & more & darker & lighter \\ -& - points & points & spectrogram & spectrogram \\\hline -\end{Table} - -\section{Other Controls} - -\begin{description} -\item[\Opt{Control+q}] Quit -\item[\Opt{Control+s}] Save an image of the current view -\item[\Opt{Shift+s}] Save an image of each layer of the current view -(layers: spectrogram, threshold overlay, points/lines overlay) -\item[\Opt{F1}] Show this help page -\item[\Opt{F2}] Toggle visibility of the tool window -\item[\Opt{t}] Toggle spectrogram layers -\item[\Opt{c}] Toggle crop mode -\item[\Opt{e}] Toggle eraser mode -\item[\Opt{Esc}] Return to normal mode -\item[\Opt{u}] Undo last erase, in erase mode only, up to 7 undo levels -\item[\Opt{p}] Play the currently displayed signal -\item[\Opt{Shift+p}] Play the currently displayed signal at half speed -\item[\Opt{Ctrl+p}] Play the currently displayed signal at 1/3 speed -\item[\Opt{Alt+p}] Play the currently displayed signal at 1/4 speed -\item[\Opt{Shift+Ctrl+p}] Play the currently displayed signal at 1/6 speed -\item[\Opt{Shift+Alt+p}] Play the currently displayed signal at 1/12 speed -\end{description} - -\section{Tool Window} - -The tool window displays the current cursor position and the currently -calculated frequency excursion. The tool window also allows for -point-and-click access to the available modes. - -\begin{description} -\item[\Opt{Erase}] Toggle erase mode -\item[\Opt{Crop}] \Arg{Left-click}: Toggle crop mode \Arg{Right-click}: -Undo all cropping -\end{description} - - -\section{See Also} - -\Opt{fex}(1) - -\LatexManEnd DELETED doc/fex-help.1 Index: doc/fex-help.1 ================================================================== --- doc/fex-help.1 +++ doc/fex-help.1 @@ -1,235 +0,0 @@ -'\" t -.\" Manual page created with latex2man on Wed Jul 2 13:29:59 EDT 2014 -.\" NOTE: This file is generated, DO NOT EDIT. -.de Vb -.ft CW -.nf -.. -.de Ve -.ft R - -.fi -.. -.TH "FEX" "1" "02 July 2014" "Frequency Excusion Controls " "Frequency Excusion Controls " -.SH NAME - -.PP -Fex -can be readily controlled with either the keyboard or a mouse -with a two\-axis scroll wheel. -.PP -.SH DIRECTIONAL COMMANDS - -.PP -Direction commands are specified by holding a modifier key and -indicating the direction with a mouse scroll wheel, the home row -directional keys (h k j l), or cursor arrow keys. -.PP -.TS -tab(&); -l l l l l. -T{ -T} -_ -T{ -\fBModifiers\fP -T}&T{ -\fBUp\fP -T}&T{ -\fBDown\fP -T}&T{ -\fBLeft\fP -T}&T{ -\fBRight\fP -T} -_ -T{ -\fINone\fP -T}&T{ -scroll -T}&T{ -scroll -T}&T{ -scroll -T}&T{ -scroll -T} -T{ -T}&T{ -up -T}&T{ -down -T}&T{ -left -T}&T{ -right -T} -T{ -T} -T{ -\fIControl\fP -T}&T{ -zoom -T}&T{ -zoom -T}&T{ -\- -T}&T{ -\- -T} -T{ -T}&T{ -in -T}&T{ -out -T}&T{ -T}&T{ -T}&T{ -T} -T{ -T} -T{ -\fIAlt\fP -T}&T{ -bigger -T}&T{ -smaller -T}&T{ -narrow -T}&T{ -wider -T} -T{ -T}&T{ -eraser -T}&T{ -eraser -T}&T{ -eraser -T}&T{ -eraser -T} -T{ -T} -T{ -\fIShift\fP -T}&T{ -bigger -T}&T{ -smaller -T}&T{ -narrower -T}&T{ -wider -T} -T{ -T}&T{ -points -T}&T{ -points -T}&T{ -lines -T}&T{ -lines -T} -T{ -T} -T{ -\fIControl+Shift\fP -T}&T{ -fewer -T}&T{ -more -T}&T{ -darker -T}&T{ -lighter -T} -T{ -T}&T{ -points -T}&T{ -points -T}&T{ -spectrogram -T}&T{ -spectrogram -T} -_ -.TE -.PP -.SH OTHER CONTROLS - -.PP -.TP -\fBControl+q\fP - Quit -.TP -\fBControl+s\fP - Save an image of the current view -.TP -\fBShift+s\fP - Save an image of each layer of the current view -(layers: spectrogram, threshold overlay, points/lines overlay) -.TP -\fBF1\fP - Show this help page -.TP -\fBF2\fP - Toggle visibility of the tool window -.TP -\fBt\fP - Toggle spectrogram layers -.TP -\fBc\fP - Toggle crop mode -.TP -\fBe\fP - Toggle eraser mode -.TP -\fBEsc\fP - Return to normal mode -.TP -\fBu\fP - Undo last erase, in erase mode only, up to 7 undo levels -.TP -\fBp\fP - Play the currently displayed signal -.TP -\fBShift+p\fP - Play the currently displayed signal at half speed -.TP -\fBCtrl+p\fP - Play the currently displayed signal at 1/3 speed -.TP -\fBAlt+p\fP - Play the currently displayed signal at 1/4 speed -.TP -\fBShift+Ctrl+p\fP - Play the currently displayed signal at 1/6 speed -.TP -\fBShift+Alt+p\fP - Play the currently displayed signal at 1/12 speed -.PP -.SH TOOL WINDOW - -.PP -The tool window displays the current cursor position and the currently -calculated frequency excursion. The tool window also allows for -point\-and\-click access to the available modes. -.PP -.TP -\fBErase\fP - Toggle erase mode -.TP -\fBCrop\fP - \fILeft\-click\fP: -Toggle crop mode \fIRight\-click\fP: -Undo all cropping -.PP -.SH SEE ALSO - -.PP -\fBfex\fP(1) -.PP -.\" NOTE: This file is generated, DO NOT EDIT. DELETED doc/fex.1 Index: doc/fex.1 ================================================================== --- doc/fex.1 +++ doc/fex.1 @@ -1,158 +0,0 @@ -'\" t -.\" Manual page created with latex2man on Wed Oct 1 12:46:47 EDT 2014 -.\" NOTE: This file is generated, DO NOT EDIT. -.de Vb -.ft CW -.nf -.. -.de Ve -.ft R - -.fi -.. -.TH "FEX" "1" "01 October 2014" "Frequency Excusion " "Frequency Excusion " -.SH NAME - -.PP -Fex -\- The frequency excursion calculator -.PP -.SH SYNOPSIS - -.PP -fex -[\fB\-l\fP|\fB\-\-long\fP] -[\fB\-v\fP|\fB\-\-version\fP] -[\fB\-v\fP|\fB\-\-version\fP] -\fI\fP -.PP -fex\-gtk -[\fB\-l\fP|\fB\-\-long\fP] -\fI\fP -[\fI\fP -\&.\&.\&.] -.PP -.SH DESCRIPTION - -.PP -Fex -is a bioacoustic analysis tool for calculating the frequency -excursion of an audio recording of bird songs or other sound waves. -.PP -Fex\-gtk -is a wrapper script for fex that facilitates batch -processing of large numbers of wave files. Fex\-gtk -can be -provided a list of file names, or can be run with no parameters to -provide a dialog window to select input wave files. Fex -will be -run on each input file, and the results can either be stored to a data -file or displayed in a dialog window upon completion. -.PP -Fex\-gtk -is also the executable target of fex.desktop -to -allow for drag\-and\-drop operation of fex\&. -The desktop file can -accept any number of wave files as a drop target. -.PP -.SH OPTIONS - -.PP -.TP -\fB\-l\fP|\fB\-\-long\fP - Provide three column output specifying the path length, path -duration, and frequency excursion (calculated as path length over -duration). Default is to provide only the frequency excursion value. -.TP -\fB\-h\fP|\fB\-\-help\fP - Print help message and exit. -.TP -\fB\-v\fP|\fB\-\-version\fP - Print version information and exit. -.PP -.SH CONFIGURATION - -Fex -is configured via a runtime configuration file read from one -of -$XDG_CONFIG_HOME/fex/config, -$HOME/.config/fex/config, -$HOME/.fexrc, -or -/usr/share/fex/config\&. -.PP -Read the example configuration file at /usr/share/fex/config -for -a complete description of the available options. Those listed below are -only the most likely to be changed. Settings not listed below should be -changed only with caution. -.PP -.SS SETTINGS -.PP -The options below are configured with the following format: -.PP -\fBset\fP -\fIoption\fP -= \fIvalue\fP -.PP -.TP -\fBthreshold\fP - Amplitude at which points can be considered part of the signal -in dB below the maximum amplitude. -.TP -\fBfloor\fP - Sound floor for the spectrogram display -in dB below the maximum amplitude. -.TP -\fBbandpass\fP - Hi pass and low pass filter values in kHz. -.PP -.SS COLORS -.PP -Colors are configured with the following format where each setting is a -floating point value between 0.00 and 1.00: -.PP -\fBcolor\fP -\fIelement\fP -= \fIRed\fP -\fIGreen\fP -\fIBlue\fP -\fIAlpha\fP -\fIWidth\fP -.PP -.TP -\fBspectrogram\fP - Background spectrogram -.TP -\fBthreshold\fP - Points above the current threshold -.TP -\fBpoints\fP - Points included in the current frequency excursion calculation -.TP -\fBlines\fP - Lines connecting the peak points -.PP -.SH SEE ALSO - -.PP -\fBfex\-help\fP(1) -.PP -\fBhttp://wiki.behaviorenterprises.com/index.php?title=Frequency_Excursion\fP -.PP -.SH AUTHOR - -Copyright (C)2013\-2014 Jesse McClure -.br -License GPLv3: GNU GPL version 3 \fBhttp://gnu.org/licenses/gpl.html\fP -.br -This is free software: you are free to change and redistribute it. -.br -There is NO WARRANTY, to the extent permitted by law. -.PP -Submit bug reports via the website: -.br -\fBhttp://behaviorenterprises.com/?page=software&package=fex\fP -.PP -.\" NOTE: This file is generated, DO NOT EDIT. DELETED pkg/README.md Index: pkg/README.md ================================================================== --- pkg/README.md +++ pkg/README.md @@ -1,48 +0,0 @@ -###FEX Distibion and packaging - -For distributions equipped to build from git sources (e.g. Archlinux), -all packaging materials will be provided in subdirectories here. - -For other distrobutions, I will work on making suitable packaging materials -available and/or will gladly accept pull requests from those who are more -familiar with other distros. The directories for such distros contain the -materials I currently use to build packages for those targets. - -Binary and/or source packages will be available at the site below as they -become available: - -http://behaviorenterprises.com/repo/ - -####Dependencies - -The following packages and all their dependencies are required. - -+ cairo -+ desktop-file-utils -+ fftw -+ libxpm -+ libsndfile -+ python2 - -Dependencies for building fex include the above packages, along with any -associated -dev or -devel packages for distros that use split packages, and, -of course, git to pull the source code. - -####Building - -There is no need to configure: - -```bash -git clone http://github.com/TrilbyWhite/fex.git -cd fex -make -``` - -####Installation - -make install accepts DESTDIR and PREFIX variables: - -```bash -make DESTDIR=/path/to/pkgdir PREFIX=/usr install -``` - DELETED pkg/archlinux/PKGBUILD Index: pkg/archlinux/PKGBUILD ================================================================== --- pkg/archlinux/PKGBUILD +++ pkg/archlinux/PKGBUILD @@ -1,29 +0,0 @@ -# Maintainer: Jesse AKA "Trilby" -_gitname="fex" -pkgname="${_gitname}-git" -pkgver=2.0 -pkgrel=1 -pkgdesc='Frequency Excursion Calculator' -url='http://github.com/TrilbyWhite/fex.git' -arch=('i686' 'x86_64') -license=('GPL3') -depends=('cairo' 'desktop-file-utils' 'fftw' 'libxpm' 'libsndfile' 'python2' 'pygtk' 'sox') -makedepends=('git') -install="${_gitname}.install" -source=("${_gitname}::git://github.com/TrilbyWhite/fex.git") -sha256sums=('SKIP') - -pkgver() { - cd "${_gitname}"; - echo "2.$(git rev-list --count HEAD).$(git describe --always )" -} - -build() { - cd "${_gitname}" - make -} - -package() { - cd "${_gitname}" - make DESTDIR="${pkgdir}" install -} DELETED pkg/archlinux/fex.install Index: pkg/archlinux/fex.install ================================================================== --- pkg/archlinux/fex.install +++ pkg/archlinux/fex.install @@ -1,11 +0,0 @@ -post_install() { - update-desktop-database -q -} - -post_upgrade() { - post_install $1 -} - -post_remove() { - post_install $1 -} DELETED pkg/deb/README Index: pkg/deb/README ================================================================== --- pkg/deb/README +++ pkg/deb/README @@ -1,8 +0,0 @@ - -makedeb is experimental - use at your own risk. - -The goal is to be able to build debian packages from an rpm spec file - -or something very close to it. - -26 Sept 2014 - makedeb succesfully built an installable deb package on ubunt 14 - DELETED pkg/deb/fex-calc.spec Index: pkg/deb/fex-calc.spec ================================================================== --- pkg/deb/fex-calc.spec +++ pkg/deb/fex-calc.spec @@ -1,46 +0,0 @@ -summary: Frequency Excursion Calculator -name: fex -version: 2 -release: 1 -license: GPL3 -group: Applications/Science -source: https://github.com/BehaviorEnterprises/Fex.git -url: https://wiki.BehaviorEnterprises.com -vendor: Behavior Enterprises -packager: Jesse McClure -requires: desktop-file-utils, libasound2, libcairo2, libfftw3-3, libsndfile1, libxpm4, python, python-gtk2 -buildrequires: libasound2-dev, libcairo2-dev, libfftw3-dev, gcc, libsndfile1-dev, libx11-dev, libxpm-dev, pkg-config -prefix: /usr - -%description -Frequency Excursion Calculator - -%prep -%setup -c - -%build -make - -%install -make "DESTDIR=${RPM_BUILD_ROOT}" install - -%clean -rm -rf "${RPM_BUILD_ROOT}" - -%post -update-desktop-database -q - -%postun -update-desktop-database -q - -%files -/usr/bin/fex -/usr/bin/fex-gtk -/usr/share/applications/ -/usr/share/applications/fex.desktop -/usr/share/fex/ -/usr/share/fex/config -/usr/share/man/man1/fex-help.1.gz -/usr/share/man/man1/fex.1.gz -/usr/share/pixmaps/fex.png - DELETED pkg/deb/makedeb Index: pkg/deb/makedeb ================================================================== --- pkg/deb/makedeb +++ pkg/deb/makedeb @@ -1,88 +0,0 @@ -#!/bin/bash - -## VERSION: -#V#MakeDEB -#V# version 1.0, copyright 2014, Jesse McClure -#V# license: CC-BY-SA https://creativecommons.org/licenses/by-sa/2.0/ -## HELP: - -if [[ -n $1 ]]; then - case $1 in - -h|--help|help) awk '/^#[VH]#/ { sub(/^#[VH]#/,""); print $0; }' $0 ;; - -v|--ver*|ver*) awk '/^#V#/ { sub(/^#V#/,""); print $0; }' $0 ;; - esac - exit -fi - -start_dir=$(pwd) - -spec=$(find -maxdepth 1 -name "*.spec") -if [[ ! -f ${spec} ]]; then - echo "No spec file found" - exit 1 -fi - -## GET VALUES FROM SPEC FILE: -pkgbase=$(awk -F ': ' '/^name:/ { print $2; }' ${spec}) -pkgname=$(basename ${spec}) -pkgname=${pkgname/\.spec/} -git_url=$(awk -F ': ' '/^source:/ { print $2; }' ${spec}) -pkgver_base=$(awk -F ': ' '/^version:/ { print $2; }' ${spec}) -email=$(awk -F ': ' '/^packager:/ { print $2; }' ${spec}) -license=$(awk -F ': ' '/^license:/ { print $2; }' ${spec}) -upstream_url=$(awk -F ': ' '/^url:/ { print $2; }' ${spec}) -description=$(awk -F ': ' '/^summary:/ { print $2; }' ${spec}) -section=$(awk -F ': ' '/^group:/ { print $2; }' ${spec}) -build_deps=$(awk -F ': ' '/^buildrequires:/ { print $2; }' ${spec}) -deps=$(awk -F ': ' '/^requires:/ { print $2; }' ${spec}) - -## CHECK BUILD ENVIRONMENT: -#sudo apt-get install build-essential autoconf automake autotools-dev dh-make debhelper devscripts fakeroot xutils lintian pbuilder -topdir=/tmp/makeDEB -rm -rf ${topdir}/${pkgname} -mkdir -p ${topdir}/${pkgname} - -## GET CODE AND MAKE SOURCE TARBALL: -if [[ -d ${pkgname} ]]; then - cd ${pkgname}; - git pull; -else - git clone ${git_url} ${pkgname} - cd ${pkgname} -fi -pkgver="${pkgver_base}.$(git rev-list --count HEAD)" -make dist -mv ${pkgbase}*.tar.gz ${topdir}/${pkgname}/${pkgname}-${pkgver}.tar.gz - -## BUILD FOLDER PREPARATION -cd ${start_dir} -mv ${pkgname} ${topdir}/${pkgname}/${pkgname}-${pkgver} - -## DEBIANIZE -cd ${topdir}/${pkgname}/${pkgname}-${pkgver} -dh_make \ - --copyright "${license}" \ - --email "${email}" \ - --file "../${pkgname}-${pkgver}.tar.gz" \ - --single \ - --yes - -## EDIT CONTROL FILE -sed -i 's|^Depends:.*|Depends: '"${deps}"'|' debian/control -sed -i 's|^Build-Depends:.*|Build-Depends: '"${build_deps}"'|' debian/control -sed -i 's|^Maintainer:.*|Maintainer: '"${email}"'|' debian/control -sed -i 's|^Homepage:.*|Homepage: '"${upstream_url}"'|' debian/control -sed -i 's|^Description:.*|Description: '"${description}"'|' debian/control -sed -i 's|^Section:.*|Section: '"${section}"'|' debian/control - -## CREATE CHANGELOG -#echo "${pkgname} (${pkgver}-1) unstable; urgency=low" > debian/changelog -#echo "* Initial release" >> debian/changelog -#echo "-- ${maintainer} <${email}> " >> debian/changelog - -## BUILD THE PACKAGE -dpkg-buildpackage - -## CLEAN UP: -cd ${startdir} - DELETED pkg/rpm/README Index: pkg/rpm/README ================================================================== --- pkg/rpm/README +++ pkg/rpm/README @@ -1,7 +0,0 @@ -makerpm uses rpmbuild and a slightly modified spec file (allowing a git -source) to build an installable rpm file. - -Currently makerpm is being developed and tested on Fedora 20. - -TODO: - find dependency for asoundlib.h DELETED pkg/rpm/fex.spec Index: pkg/rpm/fex.spec ================================================================== --- pkg/rpm/fex.spec +++ pkg/rpm/fex.spec @@ -1,46 +0,0 @@ -summary: Frequency Excursion Calculator -name: fex -version: 2 -release: 1 -license: GPL3 -group: Applications/Science -source: https://github.com/BehaviorEnterprises/Fex.git -url: https://wiki.BehaviorEnterprises.com -vendor: Behavior Enterprises -packager: Jesse McClure jesse [at] mccluresk9 [dot] com -requires: cairo, desktop-file-utils, fftw, libsndfile, libXpm, python, pygtk2, sox -buildrequires: cairo-devel, fftw-devel, gcc, libsndfile-devel, libX11-devel, libXpm-devel, pkgconfig -prefix: /usr - -%description -Frequency Excursion Calculator - -%prep -%setup -c - -%build -make - -%install -make "DESTDIR=${RPM_BUILD_ROOT}" install - -%clean -rm -rf "${RPM_BUILD_ROOT}" - -%post -update-desktop-database -q - -%postun -update-desktop-database -q - -%files -/usr/bin/fex -/usr/bin/fex-gtk -/usr/share/applications/ -/usr/share/applications/fex.desktop -/usr/share/fex/ -/usr/share/fex/config -/usr/share/man/man1/fex-help.1.gz -/usr/share/man/man1/fex.1.gz -/usr/share/pixmaps/fex.png - DELETED pkg/rpm/makerpm Index: pkg/rpm/makerpm ================================================================== --- pkg/rpm/makerpm +++ pkg/rpm/makerpm @@ -1,82 +0,0 @@ -#!/bin/bash - -## VERSION: -#V#MakeRPM -#V# version 1.0, copyright 2014, Jesse McClure -#V# license: CC-BY-SA https://creativecommons.org/licenses/by-sa/2.0/ -## HELP: -#H# -#H#makerpm will look in the current working directory for a spec file with -#H#the following requirements: -#H# -#H#1) The "source" line should provide a full git url from which the source -#H#can be cloned -#H# -#H#2) The "version" line should provide only a base number upon which the -#H#commit count will be appended -#H# -#H#The upstream git source must also include a Makefile in the toplevel -#H#directory with a directive called 'dist' which will make a source -#H#tarball (.tar.gz) in that same directory. -#H# -#H#makerpm will 1) revise the source and version lines in a copy placed in -#H#rpmbuild's topdir/SPECS/ folder, 2) install the build dependencies if it -#H#is the first build for the package on the machine, 3) obtain the git -#H#source, 4) make the tarball and move it to topdir/SOURCES/, 5) build the -#H#rpm and srpm, and 6) clean up / remove the cloned git dir. - -if [[ -n $1 ]]; then - case $1 in - -h|--help|help) awk '/^#[VH]#/ { sub(/^#[VH]#/,""); print $0; }' $0 ;; - -v|--ver*|ver*) awk '/^#V#/ { sub(/^#V#/,""); print $0; }' $0 ;; - esac - exit -fi -exit - -start_dir=$(pwd) - -## CHECK FOR SPEC FILE: -spec=$(find -name "*.spec") -if [[ ! -f ${spec} ]]; then - echo "No spec file found" - return -fi - -## GET VALUES FROM SPEC FILE: -pkgname=$(awk '/^name:/ { print $2; }' ${spec}) -git_url=$(awk '/^source:/ { print $2; }' ${spec}) -pkgver_base=$(awk '/^version:/ { print $2; }' ${spec}) - -return - -## CHECK BUILD ENVIRONMENT: -topdir=$(rpmbuild --eval '%_topdir') -mkdir -p ${topdir}/{BUILD,RPMS,SOURCES,SPECS,SRPMS} - -## INSTALL BUILD DEPS IF FIRST BUILD: -builds=$(find ${topdir}/RPMS/ -name "${pkgname}*") -[[ -z $builds ]] && sudo yum-builddep ${spec} - -## GET CODE AND MAKE SOURCE TARBALL: -git clone ${git_url} -cd ${pkgname} -pkgver="${pkgver_base}.$(git rev-list --count HEAD)" -make dist -mv ./${pkgname}*.tar.gz ${topdir}/SOURCES/${pkgname}-${pkgver}.tar.gz - -## PREPARE SPEC FILE: -cd ${start_dir} -cp ${spec} ${topdir}/SPECS/ -cd ${topdir}/SPECS/ -sed -i 's/^version: .*$/version: '${pkgver}'/' ${pkgname}.spec -sed -i 's/^source: .*$/source: '${pkgname}-${pkgver}'.tar.gz/' ${pkgname}.spec - -## RUN RPMBUILD: -cd ${topdir}/SPECS -rpmbuild -ba ${pkgname}.spec - -## CLEAN UP: -cd ${startdir} -rm -rf ${pkgname} - ADDED pyfex/default.ini Index: pyfex/default.ini ================================================================== --- pyfex/default.ini +++ pyfex/default.ini @@ -0,0 +1,29 @@ + +[defaults] +window length = 256 +bin size = 64 +low pass = 01.25 +high pass = 10.00 +threshold = 18.00 +floor = 24.00 +log transform = false + +[colors] +window background = #606468FF +spectrogram background = #FFFFFFFF +spectrogram foreground = #000000FF +threshold = #58749848 +point border = #3399FFFF +point fill = #3399FF48 +lines = #E86850FF +cursor = #FF0000AA + +[warbler] +#match file extension = wav +#match mime type = audio/x-wav +match path = warber +threshold = 14.00 + +[sparrow] +match path = sparrow +threshold = 24.00 ADDED pyfex/fexUI Index: pyfex/fexUI ================================================================== --- pyfex/fexUI +++ pyfex/fexUI @@ -0,0 +1,44 @@ +#!/usr/bin/env python + +from sys import argv +from subprocess import DEVNULL, check_output +from configparser import ConfigParser + +ini = ConfigParser() +ini.read('default.ini') +conf = ini['defaults'] +col = ini['colors'] +args = [ + './fex', + '--winSize=' + conf['window length'], + '--binSize=' + conf['bin size'], + '--loPass=' + conf['low pass'], + '--hiPass=' + conf['high pass'], + '--threshold=' + conf['threshold'], + '--floor=' + conf['floor'], + '--log10=' + conf['log transform'], + '--winBG=' + col['window background'], + '--specBG=' + col['spectrogram background'], + '--specFG=' + col['spectrogram foreground'], + '--threshFG=' + col['threshold'], + '--pointBG=' + col['point fill'], + '--pointFG=' + col['point border'], + '--linesFG=' + col['lines'] + '--cursorFG=' + col['cursor'] +] + +def run_fex(files): + if len(files) == 0: + print("zero") + # prompt with dialog returning list of files + # run_fex(list of files) + elif len(files) == 1: + print(check_output(args + [files[0]],stderr=DEVNULL).decode("utf-8")) + else: + print("many") + # loop through files running fex on each + +argv.remove(argv[0]) +run_fex(argv) + + DELETED share/config Index: share/config ================================================================== --- share/config +++ share/config @@ -1,60 +0,0 @@ -## FEX Configuration -## -## Copy this file to one of the following locations for editing -## $XDG_CONFIG_HOME/fex/config -## $HOME/.config/fex/config -## $HOME/.fexrc - -## Lines starting with a '#' sign are ignored as comments -## but this file is not parsed by a shell interpreter. - -## Entries should be of one of two forms: 'set' or 'color' -## set = -## color = - -## Settings -## threshold: decibels below the peak amplitude to include in signal -## floor: decibels below the peak amplitude to show in the spectrogram -## samples: number of samples per window for FFT -## bandpass: bandpass filter in kHz -## scale: number of graphical units per data unit -## window: one of the following window functions for the FFT -## hanning, hamming, blackman, nutall, blackman-nutall, -## blackman-harris, rectangular, custom -## Custom must be followed by up to 4 numbers specifying the -## coefficients for a generalized cosine window function -## fontFamily: font name -## fontSize: font size in pixels -## help: command for launching the help page -## output: any combination of the following: -## path: print path length -## time: print path duration -set threshold = 18.0 -set floor = 30.0 -set samples = 256 -set bandpass = 1.25 10.0 -set scale = 8 -set window = hanning -set fontFamily = droid sans -set fontSize = 14 -set help = xterm -e man fex-help - -## Colors -## spectrogram: background spectrogram -## threshold: points included in the signal -## points: points included in the current excursion calculation -## lines: lines connecting points in the current calculation -## eraser1/2: two colors for eraser block -## crop: crop window lines -color spectrogram 0.0 0.0 0.0 1.0 1.0 -color threshold 0.0 1.0 0.8 0.4 1.0 -color points 0.0 0.1 0.5 0.8 8.0 -color lines 1.0 0.0 0.0 0.8 4.0 -color eraser1 1.0 1.0 0.6 1.0 1.0 -color eraser2 1.0 0.6 0.6 1.0 1.0 -color crop 0.0 1.0 0.2 1.0 2.0 - -## NOTES: -## For more information on configuring and using Fex, please see -## http://wiki.behaviorenterprises.com/?title=Frequency_Excursion - DELETED share/fex.desktop Index: share/fex.desktop ================================================================== --- share/fex.desktop +++ share/fex.desktop @@ -1,10 +0,0 @@ -[Desktop Entry] -Name=Fex -Comment=Calculates the frequency excursion of a sound wave -Exec=fex-gtk %F -#Exec=fex-gtk --long %F -Terminal=false -Type=Application -Categories=Science -Icon=/usr/share/pixmaps/fex.png -MimeType=audio/* DELETED share/icon.png Index: share/icon.png ================================================================== --- share/icon.png +++ share/icon.png cannot compute difference between binary files DELETED src/config.c Index: src/config.c ================================================================== --- src/config.c +++ src/config.c @@ -1,178 +0,0 @@ -/**********************************************************************\ -* FEX - The Frequency Excursion Calculator -* -* Author: Jesse McClure, copyright 2013-2014 -* License: GPL3 -* -* 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 -* . -* -\**********************************************************************/ - -#include "fex.h" - -#define CONF_SET 0x01 -#define CONF_COL 0x02 - -#define C_TYPE__ 0x00 -#define C_TYPE_D 0x01 -#define C_TYPE_F 0x02 -#define C_TYPE_LF 0x03 -#define C_TYPE_S 0x04 -#define C_TYPE_LN 0x05 - -#define STRING(s) STRINGIFY(s) -#define STRINGIFY(s) #s -#define LINE_LEN 256 - -static WindowFunction custom; -static WindowFunction windows[] = { - { "hanning", {0.5, 0.5, 0.0, 0.0} }, - { "hamming", {0.54, 0.46, 0.0, 0.0} }, - { "blackman", {0.42659, 0.49656, 0.076849, 0.0} }, - { "nuttall", {0.355768, 0.487396, 0.144232, 0.012604} }, - { "blackman-nutall", {0.3635819, 0.4891775, 0.1365995, 0.0106411} }, - { "blackman-harris", {0.35875, 0.48829, 0.14128, 0.01168} }, - { "rectangular", {1.0, 0.0, 0.0, 0.0} }, -}; - -static inline void version() { - printf(STRING(PROGRAM_NAME) " v" STRING(PROGRAM_VER) -", Copyright © 2013-2014 Jesse McClure \n" -"You should have received a copy of the GNU General Public License\n" -"along with this program. If not, see .\n"); - exit(0); -} - -static inline void help() { - printf("\n" - "USAGE\n " STRING(PROGRAM_NAME) " \n\n" - "OPTIONS\n" - " -l|--long long output (path, duration, + FE)\n" - " -v|--version show version information then exit\n" - " -h|--help show help information then exit\n\n" - "SEE ALSO\n" - " fex(1) and fex-help(1)\n" - "\n" ); - exit(0); -} - -const char *configure(int argc, const char **argv) { - int i; - /* set defaults */ - const char *arg, *fname = NULL, *rcname = NULL; - char help_cmd[256] = "xterm -e man man"; - conf.help_cmd = NULL; - conf.long_out = False; - conf.layers = True; - /* process command line */ - for (i = 1; i < argc; i++) { - arg = argv[i]; - if (strncmp(arg,"--h",3) == 0 || strncmp(arg,"-h",2) == 0) - help(); - else if (strncmp(arg,"--v",3) == 0 || strncmp(arg,"-v",2) == 0) - version(); - else if (strncmp(arg,"--l",3) == 0 || strncmp(arg,"-l",2) == 0) - conf.long_out = True; - else if (strncmp(arg,"-c",2) == 0 && (++i) < argc) - rcname = argv[i]; - else - fname = argv[i]; - } - if (!fname) die("no audio file provided"); - /* find configuration file */ - FILE *rc = NULL; - char *pwd = getenv("PWD"); - if (rcname) rc = fopen(rcname,"r"); - else if ( (!chdir(getenv("XDG_CONFIG_HOME")) && !chdir("fex")) || - (!chdir(getenv("HOME")) && !chdir(".config/fex")) ) - rc = fopen("config","r"); - if (!rc && !chdir(getenv("HOME"))) rc = fopen(".fexrc","r"); - chdir(pwd); - if (!rc) rc = fopen("/usr/share/fex/config","r"); - if (!rc) die("unable to open configuration file"); - /* initialize conf structure and config reading variables */ - char line[LINE_LEN], prefix[32], option[32], fmt[LINE_LEN]; - char window[32], font_fam[LINE_LEN]; - const char *fspec[] = { "", "%d ","%f ", "%lf ", "%s", "%[^\n]" }; - int j, mode; - conf.thresh = 14.0; - conf.spect_floor = 40.0; - conf.hipass = 12.0; - conf.lopass = 800.0; - conf.winlen = 256; - conf.hop = 0; - conf.win = (WindowFunction *) windows; - struct { - const char *name; - int mode; - int type[5]; - void *var[5]; - } cf[] = { - #include "config.h" - }; - /* read config file */ - while (fgets(line,LINE_LEN,rc)) { - if (line[0] == '#' || line[0] == '\n') continue; - sscanf(line,"%s %s",prefix,option); - if (strncasecmp(prefix,"set",3) == 0) mode = CONF_SET; - else if (strncasecmp(prefix,"col",3) == 0) mode = CONF_COL; - else fprintf(stderr,"bad config entry: %s",line); - sprintf(fmt,"%s %s ",prefix,option); - if (mode == CONF_SET) strcat(fmt,"= "); - for (i = 0; i < sizeof(cf) / sizeof(cf[0]); i++) { - if ( !strncasecmp(option,cf[i].name,strlen(cf[i].name)) && - cf[i].mode == mode ) { - for (j = 0; j < 5; j++) strcat(fmt,fspec[cf[i].type[j]]); - sscanf(line,fmt,cf[i].var[0],cf[i].var[1],cf[i].var[2], - cf[i].var[3],cf[i].var[4]); - } - } - } - /* set hop, threshold, floor, and windowing function */ - if (!conf.hop) conf.hop = conf.winlen / 4; - conf.thresh *= -1; - conf.spect_floor *= -1; - if (strncasecmp(window,"custom",6) == 0) - conf.win = (WindowFunction *) &custom; - else if (strlen(window)) - for (i = 0; i < sizeof(windows)/sizeof(windows[0]); i++) - if (!strncasecmp(window,windows[i].type,strlen(window))) - conf.win = (WindowFunction *) &windows[i]; - /* set fonts */ - conf.font = cairo_toy_font_face_create(font_fam, CAIRO_FONT_SLANT_NORMAL, - CAIRO_FONT_WEIGHT_NORMAL); - conf.bfont = cairo_toy_font_face_create(font_fam, CAIRO_FONT_SLANT_NORMAL, - CAIRO_FONT_WEIGHT_BOLD); - /* prep 'help' function */ - char *help_arg = strtok(help_cmd," "); - for (i = 0; help_arg; i++) { - conf.help_cmd = realloc(conf.help_cmd, (i+2) * sizeof(char *)); - conf.help_cmd[i] = strdup(help_arg); - conf.help_cmd[i+1] = NULL; - help_arg = strtok(NULL," "); - } - /* return audio file name */ - return fname; -} - -int deconfigure() { - /* clean up, free data */ - int i; - for (i = 0; conf.help_cmd[i]; i++) free(conf.help_cmd[i]); - free(conf.help_cmd); - cairo_font_face_destroy(conf.font); - cairo_font_face_destroy(conf.bfont); - return 0; -} ADDED src/config.cpp Index: src/config.cpp ================================================================== --- src/config.cpp +++ src/config.cpp @@ -0,0 +1,74 @@ + +#include "config.hpp" +#include + +sf::Color toColor(char *str) { + if (str[0] == '#') ++str; + unsigned long hex = strtoul(str,NULL,16); + unsigned short int r,g,b,a; + r = (hex & 0xFF000000) >> 24; + g = (hex & 0x00FF0000) >> 16; + b = (hex & 0x0000FF00) >> 8; + a = (hex & 0x000000FF); + return sf::Color(r,g,b,a); +} + +bool toBool(char *str) { + switch (str[0]) { + case 'T': case 't': case '1': case 'Y': case 'y': return true; break; + case 'F': case 'f': case '0': case 'N': case 'n': return false; break; + default: return false; + } +} + +Config::Config(int argc, char *const *argv) { + struct option opts[] = { + { "winSize", optional_argument, 0, 0 }, + { "binSize", optional_argument, 0, 0 }, + { "loPass", optional_argument, 0, 0 }, + { "hiPass", optional_argument, 0, 0 }, + { "threshold", optional_argument, 0, 0 }, + { "floor", optional_argument, 0, 0 }, + { "log10", optional_argument, 0, 0 }, + { "winBG", optional_argument, 0, 0 }, + { "specBG", optional_argument, 0, 0 }, + { "specFG", optional_argument, 0, 0 }, + { "threshFG", optional_argument, 0, 0 }, + { "pointBG", optional_argument, 0, 0 }, + { "pointFG", optional_argument, 0, 0 }, + { "linesFG", optional_argument, 0, 0 }, + { "cursorFG", optional_argument, 0, 0 }, + {0, 0, 0, 0 } + }; + int i, c, index; + char noarg[] = ""; + for (i = 1; (c=getopt_long_only(argc, argv, "", opts, &index)) != -1; ++i) { + if (c != 0 || !optarg) continue; + else if (index == 0) conf.winlen = atoi(optarg); + else if (index == 1) conf.hop = atoi(optarg); + else if (index == 2) conf.lopass = atof(optarg); + else if (index == 3) conf.hipass = atof(optarg); + else if (index == 4) conf.threshold = atof(optarg); + else if (index == 5) conf.floor = atof(optarg); + else if (index == 6) conf.log10 = toBool(optarg); + else if (index == 7) conf.winBG = toColor(optarg); + else if (index == 8) conf.specBG = toColor(optarg); + else if (index == 9) conf.specFG = toColor(optarg); + else if (index == 10) conf.threshFG = toColor(optarg); + else if (index == 11) conf.pointBG = toColor(optarg); + else if (index == 12) conf.pointFG = toColor(optarg); + else if (index == 13) conf.linesFG = toColor(optarg); + else if (index == 14) conf.cursorFG = toColor(optarg); + } + if (i > argc) exit(1); + fname = strdup(argv[i]); + char *dup = strdup(argv[i]); + name = strdup(basename(dup)); + free(dup); +} + +Config::~Config() { + if (name) free(name); + if (fname) free(fname); +} + DELETED src/config.h Index: src/config.h ================================================================== --- src/config.h +++ src/config.h @@ -1,63 +0,0 @@ - -/* set */ -{ "threshold", CONF_SET, - { C_TYPE_LF, C_TYPE__, C_TYPE__, C_TYPE__, C_TYPE__ }, - { &conf.thresh, NULL, NULL, NULL, NULL}, }, -{ "floor", CONF_SET, - { C_TYPE_LF, C_TYPE__, C_TYPE__, C_TYPE__, C_TYPE__ }, - { &conf.spect_floor, NULL, NULL, NULL, NULL}, }, -{ "samples", CONF_SET, - { C_TYPE_D, C_TYPE__, C_TYPE__, C_TYPE__, C_TYPE__ }, - { &conf.winlen, NULL, NULL, NULL, NULL}, }, -{ "hop", CONF_SET, - { C_TYPE_D, C_TYPE__, C_TYPE__, C_TYPE__, C_TYPE__ }, - { &conf.hop, NULL, NULL, NULL, NULL}, }, -{ "bandpass", CONF_SET, - { C_TYPE_LF, C_TYPE_LF, C_TYPE__, C_TYPE__, C_TYPE__ }, - { &conf.hipass, &conf.lopass, NULL, NULL, NULL}, }, -{ "scale", CONF_SET, - { C_TYPE_D, C_TYPE_LF, C_TYPE__, C_TYPE__, C_TYPE__ }, - { &conf.scale, NULL, NULL, NULL, NULL}, }, -{ "window", CONF_SET, - { C_TYPE_S, C_TYPE_LF, C_TYPE_LF, C_TYPE_LF, C_TYPE_LF }, - { window, &custom.a[0], &custom.a[1], &custom.a[2], &custom.a[3]}, }, -{ "fontFamily", CONF_SET, - { C_TYPE_LN, C_TYPE__, C_TYPE__, C_TYPE__, C_TYPE__ }, - { font_fam, NULL, NULL, NULL, NULL}, }, -{ "fontSize", CONF_SET, - { C_TYPE_D, C_TYPE__, C_TYPE__, C_TYPE__, C_TYPE__ }, - { &conf.font_size, NULL, NULL, NULL, NULL}, }, -{ "help", CONF_SET, - { C_TYPE_LN, C_TYPE__, C_TYPE__, C_TYPE__, C_TYPE__ }, - { &help_cmd, NULL, NULL, NULL, NULL}, }, - -/* color */ -{ "spectrogram", CONF_COL, - { C_TYPE_LF, C_TYPE_LF, C_TYPE_LF, C_TYPE_LF, C_TYPE_LF }, - { &conf.col[0].r, &conf.col[0].g, &conf.col[0].b, &conf.col[0].a, - &conf.col[0].w } }, -{ "threshold", CONF_COL, - { C_TYPE_LF, C_TYPE_LF, C_TYPE_LF, C_TYPE_LF, C_TYPE_LF }, - { &conf.col[1].r, &conf.col[1].g, &conf.col[1].b, &conf.col[1].a, - &conf.col[1].w } }, -{ "points", CONF_COL, - { C_TYPE_LF, C_TYPE_LF, C_TYPE_LF, C_TYPE_LF, C_TYPE_LF }, - { &conf.col[2].r, &conf.col[2].g, &conf.col[2].b, &conf.col[2].a, - &conf.col[2].w } }, -{ "lines", CONF_COL, - { C_TYPE_LF, C_TYPE_LF, C_TYPE_LF, C_TYPE_LF, C_TYPE_LF }, - { &conf.col[3].r, &conf.col[3].g, &conf.col[3].b, &conf.col[3].a, - &conf.col[3].w } }, -{ "eraser1", CONF_COL, - { C_TYPE_LF, C_TYPE_LF, C_TYPE_LF, C_TYPE_LF, C_TYPE_LF }, - { &conf.col[4].r, &conf.col[4].g, &conf.col[4].b, &conf.col[4].a, - &conf.col[4].w } }, -{ "eraser2", CONF_COL, - { C_TYPE_LF, C_TYPE_LF, C_TYPE_LF, C_TYPE_LF, C_TYPE_LF }, - { &conf.col[5].r, &conf.col[5].g, &conf.col[5].b, &conf.col[5].a, - &conf.col[5].w } }, -{ "crop", CONF_COL, - { C_TYPE_LF, C_TYPE_LF, C_TYPE_LF, C_TYPE_LF, C_TYPE_LF }, - { &conf.col[6].r, &conf.col[6].g, &conf.col[6].b, &conf.col[6].a, - &conf.col[6].w } }, - ADDED src/config.hpp Index: src/config.hpp ================================================================== --- src/config.hpp +++ src/config.hpp @@ -0,0 +1,37 @@ + +#include +#include +#include +#include + +class Config { + protected: + struct { + int winlen = 256; + int hop = 64; + double lopass = 01.25; + double hipass = 10.00; + double threshold = 18.00; + double floor = 24.00; + bool log10 = false; + sf::Color winBG = sf::Color(0x60,0x64,0x68); + sf::Color specBG = sf::Color(0xFF,0xFF,0xFF); + sf::Color specFG = sf::Color(0x00,0x00,0x00); + sf::Color threshFG = sf::Color(0x58,0x74,0x98,0x48); + sf::Color pointFG = sf::Color(0x33,0x99,0xFF); + sf::Color pointBG = sf::Color(0x33,0x99,0xFF,0x48); + sf::Color linesFG = sf::Color(0xE8,0x68,0x50); + sf::Color cursorFG = sf::Color(0xFF,0x00,0x00,0xAA); + } conf; + struct { + bool overlay = true; + bool cursor = false; + bool eraser = false; + } toggle; + char *fname = NULL, *name = NULL; + + public: + Config(int, char *const *); + ~Config(); +}; + DELETED src/fex-gtk Index: src/fex-gtk ================================================================== --- src/fex-gtk +++ src/fex-gtk @@ -1,118 +0,0 @@ -#!/usr/bin/env python2 -#----------------------------------------------------------------------# -# FEX - The Frequency Excursion Calculator -# -# Author: Jesse McClure, copyright 2013-2014 -# License: GPL3 -# -# 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 -# . -# -#----------------------------------------------------------------------# - -import sys -import os -import subprocess -import pygtk -import gtk - -def main(argv): - if (len(argv) > 0) and (argv[0] == "--long"): - opt_long = True - del argv[0] - else: - opt_long = False - if (len(argv) == 0): - filelist = input_files() - else: - filelist = argv - if (len(filelist) == 0): - sys.exit(0) - if (opt_long): - data = "Song\tPath\tTime\tFEX\n" - else: - data = "Song\tFEX\n" - for filename in filelist: - song = os.path.splitext(os.path.basename(filename))[0] - try: - if (opt_long): - FE = subprocess.check_output(["fex","--long",filename]) - else: - FE = subprocess.check_output(["fex",filename]) - except subprocess.CalledProcessError as err: - FE = "NA\n" - data = data + song + "\t" + FE - if (len(filelist) == 1): - filename = "" - else: - filename = data_file() - if (len(filename) == 0): - label = gtk.Label(data) - win = gtk.Dialog("Fex", None, - gtk.DIALOG_DESTROY_WITH_PARENT, - (gtk.STOCK_OK, gtk.RESPONSE_ACCEPT)) - win.vbox.pack_start(label) - label.show() - win.run() - else: - fptr = open(filename,"w") - fptr.write(data) - -def input_files(): - win = gtk.FileChooserDialog("Open ...", None, - gtk.FILE_CHOOSER_ACTION_OPEN, - (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, - gtk.STOCK_OPEN, gtk.RESPONSE_OK)) - win.set_default_response(gtk.RESPONSE_OK) - win.set_select_multiple(True) - # wave filter - filter = gtk.FileFilter() - filter.set_name("Waves") - filter.add_pattern("*.wav") - filter.add_pattern("*.WAV") - win.add_filter(filter) - # alternative filter - filter = gtk.FileFilter() - filter.set_name("All files") - filter.add_pattern("*") - win.add_filter(filter) - # get files - response = win.run() - if (response == gtk.RESPONSE_OK): - filelist = win.get_filenames() - else: - filelist = [] - win.destroy() - while gtk.events_pending(): - gtk.main_iteration(False) - return filelist - -def data_file(): - win = gtk.FileChooserDialog("Save As ...", None, - gtk.FILE_CHOOSER_ACTION_SAVE, - (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, - gtk.STOCK_OPEN, gtk.RESPONSE_OK)) - win.set_default_response(gtk.RESPONSE_OK) - win.set_do_overwrite_confirmation(True); - response = win.run() - if (response == gtk.RESPONSE_OK): - filename = win.get_filename() - else: - filename = "" - win.destroy() - return filename - -if (__name__ == "__main__"): - main(sys.argv[1:]) - DELETED src/fex.c Index: src/fex.c ================================================================== --- src/fex.c +++ src/fex.c @@ -1,56 +0,0 @@ -/**********************************************************************\ -* FEX - The Frequency Excursion Calculator -* -* Author: Jesse McClure, copyright 2013-2014 -* License: GPL3 -* -* 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 -* . -* -\**********************************************************************/ - -#include "fex.h" - -int die(const char *msg, ...) { - va_list arg; - fprintf(stderr,"Fatal Error: "); - va_start(arg, msg); - vfprintf(stderr,msg,arg); - va_end(arg); - exit(1); -} - -int main(int argc, const char **argv) { - const char *fname = configure(argc,argv); - Wave *wav = create_wave(fname); - FFT *fft = create_fft(wav); - create_spectro(fft, fname); - free_wave(&wav); - - xlib_event_loop(); - if (spect->fex > 0 && conf.long_out) - fprintf(stdout,"%.3lf\t%.3lf\t%.3lf\n", - spect->pex, spect->tex, spect->fex); - else if (spect->fex > 0) - fprintf(stdout,"%.3lf\n", spect->fex); - else if (conf.long_out) - fprintf(stdout,"NA\tNA\tNA\n"); - else - fprintf(stdout,"NA\n"); - - free_spectro(); - free_fft(&fft); - deconfigure(); - return 0; -} ADDED src/fex.cpp Index: src/fex.cpp ================================================================== --- src/fex.cpp +++ src/fex.cpp @@ -0,0 +1,8 @@ + +#include "spectrogram.hpp" + +int main(int argc, char *const *argv) { + Spectrogram spec(argc, argv); + spec.mainLoop(); + return EXIT_SUCCESS; +} DELETED src/fex.h Index: src/fex.h ================================================================== --- src/fex.h +++ src/fex.h @@ -1,132 +0,0 @@ -/**********************************************************************\ -* FEX - The Frequency Excursion Calculator -* -* Author: Jesse McClure, copyright 2013-2014 -* License: GPL3 -* -* 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 -* . -* -\**********************************************************************/ - -#ifndef __FEX_H__ -#define __FEX_H__ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define RGBA_SPECT 0x00 -#define RGBA_THRESH 0x01 -#define RGBA_POINTS 0x02 -#define RGBA_LINES 0x03 -#define RGBA_ERASE1 0x04 -#define RGBA_ERASE2 0x05 -#define RGBA_CROP 0x06 -#define RGBA_LAST 0x07 - - -#define set_color(x,n) { \ - cairo_set_source_rgba(x, conf.col[n].r, conf.col[n].g, \ - conf.col[n].b, conf.col[n].a); \ - cairo_set_line_width(x, conf.col[n].w); \ -} - -typedef struct Wave { - double *d; - int samples; - int rate; -} Wave; - -typedef struct FFT { - double **amp; - double *time; - double *freq; - double max, min; - int nfreq, ntime; - char **mask; -} FFT; - -typedef struct WindowFunction { - const char *type; - double a[4]; -} WindowFunction; - -typedef struct Spectro { - const char *fname; - char *name; - unsigned char *a_spec, *a_thresh; - cairo_surface_t *m_spec, *m_thresh, *s_points; - FFT *fft; - int fft_x, fft_y, fft_w, fft_h, fft_lo, fft_hi; - double pex, tex, fex; -} Spectro; - -typedef struct RGBA { - double r, g, b, a, w; -} RGBA; - -typedef struct Config { - double thresh, spect_floor; - double hipass, lopass; - int scale; - int winlen, hop, font_size; - WindowFunction *win; - RGBA col[RGBA_LAST]; - cairo_font_face_t *font, *bfont; - char **help_cmd; - Bool long_out, layers; -} Config; - -/* main.c */ -extern int die(const char *, ...); -/* config.c */ -extern const char *configure(int, const char **); -extern int deconfigure(); -/* fft.c */ -extern FFT *create_fft(Wave *); -extern int free_fft(FFT **); -/* spectro.c */ -extern int create_spectro(FFT *, const char *); -extern int free_spectro(); -/* wave.c */ -extern Wave *create_wave(const char *); -extern int free_wave(Wave **); -/* xlib.c */ -extern int create_xlib(); -extern int free_xlib(); -extern cairo_t *xlib_context(); -extern int xlib_event_loop(); - -/* global data */ -Config conf; -Spectro *spect; - -#endif /* __FEX_H__ */ - DELETED src/fft.c Index: src/fft.c ================================================================== --- src/fft.c +++ src/fft.c @@ -1,121 +0,0 @@ -/**********************************************************************\ -* FEX - The Frequency Excursion Calculator -* -* Author: Jesse McClure, copyright 2013-2014 -* License: GPL3 -* -* 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 -* . -* -\**********************************************************************/ - -#include "fex.h" - -#define FFTW_FLAGS FFTW_FORWARD, FFTW_ESTIMATE -FFT *create_fft(Wave *wav) { - /* allocate memory */ - FFT *fft = (FFT *) calloc(1,sizeof(FFT)); - fft->nfreq = conf.winlen/2 + 1; - fft->ntime = wav->samples/conf.hop; - fft->amp = (double **) calloc(fft->ntime, sizeof(double *)); - fft->time = (double *) calloc(fft->ntime, sizeof(double)); - fft->freq = (double *) calloc(fft->nfreq, sizeof(double)); - fft->mask = (char **) calloc(fft->ntime, sizeof(char *)); - /* calculate step sizes and fill time/freq arrays */ - double nyquist = (double) wav->rate / 2000.0; - double df = nyquist / fft->nfreq; - double dt = (double)wav->samples / (double)(wav->rate * fft->ntime); - double f, t; - int i, j; - for (i = 0, f = 0.0; i < fft->nfreq; i++, f += df) fft->freq[i] = f; - for (i = 0, t = 0.0; i < fft->ntime; i++, t += dt) fft->time[i] = t; - /* prepare fftw */ - fftw_complex *in, * out; - fftw_plan p; - in = (fftw_complex *)fftw_malloc(conf.winlen * sizeof(fftw_complex)); - out = (fftw_complex *)fftw_malloc(conf.winlen * sizeof(fftw_complex)); - p = fftw_plan_dft_1d(conf.winlen, in, out, FFTW_FLAGS); - /* create windowing function */ - double window[conf.winlen]; - double *a = conf.win->a; - double wl = conf.winlen; - for (i = 0; i < conf.winlen; i++) - window[i] = a[0] - a[1] * cos(2 * M_PI * (i / (wl - 1.0))) + - a[2] * cos(2 * M_PI * (i / (wl - 1.0))) - - a[3] * cos(2 * M_PI * (i / (wl - 1.0))); - /* loop over signal */ - int pos; - for (pos = 0, j = 0; pos < wav->samples; pos += conf.hop, j++) { - fft->amp[j] = (double *) malloc(fft->nfreq * sizeof(double)); - fft->mask[j] = (char *) calloc(fft->nfreq, sizeof(char)); - /* copy windowed chunk to dat */ - for (i = 0; i < conf.winlen; i++) { - if (pos + i < wav->samples) { - in[i][0] = wav->d[pos + i] * window[i]; - in[i][1] = 0.0; - } - else { - in[i][0] = 0.0; - in[i][1] = 0.0; - goto doublebreak; - } - } - /* calculate fft & fill amp matrix */ - fftw_execute(p); - for (i = 0; i < fft->nfreq; i++) - fft->amp[j][i] = sqrt(out[i][0] * out[i][0] + - out[i][1] * out[i][1]); - } - doublebreak: - fftw_destroy_plan(p); - fftw_free(out); - fftw_free(in); - /* fill and zero unused bins */ - for ( ; j < fft->ntime; j++) { - fft->amp[j] = (double *) calloc(fft->nfreq, sizeof(double)); - fft->mask[j] = (char *) calloc(fft->nfreq, sizeof(char)); - } - /* band pass filter */ - for (i = 0; i < fft->ntime; i++) { - for (j = 0; j < fft->nfreq && fft->freq[j] < conf.hipass; j++) - fft->amp[i][j] = 0; - for (j = fft->nfreq - 1; fft->freq[j] > conf.lopass; j--) - fft->amp[i][j] = 0; - } - /* normalize, log transform, and scale to dB */ - fft->max = fft->min = 0.0; - for (i = 0; i < fft->ntime; i++) for (j = 0; j < fft->nfreq; j++) - if (fft->amp[i][j] > fft->max) fft->max = fft->amp[i][j]; - for (i = 0; i < fft->ntime; i++) for (j = 0; j < fft->nfreq; j++) { - fft->amp[i][j] = 10.0 * log10(fft->amp[i][j] / fft->max); - if (fft->amp[i][j] < fft->min && fft->amp[i][j] > -900) - fft->min = fft->amp[i][j]; - } - fft->max = 0.0; - return fft; -} - -int free_fft(FFT **fftp) { - FFT *fft = *fftp; - int i; - for (i = 0; i < fft->ntime; i++) { - free(fft->amp[i]); - free(fft->mask[i]); - } - //free(fft->amp); - //free(fft->time); - free(fft->freq); - free(fft); - return 0; -} ADDED src/fft.cpp Index: src/fft.cpp ================================================================== --- src/fft.cpp +++ src/fft.cpp @@ -0,0 +1,222 @@ + +#include "fft.hpp" + +// TODO configurable window_function +// * Maybe these should just be defined from the command line. +static double window_function[4] = { 0.5, 0.5, 0, 0 }; // hanning +/* +Hamming 0.54 0.46 0.00 0.00 +Hanning 0.50 0.50 0.00 0.00 +Blackman 0.42659 0.49656 0.076849 0.00 +Nuttall 0.355768 0.487396 0.144232 0.012604 +BlackNutt 0.3635819 0.4891775 0.1365995 0.0106411 +BlackHarris 0.35875 0.48829 0.14128 0.01168 + +*/ + +Fft::Fft(int argc, char *const *argv) : Config(argc, argv) { + song.loadFromFile(fname); + ntime = song.getSampleCount() / conf.hop; + nfreq = conf.winlen / 2 + 0.5; + time = (double *) malloc(ntime * sizeof(double)); + freq = (double *) malloc(nfreq * sizeof(double)); + amp = (double *) malloc(nfreq * ntime * sizeof(double)); + erase = (unsigned short int *) calloc(nfreq * ntime, sizeof(unsigned short int *)); + /* fill time and freq arrays */ + double nyquist = (double) song.getSampleRate() / 2000.0; + double dt = song.getDuration().asSeconds() / (double) ntime; + double df = nyquist / (double) nfreq; + int i; + time[0] = freq[0] = 0.0; + for (i = 1; i < ntime; ++i) time[i] = time[i-1] + dt; + for (i = 1; i < nfreq; ++i) freq[i] = freq[i-1] + df; + /* preare fftw */ + fftw_complex *in, *out; + fftw_plan plan; + in = (fftw_complex *) fftw_malloc(conf.winlen * sizeof(fftw_complex)); + out = (fftw_complex *) fftw_malloc(conf.winlen * sizeof(fftw_complex)); + plan = fftw_plan_dft_1d(conf.winlen, in, out, FFTW_FORWARD, FFTW_ESTIMATE); + /* windowing function */ + double *window = (double *) malloc(conf.winlen * sizeof(double)); + int t, f, pos; + for (t = 0; t < conf.winlen; ++t) + window[t] = window_function[0] - + window_function[1] * cos(2 * M_PI * t / (conf.winlen - 1.0)) + + window_function[2] * cos(4 * M_PI * t / (conf.winlen - 1.0)) - + window_function[3] * cos(6 * M_PI * t / (conf.winlen - 1.0)); + /* loop over signal */ + const sf::Int16 *data = song.getSamples(); + for (pos = 0, t = 0; pos < song.getSampleCount() && t < ntime; pos += conf.hop, ++t) { + /* copy windowed chunk to in */ + for (i = 0; i < conf.winlen; ++i) { + if (pos + i < song.getSampleCount()) + in[i][0] = data[pos + i] * window[i]; + else + in[i][0] = 0.0; + in[i][1] = 0.0; + } + /* calculate fft and fill amp */ + fftw_execute(plan); + for (f = 0; f < nfreq; ++f) + amp[nfreq * t + f] = sqrt(out[f][0] * out[f][0] + out[f][1] * out[f][1]); + } + /* zero unused bins */ + for (; t < ntime; ++t) for (f = 0; f < nfreq; ++f) + amp[nfreq * t + f] = 0; + /* drestroy and free data */ + fftw_destroy_plan(plan); + fftw_free(out); + fftw_free(in); + free(window); + /* psuedo bandpass filter */ + int f_zero, f_count = 0; + for (f = 0; freq[f] < conf.lopass; ++f); + f_zero = f; + for (; freq[f] <= conf.hipass; ++f) f_count++; + for (f = 0; f < f_count; ++f) freq[f] = freq[f+f_zero]; + freq = (double *) realloc(freq, f_count * sizeof(double)); + double *new_amp = (double *) malloc(ntime * f_count * sizeof(double)); + for (t = 0; t < ntime; ++t) for (f = 0; f < f_count; ++f) + new_amp[f_count * t + f] = amp[nfreq * t + f + f_zero]; + nfreq = f_count; + free(amp); + amp = new_amp; + /* normalize, log transform and scale to dB */ + double max = 0.0; + for (t = 0; t < ntime; ++t) for (f = 0; f < nfreq; ++f) + if (amp[nfreq * t + f] > max) max = amp[nfreq * t + f]; + for (t = 0; t < ntime; ++t) for (f = 0; f < nfreq; ++f) + amp[nfreq * t + f] = 10.0 * log10(amp[nfreq * t + f] / max); + /* prepare point and line overlays */ + lines.setPrimitiveType(sf::LinesStrip); + lines.resize(ntime); + points.setPrimitiveType(sf::Quads); + points.resize(ntime * 4); + for (t = 0; t < ntime; ++t) { + lines[t].color = conf.linesFG; + points[4*t].texCoords = sf::Vector2f(0,0); + points[4*t+1].texCoords = sf::Vector2f(64,0); + points[4*t+2].texCoords = sf::Vector2f(64,64); + points[4*t+3].texCoords = sf::Vector2f(0,64); + } + t1 = f1 = 0; + t2 = ntime; f2 = nfreq; + /* prepare sprites */ + makeSpectrogram(); + makeThreshold(); + makeOverlay(); +} + +void Fft::setCrop(sf::Vector2f a, sf::Vector2f b) { + if (a.x == -1) { /* reset */ + t1 = f1 = 0; + t2 = ntime; f2 = nfreq; + } + else { + a.y *= -1; + b.y *= -1; + t1 = (a.x < b.x ? a.x : b.x); + t2 = (a.x < b.x ? b.x : a.x); + f1 = (a.y < b.y ? a.y : b.y); + f2 = (a.y < b.y ? b.y : a.y); + } + makeThreshold(); + makeOverlay(); +} + +void Fft::makeSpectrogram() { + int t, f; + sf::Image img; + img.create(ntime, nfreq); + double dd; + unsigned short int di; + for (f = 0; f < nfreq; ++f) for (t = 0; t < ntime; ++t) { + dd = 255 * (1 + amp[nfreq * t + f] / conf.floor); + di = (dd > 255 ? 255 : (dd < 0 ? 0 : dd)); + img.setPixel(t, f, sf::Color(255, 255, 255, di)); + } + texSpec.loadFromImage(img); + texSpec.setSmooth(true); + spec = sf::Sprite(texSpec); + spec.setScale(1.0,-1.0); +} + +void Fft::makeOverlay() { +// * Change function name to "recalculate"? + int t, f, fmax, n;; + double max, pt, pf; + pathLength = timeLength = 0.0; + for (t = t1, n = 0; t < t2; ++t) { + fmax = -1; + max = std::numeric_limits::lowest(); // TODO: is this negative? Should it be? + for (f = f1; f < f2; ++f) { + if (erase[nfreq * t + f]) continue; + if (amp[nfreq * t + f] < max) continue; + max = amp[nfreq * t + (fmax=f)]; + } + if (max < -1.0 * conf.threshold) continue; + if (n) { /* increment lengths for fex calculation for all but first point */ + if (conf.log10) pathLength += hypot(log10(freq[fmax])-log10(pf),time[t]-pt); + else pathLength += hypot(freq[fmax]-pf,time[t]-pt); + timeLength += time[t]-pt; + } + pf = freq[fmax]; pt = time[t]; + lines[n].position = sf::Vector2f(t + 0.5, - fmax - 0.5); + points[4*n].position = sf::Vector2f(t, - fmax); + points[4*n+1].position = sf::Vector2f(t + 1, - fmax); + points[4*n+2].position = sf::Vector2f(t + 1, - fmax - 1); + points[4*n+3].position = sf::Vector2f(t, - fmax - 1); + ++n; + } + for (; n < ntime; ++n) { + /* set remaining lines to last point and points to off screen */ + lines[n].position = lines[n-1].position; + points[4*n].position = sf::Vector2f(-2,0); + points[4*n+1].position = sf::Vector2f(-2,0); + points[4*n+2].position = sf::Vector2f(-2,0); + points[4*n+3].position = sf::Vector2f(-2,0); + } +} + +void Fft::makeThreshold() { + int t, f; + sf::Image img; + img.create(ntime, nfreq); + for (f = f1; f < f2; ++f) for (t = t1; t < t2; ++t) + img.setPixel(t, f, sf::Color(255, 255, 255, (amp[nfreq * t + f] > - conf.threshold ? 255 : 0))); + texThresh.loadFromImage(img); + texThresh.setSmooth(true); + thresh = sf::Sprite(texThresh); + thresh.setScale(1.0,-1.0); +} + +void Fft::eraseShift() { + int t, f; + unsigned short int *a; + for (f = 0; f < nfreq; ++f) for (t = 0; t < ntime; ++t) { + a = &erase[nfreq * t + f]; + if (*a) *a |= (*a<<1); + } +} + +void Fft::eraseUndo() { + int t, f; + unsigned short int *a; + for (f = 0; f < nfreq; ++f) for (t = 0; t < ntime; ++t) { + a = &erase[nfreq * t + f]; + if (!(*a & 0xFF)) *a = (*a>>1); + } +} + +void Fft::erasePoint(int x, int y) { + if (x < ntime && y < nfreq) erase[nfreq * x + y] |= 0x01; +} + +Fft::~Fft() { + if (amp) free(amp); amp = NULL; + if (time) free(time); time = NULL; + if (freq) free(freq); freq = NULL; + if (erase) free(erase); erase = NULL; + ntime = nfreq = 0; +} + ADDED src/fft.hpp Index: src/fft.hpp ================================================================== --- src/fft.hpp +++ src/fft.hpp @@ -0,0 +1,37 @@ + +#include "config.hpp" +#include +#include +#include + +class Fft : public Config { + private: + sf::Texture texSpec, texThresh; + sf::VertexArray points, lines; + double *freq = NULL, *time = NULL, *amp = NULL; + unsigned short int *erase = NULL; + int t1, t2, f1, f2; + + protected: + sf::Sprite spec, thresh; + sf::SoundBuffer song; + int ntime, nfreq; + double pathLength, timeLength; + + void makeSpectrogram(); + void makeThreshold(); + void makeOverlay(); + void setCrop(sf::Vector2f, sf::Vector2f); + sf::FloatRect getCrop() { return sf::FloatRect(t1, f1, t2 - t1, f2 - f1); } + sf::VertexArray const &getPoints() const { return points; }; + sf::VertexArray const &getLines() const { return lines; }; + + void eraseShift(); + void erasePoint(int, int); + void eraseUndo(); + + public: + Fft(int, char *const *); + ~Fft(); +}; + DELETED src/icon.xpm Index: src/icon.xpm ================================================================== --- src/icon.xpm +++ src/icon.xpm @@ -1,261 +0,0 @@ -/* XPM */ -char *icon[] = { -/* columns rows colors chars-per-pixel */ -"64 64 191 2 ", -" c #010001", -". c #000E0F", -"X c #060904", -"o c #01071D", -"O c #1B0018", -"+ c #001412", -"@ c #310400", -"# c #3B0016", -"$ c #15002D", -"% c #120023", -"& c #05063B", -"* c #160039", -"= c #001236", -"- c #000C25", -"; c #29003A", -": c #290039", -"> c #3C003D", -", c #32003B", -"< c #2D0028", -"1 c #002827", -"2 c #003E2E", -"3 c #002A37", -"4 c #003D32", -"5 c #5A0000", -"6 c #46001E", -"7 c #5E001C", -"8 c #450008", -"9 c #6D0000", -"0 c #7B0000", -"q c #70001B", -"w c #660016", -"e c #42002D", -"r c #470022", -"t c #55002C", -"y c #5A0028", -"u c #470037", -"i c #4B003B", -"p c #4B0034", -"a c #560039", -"s c #510036", -"d c #67002A", -"f c #73002D", -"g c #750025", -"h c #6A0031", -"j c #630031", -"k c #720033", -"l c #004134", -"z c #004B3A", -"x c #004637", -"c c #010042", -"v c #110043", -"b c #13004A", -"n c #1C004A", -"m c #00124A", -"M c #0C0051", -"N c #000B5E", -"B c #050458", -"V c #170055", -"C c #001A5E", -"Z c #00145A", -"A c #250046", -"S c #24004D", -"D c #2B0048", -"F c #3B0044", -"G c #350044", -"H c #00334C", -"J c #002954", -"K c #003E54", -"L c #00325A", -"P c #002A48", -"I c #001364", -"U c #001C6B", -"Y c #001A65", -"T c #001E73", -"R c #001E7A", -"E c #000C64", -"W c #00286A", -"Q c #003369", -"! c #003D6C", -"~ c #003B63", -"^ c #002476", -"/ c #00267D", -"( c #002D7E", -") c #002C75", -"_ c #003376", -"` c #00317C", -"' c #003A79", -"] c #460041", -"[ c #004C42", -"{ c #004547", -"} c #005343", -"| c #005945", -" . c #005E4B", -".. c #004B58", -"X. c #005954", -"o. c #00525E", -"O. c #00624E", -"+. c #00694C", -"@. c #00724C", -"#. c #006651", -"$. c #006C55", -"%. c #006B5B", -"&. c #00625C", -"*. c #007257", -"=. c #00745C", -"-. c #007A5E", -";. c #007856", -":. c #004963", -">. c #004569", -",. c #005E63", -"<. c #00546C", -"1. c #005D6C", -"2. c #005361", -"3. c #004474", -"4. c #004B74", -"5. c #004279", -"6. c #004D79", -"7. c #005472", -"8. c #005579", -"9. c #005C73", -"0. c #006B66", -"q. c #00646B", -"w. c #006C6D", -"e. c #006362", -"r. c #007561", -"t. c #007C63", -"y. c #00746C", -"u. c #007C6A", -"i. c #006576", -"p. c #006C76", -"a. c #007372", -"s. c #007C73", -"d. c #00747C", -"f. c #007D7B", -"g. c #850000", -"h. c #940000", -"j. c #9D0000", -"k. c #8A0012", -"l. c #850019", -"z. c #92001A", -"x. c #A30000", -"c. c #A50800", -"v. c #B60002", -"b. c #BA0000", -"n. c #B9000E", -"m. c #BC0E00", -"M. c #A30011", -"N. c #A80019", -"B. c #B50018", -"V. c #820024", -"C. c #8C0029", -"Z. c #8E0024", -"A. c #930024", -"S. c #9F0029", -"D. c #970027", -"F. c #A40023", -"G. c #C40000", -"H. c #CA000E", -"J. c #D00000", -"K. c #DB0000", -"L. c #D6000D", -"P. c #C50012", -"I. c #CA0012", -"U. c #E30000", -"Y. c #E50009", -"T. c #EC0000", -"R. c #00825E", -"E. c #008265", -"W. c #008C65", -"Q. c #00856A", -"!. c #008A6D", -"~. c #00926C", -"^. c #00946A", -"/. c #008476", -"(. c #008D71", -"). c #00847C", -"_. c #009274", -"`. c #009578", -"'. c #00997A", -"]. c #009872", -"[. c #002F87", -"{. c #003582", -"}. c #003A82", -"|. c #003589", -" X c #004383", -".X c #004885", -"XX c #005885", -"oX c #006983", -"OX c #007D83", -"+X c #008187", -"@X c None", -/* pixels */ -"@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@XO.@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X", -"@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X2.e.@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X", -"@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@XQ <.-.@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X", -"@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X$ . !.@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X", -"@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@Xt S !.@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X", -"@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X .@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@Xe D Q.-.@X@X@X%.@X@X@X@X@X@X@X@X@X@X", -"@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@XK <.Q.r.@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@Xt z.i.~.$.Q.@X`.@X@X@X@X@X@X@X@X@X@X", -"@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X` }.-.t.@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@Xb & ' !.t.=.@XQ.@X@X@X@X@X@X@X@X@X@X", -"@X@X@XE.@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X< V.-.(.@X@XQ.@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X; _ w E.!.@X#.$.@X@X@X@X@X@X@X@X@X@X", -"@X@XC ( @X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@Xa N.` ~.#.@X!.@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X# r.D.4.(.| t.#.@X@X@X@X@X@X@X@X@X@X", -"@X@XU ^ O.@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@XG U ^ !.-.@X!.@X@X@X@X@X@X@X@X@X@X@X@X@X@X@Xe *.N 3.!.-.!.r.$.@X@X@X@X@X@X@X@X@X", -"@X@Xj I.y.!.@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@Xd J I.i.Q.@X!.@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@XE.$ 6 E._.'._._.@X@X@X@X@X@X@X@X@X", -"@X@Xu A.9.Q.@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@XO %.f [.E.Q.(.r.@X@X@X@X@X@X@X@X@X@X@X@X@X@X@XO.{ i E._.`.Q.`.-.@X@X@X@X@X@X@X@X", -"@X@X@XI L Q._.@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@XQ s.T f t.!.(.Q.@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@Xi.A E.!._.t._.E.@X@X@X@X@X@X@X@X", -"@X@X@X7.; y.'.@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@Xr.(.0.Y.r._.`.!.E.@X@X@X@X@X@X@X@X@X@X@X@XU.@X@XQ.# ' (.!.@X!.!.@X@X@X@X@X@X@X@X", -"@X@X@X<.f w.`.O.@X@X@X@X@X@X@X@X@X@X@X@X@X@X@Xv.@X#.u.b ;.!.!.!.E.@X@X@X@X@X@X@X@X@X@X@X@XJ.@X@X=.P }.Q.!.*.r.!.@X@X@X@X@X@X@X@X", -"@X@X@X=.A.3 _.r.@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X(.` o.!.!.Q.Q.@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X..n.u.(.$. .Q.@X@X@X@X@X@X@X@X", -"@X@X@X-.a B Q.Q.@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@XE.q./ E.!.t.-.@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X0.S.R.(.;.} (.@X@X@X@X@X@X@X@X", -"@X@X@XE.` F t.!.@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@XE.> t.u.=.#.@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@XX.^ R.Q.r.@X_.@X@X@X@X@X@X@X@X", -"@X@X@Xt.w.n.,.(.$.#.@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@XQ.L.q.t.$.@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X} H .Xt.Q.@X`.=.@X@X@X@X@X@X@X", -"@X@X@X@XQ.c ..(.t.$.@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@XO.b :.E.$.=.@X$.@X@X@X@X@X@X@X@X@X@X@X@X@X@X@XX.}.t.!.$.E.E.@X@X@X@X@X@X@X", -"@X@X@X@Xt..X1 !.!.=.@X@X@X@X@X@X@X@X@X@X@X@XK.@X@X@X@X@X` o Q.%._.@XQ.@X@X@X@X@X@X@X@X@XT.@X@X@X@X@Xr.Z.r.!.!.@X_.@X@X@X@X@X@X@X", -"@X@X@X@X=.Q.V ~._.=.@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@Xt.F y.r.`.@X(.@X@X@X@X@X@X@X@X@XG.@X@X@X@X@XQ.F.r.(._.@X`.@X@X@X@X@X@X@X", -"@X@X@X@X@XW.S ]._.$.@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@XE.n 0.u.!.E.E.@X@X@X@X@X@X@X@X@X@X@X@X@X@X@XQ.F =.!._.#._.@X@X@X@X@X@X@X", -"@X@X@X@X@XR.C.'._.O.@X@XO.@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X!.l.l (.Q.`.@Xt.@X@X@X@X@X@X@X@X@X@X@X@X@X@XQ.& ! !.(.=._.@X@X@X@X@X@X@X", -"@X@X@X@X@X| u f.(.O.} @X=.@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X%.= 4 Q.!.!.t.E.@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X../ t._.=.(.@XE.@X@X@X@X@X", -"@X@X@X@X@X@X* y.(.O.E.@Xt.E.@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X5.~ E._.E.(.t.@X@X@X@X@X@X@X@X@X@X@X@X@X@X@Xq.N.t._.=.(.@XE.@X@X@X@X@X", -"@X@X@X@X@X@X[ Z ~.#.'.@XQ.!.@X@X@X@X@X@X@Xx.@X@X@X@X@X@X@XE.Y W._.=._.t.@X@X@X@X@X@X@X@X@X@X@X@X@X@X@Xu.I.! _.=.(.@XE.@X@X@X@X@X", -"@X@X@X@X@X@Xw.V ^.$.`.@XE.$.@X@X@X@X@X@X@XG.@X@X@X@X@X@X@XQ.: Q.Q.E.!.!.@X@X@X@X@X@X@Xv.@X@X@X@X@X@X@Xt.^ Q W.E.~.O.t.@X@X@X@X@X", -"@X@X@X@X@X@X+XF./.r.'.@XE.@X#.@X@X@X@X@X@Xb.@X@X@X@X@X@X@X!.M.s.=.(.t.(.@Xt.@X@X@X@X@XT.@X@X@X@X@X@X@Xr.5.y Q.!._.$.E.@X@X@X@X@X", -"@X@X@X@X@X@XW.D.XXr.`.t.E.@Xr.@X@X@X@X@X@X@X@X@X@X@X@X@X@X*.7 7.=.(.@Xt.@X!.@X@X@X@X@Xb.@X@X@X@X@X@X@X@XE.k y.(.!. . .@X@X@X@X@X", -"@X@X@X@X@X@X@Xn $ t._.!.t.@XQ.@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X' o =.(.@X#.@X_.@X@X@X@X@X@X@X@X@X@X@X@X@X@XW.h w.!.E.@X@X@X@X@X@X@X", -"@X@X@X@X@X@X@XL V.q.!._.E.@XQ.@X@X@X@X@X@X@X@X@X@X@X@X@X@X@Xy.p :.(.@X@XE._.E.@X@X@X@X@X@X@X@X@X@X@X@X@XE.< Z !.-.@X@X@X@X@X@X@X", -"@X@X@X@X@X@X@Xi.] 9.Q._.Q.$.t.@X@X@X@X@X@X@X@X@X@X@X@X@X@X@XQ.S 4.(.@X=.!._.E.@X@X@X@X@X@X@X@X@X@X@X@X@Xt.3.M !.-.| @X@X@X@X@X@X", -"@X@X@X@X@X@X@Xy.s L y.!.Q.Q.O.@X@X@X@X@XU.@X@X@X@X@X@X@X@X@XE.h O !.!.(._.(.Q.@X@X@X@X@X@X@X@X@X@X@X@X@X=.oXD.(.=.#.@X@X@X@X@X@X", -"@X@X@X@X@X@X@X-.O A ( !.Q.(.| @X@X@X@X@XU.@X@X@X@X@X@X@X@X@XE.r i E._._.Q.(.Q.@X@X@Xb.@X@X@X@X@X@X@X@X@X@XQ.B.d.%.-.@X@X@X@X@X@X", -"@X@X@X@X@X@X@X@XXXB., E.!.!.| @X@X@X@X@X@X@X@X@X@X@X@X@X@X@Xt.6.F Q.!.!.| !.Q.@X@X@Xb.@X@X@X@X@X@X@X@X@X@X@.G o.=.E.@X@X@X@X@X@X", -"@X@X@X@X@X@X@X@X).D.P.e._.Q.| @X@X@X@X@X@X@X@X@X@X@X@X@X@X@Xa.q 8.Q.Q.@XQ.Q.@X@X@Xh.@X@X@X@X@X@X@X@X@X@X@X>.% t.!.@X@X@X@X@X@X", -"@X@X@X@X@X@X@X@XR.V > ' !.Q. . @X@X@X@X@X@X@X@X@X@X@X@X@X@X@X+.= ' E.!.@X!.#.@X@X@X9 @X@X@X@X@X@X@X@X@X@X@Xd.v R.!.@X@X@X@X@X@X", -"@X@X@X@X@X@X@X@X@X` N : E.t.O. @X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X8.k.t._.@XQ.@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@Xd.h Q._.=.@X@X@X@X@X", -"@X@X@X@X@X@X@X@X@Xr.X.j r.E.*. @X@X0 @X@X@X@X@X@X@X@X@X@X@X@X`.S.W._.@XQ.@X@X@X9 @X@X@X@X@X@X@X@X@X@X@X@X!.d p.!.Q.@X@X@X@X@X", -"@X@X@X@X@X@X@X@X@X} u.V.0.Q.Q.X @X@Xj.@X@X@X@X@X@X@X@X@X@X@X@XE.E t.(.@X!.@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@XW.: 7.(.=.@X@X@X@X@X", -"@X@X@X@X@X@X@X@X@X@X(.k <.!.].+ @X@Xb.@X@X@X@X@X@X@X@X@X@X@X@X@X* oX(.@X!.@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X= - !.#.@X@X@X@X@X", -"@X@X@X@X@X@X@X@X@X@XQ.Z U !.'.z + @Xg.@X@X@X@X@X@X@X@X@X@X@X@X@X2 X!.@X_.@X@X@Xj.@X@X@X@X@X@X@X@X@X@X@X@X@X2.8 !.z @X@X@X@X@X", -"@X@X@X@X@X@X@X@X@X@Xr.3.k !.'.t.1 @X@X@X@X@X@X@X@X@X@X@X@X@X@X@Xe.g Q.@X_.@X@X@XJ.@X@X@X@X@X@X@X@X@X@X@X@X@Xd.O _.@X@X@X@X@X@X", -"@X@X@X@X@X@X@X@X@X@X@Xu.N.u.'.'.2 @X@X@X@X@X@X@X@X@X@X@X@X@X@X@X).B.t.@X(.@X@X@Xg.@X@X@X@X@X@X@X@X@X@X@X@X@X_.S ^.@X @X@X@X@X", -"@X@X@X@X@X@X@X@X@X@X@X!.k 7.'._.l @X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X%.F 0.@X!.@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@XE.I Q.@X@X @X@X@X", -"@X@X@X@X@X@X@X@X@X@X@X'.* J `.!.l @Xh.@X@X@X@X@X@X@X@X@X@X@X@X@X@X@XA >.@XQ.@X@X5 @X@X@X@X@X@X@X@X@X@X@X@X@X@X;.r OX@X @X@X@X", -"@X@X@X@X@X@X@X@X@X@X@XE.4.M /.!.2 @XK.@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X1 U =.Q.@X@X9 @X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@ X@X @X@X@X", -"@X@X@X@X@X@X@X@X@X@X@X@Xi.A.a.!.4 @Xx.@X@X@X@X@X@X@X@X@X@X@X@X@X@X@Xi.A.r.Q.@X@X0 @X@X@X@X@X@X@X@X@X@X@X@X@X@X@X:.y X @X@X", -"@X@X@X@X@X@X@X@X@X@X@X@Xu.H.C ~.2 @X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X/.H.3.Q.@X@Xg.@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X+XI.m @X@X", -"@X@X@X@X@X@X@X@X@X@X@X@X$.Z B ^.l @X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X*.b [.y.@X@X0 @X@X@X@X@X@X@X@X@X@X@X@X@X@X@Xw.D W @X@X", -"@X@X@X@X@X@X@X@X@X@X@X@X@X XF.).l 9 @X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X( I.&.@X@X9 @X@X@X@X@X@X@X@X@X@X@X@X@X@X@X+.V N. @X ", -"@X@X@X@X@X@X@X@X@X@X@X@X@X!.I.|.x 9 @X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@XQ.I.U o @X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@Xz M. @X ", -"@X@X@X@X@X@X@X@X@X@X@X@X@X^.b S z 0 @X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X(.{.i o h.@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@Xa.Y @X@X", -"@X@X@X@X@X@X@X@X@X@X@X@X@X_.4.Y.5.c.@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X_.7.H.: l.@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X/.H & . @X@X", -"@X@X@X@X@X@X@X@X@X@X@X@X@X@Xa.C.[.m.@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X-.i B u @X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X=.&.R X @X@X", -"@X@X@X@X@X@X@X@X@X@X@X@X@X@Xe.U P.@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X+.` A.l.@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X[ h @X@X@X", -"@X@X@X@X@X@X@X@X@X@X@X@X@X@X$.<.Y.~ @X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@Xy.n.k.@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@Xz I.X @X@X@X", -"@X@X@X@X@X@X@X@X@X@X@X@X@X@X@XK R @X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@XW.T @X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X..u + @X@X@X", -"@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X) @X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@XE.U @X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@Xc V.@X@X@X", -"@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X9.Y @X@X@X", -"@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X", -"@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X@X" -}; DELETED src/spectro.c Index: src/spectro.c ================================================================== --- src/spectro.c +++ src/spectro.c @@ -1,213 +0,0 @@ -/**********************************************************************\ -* FEX - The Frequency Excursion Calculator -* -* Author: Jesse McClure, copyright 2013-2014 -* License: GPL3 -* -* 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 -* . -* -\**********************************************************************/ - -#include "fex.h" - -#define set_color(x,n) { \ - cairo_set_source_rgba(x, conf.col[n].r, conf.col[n].g, \ - conf.col[n].b, conf.col[n].a); \ - cairo_set_line_width(x, conf.col[n].w); \ -} - -int create_spectro(FFT *fft, const char *fname) { - spect = (Spectro *) calloc(1, sizeof(Spectro)); - /* names */ - spect->fname = fname; - char *c = strrchr(spect->fname,'/'); - if (c && (++c)) spect->name = strdup(c); - else spect->name = strdup(fname); - if ( (c=strrchr(spect->name,'.')) ) *c = '\0'; - /* fft */ - spect->fft = fft; - spect->fft_w = fft->ntime; - spect->fft_h = fft->nfreq; - /* set bounds */ - int i; - for (i = 0; i < spect->fft->nfreq && - spect->fft->freq[i] < conf.hipass; i++); - spect->fft_lo = spect->fft_y = i; - for (i++; i < spect->fft->nfreq && - spect->fft->freq[i] < conf.lopass; i++); - spect->fft_hi = i; - spect->fft_h = i - spect->fft_y; - /* cairo_surfaces */ - spectro_spec(); - spectro_thresh(); - spectro_points(); - /* xlib */ - create_xlib(); - return 0; -} - -int free_spectro() { - cairo_surface_destroy(spect->m_spec); - cairo_surface_destroy(spect->m_thresh); - cairo_surface_destroy(spect->s_points); - free_xlib(); - free(spect->name); - free(spect); - return 0; -} - -int img_draw() { - cairo_surface_t *img; - img = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, spect->fft_w*conf.scale, spect->fft_h*conf.scale * 4); - cairo_t *ctx; - ctx = cairo_create(img); - cairo_scale(ctx,conf.scale,-4.0 * conf.scale); - cairo_translate(ctx, 0, -1.0 * spect->fft_h); - cairo_set_source_rgba(ctx,1.0,1.0,1.0,1.0); - cairo_rectangle(ctx,0,0,spect->fft_w,spect->fft_h); - cairo_fill(ctx); - set_color(ctx,RGBA_SPECT); - cairo_mask_surface(ctx,spect->m_spec,0,0); - cairo_surface_write_to_png(img,"/tmp/img1.png"); - cairo_destroy(ctx); - cairo_surface_destroy(img); - img = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, spect->fft_w*conf.scale, spect->fft_h*conf.scale * 4); - ctx = cairo_create(img); - cairo_scale(ctx,conf.scale,-4.0 * conf.scale); - cairo_translate(ctx, 0, -1.0 * spect->fft_h); - cairo_set_source_rgba(ctx, conf.col[RGBA_THRESH].r, conf.col[RGBA_THRESH].g, - conf.col[RGBA_THRESH].b, 0.8); - cairo_mask_surface(ctx,spect->m_thresh,0,0); - cairo_surface_write_to_png(img,"/tmp/img2.png"); - cairo_destroy(ctx); - cairo_surface_destroy(img); - img = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, spect->fft_w*conf.scale, spect->fft_h*conf.scale * 4); - ctx = cairo_create(img); - cairo_scale(ctx, 1.0, -4.0); - cairo_translate(ctx, 0, -1.0 * spect->fft_h * conf.scale); - cairo_set_source_surface(ctx,spect->s_points, 0, 0); - cairo_paint_with_alpha(ctx, 0.8); - cairo_surface_write_to_png(img,"/tmp/img3.png"); - cairo_destroy(ctx); - cairo_surface_destroy(img); - return 0; -} - -int spectro_draw() { - cairo_t *c = xlib_context(); - cairo_set_source_rgba(c,1.0,1.0,1.0,1.0); - cairo_rectangle(c,0,0,spect->fft_w,spect->fft_h); - cairo_fill(c); - set_color(c,RGBA_SPECT); - cairo_mask_surface(c,spect->m_spec,0,0); - if (conf.layers) { - set_color(c,RGBA_THRESH); - cairo_mask_surface(c,spect->m_thresh,0,0); - cairo_scale(c,1.0/conf.scale,1.0/conf.scale); - cairo_set_source_surface(c,spect->s_points,0,0); - cairo_paint(c); - } - cairo_destroy(c); - return 0; -} - -int spectro_points() { - if (spect->s_points) cairo_surface_destroy(spect->s_points); - spect->s_points = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, - spect->fft_w * conf.scale, spect->fft_h * conf.scale); - cairo_t *p = cairo_create(spect->s_points); - cairo_t *l = cairo_create(spect->s_points); - set_color(p,RGBA_POINTS); - set_color(l,RGBA_LINES); - int i, j, f; - double lt = spect->fft->time[0], lf = spect->fft->freq[0]; - spect->pex = 0.0; - spect->tex = 0.0; - /* loop through time bins */ - for (i = spect->fft_x; i < spect->fft_w + spect->fft_x; i++) { - /* find maximum (non masked) frequency in time bin */ - for (f = 0, j = spect->fft_y; j < spect->fft_h+spect->fft_y; j++) { - if (spect->fft->mask[i][j]) continue; - if (spect->fft->amp[i][j] > spect->fft->amp[i][f] || !f) - f = j; - } - /* add points and do calculations if f is above threshold */ - if (f > 0 && spect->fft->amp[i][f] > conf.thresh) { - if (lt != spect->fft->time[0]) { - spect->pex += sqrt( - (spect->fft->freq[f] - lf) * (spect->fft->freq[f] - lf) + - (spect->fft->time[i] - lt) * (spect->fft->time[i] - lt) ); - spect->tex += spect->fft->time[i] - lt; - } - lt = spect->fft->time[i]; - lf = spect->fft->freq[f]; - cairo_line_to(l, - (i - spect->fft_x) * conf.scale + conf.scale / 2, - (f - spect->fft_y) * conf.scale + conf.scale / 2); - cairo_new_sub_path(p); - cairo_arc(p, - (i - spect->fft_x) * conf.scale + conf.scale / 2, - (f - spect->fft_y) * conf.scale + conf.scale / 2, - conf.col[RGBA_POINTS].w,0,2*M_PI); - } - spect->fex = spect->pex / spect->tex; - } - cairo_fill(p); - cairo_stroke(l); - cairo_destroy(p); - cairo_destroy(l); - return 0; -} - -int spectro_spec() { - if (spect->m_spec) cairo_surface_destroy(spect->m_spec); - if (spect->a_spec) free(spect->a_spec); - int i, j, stride; - stride = cairo_format_stride_for_width(CAIRO_FORMAT_A8, spect->fft_w); - spect->a_spec = (unsigned char *) calloc(stride,spect->fft_h); - unsigned char *a = NULL; - for (j = spect->fft_y; j < spect->fft_h + spect->fft_y; j++) { - a = spect->a_spec + (j - spect->fft_y) * stride; - for (i = spect->fft_x; i < spect->fft_w + spect->fft_x; i++, a++) { - *a = 255 - (unsigned char) 255 * ( - ( (spect->fft->amp[i][j] - conf.spect_floor) >= 0) ? - spect->fft->amp[i][j] / conf.spect_floor : 1); - } - } - spect->m_spec = cairo_image_surface_create_for_data(spect->a_spec, - CAIRO_FORMAT_A8, spect->fft_w, spect->fft_h, stride); - return 0; -} - -int spectro_thresh() { - if (spect->m_thresh) cairo_surface_destroy(spect->m_thresh); - if (spect->a_thresh) free(spect->a_thresh); - int i, j, stride; - stride = cairo_format_stride_for_width(CAIRO_FORMAT_A8, spect->fft_w); - spect->a_thresh = (unsigned char *) calloc(stride, spect->fft_h); - unsigned char *a = NULL; - for (j = spect->fft_y; j < spect->fft_h + spect->fft_y; j++) { - a = spect->a_thresh + (j - spect->fft_y) * stride; - for (i = spect->fft_x; i < spect->fft_w + spect->fft_x; i++, a++) { - if (spect->fft->mask[i][j]) *a = 0; - else if (spect->fft->amp[i][j] > conf.thresh) *a = 255; - else *a = 0; - } - } - spect->m_thresh = cairo_image_surface_create_for_data(spect->a_thresh, - CAIRO_FORMAT_A8, spect->fft_w, spect->fft_h, stride); - return 0; -} - ADDED src/spectrogram.cpp Index: src/spectrogram.cpp ================================================================== --- src/spectrogram.cpp +++ src/spectrogram.cpp @@ -0,0 +1,265 @@ + +#include "spectrogram.hpp" +#include + +Spectrogram::Spectrogram(int argc, char *const *argv) : Fft(argc, argv) { +// if (getenv("FEX_FULLSCREEN")) + win.create(sf::VideoMode::getDesktopMode(), "Fex", sf::Style::Fullscreen); +// else +// win.create(sf::VideoMode(640,480), "Fex"); + aspect = (ntime * win.getSize().y * conf.hop) / (float) (nfreq * win.getSize().x * conf.winlen); + view.reset(sf::FloatRect(0, -nfreq * (1 + aspect)/2.0, ntime, nfreq * aspect)); + win.setView(view); + spec.setColor(conf.specFG); + sf::RenderTexture render_ball; + render_ball.setSmooth(true); + render_ball.create(64,64); + sf::CircleShape dot(32); + dot.setFillColor(conf.pointBG); + dot.setOutlineColor(conf.pointFG); + dot.setOutlineThickness(-8); + render_ball.draw(dot); + ball = render_ball.getTexture(); + back.setSize(sf::Vector2f(ntime,-nfreq)); + back.setFillColor(conf.specBG); + mouse.x = ntime / 2; mouse.y = - nfreq / 2; + crop1 = sf::Vector2f(-1, -1); + eraser.setSize(sf::Vector2f(4, 18)); + eraser.setFillColor(sf::Color(255,200,0,200)); + eraser.setPosition(0, 0); + eraser.setOrigin(2, 10); +} + +Spectrogram::~Spectrogram() { } + +int Spectrogram::mainLoop() { + sf::Event ev; + while (win.isOpen() && win.waitEvent(ev)) { + evHandler(ev); + while (win.pollEvent(ev)) evHandler(ev); + drawMain(); + win.display(); + char out[256]; + snprintf(out,255,"%s - (%0.3fs, %0.3fKHz) FE: %lf ", + name, + song.getDuration().asSeconds() * mouse.x / ntime, + conf.lopass - (conf.hipass - conf.lopass) * mouse.y / nfreq, + 1234.5 + ); + win.setTitle(sf::String(out)); + } + printf("%lf\t%lf\t%lf\n", pathLength, timeLength, pathLength / timeLength); + return 0; +} + +void Spectrogram::evHandler(sf::Event ev) { + switch (ev.type) { + case sf::Event::Closed: evClose(ev); break; + case sf::Event::KeyPressed: evKeyPress(ev); break; + case sf::Event::KeyReleased: evKeyRelease(ev); break; + case sf::Event::MouseMoved: evMouseMove(ev); break; + case sf::Event::MouseButtonPressed: evMouseButton(ev); break; + case sf::Event::MouseWheelScrolled: evMouseWheel(ev); break; + case sf::Event::Resized: evResize(ev); break; + } +} + +void Spectrogram::drawMain() { + win.clear(conf.winBG); + win.draw(back); + win.draw(spec); + thresh.setColor(conf.threshFG); + if (toggle.overlay) { + win.draw(thresh); + win.draw(getPoints(), &ball); + win.draw(getLines()); + if (toggle.cursor) { + if (crop1.x > 0) drawCursor(crop1.x, crop1.y); + drawCursor(mouse.x, mouse.y); + } + if (toggle.eraser) + win.draw(eraser); + } +} + +void Spectrogram::drawCursor(float x, float y) { + sf::RectangleShape lineV(sf::Vector2f(1, nfreq)); + lineV.setFillColor(conf.cursorFG); + lineV.setPosition(view.getViewport().left + x, -nfreq); + win.draw(lineV); + sf::RectangleShape lineH(sf::Vector2f(ntime, 1)); + lineH.setFillColor(conf.cursorFG); + lineH.setPosition(0,view.getViewport().top + y); + win.draw(lineH); +} + +void Spectrogram::listen(float speed) { + sf::Sound snd(song); + snd.play(); + snd.setPitch(speed); + while(snd.getStatus() == 2) { + sf::RectangleShape line(sf::Vector2f(10, nfreq)); + line.setFillColor(sf::Color(0,255,0,120)); + line.setPosition(ntime * (snd.getPlayingOffset() / song.getDuration()), -nfreq); + drawMain(); + win.draw(line); + win.display(); + } +} + +void Spectrogram::evClose(sf::Event ev) { +} + +void Spectrogram::evKeyPress(sf::Event ev) { + if (ev.key.code == sf::Keyboard::LShift) toggle.cursor = !toggle.cursor; + if (ev.key.code == sf::Keyboard::RShift) toggle.cursor = !toggle.cursor; + if (ev.key.code == sf::Keyboard::LAlt) toggle.eraser = !toggle.eraser; + if (ev.key.code == sf::Keyboard::RAlt) toggle.eraser = !toggle.eraser; + if (ev.key.control) switch (ev.key.code) { + case sf::Keyboard::Space: toggle.overlay = !toggle.overlay; break; + case sf::Keyboard::Right: conf.floor -= 0.25; makeSpectrogram(); break; + case sf::Keyboard::Left: conf.floor += 0.25; makeSpectrogram(); break; + case sf::Keyboard::Up: conf.threshold -= 0.25; makeOverlay(); break; + case sf::Keyboard::Down: conf.threshold += 0.25; makeOverlay(); break; + case sf::Keyboard::Q: win.close(); break; + case sf::Keyboard::Num1: listen(1.0); break; + case sf::Keyboard::Num2: listen(0.5); break; + case sf::Keyboard::Num3: listen(0.333); break; + case sf::Keyboard::Num4: listen(0.25); break; + case sf::Keyboard::Num5: listen(0.2); break; + } + else if (ev.key.alt) switch (ev.key.code) { + case sf::Keyboard::Space: toggle.eraser = !toggle.eraser; break; + } + if (ev.key.shift) switch (ev.key.code) { + case sf::Keyboard::Space: toggle.cursor = !toggle.cursor; break; + } +} + +void Spectrogram::evKeyRelease(sf::Event ev) { + if (ev.key.code == sf::Keyboard::LShift) toggle.cursor = !toggle.cursor; + if (ev.key.code == sf::Keyboard::RShift) toggle.cursor = !toggle.cursor; + if (ev.key.code == sf::Keyboard::LAlt) toggle.eraser = !toggle.eraser; + if (ev.key.code == sf::Keyboard::RAlt) toggle.eraser = !toggle.eraser; +} + +void Spectrogram::evResize(sf::Event ev) { + aspect = (ntime * win.getSize().y * conf.hop) / (float) (nfreq * win.getSize().x * conf.winlen); +} + +void Spectrogram::evMouseMove(sf::Event ev) { + sf::Vector2f prev = mouse; + mouse = win.mapPixelToCoords(sf::Vector2i(ev.mouseMove.x,ev.mouseMove.y)); + if (toggle.overlay && toggle.cursor) { + // + } + else if (toggle.overlay && toggle.eraser) { + if (sf::Mouse::isButtonPressed(sf::Mouse::Left) && toggle.eraser) erase(); + } + else { + if (sf::Mouse::isButtonPressed(sf::Mouse::Right)) { + view.setSize(view.getSize().x + prev.x - mouse.x, view.getSize().y + prev.y - mouse.y); + view.move((prev.x - mouse.x)/2.0, (prev.y - mouse.y)/2.0); + } + if (sf::Mouse::isButtonPressed(sf::Mouse::Left)) { + view.move(prev.x - mouse.x, prev.y - mouse.y); + } + win.setView(view); + } + mouse = win.mapPixelToCoords(sf::Vector2i(ev.mouseMove.x,ev.mouseMove.y)); + float in_bounds = 1.0; + if (mouse.x < 0) in_bounds = mouse.x = 0.0; + else if (mouse.x > ntime) in_bounds = mouse.x = ntime; + if (mouse.y > 0) in_bounds = mouse.y = 0.0; + else if (mouse.y < - nfreq) in_bounds = mouse.y = - nfreq; + if (in_bounds == 1.0) eraser.setPosition(mouse); + else eraser.setPosition(sf::Vector2f(-ntime,nfreq)); +} + +void Spectrogram::erase() { + sf::FloatRect rect = eraser.getGlobalBounds(); + sf::Transform t = eraser.getInverseTransform(); + sf::Vector2f point; + int i, j; + for (i = rect.left - 0.5; i < rect.left + rect.width + 1; ++i) { + for (j = rect.top - 0.5; j < rect.top + rect.height + 1; ++j) { + point = t.transformPoint(i + 0.5, j - 0.5); + if (point.x > -0.25 && point.x < 4.25 && point.y > -0.25 && point.y < 18.25) + erasePoint(i, -j); + } + } + makeOverlay(); +} + +void Spectrogram::evMouseButton(sf::Event ev) { + sf::FloatRect rect; + if (toggle.overlay && toggle.cursor) switch (ev.mouseButton.button) { + /* set a crop window: requires 2 presses */ + case sf::Mouse::Button::Left: + if (crop1.x < 0) crop1 = mouse; + else { setCrop(crop1, mouse); crop1.x = -1; } + break; + /* zoom to fit crop area to window */ + case sf::Mouse::Button::Middle: + rect = getCrop(); + rect.top -= rect.height * (1 + aspect) / 2.0; + rect.height *= aspect; + view.reset(rect); + win.setView(view); + break; + /* reset crop to full song */ + case sf::Mouse::Button::Right: + crop1.x = -1; + setCrop(crop1, mouse); + break; + } + else if (toggle.overlay && toggle.eraser) switch (ev.mouseButton.button) { + case sf::Mouse::Button::Left: if (toggle.eraser) erase(); break; + } + else switch (ev.mouseButton.button) { + /* NOTE: left and right are handled in evMouseMove */ + /* zoom to fit song to window */ + case sf::Mouse::Button::Middle: + view.reset(sf::FloatRect(0, -nfreq * (1 + aspect)/2.0, ntime, nfreq * aspect)); + win.setView(view); + break; + } +} + +void Spectrogram::evMouseWheel(sf::Event ev) { + bool vert = (ev.mouseWheelScroll.wheel == 0); + float dx = ev.mouseWheelScroll.delta; + if (toggle.overlay && toggle.cursor) { + // TODO: anything here? Probably not. + } + if (toggle.overlay && toggle.eraser) { + /* rotate */ + if (!vert) { eraser.rotate(-dx); return; } + /* or scale */ + sf::Vector2f scale = eraser.getScale(); + float r = eraser.getRotation(); + if (r < 30 || r > 330 || (r > 150 && r < 210) ) + scale.y += 0.008 * dx; + else if ( (r > 60 && r < 120) || (r > 240 && r < 300) ) + scale.x += 0.008 * dx; + else { + scale.x += 0.004 * dx; + scale.y += 0.004 * dx; + } + if (scale.x < 0.5) scale.x = 0.5; + else if (scale.x > 5.0) scale.x = 5.0; + if (scale.y < 0.5) scale.y = 0.5; + else if (scale.y > 5.0) scale.y = 5.0; + eraser.setScale(scale); + } + /* No modifier wheel movements are for zooming: */ + else if (vert) { + // TODO: make 0.0075 step size customizable? + float vx = view.getSize().x / ntime, vy = view.getSize().y / nfreq; + if (dx < 0 && vx > 1.20 && vy > 1.20) return; + if (dx > 0 && vx < 0.01 && vy > 0.01) return; + view.zoom(1.0 - 0.0075 * dx); + win.setView(view); + } +} + ADDED src/spectrogram.hpp Index: src/spectrogram.hpp ================================================================== --- src/spectrogram.hpp +++ src/spectrogram.hpp @@ -0,0 +1,39 @@ + +#include "fft.hpp" +#include +#include +#include + +class Spectrogram : public Fft { + private: + sf::RenderWindow win; + sf::View view; + sf::Vector2f mouse, crop1; + sf::RectangleShape back; + sf::Texture ball; + sf::RectangleShape eraser; + bool mod_ctrl, mod_shift, mod_alt; + float aspect; + + void drawMain(); + void drawCursor(float, float); + void drawHud(); + void erase(); + + void checkModKeys(); + void evHandler(sf::Event); + void evClose(sf::Event); + void evKeyPress(sf::Event); + void evKeyRelease(sf::Event); + void evMouseButton(sf::Event); + void evMouseMove(sf::Event); + void evMouseWheel(sf::Event); + void evResize(sf::Event); + protected: + void listen(float=1.0); + public: + int mainLoop(); + Spectrogram(int, char *const *); + ~Spectrogram(); +}; + DELETED src/wave.c Index: src/wave.c ================================================================== --- src/wave.c +++ src/wave.c @@ -1,65 +0,0 @@ -/**********************************************************************\ -* FEX - The Frequency Excursion Calculator -* -* Author: Jesse McClure, copyright 2013-2014 -* License: GPL3 -* -* 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 -* . -* -\**********************************************************************/ - -#include "fex.h" - - -Wave *create_wave(const char *fname) { - Wave *w = (Wave *) calloc(1,sizeof(Wave)); - SF_INFO *winfo; - SNDFILE *wfile = NULL; - winfo = (SF_INFO *) calloc(1, sizeof(SF_INFO)); - wfile = sf_open(fname, SFM_READ, winfo); - w->samples = winfo->frames; - w->rate = winfo->samplerate; - w->d = (double *) calloc(w->samples+1, sizeof(double)); - sf_count_t n; - if (winfo->channels == 1) { - n = sf_readf_double(wfile, w->d, w->samples); - } - else { /* average over channels */ - double *multi = calloc((w->samples+1)*winfo->channels, sizeof(double)); - n = sf_readf_double(wfile, multi, w->samples * winfo->channels); - int i, nframe; - double mix; - for (nframe = 0; nframe < w->samples; nframe++) { - mix = 0.0; - for (i = 0; i < winfo->channels; i++) - mix += multi[nframe * winfo->channels + i]; - w->d[nframe] = mix / winfo->channels; - } - free(multi); - } - if (n != w->samples) - fprintf(stderr,"Error reading \"%s\"\n\t" - "\t%d samples read of\n\t%d reported size\n", - fname, (int) n, w->samples); - sf_close(wfile); - return w; -} - -int free_wave(Wave **wp) { - Wave *w = *wp; - free(w->d); - free(w); - return 0; -} DELETED src/xlib.c Index: src/xlib.c ================================================================== --- src/xlib.c +++ src/xlib.c @@ -1,169 +0,0 @@ -/**********************************************************************\ -* FEX - The Frequency Excursion Calculator -* -* Author: Jesse McClure, copyright 2013-2014 -* License: GPL3 -* -* 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 -* . -* -\**********************************************************************/ - -#include "fex.h" - -#define MODE_NULL 0x00 -#define MODE_ERASE 0x01 -#define MODE_CROP 0x02 - -#define EVENT_MASK ExposureMask | ButtonPressMask | KeyPressMask | \ - StructureNotifyMask - -/* spectro.c */ -extern int img_draw(); -extern int spectro_draw(); -extern int spectro_points(); -extern int spectro_spec(); -extern int spectro_thresh(); - -static void buttonpress(XEvent *); -static void clientmessage(XEvent *); -static void configurenotify(XEvent *); -static void expose(XEvent *); -static void keypress(XEvent *); -static void motionnotify(XEvent *); - -static int crop(int, int); -static int erase(int, int); -static int eraser_cursor(int, int); -static int move(double, double); -static int play(float); -static int pt_line(double, double); -static int screenshot(); -static int sp_floor(double); -static int threshold(double); -static int zoom(double); - -static Display *dpy; -static int scr; -static unsigned int ww, wh, mx, my; -static GC gc; -static Window root, win; -static Pixmap buf; //, ibuf, sbuf; -static Atom WM_DELETE_WINDOW; -//static cairo_t *ictx, *sctx; -static Bool running = True; -static double xsc = 1.0, ysc = 1.0, xoff = 0.0, yoff = 0.0; -static int mode = 0, ew = 31, eh = 64; -static char e_col[2][8]; -static void (*handler[LASTEvent])(XEvent *) = { - [ButtonPress] = buttonpress, - [ClientMessage] = clientmessage, - [ConfigureNotify] = configurenotify, - [Expose] = expose, - [KeyPress] = keypress, - [MotionNotify] = motionnotify, -}; - -#include "xlib_toolwin.c" -#include "xlib_actions.c" -#include "xlib_events.c" - -int create_xlib() { - if (!setlocale(LC_CTYPE,"")) die("unable to set locale"); - if (!XSupportsLocale()) die("unsupported locale"); - if (!XSetLocaleModifiers("")) die("unable to set locale modifiers"); - if ( !(dpy=XOpenDisplay(0x0)) ) die("unable to open display"); - scr = DefaultScreen(dpy); - root = DefaultRootWindow(dpy); - gc = DefaultGC(dpy,scr); - ww = DisplayWidth(dpy,scr); - wh = DisplayHeight(dpy,scr); - /* create windows */ - buf = XCreatePixmap(dpy, root, ww, wh, DefaultDepth(dpy,scr)); - win = XCreateSimpleWindow(dpy,root,0,0,(ww*=0.85),(wh*=0.85),0,0, 0); - XSelectInput(dpy, win, EVENT_MASK | SubstructureRedirectMask | - PointerMotionMask); - XStoreName(dpy, win, "FEX: Frequency Excursion Calculator"); - XClassHint *hint = XAllocClassHint(); - hint->res_name = "FEX"; - hint->res_class = "FEX"; - XSetClassHint(dpy, win, hint); - WM_DELETE_WINDOW = XInternAtom(dpy, "WM_DELETE_WINDOW", False); - XSetWMProtocols(dpy, win, &WM_DELETE_WINDOW, 1); - #include "icon.xpm" - Pixmap image, shape; - XWMHints *hints; - XpmCreatePixmapFromData(dpy, win, icon, &image, &shape, NULL); - hints = XAllocWMHints(); - hints->flags = IconPixmapHint | IconMaskHint; - hints->icon_pixmap = image; - hints->icon_mask = shape; - XSetWMHints(dpy, win, hints); - XFree(hints); - /* set up eraser / crop colors */ - sprintf(e_col[0],"#%02hhX%02hhX%02hhX", - (unsigned char) conf.col[RGBA_ERASE1].r * 255, - (unsigned char) conf.col[RGBA_ERASE1].g * 255, - (unsigned char) conf.col[RGBA_ERASE1].b * 255); - sprintf(e_col[1],"#%02hhX%02hhX%02hhX", - (unsigned char) conf.col[RGBA_ERASE2].r * 255, - (unsigned char) conf.col[RGBA_ERASE2].g * 255, - (unsigned char) conf.col[RGBA_ERASE2].b * 255); - char c_col[8]; - XColor c; - sprintf(c_col,"#%02hhX%02hhX%02hhX", - (unsigned char) conf.col[RGBA_CROP].r * 255, - (unsigned char) conf.col[RGBA_CROP].g * 255, - (unsigned char) conf.col[RGBA_CROP].b * 255); - XAllocNamedColor(dpy,DefaultColormap(dpy,scr),c_col,&c,&c); - XSetLineAttributes(dpy, gc, conf.col[RGBA_CROP].w, LineSolid, - CapButt, JoinRound); - XSetForeground(dpy, gc, c.pixel); - toolwin_create(); - spectro_draw(); - XSetWindowBackgroundPixmap(dpy, win, buf); - return 0; -} - -int free_xlib() { - XUndefineCursor(dpy, win); - toolwin_destroy(); - XFlush(dpy); - XCloseDisplay(dpy); - return 0; -} - -cairo_t *xlib_context() { - cairo_surface_t *t = cairo_xlib_surface_create(dpy, buf, - DefaultVisual(dpy,scr), ww, wh); - cairo_t *c = cairo_create(t); - cairo_surface_destroy(t); - cairo_translate(c,0,wh * ysc); - cairo_scale(c, (ww * xsc)/ (float) spect->fft_w, - -1.0 * (wh * ysc) / (float) spect->fft_h); - cairo_translate(c, xoff, yoff); - return c; -} - -int xlib_event_loop() { - XMapWindow(dpy, win); - XMapWindow(dpy, info->win); - XEvent ev; - while (running && !XNextEvent(dpy,&ev)) - if (ev.type < LASTEvent && handler[ev.type]) - handler[ev.type](&ev); - return 0; -} - - DELETED src/xlib_actions.c Index: src/xlib_actions.c ================================================================== --- src/xlib_actions.c +++ src/xlib_actions.c @@ -1,288 +0,0 @@ -/**********************************************************************\ -* FEX - The Frequency Excursion Calculator -* -* Author: Jesse McClure, copyright 2013-2014 -* License: GPL3 -* -* 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 -* . -* -\**********************************************************************/ - - -int crop(int x, int y) { - int x1 = x, y1 = y, x2, y2, t; - XCopyArea(dpy, win, buf, gc, 0, 0, ww, wh, 0, 0); - XEvent e; - XGrabPointer(dpy, win, True, PointerMotionMask | ButtonPressMask, - GrabModeAsync, GrabModeAsync, None, None, CurrentTime); - while (e.type != ButtonPress) { - XMaskEvent(dpy, PointerMotionMask | ButtonPressMask | - KeyPressMask, &e); - if (e.type == KeyPress) break; - x2 = e.xmotion.x; - y2 = e.xmotion.y; - if (x2 > ww) x2 = ww; - if (y2 > wh) y2 = wh; - mx = spect->fft_w * x2/(ww*xsc) - 1.0 * xoff + spect->fft_x; - my = spect->fft_h * (1.0-y2/(wh*ysc)) - 1.0 * yoff + spect->fft_y; - XCopyArea(dpy, buf, win, gc, 0, 0, ww, wh, 0, 0); - XDrawLine(dpy, win, gc, x2, 0, x2, wh); - XDrawLine(dpy, win, gc, 0, y2, ww, y2); - info_draw(info); - if (e.type == ButtonPress) break; - while(XCheckMaskEvent(dpy, PointerMotionMask, &e)); - } - XUngrabPointer(dpy, CurrentTime); - if (x2 < x1) { t = x1; x1 = x2; x2 = t; } - if (y2 > y1) { t = y1; y1 = y2; y2 = t; } - mode = MODE_NULL; - info_draw(info); - if (e.type == KeyPress) { - spectro_draw(); - XCopyArea(dpy, buf, win, gc, 0, 0, ww, wh, 0, 0); - return 0; - } - int oldy = spect->fft_y; - spect->fft_x = spect->fft_w * x1/(ww*xsc) - 1.0*xoff + spect->fft_x; - spect->fft_y = spect->fft_h*(1.0-y1/(wh*ysc))-1.0*yoff+spect->fft_y; - spect->fft_w = spect->fft_w * x2/(ww*xsc) - 1.0*xoff - spect->fft_x; - spect->fft_h = spect->fft_h*(1.0-y2/(wh*ysc))-1.0*yoff + - oldy - spect->fft_y; - spectro_spec(); - spectro_thresh(); - spectro_points(); - spectro_draw(); - XCopyArea(dpy, buf, win, gc, 0, 0, ww, wh, 0, 0); - return 0; -} - -int erase(int x, int y) { - int x1, x2, y1, y2, i, j; - double sew = spect->fft_w * ew / (ww * xsc); - double seh = spect->fft_h * eh / (wh * ysc); - if (x == -1 && y == -1) { /* UNDO LAST ERASE */ - for (i = 0; i < spect->fft->ntime; i++) - for (j = 0; j < spect->fft->nfreq; j++) - spect->fft->mask[i][j] = ( (spect->fft->mask[i][j] >> 7) ? - (spect->fft->mask[i][j] >> 1) | 0x40 : - (spect->fft->mask[i][j] >> 1) ); - spectro_points(); - spectro_draw(); - XCopyArea(dpy, buf, win, gc, 0, 0, ww, wh, 0, 0); - return 0; - } /* ELSE START NEW ERASE */ - XEvent e; - XGrabPointer(dpy, win, True, PointerMotionMask | ButtonReleaseMask, - GrabModeAsync, GrabModeAsync, None, None, CurrentTime); - /* rotate bits for 7 undo levels */ - for (i = 0; i < spect->fft->ntime; i++) - for (j = 0; j < spect->fft->nfreq; j++) - spect->fft->mask[i][j] = ( (spect->fft->mask[i][j] >> 7) ? - (spect->fft->mask[i][j] << 1) | 0x40 : - (spect->fft->mask[i][j] << 1) ); - while (e.type != ButtonRelease) { - XMaskEvent(dpy, PointerMotionMask | ButtonReleaseMask, &e); - /* set erase bit mask */ - mx = spect->fft_w*e.xbutton.x/(ww*xsc) - 1.0*xoff + spect->fft_x; - my = spect->fft_h*(1.0-e.xbutton.y/(wh*ysc)) -1.0*yoff+spect->fft_y; - x1 = mx - sew / 2.0; y1 = my - seh / 2.0; - x2 = mx + sew / 2.0; y2 = my + seh / 2.0; - if (x1 < 0) x1 = 0; - if (y1 < 0) y1 = 0; - if (x2 >= spect->fft->ntime) x2 = spect->fft->ntime - 1; - if (y2 >= spect->fft->nfreq) y2 = spect->fft->nfreq - 1; - for (j = y1; j <= y2; j++) - for (i = x1; i <= x2; i++) - spect->fft->mask[i][j] |= 0x01; - /* redraw */ - spectro_thresh(); - spectro_points(); - spectro_draw(); - XCopyArea(dpy, buf, win, gc, 0, 0, ww, wh, 0, 0); - info_draw(info); - if (e.type == ButtonRelease) break; - while(XCheckMaskEvent(dpy, PointerMotionMask, &e)); - } - XUngrabPointer(dpy, CurrentTime); - return 0; -} - -int eraser_cursor(int w, int h) { - XUndefineCursor(dpy, win); - if ( !(mode & MODE_ERASE) ) return 0; - if ( (ew+=w) < 3 ) ew = 3; - if ( (eh+=h) < 3 ) eh = 3; - if ( ew > ww/4 ) ew = ww / 4; - if ( eh > wh/2 ) eh = wh / 2; - int i, stride = ew/ 8 + 1; - char data[stride * eh]; - char mask[stride * eh]; - XColor bg, fg; - XAllocNamedColor(dpy,DefaultColormap(dpy,scr),e_col[0],&bg,&bg); - XAllocNamedColor(dpy,DefaultColormap(dpy,scr),e_col[1],&fg,&fg); - memset(mask, 0xAA, stride * eh); - memset(data, 0xAA, stride * eh); - for (i = 0; i < eh; i+= 2) memset(&mask[stride * i], 0x55, stride); - Pixmap cd = XCreateBitmapFromData(dpy, win, data, ew, eh); - Pixmap cm = XCreateBitmapFromData(dpy, win, mask, ew, eh); - Cursor c = XCreatePixmapCursor(dpy, cd, cm, &fg, &bg, ew/2, eh/2); - XDefineCursor(dpy, win, c); - XFreePixmap(dpy, cd); - XFreePixmap(dpy, cm); - XFlush(dpy); - return 0; -} - -int move(double x, double y) { - xoff += x / xsc * spect->fft_w; yoff += y / ysc * spect->fft_h; - if ( yoff > spect->fft_h * (1.0 - 1.0/ysc) ) - yoff = spect->fft_h * (1.0 - 1.0/ysc); - if ( yoff < 0) yoff = 0; - if ( xoff < spect->fft_w * (1.0/xsc - 1.0) ) - xoff = spect->fft_w * (1.0/xsc - 1.0); - if ( xoff > 0) xoff = 0; - if (x || y) { /* don't redraw for offset checks */ - spectro_draw(); - XCopyArea(dpy, buf, win, gc, 0, 0, ww, wh, 0, 0); - } - return 0; -} - -int play(float speed) { - /* calculate fft coordinates of current view window */ - int tw = spect->fft_w / xsc; - int th = spect->fft_h / ysc; - int tx = spect->fft_x - xoff; - int ty = spect->fft_y - yoff + spect->fft_h - th; - if (tx + tw >= spect->fft->ntime) tw = spect->fft->ntime - tx - 1; - if (ty + th >= spect->fft->nfreq) th = spect->fft->nfreq - ty - 1; - /* get time and frequency values of current view window */ - double _start = spect->fft->time[tx]; - double _end = spect->fft->time[tx+tw]; - double _low = spect->fft->freq[ty]; - double _hi = spect->fft->freq[ty+th]; - double _mid = (_hi+_low)/2.0; - double _wid = (_hi-_low)/2.0; - /* fork and play */ - if (!fork()==0) { - close(ConnectionNumber(dpy)); - char start[12], end[12], mid[12], wid[12], sp[8]; - snprintf(sp,7,"%3f",speed); - sprintf(start,"=%lf",_start); sprintf(end,"=%lf",_end); - sprintf(mid,"%lfk",_mid); sprintf(wid,"%lfk",_wid); - execl("/usr/bin/play", "play", "-q", spect->fname, - "trim", start, end, "bandpass", mid, wid, - "speed", sp, NULL); - perror("Fex Play"); - exit(1); - } - /* draw cursor while playing */ - int i, step = 12; - double dur = _end - _start; - useconds_t usec = dur * 1000000.0 * step / (double) ww; - step = speed * step + 0.5; - for (i = 0; i < ww; i+=step) { - XCopyArea(dpy, buf, win, gc, 0, 0, ww, wh, 0, 0); - XDrawLine(dpy, win, gc, i, 0, i, wh); - XDrawLine(dpy, win, gc, i+step, 0, i+step, wh); - XFlush(dpy); - usleep(usec); - } - XCopyArea(dpy, buf, win, gc, 0, 0, ww, wh, 0, 0); - XFlush(dpy); - return 0; -} - -int pt_line(double p, double l) { - conf.col[RGBA_POINTS].w += p; - conf.col[RGBA_LINES].w += l; - if (conf.col[RGBA_POINTS].w < 0) conf.col[RGBA_POINTS].w = 0.0; - if (conf.col[RGBA_LINES].w < 0) conf.col[RGBA_LINES].w = 0.0; - spectro_points(); - spectro_draw(); - XCopyArea(dpy, buf, win, gc, 0, 0, ww, wh, 0, 0); - return 0; -} - -int screenshot() { - char fname[256]; - static int n = 0; - snprintf(fname, 256, "%s-%d.png", spect->name, n++); - cairo_surface_t *t = cairo_xlib_surface_create(dpy, buf, - DefaultVisual(dpy,scr), ww, wh); - cairo_surface_write_to_png(t, fname); - cairo_surface_destroy(t); - return 0; -} - -int series_export() { - static int n = 0; - double *dat = malloc(spect->fft_w * sizeof(double)); - int i, j, f; - /* find the peak frequency relative to max for each time bin */ - for (i = spect->fft_x; i < spect->fft_w + spect->fft_x; ++i) { - f = 0; - for (j = spect->fft_y; j < spect->fft_h+spect->fft_y; ++j) { - if (spect->fft->mask[i][j]) continue; - if (spect->fft->amp[i][j] > spect->fft->amp[i][f] || !f) - f = j; - } - if (f > 0 && spect->fft->amp[i][f] > conf.thresh) - dat[i - spect->fft_x] = spect->fft->freq[f]; - else - dat[i - spect->fft_x] = 0.0; - } - char *fname = malloc(strlen(spect->name) + 10); - sprintf(fname, "%s%d.freq", spect->name, n++); - f = open(fname, O_WRONLY | O_CREAT, 0644); - write(f, dat, spect->fft_w * sizeof(double)); - close(f); - free(fname); - free(dat); - return 0; -} - -int sp_floor(double f) { - conf.spect_floor += f; - spectro_spec(); - spectro_draw(); - XCopyArea(dpy, buf, win, gc, 0, 0, ww, wh, 0, 0); - if (info->vis) info->draw(info); - return 0; -} - -int threshold(double f) { - conf.thresh += f; - spectro_thresh(); - spectro_points(); - spectro_draw(); - XCopyArea(dpy, buf, win, gc, 0, 0, ww, wh, 0, 0); - if (info->vis) info->draw(info); - return 0; -} - -int zoom(double f) { - double px = xsc, py = ysc; - xsc += f; ysc += f; - if (xsc < 1.0) xsc = 1.0; - if (ysc < 1.0) ysc = 1.0; - xoff += (spect->fft_w/xsc - spect->fft_w/px) / 2.0; - yoff += (spect->fft_h/py - spect->fft_h/ysc) / 2.0; - if (f < 0) move(0,0); /* check offsets for bounds */ - spectro_draw(); - XCopyArea(dpy, buf, win, gc, 0, 0, ww, wh, 0, 0); - return 0; -} - DELETED src/xlib_events.c Index: src/xlib_events.c ================================================================== --- src/xlib_events.c +++ src/xlib_events.c @@ -1,202 +0,0 @@ -/**********************************************************************\ -* FEX - The Frequency Excursion Calculator -* -* Author: Jesse McClure, copyright 2013-2014 -* License: GPL3 -* -* 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 -* . -* -\**********************************************************************/ - - -#define CtrlMask ControlMask -void buttonpress(XEvent *ev) { - XButtonEvent *e = &ev->xbutton; - if (e->window == info->win) info->button(info, e); - else if (e->state == (ControlMask | ShiftMask)) { - if (e->button == 4) threshold(0.1); - else if (e->button == 5) threshold(-0.1); - else if (e->button == 6) sp_floor(-0.1); - else if (e->button == 7) sp_floor(0.1); - } - else if (e->state == ControlMask) { - if (e->button == 4) zoom(0.025); - else if (e->button == 5) zoom(-0.025); - else if (e->button == 6) return; - else if (e->button == 7) return; - } - else if (e->state == Mod1Mask) { - if (e->button == 4) eraser_cursor(1,1); - else if (e->button == 5) eraser_cursor(-1,-1); - else if (e->button == 6) eraser_cursor(-1,1); - else if (e->button == 7) eraser_cursor(1,-1); - } - else if (e->state == ShiftMask) { - if (e->button == 4) pt_line(0.2,0); - else if (e->button == 5) pt_line(-0.2,0); - else if (e->button == 6) pt_line(0,-0.2); - else if (e->button == 7) pt_line(0,0.2); - } - else if (e->button == 4) move(0,-0.02); - else if (e->button == 5) move(0,0.02); - else if (e->button == 6) move(0.02,0); - else if (e->button == 7) move(-0.02,0); - else if (mode == MODE_ERASE && e->button == 1) erase(e->x, e->y); - else if (mode == MODE_ERASE && e->button == 3) erase(-1,-1); - else if (mode == MODE_CROP && e->button == 1) crop(e->x, e->y); - while(XCheckMaskEvent(dpy, ButtonPressMask, ev)); -} - -void clientmessage(XEvent *ev) { - XClientMessageEvent *e = &ev->xclient; - if ( (Atom)e->data.l[0] == WM_DELETE_WINDOW ) { - if (e->window == info->win) { - info->vis = False; - XUnmapWindow(dpy, info->win); - } - else if (e->window == win) { - running = False; - } - } -} - -void configurenotify(XEvent *ev) { - while (XCheckTypedEvent(dpy,ConfigureNotify, ev)); - XConfigureEvent *e = &ev->xconfigure; - if (e->window == win) { - /* The XServer is not storing the new/current values for width + - * height. These must be retrieved directly. - * Is this an X11 bug? */ - Window wig; - int ig; - unsigned int uig; - XGetGeometry(dpy, win, &wig, &ig, &ig, &ww, &wh, &uig, &uig); - //ww = e->width; wh = e->height; - spectro_draw(); - XSetWindowBackgroundPixmap(dpy, win, buf); - XClearWindow(dpy,win); - } -} - -void expose(XEvent *ev) { - XExposeEvent *e = &ev->xexpose; - if (e->window == info->win) info->draw(info); - else { - XSetWindowBackgroundPixmap(dpy, win, buf); - XClearWindow(dpy,win); - } -} - -void keypress(XEvent *ev) { - XKeyEvent *e = &ev->xkey; - KeySym sym = XkbKeycodeToKeysym(dpy, (KeyCode)e->keycode, 0, 0); - int mod = ((e->state & ~Mod2Mask) & ~LockMask); - if (mod == (ControlMask | ShiftMask)) { - if (sym == XK_q) { - spect->fex = 0; - running = False; - } - if (sym == XK_j || sym == XK_Down) threshold(-0.05); - else if (sym == XK_k || sym == XK_Up) threshold(0.05); - else if (sym == XK_h || sym == XK_Left) sp_floor(-0.05); - else if (sym == XK_l || sym == XK_Right) sp_floor(0.05); - else if (sym == XK_p) play(0.1666); - } - else if (mod == (Mod1Mask | ShiftMask)) { - if (sym == XK_p) play(0.08333); - } - else if (mod == ControlMask) { - if (sym == XK_q) running = False; - else if (sym == XK_f) series_export(); - else if (sym == XK_s) screenshot(); - else if (sym == XK_i) img_draw(); - else if (sym == XK_j || sym == XK_Down) zoom(-0.025); - else if (sym == XK_k || sym == XK_Up) zoom(0.025); - else if (sym == XK_h || sym == XK_Left) return; - else if (sym == XK_l || sym == XK_Right) return; - else if (sym == XK_p) play(0.33); - } - else if (mod == Mod1Mask) { - if (sym == XK_j || sym == XK_Down) eraser_cursor(-1,-1); - else if (sym == XK_k || sym == XK_Up) eraser_cursor(1,1); - else if (sym == XK_h || sym == XK_Left) eraser_cursor(-1,1); - else if (sym == XK_l || sym == XK_Right) eraser_cursor(1,-1); - else if (sym == XK_p) play(0.25); - } - else if (mod == ShiftMask) { - if (sym == XK_j || sym == XK_Down) pt_line(-0.2,0); - else if (sym == XK_k || sym == XK_Up) pt_line(0.2,0); - else if (sym == XK_h || sym == XK_Left) pt_line(0,-0.2); - else if (sym == XK_l || sym == XK_Right) pt_line(0,0.2); - else if (sym == XK_p) play(0.5); - } - else if (sym == XK_j || sym == XK_Down) move(0,0.02); - else if (sym == XK_k || sym == XK_Up) move(0,-0.02); - else if (sym == XK_h || sym == XK_Left) move(0.02,0); - else if (sym == XK_l || sym == XK_Right) move(-0.02,0); - else if (sym == XK_F1) { - if (fork() == 0) { - close(ConnectionNumber(dpy)); - fclose(stderr); - fclose(stdout); - execvp(conf.help_cmd[0],(char * const *)conf.help_cmd); - } - } - else if (sym == XK_F2) { - if ( (info->vis = !info->vis) ) XMapRaised(dpy,info->win); - else XUnmapWindow(dpy,info->win); - XFlush(dpy); - } - else if (sym == XK_e) { - //mode = MODE_ERASE & (mode ^= MODE_ERASE); - mode = (mode & MODE_ERASE ? 0 : MODE_ERASE); - eraser_cursor(0,0); - info->draw(info); - } - else if (sym == XK_c) { - //mode = MODE_CROP & (mode ^= MODE_CROP); - mode = (mode & MODE_CROP ? 0 : MODE_CROP); - if (!(mode & MODE_CROP)) XDefineCursor(dpy, win, None); - else XDefineCursor(dpy, win, XCreateFontCursor(dpy, 34)); - info->draw(info); - } - else if (sym == XK_Escape) { - mode = MODE_NULL; - XDefineCursor(dpy, win, None); - info->draw(info); - } - else if (sym == XK_p) play(1.0); - else if (sym == XK_t) { - conf.layers = !conf.layers; - spectro_draw(); - XCopyArea(dpy, buf, win, gc, 0, 0, ww, wh, 0, 0); - } - else if (sym == XK_u && mode & (MODE_ERASE)) erase(-1,-1); - while(XCheckMaskEvent(dpy, KeyPressMask, ev)); -} - -void motionnotify(XEvent *ev) { - //static int px, py; - int x = ev->xmotion.x, y = ev->xmotion.y; - mx = spect->fft_w * x / (xsc * ww) - 1.0 * xoff + spect->fft_x; - my = spect->fft_h * (1.0 - y / (ysc * wh)) - 1.0 * yoff + spect->fft_y; - info->draw(info); - if (mode == MODE_CROP) { - XCopyArea(dpy, buf, win, gc, 0, 0, ww, wh, 0, 0); - XDrawLine(dpy, win, gc, x, 0, x, wh); - XDrawLine(dpy, win, gc, 0, y, ww, y); - } -} - DELETED src/xlib_toolwin.c Index: src/xlib_toolwin.c ================================================================== --- src/xlib_toolwin.c +++ src/xlib_toolwin.c @@ -1,265 +0,0 @@ -/**********************************************************************\ -* FEX - The Frequency Excursion Calculator -* -* Author: Jesse McClure, copyright 2013-2014 -* License: GPL3 -* -* 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 -* . -* -\**********************************************************************/ - -typedef struct ToolWin ToolWin; -struct ToolWin { - Window win; - Pixmap buf; - int w, h; - char *name; - cairo_t *ctx; - Bool vis; - int (*backing)(ToolWin *); - int (*draw)(ToolWin *); - int (*button)(ToolWin *, XButtonEvent *); -}; - -static int toolwin_backing(ToolWin *); -//static int toolwin_button(ToolWin *, XButtonEvent *); -static int toolwin_create(); -static int toolwin_destroy(); -static int toolwin_draw(ToolWin *); -static int toolwin_win_create(ToolWin *); -static int toolwin_win_destroy(ToolWin *); - -static ToolWin *info; //, *help; -//static char *help_name = "FEX Help"; -static cairo_text_extents_t ext; - - -//static int help_draw(ToolWin *tw) { -// toolwin_backing(tw); -// cairo_set_source_rgba(tw->ctx,0,0,0,1.0); -// cairo_rectangle(tw->ctx, 10, 10, 460, 300); -// cairo_stroke_preserve(tw->ctx); -// cairo_set_source_rgba(tw->ctx,0.8,0.8,0.8,1.0); -// cairo_fill(tw->ctx); -//// cairo_surface_t *img = cairo_image_surface_create_from_png( -//// "./help.png"); -//// cairo_set_source_surface(tw->ctx,img, 8, 8); -//// cairo_paint(tw->ctx); -//// cairo_surface_destroy(img); -// -// toolwin_draw(tw); -//} - -#define MARGIN 4.0 -#define MAX_STRING 256 -#define A_LEFT 0x00 -#define A_CENTER 0x01 -#define A_RIGHT 0x02 -static int info_printf(ToolWin *tw, int align, char *fmt, ...) { - char str[MAX_STRING]; - va_list arg; - va_start(arg, fmt); - vsprintf(str, fmt, arg); - va_end(arg); - cairo_text_extents(tw->ctx,str,&ext); - double x = (align == A_RIGHT ? tw->w - ext.x_advance - MARGIN : - (align == A_CENTER ? (tw->w - ext.x_advance) / 2.0 : MARGIN)); - cairo_rel_move_to(tw->ctx, x, conf.font_size); - cairo_show_text(tw->ctx,str); - cairo_rel_move_to(tw->ctx, -1.0 * ext.x_advance - x, conf.font_size / 3.0); - return 0; -} - -static int info_split_printf(ToolWin *tw, char *bold, char *fmt, ...) { - char str[MAX_STRING]; - va_list arg; - va_start(arg, fmt); - vsprintf(str, fmt, arg); - va_end(arg); - cairo_set_font_face(tw->ctx, conf.bfont); - cairo_text_extents(tw->ctx,bold,&ext); - cairo_rel_move_to(tw->ctx, MARGIN, conf.font_size); - cairo_show_text(tw->ctx,bold); - cairo_rel_move_to(tw->ctx, -1.0 * ext.x_advance - MARGIN, 0); - cairo_set_font_face(tw->ctx, conf.font); - cairo_text_extents(tw->ctx,str,&ext); - cairo_rel_move_to(tw->ctx, tw->w - ext.x_advance - MARGIN, 0); - cairo_show_text(tw->ctx,str); - cairo_rel_move_to(tw->ctx, MARGIN - tw->w, conf.font_size / 3.0); - return 0; -} - -static int info_draw(ToolWin *tw) { - toolwin_backing(tw); - /* info */ - cairo_set_source_rgba(tw->ctx,0,0,0,1.0); - cairo_set_font_face(tw->ctx, conf.bfont); - cairo_move_to(tw->ctx, 0, 8); - info_printf(tw, A_CENTER, "%.3lf sec, %.2lf KHz", - spect->fft->time[mx],spect->fft->freq[my]); - cairo_rel_move_to(tw->ctx,0,12); - info_split_printf(tw, "Threshold:", "%.2lf", -1.0 * conf.thresh); - info_split_printf(tw, "Spectrogram Floor:", "%.2lf", - -1.0 * conf.spect_floor); - info_split_printf(tw, "Path Length:","%.2lf", spect->pex); - info_split_printf(tw, "Path Duration:","%.3lf", spect->tex); - info_split_printf(tw, "Frequency Excursion:","%.3lf", spect->fex); - cairo_move_to(tw->ctx, 0, 145); - /* modes */ - info_split_printf(tw, "Modes:",""); - cairo_set_font_face(tw->ctx, conf.bfont); - /* erase */ - set_color(tw->ctx,RGBA_ERASE1) - if (mode & MODE_ERASE) set_color(tw->ctx,RGBA_ERASE1) - else cairo_set_source_rgba(tw->ctx,0.8,0.8,0.8,1.0); - cairo_rectangle(tw->ctx, 10, 170, tw->w / 2.0 - 15, 20); - cairo_fill_preserve(tw->ctx); - cairo_set_source_rgba(tw->ctx,0,0,0,1.0); - cairo_stroke(tw->ctx); - cairo_text_extents(tw->ctx,"Erase",&ext); - cairo_move_to(tw->ctx, tw->w / 4.0 - ext.width / 2.0, 185); - cairo_set_source_rgba(tw->ctx,0,0,0,1.0); - cairo_show_text(tw->ctx,"Erase"); - /* crop */ - if (mode & MODE_CROP) set_color(tw->ctx, RGBA_CROP) - else cairo_set_source_rgba(tw->ctx,0.8,0.8,0.8,1.0); - cairo_rectangle(tw->ctx, 5 + tw->w / 2.0, 170, tw->w / 2.0 - 15, 20); - cairo_fill_preserve(tw->ctx); - cairo_set_source_rgba(tw->ctx,0.0,0.0,0.0,1.0); - cairo_stroke(tw->ctx); - cairo_text_extents(tw->ctx,"Crop",&ext); - cairo_move_to(tw->ctx, tw->w * 0.75 - ext.width / 2.0, 185); - cairo_set_source_rgba(tw->ctx,0,0,0,1.0); - cairo_show_text(tw->ctx,"Crop"); - /* draw */ - toolwin_draw(tw); - return 0; -} - -static int info_button(ToolWin *tw, XButtonEvent *e) { - if (e->y < 170 || e->y > 190) return 0; - if (e->x < 10 || e->x > tw->w - 10) return 0; - if (e->x < tw->w / 2.0 - 5) { /* erase button */ - if (e->button == 1) { - //mode = MODE_ERASE & (mode ^= MODE_ERASE); - mode = (mode & MODE_ERASE ? 0 : MODE_ERASE); - eraser_cursor(0,0); - tw->draw(tw); - } - } - else { /* crop button */ - if (e->button == 1) { - //mode = MODE_CROP & (mode ^= MODE_CROP); - mode = (mode & MODE_CROP ? 0 : MODE_CROP); - if (!(mode & MODE_CROP)) XDefineCursor(dpy, win, None); - else XDefineCursor(dpy, win, XCreateFontCursor(dpy, 34)); - tw->draw(tw); - } - else if (e->button == 3) { /* uncrop */ - mode |= MODE_CROP; - tw->draw(tw); - spect->fft_x = 0; - spect->fft_y = spect->fft_lo; - spect->fft_w = spect->fft->ntime; - spect->fft_h = spect->fft_hi - spect->fft_lo; - spectro_spec(); - spectro_thresh(); - spectro_points(); - spectro_draw(); - XCopyArea(dpy, buf, win, gc, 0, 0, ww, wh, 0, 0); - mode &= ~MODE_CROP; - tw->draw(tw); - } - } - return 0; -} - -int toolwin_backing(ToolWin *tw) { - cairo_set_source_rgba(tw->ctx,0.6,0.6,0.6,1.0); - cairo_rectangle(tw->ctx, 0, 0, tw->w,tw->h); - cairo_fill(tw->ctx); - return 0; -} - -//int toolwin_button(ToolWin *tw, XButtonEvent *e) { -// XRaiseWindow(dpy, tw->win); -// return 0; -//} - -int toolwin_create() { - info = (ToolWin *) calloc(1, sizeof(ToolWin)); - //help = (ToolWin *) calloc(1, sizeof(ToolWin)); - info->w = 240; info->h = 200; - info->name = spect->name; - info->vis = True; - info->draw = info_draw; - info->button = info_button; - //help->w = 480; help->h = 320; - //help->name = help_name; - //help->vis = False; - //help->draw = help_draw; - //help->button = toolwin_button; - toolwin_win_create(info); - //toolwin_win_create(help); - return 0; -} - -int toolwin_destroy() { - toolwin_win_destroy(info); - //toolwin_win_destroy(help); - free(info); - //free(help); - return 0; -} - -int toolwin_draw(ToolWin *tw) { - XClearWindow(dpy,tw->win); - XFlush(dpy); - return 0; -} - -int toolwin_win_create(ToolWin *tw) { - tw->win = XCreateSimpleWindow(dpy, root, 20, 20, tw->w, tw->h, 0, 0, 0); - tw->buf = XCreatePixmap(dpy, root, tw->w, tw->h, DefaultDepth(dpy,scr)); - cairo_surface_t *t = cairo_xlib_surface_create(dpy, tw->buf, - DefaultVisual(dpy,scr), tw->w, tw->h); - tw->ctx = cairo_create(t); - cairo_surface_destroy(t); - cairo_set_font_face(tw->ctx,conf.font); - cairo_set_font_size(tw->ctx,conf.font_size); - XSelectInput(dpy, tw->win, EVENT_MASK); - XSetTransientForHint(dpy, tw->win, win); - XSetWMProtocols(dpy, tw->win, &WM_DELETE_WINDOW, 1); - XSizeHints *hints = XAllocSizeHints(); - hints->min_width = hints->max_width = tw->w; - hints->min_height = hints->max_height = tw->h; - hints->flags = PMinSize | PMaxSize; - XSetWMNormalHints(dpy, tw->win, hints); - XFree(hints); - XStoreName(dpy, tw->win, tw->name); - if (tw->backing) tw->backing(tw); - else toolwin_backing(tw); - XSetWindowBackgroundPixmap(dpy, tw->win, tw->buf); - XFlush(dpy); - return 0; -} - -int toolwin_win_destroy(ToolWin *tw) { - cairo_destroy(tw->ctx); - XDestroyWindow(dpy, tw->win); - XFreePixmap(dpy, tw->buf); - return 0; -} -