pax_global_header00006660000000000000000000000064137073631310014516gustar00rootroot0000000000000052 comment=47082159995ffe9dab2ace44742ee89781866ec4 freewheeling-0.6.6/000077500000000000000000000000001370736313100141735ustar00rootroot00000000000000freewheeling-0.6.6/.gitignore000066400000000000000000000003031370736313100161570ustar00rootroot00000000000000Makefile autom4te.cache/ config.log config.status data/Makefile src/Makefile src/*.o src/.Tpo src/.deps/ src/fweelin src/elastin/.deps/ src/elastin/.dirstamp src/elastin/*.o **/fweelin-stackdump freewheeling-0.6.6/AUTHORS000066400000000000000000000000371370736313100152430ustar00rootroot00000000000000JP Mercury freewheeling-0.6.6/COPYING000066400000000000000000000431101370736313100152250ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. freewheeling-0.6.6/ChangeLog000066400000000000000000001255131370736313100157540ustar00rootroot00000000000000 2019-05-02 v0.6.6 * fixed thread-count race condition during memory-manager init - long-standing bug which caused intermittent startup failures * changed C FALSE to C++ false in fluidsynth class - fixes build failures with GCC9 on some systems 2019-01-29 v0.6.5 * made compatible with both fluidsynth v1 and v2 * fixed deprecation and compiler warnings and other housekeeping tasks * removed experimental 'elastin' classes 2017-04-03 v0.6.4 * made font paths consistent with debian packaging * implemented 'tiny' font specified in graphics.xml (although still unused) 2017-04-01 v0.6.2 * FreeWheeling now requires nettle instead of gnutls-openssl because gnutls-openssl is no longer supported on ArchLinux * deprecation, bug, and compiler warning fixes by GitHub user 'Jajcus' 2016-10-31 v0.6.1 * new version control and repos - SVN history converted to git sadly, JP has been incommunicado for some time so it is not possible to properly maintain the sourceforge repo. the project has been forked to github and notabug for further development https://github.com/free-wheeling/freewheeling/ https://notabug.org/freewheeling/freewheeling/ * restored freewheeling wiki on github https://github.com/free-wheeling/freewheeling/wiki * upgraded autotools files * FreeWheeling will use semantic versioning from this point on (e.g. MAJOR.MINOR.REV) IN PROGRESS v0.6.1 - SVN Thursday March 17, 2011 * Multi-track streaming. Now you can stream each input to disk, stream loops to disk, and stream the whole final mix to disk. Control what to stream from basics.xml: This allows you to do more precise edits after a performance. It is especially useful for live microphone pickups, which often require separate gain and FX adjustments during later editing. As always, the disk streams can be toggled in real-time with the PrintScreen key (see help). Freewheeling finds an unused filename for each new stream. The streams are time-aligned, so they can be loaded as tracks into a multi-track sequencer. Thursday March 10, 2011 * Configurable soft monitoring is now available in basics.xml: * QTractor OSC integration is now working. Saturday February 26, 2011 After more than two years, activity has resumed on Freewheeling's development. I am in the process of refactoring the code to make it more stable. New Features in the works: * DONE - Direct hardware mixing controls Direct control of ALSA mixer controls from within Freewheeling * DONE - SYNTHEDIT - An easier way to manage synth plugins with MANY parameters from a tactile interface with FEW knobs - stores parameters and allows motor-fader updates * FIXED - MIDI Sync Transmit now works as advertised - Loops stay in lockstep with externals Added MIDI sync metronome for listening to beats/bars. * QTractor integration. Rui Nuno Capela and I are working on a QTractor branch that will allow snapshots of all playing loops to be instantly transferred into a QTractor session. Go from circular time to sequencer time! This SVN update contains proof-of-concept code against the 'qtractor-osc' branch. Tuesday January 20th, 2009 New Features ------------ * A proper BCF-2000 Preset (SYSEX Dump Format) is now included See data/bcf2000-help.txt for instructions if you use a BCF-2000. * Snapshot moving ALT-P swaps the last two selected snapshots. * Z/X paging through loops now works across interfaces (BCF-2000, MIDI keyboard, ...) Sunday December 28th, 2008 New Features ------------ * As part of ongoing work to make Freewheeling more reliable, crash reports are now automatically generated if GDB is installed. The type of crash is printed on the terminal. The report is saved to file 'fweelin-stackdump'. If you encounter a crash, please send me this file along with a description of what you were doing when the crash occurred. Thank you. Fixes ----- * Fixed an overdub crash with the new triggering method * Fixed a positioning bug when recording loops with the new triggering method Friday December 25th, 2008 New Features ------------ * This version uses an experimental new way of triggering loops. The loops always play immediately when triggered, and they start in the right place. The 'right place' is given by a 'long count', which is the overall pattern of all loops. This method allows switching between snapshots mid-phrase without a loss of positioning, and triggering new snapshots before the downbeat to catch pickup notes. Musically, the long count is the length of the larger musical phrase which is described by all the loops. Mathematically, the long count's length is the LCM (Lowest Common Multiple) of the length of all loops that have been activated. (Example) For a scene with loops with length 1, 2, 4, and 8 beats, the long count is 8 beats. For a scene with loops length 4 and 3 beats, the long count is 12 beats. You don't really have to think about the long count. But it's helpful to know that the long count is defined so that when it rolls over, all loops are rolling over to their start points. You can see the long count visually in an outer ring of the pulse display (top right). The old triggering method is no longer in this version. I would appreciate any feedback you might have on how this new method works for you. Happy Holidays! -Mercury Tuesday October 28th, 2008 New Features ------------ * Automatic bypassing of unused channels now works with combi patches across many zones Sunday October 19th, 2008 New Features ------------ * Improved MIDI handling with automatic bypassing of unused channels This new feature keeps track of which patches are active and recently used, and which have sustaining notes either with or without pedal. FreeWheeling will automatically send out a configurable MIDI CC on those channels that are inactive, and another CC when those channels become active. As I'm playing, FreeWheeling automatically frees up CPU from unused plugin channels on my plugin hardware rack. You can use this feature with any plugin host that will bypass/unbypass channels via MIDI CC. I use it with a Muse Research Receptor. ** Patch changes are now registered when you SELECT a patch. Browsing to the patch does not switch patches. Now, you must move to the new patch and press ENTER or a MIDI select button. For example, the following in a patch definition file: Defines a piano patch sending on channel 0 (1st MIDI channel). After 60 seconds of unreleased sustained notes, when the channel is inactive, it will be bypassed. 5 seconds after all notes are released with the sustain pedal up, and once the channel is inactive, it will be bypassed. This follows the natural decay of a piano- long sustain, short release. I can play piano notes, hold them, and switch to another channel. When I release those piano notes, the appropriate notes are released and the channel is bypassed soon after. I am already continuing on with whatever new patch I'm playing. Here, two drum patches that receive on channel 10 and 11 are defined. They are both bypassed via channel 5. I use this with multitimbral plugins that receive on several channels but are bypassed as one. To enable auto-bypass, you must define a MIDI CC to use. This can be defined for each patch or combi zone, but is more easily defined for a whole patchbank (from browsers.xml): Here MIDI CC #116 is used to auto-bypass channels on the Receptor. You can also set default values for bypasstime1 and bypasstime2 on a per-patchbank basis. Fixes ----- * Fixed doubling of MIDI note-off messages RELEASE v0.6 Friday October 3rd, 2008 Folks, Here is a full 0.6 release. Included are updated Mac and Linux versions. The new Mac version works with the latest Jack version and under OS X Leopard. As you can see from the SVN updates below, there's quite a bit that's new since 0.5.5. Your feedback is always welcome. -~Mercury v0.5.6 - SVN Thursday September 4th, 2008 New Features ------------ * Logarithmic faders and loop levels, conforming to IEC 60-268-18. Level meters and loop faders are now logarithmic, visually graded with 6dB markings. This means you can create much smoother fades using MIDI controllers, and you can see a broader range of levels on-screen. One new configuration parameter controls the maximum dB selectable: Saturday August 30th, 2008 Fixes ----- * Saving over existing snapshots now preserves name * Upgrades to BCF-2000 template Wednesday August 13th, 2008 New Features ------------ * Rename snapshots Press ALT-1 through ALT-9 to rename a snapshot. Label your song sections for easy recall. * Way overhauled BCF-2000 interface The Behringer BCF-2000 MIDI template has been overhauled. Most major functions can be controlled from the surface. Continuously variable loop volumes, overdubs on knob presses, loop selection and triggering, scenes, pulses, and multiple pages of loops. The whole template can be customized by editing the MIDI CC variables at the top of the file. By changing the CCs, you can use it as a template for other control surfaces. A future configuration editor may build on this concept of 'templates with editable settings'. For now, you can edit the file and adjust the most common commands easily. Saturday July 5th, 2008 New Features ------------ * Multiple pages of snapshots 100 snapshots are provided by default (edit this in basics.xml). You can pageup/pagedown through them by holding CTRL or SHIFT and pressing , or . Then use CTRL 1-9 to trigger and SHIFT 1-9 to store. Fixes ----- * Reworked some of the guts to fix crashes. Race condition fixes in block manager. Thanks to Florent and Andrea for your crash reports. They helped nail the bug. Monday Jun 16th, 2008 New Features ------------ * Create snapshots for playing loops - Create / save / load snapshots. All loop levels and playing loops are remembered. To create a snapshot, hold SHIFT and press 1-9. The snapshot is shown in a popup window. - An easy way to switch between song sections. To switch snapshots, hold CTRL and press 1-9. - Snapshots are saved/loaded in scenes. Still to do on snapshots: Renaming, fading, paging through snapshots on display, more flexible synchronization. * Easily adjust levels for all selected loops To use: Select some loops. Hold CTRL and press UP/DOWN repeatedly to adjust all loop levels. Or, hold CTRL and use the mousewheel on any loop. All selected loops are adjusted. This works well when you have many loops that are overdriving Freewheeling's outputs. The limiter is bouncing around. You could reduce the output level, but this approach is more flexible- and the results are saved in snapshots and scenes. Friday Nov 9th, 2007 New Features ------------ * Completely revamped configuration system- Better splitting and organization- There are now many configuration files. The configuration is divided into 'interfaces'. Each interface defines behavior and display related to a hardware interface. You can build whole functionality for a given MIDI interface such as a fader box, and share it on the Internet. This should help the current situation where people are patching together bits of each other's configurations. Sunday July 8th, 2007 New Features ------------ * Working on real-time pitch and time stretching- not yet usable! * Adjustable global tuning for Fluidsynth: From .fweelin.rc: Adjusts Fluidsynth to -31.76 cents tuning, or 432 Hz tuning. Fixes ----- * Fixed a bug where some non-critical events (such as loading or selecting loops) could be missed. * Fixed glitch in memory manager that could cause spontaneous exits, usually when erasing loops * Better clipping of out-of-range MIDI values * Removed old 'DelayProcess' code for dealing with real-time events. New code uses real-time event manager. Tuesday March 13th, 2007 New Features ------------ * Erase-selected-loops command Shift+Space now erases all selected loops. * New ability to tag patch banks By tagging patch banks, you can change the way Freewheeling responds depending on which patches you have selected. For example, I use Freewheeling with a B3 organ softsynth. My organ patches are arranged in a patch bank. I've tagged that patch bank, and configured Freewheeling to respond differently when that patch bank is active. So, when I am on an organ patch, my faders control the B3 drawbars instead of their usual Freewheeling functions. You can, of course, change any of Freewheeling's behaviors depending on the patch bank selected. For more info, check the 'SYSTEM_cur_patchbank_tag' variable in the configuration. * Receive and transmit MIDI channel pressure (aftertouch) messages * New 'routethroughpatch' configuration option for MIDI events allows you to send deliberate MIDI messages to the port(s) and channel(s) for the current patch. An example configuration is provided that changes the behavior of the modwheel (CC #1). When enabled, the modwheel value is modulated by aftertouch. This allows me to control vibrato (CC #1) on my softsynths with pressure on the keys. The modwheel and pressure values are summed together and sent out as a control change message. If I am playing several softsynth channels from my one keyboard, the aftertouch then affects all the channels seamlessly. Fixes ----- * Fixed problem installing configuration files from folders with spaces. 2007-01-25 v0.5.5 New Features ------------ * MIDI sync transmit - Toggle-able sync transmit on definable output ports A friend of mine who is an avid Ableton Live user asked me to collaborate with him. I realized that this was a perfect opportunity to develop MIDI sync. Freewheeling already syncs via the Jack transport, but Ableton and other hardware sequencers are not Jack-aware. As of this version, Freewheeling transmits MIDI sync on definable MIDI outs. By default, MIDI clock is sent to the first MIDI output. To send MIDI clock, you must first enable it-- Go to the sync panel (shift+F1) and press shift+F2. MIDI Sync Transmit is now enabled (the light glows). Now, you can begin playing, and create a pulse. You can either tap the pulse tempo, or you can record a loop and use it as the pulse tempo. Once the pulse begins, Freewheeling starts the external sequencer at bar 1. If you deselect the pulse (F6 for free timing), Freewheeling will stop your external sequencer. Any pulse you select will begin transmitting MIDI sync. Freewheeling does not yet receive MIDI sync, so you can't yet use Ableton as tempo master. * Selecting and working with multiple loops You can now toggle (t) and fade (MIDI CC89) volume of several loops together. You can select loops by right clicking on them, or by shift+clicking on them, or by shift+pressing their trigger. You can select all playing loops by pressing the keypad asterisk. You can select all idle loops with shift+kp asterisk. Ctrl+kp asterisk inverts the current selection, and alt+kp asterisk unselects all loops. This is the first step towards having multiple scenes of loops that you can trigger/fade between. * New configuration allows MIDI control of: Undo- CC#51 Patch bank changing by fader- CC #88 Patch bank changing by buttons- CC #53 / #54 * Continuously variable feedback for overdubs You can now change the loop feedback during overdubbing. You can realtime vary the amount of the loop that is fed-back into itself. The current feedback level is shown on-screen. By default, MIDI CC#87 controls the loop feedback. The feedback controls are configurable in .fweelin.rc, here: * New configuration allows browsing via MIDI program change I developed this config for the CME-UF8 master controller, which has a rotary encoder that sends MIDI program change messages. With the new config, a MIDI program change knob can be used to spin through scenes, loops, or softsynth patches. Also, controller #50 is configured to act as a shift key for faster scrolling through browsers. * Save Current Scene (F7) now overwrites an existing scene. * Save New Scene (shift + F7) forces a new scene to be created. When overwriting, sequential backups are made with the extensions '.backup.1' '.backup.2' etc. Scene file data is very small. Loops are stored separately, so there is no duplication of unmodified loops. * Sync panel can now be toggled with Shift-F1 Defaults to OFF Fixes ----- - Better stability in Event Manager- should fix crashes - Deliberate MIDI output of events now follows the ports and channels you specify. Incidental echoing of MIDI events follows the settings from the current patch. - Fixed crash on repeat loading of scenes/loading of large scenes - No more console-dependent startup questions when a new version is installed. - Library path can now be specified relative to home folder (for example, ~/fw-lib) - Stream out now shows size in mb, for less frantic update 2006-11-21 v0.5.3 Many thanks to Danni Coy, who has contributed very significantly to this release. Actually, he did most of the work! New Features ------------ * MAC OS X support FreeWheeling is now cross-platform. A universal binary is now available for both Intel & PPC Mac platforms. * Multiple Audio Formats (Contributed by Danni- Thank You!) Save and load loops and live streams in OGG, WAVE, AU, and FLAC. * OGG encoding quality setting in configuration * More flexible MIDI control of external synths. - Combination patches allow you to split one MIDI controller into a range of zones. This allows you to control several different sounds or softsynths from one MIDI control source. A combipatch defines the zones, as well as the output MIDI port and channel that each zone sends to. You can also send MIDI program and bank change messages for each zone, allowing you to switch programs on external synths. All of this functionality is integrated into the patch browser, so you can seamlessly control other synth apps and sound modules from within FreeWheeling. See 'examples/combipatchdemo.xml' for an example configuration. - Added 'suppressprogramchanges' option for patch banks With suppressprogramchanges=1, no MIDI bank and program change messages are sent when patches are changed within a patch bank. This is useful when you have a softsynth loaded with patches on different channels and you merely want to switch channels- each patch is mapped to a different channel, but you don't want program change messages being sent to mess up your patches. Use this for banks of Linuxsampler channels. - Added 'separatechannels' option for patch banks With separatechannels=0, patches mapped to different channels appear in the same patch bank. With this option, you can have a collection of several patches on different channels that appear together in one list for browsing. This is useful for sampling synths where your patches are pre-loaded onto channels. With separatechannels=1, the old behavior is used. The old behavior splits each channel into a separate bank. This works well for DSSI softsynths, where many synths run on the same port, but each channel accesses a different synth and different set of patches. Fixes ----- * MIDI thread now runs at high priority FIFO, rather than low priority FIFO-- this may improve MIDI performance, and hopefully will not affect stability. * Fixed configuration bug that broke 'CTRL+click' loop renaming. 2006-05-17 v0.5.2a Bug Fix Release --------------- * v0.5.2 MIDI port switching was broken. (Problem in the configuration .fweelin.rc). The configuration in this release should work. No other changes have been made. 2006-05-13 v0.5.2 The Patch Browser Upgrade New Features ------------ * Integrated patch browsers for external audio apps * Bank and program changes are now sent based on the patches you define * MIDI outputs are now switched as part of the integrated patch browser * Automatic patch list generation for DSSI softsynths Detail: The Fluidsynth patch browser has been expanded to provide patch browsing for external synths/apps. You can define your patches (MIDI port, channel, bank, program, and name) in external XML patch files. All your patches, internal and external, now appear in the patch browser. The browser now has several pages, one for each MIDI port and channel for which you have defined patches. Therefore, if you have Hexter on channel 1 of MIDI output 1, and WhySynth on channel 2 of MIDI output 1, you can independently browse your Hexter and WhySynth patches right from within Freewheeling. Freewheeling sends the right bank and program changes out the right MIDI port based on your patch definitions. It also echoes your MIDI events to the right place, so that you can switch one keyboard between several softsynths. When you have the patch browser selected, you can use the left/right arrow keys to switch between browser sections. This causes your incoming MIDI events to be switched from one port to another- as defined in your ~/.fweelin.rc and patch XML files. This way, you can quickly switch between softsynths without leaving Freewheeling's interface. To use this feature, please read 'examples/readme.txt' for setup info. I will likely be expanding this to include 'combi' type actions where you can custom configure your MIDI signal to be sent to several softsynths. Then you could, for example, play Hexter with your left hand and Linuxsampler with your right hand. * Configuration files now live in ~/.fweelin/ ~/.fweelin.rc will be moved to ~/.fweelin/.fweelin.rc when you start version 0.5.2. Fixes ----- * Fixed startup segfault when running without integrated FluidSynth 2006-03-22 v0.5.1 Thank you to all for good ideas and inspiration over the summer and winter. Many thanks to Paul Davis for hooking me up with a great Linux Audio development gig. And thanks to an anonymous donor for his contribution, and to Dubphil and Paul Brossier for beta testing. ** FreeWheeling now requires libgnutls11-dev (gnutls-openssl) instead of openssl (Thanks, Piem). New Features ------------ * Significantly less memory usage-- more than 20 megabytes less. Thanks to Drobilla for pointing out the issue with thread stack size. * New scripts (see scripts/ folder) to help you manage a library of loops. You can now bath move, delete, and archive loops & scenes by date. * Jack transport sync- - Master and slave mode For sync to work, you must first create a pulse, either by recording a loop and pressing F1, or by tapping a pulse by tapping F2 twice. Freewheeling tries to become the Jack timebase master, but if another app is master, it switches to slave mode. In master mode, Freewheeling generates beats and bar counts for every repetition of the currently selected pulse. In slave mode, Freewheeling receives beats and bar counts and syncronizes the currently selected pulse to them. For both master and slave modes, you can adjust the number of bars/beats per pulse using: Ctrl/Shift + S - adjust timebase You can also switch between sync to bars or sync to beats using: Alt + S - switch bars/beats sync Note that in master mode, FW is currently hard-wired to generate 4 beats per bar. Since this is preliminary code, not a big deal. * New user interface - Progress bar for saving and loading loops and scenes - Better organization of help page with clear sections - Mouse support - Click on loops triggers them. - Space + Click erases loops. - Mousewheel on loops now adjusts loop volumes-- very convenient when you are mixing and playing with improvisations. These can be configured. See 'loop-clicked' in .fweelin.rc. - Joystick support - Joystick buttons can now trigger events. For example, I have used FW with a DDR dance mat to trigger loops. See 'joybutton' in .fweelin.rc. - New 'engage' and 'shot' options in trigger-loop. 'Engage' forces a loop to ON or OFF, overriding the default toggle behavior. You can use it to create triggers that play short bursts, rather than long loops. 'Shot' to be implemented. * Stability improvements - Better thread safety and design improvements to the real-time memory manager have improved stability. * Significant improvements to loop/scene management and browsing - You can now give loops and scenes your own names - New names are stored within the filename of library files - Expanded browser window shows several items at once - Browser now sorts so that newer loops and scenes are first * Better handling of looppoints - Resolved issue with clicking at the looppoint on reloaded loops. - Resolved sporadic clicks on syncronized loops. * Better handling of loading/saving loops * Adjustable video loop delay - You can now adjust the performance of FreeWheeling by changing the delay between video refreshes. Several people asked for this feature, because FW is processor-heavy on the video side. The video thread does run at a low priority, and so it should not affect the performance of other realtime audio threads. However, the system may get sluggish, and if this happens, you may want to increase the delay in .fweelin.rc: Fixes ----- * Fixed 'glibc double free' segfault- FW should now run when compiled with GCC 4.0. * Adjusted the way F2 tap tempo works- tapping a new tempo with F2 is now more responsive, but less tolerant of mistakes * Fixed 'pure virtual method called' segfault * Fixed segfault when browsing past end of FluidSynth patch list * Various fixes to reduce CPU hogging * Merged patches from Piem's debian package: MaxVol, compile fixes for GCC 4.0, and removal of non-free elements * FW can now run without physical JACK inputs or outputs. Thanks to Piem for this patch. 2005-05-02 v0.5pre4 Many thanks to Sune Mai for several clever fixes, to Plutek for your generous donation, and to all of you for inspiration and feedback: Wolfgang Woehl, Mark Knecht, Shayne O'Connor, Esben Stien, Gregory Maxwell... ** FreeWheeling now requires libvorbisfile. New Features ------------ * Go back to previous improvisations - Saving -and- loading of loops and scenes of many loops - Integrated browser for scenes, loops, and FluidSynth patches - Loops and scenes are sorted by time in browser QuickStart: Use F8 to save a loop, F7 to save a scene of all loops, F9 to toggle auto-saving of all loops, 'b' to switch browsers from FluidSynth to Loops to Scenes, 'enter' to load the selected loop or scene, Shift +/- jumps to the next group of scenes or loops on disk (at least an hour different in time) When loading a scene, the loops are restored to their original placement. When loading a single loop, it goes to the footswitch (SW) by default. You can then move it to any QWERTY or MIDI key by pressing that key. FreeWheeling no longer saves in folders save1, save2, etc. A new library folder (by default, fw-lib/) contains all your loops, scenes, and live mixes. A new script scripts/godelete-date, can be used to delete loops and scenes from your library by date. * Full stereo support - Individual inputs configurable stereo or mono - Automatic stereo or mono loops - FluidSynth in stereo or mono QuickStart: In ~/.fweelin.rc find: This configures two mono and one stereo input. FreeWheeling no longer auto-connects to system inputs and outputs. You only need to configure what kinds of inputs you'd like. Please note that, for now, you need to manually add displays and keyboard mappings for any inputs you add. The rest is handled automatically. * Multiple ALSA MIDI outputs - Send live MIDI messages to different MIDI ports to control different Linux apps in real-time QuickStart: Use "m" key to switch MIDI outputs. The default configuration, defines two MIDI outputs. "m" toggles between the two outputs and the internal FluidSynth. * Configurable limiter - Max gain, threshold, and release rate can be changed - By default, limiter no longer raises gain above 100% See help in ~/.fweelin.rc * Input level displays - Peak levels for each input are now shown * Footpedal volume adjust configuration QuickStart: Use MIDI controller 1 to control individual input levels. Press keyboard 1-4 to select input. Then move CC1 to adjust volume. Or press and hold keyboard 1-4 while moving CC1 to jump to a new pedal value without adjusting volume. In ~/.fweelin.rc, see: You can change the CC# and max volume. * Laptop keyboard configuration QuickStart: If you are using FW on a laptop, you probably don't have easy access to some keys. I've provided a laptop keyboard configuration which remaps some keys. In the help pages, the new keys are shown in square brackets. To enable this configuration, edit ~/.fweelin.rc: init="0" becomes init="1" * Config file version checking - If your config file is out of date, FreeWheeling will ask whether you'd like a new one installed. This means you never have to manually erase ~/.fweelin.rc. Fixes ----- * fixed MIDI note off being misinterpreted on keyboards that send note on with velocity 0 * JACK ports are no longer auto-connected * fixed startup hang on some systems (mutex init problem) * fixed bug in block memory allocator Recycle() that causes a segfault during bursting of many events * compile fix error: 'ISO C++ forbids cast to non-reference type used as l-value' in RTNew() * footswitch is now controller 64 by default, not 67 * several keys have been remapped- see the help for details 2005-03-11 v0.5pre3 New Features ------------ * A new way to tap downbeat and tempo (tap-pulse event) * Switching of metronome sound for pulses (switch-metronome event) * FreeWheeling events can now trigger MIDI events, so you can control other audio apps from within FluidSynth-- For example, you can fire off changes to your modular synths from your keyboard or footpedals. This eliminates the need for an extra MIDI router app, since it is now built in to FreeWheeling. Your custom FreeWheeling setup defines how MIDI events are generated. * More flexible, clearer configuration syntax, with better error checking and colored warning messages. * Full input & output implementation of MIDI program change and pitch bend messages. * An example of the new MIDI output features- A MIDI patch changer has been configured using the left/right arrow keys. An on screen display shows patch number. See .fweelin.rc and video tutorial: Hookups. * Faster, tighter memory management for events. * Scripts are now included that load FreeWheeling and Hexter DX7 softsynth, connect to LADSPA reverb and tube amp sim- see scripts/README. Fixes ----- * fixed config bug that may cause "PreallocatedType: no instance available" errors on startup * compile fix on Mandrake GCC 3.4.x - 'parenthesized type-id' error 2005-01-19 v0.5pre2 New Features * Saving and autosaving of loops in OGG format- loops and live mixes are saved in their own folders * Real-time toggling of FluidSynth * Multipage help * Documentation for 'z'/'x' loop octave Fixes * configure check for SDL_gfx filledPieRGBA vs filledpieRGBA * configure now gives websites for dependent libraries * added XInitThreads to fix 'Xlib async reply' error 2005-01-03 v0.5pre1 - first public prerelease 2003 -2004 v0.1, 0.2, 0.3, 0.4 (internal) many internal changes-- * moving from OpenGL to 2-D SDL * loop visuals * downbeat awareness * memory manager * event manager * block extended data * configuration system * many bugfixes These form the foundation of FreeWheeling as a modular looping platform. 2002-06-05 FreeWheeling (then 'dogon listening device') * initial Linux version based on Mac MAX/MSP prototype freewheeling-0.6.6/INSTALL000066400000000000000000000366141370736313100152360ustar00rootroot00000000000000Installation Instructions ************************* Copyright (C) 1994-1996, 1999-2002, 2004-2016 Free Software Foundation, Inc. Copying and distribution of this file, with or without modification, are permitted in any medium without royalty provided the copyright notice and this notice are preserved. This file is offered as-is, without warranty of any kind. Basic Installation ================== Briefly, the shell command './configure && make && make install' should configure, build, and install this package. The following more-detailed instructions are generic; see the 'README' file for instructions specific to this package. Some packages provide this 'INSTALL' file but do not implement all of the features documented below. The lack of an optional feature in a given package is not necessarily a bug. More recommendations for GNU packages can be found in *note Makefile Conventions: (standards)Makefile Conventions. The 'configure' shell script attempts to guess correct values for various system-dependent variables used during compilation. It uses those values to create a 'Makefile' in each directory of the package. It may also create one or more '.h' files containing system-dependent definitions. Finally, it creates a shell script 'config.status' that you can run in the future to recreate the current configuration, and a file 'config.log' containing compiler output (useful mainly for debugging 'configure'). It can also use an optional file (typically called 'config.cache' and enabled with '--cache-file=config.cache' or simply '-C') that saves the results of its tests to speed up reconfiguring. Caching is disabled by default to prevent problems with accidental use of stale cache files. If you need to do unusual things to compile the package, please try to figure out how 'configure' could check whether to do them, and mail diffs or instructions to the address given in the 'README' so they can be considered for the next release. If you are using the cache, and at some point 'config.cache' contains results you don't want to keep, you may remove or edit it. The file 'configure.ac' (or 'configure.in') is used to create 'configure' by a program called 'autoconf'. You need 'configure.ac' if you want to change it or regenerate 'configure' using a newer version of 'autoconf'. The simplest way to compile this package is: 1. 'cd' to the directory containing the package's source code and type './configure' to configure the package for your system. Running 'configure' might take a while. While running, it prints some messages telling which features it is checking for. 2. Type 'make' to compile the package. 3. Optionally, type 'make check' to run any self-tests that come with the package, generally using the just-built uninstalled binaries. 4. Type 'make install' to install the programs and any data files and documentation. When installing into a prefix owned by root, it is recommended that the package be configured and built as a regular user, and only the 'make install' phase executed with root privileges. 5. Optionally, type 'make installcheck' to repeat any self-tests, but this time using the binaries in their final installed location. This target does not install anything. Running this target as a regular user, particularly if the prior 'make install' required root privileges, verifies that the installation completed correctly. 6. You can remove the program binaries and object files from the source code directory by typing 'make clean'. To also remove the files that 'configure' created (so you can compile the package for a different kind of computer), type 'make distclean'. There is also a 'make maintainer-clean' target, but that is intended mainly for the package's developers. If you use it, you may have to get all sorts of other programs in order to regenerate files that came with the distribution. 7. Often, you can also type 'make uninstall' to remove the installed files again. In practice, not all packages have tested that uninstallation works correctly, even though it is required by the GNU Coding Standards. 8. Some packages, particularly those that use Automake, provide 'make distcheck', which can by used by developers to test that all other targets like 'make install' and 'make uninstall' work correctly. This target is generally not run by end users. Compilers and Options ===================== Some systems require unusual options for compilation or linking that the 'configure' script does not know about. Run './configure --help' for details on some of the pertinent environment variables. You can give 'configure' initial values for configuration parameters by setting variables in the command line or in the environment. Here is an example: ./configure CC=c99 CFLAGS=-g LIBS=-lposix *Note Defining Variables::, for more details. Compiling For Multiple Architectures ==================================== You can compile the package for more than one kind of computer at the same time, by placing the object files for each architecture in their own directory. To do this, you can use GNU 'make'. 'cd' to the directory where you want the object files and executables to go and run the 'configure' script. 'configure' automatically checks for the source code in the directory that 'configure' is in and in '..'. This is known as a "VPATH" build. With a non-GNU 'make', it is safer to compile the package for one architecture at a time in the source code directory. After you have installed the package for one architecture, use 'make distclean' before reconfiguring for another architecture. On MacOS X 10.5 and later systems, you can create libraries and executables that work on multiple system types--known as "fat" or "universal" binaries--by specifying multiple '-arch' options to the compiler but only a single '-arch' option to the preprocessor. Like this: ./configure CC="gcc -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ CXX="g++ -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ CPP="gcc -E" CXXCPP="g++ -E" This is not guaranteed to produce working output in all cases, you may have to build one architecture at a time and combine the results using the 'lipo' tool if you have problems. Installation Names ================== By default, 'make install' installs the package's commands under '/usr/local/bin', include files under '/usr/local/include', etc. You can specify an installation prefix other than '/usr/local' by giving 'configure' the option '--prefix=PREFIX', where PREFIX must be an absolute file name. You can specify separate installation prefixes for architecture-specific files and architecture-independent files. If you pass the option '--exec-prefix=PREFIX' to 'configure', the package uses PREFIX as the prefix for installing programs and libraries. Documentation and other data files still use the regular prefix. In addition, if you use an unusual directory layout you can give options like '--bindir=DIR' to specify different values for particular kinds of files. Run 'configure --help' for a list of the directories you can set and what kinds of files go in them. In general, the default for these options is expressed in terms of '${prefix}', so that specifying just '--prefix' will affect all of the other directory specifications that were not explicitly provided. The most portable way to affect installation locations is to pass the correct locations to 'configure'; however, many packages provide one or both of the following shortcuts of passing variable assignments to the 'make install' command line to change installation locations without having to reconfigure or recompile. The first method involves providing an override variable for each affected directory. For example, 'make install prefix=/alternate/directory' will choose an alternate location for all directory configuration variables that were expressed in terms of '${prefix}'. Any directories that were specified during 'configure', but not in terms of '${prefix}', must each be overridden at install time for the entire installation to be relocated. The approach of makefile variable overrides for each directory variable is required by the GNU Coding Standards, and ideally causes no recompilation. However, some platforms have known limitations with the semantics of shared libraries that end up requiring recompilation when using this method, particularly noticeable in packages that use GNU Libtool. The second method involves providing the 'DESTDIR' variable. For example, 'make install DESTDIR=/alternate/directory' will prepend '/alternate/directory' before all installation names. The approach of 'DESTDIR' overrides is not required by the GNU Coding Standards, and does not work on platforms that have drive letters. On the other hand, it does better at avoiding recompilation issues, and works well even when some directory options were not specified in terms of '${prefix}' at 'configure' time. Optional Features ================= If the package supports it, you can cause programs to be installed with an extra prefix or suffix on their names by giving 'configure' the option '--program-prefix=PREFIX' or '--program-suffix=SUFFIX'. Some packages pay attention to '--enable-FEATURE' options to 'configure', where FEATURE indicates an optional part of the package. They may also pay attention to '--with-PACKAGE' options, where PACKAGE is something like 'gnu-as' or 'x' (for the X Window System). The 'README' should mention any '--enable-' and '--with-' options that the package recognizes. For packages that use the X Window System, 'configure' can usually find the X include and library files automatically, but if it doesn't, you can use the 'configure' options '--x-includes=DIR' and '--x-libraries=DIR' to specify their locations. Some packages offer the ability to configure how verbose the execution of 'make' will be. For these packages, running './configure --enable-silent-rules' sets the default to minimal output, which can be overridden with 'make V=1'; while running './configure --disable-silent-rules' sets the default to verbose, which can be overridden with 'make V=0'. Particular systems ================== On HP-UX, the default C compiler is not ANSI C compatible. If GNU CC is not installed, it is recommended to use the following options in order to use an ANSI C compiler: ./configure CC="cc -Ae -D_XOPEN_SOURCE=500" and if that doesn't work, install pre-built binaries of GCC for HP-UX. HP-UX 'make' updates targets which have the same time stamps as their prerequisites, which makes it generally unusable when shipped generated files such as 'configure' are involved. Use GNU 'make' instead. On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot parse its '' header file. The option '-nodtk' can be used as a workaround. If GNU CC is not installed, it is therefore recommended to try ./configure CC="cc" and if that doesn't work, try ./configure CC="cc -nodtk" On Solaris, don't put '/usr/ucb' early in your 'PATH'. This directory contains several dysfunctional programs; working variants of these programs are available in '/usr/bin'. So, if you need '/usr/ucb' in your 'PATH', put it _after_ '/usr/bin'. On Haiku, software installed for all users goes in '/boot/common', not '/usr/local'. It is recommended to use the following options: ./configure --prefix=/boot/common Specifying the System Type ========================== There may be some features 'configure' cannot figure out automatically, but needs to determine by the type of machine the package will run on. Usually, assuming the package is built to be run on the _same_ architectures, 'configure' can figure that out, but if it prints a message saying it cannot guess the machine type, give it the '--build=TYPE' option. TYPE can either be a short name for the system type, such as 'sun4', or a canonical name which has the form: CPU-COMPANY-SYSTEM where SYSTEM can have one of these forms: OS KERNEL-OS See the file 'config.sub' for the possible values of each field. If 'config.sub' isn't included in this package, then this package doesn't need to know the machine type. If you are _building_ compiler tools for cross-compiling, you should use the option '--target=TYPE' to select the type of system they will produce code for. If you want to _use_ a cross compiler, that generates code for a platform different from the build platform, you should specify the "host" platform (i.e., that on which the generated programs will eventually be run) with '--host=TYPE'. Sharing Defaults ================ If you want to set default values for 'configure' scripts to share, you can create a site shell script called 'config.site' that gives default values for variables like 'CC', 'cache_file', and 'prefix'. 'configure' looks for 'PREFIX/share/config.site' if it exists, then 'PREFIX/etc/config.site' if it exists. Or, you can set the 'CONFIG_SITE' environment variable to the location of the site script. A warning: not all 'configure' scripts look for a site script. Defining Variables ================== Variables not defined in a site shell script can be set in the environment passed to 'configure'. However, some packages may run configure again during the build, and the customized values of these variables may be lost. In order to avoid this problem, you should set them in the 'configure' command line, using 'VAR=value'. For example: ./configure CC=/usr/local2/bin/gcc causes the specified 'gcc' to be used as the C compiler (unless it is overridden in the site shell script). Unfortunately, this technique does not work for 'CONFIG_SHELL' due to an Autoconf limitation. Until the limitation is lifted, you can use this workaround: CONFIG_SHELL=/bin/bash ./configure CONFIG_SHELL=/bin/bash 'configure' Invocation ====================== 'configure' recognizes the following options to control how it operates. '--help' '-h' Print a summary of all of the options to 'configure', and exit. '--help=short' '--help=recursive' Print a summary of the options unique to this package's 'configure', and exit. The 'short' variant lists options used only in the top level, while the 'recursive' variant lists options also present in any nested packages. '--version' '-V' Print the version of Autoconf used to generate the 'configure' script, and exit. '--cache-file=FILE' Enable the cache: use and save the results of the tests in FILE, traditionally 'config.cache'. FILE defaults to '/dev/null' to disable caching. '--config-cache' '-C' Alias for '--cache-file=config.cache'. '--quiet' '--silent' '-q' Do not print messages saying which checks are being made. To suppress all normal output, redirect it to '/dev/null' (any error messages will still be shown). '--srcdir=DIR' Look for the package's source code in directory DIR. Usually 'configure' can determine that directory automatically. '--prefix=DIR' Use DIR as the installation prefix. *note Installation Names:: for more details, including other options available for fine-tuning the installation locations. '--no-create' '-n' Run the configure checks, but stop before creating any output files. 'configure' also accepts some other, not widely useful, options. Run 'configure --help' for more details. freewheeling-0.6.6/MacOSX/000077500000000000000000000000001370736313100152655ustar00rootroot00000000000000freewheeling-0.6.6/MacOSX/English.lproj/000077500000000000000000000000001370736313100200035ustar00rootroot00000000000000freewheeling-0.6.6/MacOSX/English.lproj/InfoPlist.strings000066400000000000000000000005421370736313100233260ustar00rootroot00000000000000ÿþ/* Localized versions of Info.plist keys */ CFBundleName = "FreeWheeling"; CFBundleShortVersionString = "FreeWheeling"; NSHumanReadableCopyright = "Copyright 2007 Jan Pekau"; freewheeling-0.6.6/MacOSX/FweelinMac.h000066400000000000000000000015151370736313100174520ustar00rootroot00000000000000// // FweelinMac.h // fweelin // #ifndef __FWEELIN_MAC_H__ #define __FWEELIN_MAC_H__ // Interface class between Objective-C Mac OS X code and C++ Fweelin code class FweelinMac { public: // Performs setup/takedown on a new pthread to make it behave well with Cocoa void SetupCocoaThread(); void TakedownCocoaThread(); void *autoreleasepool; // MIDI input list static void ClearMIDIInputList(); static void AddMIDIInputSource(char *name); static void SetMIDIInput(int idx); // Menu shortcuts to commands static void SetDebugMode(int active); static void Quit(); static void ShowHelp(); static void LinkSDLMain (void *m) { sdlmain = m; }; static void *sdlmain; // Pointer to instance of SDLMain static void LinkFweelin (void *fw) { fweelin = fw; }; static void *fweelin; // Pointer to instance of Fweelin }; #endiffreewheeling-0.6.6/MacOSX/FweelinMac.mm000066400000000000000000000032021370736313100176270ustar00rootroot00000000000000// // FweelinMac.mm // fweelin // #import #include "FweelinMac.h" #include "SDLMain.h" #include "fweelin_core.h" void *FweelinMac::sdlmain = 0; void *FweelinMac::fweelin = 0; void FweelinMac::ClearMIDIInputList() { // printf("***SDLMAIN: %p\n",sdlmain); SDLMain *s = (SDLMain *)sdlmain; [s clearMIDIInputList]; }; void FweelinMac::AddMIDIInputSource(char *name) { SDLMain *s = (SDLMain *)sdlmain; [s addMIDIInputSource:[NSString stringWithUTF8String:name]]; }; void FweelinMac::SetMIDIInput(int idx) { // Connect MIDI Fweelin *fw = (Fweelin *)fweelin; fw->getMIDI()->SetMIDIInput(idx); }; void FweelinMac::SetDebugMode(int active) { Fweelin *fw = (Fweelin *)fweelin; ShowDebugInfoEvent *devt = (ShowDebugInfoEvent *) Event::GetEventByType(T_EV_ShowDebugInfo); devt->show = active; fw->getEMG()->BroadcastEventNow(devt, fw); }; void FweelinMac::Quit() { Fweelin *fw = (Fweelin *)fweelin; ExitSessionEvent *evt = (ExitSessionEvent *) Event::GetEventByType(T_EV_ExitSession); fw->getEMG()->BroadcastEventNow(evt, fw); }; void FweelinMac::ShowHelp() { Fweelin *fw = (Fweelin *)fweelin; VideoShowHelpEvent *evt = (VideoShowHelpEvent *) Event::GetEventByType(T_EV_VideoShowHelp); evt->page = 1; fw->getEMG()->BroadcastEventNow(evt, fw); }; // Performs initialization on a new pthread to make it behave well with Cocoa void FweelinMac::SetupCocoaThread() { // printf("MULTITHREADED: %d\n",[NSThread isMultiThreaded]); autoreleasepool = [[NSAutoreleasePool alloc] init]; }; void FweelinMac::TakedownCocoaThread() { NSAutoreleasePool *tmp = (NSAutoreleasePool *) autoreleasepool; [tmp release]; }; freewheeling-0.6.6/MacOSX/Info.plist000066400000000000000000000015351370736313100172410ustar00rootroot00000000000000 CFBundleDevelopmentRegion English CFBundleExecutable ${EXECUTABLE_NAME} CFBundleIconFile freewheeling.icns CFBundleIdentifier com.yourcompany.fweelin CFBundleInfoDictionaryVersion 6.0 CFBundleName ${PRODUCT_NAME} CFBundlePackageType APPL CFBundleSignature ???? CFBundleVersion MAC NSMainNibFile SDLMain NSPrincipalClass NSApplication freewheeling-0.6.6/MacOSX/README-MAC000066400000000000000000000114441370736313100165470ustar00rootroot00000000000000Intro for Mac OS X ================== FreeWheeling for Mac OS X is a direct port of the Linux version. A Universal binary will be made available for each release, along with source code if you wish to compile it yourself. The user interface remains the same across OS X and Linux versions. This means that FreeWheeling OS X does not make use of Mac's Aqua interface. A few basic commands specific to the Mac version have been provided in a Mac menu. The rest of the functionality is built into the app window. FreeWheeling is designed to be mostly MIDI and keyboard driven. A few things can be done from a mouse, but while playing music, the idea is to keep your hands on your instrument. FreeWheeling is not a music production or DJing tool. FreeWheeling works for instrumentalists, such as drummers, guitarists, keyboardists and vocalists. FreeWheeling is like a second instrument, that you use to reflect back parts of your playing, to build loops in a spontaneous way. You can configure FreeWheeling to work with the PC keyboard, joysticks, or MIDI-enabled devices. Setup for Mac OS X ================== 1. Drag the 'Fweelin' app to the 'Applications' folder. 2. Download and install JACK. http://jackosx.com/ Jack is an audio connection kit similar to Rewire. It allows you to plug FreeWheeling into different audio apps, such as soft synths or sequencers. 3. Start 'Jack Pilot', included with your JACK installation. Set the lowest possible latency that provides stable performance. Set 'Jack Pilot' to 'Full Duplex' (recording and playback enabled), if you wish to record live instruments in FreeWheeling. If you are using the onboard Mac sound, you can get 'Full Duplex' recording and playback by creating an 'Aggregate Audio Device'. To do this, choose 'Open Audio MIDI Setup' from the JackPilot menu, or run 'Applications/Utilities/Audio MIDI Setup'. Then, select 'Open Aggregate Device Editor...' from the Audio menu. 4. If you wish to debug the console output of FreeWheeling for troubleshooting, start 'Applications/Utilities/Console' now. 5. Run 'FreeWheeling'. The main window should appear. If it does not, consult the Console log (step 4), or try running from a Terminal. Using FreeWheeling for Mac OS X =============================== FreeWheeling can be driven from any one MIDI source. To select the source, choose 'Preferences' from the 'Fweelin' menu. By default, FreeWheeling grabs loops with the QWERTY keys as well as one octave of keys on your MIDI keyboard. This can be configured in the configuration files. The main one is ~/.fweelin/fweelin.xml. They are all stored in ~/.fweelin. Some keyboard commands (function keys especially) may conflict with Mac OS X keyboard shortcuts. I suggest using an external USB keyboard, or modifying Freewheeling's configuration. You will have to connect audio to go into and out of FreeWheeling using Jack Pilot. Most often, you will want to route your system audio inputs into FreeWheeling, and FreeWheeling's audio outputs back out to the system, or into a sequencer or effects program. Regular Mac audio apps work with JACK. Simply point them to the 'JACK' device. FreeWheeling can also drive soft-synths and effects. FreeWheeling creates several MIDI outputs, which appear as virtual MIDI sources. You can connect your audio apps to these MIDI sources. FreeWheeling has a built-in configurable patch browser that can be used to select patches on different MIDI outputs. You can also create combination patches that split your MIDI input into a variety of keyboard zones, playing different outputs together. For a crash-course in Freewheeling (albeit, an old version), please refer to the video tutorials at: http://freewheeling.sourceforge.net/ If you'd like to configure Freewheeling, please read the configuration files located in your home folder in the hidden subfolder .fweelin/ (once you've run FreeWheeling, this folder appears) To find this folder through the Finder, you must have hidden files enabled in your Finder. Or, you can access it through the Mac Terminal app. For more help, please browse or sign on to the mailing-list. Happy Looping! -JP Mercury. Compiling FreeWheeling from Source ================================== FreeWheeling for Mac OS X can be compiled from source. Download the source package. You will need Apple's XCode tools. Load MacOSX/fweelin.xcodeproj FreeWheeling depends on several frameworks. Many of these can be installed from third-party sites. However, some, such as libsndfile, require a small amount of tweaking to be compiled as Frameworks. A ZIP file of all dependency Frameworks with xcodeproj files is available. Please contact JP Mercury: http://home.graffiti.net/swirlee/swirlee.jpg If you wish to contribute to the development of FreeWheeling, please be in touch. Happy Compiling! -JP Mercury. freewheeling-0.6.6/MacOSX/SDLMain.h000066400000000000000000000010651370736313100166670ustar00rootroot00000000000000/* SDLMain.m - main entry point for our Cocoa-ized SDL app Initial Version: Darrell Walisser Non-NIB-Code & other changes: Max Horn Feel free to customize this file to suit your needs */ #import @interface SDLMain : NSObject { IBOutlet NSPopUpButton *midiInputSel; } - (IBAction)setMIDIInput:(id)sender; - (IBAction)toggleDebugMode:(id)sender; - (IBAction)quitFW:(id)sender; - (IBAction)showHelp:(id)sender; - (void)clearMIDIInputList; - (void)addMIDIInputSource:(NSString *)name; @end freewheeling-0.6.6/MacOSX/SDLMain.mm000066400000000000000000000300461370736313100170520ustar00rootroot00000000000000/* SDLMain.m - main entry point for our Cocoa-ized SDL app Initial Version: Darrell Walisser Non-NIB-Code & other changes: Max Horn Feel free to customize this file to suit your needs */ #import "SDL.h" #import "SDLMain.h" #include "FweelinMac.h" #import /* for MAXPATHLEN */ #import extern char *FWEELIN_DATADIR; /* For some reaon, Apple removed setAppleMenu from the headers in 10.4, but the method still is there and works. To avoid warnings, we declare it ourselves here. */ @interface NSApplication(SDL_Missing_Methods) - (void)setAppleMenu:(NSMenu *)menu; @end /* Use this flag to determine whether we use SDLMain.nib or not */ #define SDL_USE_NIB_FILE 1 /* Use this flag to determine whether we use CPS (docking) or not */ #define SDL_USE_CPS 1 #ifdef SDL_USE_CPS /* Portions of CPS.h */ typedef struct CPSProcessSerNum { UInt32 lo; UInt32 hi; } CPSProcessSerNum; extern OSErr CPSGetCurrentProcess( CPSProcessSerNum *psn); extern OSErr CPSEnableForegroundOperation( CPSProcessSerNum *psn, UInt32 _arg2, UInt32 _arg3, UInt32 _arg4, UInt32 _arg5); extern OSErr CPSSetFrontProcess( CPSProcessSerNum *psn); #endif /* SDL_USE_CPS */ static int gArgc; static char **gArgv; static BOOL gFinderLaunch; static BOOL gCalledAppMainline = FALSE; static NSString *getApplicationName(void) { NSDictionary *dict; NSString *appName = 0; /* Determine the application name */ dict = (NSDictionary *)CFBundleGetInfoDictionary(CFBundleGetMainBundle()); if (dict) appName = [dict objectForKey: @"CFBundleName"]; if (![appName length]) appName = [[NSProcessInfo processInfo] processName]; return appName; } #if SDL_USE_NIB_FILE /* A helper category for NSString */ @interface NSString (ReplaceSubString) - (NSString *)stringByReplacingRange:(NSRange)aRange with:(NSString *)aString; @end #endif @interface SDLApplication : NSApplication @end @implementation SDLApplication /* Invoked from the Quit menu item */ - (void)terminate:(id)sender { /* Post a SDL_QUIT event */ SDL_Event event; event.type = SDL_QUIT; SDL_PushEvent(&event); } @end /* The main class of the application, the application's delegate */ @implementation SDLMain - (void)awakeFromNib { // NSLog(@"AWAKE\n"); FweelinMac::LinkSDLMain(self); } - (IBAction)toggleDebugMode:(id)sender { // Toggle debug mode int state = [sender state]; state = (state == 0 ? 1 : 0); [sender setState:state]; FweelinMac::SetDebugMode(state); } - (IBAction)quitFW:(id)sender { FweelinMac::Quit(); } - (IBAction)showHelp:(id)sender { FweelinMac::ShowHelp(); } - (IBAction)setMIDIInput:(id)sender { // printf("IDX: %d\n",idx); int idx = [sender indexOfSelectedItem]; FweelinMac::SetMIDIInput(idx); } - (void)clearMIDIInputList { [midiInputSel removeAllItems]; } - (void)addMIDIInputSource:(NSString *)name { [midiInputSel addItemWithTitle:name]; } // Dummy thread to invoke multithreaded mode - (void) dummyThread:(id)sender { while (1) { printf("Dummy thread!\n"); sleep(1); } //[NSThread exit]; } /* Set the working directory to the .app's parent directory */ - (void) setupWorkingDirectory:(BOOL)shouldChdir { if (shouldChdir) { char parentdir[MAXPATHLEN]; CFURLRef url = CFBundleCopyBundleURL(CFBundleGetMainBundle()); CFURLRef url2 = CFURLCreateCopyDeletingLastPathComponent(0, url); if (CFURLGetFileSystemRepresentation(url2, true, (UInt8 *)parentdir, MAXPATHLEN)) { assert ( chdir (parentdir) == 0 ); /* chdir to the binary app's parent */ } CFRelease(url); CFRelease(url2); } } #if SDL_USE_NIB_FILE /* Fix menu to contain the real app name instead of "SDL App" */ - (void)fixMenu:(NSMenu *)aMenu withAppName:(NSString *)appName { NSRange aRange; NSEnumerator *enumerator; NSMenuItem *menuItem; aRange = [[aMenu title] rangeOfString:@"SDL App"]; if (aRange.length != 0) [aMenu setTitle: [[aMenu title] stringByReplacingRange:aRange with:appName]]; enumerator = [[aMenu itemArray] objectEnumerator]; while ((menuItem = [enumerator nextObject])) { aRange = [[menuItem title] rangeOfString:@"SDL App"]; if (aRange.length != 0) [menuItem setTitle: [[menuItem title] stringByReplacingRange:aRange with:appName]]; if ([menuItem hasSubmenu]) [self fixMenu:[menuItem submenu] withAppName:appName]; } [ aMenu sizeToFit ]; } #else static void setApplicationMenu(void) { /* warning: this code is very odd */ NSMenu *appleMenu; NSMenuItem *menuItem; NSString *title; NSString *appName; appName = getApplicationName(); appleMenu = [[NSMenu alloc] initWithTitle:@""]; /* Add menu items */ title = [@"About " stringByAppendingString:appName]; [appleMenu addItemWithTitle:title action:@selector(orderFrontStandardAboutPanel:) keyEquivalent:@""]; [appleMenu addItem:[NSMenuItem separatorItem]]; title = [@"Hide " stringByAppendingString:appName]; [appleMenu addItemWithTitle:title action:@selector(hide:) keyEquivalent:@"h"]; menuItem = (NSMenuItem *)[appleMenu addItemWithTitle:@"Hide Others" action:@selector(hideOtherApplications:) keyEquivalent:@"h"]; [menuItem setKeyEquivalentModifierMask:(NSAlternateKeyMask|NSCommandKeyMask)]; [appleMenu addItemWithTitle:@"Show All" action:@selector(unhideAllApplications:) keyEquivalent:@""]; [appleMenu addItem:[NSMenuItem separatorItem]]; title = [@"Quit " stringByAppendingString:appName]; [appleMenu addItemWithTitle:title action:@selector(terminate:) keyEquivalent:@"q"]; /* Put menu into the menubar */ menuItem = [[NSMenuItem alloc] initWithTitle:@"" action:nil keyEquivalent:@""]; [menuItem setSubmenu:appleMenu]; [[NSApp mainMenu] addItem:menuItem]; /* Tell the application object that this is now the application menu */ [NSApp setAppleMenu:appleMenu]; /* Finally give up our references to the objects */ [appleMenu release]; [menuItem release]; } /* Create a window menu */ static void setupWindowMenu(void) { NSMenu *windowMenu; NSMenuItem *windowMenuItem; NSMenuItem *menuItem; windowMenu = [[NSMenu alloc] initWithTitle:@"Window"]; /* "Minimize" item */ menuItem = [[NSMenuItem alloc] initWithTitle:@"Minimize" action:@selector(performMiniaturize:) keyEquivalent:@"m"]; [windowMenu addItem:menuItem]; [menuItem release]; /* Put menu into the menubar */ windowMenuItem = [[NSMenuItem alloc] initWithTitle:@"Window" action:nil keyEquivalent:@""]; [windowMenuItem setSubmenu:windowMenu]; [[NSApp mainMenu] addItem:windowMenuItem]; /* Tell the application object that this is now the window menu */ [NSApp setWindowsMenu:windowMenu]; /* Finally give up our references to the objects */ [windowMenu release]; [windowMenuItem release]; } /* Replacement for NSApplicationMain */ static void CustomApplicationMain (int argc, char **argv) { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; SDLMain *sdlMain; /* Ensure the application object is initialised */ [SDLApplication sharedApplication]; #ifdef SDL_USE_CPS { CPSProcessSerNum PSN; /* Tell the dock about us */ if (!CPSGetCurrentProcess(&PSN)) if (!CPSEnableForegroundOperation(&PSN,0x03,0x3C,0x2C,0x1103)) if (!CPSSetFrontProcess(&PSN)) [SDLApplication sharedApplication]; } #endif /* SDL_USE_CPS */ /* Set up the menubar */ [NSApp setMainMenu:[[NSMenu alloc] init]]; setApplicationMenu(); setupWindowMenu(); /* Create SDLMain and make it the app delegate */ sdlMain = [[SDLMain alloc] init]; [NSApp setDelegate:sdlMain]; /* Start the main event loop */ [NSApp run]; [sdlMain release]; [pool release]; } #endif /* * Catch document open requests...this lets us notice files when the app * was launched by double-clicking a document, or when a document was * dragged/dropped on the app's icon. You need to have a * CFBundleDocumentsType section in your Info.plist to get this message, * apparently. * * Files are added to gArgv, so to the app, they'll look like command line * arguments. Previously, apps launched from the finder had nothing but * an argv[0]. * * This message may be received multiple times to open several docs on launch. * * This message is ignored once the app's mainline has been called. */ - (BOOL)application:(NSApplication *)theApplication openFile:(NSString *)filename { const char *temparg; size_t arglen; char *arg; char **newargv; if (!gFinderLaunch) /* MacOS is passing command line args. */ return FALSE; if (gCalledAppMainline) /* app has started, ignore this document. */ return FALSE; temparg = [filename UTF8String]; arglen = SDL_strlen(temparg) + 1; arg = (char *) SDL_malloc(arglen); if (arg == NULL) return FALSE; newargv = (char **) realloc(gArgv, sizeof (char *) * (gArgc + 2)); if (newargv == NULL) { SDL_free(arg); return FALSE; } gArgv = newargv; SDL_strlcpy(arg, temparg, arglen); gArgv[gArgc++] = arg; gArgv[gArgc] = NULL; return TRUE; } /* Called when the internal event loop has just started running */ - (void) applicationDidFinishLaunching: (NSNotification *) note { int status; /* Set the working directory to the .app's parent directory */ [self setupWorkingDirectory:gFinderLaunch]; #if SDL_USE_NIB_FILE /* Set the main menu to contain the real app name instead of "SDL App" */ [self fixMenu:[NSApp mainMenu] withAppName:getApplicationName()]; #endif /* Hand off to main application code */ gCalledAppMainline = TRUE; status = SDL_main (gArgc, gArgv); /* We're done, thank you for playing */ exit(status); } @end @implementation NSString (ReplaceSubString) - (NSString *)stringByReplacingRange:(NSRange)aRange with:(NSString *)aString { unsigned int bufferSize; unsigned int selfLen = [self length]; unsigned int aStringLen = [aString length]; unichar *buffer; NSRange localRange; NSString *result; bufferSize = selfLen + aStringLen - aRange.length; buffer = (unichar *) NSAllocateMemoryPages(bufferSize*sizeof(unichar)); /* Get first part into buffer */ localRange.location = 0; localRange.length = aRange.location; [self getCharacters:buffer range:localRange]; /* Get middle part into buffer */ localRange.location = 0; localRange.length = aStringLen; [aString getCharacters:(buffer+aRange.location) range:localRange]; /* Get last part into buffer */ localRange.location = aRange.location + aRange.length; localRange.length = selfLen - localRange.location; [self getCharacters:(buffer+aRange.location+aStringLen) range:localRange]; /* Build output string */ result = [NSString stringWithCharacters:buffer length:bufferSize]; NSDeallocateMemoryPages(buffer, bufferSize); return result; } @end #ifdef main # undef main #endif /* Main entry point to executable - should *not* be SDL_main! */ int main (int argc, char **argv) { /* Copy the arguments into a global variable */ /* This is passed if we are launched by double-clicking */ if ( argc >= 2 && strncmp (argv[1], "-psn", 4) == 0 ) { gArgv = (char **) SDL_malloc(sizeof (char *) * 2); gArgv[0] = argv[0]; gArgv[1] = NULL; gArgc = 1; gFinderLaunch = YES; } else { int i; gArgc = argc; gArgv = (char **) SDL_malloc(sizeof (char *) * (argc+1)); for (i = 0; i <= argc; i++) gArgv[i] = argv[i]; gFinderLaunch = NO; } // Setup multithreaded mode [NSThread detachNewThreadSelector:@selector(dummyThread) toTarget:nil withObject:nil]; // printf("MULTITHREADED: %d\n",[NSThread isMultiThreaded]); #if SDL_USE_NIB_FILE [SDLApplication poseAsClass:[NSApplication class]]; NSApplicationMain (argc, (const char **) argv); #else CustomApplicationMain (argc, argv); #endif return 0; } freewheeling-0.6.6/MacOSX/SDLMain.nib/000077500000000000000000000000001370736313100172635ustar00rootroot00000000000000freewheeling-0.6.6/MacOSX/SDLMain.nib/classes.nib000066400000000000000000000006131370736313100214120ustar00rootroot00000000000000{ IBClasses = ( {CLASS = FirstResponder; LANGUAGE = ObjC; SUPERCLASS = NSObject; }, { ACTIONS = {quitFW = id; setMIDIInput = id; showHelp = id; toggleDebugMode = id; }; CLASS = SDLMain; LANGUAGE = ObjC; OUTLETS = {midiInputSel = NSPopUpButton; }; SUPERCLASS = NSObject; } ); IBVersion = 1; }freewheeling-0.6.6/MacOSX/SDLMain.nib/info.nib000066400000000000000000000010651370736313100207120ustar00rootroot00000000000000 IBDocumentLocation 987 57 356 240 0 0 1440 878 IBEditorPositions 29 82 376 205 44 0 0 1440 878 IBFramework Version 446.1 IBOpenObjects 339 IBSystem Version 8L2127 freewheeling-0.6.6/MacOSX/SDLMain.nib/objects.nib000066400000000000000000000113161370736313100214100ustar00rootroot00000000000000 streamtypedè„@„„„NSIBObjectDataà„„NSObject…’„„„NSCustomObject)”„@@„„„NSMutableString„„NSString”„+ NSApplication†…†„i"–„––„™™SDLMain†…†•–„„„NSView)„„ NSResponder”’…š„ @@@@ffffffff„„„NSMutableArray„„NSArray”š’„„„ NSTextField„„ NSControl)’œš‚€…………-¾Ô¾Ô’œ’…’…’…„icc@„„„NSTextFieldCell>„„ NSActionCell„„NSCellA”„ii‚þ‚@„@@@@„™™+Help For Mac Users: Press / (?) for help inside FreeWheeling. Press repeatedly. There are several pages of help. This will give you a quick reference to most available commands. Essentials: Use the TAB key to switch layouts. The QWERTY keyboard keys start recording and playing loops. *** When the RED light is on, you are recording, and memory is being used. Press U to undo and stop. *** For more info on how to use FreeWheeling: Video Tutorials- http://freewheeling.sourceforge.net FreeWheeling is very configurable. Look in ~/.fweelin/.fweelin.rc for documentation and settings. *** There are some issues with keyboard keys on this Mac version. The internal Mac keyboard does not have all the keys we have bound to. I suggest using a full-size USB keyboard. Also, some international keyboards do not work quite right. If key bindings are not working for you, try enabling debug mode (in the Fweelin menu). From here, you can see all keypresses received on the console. All key bindings can then be edited in the configuration file, ~/.fweelin/.fweelin.rc †„„„NSFont”š$„[36c]ÿþLucidaGrande„f „c«««†……„i:…’…’¢„c@@„„„NSColor”«„@@@„™™System†„™™ controlColor†„­«„ffƒ«ª*?††„­«¯®„™™controlTextColor†„­«°†††’…„:…†’„£’œš‚€…………uu’œ’…’…’…¢„¦¦‚þ‚@§„™™All The Best... †„«š,„[44c]$ÿþLucidaGrande-Boldª ««««†……¬…’…’´­¬±†’…±…††……… àà’…’…’…’…†„„„NSWindowTemplateø”„ iiffffi@@@@@cˆõà‚xp„™™FreeWheeling Mac Help†„˜™NSWindow†„˜™View†œ…„ffff n«°Õ’…«°ƒîÿƒîÿ†–„„„NSMenuÌ”„i@@@„™™SDL App†„ š ’„„„ NSMenuItemŸ”’½„ i@@IIi@@@@:i@„™™ About SDL App†„™™†‚ÿÿÿ…„„„NSCustomResource)”–„™™NSImage†„™™NSMenuCheckmark††…„Æ–Ç„™™NSMenuMixedState††……’…’…†’„Â’½¹‚ÀÄÄ‚‚ÿÿÿ…Å…É……’…’…†’„Â’½¹„™™Preferences...†Ä‚‚ÿÿÿ…Å…É……’…’…†’„Â’½¹„™™ Debug Mode†Ä‚‚ÿÿÿ…Å…É……’…’…†’„Â’½¹‚ÀÄÄ‚‚ÿÿÿ…Å…É……’…’…†’„Â’½¹„™™ Hide SDL App†„™™h†‚‚ÿÿÿ…Å…É……’…’…†’„Â’½¹„™™ Hide Others†Ä‚‚ÿÿÿ…Å…É……’…’…†’„Â’½¹„™™Show All†Ä‚‚ÿÿÿ…Å…É……’…’…†’„Â’½¹‚ÀÄÄ‚‚ÿÿÿ…Å…É……’…’…†’„Â’½¹„™™ Quit SDL App†„™™q†‚‚ÿÿÿ…Å…É……’…’…††„™™ _NSAppleMenu††„Â’„¾·„™™SDLMain†„ š’Ý’„Â’Þ¹„™™Window†Ä‚‚ÿÿÿ…Å…É„submenuAction:…’…’„¾·„˜™Window†„ š’„’㹄™™Minimize†„™™m†‚‚ÿÿÿ…Å…É……’…’…††„™™_NSWindowsMenu†††’„Â’Þ¹„™™Help†Ä‚‚ÿÿÿ…Å…É»…’…’„¾·„˜™Help†„ š’„’칄™™FreeWheeling Help†„™™?†‚‚ÿÿÿ…Å…É……’…’…†’„’칄™™ FW Mac Help†„™™?†‚‚ÿÿÿ…Å…É……’…’…††…†††„™™ _NSMainMenu††¹¿Ä‚‚ÿÿÿ…Å…É»…’…’½†–Þ•–„¹´Œhð‚xð„™™ Preferences†„˜™NSPanel†„˜™View†„’…š„ š’„£’úš‚€…………ÏP P ’ú’…’…’…¢„¦¦‚þ‚@§„™™ MIDI Input:†„«š$©ÿþLucidaGrandeª «««« †……¬…’…’ü­¬±†’…±…†’„„„ NSPopUpButtonÌ„„NSButton¤’úš‚€…………¯::’ú’…’…’…¢„„„NSPopUpButtonCell1„„NSMenuItemCellÒ„„ NSButtonCell?§¦‚@þA„‚§…ª……¬…’…’„ ssii@@@@@K‚ÿ@‚Ä„˜™†…ª…–„Â’„¾·„˜™ OtherViews†„ š’’„Â’ ¹„™™Item2†Ä‚‚ÿÿÿ…Å…É„_popUpItemAction:…’’…†’„Â’ ¹„™™Item3†Ä‚‚ÿÿÿ…Å…ÉÂ…’’…††…†¹„™™Item1†Ä‚‚ÿÿÿ…Å…ÉÂ…’’…†…„i@i‚= †††………hðhð’…’…’…’…†…µ n«°Õ’…«°ƒîÿƒîÿ†•– –„––„™™ NSFontManager†…†•–òì–ìê–ãá–üú–ؽ–Ô½–Ýޖ̽–Á½–´œ–н– – –áޖ˽–æã–Ù½–Ö½– –ïì–¢œ–ν–¸•–ѽ–êÞ–ú–úöš–„™™ NSMenuItem†–´„™™ NSTextField21†–„™™ Font Manager†–ö„™™ Preferences†–æ„™™ NSMenuItem1†–¸„™™Mac Help†–•„˜™ File's Owner†–Ù„™™1111†–ꄘ™1†– „™™ PopUpList†–ü„™™NSTextField111111†–Þ„˜™MainMenu†–¢„™™ NSTextField2†–„™™ NSMenuItem2†–ã„™™NSMenu†–„™™ NSPopUpButton†–™†–섘™2†–á„™™ NSMenuItem1†–Є™™ NSMenuItem†– „™™ NSMenuItem1†–š›’„„„ NSMutableSet„„NSSet”„I†’„ š ’„„„NSNibControlConnectorÏ„„NSNibConnector”¯Á•„˜™orderFrontStandardAboutPanel:††’„-¯Ô•„™™hideOtherApplications:††’„-¯Ñ•„™™hide:††’„-¯Ö•„™™unhideAllApplications:††’„„„NSNibOutletConnectorÏ.¯•š„™™delegate††’„-¯æ…„˜™performMiniaturize:††’„-¯Ìö„™™makeKeyAndOrderFront:††’„7¯š„™™ midiInputSel††’„-¯š„™™ setMIDIInput:††’„-¯ò¸„™™makeKeyAndOrderFront:††’„-¯Îš„™™toggleDebugMode:††’„-¯Ùš„™™quitFW:††’„-¯ïš„™™ showHelp:†††’š0„@i2˜ÊöGÊцÊÐÄÊAUÊ6ÃÊÔ‘Ê¢VÊÎYÊÖ–ÊJÊÁ:ÊÝ8Ê4™Ê,ŽÊMÊêgÊÙˆÊØ•ÊòRÊãÊæʸSÊýÊ NÊ;OÊCZʽ9Ê9 ÊïoÊG]Ê0’ÊšÂÊ=PÊúHÊÞÊáÊüIÊ KÊ?QÊÌ%ÊœTÊìjÊLÊE\Ê´XÊË[Ê•š^š’„˜™IBCocoaFramework††freewheeling-0.6.6/MacOSX/freewheeling.icns000066400000000000000000001564371370736313100206270ustar00rootroot00000000000000icnsÝics#Hðø?üþþþþþþþþ?üøððø?üþþþþþþþþ?üøðics8¬++3,,+¬÷2÷+W 3]÷¬2ù÷] ö+ 2,,3ö2,WW,22]ø2,ø,,2÷,÷¬W3¬÷2,,÷÷W,33,2,+¬÷Vù2ø÷¬is32{‘dÐå´ãØÛV„ ÉÐòúúýøùæÁ‚ Ò¥õ÷üüÿüûàȀb½üøüù€ýtûüöîÅ ùþùüûüôôüûúàÚøüôéäßÛ³÷ýýüèÊúýüúᛘàñðïð͹úûüøç¶Æàìëóé¿ñõýøøÞÎïìóïæ¶¾àýðþûêëòðïèîÊS²èýøþððèðñõ¶?€ ÅÐùû÷ãìíóüåÁ‚ Æ¡åÔÎõáÆâÌ„H¤ž¶³¼A‘‘aÄΑ¼¾ÍS„ ­¼Í¿Æ¾ÍϽ‚ Î…¶»ÇÄÉÂÔˆ{€*b¢Ê²½ÂÈÆÑ½ ®ÊŠÁvŸÂ¶»ËÃÊ¿ÇÊÔÍÞÛ¶¨±³¹‹ÌÒ€ÙO®ÎÑÔÖ€¾ÊÂÁ¼ªšÀÃÁ¼±t§°ÀÊÏÓÍ®²³À¹»¸¸ÐÈÊÆ³¢º´Ä±¿¿·ÇÎÐÈ¿¾¾S–¤½¿ÊÀÎÃÔÌ™?€ ªÃǽ¸ÏÁÓ̼¼‚ ‹¸™ È³£ÁÆ„H¾šŠž¤¸@‘‘a¼¹s§ÂS„ ¿Œ¨Œ™§»¹‚ Êk}‹œ‘š“´U_¼€}`Œz—›—«…Ss¯†¾RW}ƒ¦“¥U‹¡§ÌÃÆ³o„‘™j£­½¾Ë˜¬°¯²¥nk¥¨¡Ÿ“Œ€Ž‘…€_œ¦ª·¹¶ ~€‹ƒ‡˜¨º¬ª¥†Ž´‘z“±µ¶ª”¶Q~qŠš—°¥½°š>€ À‡‘—Ž–ºž½¦˜·‚ Àvj|¡‹‹¥Á„Gº’{Š˜µ?‘s8mk 5555†ÿÿÿÿÿÿŸöÿÿÿÿÿÿÿÿúöÿÿÿÿÿÿÿÿÿÿù‡ÿÿÿÿÿÿÿÿÿÿÿÿü ÿÿÿÿÿÿÿÿÿÿÿÿÿÿ')ÿÿÿÿÿÿÿÿÿÿÿÿÿÿ5ÿÿÿÿÿÿÿÿÿÿÿÿÿÿ5ÿÿÿÿÿÿÿÿÿÿÿÿÿÿ1ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿCŸÿÿÿÿÿÿÿÿÿÿÿÿÉúÿÿÿÿÿÿÿÿÿÿü4úÿÿÿÿÿÿÿÿý3¶ÿÿÿÿÿÿÉ2g{ICN#øþÿÿ€ÿÿÀÿÿàÿÿðÿÿøÿÿü?ÿÿü?ÿÿü?ÿÿþÿÿþÿÿþÿÿþÿÿþÿÿþÿÿþÿÿþÿÿþ?ÿÿþ?ÿÿü?ÿÿüÿÿøÿÿøÿÿðÿÿÀÿÿÀÿÿ€þðøþÿÿ€ÿÿÀÿÿàÿÿðÿÿøÿÿü?ÿÿü?ÿÿü?ÿÿþÿÿþÿÿþÿÿþÿÿþÿÿþÿÿþÿÿþÿÿþ?ÿÿþ?ÿÿü?ÿÿüÿÿøÿÿøÿÿðÿÿÀÿÿÀÿÿ€þðicl8ûø++++ö+øûüø+ö+WW,,,++÷ûþV+÷,,32,öøþþ÷+2,ö÷þ++22÷+þ+÷W2 W]÷+þþ÷öW33  33]]+÷þø÷2  33öVþü÷W3  öùøø]]÷+÷,2  23öûV++  322,23öø+÷,333W3W,W2,÷++2,2W]]]22+÷V2,2]]ùV22,222222232+÷]3W]ùøø2÷+ö+V2 3]Wøø22,,,ö÷V2 22ø÷+3W2÷V÷33 2+,3^÷ø÷W32,2÷ü÷ø2 ,32+øû÷2332+üø÷]33÷Vþ+÷W22,÷÷þþ+÷3,2++þ+÷W33323,ö+þ+÷2233]]3]V,+÷þþø+ø]‚]2322]úø+øþû÷÷÷VùVùøV÷÷÷üø++++++øil32 ¨ u°ÍÍÉÕÞÒ§c‘ ‚·ÕáߥœÖÚÕÏÎÃ|-¨ÏÐÜåîæÍñòîââç⯊BÈÏÍáñùûúïûüû÷õðêåÃ'ˆÉÒÖçõøüúýôýÿü÷ûøìºÌɆ?Îě߸÷÷ýúÿöþÿüûûù鮘ÇÌ(„0Æá¬·Úùúùûüþõýÿ€üùàʯ ÚŃ«ÉÇî÷öøûûùúÿóýþùýü÷óöåËæä£0€Å™¼ôüü÷õûüüÿöûþûþùö÷ùûüõìàŽ·³‹°ðüýü÷øýýþõüþýøî÷ùûýüúðæÁ6ÓÌÑ×óøøúýúõùùë÷øðÙäûÿûúûýøêàiªÙÝôûýýøôïõðÚëÜÜâǵçúüüý€üïç°ÉÍßñö÷ûýüôØÆ¼°½¬Õ¦ÕóøýþýÿýôåÌÉÇÅã÷ûýüûýþùę̈•—ÄñûüýúúüüúðÉÒÁ«äùùýüûúöîÞ–‰ «ËÈÕÖÔÕÕÖØÒ»¹×Á”×ùüýþýþýú籑µ¶ÄÈÜêñòðîï÷b÷æèƲßúúùûùúøôòÆ“—²¹¿ÌâäéëêìïôðàâħÔóüúúùøúúïì×½½Èåëèïñïëëí˱ÀūŵáôóöüýùöûûìÊÜÎðïïëîóóññܚƦ€Å—·ïúüû÷öüüýîÙçäæóïîìëðòõëÁÇV€º³Âïùøôùý€üïßëðëóðñðïíæÑÐØ³xÈ»Îæñúüüøýûðæîóííñðññó긶Ô^‚±È¸ñúúøúýüïîëðîçðîñõôì¹Æ¤ƒ ÊÅ­âõööüøõäæè€ìððõõîÞÏÁ„'Ïɼåïöý÷òæîëïïîçõ÷óÖÚɆ ÐÉ™Àòùò×Òôðøôã½ëìÞå͉(ËÇ¿Éλž«íèøîÇ–²ÐÜÇŠ±Ì·Œvx‘ÑÁÙ̈±Íª r½ÇÙ“­–²¤ÃÆ·^’¹ÒÎËËÐÔ¯©¨ p¬ÉÉÅÌ×Ï£^‘ ³Í×Ê‹€¶½ÀÃÆ¾y-¦Ç»½¾Å·”¼ÁÁ±ºÑÙªŠ?Ãį´ÀÉÏÅ«¿ÇÂºÂÆÍÛÀ%ˆÆÈ±³»ÁÌÎÉ­¿ÌÀÀÌÑÍŸÂņ<˺€®½¼ÁÇÎʳÁ˾ÂÑÕÁ†~¹Ç(„0ÃØ”›·»ÀÅÎÊ´ÀË¿ÆÓ̦Œ|ÍÁƒ¦Á¨Åij«¶½ÃÌ˹ÁÉÀÎÏ·ŸŸš–ÅÖœ-~†·Ãƶ®¹¿ÅÍÁÂÆÆÒ¤ž£´ÅÄËÖ‡¶¬oz£®À÷²¼ÀÎÆÃÃËÌ© ¨·ÃÉÈÅӺѿ·©ªŸ¥¶½¸³¾Ç¾ÃÄÇ©±¾ÉÌÍÏÐÏÙbªÔÆÛÜÙÍ·¬¨¹¸©¾°±¿©‰¶ÉÌÑ×Ö×ÚÓß­ÈÀÃØâáßÜÓÅ£–—Š˜‡»ƒ±ÌÑÖÝÜÛÙÐɾÅŰÀÑØÛÚÚÛÜØË®Œzr|¥ËÕÔÑËÈÆÄÃÀ¬Ë¿c•²¾ÀÀ¿ÅÈÈǼ¥~s•²®³°®°±¯¯¨‘ŸÐ¾~¦½¿¿ÁÁÅijˆs€¦¥±¶ÉÑ×ÙÛÝÚÞÛÓâÄž¯ÁÂÂÁ¿½¹¶·™p‚¥ª«²Â¿ÃÃÉÐÏÎÌÆÛ›©·¸¶4½¾±µ¯¡­¸ÐÍÅÊÉÃÀ¿½š†­Ã¨¿‘«´±µ¿Ã½¶½¿Á©Ã¶ÓÐÍÆÇÉÉÇÀ¥o¼£€Ä‹¸ÁÁÀ¸¶¾Àú±ÈÅÂÒÏËÆÄÉÈöžÁS€¸©£À¾¸µº¿¿Á¹·ÈÌÂÐÒÎÌÈ·¢¨Å¯uĦ£ª¬¸¿ÁÀÈÁ¼¿ÊÎÄËÓÑÍÊÅµŠžÍ[‚¯Àrƒ³¿À¾ÆÇ¾¹ÈÍÎÅÂÔÑÍÉ·”½ ƒ È¾Ž²¿¾¿ÊÁ¹²ÃÍÐÈÀËÑÎÅ¿¸Ã¿„'Í¿›º¼ÂƼ¹¸ÈÍÐȾ½Î˲ËĆ ÍÁ€šÃ¿²¡¤ÉÂÌŲ’ÄÁ¹ØÊ‰(É­ª¢…q~¾·ÉÀŸu–¸Ðʯɮy_au­™²©tx¨Ç¦ r¼Ç¿”ˆœ„£™¾Ã´]’¹ÒËÉÉÍÓ®©¨ lªÇÅÂÈÑË£]‘ }±È˹viž£®¹¿ºu-¤Â° –¢h‘˜™‰œ¿Ð¦Š?À¼——Ÿ©–uŽš”‹•¢¶Ñ¼%ˆÄÀ”„†“©¬šu ’“¥°±‰»Á†<Dzj‡‰ˆ“›«šy‘ŸŒ«´Ÿin°Ã$„-ÁÑ~idyƒ‘™ªœ}Œœ²¥sVTc½ƒ¤ºŽ ˜yjwŠš¥Ÿ‡›“­«€YRZm§Ëš+~½vk…—t˜¢–’•›ªŒ_W`{šŸ´Í„µ¦YOfoŽ•‚uƒ¦ž”’¡¢lXh…–¡£¥Ã¶ ϶¢‚oWa|ƒ{{Œ €™£‚fr†š£ª¬®µÓ^ªÐ³Ãöœ}ol†˜žŒdŒœ¢¬¹¼¼¾»Ø©Æ³§½ËÈ»ª—uksh{l¡i“­±·ÀÂÀ½´°²ÃÅ ž¯¼¾¾¼¹¸¶¬’ue^fŒ®²¯¬©¥œ˜™š’þ‡‘––“‘—Ÿ£œŒhc€„Ÿ™›”’•–Œ…p‰Ê¾nŽŽ’“’†h^pœ™¡§·¼ÁÃÉËÈÈÆÅà‹…Š’‘‹„|pTp›žšš§ ¡¢«µ²°¯²×Â’ƒ€„‚ˆ‡{…Šˆ¨½µª­ª¡™‘odŸÀ¨»r|~}ŠŽˆˆ³¥ ¾º²ª¨©¨¤”xH²¢€ÃmeˆŽŠƒ‹Ž““–´°©¹¶¯©¤¨¤˜Š€¼R€¸Ÿ†–„}„““—°±¥¶¹´°© Žy„¶«uÁ‘|zw‚‹‘™Ž¯°¢°¼·²­ ˆc‡ÇY‚­¹WXƒ––ˆŒ§µ²¤¡»½³¨›ŠuµŸƒ Æ·uˆ‹Œ›‘‰‹¨¸ºªœ¯»°ž•™·½„%̳|Š“–”®´¶ª–³©˜¾Á†̹gwš~u|¥ ©ˆp¨¡–ÊÆ‰&ǼŽ}ZP\™¡š{\‚§ÇÀŠ®Æ§jLO_‘x’Œ\l¡Ä¥ oºÅ½Ž~v–ºÁ´\’¸ÐÊÉÈËÒ¬©l8mk ÁÿÿÿÿÿÿÿÿÍ& –÷þÿÿÿÿÿÿÿÿþø¬# TöüÿÿÿÿÿÿÿÿÿÿÿÿýøtPüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþ{IÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿtPÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿxTüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿý|öÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿü•üÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿú;öÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿûK÷ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÕàþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ1 ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ6 ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ6 ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ6 ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ6 ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ6 ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ6 çÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ5)ùÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþá'÷ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿû[ «ýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþË/"øÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿûV týÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿý¥(zÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ§8tÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ£4xýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþ¦4|ùýÿÿÿÿÿÿÿÿÿÿÿÿþû¥7=µúûþÿÿÿÿÿÿþüûÊU'>MëÿÿÿÿÿÿñaE- 255555) it32…•ÿÿÿÿÿŸ'3qƒ„ˆ°¹¾ÂÏÕÖÓÒÑÑÏÍÎÏ×ÙÚÞâãâàÞÛÓ¾µ±§}xt^!Ö%]z|§°´¸ÅËÌÉÉÈÈÆÅÅÆÎÏÐÔØÙØÕÔÑÉ´«¨žtpjJ×%Qu{~¦®²¶ÂÈÉÆÄÄÃÂÁÀÃÊÌÍÑÔÕÔÓÑÎDzª¦œtogAÏ5VŒŠ‡…Š™©­¯ÃÈÊËÑÓÐͳ³±­®´ÉÏÑÕר×ÖÔÒÏÀ¾¼·¢Ÿœ„„‰…ˆ‹‡9Ç&XŸ¥§«½ÃÄËÓÖÖÜßÞÞÝÞØÂ«¤¤¡œž©ÊÔÖØÚÚÙØ×ÕÓ΀̀ÉÇÅÉö´±£KÇ D›¨­²ÈÐÑÙàââå€äßàÙÁ§  ˜›¦ÉÔ×ÚÛÛÜÚØØÖÓÑÑÒ€ÔÖØÙÑÀ½µ£4Á$1+U™¨®³ÅÎÏÖßááãäåäááÚÆ°¨©¥ «ÎÙÛÝ€ßÝÛÛÙÔ€Ò€ÔÕרÑÃÀ¸¤F%ºC9z{xˆ–’˜±¸¼¿ËÑÑ×Þßàãäååçèå×ÈÅĽ³µ¾ÛãåççèççæäâÞÜÛÛÙÙØÛÞÞÙÓÐÍÁ—Šrtn,¹CG‰•˜±ÊÐÌÊÈÉÌÐÔÔØÝÞßäåæèëîìçâáàÔÈÉÐèïñðñòðïðïìåâááßÞßâåæåäãâá××зœ–†4¹F¡»×ßÚЀÎÕÖØÛÞàáæèéêîïðìééçÝÐÑ×íòóôóñðîèæåä€áæéêé‚êëâŨ¢Œ5µ n`Vb”¦©¼ÏÖӀРÒ×ÚÛßääåêëìì€ñ ïììêáÕ×Ýîôõö õóòñêéèççåæé€ëééèáɱ¬•S=>F²p³¸¶³ÃÊÇÆÅÄÉÑÕ×Ùàãåêïñðõöõõ€ø öõööïèéìöùùú€ûúùúøõ€óò€ñóóðíìêêèéæÝÖÖʬ¨¦H±a·ÃÆÅÏÕÒÉÁ¿ÆÓØÙÛäçèîóõõøùøø€ú ùùúøôîïñùûûü€ýüûüû÷öõõ€ôñíëêêéêèæääÚľ¸§B±Y¶ÄÊËÓØÖÌÁ¿ÇÕÛÝÞæééïõõöø€ù úûûúúûúöððòúüû‚üûûúø€÷öõõóíìëêëêêçäåÜÊÆ¼§@®HX8l´ÅËÌÒÖÔÍÈÅÍÙÞàâéììñöö÷ø€ùú€ûöññôúý…üúù‚÷öôïîííêêçàÚ×ÓÉÆ¿ªU5%ª>¡ÁÃÃÏÓÔÓÒÑÓÕØÙÞéíîïöøø€÷øûüûû€ú ûýþýùôôöüþýþ€ÿ"ýüüúù÷÷øùúùúûûùöôóðéæßȰ§³ÈÐÑÍÁ¼¶‡ª—ÁÊÌÓ××ÕÔÒÓØÚÛáëîðòøúùù€øüüûû€ú ûýþýùôôöüýýþ€ÿ ýüüúù÷÷øúûú€üûõôóñéæßƬ¡¯ÊÓÕÒÊʽ€¨@5޽ÈÈÍÏÐÐÓÓÔÙÞÞãëîðñöƒøüüûû€ú ûýþýùôôöüýýþ€ÿýüüûù€øûúú€ûúöõôòèæßÇ­£®ÆÍÏËÇǹ~¤0I£˜¨ÃËö²´»ËÔ×ßçêíñóôô÷÷øø÷øøûüüûûúúûýþýùõõøüýýþ€ÿýüüûù€øüûûúùù€øöòãÞØ¿¥œ£°³µ¹ÄÌÁŸ‚‰"£\ÄÅÁÃÉÎÀ¢—˜¤Ç×Ùåòõõƒ÷øø÷øøüýýüûúúüþÿþûööùýÿþþ€ÿýüüûú€ùýýüú€øúúùóáØÒ¹ž•—œœž§ÂÑÍû¾¹=£:ÅÍÊÌÍÐÀ‘ŸÆØÚçõùø÷öö€÷øøüýýüûúúüþÿþûööùýÿþþ€ÿýüüûû€úýüüú€øûûúõáØÒ¹”•—–˜¢ÅÔÑÍÊÍÀ#Ÿ!l\UlÊÒÏÉÄÅ»¡˜š¤ÆÕ×åõøù÷øø÷ø÷øø÷øø€ýüûúúüþÿþûööùýÿþþ€ÿ ýüüûüûúûýüüú€øùúùñÝÒλ¨¡ ›šœ¢»ÆÄÇËÏÄX<>F›5l³·³·ÞãÛŰ«ª¤¢¤­ÁËÏàò÷÷ùúúùø÷øùùúúûüüûûúúüþÿþúõõøûýýþ€ÿ)ýüüûýûûüþþýûúûúøøöíÓÅÆÁ»º´§¡ ¡¤¤¨½ÒÙÓ®¨© H›`·ÂÄÇåéàŪ£§¥§©®ÁÉÌßò÷÷ú€û€øù€úûüüûûúúüþÿþúõõøüýýþ€ÿý„ü!þþýûúûùøøöíÎÀÂÁÁº©£ Ÿž›¢»ÓÜ×Ä¿º©B›WµÄÉÎäéáÆ«¥¨ª¬®´ÃÊÎàò÷÷ûüûû€øù€úûüüûüûúüþÿþúõõøüýýþ€ÿýƒü"ûþþýûúûúøøöíÐÂÄÅÇÇ¿­¦¤£Ÿ›¢»ÕÝÙÉÇÀ©?˜ AJGc²ÃÉÍÞâÜÉ·²´·¸º¾ËÑÕäó÷øûýüûúùùúƒûúü€þúõõ÷üýýþ€ÿ,ýûûüûüüûþþýüûüû÷÷õîØÌÎÏÎÐÇ·°®«¥Ÿ¥½×ÝÚÍÌÄ­Q-(”1x‹•ÂÎÑÐÍÍÐÓ×ÙÛßàáãèêêïôôöúüüûü€û‡ú üþÿþùóôöûýýþüúúûý%þýýüüýúòððïæãåèêìäÓÌÉĵ¬²ÇÝãàÜÝÖÇŒxY“*—¦ÈÒÔÑÆÄÊØçìîóôõ„ôöûþýý€üû€úù€ú üþÿþùóóöûýýþüøøù…ýþÿûñîï€ðñôøøðßÙÖм±¶ÊßäããäßÑ£—Š_”y™¢©ÄÎÑÎÇÆËØçëìòóôõòóô€õ÷ûý€üýüû€úùûûúüþÿþùóóõûýýþþÿþüùøùü„ýþÿüòïðð€ñ ôøøòáÝÙÓ¹½Ïâæ€äßÒ§›‹_ ‘‰²¼º¿ÁÃÄÄÃÈÚëðñõö÷ù÷øø÷ø‚÷øúü‚ûù€úüþÿþúôõ÷ûýýþþÿþüùøú‚ý þþüüýúôñòóõ€ö÷÷ôëéçãÜÖÙáèêèèçäÛ»®€NHM>•ÊÕÌ»µ¶¸ÀÁÇÛïõõû€ü ûüûúø÷öòññóùüûüú€ù€úü€þû÷÷ùúüüý€þüùøùýþýý€þüúûúõôôöúüûùøööõ€ôóôòññïîìëêçÜÜΣvljQ‘‘ÏÝÒ»´´¸ÁÃÈÝñ÷øûƒý ú÷øöòïïòúüüý€üú€ù€ú%üþþýûö÷ùúüüýþÿþüùøùýþýþþÿÿýûüûõôô÷úüüú€÷øüüúöòñïîíëéå娫|rnNSV>L“ÇÓȯ¨¨­½¿ÅÙïõöû€ý€ü úøù÷óññôøúùû€üû€úüûûý€þûö÷øúûûý€þüúúûýþþýûüýûùúù÷öö÷ùúúù€øùùøøüüû÷ôóòîîíéæäÙ²Š€{Rˆš•§¼¿´“Š‹“°³ºÒëòôúýüü€þýüüû÷ööõóñòøþÿþ€ýüüûûýÿÿþúõöøúüüý€þýûûüýøùøõòòôöƒøúüýýûýüúù÷öõîëêèääÝ饙d‡¤¦¤­·¸®‹‚ƒŒ¬±¸Ñêñôúýýüþ ýýûù÷ø÷ðîð÷þÿ‚þ€ü ýÿÿþúõö÷úûûý€þý€ü€þü÷÷øôïðò÷ùùø÷õ÷ù€ü€þýüýüúøøöïìëèæåÞʳ¯£i„¤ª©¯¶¶¬Š‚Œ«°¶Ðêñóûþýýþ ýýûù÷÷öðîð÷þÿ‚þ€ü ýÿÿþúõö÷úûûý€þý€ü€þý€öóððó÷ùùø÷õöùûüüý€üúøøöïíìêçæàÌ·´§h)„©°®²¶µ¬Ž††Ž«¯·Ïéñóûþýýþÿþþýýûùøù÷óðò÷üýüÿ€þ€ü ýÿÿþúõöøúüüý€þýüüûüûûúòòóòòñô÷ùù÷øö÷øúúûûƒüúùù÷ðîíëèæáн¼¬l“½È»´°«••¦©°Ëæíðø€ûýýü„ýûù÷‚øü†ýüùõõöúûûüý ÿÿüø÷öóãâåìóõöƒûúüýýüýý‚ü€û úõôóñíëæÝÔÕÃx—ÆÒ˾²®ª—’’—¢¥¬Èäìïø€ûýýüý€þÿúùøø÷ö÷ü„ýþþýùõöøú€üýÿÿü÷ôóðÞÛßéóõöú€ûƒüûüû‚ü ûøöõóíëéâÝßË|–ÆÒËÀ¶±® œœ ©¬³Íæíïøúûüûýüý€ÿþú€ùø÷÷üýüüƒýüùóóöùûûüýþýúóñïíÞÝàëôö÷ú‡ûüû‚üûù÷öôíëèâÞßÊŠ™Ë×ÒËÅÄÃÀ¿¿ÁÅÇÌÜìñò÷€ùƒúûü€ý€üúùùøø÷÷øú€û úûùôíîðöøù€ú€ù ÷óåáàáÜÛÞêõ÷ùû€ýþþýü€ú€ûüûƒüùø÷ôîëéåãåÕ–EJ]Š™ÏÜØÕÓÔØáãåæããåìòôõö÷÷øö÷ööøöøú€üþÿÿü€úóññóöø÷÷ø÷õïççêóö‚÷ôñðêØÒÑÔÙÚÞéõùù„ÿû€ø€úûû€ü€ýúùøõïì€éëÝ®tt~Š’ÎÝÙØ××Ýéïðïéêëîóôóôôõõöõõ÷ú€ü€ÿý€ûòððó÷ù€ø÷õîåæéóö€÷ö÷ôòïé×ÐÎÐØÚÝéöùúƒÿþû€ø€úûû€ü€ýûúùöîëêêéìß³||„‡)‘ÌÜØØ××Üéîîíééêîòóó€ô#öõöõö÷õ÷ûüüýýþþüúúùñïïðôõôõööôíååèòóôóïíëåÓÌËÏÚÛÞêõøùþÿ‚þûø÷÷€úûû€ü€ýûúùöîëêêéëß´~~ˆ‡«ž—¹ÕÝ€Û Ýáïóõõøùúúûƒü úúùøõôôõôóòðíïô÷ù÷ñïíêàÜÝäëíëåÞÝÝ€ÞáäåãÙÐÍɸ³³»Üàãìöúùüüûüýþþýûûüü€ýƒüýüüûùñïîëéëãɦ§°‡´©¦ÂÖÝÛÜÝßãðôö÷úûûüýþþýýþýûúúö€ó/ññðïìéêñ÷ø÷ððîéÚÔÖàéìêãÜÜÛÛÚÚÝáâßÔÊÆÁ²­¯¸Ûáãì÷ùù€úûü€ý€üýþýý„üýüûùòðïìéëã̯°¹‡¶¬ªÂÖÛÚÜßàäñõ÷÷û€ü€ý:üýýüûùùõóòòññðïëéêïõöõîìëæ×ÑÓÝæèçáÚÚÙ×ÖÕÛßàÞÐÅÁ¾²®¯¸Ýâäíöùø€úûü€ý€üý„üýüûùòðîìééãγ´¾‡»±¯ÃÓØØÜÞàäðôööùƒúûúúùø€õ€ò-ðíêêìíîíåâáÞÒÏÏÕÚÜÛÙÔÓÓÎÍÌÕÝßÛ̾»º¶´µ¾àåæîö÷øù€úü€ý€üý„üûûúøðîíèããÝÌ··Á‡ÊÁ½ÅÍÎÐÖÝàãïñóó÷ö€÷ øøúûûüüýýüüýý€ù6÷òïìá×ÔÓÌÊÈÇ¿¾½¹µµ¶»¿¿¼´°°ÃÕÙÓ¾©¤®ÅÍÐÕîññóö÷÷ûüûüþÿÿþýý‚üþþÿ€ýüøõõòêçäÛÑÐÍÇÀÂ̇ÑÇÃÇËËÍÖÝáãîñòóööõõöö÷øùúûýþþÿ+üûúøòïìÝÎÊÊ¿¿¾ºº·±¬©¬³»»·«§§¾ÓÙѺ¡¨ÇÑÖÚñôó€õöúûûüþÿÿþ„ý€ÿ€þý÷õôñéæâ×ÍÊÉÆÂÆÐ‡ÑÈÄÇÉÊÍÕÝáãðóóô÷÷ö€÷ùøùùúýþþ€ÿ8þûúúøòðíßÑÍÌÅÃÁÀº¹µ¯¨¥¨­´µ°§¢¢¸ÌÒÊ·¢žªÌ×Üàòõôõöö÷úûûüþÿÿþ„ý€ÿ€þýøööóëèåØËÈÈÇÆÉÓ‡ÏÅÁÅÈÈËÕßãæñõõö€øù€ûüû†ü&úøöõìãáàÖÕÒÎÄÁ½³©¦§¦¦¥£›™™§³¶µ±­¯·Øàäçöøùúû€ü€ýü€ú€ûüüƒýùø÷õïíéÛÍÉÈÉÈËÕ‡ÍÃÀÃÅÆÊÖáæèô÷÷øùúú€ûüûüüûü‚û,üýÿÿþýüüùõõóéæäßÌÈ÷ª§§Ÿ˜–”‘ŽŽ”˜™ª·¾Æâëîïøúú€ûýûƒüúøùøúùùûû€ý€ü úùù÷óñíÞÏÉ€ÊÍׇ ÌÂÀÂÅÆÉÖâæêô€øüüûüƒýûý‚ûüþ€ÿ(þþÿýúûùïìêãÏÉ÷©¦¥“‘‘Œ‹‹Ž‘‘•¨ºÁÉæïòóúüûü…ýüýûùùúûü€ýüüý€ûùöõðàÏ€ÊËÎØ‡ÌÃÀÁÂÃÇÕâçêôøùøüƒýüý‚üýþ€ÿ,ýýüúø÷öëéçáÌǶ§¤£›’‘‘Ž’••šªºÁÉâêíîö÷øøùúùú€ù€ø÷€õ€ö÷ø‚ùø÷ööõðïêÛÍÈÈÉËÎØ‡ ÉÀ½º¸¸½Ïáæéõ€ù€úüƒýüü‡û+øø÷õóòñåãáÛÉľ°¡œ–Ž”••šžž¢²ÁÆÉ×ÛÜÞççèèéêêéèèççèçèç€è€é€êéèçæäÙ×ÔÌÃÁÂÇÎÑÚ‡ż¸²®«²Éàçêôøùø€ùû€ý€ü7ûûúúûûüúø÷÷öôóòïíìëÞÜÚÔÅÀº©™”•‰‰›Ÿ ¤§©¬»ÉÍËÈÇÈÉÒÓÔÕ×ØØ€ÕÔÔÓÓÔÕÕÖÕƒÖרØ×ÔÓÑÍÀ¼º¹¸¸¹ÃÎÒÛ‡޹±«©°Èàçêôøùù€úü€þ€ýüüûû€ü1ûùøø÷õôóðîíìßÝÛÕÿ¹¨˜““‰‰œ ¡¦©©­»ÊÍÊÈÆÇÈÐÒÓÕÖØÖÖ€ÕÔ†Õ Ö×ר×ÔÓÑÍÀ¼€º¹»ÃÎÒ܇ ޹¯¨¥­ÅÝåéô€ù€ûü€þýƒü7ûúùùøöõôòðïîáßÝ×Á»µ¦—’’ŽŠŠž£¤¨ª«®»ÇËÉÈÇÇÊÓÔÕÖØÙÚÙÚÚÙÚÙÙˆÚÛ€ÜÚÚÙÕÊÆÄÄÂÁÂÉÑÕ߇޹¨œ— ºÕÞâóøùù€ûü€ýþ€üý€þ€üûûúù÷ööôæãÞÖ¸°ªž“ ’—©¯²²´³µ¼ÅÆ ÇÊÖ×ÙÝàâäéëëêí€ì€êééèéêëììî€ï ëëèåàÞÝÜÜßê‡޹¦—’›·ÒÜáòøùú€üýþ€ýþ€ý.üüûúùøøöçåáÖ¶¬¦œ’‘˜­´¶µ¶µ·¼ÃÄÄÆÆÇÊ×ÙÚÞâãæíð€ñòññòññ€ïîîíí€ïðôõöõööôîçæäãàâí‡ޏ¥—’œ·ÒÜáòøùú€üýþ€ý„þýýûüûùùöêçãØ¶¬¥›’Ž€’˜®µ¶·¶¶¸½ÂÄÄÅÆÇÊØÚÚÞâãæîñ€ò€óòòðññïïíîïïðññ÷€ø ùù÷ñêèçãàãî‡È¿¼¯¥¢©Á×ßãôùúúƒûüûüüûüûû€üûü€û,úúù÷õôóîíêÞÀµ¯¡“Ž‘’”š­³µµ¶¶¸»¾ÀÁÆÇÇÌÛÞÞßààäé€ì„îƒìíîïððõ€ö õõóíçåäàÜàê‡ Ë¾·±¯¶ÇÚáæõ„ú€ùû€øù€ûù,øø÷õóòòðñîäÈ¿¶¥“’”–𬱲´··¸º¼¾¾ÅÅÈÌßãâáßßáç€è€ê€ëêêééêëìíîïðïõööõôóñëãáàÞÚÝè‡ Ë¿¸´³¹ËÜâçõ„ú€ù€ûü€øù€ûù/øø÷óòðñòóïçÈÀ·¥’ŒŽ“•𬱲´··¸¸º¼¾ÄÆÈÌáäâáßÞáæçéè€éêë‚êëëííîïððö÷÷öõõóìäâáÞÛÞé‡Ë¿·±°¶ÈÛáæôùúùúûúú€ù€ûü€øú€ûù/øø÷õóòòñòïæÍĽ¬™”•—™šž®²³¶¸¹¹¼¿¿ÂÈÊÌÏáäãâààâèêêé„ë€êëì€íððòñòòñïîëæàÞÝÚØÛæ‡˾´«©¯ÄØßãòöøù€üû€úûˆù'úúù÷öõôñðîéÙÔϳ¯®¬¨§ª³¶¶º¾¿ÀÇÍÐÒÖØÚÜãää€åçì€îíììëë€ê€ëíîïîâßßÝÖÔÓÒÐÐÎÏÏÒ܇˾²§¤«ÁÕÞâïôöøüýý€üûü€ûù€÷€ùúüýýûùù÷ïííêçäâ×ÍÊÈÀ·¶¶€¸¾ÅÅÈÒÜààåæççååæçêêìò€óðïïîííìé€èêééêííêÕÎËÉ¿¼¼¾ÁÂÁÂÄÈÒ‡ÊÁ½°¦£«¿ÒÛßîóôöüýý€üûü€ûùùøø÷ö÷øùùúûýýûúúøïíììëëèßÖÔÑȽ‚»ÁÇÇÊÕàäåêììëåäæèëìíóóôôðð€ïîíêêééëìíêÒÊÉÅ·³³¸¾¿¾¿ÀÃ͇ƽ¹±«©®¾ÎÔÚëñóô€ûú€ù„úù€ø‚ú:ûûùøø÷ñïîîííëâÙØÔË¿¾¾¿¿ÀÄÇÇÊ×ãæçêììêçæèéêëíðñòñððïïðïîìëëìë€ìíîëÕÏÌǶ¯°·¿Á¿½¼¿È‡»²°·»¾€¿ÁÉâéìîö÷÷„ö÷ú€û'üüýüüýûúùøø÷ö÷÷ùø÷ø÷õîçåâÕÅÄÇÑÓÓÎÊÈÌÚêíí€îï„ìîîïïòóôôðð€ïîïîïðîÜØÔÊ©ž¯¿ÄÀ¸®¯¹‡¸°­·Àľº¼ÅÞçêìôõõô€óôõô÷ú€üþþý€þ üù÷÷öôôõùûúøòìêæÙÈÇËÕÙÙÑËÈÌÝíððïîîïíëëìëìíìóôóôôõóòñ€ðïðïÞÛ×ʦ–˜¬ÀÆÁµ©«´‡µ¬§µÂÆÃ¾¸¹ÃÛäèêóõôôòòóôõôöú€ü€ý€þüù÷÷öõôõú€ûúúøòìëçÚÉÈÌØÛÛÔÍÊÎÞíòñïðïðí‚ë ìíñóòóõôóó€ò‚ðñîàÝÙ˦–—¬ÀÇ´£¦¯‡ª’«ÂÈĺ±²»ÒÙÞàñóòôõôô÷÷öùú€üýýüüûûúø÷ö÷úüüûüûùóíìèÛËÊÎÙÝÞÖÏÎÑßëð‚ïðïïíëìííð€òôƒó€ñòñòñâàÛϬ°ÃÉòœ¥‡|ºÎÄ®–’™®³·¿åìíñ÷ùù€üýþÿÿýýþúôññòõö÷ùý€þ€ýüüúôïíëàÔÔ×âääâàßßâãåçïòññðïðð€í!ìêééêíìïôõööôôõõ÷øøîíêá¶¶ÀÌÐÄžooxŠz¾ÐÆ«‘•¦«¯¹åëëòøúûû€ü€ÿþýþûóððñõö÷úþÿÿƒý ûôïíëáÕÕØâåæã€áâääæð€òððïððïï€í!ìêèèëììîôõööõõö÷÷ù÷ðïëâÆº¹ÃÍÑÅlltŠ„¾ÎĬ”˜ª¯³½æììò÷ùúû€üþ ýýúõññòö÷øûýþþýüüúôïíëâ××Úãæçä€âãääæð€òððïððïï€î íêèéëììíóó‚ôõ÷ø÷îîëâÆ»»ÂËИcdmŠ‹¿ÎŲž›£µ»¿Çëðñôøúûûüüûúùøø÷öö€õöùúúü€þü ýýüõïíëäÛÛÝå€çƒæèñ€óððïððïïî„ìîî€ïððò€ôíëèâÐÇÇÈÈ̼ƒ49HŠÁÎÆ·§¥¬ÀÅÉÐïôôøüý€üýûöôõòððó÷úùúýþþý"üûûüýþüõîíìæààáèêéêëëêéèçêñóôóððïðð†ïîììëéèèéìíîïðòñêéèãÚÕÒÍÇȵlŠ’ÂÎǶ§¦®ÁÈÌÒñõõøü‚ýûöôôòïïñøúúûýþþý$üûûüýþüõîíìçââäéëêëììëêççêñôôóððïððïðïðïïîììêèææéêíîðñòòìëéäÜØÕÍÇȶi%Ž»ÇÀ¶­¬±ÀÄÈÐíòòõùûúúûûúõôôóòñôùûûüýþþý…ü ýûôîíìçááãêìëí€î ìèéêòóòòðïðïï…ðïîîíìë€êèéèåâááÞÞÝÚÚØÕÊÁ²i…¯¸·¶¸º»¾¾ÀÈèìíñöø÷öõõö€õöø÷ùýÿÿþ€ýû€ùûüýûüûùõñïíæÞÞàéêìïòóòï€íóòóó„ðòóññðïð€ïðíäáÞÐÄ¿ÀÁÂÂÆÖÛÕÄ´±¤c…¬¶´¸¾¿¾½½¿Çæììðö÷öôóôôõõö÷øùúÿ€ýû€øýýþüûúøôñïíæÞÞáéìíïóôóð€ïòñòò„ðòòññð‚ïñ€ðíãÞÚɹ´µ¹º»ÀÔÛ×IJ¯¢f…«¯¯µ¾À¿½½¿Æäèéîóõôôóóôôõö÷øùúþ€ÿ€ýû€ø€ýüûúøôñïíçßßâèëíðôõôñ€ïññòñ€ð…ñ„ð€òïãßÚɸ°²¶·¸½ÔÜÖ¿ª¦h€œš­ÁÆÂ¼»¼ÃÙÝßæíïïòñòóö÷øùùúûþ€ÿ#üüûùø÷øûýýüûúøôñïîèááäéìíïóôóðîíîððñð…ñ„ð€óñæãß̺³³·¶¶½ÒÛÒ±’Œˆ^5G1AŒÆÖϾº¹º½½ÁË×Ûßêíîðùüûüþýýüúù€ø÷÷ýÿÿýüûùõñïïíìëìîïïðòóòðîíìëêêë€ðñðƒñòóôóóðïéÔ½µµ¶µ¶»ÒÛ˃.)‘ƒÎàÔ¿¸··®®³ÁÏÒÙåëìïúþ‚ýþýýüùø€÷ ööýÿÿþüûùõñï„ðïðñòñðííëéæçéðòñƒð‚ñ òôõõöõöðØ¿€¶³´»ÑÜÇp•ŠÉØÏ¿»¹·«ª¯½ÊÍÕæëíðúþ‚ý€üúùƒ÷üÿÿþüûùõñ€ïðïïîîïïðñðïííëéçèéðòñ€ðï‚ð‚ñ òôõöõóóìÕ¾µµ€¶»ÌÕÂr•·Ã¿€Â¼š—«·ºÆâìïðùüû€üûûúúù÷ö÷øùúúýþþýüûùõð€îïîîììíîïð€ïîìèåæèñóñðïîîïïððñòòó‚ôóòïîèÓ½µ·ÀÁÁ¿·¹¨e•x¡­±ÅÍÌ¿‰ƒŠ—£¥·àíñòöùøù€û€ø÷÷õöùý‚þýüûùôïììíïîíëêêìƒï)îæäåçòôòïíììïïððòóóõööõôóòñéèâϽµ·ÉÍËÁ¦ŸY”!{ ©®ÈÑÏ¿€yœž³Þíñó÷ùøùûüúø€÷õôõúþÿÿ€þýüûùôï€íîíìëêêì€î€ï)íæäåçóôóïìëìîïððòóóõö÷öôóòðéæàκ²µÊÑÏ䚌\” rŽ“—ÁÍÏ••›¡¡³Ûèìíô÷÷øúüû÷ƒöúþÿÿý ûúøòìêêëìëë€éì€î€ïíéæçéñóñðîíîïïðñô‚õôòñðîçãÞÏ¿º¼ÉÍÉ»‰tQ•!/9:T®ÆÌÊ¿¿½´©¥µÔÞâåïôõ÷ùûøõóóõ÷úùû€þùøùøöõóíçääæèçèçèèêƒìëì€ëðïðïï‚ðò÷ùø÷õôòïîìéáÝÛÕÍËÊÆÅ¾£B" ˜!@¯ÆÎÍÏÐ̼«¦µÑÛßâîóóöúûùôòòôøûúûýþþ€ø÷õôòëãááä€å€çêë‚ì‚íðïððñòñ€ðòùüû÷óóòííëçàÚÙÖÓÑÑÅļ .›B¯ÃÈÇÑÔµÎ×Üßëññôùú÷óññóøúúû€þ ùøøöõóñëãááä€å€çêìîíîíïîïðòóò€ñóùüû÷òòðììéæÞÙÙÕÒÒÐÀ½µœ/›4G¥±¯¯ÎÓο±®¸ÉÐÒØçîîó÷ø÷òññòúüûüýþýù÷÷öóòðêåââåèçèçèèê‡íììëìðóôô€òôùûû÷óòðèæäâÝÙ×ÓÐÐˤžœ‹.œLC>YÄÐÌÈÆÆÄ¾¼¾ÅÛååéîïðïïðòúüûü€ýù÷÷öòñïëæäåèíìëëêêì‡ïíäãåìóõô€õö÷ø÷ôñðéÝØÕ×ÙÛ×ÏÈÉ»I,)- !ÃÒÍÏÑÑÈ·°±»Õáâçìîíðïðóùýýü€ýøöõõññïëçåæéïïíìëìîïðïðíáàâëõ‚ö÷÷øöóñïèÖÏÎÑØÜÙÐÇɸ£9¼Â¾ÅÍÐȺµ¶½ÐÙÛÞâãåíððòù€ü(ýþýøööõïîìèåãäéððîìëìîðññððïïððïìÜÚÝèòõõö€÷õöõòîîæØÑÐÒÖÙÕĵµ¬'£Ž…‚£ÅÐÊÄ€Á½¼½¾¿¾Éãìïñöúùú€ûôóòïäáßÞÝÛÞçðñðîîíñó€ô$óòòîîìåÉÄÊÙéííòòóóðïîêæåâÞÜÚØÒÒÆœqmn¤ ‚¾ÎÍÌÎÍ럟š—¬Ùéîîõ÷€øùùóñïêÚÔ€Ó ÒÖãóóòððïôöù€÷ õôìëèݵ®´ÉßäæîððïêèæâÝÚÜäåäÞÏʸtªQ…ÃÓÑÒÒÏĤ”–“‰£×êïïõ÷øøùúúôòñëÙÓÑÓÓÒÕãõôòñððôøúø÷÷õôíìèÞ°¨°ÇÞäçïòòïèåäßÚØÜäççâÐ˺nª¾ÅÄÎÒÐÅ¦šš—“¦Õåëìðóóô€õîíëåÔÎÌÍÏÎÒáóôóñððõ÷ù€÷öóëéæÜ­§®ÃØÞàêííìæäãßÙØÛáãâÛÁº®p«Q%?&[±ÈÎÊÄÁÁ»²±¸ÈÍÎÏÔØØ×רÕÉÅþ­¨§¬²²¸Ïíïíêéêñ÷ù÷öõòíÜ×ÒÉš”˜£¯°¶ÇÌÎÑÜààÞÜÜÙÐÏÅ«L '®B<°ÈÐÎÌÌËû¹¼ÂÃÅÇÎÑÒÐÐÑÏ¿½¹³¤žž¥¬­³Íìïìêééð÷øøõóòìØÓÎÕ’𣣫½ÃÅÉÙà߀ÝØÍËÁ¤(±KB°ÄÈÇËÎËĽ»¼ÁÁÂÆÉÍÎÌÊËȹµ³®ž™™¡ªª°Êëíëéçèïô÷öôòðêÕÐÊ¿”Œ‘—žŸ§»ÀÂÈÖßÝÛÚÛÔÄ» )±L¦²±®½ÅÃÂÁ>ÂÃÄÅÇÇÁ¼¼º«¨§£—“”›¤¤«ÅåæäâàáéïòðïîìäËÿ¶‘ŠŽ—ž ¨¼ÂÄÈØßÜÕÏÐħ¤¡Ž-²IMD@S•¯±ÁÒ×ÒÇÄÃÀ¶²¯ ’ŽŽ…„„‚€~Œ—˜Ÿ¹×ÙÖÎÌÍÖÞáßÞßÜЫ ˜ƒ€ƒ›œ¥¼ÁÄÊ×àÙ­«ŽD,,0¶C3©­ÂÚâÙËÅ¿¯ª¦“€}|ussuwx{†‘’™³ÒÔÑÇÅÄÑÚÜÜÛÚÖÉ¡”Œ~{Œ˜›¥¼ÃÇÌÜäÛÀ¦¢‚"¹0ˆž²ÇÍÉÄÃÀ½±¬¨–…€w,yx|†‘—°ÍÎÊÁ¾¾ÊÔÖÖÔÒÏâ–’ƒ…œŸ§»ÁÄÅÈÌÄ­•’x¹C hqitz‹®º½»¼»¹®¤¡¡™™—”ˆ„†Œ‘’–©¿¿¼¯¬¬¹ÄÇÅÁ½»·­©¨¦£¡£©±²´·¹µ¨„tvi]`T º>š±¹¼ÆÌÊÇÄÃûº·°™’‘€’–¡±±¬Ÿš™©´¸´¯¨¦«¸½¾¿ÃÃÄÅÆÇÁ´²©2‚ Á)œ´º¾ÌÓÓÑÐÐÎÆÄÁ·›’€‘“ž¬¬¦˜’’¢¯³°¨ŸŸ¦»ÂÄÇÏ‚ÐÉ·³ªŽÇ5=œ«¯®»Á¿¾¼º¸À¿·ž—•––•˜¢­­©ž™˜¦±´²«¤¤ªºÀÂÀ¸¹»»¼½´¨¤ž‹(Ç0'x}xsxzxvrmt°½¿»±®­«ªª«±··´­ªª´»½»¹¶µ¸º½º«nhortvr€jaÓŸ·ÀÀÈÉËÇ€ÄÃÂÁÁ€Ã ÅÆÇÈÉÌÌɾ¼³–ß ¨¾ÄÄÍÏÏÍÊÉÉÈƒÇ ÉËËÌÎÑÑÍÁ¾¶œß ¶ÈÍÎÖØØÖÓÒÒуРÒÔÔÕØÚÛÖÊÇÀ¨ÿÿÿÿÿ¤ÿÿÿÿÿŸ'/l~ƒ«·»¿ÍÑÒÏÎÍÍËÉÊËÐÐÑ×ÛÜÜÚÙØÐº²­¢ysoYÖ%Xuvz¢­±´ÂÇÈÅÅÄÄÂÀÁÁÆÇÇÍÑÒÒÏÏÍÆ°¨¤™okfF×%Mouw¡ª¯²¾ÂÄÁ¿¿¾½º»¼ÁÂÂÈÌÍÍÌËÉ®¦¢˜nib;ÏLЇ„‚‹‰…’¢¥§¼ÀÁÂÄÆÂµ¦££¡£¶¼¾ÁÄ‚ÅÁ·´²¯›˜”ˆ€†€…ˆƒ9Ç X›¢¢¦¹¿¾ÄËÎÍÔÔÓÑËÊ«’Š‹†„ެ¶¸»¾¾€¿‚ÀÁ¿€ÀÁľ±¯¬ŸGÇ%B—¤©®ÂÊËÑØÙØÚÙØÕËɨ‹„„€{}‡©³¶¹»¼½¾¿ÀÀ€Ã ÅÊÊËÎÑÓË»·°Ÿ3Á(1+N•£©®¾ÆÇÌÒÔÓÔÕÕÑËÉÁ«‘Š‹†}€‰¬µ·º¼½¾¾€¿€À ÁÅÆÇÊÍÏȼ¸±ž@º9xyv…•‘•¨®±³½ÁÁÄÇÈÈ€ÊÉÇÇij¢Ÿž•ŠŠ“¯¸¹¼¿¿À¿»º¹º¼¼½ÄËÍÊÇÅù“†‹~oql%¹Dˆ”–¯ÈÎÇ¿»º»»¼»¼¾¾€¿ÀÁÅÇÆ½µ´±¤’’›²º¼½À€Áÿµ²±²³³µ¿ÊÍÍÔÔÕÖÐÓͲ—’ƒ0¹&DŠšŸ¸ÑÚÓÿ½¼½»»¼½¼¼¾¾¿ÀÄÅÆ¿¹¹µ¨•–´º½¿ÁÂÁ¿³°¯¯±±³¿ÊÍÎרÙÜâæÞÀ¡œ…4µk[T_‘¢¤¶ÉÏʽº¹¹€º¼¾½¾¿¿ÀÂÆÈÆÀ¼»¸©˜™¡´»½¿Âÿµ²±²µ´·ÀÈËÍÑÒÒÕÜàÙ«¦P=>F² l²µ´²¾ÅÀ¼·´µ´€µ;¶¶¸¼ÂÄÃÇÈÇÉËÍÌÆÂ¿´§§¬¹½¾ÂÆÇÆÅÃÂÁº¸·¹»»½ÂÉÊÊÈÈÉÌÕÚØÓÏÐĨ¥¤šF±)_µÀÂÁÊÏʾ±­¯±±²²´µ¶½ÃÅÅÉÊÉÊÎÏÎÉÅÅø««¯º¾¿Â€ÇÅÄüº¹º¿¾ÀÄÇÉÈÄÃÃÆÓØÙÚÛÞÔÁ»µ¤@±KW²ÀÅÆÌÐ̾®ª¬±±²²µ¶·½ÄÅÆÉÊÊËÍÏÍÉÆÅø¬«¯»¿ÀÃÆÇÇÅÄÃÁ½»º»¿¿ÀÄÈÊÉÄÃÄÇÓ×ÙÙÛÞÖŹ¢=®QHX8j±ÁÆÅÈÉÆ»®ª­²³´´·¸¸¾ÄÄÅÊËËÌÍÎÍÊÇÆÄ¹¬¬¯¼¿ÀÄÆÈÇÆÄÂÁ½¼¼½ÀÀÁÅÊËÊÇÆÇËÑÖÕÑÎÍÊÃÁº¥R5%ª>Ÿ¾ÁÁÊÎÍÇ»´´±¯®°¶·¸¹½¿¿ÀÂÃÃËÎÍÍ€ÎËÈÉź¬¬¯¼¿ÀÅÈËÊÆÃÁÁ€¿ÁÇÉÉÍÐÑ€ÐÏÍÌËŰ˜Ÿ¾ÉËȼº´†ª•¿ÈÈÎÑÐȺ²±±®­±¶¸¹º¿ÁÀÁ€ÃËÎÍÍ€ÎËÉÊÆº¬­°¼¿ÀÅËÌËÆÃÁÁ€¿ÀÉËËÎÑÒÒÐÐÏÏÌËÅ­“‰šÁÌÎÌÆÇ»~¨@5ºÅÃÆÆÅ·²²±±°²¶€¸ ¾¿ÀÁÂÃÃÊÍÌ̀ΠËÉÊÆ»­®±¼¾¿Å€ËÆÂ‚ÀÁÊËÌÎÐÑÑÐÐÏÎÉÈ«’ˆ˜ºÂÆÅÂĶ{¤I¡—ަ¿Ç¾ª¤¢¥­¯¯²··¸¸¹º»¿ÀÀÁ€Â;ÈÊÊËÎÏÏÌÉÉÆ¼¯°³½¿ÁÆËÌËÅÁ¿¿ÀÀ¿ÂÌÍÎÏÑÒÓÓÕÓÏÁ½¸ ‡~‰ž¤§¬¼Æ»›}†"£VÁÁ¼¿Åɸ‘ƒŠ¡««³½¿½»¹º»¿ÀÀÁ€ÂÆ€ÈÎÏÏÍÊËÈ¿°±µ¿ÂÂÆËÌÉÄ¿¾¾€¿ÂÎÐÐÑÓÔÔØØ×к°«•|sx…†Š•·ÈÅ»¶»µ;£46ÂÊÆÇÈʸŠ{z‚ ¬¬¶¿Â¿»º¹º¾¿ÀÁÁÂÁÆÇÇÉÍÏÏÍÊËȾ±²¶¿ÁÂÆËÌÊÄ€¾¿¿ÀÃÏÐÐÒ€ÔØØÖи­©’xot~‚¸ËÊÇÅɼ Ÿ`iZPgÇÏË»¼¬‹~„›¤¥°¼¿½»ºº»½¾¿ÀÁÂÁÆÇÇÉÍÏÏÍÊÊÈ¿³³·¿ÁÂÆËÌÊÄ¿¾¾¿¿ÀÃÐÑÑÒÓÓÔÓÕÓʱ£ ~x{}~Šª··¾ÅʾW<>F›l²¶²µØÞÓº¡š•ˆ‚ƒ‡”—¦´¹¸ƒ»D¼¿ÁÂÂÅÆÆÇÍÏÏÍÊÊÈ¿²³·½ÀÀÆËÌÊÄ¿¾¾ÃÂÄÆÒÔÓÓÔÔÒÍÍɽ›ŠŒŠ‡‡„~{|ˆŒ‘¬ÈÑ˪¥¦F›R^¶ÀÁÄßãÙ¸–Ž„ƒƒ…ŒŽ‘¢´·¸º½¼»»º»¾ÁÂÂÅÆÆÈÍÏÏÍÊÊÈ¿´´·¿ÀÀÆËÌÊÄ¿¾¾ÂÂÄÇÓÕÔÔÓÓÑÌÌÈ»”‚…‡ŠŒˆ}€z †¨ÉÓп»·§@›aU²ÁÅÊÝá×·–ŽŽˆ‡‡ˆŒŽ‘¡²µ¶»½½»»º»¾ÁÂÂÅÆÆÈÍÏÏÍÊÊÈ¿´´¶¿ÀÀÆËÌÊÄ¿¾¾ÂÂÃÇÓÕÔÓÒÓÐÊÉź’ƒ‰‰~zy{}{„¦ÈÒÐü¥<˜AJGc°ÁÇÈÔ×ϸ ™˜“€‘T““—¢­±²¹»ºº»»¼¿ÁÂÂÅÆÆÈÍÐÏÍÊÊÈ¿³´¶¿ÀÀÆËÌÊľ¾¿ÃÄÅÇÒÔÓÒÒÓÏľµ•„ˆ‹‘‹~}}„¥ÇÐÍÅÅ¿§M+&” &vˆŠ’½ÈËǺ¸€¹7º¹·¶µ²­¨¨§§¦ª³¶·¸º»¼¾¿À¿ÅÆÆÈËÍÍÌËÌÉÁ·¸º¿ÀÁÅÈÉÇþ¾ÀÅÇÉÊÑÑÐɶ¯®ª›”—›Ÿ¡œŠ†€ˆ§ÄÌËÐÓÎÀ†{rU“h*|•™¢ÄÎÎÇ®ª®ºÅÈÈÇÇÅÁ¶°¯©¢ ¦±µµ·º½½¾¿À¿ÅÆÆÈËÍÍÌËÌÉÁ··º¾ÀÁÅÈÉÇþ½¿ÈÉËÌÏÐÏÏÐÐۧ¥¤šœ ¤¦¡–“’†€ˆ¥ÁÈÈÕÙÖÉš‚Y”v–Ÿ¥¿ÈÉ¸ÄÆÅ3Á·²±«¥£¦±³´·º½¼½¿¿ÀÄÅÆÈÌÎÍÌËËÊÁ·¸¹¿ÀÀÅÈÊÇÿ¾ÀÈÊÌÍÏÐÏ€Î!ݧ¥£™›ž¢¤ —•“’‹‡Ž¨ÂÈÈÔØÕÈŸ“…W‘*†¯¸µ¸º¹µ§£§´ÂÅÄÇÇÆÆ¾¼»³«ª««¬­¯¹½¼½¾¾¿ÂÂÃÅÉ‚Ë"Êû¼½ÀÁÂÅÈÊÇÄÀ¿ÂÊÍÏÏÒÔÒËÆÅ¼ª¢  œœ‚žŸ £¤§µÂÅÆÓÖÖκ´§{KCI:%•ÉÓȲª¨¦Ÿœ¡°¿ÃÄÉËËÊÅÅû²°­§¥¤ª·½¼¼½½¾€ÀÂÇÉÉÊËËÊÄ€¿7ÁÁÂÅÇÈÇÄÀÀÃÏÒÒÓ××Ôɾ¼³¢›šœŸ  œ˜˜¥¨ª®º¿¿ÀÂÂÃÑÕÖÖÔ×ÊžofdL‘‘ÎÛϱ¨¥¥žœ °ÀÄÅÊ€ÌXÉÉÆ½´²®¥¢¢©¶¾½½¼¼½ÀÀÁÃÇÉÉÊËËÉÅ¿ÀÀÁÁÂÅÇÈÇÅÁÁÄÐÓÓÔרÕɽ»³¢›™šž  œ––š§ª­²¿ÇÆÄÂÁÃÑÕÖ×ÝàÓ¥vkgH7ST;J’ÅУ™——–•™©º¾¿ÆÇÈÈÇÈÆ¿¹¸´¬©©«´·¸¸º»¼¾¿ÀÁÇÇÈÊËÌËÇÀÁÁ€ÂÄ€ÆÅÂÃÈÐÔÕÓÑÒÏ÷´¯ žœœŸœ¢¬¯±µÁÆÅÄÃÂÄÍÐÐÒÚÞÒ«‚ztN7…œ™”¤·¹ªusw„…Š™«°²¹¼¼¾ÉÌËÈÄÄÀ¶³±°¬ª¬´»½¼¿¿ÀÁÂÃÄÉÎÏÎÈÁ€ÁÃÅ ÆÇÈÐÒÒÑÈÈõ§¢¡ ŸžžŸŸ¡§«­°º»½¾ÅÈÇÆ€Å ÇÆÇÊÒ×Òº¡ž“a7…¡¤¡¨²°¤wkjm~€ƒ•©­®·¸º¼ÈÌÌËÉÉ´©¤§°¹¼»¾¿ÀÀÁÀÂÈÏÐÏÉÂÃÀÁÂÃÃÄÅÇÉËÒÔÔÑÅÄÀ²¢ž‚Ÿ ž¡¨®°³½ÀÀÂÅÉ€Ç ÆÆÃÂÃÇÐÖÒ¿«©œc‚¢¨§ª¯­ vifkƒ”¥ª¬´¶·»ÆÌË€Ê2ƽº¸´ª¤§°¸»º¾¾¿¿À¿ÁÈÏÐÏÉÃÄÃÂÁÁÂÃÃÄÅÇÉÉÒÓÓÑÁÁ½¯¡œŸŸ  ¡ª±³·¾ÀÁÃÆÈ€Ç ÆÆÂÁÂÆÑÖÒÁ°®¢e)ƒ¨¯¬®°­¡xkin||‘¤¨ª¯±³¶ÁÇÇÈÇÉž¼»·­§ª±·¹¸½€¾ ÀÀÁÈÏÐÏÊÄÅÄÀÂÃÃÄÆÈÊÊÑÒÑνº·¬¡œž€ ¡¦¦¨®µ¶¹¿ÁÁÄÆÈÇÇÈÇÇÃÃÄÇÐÔÑ´µ¦g4‘»Æ¿¶­¨Ÿ~ussvtx‰™ž¤¤¦©²¶·¼ÃÅÅÆÇÆÂ·²³±°¯°¹½¼¼¿¿ÀÆËÍÌʀǀÄÀÂÇ€ÌÎÎÍÆ§¢£Ÿœ›ž¤¤¦©±µ¶»ÀÂÂÆÇÆÇÉ‚Ê ÉÈÇÈÊÑÓÓÏËϾt;—ÅÑɹª¤›€vtsomqƒ”™˜ž £«°±ºÃÅÆÊÌËÇ»¶µ±­¬®¹»»¼½¾¿ÅÌÎÎÊÈÈÇÆÅÅÄ€ÂÈÍÎÎÍÍËÁž—™šœ›¤¥¦¬·¾¾ÂÆÇÆ€ÇÈÉ€Ê€Ë ÉÉÊËÐÑÓÓÕÙÆx4”ÄÐȺ¬§Ÿ‡|}xvz‰˜œ›ŸŸ £ª®°¸¿ÁÁÇÈÇź¸¶³±®°¸º»»¾¾ÀÅËÍÌʀƀÅÄ€ÂÈÍÎÌÉÈÆ¾ž˜™Ÿž¡¥§©¬¹¾¿ÂÆÇÈǀȀÊË€ÌËÉËÌÏÐÑÓÕØÄyŠ–ÉÔÎù¶³©¥£¡˜—˜Ÿ¦§¤¡  ¡£¥¦­´µ¸½€¿½¼¼·´³³µ¶¶¸¼¾ÀÃÇÊÈÅÀÁÂÃÄÄ€ÃÄÇÌÌǺµ³¯›—™ §§ª¯±³µ¿ÃÄÆÈÉÉ€ËÌËÌÌ̈́ΠÏÏÑÔØÝÎ>EWŠ4˜ÍÚÔÍÇÅÇÊËÊǽº¹µ²±¬¡žžŸ£¨ª®¶¹»¼¿Á¿¼¹·¸±°°³½¿ÀÃÅÆÅÀ€¼ÂÂÀÄÅÇÉÉ«£¡ ——™¤¯°²º»½¿Æ€ÊËËÌÍ€ÎÏÏÐÐÏÐÐÒÒÑÑÏÎÏÖÞãÕ¦jmxŠTÌÚÕÏÉÈÌÒÖÖÒÃÂÀ¹³²¬¡žœ›š™š ¥¦ª³¶¸ºÀÄþºº¹±¯¯³½ÀÁÃÅÆÅ¿º»¼ÂÃÄÅÅÄÆÈËÉÁ© ›—•™£¯²µ¼¿¿ÁÉÌË€Ì˃πÐÑÑÓÓÒÒÍÍÎÖÞãתst}‡>)ŽÊÙÔÎÈÇÊÒÕÔÑÅÃÁ¼¶´°¥¢¡¡žŸ£¦§«´¶·¹¾ÀÀ¼¹¹¸±¯¯³»¾¿ÁÄÅÄÀº»¼ÀÁÁ€ÄÅÉÆ¿¨žœ››™›§²´·½¿¿ÂÉÌÌËÌÌÍÐÏÐÑ€ÒÑÒÔÓÒÏÎÏÖÞâ׬ww‡:«ž—¶Ð×ÓÍÇÆÊÖÚÛÛÙÚÙØ×ÖÓÍËÉǽ¸¸³®­¬¬ªª«©ª¬µ½¿¾¸¶¶µ¬«¬´¼¾½¸°±±€²!¹¾À¾¹³¯©ˆ‡«®¯ºÄÇÆÈÈÇÉÎÐÐÑÑÒÓÖ×ÖÖ€ÕÖ××ÙרÙ×ÔÒÓØßâÛÁ¡¢«‡´©¦¾Ñ×ÓÍÇÆÊ×ÛÜÝ€ß&àÞßÜ×ÔÓÐþ½¶°¯®©¨¨§§¥¨³¾Á¿º¸·´ª¦¨²»¿¾¶¯°$¯·¿À¾¶®«¢Œ€‹®²´¾ÉËËÉÉÊËÎÐÐÑÓÓÕÖÙØ×Ø×€ØÙÙ€Û ÙÔÒÓØßâÝÆ«­·‡¶¬ª¿ÐÔÑÌÈÆÊ×ÛÝÝà‚á%ßÚÚØÓÈÂÁº³²°««ª©¦¥©²¼¿¾¸¶¶³©¥¨°¹¼¹µ°¯¯€­¶¾¿¾´ª§ ƒƒŒ°µ¶ÀÊÍËÌËÌÍÏÑÑÓÔÔÕØ€ÙØ€Ù€Û ÙÔÒÓØÞàÚǰ±»‡º°­¾ÌÐÎËÇÆÊ×ÛÝÝß‚àGÞÜÛÙÖËÇÆÁ¼º·³°¯°«ª¬°¶·¶±±°­¦¢¤ª°±±®ª«ª¦¥¥±¼¿»¯£Ÿœ‘Ž•µººÃÌÍÍËËÌÌÒÓÒÕÖÕ×Ù€ÚØ€ÙØÙÙ×ÓÑÒÕØÙÕŲ³¾‡ÉÀ¼¿€ÁÂÃÄÈÔ×ÙÙâááà€ß@ÞÜÛÛØÖÖÓÍÌÊÇ¿»¸¬¡žžš›š™˜˜—”Ž•š™—Ž‹Œ¤¸¿·¡‰ƒ‹¡§ª¯ÅÈÉÌÏÑÐÒÑÑÓØÚÙÛ܃ۀÚÙØØ×ÓÑÑÐËÊÈÅÂÁÁ¿¼¿É‡ÏÅÀ¿¿¾¾ÁÃÄÈÔØÙÙâãââ€á€à€á4àßàßÜÔÑÏÌÄ¿¼ª˜••’‘’’”•“Œ†„†––’ˆ„„ ¸¿·œ€{…¦¯²·ÌÎÎÐÐÑÑ€ÒÔÚÜÜÝ€Þ€ÝÜÜÛÛÚØÙØÒÐÏÎÊÊǽ»»½¾Â̇ÐÆÁ¿¼»¼¿ÂÄÇÓרÚàâ‚áàâ2ááÞ×ÕÓÐÇÃÀ°Ÿœœ˜——˜–—”†ƒ†‹’’ކ‚‚œ²¸°šƒ}ˆª´¸¼ÍÏÏÐÑÒÒ€ÓÕØÚÚۀ܀ÛÚÙØØ×ÖÖÕÐÏÏÍÉÇÇÀ¸·¹¼ÀÄ·Íÿ»·µ¸¼¿ÁÅÐÔÔÕÝ€Þ‡Ý7ÜÙØ×ÕÒÏÎĸ¸¶±°¯­¢ “І‡††…ƒ}{{‹˜œš”–µ¾ÁÃÏÒÑÑÒÒÓÓÔÔÓÔÓÓ€ÔÓÓÒÑÑÐÏÏ΀ÍÊÉÉÈÅÄû³±³¹ÀÄ·ËÁ¾·±°²¸¿ÁÃÏÒÒÔØÙÙÚ€Û‡Ú5ÛÛÝÝÜÛÚÚ×ÓÓÑÉÇÅ¿¯ª¦šŒŠ‰‚{{yvssz~Žš ¥ÀÆÉËÓÕÔÔÓÓÔÓÔÓÒÏ€ÌËËÊÊ€ÉÇÇ€ÆÅÆÃÃÄÃÂÁ¿·¯«¯·ÀÆÏ‡ÊÀ½¶±°°¹¿ÁÃÍÐÑÓØÙØÙ€ÛÙÚÚÙÚ‚ÙÚÝ€Þ6ÝÝÞÜÛÜÚÑÎÌÆ²­¨›Ž‹Š‚yxvtqquwv{£ªÃËÍÎÖ×ÖÕÔÔÕÔÕÔÒÏËÌÌÊÊË€ÈÇÆÅÅÄ€ÃÂÂÃÃÁ¿¶­ª­¶ÀÆÏ‡ÉÀ»µ®¬®¶¾¿ÂËÎÐÐÔÕÕÖ€×ÖרØÙÛ€Ü&ÛÛÚÙØ××ÌËÉð«§šŒ‰ˆ€xxwvutx{zž¤«¿ÆÉÊÑÓ€Ò‚ÑÏʃȀÆÅÄÃÃÂÁÁÀÁÂÁÀ½½»²«©«µÀÅχǾº®¥¢¥®·º»ÅÆÇÉËÌÌ€ÍÌÌËËÌÍ΀ÏÐЃÒ"ÑÐÐÏÏÄÂÁ¼­©¥•…‚|vwy}ƒ‡†Š˜¦«®¸¼½¾€ÄÀ ÁÁÀÀ½¼¼½¾¾¿€½¼»ºº¹¸¸·¶µµ³«ª¨§¥£§´ÃÈч úµ¥˜”˜¤±µ¶½€¿„À¿ÃÄÅÆÇ…È€ÇÆÆ¼»º¶¨¤Ÿ€{|wstyˆŽ’“–£±³±¯€®³´´²±²°¯€®€­®„°¯®®­©¨§£”–›› ±ÅËÕ‡û¶¤•‘•£±´¶¼¿¾¾†¿ÀÀÂÄÅÆÇ…È€ÇÆÆ¼»º¶¦£ž€{{xssxŠ’””˜£°²±¯€®³´´²€±„¯°„±€°€¯®ªª¨¤•‘’—œž¡²ÆËÕ‡ûµ¢““ ­±³¼¿¾¾†¿ÀÀÂÃÃńǀÆÅ º¹·²£ž™Œ}yyxuv{Œ‘’•–—™¥±²±°°¯±¶¸·¸¶€·¸‡¹¸··¶³²²­£ŸŸ£§§«¹ÊÏÚ‡ ºµœ†€…–¦«®¹€½ƒ¿À¿¿ÀÀ€ÂÄ€ÆÇ€Å,ÄÃĶ´±ª’Œ‡€wuwy}„› £¢¢¡£¨¯±°´³´·ÃÄÄÅÆÆÈÌÎÎÍÐÑÑ€ÒƒÓ‚Ò ÑÑÍÍËËÉÈÉÎÔÙ㇠ºµš{€“¤¨¬¸€½ƒ¿À¿¿ÀÀ€ÁÀŀÆÅÄ€Ã,ÂÃÁ´²¯§Œ…‚|usuy~€‡¤§¦¥¤¦ª¯°±´´µ·ÆÇÈÊËÌÎÓÔÕÖ×€ØÙÙÚÚ€Û€ÜÛÚÙÙ€Ü ÛÛÚÚ×ÒÒÑÖÙÜ燺´™{’¤¨¬¸½¾¾¿ƒÀÁ€À€ÄÅÆÆÅÃÂÀÂ*À´²¯§‹„ztrty‡Ÿ¦¨§¥¥¦ª¯±²²³µ·ÇÈÈÊËÌÏÔÖ×ØÙ‚ÚÙÜÜÛÝÝßßÝ€ÜÞßßÞÝÜÛØÕÔÕÖÙÝè‡ƽ¸¢‘Šœ¨¬¯º¾¿¿ÀƒÁ€ÀÁ€ÂÀÀ€¿¾¾¼€»%µµ³«”‰~spqx‡ž¤§¦§§¨ª¬®®²±²¶ÆÇÆÅÃÂÆÉ€ÌÎÏÏÐÒÒÓÔÖ€×€Ö× ÔÔÓÐÎÍÎÑÔÚå‡Ǿ¹ª™›¤®°²¼¿ÀÀÁƒÂÃÃÂÂÀ¿ÀÀ¿À¿½½¼»º¹·¸¸€·'¸·°™“Žrnqx‡ž¤¥§§¨¨©ª««®®°³ÅÆÄÁ½¼¾ÂÃÄÄÅ ÆÆÈÉËÌÌÑÒÒÐÑÑÐÏÌÇÇÈÎÒ×㇠ȿº«¡ §¯±³½€ÀÂ…ÃÂÿ€¾¿¿¾¼€»·¸·µµ´µ¸¸·°š”Žpkov~‡¤¥§¨©©¨€© ­®¯³ÃÆÄ¿»º¼ÀÁ‚€ÃÄÉÊËÌÏÒÑÑ€ÐÑÑÐÑÏÐÎËÇÆÈÌÒ×â‡È¿º«Ÿ›¦®°³¼¿ÁÀÁƒÂÁÁÀÁ¾½½€¿¾¼€»¹¹¸¸·€¶·µ¯—’„vru|‚…ŠŸ¥¦¨ª«ª«€­±°²¶ÄÆÄÁ½¼¾ÂÂÃÂÄÃÀÄÅÇÈÈÉÎÏÏÍÎÎÏËËÌËÉÈÈÆÄÄÅÊÑÔ߇ÉÀ»ª›—™£­¯°¹»»¼¿ƒ¾€½¼»ºº¹€¸€¹º¼½¾»¹¹¸´²²¯¦¤¡˜ŽŒ‘•£§¨¬®°°¶€¼¾¾¿ÀÃÄÄÃÁÀÃÆÈÈÇÅÄÄ€ÃÄÀÄÇÆÇŸµ´³­¬­²·¹»ÀÈÍׇÉÀ»©š”˜¢«¯°¶·¸¸„º€¹¸·¶¶´±±³¶¸¹ºÀÂÁÀ¿¾¼²¯€°±°«¦¥¤¢ŸŸ ¦§¨¯¶·¹ÁÉÌË€ÊÈÄÃÃÄÇÆÈËÍÍËÈÆÆÄ€Â¿ÀÀ€¿¾¼¤œ›“‘“Ÿª­¯¶¾Ä· È¿º¨™•˜¢ª­¯µ€¸º¹¹€¸·¸€·€µ(´±±³·¹º»¿ÂÁÁÀ¿½²¯¯±²´´±¯®®¨¡¡£©««²·¸ºÅÏÑЀÏÌÃÂÃÅÇÈÉÍÎÎÌÈÆÆÄÁÂÁ¿¿¾¾€¿¼º¼¸ ™—•‹ˆ‹š¨«­´¼Àʇż¸¬ žž£¦¦©´¶·¶€¸…¶€·&¶´´µº»¼½¾ÁÀ½¼¼»³±±²µ¶¶²°±¯ª¢£¦«®¯³¶µ¹ÃÍÏÎÌÆÅ€Ç&ÈÈÌËÌÊÈÇÇÆÃÄÃÁÀÀÁ¿À¿¾½½º£œ›–‰‚†™¬°°³·¼Å‡¹°®±´µ²¦›šž­±²³€µ ³²²³³´´µº»º½¿¿À ¿¼º¹¸·¶··¹¹º½€¾!½¾»²¦¦¬¹¾¿º¶´¸ÃÐÓÓÐÐÏÎËÊÊÉÈÈÇÇÆÆÇÈ€É€ÈÆ€ÅÄÄÃÀ¾¾¼¨¢ —|pu’°¸µ¯ª¬¶‡·¯«³»¾¸§—“™«¯±°´³³±€¯@³³²¶¹½½¾ÁÂÁÄÄû¹¸¶³²³º¼»¼¿ÀÁÁÀ¿µ¨©­¾Âú´±µÃÑÔÔÐÐÏÏÎÍÎÊÈÈÇÄÃÃÄÉË€ÊËÉÈ€ÇÅÅÄ¿¿½ª¤ —vho‘±»·¯¥¨±‡V´«¦³½Á¼©”˜©¯°¯³´³±¯¯°³´³µ»½¾ÀÁÂÂÄÄú¸·¶µ³´¼¾¿¾¿¿ÀÀÁÂÀ´¨¨®¿Ãļµ²¶ÄÑÕÔÑÑÐÐÏÎÎËÇÈÇÄÃÃÅÊ˂ʀÈÇÇÆÅÂÀÀ¾ª¥¢˜vio‘³½¹® ¤­‡©œ‘¨¼Â¼¥“¢¥§¨³´€³ ²³¶·¶¸¼¾¿ÀÁ€ÁÀ¾¹·¶·»½¾¾¿¿€ÀÁ¾µ©©®¾Ãļ·µ¸ÃÎÒÑÐÏÎÎÌÈÉÈÆÅÅÆÇÉÈÈÊ‚ÉÈÈÇÇÄ¿À¾¬©¥š}ou–µ¿º«˜š¢‡)z¸ËÀ}ux‚…Œ®³³¸½¾¾¿¿ÀÁÃÅÅÃÂþ¶²±³µ¶·º¾¿ÀÀ€Á¿½¼»µ®°´ÃÆÈÅÁÂÁÂÃÄÅÏ€Ñ+ÐÏÏÎÍÎËÉÇÇÆÂÁÁÂÅÄÆÍÏÏÎËÊÉÆÄÄ÷µ³­–‘©Áɾ™lluŠ'x¼ÍÀœzqu|}‡®³²¹¿ÀÁ¿¿ÀÁÅÆÆÅÂÿ´±°±´µ·»¿Á‚ÀÃÄÿ¼»º´®¯³ÂÆÈÅ€ÃÂÁÂÅÏ€Ò+ÐÐÏÏÎÍÌÉÈÈÆÂÀÀÃÄÃÅÍÏÏÎÌÌËÉÅÅù·µ®˜“ªÂÊ¿˜iiqŠƒ½ÍÀ ~w{€‚„Œ°µµº¾ƒÀ€ÄÃÁÁ½¶²±²µ¶·»¾À¿À€Â¿»ººµ¯°µÃÈÉÆÅÄÄÃÀÁÄÏ€ÒÐÐÏÏÎÍÌ€È!ÆÃÁÁÃÄÄÆËÍÍÌÌËÊÆÄĸ·µ¯›’—¬Àɽ“`aiŠ(оÌÁ§‹…‰‘’“š¸¼»¾ÀÁÁÂÂÁÁ¿¾¾¼ºº¹¶µµ¶¹º»½¿À¿€ÀÁÂÃľº¹¹¶²³·ÃÇÇÆ€Å¿ÀÃÏ€Ò ÑÑÐÏÏÎÍËÊÊÉÆ€Å€ÄÆ€ÅÄÂÂÁº¸·´©¥©´¿Ç·~27FŠ ŽÀÌî—“—Ÿ¢¢§¿€ÁÃĀà ÂÁº¸¸µ³²´·º¹º¾¿À¿ ÀÄÆÆ¿¸¸··¶·ºÄ‚ÇÆÃ¿ÀÃÍÏÑÑÒÒÑÑÐÏÏ€ÌËÉÈÇÆÅÄÃÀ€¿ÁÀÁÀº¹¹¸¹¸º½¿Å±jŠ(’ÁÍÅ¯š—š£¥§«ÀÃÂÂÅÅÄÅÄÃÁº··´°°²¸ºº»¿¿ÀÀ¿À¿€¾ ¿ÄÆÅ¾¸·¸·¸¹¼Å‚ÈÆÃ¿¿ÂÍÐÑÑÒÒÑÑÐÏÏ€Ì ËÊÉÈÇÅÄÁ¿¾€¿ÁÀÁ€Â ¼»»¼¼½½¾ÁųgŽºÆ¿°¢ž £¤¥©¿ÂÀ€ÁÀ¿À¿½¸¶¶´²²¶¹¼½½¿À¿¿À¿ ÀÁÂÃľ¸¸·¸·¸¼Ä€È ÉÉÈÄÀÀÃÍÏÐЀÒÑÐÐÏÍÍÌËËÊÉÇÆÅÄÀ¿¿¾¼»»¶€³ ²±²´½ÀÀ¼»¾®g„­¶´±±°­¦¢¡§¼¾½½¾¾¼µ³³²´³³µ¸·¹¾ÀÁ€À¿ÀÃÄÆÄÂÁÀ½º¹¸·µ¶ºÄÇÈËÏÏÎÈÂÂÅÍÏÐÐÒÑÑ€ÐÏÎÌËËÊÉÊÇÅÃÃÀ³¯¬ ”’›Ÿ§ÂËȺ®­ `„«´²³··²¥¡ ¦½¿¾€½º´°±±²²³µ¹¹»¿¿ÀÀÁÁ€À¿¿ÄÅÆÅÁÀ¿½»º¹¸´µ¹ÄÈÈËÐÐÏÉÃÄÇÌÏÐÐÒÑÑ€ÐÏÏ€ÌË€ÊÅÄÿ±«¨˜‰…ˆ”–™£ÂÍË»«ªc „¨­¬±¹ºµ¥ ¡¦¹¼»·²€°±²³µ¸¹»¿ÀÁ€À ¿¿ÅÆÇÆÀÀ¿½»º¹¸µ¶ºÃÇÈËÐÐÏÉÄÃÆÎÐÑÐÑ‚ÒÑÐÐÏÏ€ÌËÊÊÉÆÅÄ¿±ª¦˜ˆƒ‡“–˜¢ÄÐ͸¤¢™e~š›˜¨¼À¸©£¢¦±±²²³´³¯¯®¯²´µ·¹º¼¿ÀÁ€À¿ÀÅÇÈÆÂÀ¿½¼»»º¹º½ÅÈÉÌÏÐÏÉÃÂÆËÎÏ΃ÓÒÐÐÏÏ€ÌËÊÊÉÆÅÄÀ³­«š‰…ˆ—™¦ÄÐÊ«Ž‰…]!5G1A‹ÄÓɱª§£—“•™Ÿ ¦¨¨«¶º¹¼½¼½ÃÂÃÄÀÉËÉÇÂÀ¿½»»¼¿ÃÃÆÊÍÌÍÎÎÍɀįůÈÒ‚ÓÒÐÐÏÏ€ÌËÊÊÉÅÄÃÁ¼¹µ¤‘‹Ÿ£«ÉÕÆ~-(‘‚ÍÞе¬¨£‰…‡––𢥦ª·¼»¼½½¾Ã€ÂÀ¿ÀÁÊÌÌÊÂÀ¿¾½¼¾ÂÈÉÉÍÎ̀ΠÍÉÃÂÄÂÃÄÇÓÕÔÒÑÐÏÏ€ÌËÊÊÉÅÄÿ½¸§” £§°ÌÙÆo•ŠÈÖ˶°¬¥‡ƒ‡““™£§¨¬¸½¼½¾¾¿ÁÀ¿ÀÁÀÁÂÈËÊÈÂÀ¿¿¼¼¾ÂÈÈÉÌÍÍ€ÎÍÉÃÂÃÇÓÕÔÓÑÐÏÏÍÌÌËÊÊÉÅÄľ¼¸¦”¤¨ª±ÇÑ¿q•€´À¼»»¸­~x{€…„ަ­¯±»¿À¿¿¾½¾ÂÆÇÈÇÈÇÅÀ¾½¼ºº¼ÁÈÈÉÌÍ̀ΠÍÊÆÅÄÁ¿ÀÄÓÕÔÔ€ÓÐÐÏÎÍËËÊÉÉÇÄÂÁ¿º¸µ¥•”°·¸·²µ¥d•Fv «®ÁÈÆ·pimsvt„©³·¸¾ÁÀÁÂÂÁ¿¿¾½¼º¼ÄËÍÌÇÅľ¼»º¸·¹ÀÈÈÉÌÍÍÎÏÏÎËÈÆÆ¿¾¿ÂÒÕÔÓ€ÒÐÐÏÎÌÊÊÉÈÈÆÂÀ¿¾¶´±¤—’˜¼Ãü¡œŒW”G!zž§«ÅÍÉ·j`flqo€ª¶º»¿ÂÁÂÃþ¾½¼¼º¼ÄÌÎÍÆÄÃÁ½»º¹¸¸ºÀÈÈÉÌÍÍÎÏÏÎËÈÆÅ¾½¾ÂÓÕÕÓ€ÒÑÑÐÏÌÊÊÉÈÉÆÂÀ¿½·³°¤–‘˜¾ÉȾ —‰Z”G pŒ‘“¾Ê˽ƒ}}zw†«´¸¹¾ÁÀÁÃý½¼¼¾¾¿ÅÊÍÌÅÂÁÀ¼»º¸·¶¸¾ÆÆÈËÍÎÏÏÐÏÌÉÇÅÀ¾¿ÂÎÑÐÑ€ÒÐÐÏÎÍËÊÉÇÆÄÁÀ¿¾·µ´«¢Ÿ£¾ÆÃ¶„|qN•B/9:T¬ÄÊÆ·¶²¡†‘©¯±³º½¾ÀÂÄÁ½¼¼½ÁÃÄÈÌÍÌ¿¿¾º¹·¶µ³µ½ÅÅÇËÍÎÏÏÐÏÍÊÉÇÂÀ¿Á€Ë!ÏÒÓÒÐÐÏÏÌÌËÇÄÿ¿¾¼¹·¹»¼¾¾Á¼ @! ˜@®ÅÍ€ÊJÄ«“Š•©®°³»¾¾ÀÂÄÁ¼»»½ÂÆÆÈÊÌÊÁÀ¿¿¹¸·µ²±³»ÂÃÅÊÍÎÏÏÐÏÍËÊÈÂÀÀÂÇÈÈÎÓÔÒÐÐÏÏÍÎÍÇÁÁÀ€¿ ¾º¹ºÁÇÈÈÃļ +›aB®ÂÆÅÎÐȰ–Ž˜¨¯°²¹½½¿ÂÃÀ¼»»¼ÃÆÇÈÊÌÊÀ¿¾½¹¸·µ²±³»ÂÂÅÊÍÎÏÐÑÐÍËÊÈÂÀÀÁÇÆÈÍÒÔÒÏÏÎÎÍÎÍÇÀÀ¿¾¿¾¼¼º½ÂÇËɽ»´œ,›G¥°®­ÊÏdzŸ™ž§©«­¸»»¿ÂÃÁ¼»»¼ÅÈÊÈ¿¾½¼¹¸·¶µ³µ½ÅÅÇËÍÎÏÐÑÐÍËÊÈÁ€À!ÃÂÄÌÒÔÓÏÏÎÍÌËËÆÁÀ¿¼¼º»¾¿¿ÃÆÉÅ¢žœ‹-œ&LC>YÂÎɽ¼µ£ ²¸¸º¼½¼»º»½ÆÊÈÇÆÅľ¼»¼¹¹€¸5·¹¿ÇÇÉÊÌÍÎÏÐÏÍËÉÇÂÀ¿¿··¹ÄÎÑÏÎÎÍÌÊÉÈÅÁÀ¼¶³²¸ÅÌÊÅÂÅ·H,)- !!ÂÑËÌÌ˽ž””›®··»½¾¼¼º»½ÇËÊÆÄÃü»º»ƒº1»ÁÉÊÊËÌÍÎÏÐÏÍËÉÇÁ¿¿¼³²¶ÁÎÑÏÎÎÍËÉÇÆÃÀ¿¼±­¯¶ÉÓÐÊÄÆ· £$6¼Á¾ÂÇ˾¥œ›Ÿ­²³´µ¶·»¼¼¿ÅÊÉÆÃº¹¹¸·¶¶€·¹ÀÊÊÉ€ËÍ€Ï%ÌÉÈÆÁ¿¾¼¯­±¿ÌÏÎÍÎÎÌÈÇÆÂÀÀ½µ²³¹ÉÑ;²³«$£XŒ„¡ÂÌõ°®¬¢™—”Ÿ¶¾¿ÀÅÈÆÃÀ¿¿µ´³±®¬«­®­±¼ÉÊÈÈÇÆËÍÎÎËÈÇÄ¿¼ºµ›—œ°ÃÇÈÊÌÍÊÃÀ¿¾¾½¿ÄÅÆÇÈÌÀ—pkm¥U ¼ÌÉÅÆÃ¹˜ˆˆ€wr†±¾ÂÂÄÅÄÁ½¼¼³±°­£ Ÿ£¥¤©¶ÈÉÇÅÃÃÈÌÍÌÊÈÆÅº¹¶­†‡¡º¿ÁÇÉÉÆ¼¸¸¹¹¸ÁÒÙÚÕÊÇ´qª„ÁÑÍÏÎʽ“€xmg±À€Ä=ÅÄÀ½½»³²°®¡žŸ¡££§µÉÊÆÅÃÂÈÌÍËÉÇÅÄ»º¸­{ƒž¹¿ÀÉËËÇ»··¸¹¸Â×ßàÛÍɸmªR‹¼ÂÂÊÍË¿˜ˆˆvp„±¿ÃÂÂÿ»»º°®­«ž›šž¢ ¤³ÆÈÆÄÂÂÈÌÍËÉÇÆÃ¹¸´«{„œ³¹¼ÅÇÇĽ¹¹º»»ÂÕÜÜÕ½¸¬o«Q%?&Z¯ÅËǾº¸®¤¡¦­¯¯®®¯¬©¦¥¢‹‰†|xy„„Š¢¿À¾»º¹ÂÉËÉÇž¯«¨Ÿuot‚’—¨¬¯³ÂÈÉËÍÏÍÊÊÁ§H%®K<®ÆÎËÉÈÆ¼±®®¬««ª««ª¥¡¡žˆ„‚~tpqx„Ÿ¿À¾º¹¹ÁÈÊÈÆÄ¾«¨¥œqmq{†‡ŽŸ¥¨­ÃÌÌÎÒÔÏÈǾ¡'±KB¯ÃÇÅÉËȾ´²°¬«ª«¨¨§£Ÿž›†}ropw~~„œ¼¿»¹¶·ÀÇÊÈÆÄ½ª¥¡™rlrz„†Œ ¤§¯ÂÎÍÎÑÓÍÀ¾¸ž(±KG¦±¯­»ÃÁ½ºº·°¯¯­¨§¦ž••“€|zxomnu||‚›º¼¹³°±ºÃÅÃÂÂÀ¹¢œ™’qlq|†‰‘¤ª­²ÈÑÏËÇɽ¥¢Ÿ+²IMB@R“¬®¾ÏÔÍ¿»¸³¦ ›‰xssdbbcddgnvw|”°±­¤¡ «µ·¶µµ³©‡~{zmjo~ŒŽ˜¯¶º¿ÏÙÒ¼¨¥ŠB+*.¶C0Œ§«ÁÙá×Å¿»µ¥˜‚kgf]Z[\__bluuz‘¯¯«Ÿ›œ§°³²²³°¤€uqrhgl}‹š³¼ÀÅ×àØ½¢ž ¹0†››°ÇÌÈ¿¾½·¨¢‡rmmc€b,dcgotv{‘¬­¨œ——¤®±°¯¯¬£„{xvqouƒ‘•µ»¾ÀÄɪ‘u¹C fohr~y‰«¶¹·µ´²¥—•”ŒŠ‰†{uvz}}’¥¥ “ŽŽœ§«ª¦£¡Ÿ™—–—––™¡«¬®³´±¥‚sug[^Rº5>˜¯·¹ÄÉÈÅÀ¿¿µ³°ª‘‰‡†„ƒ…ž˜‰„„” ¤¡–—­³µ·¾¾¿ÂÄÅ¿±¯¦2‚Á5(œ³¹½ËÒÑÐÏÎÍÂÁ½²–Œˆˆ…„†››”†€‘ž¢Ÿ™‘‘š³¼¿ÂÌÍÍÎÎÏǵ±¨Ç5=›ª®­ºÀ½¼¼¹¸¼¾¼²š‘ŽŽŒŠ–žžš‰ˆ—¢¥¤—˜Ÿ³º¼»¶·¹º»¼´¥¡‰(Ç5'w{vrwywuqlr­»½¸®ª¨¦¤£¤©¯¯«£Ÿ ª²´²±¯¯±µ¹¶§mgnqrurhhi_Óž¶¿¿ÆÇÈÄÁ€À‚¿ ÀÁÂÃÄÆÊËÆ¼¹°“ß ¦½ÃÃÌÎÎËÇÆÇ„Å ÆÈÈÉÌÐÐÌ¿¼´›ß µÇÌÍÕ××ÔÐÏτΠÏÒÑÒÖÙÚÕÈÅ¿¨ÿÿÿÿÿ¤ÿÿÿÿÿŸ'/iy{€©µ¹½ËÏÐÌÊÉÊÇÆÆÇÌÍÍÑÖ××ÖÖÕ͹±¬¢vplXÖUprv «¯²ÀÅÆÃÁÀÁ¾½½¾ÂÃÃÇËÌ Êï§£™lhcE×Gkosœ§«®¼¿À¾»ºº¹¶¶¸»½½ÁÅÆ ľ«£Ÿ•lf_:Ï LŠ…‚Šˆ„ ¡¶€º%»»·¨š––’Ž•¦¬®±µµ¶·¸¹·¯®­©–“…{~€~ƒ5Ç5U𡡤·½»ÀÆÈÆÉÉÈ帰˜~vwrloy•ž £¦¥¦ª­¯±´¶·¸¸¹º¹¼Àº­«¨œEÇ5=–¢§¬ÀÈÈÍÒÒÑÎÍËÆº¶­’ulmicdošŸ ¡¢§ª¬®µ·º¼ÁÃÄÉÍÏÇ·³¬š/Á;1+N’ ¦ª»ÂÂÅÉÊÈÆÅÄÀµ³«’xpqkdfo™› ¡¢¥¨ª«¯°²´¹º»ÀÆÈµ²«˜?º,9vxu…”’¥ª¬­´·¶µµ´³±°¯®««§–ƒ}tfgpŒ•–™žŸ¡¡¢€Ÿ ¦§©²¼¿½¼¼¹°ŽƒŠ{jnh%¹CA…”®ÆÍź´²²®­«¦ Ÿž›™™œ¡¤£˜ŽŠ{hhp‰’•™š™šœ›™ŽŒŒ““—¦´¸¼ÄÇÊËÊÏÈ®”Ž€-¹(D‡—œµÏØÎ¼¶²±«¨¦ ›™˜”“”–Ÿ¡ ˜’‘}ihoˆ‘”–˜˜€™•‰……‡’¡¯´ºÄÉËÏÛáØ»ž˜‚1µ*k[P^Ÿ¡³Äʲ­«©¥£¢Ÿ›™˜—–—š £¢™‘Œ}jiq‡Ž”–˜—”Ї†ˆŽ‘Ÿ¬¯´¼¿ÁÅÓÙÓ¼¥¡‹L<± W¯½ÃÂÇÉij š—“€Ž:ŒŽ”™››  ¡£§ª§Ÿ—•’…uuz‰Ž”™›š˜–”“‹‹Œ‘’˜ž ¡¢£¥«¿ÇÊÍÑÕÎÁ¾¶Ÿ<®HX6i­½ÂÁÀÀ»«š•”Ž€Œ/‹“™š›¢£¤¥¨©¦Ÿ—•‘…utz‰Ž•šœ›˜•“‘Ž‹‹““•›¡£¤¥¦¨®¼€Ä ÃÄÁ¾½¶¢P5%ª >½À¿ÇÊÈ¿¬ ž”Š€‡€… Š‹‘–˜™¨«¬€«2©¡š˜•…ttyŠ˜ž Ÿ™”““‘‘’•Ÿ¡¡§¬­®°°±±³³®›…~‘·ÄÇĹ·±„ª3“¾ÆÆÊÌÊÀ¨›˜‡„ƒ„ƒ‚„‰‹Œ‘—˜™¨¬­«¬«©¡š˜•…suzŠ‘˜Ÿ¡Ÿš•““€’•¡££©­®¯±±³³²³­—u‹¸ÅÉÉÂĸ|¨@3‹¹ÃÁÀÀ¿·¥š—‰†…ƒ‚ƒˆŠ‹–—™¦€ª ««©¢š™”‡uu{ŠŽ—Ÿ Ÿ˜“’’‘‘’”¡¢£¨­®¯€±²®®ª”}u‰°½À¿¾À²x¤5IŸ•‹£¼Ã¸¢š˜—•“’ŒŠˆ…ƒƒ†ŠŽ’–—˜¡¤¤¦«­«¢š™”‡vw|‹’™Ÿ¡ž˜’”¢¥¦ª®°±´¶´±¤ œˆqix“›Ÿ¤¶Á¶˜z|„£6V¾¿¹»Àð„tqv†ŒŠ‡„„†“•––›ž «®­£š™”‰wx}‹’™Ÿ¡ž—Œ€Ž’£¦§«°²³·¸·°š‘ze]gvz~Š±Â¿·´¹´9£6ÁÈ€Ã/ů|kgnƒŒŠ’“އ…ƒ…’”••š›œ ©®­£›š–ˆxy}Œ‘˜Ÿ ž•€Œ ‹‘£¦§¬±³´·¹·°˜ŠwaYanqv„°ÄÃÂÂÆºŸ`iZPfÅËÆ¼³³¢ykhl{€€…‹Œ‰…ƒƒ†‹Ž‘”••›œœ ª®­£›š–‰yzŒ‘˜Ÿ ž•Œ‹Œ”¥¨©®³´³²³°§Š}|n`\bjmq|ž­®·ÀƺS;Iy¥³¯¨Ÿ¢«‡ ©œ‘¦¸¿´”vnqx~~€€‚ „†‰ˆ‹ŽŒ‹Œ‰…€ƒ0‚‡‰Š‹’—›—Ž‘˜¬³´¬§¥¨°¹¼»»ºº¹µ´³±­­«©§§¨¨©¨¨©€¨©©¨¦¥£•”’{xpSGR~¨¶²¥–™¡‡x¶É»gZ[YXX]}€†€Ž€8Œˆ||}€‚†‹ŒŒŽŽ’“••––—•’”›®µ¶³°¯¯®¬­®·¹¹¸¸··´±²°¬«ª©¤€£¤£¥«­­«ª¨¦Ÿ™˜—ˆ‡…‚pjq–¸Ã¸–kktŠwºË»dXYVSTZ‚‡ŽŽ€ ˆzz|€‡ŽG“”•”••–”’•›®´¶´°°¯­«ª­¶¹º¹¸··´²²±­¬«©¤¢¢££¢¦«®®­ª©§¡š™—‹ˆ†ƒrlu–¹Äº”ghpŠ‚»Ë¼”j^_][[_„ƒˆŽƒ€Ž‹Œˆ€|#‚‡ŒŽŽŽ’“•”“”••“•œ®´¶³°°¯­ª©¬µ¸¹€¸ ·µ³²±­­¬ª¥‚£¥ª¬¬«¨§¥ž™˜–Šˆ‡„uqy™¸Ä¹]`hŠ&ˆ½Ë¿{qrrpos‹ŒŽ‘’‘ˆ††…„„ƒ‚€€†‡ˆ‹Ž9”–—”‘’”•—™®²³²±±¯«§¦ª´¸¹¹¸¸·¶µ´²°¯®¬©§§¥££¤¤¥¥¤¢¡Ÿœ™˜—€Œ Љ¤¹Â³{07FŠŒ¿ËÀ¦Œ……ƒ‚„––•€–”‘‘‚~}}{~„††ˆ‹€€IŽŽ–—™”‘•šœŸ­±²±±²°ª¤£¨³¸¹¸¹¹¸·¶µµ±°°¯¬ªª§¥¤¢ Ÿžžœœ›™——–‘”Ÿ¤¯ºÁ®hŠ ÀÌÂ¨Š‰‰††ˆ˜˜—–’‘Œƒ}~{yy}„†‡‰‹€Ž€ŽŽ–——“Ž‘•š¡­±²€±!¯©£¢¦³·¸¸¹º¹¸¶µ´²±°¯­«ª¨¥¤¡žœœ››š€™ ˜“’“—¢¦«³»Â°fºÅ½ª˜’‰†…‡—˜—–••’ŽŒŠˆ€€}||†ˆ‰Š€Ž€‘’”––“‘•š› ¬°±1¯©£¢¦³··¸¹º¹¸·¶µ³²±±­¬«¨¦¥£ŸŸž›–”“‹‰Š‹Œ“§®±²µº«eo„¬µ²­ª§ ‡…‡”•“‘Ž‹ƒ€}|}~ƒŠŒŽ”••“ŽŽ’“•šª¯°²²³±ª£¢§°´´µº»º¹¸·¶µ´²³¯®®¬ª«©¢ ŸšŠ„‚uiehvy~Š®»½²ª«ž_„ª³°¯°®¥†…ˆ•–”’ŽŠ€}€|W{|‚‚…‹ŽŽŽ–——–ŽŽ‘’”™ª¯°±²³±ª££§°´´µº»»¹¸¸·µ´³³±¯¯­«¬ª¢ Ÿ™‡}n_[`rv{‡²ÀÁ³§§ša„§¬ª®³²©ˆ†ˆ“”’Œ‡€|{|{||‚ƒ…ŒŽ€ƒF—˜˜–ŽŽ““”š©®°°±²°©£¡¥°³´µº»»¹¸¸·µ´´³±°¯­¬«©¢ ž˜†~|n^Z_sw|‰µÄų  –d |™š•¤·¹¯•‹‰ˆ‡…ƒ|{yz}~„…‡ŒŽ€H—™™–Ž‘“——œª®°°±²°©¢¡¥­°±³¼½¼»¹¹¸µ´´³±°¯®­¬©£ Ÿ™‡€~p`]ay}‚ޏÇæ‰‡‚[ 5G1@ŠÃÑĤš–Žuo€poo€s v€„„‡ˆˆ‰‘‘€€‘ šœ›™ŽŽ’™¢¤§­°¯¯°°®§  ¢¨©«¯¼¾½€¼"º·µ´³±¯¯­««¨ ž™ŽŠ‡yjfl‡’ÃÒÄ})%‘‚ÍÜÍ«¡›‘ibdegfhoppt‚ˆ‡ˆ‰ŠŒ€€‘C’šœ™Ž’œ§¨ª¯±°°¯®­¦ŸŸ ¥¥§¬¼¿¾¾½¾»·µµ´±°¯®­¬© œ˜‘Ž‹|mio”š¤ÈÖÄm•ˆÈÕÇ®¥Ÿ–jdfhhfirttv„ˆˆ‰Š‹ŒŽ‚‘‘’“™œ›˜Œ‹’›¦¨ª®°.¯®§  ¡¤¥§«½¿¾¾½¾»¸¶µ´±¯¯­««¨Ÿœ›˜Œ‰{njp‘™ž§Âνp•€³¿º´³¯¡d\]^^Yax}~ˆ‹Š‹€ŽŒ’ƒ—?”‹ˆˆ‹›¦¨«°³´²±±¯©¤¢¢¡ ¡¦º¼»¼¾¾½º¹¸¶°­­«¨¨¤š˜–Šˆ~spw ¬®®¯³¤c•u©«½Ã¿­[QSSRMZ}†ˆˆ€ŽŒŠŒ”›œ–”“‡……ˆ‹Œš¦¨«²µ¶€µ ³­¨¥¥œ¡·ºº¼€¿¼¼»¸°¬«¨¦¦¡›˜–•Šˆ‡€yv~°½¾¶Ÿ™‹V”x¦©ÂÈİUJNOMHY‰‹‹€‘’‘ŽŽŒ‹Š‹”œž–“’‡„„ˆ‹Œš§ª«´µ¶€µ ³®©¦¥›œ¡·»º¼€¿€½¸°«ª¨¥¥¡š—–“Ї‡€xu~³Áºœ•‡Y”pŒ’ºÆÆ¶tlldZUb€ˆŠ‰Ž€P‘ŒŒŒŽ•œž–“’‘ˆ††‰‹‹š§©«´¶··¶·¶°ª¨¥Ÿ›œ¡²µµº¾¿¾¼»º·¯«ª¦¡¡™—–•ŽŽŒŠ‰¶À¿²ƒzoL•T/97T«ÃÈݯªwnu„ˆˆ‡‰‰Š‘ŽŠ‰Š‹’””˜ž’‰ˆˆŠŠ‹š§©¬´·¸¹ºº¸³®«§ œ›žª«­´½¿½º¹¸µ¬¨§¡›š•——œ¥®²²¼¿¹> ˜ <®ÄÌÉÅÆ¾ uz†€‡ˆ‰‰Œ‘‰ˆˆŠ“––™ž’ŽŠŠ‰€‹5Žš§©«µ¸¹º»»¹´°­ª œœž§§©²¼¿¼¹·¶´«©§ ™˜—–••˜š› ­»¿À¿Áºž+›a@®ÁÅÄËÍä„{‡ˆ‡‡ˆ‰ˆ‹ˆ‡ˆŠ”——™žœ’ŽŠ‰‰‹ŒŒš§©«µ¸¹º»¼º´°­ª œœž¤¤§²¼¿½¸¶µ²«¨¦Ÿ˜——•–—˜Ÿ£°¾Äùº²š,› G¥°®­Ç̪€ˆ€†Q‰ŠˆŒ‘‘‰ˆˆŠ•˜˜™™›™Ž‹ŠŠŒ‘œ¨ª­´·¸¹º»¹´°­ªŸ››œ  £¯»½»·µ´±©¦¤ž™—˜”••™£§ª´¿ÄÀŸ›™‰-œ#JA=WÁÍÆ½´±¥ˆ|~‡Š‰‹ŒŒŠ‹Ž–š˜˜—––ŽŽ€Ž8’“•Ÿ¬®®³´µ¶··¶²®¬¨œ—–—““—¦´¸¶²±°­¦¢ ›–•““‘“³¿¿¾¾Á´G*)- YÂÐËÈÅų‰|x{‡ŒŠ‹‹Ž—œš–”““ŒŒ‹‘“•–˜¢®¯¯²³´µ¶·µ²®¬¨›–•”Ž“£²·´±°®«£ŸŸš••“Ž’ž¼ËÉÅÁÄ´ £ 6¼Á½¾Áij…ƒˆ€‰:Š‰ŠŽŽ—š™–’’‘‹ŠŠ‹Œ‘’’• ­®­±°±³¶µµ°­«§š–•”Љޠ±µ³±±¯¬£Ÿžš€– ——š£¼Éƺ¯±¨$£+Œ„€Ÿ¾È¼©¢ž™†}}vqmw”••˜™–’…‚ƒƒ€€…ˆˆŒ™©ª€©¨¬€¯«¨¦£–’Œuqy¦¬¬­¯®ªž™€˜ —ž¬±´·¿Æ»”mjl¥U¼ÌÇÁÁ½¯ƒoodXPc˜›™™˜—ˆˆ‡~}}{vtuy}}‘¤¦¤£¡¡¥©ª¨¥¢Ÿ’…]Xb€¤¥ª®­¨˜’”•——¥ÁÌÏÌÅınªQ„ÁÐÌËÊŵji]PG^œŸœš˜–‰ˆˆ~}}{usuy||€¥¥£¡ Ÿ¤§©§¤¡žœ’„YT_~œ¤¥­°®¨™‘“–——¨ÈÔÖÓÉÆµlªR‹¼ÂÁÇÉÅ·‡ssgZTfœŸ™˜–‰ˆ‡|zyysrswzz}Ž££¢ŸŸž£§¨§£¡Ÿ„[V`~™ ¢ª­¬¨œ——š«ÈÓÔϹµ©n«Q%=#V­ÃÉÄ·³°¤˜“”––“‘Œ‰‡{yw`\[[TSS[baf›œ™”’’›¡£¡ ž—ˆƒ{SNUfwz€”—›­´µº¿ÂÂÄÆ½£F%®K;­ÄÌÉÅÄÁµ¨¤ —“‘Šˆ‡€yyv]XWVPNPW]]a{™š—’˜Ÿ¡ žœ—…€xSOTcpqxŠŽ‘™²½¾ÄÊÍÊÄļž'±K@­ÂÅÃÅÇø­ª¥™•“’‹‰‡€yxu]XWWPOOW^\az˜™–‘—Ÿ¡¡žœ›—ƒ€~xTPVcoqx‹“›µÁÂÆÊÎɽ½µœ(±KG¥°®¬¸À½¸´³­¡žœ˜ŒŠ€tsq\XWVQPPX^]az—˜•Ž‹‹•žž›š”yxsWSYgtw~”™œ£ºÆÄÂÂĺ¡ŸŠ+²IJ@?Q‘ª«»ÍÒȸ²¯©—‹v`[ZLJJKMMOV^]awŒ€||‡‘”““”’‰ia_`WV\p„ާ®²·ÊÕ馣‰@+*.¶C0‹§©ÀØßÔÁ»¶¯š‘‹sYSTGEFHJKMU^\av‹~yy…’‘‘“‡cZWYVV]qƒˆ“­¶ºÀÔÞ×»Ÿœ} ¹,†šš°ÆËƼº¸±¡™“|d^_R€QTSV[`aey’‘‹~xx…Ž’‘’“ˆja_€agy‹˜¯¶¹¼ÂÈÁ©Žu¹Cfnhr}yˆ©³µ³±¯¬žŒŒ}zokjmnmqŠ|vu„“’ŽŒˆ‡‡ˆœ§©«¯°­¢€rtf[^Rº5;—­µ·ÂÇÆÂ¼¼º²¯«¤Š‚€}xxyƒŽ‰ztt„”’‡ˆ¦«®°ºº»¿Âý°­¥/‚Á5(š±·»ÊÑÐÎÍÌËÀ¾º¯†‚€{z|„ŽŽˆxrqƒ”’Œ…‡­¶º¾ÉËËÌÍÎÆ´°§ŒÇ5;™§¬¬¸¾¼»º·¶º»¸¯•‰†‚ƒŠ“’€{{‰•™˜’Ž•®¶¸¸³µ·¸º»³¤ œˆ(Ç5'uzupwywupkq¬¹»¶ª¦¤¡žŸ£¨¨¤œ˜˜¢ª¬«ª¨©«³·´¦kflqrurfgh^Ó žµ¾¿ÄÆÇ¿¾¾¿¾½½¿ÀÀÁÄÈÉź¸¯’ߦ¼ÂÃÊÍÍÊÆÅÄÄÃÃÄÄÅÆÇÊÏÏ˾¼³›ßµÆËÍÓÖÖÓÏÎÍÎÎÍÍÌÌÍÍÏÏÐÔØÙÔÇľ§ÿÿÿÿÿ¤t8mk@   !$%&&&&&&&&&&&&&&&&&&&&&&&&&&%$!  $.6=ACDDDDDDDDDDDDDDDDDDDDDDDDDDCA=6.$  ;”æÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿë¥T.    )N¡éÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿïµmG7)    +2:BNoµîÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿóÉn\NB:0!  5v“ž¤ª°ÁàøÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿúëÒ¸°ªŸˆL'  Y»ßëíîðóùþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþûöóòðîåÉv=-  &2pÔöÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿøà‘WD3&  .;CKUa“ßøÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿúê²…rbUK>(  :y›¡¨®µÎñüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýöÞɾµ®¨‹Q2  -]½êìíïñõüþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþýùõóñïíËzL1!  /K{×ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿãœpQ=&  #Ld¥äÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿïÁ¡‡mA$  K¦ÊÚæøÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿûïæØ¼m6$  "cÉì÷úþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþüúóÚ‹L6#  -?}Ù÷ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿúè¥mS:"  <_u¥åúÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüðÇŸ…_9"  9‹Óëòüþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþý÷òá§]3"  !J¢êÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿò¿vI3"  7Ir¸ïÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿöÒœu]8!  ;‹¢¸ÞøÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿûìÒ¾§_:"  .^Óêïøþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþûöòá…S3#  #?uëÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿòŸkJ4$ #Kc~¥òÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ÷Ƥ‡mA&  K¦ÈÙåüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýðçÙ¼m?$  /dÉë÷úþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþüúóÚŠW6$  -K~Ú÷ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿúè¥vS:"  :\|¤æúÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüðÆ¤…_8!  .y¼×äøþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþûðæÓœY2! <šèþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿò¾tH3#  C¡ìÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿöÑšt]@# L§íÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿûìÒ¾§v8!  &V®ïÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþûöòá¦Q. 2bµñÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿñºa;$4Xo“ÎõÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿôÃpE+  !vºÓßðüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿöÊzM0 +“Þõøüþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ÷΀S3  2žëÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ÷Ñ„V5  8£ìÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿøÒ‡Y8 =¦îÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿøÔ‹^=# ?¨îÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿø×’gF+  @ªïÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿúà©„h7"C«ïÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüïÕ²H.$I®ðÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþûöòî[=%  -R³ñÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿnK/  =PsÃóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ}X7ÊÐÙïüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ‰a=" 'òô÷ûþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ‘gA% 1ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ•jD&9ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ—lD'">ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ—lE'$Aÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ—lE'%Cÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ—lE'&Dÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ—lE'&Dÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ—lE'&Dÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ—lE'&Dÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ—lE'&Dÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ—lE'&Dÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ—lE'&Dÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ—lE'&Dÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ—lE'&Dÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ—lE'&Dÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ—lE'&Dÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ—lE'&Dÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ—lE'&Dÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ—lE'&Dÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ—lE'&Dÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ—lE'&Dÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ—lE'&Dÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ—lE'&Dÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ—lE'%Cÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ—lE'$Aÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ—lE'">ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ—lE'9õ÷ùýþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ—lD' 1ÔÛåõýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ•jD& 'Ys–Õ÷ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ‘gA%2LsÄôÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ‰a=" $:`ºòÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþýúöó}X7 -R³ñÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýõåÕÆmK/ $I®ðÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿûêÃ¥‰Y=% C«ïÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿúà«…eG. @ªïÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùÛœsS7" ?¨îÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿøÕdD*  =¦îÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ÷Ï‚W9! 8žäøúýþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþýûñÄuL/  0‡ÈßéöýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþûôíÞ¯f@'  Lu²ÝùÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüïÖ¼¤}P4 'ŠÊâîûþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþý÷ðá³rE+ (QxœÁïüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýøàƪ„W8# 1Lp¡æúÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüòɤbB+  0Q†Øóúüþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþýüøé²…bH1  !LÏêóõö÷øøøùúþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþüúùùøøø÷öðÝ¢s^L>3*!  &2Z–±¿ÇÍÐÒÓÕØà÷ýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþûëâÜØÕÓÒÐÍİ}VC2&  /FXht}‚…ˆ”¬ëûÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüóȰ ”ˆ…‚}tfP<,  &4@JQTW[`jˆâùÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿû몋xj`[WTQJ@3&  &,1469?IkÚ÷ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùäŽkXI?9641,&  $-;N`sŒ“–——————————————————–“Œs_L:-$  $1@O[cikllllllllllllllllllkic[O@1$  '1:?CEEEEEEEEEEEEEEEEEEEEC?:1'  "%%&&&&&&&&&&&&&&&&&&%%"   freewheeling-0.6.6/MacOSX/fweelin.xcodeproj/000077500000000000000000000000001370736313100207125ustar00rootroot00000000000000freewheeling-0.6.6/MacOSX/fweelin.xcodeproj/mercury.mode1000066400000000000000000001254521370736313100233400ustar00rootroot00000000000000 ActivePerspectiveName Project AllowedModules BundleLoadPath MaxInstances n Module PBXSmartGroupTreeModule Name Groups and Files Outline View BundleLoadPath MaxInstances n Module PBXNavigatorGroup Name Editor BundleLoadPath MaxInstances n Module XCTaskListModule Name Task List BundleLoadPath MaxInstances n Module XCDetailModule Name File and Smart Group Detail Viewer BundleLoadPath MaxInstances 1 Module PBXBuildResultsModule Name Detailed Build Results Viewer BundleLoadPath MaxInstances 1 Module PBXProjectFindModule Name Project Batch Find Tool BundleLoadPath MaxInstances n Module PBXRunSessionModule Name Run Log BundleLoadPath MaxInstances n Module PBXBookmarksModule Name Bookmarks Tool BundleLoadPath MaxInstances n Module PBXClassBrowserModule Name Class Browser BundleLoadPath MaxInstances n Module PBXCVSModule Name Source Code Control Tool BundleLoadPath MaxInstances n Module PBXDebugBreakpointsModule Name Debug Breakpoints Tool BundleLoadPath MaxInstances n Module XCDockableInspector Name Inspector BundleLoadPath MaxInstances n Module PBXOpenQuicklyModule Name Open Quickly Tool BundleLoadPath MaxInstances 1 Module PBXDebugSessionModule Name Debugger BundleLoadPath MaxInstances 1 Module PBXDebugCLIModule Name Debug Console Description DefaultDescriptionKey DockingSystemVisible Extension mode1 FavBarConfig PBXProjectModuleGUID AC5A53140AC098E400622F72 XCBarModuleItemNames XCBarModuleItems FirstTimeWindowDisplayed Identifier com.apple.perspectives.project.mode1 MajorVersion 31 MinorVersion 1 Name Default Notifications OpenEditors PerspectiveWidths -1 -1 Perspectives ChosenToolbarItems active-target-popup action NSToolbarFlexibleSpaceItem buildOrClean build-and-runOrDebug com.apple.ide.PBXToolbarStopButton get-info toggle-editor NSToolbarFlexibleSpaceItem com.apple.pbx.toolbar.searchfield ControllerClassBaseName IconName WindowOfProjectWithEditor Identifier perspective.project IsVertical Layout ContentConfiguration PBXBottomSmartGroupGIDs 1C37FBAC04509CD000000102 1C37FAAC04509CD000000102 1C08E77C0454961000C914BD 1C37FABC05509CD000000102 1C37FABC05539CD112110102 E2644B35053B69B200211256 1C37FABC04509CD000100104 1CC0EA4004350EF90044410B 1CC0EA4004350EF90041110B PBXProjectModuleGUID 1CE0B1FE06471DED0097A5F4 PBXProjectModuleLabel Files PBXProjectStructureProvided yes PBXSmartGroupTreeModuleColumnData PBXSmartGroupTreeModuleColumnWidthsKey 285 PBXSmartGroupTreeModuleColumnsKey_v4 MainColumn PBXSmartGroupTreeModuleOutlineStateKey_v7 PBXSmartGroupTreeModuleOutlineStateExpansionKey 29B97314FDCFA39411CA2CEA 080E96DDFE201D6D7F000001 29B97315FDCFA39411CA2CEA 29B97317FDCFA39411CA2CEA 29B97323FDCFA39411CA2CEA 1058C7A0FEA54F0111CA2CBB AC5A53270AC099C900622F72 19C28FACFE9D520D11CA2CBB 8D1107320486CEB800E47090 1C37FBAC04509CD000000102 1C37FABC05509CD000000102 PBXSmartGroupTreeModuleOutlineStateSelectionKey 17 1 0 PBXSmartGroupTreeModuleOutlineStateVisibleRectKey {{0, 0}, {285, 629}} PBXTopSmartGroupGIDs XCIncludePerspectivesSwitch XCSharingToken com.apple.Xcode.GFSharingToken GeometryConfiguration Frame {{0, 0}, {302, 647}} GroupTreeTableConfiguration MainColumn 285 RubberWindowFrame 140 149 979 688 0 0 1440 878 Module PBXSmartGroupTreeModule Proportion 302pt Dock BecomeActive ContentConfiguration PBXProjectModuleGUID 1CE0B20306471E060097A5F4 PBXProjectModuleLabel fweelin_event.h PBXSplitModuleInNavigatorKey Split0 PBXProjectModuleGUID 1CE0B20406471E060097A5F4 PBXProjectModuleLabel fweelin_event.h _historyCapacity 0 bookmark AC19AECE0B77E57400AEC16F history AC5A56880AC2419A00622F72 AC12676A0AC8E0C600FE916E AC126C790AC8F26100FE916E ACE0E9A30ACA1CC1007E3ED2 AC6427D80AD883FA00752A08 AC6427E70AD884EE00752A08 AC642A1E0ADB317200752A08 ACA2C5D60B06E0F700E02DC6 ACA2C6CD0B06EC6700E02DC6 ACA2C7CF0B07C82F00E02DC6 ACA2C81F0B0830F900E02DC6 ACA2CB8A0B0AC86600E02DC6 ACA2CB8C0B0AC86600E02DC6 ACA2CB8D0B0AC86600E02DC6 ACA2CB9E0B0AC89600E02DC6 ACA2CE0D0B10369800E02DC6 ACF2F7A10B4C70B2005197BB ACABFD0E0B6178C500CA3C21 ACABFDBC0B61895200CA3C21 ACABFDF70B61D7DB00CA3C21 ACABFE190B61E19100CA3C21 ACABFE3E0B61E39100CA3C21 ACF227730B6826DC005CFC14 ACF227B50B682D68005CFC14 ACF227B70B682D68005CFC14 ACF227F10B689BAA005CFC14 ACF227F20B689BAA005CFC14 AC776D5F0B69B290005E3D84 AC776D600B69B290005E3D84 AC2AECD60B6AD6CE00AFA3A9 AC2AECD90B6AD6CE00AFA3A9 AC2080220B6EDC4A002A78E8 AC2080240B6EDC4A002A78E8 AC20802E0B6F09C5002A78E8 ACBF6FEF0B7326D6004A69E7 AC19AEB60B77E01400AEC16F AC19AEC20B77E09D00AEC16F AC19AEC30B77E09D00AEC16F AC19AECB0B77E57400AEC16F AC19AECC0B77E57400AEC16F prevStack AC5A54D30AC0EA0200622F72 AC5A54E90AC0EA8500622F72 AC5A54EA0AC0EA8500622F72 AC5A54EB0AC0EA8500622F72 AC5A54EC0AC0EA8500622F72 AC5A55D80AC2198F00622F72 AC5A55D90AC2198F00622F72 AC5A568E0AC2419A00622F72 AC5A56900AC2419A00622F72 AC5A56980AC2419A00622F72 AC5A569A0AC2419A00622F72 AC5A569C0AC2419A00622F72 AC5A569D0AC2419A00622F72 AC5A569E0AC2419A00622F72 AC5A56FE0AC2448600622F72 AC5A57660AC250C200622F72 AC1267750AC8E0C600FE916E AC1267760AC8E0C600FE916E AC12677A0AC8E0C600FE916E AC12677B0AC8E0C600FE916E AC126BEC0AC8E94900FE916E AC126C5A0AC8F08000FE916E AC126C5B0AC8F08000FE916E AC126C5C0AC8F08000FE916E AC126C930AC8F36000FE916E ACFC0AB00AC99E2E00DAC478 ACFC0AB10AC99E2E00DAC478 ACFC0B910AC9A70300DAC478 ACE0E72E0AC9CF47007E3ED2 ACE0E94B0ACA196D007E3ED2 AC642A270ADB317200752A08 AC642A280ADB317200752A08 ACA2C5D90B06E0F700E02DC6 ACA2CE0E0B10369800E02DC6 AC776D620B69B290005E3D84 AC776D640B69B290005E3D84 AC776D650B69B290005E3D84 AC2080280B6EDC4A002A78E8 AC20802A0B6EDC4A002A78E8 AC19AEB80B77E01400AEC16F AC19AEB90B77E01400AEC16F AC19AEC50B77E09D00AEC16F AC19AEC60B77E09D00AEC16F AC19AEC70B77E09D00AEC16F AC19AECD0B77E57400AEC16F SplitCount 1 StatusBarVisibility GeometryConfiguration Frame {{0, 0}, {672, 449}} RubberWindowFrame 140 149 979 688 0 0 1440 878 Module PBXNavigatorGroup Proportion 449pt ContentConfiguration PBXProjectModuleGUID 1CE0B20506471E060097A5F4 PBXProjectModuleLabel Detail GeometryConfiguration Frame {{0, 454}, {672, 193}} RubberWindowFrame 140 149 979 688 0 0 1440 878 Module XCDetailModule Proportion 193pt Proportion 672pt Name Project ServiceClasses XCModuleDock PBXSmartGroupTreeModule XCModuleDock PBXNavigatorGroup XCDetailModule TableOfContents AC19AEBB0B77E01400AEC16F 1CE0B1FE06471DED0097A5F4 AC19AEBC0B77E01400AEC16F 1CE0B20306471E060097A5F4 1CE0B20506471E060097A5F4 ToolbarConfiguration xcode.toolbar.config.default ControllerClassBaseName IconName WindowOfProject Identifier perspective.morph IsVertical 0 Layout BecomeActive 1 ContentConfiguration PBXBottomSmartGroupGIDs 1C37FBAC04509CD000000102 1C37FAAC04509CD000000102 1C08E77C0454961000C914BD 1C37FABC05509CD000000102 1C37FABC05539CD112110102 E2644B35053B69B200211256 1C37FABC04509CD000100104 1CC0EA4004350EF90044410B 1CC0EA4004350EF90041110B PBXProjectModuleGUID 11E0B1FE06471DED0097A5F4 PBXProjectModuleLabel Files PBXProjectStructureProvided yes PBXSmartGroupTreeModuleColumnData PBXSmartGroupTreeModuleColumnWidthsKey 186 PBXSmartGroupTreeModuleColumnsKey_v4 MainColumn PBXSmartGroupTreeModuleOutlineStateKey_v7 PBXSmartGroupTreeModuleOutlineStateExpansionKey 29B97314FDCFA39411CA2CEA 1C37FABC05509CD000000102 PBXSmartGroupTreeModuleOutlineStateSelectionKey 0 PBXSmartGroupTreeModuleOutlineStateVisibleRectKey {{0, 0}, {186, 337}} PBXTopSmartGroupGIDs XCIncludePerspectivesSwitch 1 XCSharingToken com.apple.Xcode.GFSharingToken GeometryConfiguration Frame {{0, 0}, {203, 355}} GroupTreeTableConfiguration MainColumn 186 RubberWindowFrame 373 269 690 397 0 0 1440 878 Module PBXSmartGroupTreeModule Proportion 100% Name Morph PreferredWidth 300 ServiceClasses XCModuleDock PBXSmartGroupTreeModule TableOfContents 11E0B1FE06471DED0097A5F4 ToolbarConfiguration xcode.toolbar.config.default.short PerspectivesBarVisible ShelfIsVisible SourceDescription file at '/System/Library/PrivateFrameworks/DevToolsInterface.framework/Versions/A/Resources/XCPerspectivesSpecificationMode1.xcperspec' StatusbarIsVisible TimeStamp 0.0 ToolbarDisplayMode 1 ToolbarIsVisible ToolbarSizeMode 1 Type Perspectives UpdateMessage The Default Workspace in this version of Xcode now includes support to hide and show the detail view (what has been referred to as the "Metro-Morph" feature). You must discard your current Default Workspace settings and update to the latest Default Workspace in order to gain this feature. Do you wish to update to the latest Workspace defaults for project '%@'? WindowJustification 5 WindowOrderList AC5A53180AC098FB00622F72 1C0AD2B3069F1EA900FABCE6 /Users/mercury/Desktop/port/freewheeling/MacOSX/fweelin.xcodeproj WindowString 140 149 979 688 0 0 1440 878 WindowTools FirstTimeWindowDisplayed Identifier windowTool.build IsVertical Layout Dock ContentConfiguration PBXProjectModuleGUID 1CD0528F0623707200166675 PBXProjectModuleLabel StatusBarVisibility GeometryConfiguration Frame {{0, 0}, {1207, 311}} RubberWindowFrame 286 118 1207 575 0 0 1440 878 Module PBXNavigatorGroup Proportion 311pt ContentConfiguration PBXProjectModuleGUID XCMainBuildResultsModuleGUID PBXProjectModuleLabel Build XCBuildResultsTrigger_Collapse 1021 XCBuildResultsTrigger_Open 1011 GeometryConfiguration Frame {{0, 316}, {1207, 218}} RubberWindowFrame 286 118 1207 575 0 0 1440 878 Module PBXBuildResultsModule Proportion 218pt Proportion 534pt Name Build Results ServiceClasses PBXBuildResultsModule StatusbarIsVisible TableOfContents AC5A53180AC098FB00622F72 AC19AEBD0B77E01400AEC16F 1CD0528F0623707200166675 XCMainBuildResultsModuleGUID ToolbarConfiguration xcode.toolbar.config.build WindowString 286 118 1207 575 0 0 1440 878 WindowToolGUID AC5A53180AC098FB00622F72 WindowToolIsVisible FirstTimeWindowDisplayed Identifier windowTool.debugger IsVertical Layout Dock ContentConfiguration Debugger HorizontalSplitView _collapsingFrameDimension 0.0 _indexOfCollapsedView 0 _percentageOfCollapsedView 0.0 isCollapsed yes sizes {{0, 0}, {247, 190}} {{247, 0}, {447, 190}} VerticalSplitView _collapsingFrameDimension 0.0 _indexOfCollapsedView 0 _percentageOfCollapsedView 0.0 isCollapsed yes sizes {{0, 0}, {694, 190}} {{0, 190}, {694, 191}} LauncherConfigVersion 8 PBXProjectModuleGUID 1C162984064C10D400B95A72 PBXProjectModuleLabel Debug - GLUTExamples (Underwater) GeometryConfiguration DebugConsoleDrawerSize {100, 120} DebugConsoleVisible None DebugConsoleWindowFrame {{200, 200}, {500, 300}} DebugSTDIOWindowFrame {{200, 200}, {500, 300}} Frame {{0, 0}, {694, 381}} RubberWindowFrame 589 261 694 422 0 0 1440 878 Module PBXDebugSessionModule Proportion 381pt Proportion 381pt Name Debugger ServiceClasses PBXDebugSessionModule StatusbarIsVisible TableOfContents 1CD10A99069EF8BA00B06720 ACA2C84D0B08335700E02DC6 1C162984064C10D400B95A72 ACA2C84E0B08335700E02DC6 ACA2C84F0B08335700E02DC6 ACA2C8500B08335700E02DC6 ACA2C8510B08335700E02DC6 ACA2C8520B08335700E02DC6 ACA2C8530B08335700E02DC6 ToolbarConfiguration xcode.toolbar.config.debug WindowString 589 261 694 422 0 0 1440 878 WindowToolGUID 1CD10A99069EF8BA00B06720 WindowToolIsVisible FirstTimeWindowDisplayed Identifier windowTool.find IsVertical Layout Dock Dock ContentConfiguration PBXProjectModuleGUID 1CDD528C0622207200134675 PBXProjectModuleLabel fweelin_core.cc StatusBarVisibility GeometryConfiguration Frame {{0, 0}, {862, 353}} RubberWindowFrame 237 136 862 611 0 0 1440 878 Module PBXNavigatorGroup Proportion 862pt Proportion 353pt BecomeActive ContentConfiguration PBXProjectModuleGUID 1CD0528E0623707200166675 PBXProjectModuleLabel Project Find GeometryConfiguration Frame {{0, 358}, {862, 212}} RubberWindowFrame 237 136 862 611 0 0 1440 878 Module PBXProjectFindModule Proportion 212pt Proportion 570pt Name Project Find ServiceClasses PBXProjectFindModule StatusbarIsVisible TableOfContents 1C530D57069F1CE1000CFCEE ACBF6FDA0B72BFDF004A69E7 ACBF6FDB0B72BFDF004A69E7 1CDD528C0622207200134675 1CD0528E0623707200166675 WindowString 237 136 862 611 0 0 1440 878 WindowToolGUID 1C530D57069F1CE1000CFCEE WindowToolIsVisible Identifier MENUSEPARATOR FirstTimeWindowDisplayed Identifier windowTool.debuggerConsole IsVertical Layout Dock ContentConfiguration PBXProjectModuleGUID 1C78EAAC065D492600B07095 PBXProjectModuleLabel Debugger Console GeometryConfiguration Frame {{0, 0}, {440, 358}} RubberWindowFrame 196 389 440 400 0 0 1440 878 Module PBXDebugCLIModule Proportion 358pt Proportion 359pt Name Debugger Console ServiceClasses PBXDebugCLIModule StatusbarIsVisible TableOfContents AC126BC70AC8E7D700FE916E ACA2C6770B06E8E600E02DC6 1C78EAAC065D492600B07095 WindowString 196 389 440 400 0 0 1440 878 WindowToolGUID AC126BC70AC8E7D700FE916E WindowToolIsVisible FirstTimeWindowDisplayed Identifier windowTool.run IsVertical Layout Dock ContentConfiguration LauncherConfigVersion 3 PBXProjectModuleGUID 1CD0528B0623707200166675 PBXProjectModuleLabel Run Runner HorizontalSplitView _collapsingFrameDimension 0.0 _indexOfCollapsedView 0 _percentageOfCollapsedView 0.0 isCollapsed yes sizes {{0, 0}, {366, 168}} {{0, 173}, {366, 270}} VerticalSplitView _collapsingFrameDimension 0.0 _indexOfCollapsedView 0 _percentageOfCollapsedView 0.0 isCollapsed yes sizes {{0, 0}, {406, 443}} {{411, 0}, {517, 443}} GeometryConfiguration Frame {{0, 0}, {527, 170}} RubberWindowFrame 889 183 527 211 0 0 1440 878 Module PBXRunSessionModule Proportion 170pt Proportion 170pt Name Run Log ServiceClasses PBXRunSessionModule StatusbarIsVisible TableOfContents 1C0AD2B3069F1EA900FABCE6 AC19AEBE0B77E01400AEC16F 1CD0528B0623707200166675 AC19AEBF0B77E01400AEC16F ToolbarConfiguration xcode.toolbar.config.run WindowString 889 183 527 211 0 0 1440 878 WindowToolGUID 1C0AD2B3069F1EA900FABCE6 WindowToolIsVisible Identifier windowTool.scm Layout Dock ContentConfiguration PBXProjectModuleGUID 1C78EAB2065D492600B07095 PBXProjectModuleLabel <No Editor> PBXSplitModuleInNavigatorKey Split0 PBXProjectModuleGUID 1C78EAB3065D492600B07095 SplitCount 1 StatusBarVisibility 1 GeometryConfiguration Frame {{0, 0}, {452, 0}} RubberWindowFrame 743 379 452 308 0 0 1280 1002 Module PBXNavigatorGroup Proportion 0pt BecomeActive 1 ContentConfiguration PBXProjectModuleGUID 1CD052920623707200166675 PBXProjectModuleLabel SCM GeometryConfiguration ConsoleFrame {{0, 259}, {452, 0}} Frame {{0, 7}, {452, 259}} RubberWindowFrame 743 379 452 308 0 0 1280 1002 TableConfiguration Status 30 FileName 199 Path 197.09500122070312 TableFrame {{0, 0}, {452, 250}} Module PBXCVSModule Proportion 262pt Proportion 266pt Name SCM ServiceClasses PBXCVSModule StatusbarIsVisible 1 TableOfContents 1C78EAB4065D492600B07095 1C78EAB5065D492600B07095 1C78EAB2065D492600B07095 1CD052920623707200166675 ToolbarConfiguration xcode.toolbar.config.scm WindowString 743 379 452 308 0 0 1280 1002 Identifier windowTool.breakpoints IsVertical 0 Layout Dock BecomeActive 1 ContentConfiguration PBXBottomSmartGroupGIDs 1C77FABC04509CD000000102 PBXProjectModuleGUID 1CE0B1FE06471DED0097A5F4 PBXProjectModuleLabel Files PBXProjectStructureProvided no PBXSmartGroupTreeModuleColumnData PBXSmartGroupTreeModuleColumnWidthsKey 168 PBXSmartGroupTreeModuleColumnsKey_v4 MainColumn PBXSmartGroupTreeModuleOutlineStateKey_v7 PBXSmartGroupTreeModuleOutlineStateExpansionKey 1C77FABC04509CD000000102 PBXSmartGroupTreeModuleOutlineStateSelectionKey 0 PBXSmartGroupTreeModuleOutlineStateVisibleRectKey {{0, 0}, {168, 350}} PBXTopSmartGroupGIDs XCIncludePerspectivesSwitch 0 GeometryConfiguration Frame {{0, 0}, {185, 368}} GroupTreeTableConfiguration MainColumn 168 RubberWindowFrame 315 424 744 409 0 0 1440 878 Module PBXSmartGroupTreeModule Proportion 185pt ContentConfiguration PBXProjectModuleGUID 1CA1AED706398EBD00589147 PBXProjectModuleLabel Detail GeometryConfiguration Frame {{190, 0}, {554, 368}} RubberWindowFrame 315 424 744 409 0 0 1440 878 Module XCDetailModule Proportion 554pt Proportion 368pt MajorVersion 2 MinorVersion 0 Name Breakpoints ServiceClasses PBXSmartGroupTreeModule XCDetailModule StatusbarIsVisible 1 TableOfContents 1CDDB66807F98D9800BB5817 1CDDB66907F98D9800BB5817 1CE0B1FE06471DED0097A5F4 1CA1AED706398EBD00589147 ToolbarConfiguration xcode.toolbar.config.breakpoints WindowString 315 424 744 409 0 0 1440 878 WindowToolGUID 1CDDB66807F98D9800BB5817 WindowToolIsVisible 1 Identifier windowTool.debugAnimator Layout Dock Module PBXNavigatorGroup Proportion 100% Proportion 100% Name Debug Visualizer ServiceClasses PBXNavigatorGroup StatusbarIsVisible 1 ToolbarConfiguration xcode.toolbar.config.debugAnimator WindowString 100 100 700 500 0 0 1280 1002 Identifier windowTool.bookmarks Layout Dock Module PBXBookmarksModule Proportion 100% Proportion 100% Name Bookmarks ServiceClasses PBXBookmarksModule StatusbarIsVisible 0 WindowString 538 42 401 187 0 0 1280 1002 Identifier windowTool.classBrowser Layout Dock BecomeActive 1 ContentConfiguration OptionsSetName Hierarchy, all classes PBXProjectModuleGUID 1CA6456E063B45B4001379D8 PBXProjectModuleLabel Class Browser - NSObject GeometryConfiguration ClassesFrame {{0, 0}, {374, 96}} ClassesTreeTableConfiguration PBXClassNameColumnIdentifier 208 PBXClassBookColumnIdentifier 22 Frame {{0, 0}, {630, 331}} MembersFrame {{0, 105}, {374, 395}} MembersTreeTableConfiguration PBXMemberTypeIconColumnIdentifier 22 PBXMemberNameColumnIdentifier 216 PBXMemberTypeColumnIdentifier 97 PBXMemberBookColumnIdentifier 22 PBXModuleWindowStatusBarHidden2 1 RubberWindowFrame 385 179 630 352 0 0 1440 878 Module PBXClassBrowserModule Proportion 332pt Proportion 332pt Name Class Browser ServiceClasses PBXClassBrowserModule StatusbarIsVisible 0 TableOfContents 1C0AD2AF069F1E9B00FABCE6 1C0AD2B0069F1E9B00FABCE6 1CA6456E063B45B4001379D8 ToolbarConfiguration xcode.toolbar.config.classbrowser WindowString 385 179 630 352 0 0 1440 878 WindowToolGUID 1C0AD2AF069F1E9B00FABCE6 WindowToolIsVisible 0 freewheeling-0.6.6/MacOSX/fweelin.xcodeproj/mercury.pbxuser000066400000000000000000001276171370736313100240300ustar00rootroot00000000000000// !$*UTF8*$! { 002F3A2B09D0888800EBEB88 /* SDLMain.h */ = { uiCtxt = { sepNavIntBoundsRect = "{{0, 0}, {631, 417}}"; sepNavSelRange = "{486, 0}"; sepNavVisRect = "{{0, 0}, {631, 417}}"; }; }; 002F3A2C09D0888800EBEB88 /* SDLMain.mm */ = { uiCtxt = { sepNavIntBoundsRect = "{{0, 0}, {818, 6230}}"; sepNavSelRange = "{10608, 7}"; sepNavVisRect = "{{0, 5293}, {740, 180}}"; }; }; 089C165DFE840E0CC02AAC07 /* English */ = { uiCtxt = { sepNavIntBoundsRect = "{{0, 0}, {1092, 611}}"; sepNavSelRange = "{76, 0}"; sepNavVisRect = "{{0, 0}, {1092, 611}}"; sepNavWindowFrame = "{{73, 112}, {1131, 740}}"; }; }; 29B97313FDCFA39411CA2CEA /* Project object */ = { activeBuildConfigurationName = Release; activeExecutable = AC5A53070AC098E000622F72 /* fweelin */; activeTarget = 8D1107260486CEB800E47090 /* fweelin */; addToTargets = ( 8D1107260486CEB800E47090 /* fweelin */, ); breakpoints = ( ); breakpointsGroup = AC5A531F0AC0998E00622F72 /* XCBreakpointsBucket */; codeSenseManager = AC5A53160AC098E400622F72 /* Code sense */; executables = ( AC5A53070AC098E000622F72 /* fweelin */, ); perUserDictionary = { PBXConfiguration.PBXFileTableDataSource3.PBXFileTableDataSource = { PBXFileTableDataSourceColumnSortingDirectionKey = "-1"; PBXFileTableDataSourceColumnSortingKey = PBXFileDataSource_Filename_ColumnID; PBXFileTableDataSourceColumnWidthsKey = ( 20, 433, 20, 48, 43, 43, 20, ); PBXFileTableDataSourceColumnsKey = ( PBXFileDataSource_FiletypeID, PBXFileDataSource_Filename_ColumnID, PBXFileDataSource_Built_ColumnID, PBXFileDataSource_ObjectSize_ColumnID, PBXFileDataSource_Errors_ColumnID, PBXFileDataSource_Warnings_ColumnID, PBXFileDataSource_Target_ColumnID, ); }; PBXConfiguration.PBXTargetDataSource.PBXTargetDataSource = { PBXFileTableDataSourceColumnSortingDirectionKey = "-1"; PBXFileTableDataSourceColumnSortingKey = PBXFileDataSource_Filename_ColumnID; PBXFileTableDataSourceColumnWidthsKey = ( 20, 200, 253, 20, 48, 43, 43, ); PBXFileTableDataSourceColumnsKey = ( PBXFileDataSource_FiletypeID, PBXFileDataSource_Filename_ColumnID, PBXTargetDataSource_PrimaryAttribute, PBXFileDataSource_Built_ColumnID, PBXFileDataSource_ObjectSize_ColumnID, PBXFileDataSource_Errors_ColumnID, PBXFileDataSource_Warnings_ColumnID, ); }; PBXPerProjectTemplateStateSaveDate = 192405221; PBXWorkspaceStateSaveDate = 192405221; }; perUserProjectItems = { AC12676A0AC8E0C600FE916E = AC12676A0AC8E0C600FE916E /* PBXTextBookmark */; AC1267750AC8E0C600FE916E = AC1267750AC8E0C600FE916E /* PBXTextBookmark */; AC1267760AC8E0C600FE916E = AC1267760AC8E0C600FE916E /* PBXTextBookmark */; AC12677A0AC8E0C600FE916E = AC12677A0AC8E0C600FE916E /* PBXTextBookmark */; AC12677B0AC8E0C600FE916E = AC12677B0AC8E0C600FE916E /* PBXTextBookmark */; AC126BEC0AC8E94900FE916E = AC126BEC0AC8E94900FE916E /* PBXTextBookmark */; AC126C5A0AC8F08000FE916E = AC126C5A0AC8F08000FE916E /* PBXTextBookmark */; AC126C5B0AC8F08000FE916E = AC126C5B0AC8F08000FE916E /* PBXTextBookmark */; AC126C5C0AC8F08000FE916E = AC126C5C0AC8F08000FE916E /* PBXTextBookmark */; AC126C790AC8F26100FE916E = AC126C790AC8F26100FE916E /* PBXTextBookmark */; AC126C930AC8F36000FE916E = AC126C930AC8F36000FE916E /* PBXTextBookmark */; AC19AEB60B77E01400AEC16F /* PBXTextBookmark */ = AC19AEB60B77E01400AEC16F /* PBXTextBookmark */; AC19AEB70B77E01400AEC16F /* PBXTextBookmark */ = AC19AEB70B77E01400AEC16F /* PBXTextBookmark */; AC19AEB80B77E01400AEC16F /* PBXTextBookmark */ = AC19AEB80B77E01400AEC16F /* PBXTextBookmark */; AC19AEB90B77E01400AEC16F /* PBXTextBookmark */ = AC19AEB90B77E01400AEC16F /* PBXTextBookmark */; AC19AEBA0B77E01400AEC16F /* PBXTextBookmark */ = AC19AEBA0B77E01400AEC16F /* PBXTextBookmark */; AC19AEC10B77E09D00AEC16F /* PBXTextBookmark */ = AC19AEC10B77E09D00AEC16F /* PBXTextBookmark */; AC19AEC20B77E09D00AEC16F /* PBXTextBookmark */ = AC19AEC20B77E09D00AEC16F /* PBXTextBookmark */; AC19AEC30B77E09D00AEC16F /* PBXTextBookmark */ = AC19AEC30B77E09D00AEC16F /* PBXTextBookmark */; AC19AEC40B77E09D00AEC16F /* PBXTextBookmark */ = AC19AEC40B77E09D00AEC16F /* PBXTextBookmark */; AC19AEC50B77E09D00AEC16F /* PBXTextBookmark */ = AC19AEC50B77E09D00AEC16F /* PBXTextBookmark */; AC19AEC60B77E09D00AEC16F /* PBXTextBookmark */ = AC19AEC60B77E09D00AEC16F /* PBXTextBookmark */; AC19AEC70B77E09D00AEC16F /* PBXTextBookmark */ = AC19AEC70B77E09D00AEC16F /* PBXTextBookmark */; AC19AEC80B77E09D00AEC16F /* PBXTextBookmark */ = AC19AEC80B77E09D00AEC16F /* PBXTextBookmark */; AC19AECB0B77E57400AEC16F /* PBXTextBookmark */ = AC19AECB0B77E57400AEC16F /* PBXTextBookmark */; AC19AECC0B77E57400AEC16F /* PBXTextBookmark */ = AC19AECC0B77E57400AEC16F /* PBXTextBookmark */; AC19AECD0B77E57400AEC16F /* PBXTextBookmark */ = AC19AECD0B77E57400AEC16F /* PBXTextBookmark */; AC19AECE0B77E57400AEC16F /* PBXTextBookmark */ = AC19AECE0B77E57400AEC16F /* PBXTextBookmark */; AC2080220B6EDC4A002A78E8 = AC2080220B6EDC4A002A78E8 /* PBXTextBookmark */; AC2080240B6EDC4A002A78E8 = AC2080240B6EDC4A002A78E8 /* PBXTextBookmark */; AC2080280B6EDC4A002A78E8 = AC2080280B6EDC4A002A78E8 /* PBXTextBookmark */; AC20802A0B6EDC4A002A78E8 = AC20802A0B6EDC4A002A78E8 /* PBXTextBookmark */; AC20802E0B6F09C5002A78E8 = AC20802E0B6F09C5002A78E8 /* PBXTextBookmark */; AC2AECD60B6AD6CE00AFA3A9 = AC2AECD60B6AD6CE00AFA3A9 /* PBXTextBookmark */; AC2AECD90B6AD6CE00AFA3A9 = AC2AECD90B6AD6CE00AFA3A9 /* PBXTextBookmark */; AC2AECDA0B6AD6CE00AFA3A9 = AC2AECDA0B6AD6CE00AFA3A9 /* PBXTextBookmark */; AC5A54D30AC0EA0200622F72 = AC5A54D30AC0EA0200622F72 /* PBXTextBookmark */; AC5A54E90AC0EA8500622F72 = AC5A54E90AC0EA8500622F72 /* PBXTextBookmark */; AC5A54EA0AC0EA8500622F72 = AC5A54EA0AC0EA8500622F72 /* PBXTextBookmark */; AC5A54EB0AC0EA8500622F72 = AC5A54EB0AC0EA8500622F72 /* PBXTextBookmark */; AC5A54EC0AC0EA8500622F72 = AC5A54EC0AC0EA8500622F72 /* PBXTextBookmark */; AC5A55D80AC2198F00622F72 = AC5A55D80AC2198F00622F72 /* PBXTextBookmark */; AC5A55D90AC2198F00622F72 = AC5A55D90AC2198F00622F72 /* PBXTextBookmark */; AC5A56880AC2419A00622F72 = AC5A56880AC2419A00622F72 /* PBXTextBookmark */; AC5A568E0AC2419A00622F72 = AC5A568E0AC2419A00622F72 /* PBXTextBookmark */; AC5A56900AC2419A00622F72 = AC5A56900AC2419A00622F72 /* PBXTextBookmark */; AC5A56980AC2419A00622F72 = AC5A56980AC2419A00622F72 /* PBXTextBookmark */; AC5A569A0AC2419A00622F72 = AC5A569A0AC2419A00622F72 /* PBXTextBookmark */; AC5A569C0AC2419A00622F72 = AC5A569C0AC2419A00622F72 /* PBXTextBookmark */; AC5A569D0AC2419A00622F72 = AC5A569D0AC2419A00622F72 /* PBXTextBookmark */; AC5A569E0AC2419A00622F72 = AC5A569E0AC2419A00622F72 /* PBXTextBookmark */; AC5A56FE0AC2448600622F72 = AC5A56FE0AC2448600622F72 /* PBXTextBookmark */; AC5A57660AC250C200622F72 = AC5A57660AC250C200622F72 /* PBXTextBookmark */; AC6427D80AD883FA00752A08 = AC6427D80AD883FA00752A08 /* PBXTextBookmark */; AC6427E70AD884EE00752A08 = AC6427E70AD884EE00752A08 /* PBXTextBookmark */; AC642A1E0ADB317200752A08 = AC642A1E0ADB317200752A08 /* PBXTextBookmark */; AC642A270ADB317200752A08 = AC642A270ADB317200752A08 /* PBXTextBookmark */; AC642A280ADB317200752A08 = AC642A280ADB317200752A08 /* PBXTextBookmark */; AC776D5F0B69B290005E3D84 = AC776D5F0B69B290005E3D84 /* PBXTextBookmark */; AC776D600B69B290005E3D84 = AC776D600B69B290005E3D84 /* PBXBookmark */; AC776D620B69B290005E3D84 = AC776D620B69B290005E3D84 /* PBXTextBookmark */; AC776D640B69B290005E3D84 = AC776D640B69B290005E3D84 /* PBXTextBookmark */; AC776D650B69B290005E3D84 = AC776D650B69B290005E3D84 /* PBXBookmark */; ACA2C5D60B06E0F700E02DC6 = ACA2C5D60B06E0F700E02DC6 /* PBXTextBookmark */; ACA2C5D90B06E0F700E02DC6 = ACA2C5D90B06E0F700E02DC6 /* PBXTextBookmark */; ACA2C6CD0B06EC6700E02DC6 = ACA2C6CD0B06EC6700E02DC6 /* PBXTextBookmark */; ACA2C7CF0B07C82F00E02DC6 = ACA2C7CF0B07C82F00E02DC6 /* PBXTextBookmark */; ACA2C81F0B0830F900E02DC6 = ACA2C81F0B0830F900E02DC6 /* PBXTextBookmark */; ACA2CB8A0B0AC86600E02DC6 = ACA2CB8A0B0AC86600E02DC6 /* PBXTextBookmark */; ACA2CB8C0B0AC86600E02DC6 = ACA2CB8C0B0AC86600E02DC6 /* PBXTextBookmark */; ACA2CB8D0B0AC86600E02DC6 = ACA2CB8D0B0AC86600E02DC6 /* PBXTextBookmark */; ACA2CB9E0B0AC89600E02DC6 = ACA2CB9E0B0AC89600E02DC6 /* PBXTextBookmark */; ACA2CE0D0B10369800E02DC6 = ACA2CE0D0B10369800E02DC6 /* PBXTextBookmark */; ACA2CE0E0B10369800E02DC6 = ACA2CE0E0B10369800E02DC6 /* PBXTextBookmark */; ACABFD0E0B6178C500CA3C21 = ACABFD0E0B6178C500CA3C21 /* PBXTextBookmark */; ACABFDBC0B61895200CA3C21 = ACABFDBC0B61895200CA3C21 /* PBXTextBookmark */; ACABFDF70B61D7DB00CA3C21 = ACABFDF70B61D7DB00CA3C21 /* PBXTextBookmark */; ACABFE190B61E19100CA3C21 = ACABFE190B61E19100CA3C21 /* PBXTextBookmark */; ACABFE3E0B61E39100CA3C21 = ACABFE3E0B61E39100CA3C21 /* PBXTextBookmark */; ACBF6FE70B72C07D004A69E7 = ACBF6FE70B72C07D004A69E7 /* PBXTextBookmark */; ACBF6FE80B72C07D004A69E7 = ACBF6FE80B72C07D004A69E7 /* PBXTextBookmark */; ACBF6FEF0B7326D6004A69E7 = ACBF6FEF0B7326D6004A69E7 /* PBXTextBookmark */; ACBF6FF00B7326D6004A69E7 = ACBF6FF00B7326D6004A69E7 /* PBXTextBookmark */; ACBF6FF10B7326D6004A69E7 = ACBF6FF10B7326D6004A69E7 /* PBXTextBookmark */; ACBF6FF20B7326D6004A69E7 = ACBF6FF20B7326D6004A69E7 /* PBXTextBookmark */; ACBF6FF30B7326D6004A69E7 = ACBF6FF30B7326D6004A69E7 /* PBXTextBookmark */; ACE0E72E0AC9CF47007E3ED2 = ACE0E72E0AC9CF47007E3ED2 /* PBXTextBookmark */; ACE0E94B0ACA196D007E3ED2 = ACE0E94B0ACA196D007E3ED2 /* PBXTextBookmark */; ACE0E9A30ACA1CC1007E3ED2 = ACE0E9A30ACA1CC1007E3ED2 /* PBXTextBookmark */; ACF227730B6826DC005CFC14 = ACF227730B6826DC005CFC14 /* PBXTextBookmark */; ACF227B50B682D68005CFC14 = ACF227B50B682D68005CFC14 /* PBXTextBookmark */; ACF227B70B682D68005CFC14 = ACF227B70B682D68005CFC14 /* PBXTextBookmark */; ACF227EF0B689BAA005CFC14 = ACF227EF0B689BAA005CFC14 /* PBXTextBookmark */; ACF227F10B689BAA005CFC14 = ACF227F10B689BAA005CFC14 /* PBXTextBookmark */; ACF227F20B689BAA005CFC14 = ACF227F20B689BAA005CFC14 /* PBXTextBookmark */; ACF2F7A10B4C70B2005197BB = ACF2F7A10B4C70B2005197BB /* PBXTextBookmark */; ACFC0AB00AC99E2E00DAC478 = ACFC0AB00AC99E2E00DAC478 /* PBXTextBookmark */; ACFC0AB10AC99E2E00DAC478 = ACFC0AB10AC99E2E00DAC478 /* PBXTextBookmark */; ACFC0B910AC9A70300DAC478 = ACFC0B910AC9A70300DAC478 /* PBXTextBookmark */; }; sourceControlManager = AC5A53150AC098E400622F72 /* Source Control */; userBuildSettings = { }; }; 32CA4F630368D1EE00C91783 /* fweelin_Prefix.pch */ = { uiCtxt = { sepNavIntBoundsRect = "{{0, 0}, {730, 610}}"; sepNavSelRange = "{163, 0}"; sepNavVisRect = "{{0, 0}, {730, 610}}"; }; }; 8D1107260486CEB800E47090 /* fweelin */ = { activeExec = 0; executables = ( AC5A53070AC098E000622F72 /* fweelin */, ); }; 8D1107310486CEB800E47090 /* Info.plist */ = { uiCtxt = { sepNavIntBoundsRect = "{{0, 0}, {686, 417}}"; sepNavSelRange = "{480, 0}"; sepNavVisRect = "{{0, 0}, {631, 417}}"; sepNavWindowFrame = "{{50, 133}, {1131, 740}}"; }; }; AC12676A0AC8E0C600FE916E /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 32CA4F630368D1EE00C91783 /* fweelin_Prefix.pch */; name = "fweelin_Prefix.pch: 10"; rLen = 0; rLoc = 163; rType = 0; vrLen = 163; vrLoc = 0; }; AC1267750AC8E0C600FE916E /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 002F3A2C09D0888800EBEB88 /* SDLMain.mm */; name = "SDLMain.m: 1"; rLen = 0; rLoc = 0; rType = 0; vrLen = 1339; vrLoc = 0; }; AC1267760AC8E0C600FE916E /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 32CA4F630368D1EE00C91783 /* fweelin_Prefix.pch */; name = "fweelin_Prefix.pch: 1"; rLen = 0; rLoc = 0; rType = 0; vrLen = 163; vrLoc = 0; }; AC12677A0AC8E0C600FE916E /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = AC5A53D80AC09A6400622F72 /* fweelin_browser.h */; name = BLINK_DELAY; rLen = 11; rLoc = 2395; rType = 0; vrLen = 1245; vrLoc = 1790; }; AC12677B0AC8E0C600FE916E /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = AC5A53D70AC09A6400622F72 /* fweelin_browser.cc */; name = "fweelin_browser.cc: BLINK_DELAY"; rLen = 0; rLoc = 337; rType = 0; vrLen = 1062; vrLoc = 0; }; AC126BEC0AC8E94900FE916E /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 002F3A2B09D0888800EBEB88 /* SDLMain.h */; name = "SDLMain.h: 1"; rLen = 0; rLoc = 0; rType = 0; vrLen = 307; vrLoc = 0; }; AC126C3E0AC8EED400FE916E /* .fweelin.rc */ = { uiCtxt = { sepNavIntBoundsRect = "{{0, 0}, {728, 36932}}"; sepNavSelRange = "{104754, 0}"; sepNavVisRect = "{{0, 18911}, {631, 417}}"; sepNavWindowFrame = "{{142, 49}, {1131, 740}}"; }; }; AC126C5A0AC8F08000FE916E /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = AC126C3E0AC8EED400FE916E /* .fweelin.rc */; name = ".fweelin.rc: 29"; rLen = 0; rLoc = 1545; rType = 0; vrLen = 2188; vrLoc = 0; }; AC126C5B0AC8F08000FE916E /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = AC5A53E30AC09A6400622F72 /* fweelin_fluidsynth.cc */; name = "fweelin_fluidsynth.cc: 1"; rLen = 0; rLoc = 0; rType = 0; vrLen = 1362; vrLoc = 0; }; AC126C5C0AC8F08000FE916E /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = AC5A53E40AC09A6400622F72 /* fweelin_fluidsynth.h */; name = "fweelin_fluidsynth.h: 1"; rLen = 0; rLoc = 0; rType = 0; vrLen = 1121; vrLoc = 0; }; AC126C790AC8F26100FE916E /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = AC5A53E00AC09A6400622F72 /* fweelin_datatypes.h */; name = "fweelin_datatypes.h: 20"; rLen = 0; rLoc = 290; rType = 0; vrLen = 938; vrLoc = 0; }; AC126C930AC8F36000FE916E /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = AC5A53ED0AC09A6400622F72 /* fweelin_videoio.h */; name = "fweelin_videoio.h: 30"; rLen = 0; rLoc = 738; rType = 0; vrLen = 1183; vrLoc = 0; }; AC19AEB60B77E01400AEC16F /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = AC5A53E10AC09A6400622F72 /* fweelin_event.cc */; name = "fweelin_event.cc: 310"; rLen = 0; rLoc = 11071; rType = 0; vrLen = 1199; vrLoc = 2596; }; AC19AEB70B77E01400AEC16F /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = AC5A53E20AC09A6400622F72 /* fweelin_event.h */; name = "fweelin_event.h: 10"; rLen = 0; rLoc = 139; rType = 0; vrLen = 556; vrLoc = 0; }; AC19AEB80B77E01400AEC16F /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = AC5A53E20AC09A6400622F72 /* fweelin_event.h */; name = "fweelin_event.h: 10"; rLen = 0; rLoc = 139; rType = 0; vrLen = 556; vrLoc = 0; }; AC19AEB90B77E01400AEC16F /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = AC5A53E10AC09A6400622F72 /* fweelin_event.cc */; name = "fweelin_event.cc: 310"; rLen = 0; rLoc = 11071; rType = 0; vrLen = 1199; vrLoc = 2596; }; AC19AEBA0B77E01400AEC16F /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = AC5A53E20AC09A6400622F72 /* fweelin_event.h */; name = "fweelin_event.h: 2194"; rLen = 0; rLoc = 60996; rType = 0; vrLen = 1053; vrLoc = 60658; }; AC19AEC10B77E09D00AEC16F /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = AC5A53E20AC09A6400622F72 /* fweelin_event.h */; name = "fweelin_event.h: 2194"; rLen = 0; rLoc = 60996; rType = 0; vrLen = 1076; vrLoc = 60658; }; AC19AEC20B77E09D00AEC16F /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = AC5A53E80AC09A6400622F72 /* fweelin_midiio.cc */; name = "fweelin_midiio.cc: 906"; rLen = 0; rLoc = 26017; rType = 0; vrLen = 854; vrLoc = 25452; }; AC19AEC30B77E09D00AEC16F /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = AC5A53E60AC09A6400622F72 /* fweelin_mem.cc */; name = "fweelin_mem.cc: 159"; rLen = 0; rLoc = 3783; rType = 0; vrLen = 748; vrLoc = 3423; }; AC19AEC40B77E09D00AEC16F /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = AC5A53EC0AC09A6400622F72 /* fweelin_videoio.cc */; name = "fweelin_videoio.cc: 1828"; rLen = 0; rLoc = 48261; rType = 0; vrLen = 845; vrLoc = 48037; }; AC19AEC50B77E09D00AEC16F /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = AC5A53E20AC09A6400622F72 /* fweelin_event.h */; name = "fweelin_event.h: 2194"; rLen = 0; rLoc = 60996; rType = 0; vrLen = 1076; vrLoc = 60658; }; AC19AEC60B77E09D00AEC16F /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = AC5A53E80AC09A6400622F72 /* fweelin_midiio.cc */; name = "fweelin_midiio.cc: 906"; rLen = 0; rLoc = 26017; rType = 0; vrLen = 854; vrLoc = 25452; }; AC19AEC70B77E09D00AEC16F /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = AC5A53E60AC09A6400622F72 /* fweelin_mem.cc */; name = "fweelin_mem.cc: 159"; rLen = 0; rLoc = 3783; rType = 0; vrLen = 748; vrLoc = 3423; }; AC19AEC80B77E09D00AEC16F /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = AC5A53EC0AC09A6400622F72 /* fweelin_videoio.cc */; name = "fweelin_videoio.cc: 2328"; rLen = 0; rLoc = 62301; rType = 0; vrLen = 806; vrLoc = 61776; }; AC19AECB0B77E57400AEC16F /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = AC5A53EC0AC09A6400622F72 /* fweelin_videoio.cc */; name = "fweelin_videoio.cc: 2327"; rLen = 0; rLoc = 62264; rType = 0; vrLen = 806; vrLoc = 61776; }; AC19AECC0B77E57400AEC16F /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = AC5A53E20AC09A6400622F72 /* fweelin_event.h */; name = "fweelin_event.h: 2194"; rLen = 0; rLoc = 60996; rType = 0; vrLen = 1033; vrLoc = 60658; }; AC19AECD0B77E57400AEC16F /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = AC5A53EC0AC09A6400622F72 /* fweelin_videoio.cc */; name = "fweelin_videoio.cc: 2327"; rLen = 0; rLoc = 62264; rType = 0; vrLen = 806; vrLoc = 61776; }; AC19AECE0B77E57400AEC16F /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = AC5A53E20AC09A6400622F72 /* fweelin_event.h */; name = "fweelin_event.h: 2195"; rLen = 0; rLoc = 60995; rType = 0; vrLen = 996; vrLoc = 60658; }; AC2080220B6EDC4A002A78E8 /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = AC2080230B6EDC4A002A78E8 /* ringbuffer.h */; name = "(null): 46"; rLen = 0; rLoc = 1624; rType = 0; vrLen = 991; vrLoc = 6560; }; AC2080230B6EDC4A002A78E8 /* ringbuffer.h */ = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ringbuffer.h; path = /Library/Frameworks/Jack.framework/Versions/A/Headers/ringbuffer.h; sourceTree = ""; }; AC2080240B6EDC4A002A78E8 /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = AC2080250B6EDC4A002A78E8 /* ringbuffer.h */; name = "(null): 94"; rLen = 0; rLoc = 3648; rType = 0; vrLen = 1105; vrLoc = 0; }; AC2080250B6EDC4A002A78E8 /* ringbuffer.h */ = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ringbuffer.h; path = /Users/mercury/Desktop/portaudio/src/hostapi/coreaudio/ringbuffer.h; sourceTree = ""; }; AC2080280B6EDC4A002A78E8 /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = AC2080290B6EDC4A002A78E8 /* ringbuffer.h */; name = "(null): 46"; rLen = 0; rLoc = 1624; rType = 0; vrLen = 991; vrLoc = 6560; }; AC2080290B6EDC4A002A78E8 /* ringbuffer.h */ = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ringbuffer.h; path = /Library/Frameworks/Jack.framework/Versions/A/Headers/ringbuffer.h; sourceTree = ""; }; AC20802A0B6EDC4A002A78E8 /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = AC20802B0B6EDC4A002A78E8 /* ringbuffer.h */; name = "(null): 94"; rLen = 0; rLoc = 3648; rType = 0; vrLen = 1105; vrLoc = 0; }; AC20802B0B6EDC4A002A78E8 /* ringbuffer.h */ = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ringbuffer.h; path = /Users/mercury/Desktop/portaudio/src/hostapi/coreaudio/ringbuffer.h; sourceTree = ""; }; AC20802E0B6F09C5002A78E8 /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = AC5A53D40AC09A6400622F72 /* fweelin_audioio.h */; name = "fweelin_audioio.h: 3"; rLen = 0; rLoc = 56; rType = 0; vrLen = 563; vrLoc = 0; }; AC2AECD60B6AD6CE00AFA3A9 /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 8D1107310486CEB800E47090 /* Info.plist */; name = "Info.plist: 13"; rLen = 0; rLoc = 480; rType = 0; vrLen = 861; vrLoc = 0; }; AC2AECD90B6AD6CE00AFA3A9 /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = AC5A53DA0AC09A6400622F72 /* fweelin_config.h */; name = "fweelin_config.h: EventBinding"; rLen = 0; rLoc = 4861; rType = 0; vrLen = 969; vrLoc = 5751; }; AC2AECDA0B6AD6CE00AFA3A9 /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = AC5A53EC0AC09A6400622F72 /* fweelin_videoio.cc */; name = "fweelin_videoio.cc: 1828"; rLen = 0; rLoc = 48261; rType = 0; vrLen = 885; vrLoc = 47997; }; AC5A53070AC098E000622F72 /* fweelin */ = { isa = PBXExecutable; activeArgIndex = 2147483647; activeArgIndices = ( ); argumentStrings = ( ); autoAttachOnCrash = 1; configStateDict = { }; customDataFormattersEnabled = 1; debuggerPlugin = GDBDebugging; disassemblyDisplayState = 0; dylibVariantSuffix = ""; enableDebugStr = 1; environmentEntries = ( ); executableSystemSymbolLevel = 0; executableUserSymbolLevel = 0; libgmallocEnabled = 0; name = fweelin; savedGlobals = { }; sourceDirectories = ( ); variableFormatDictionary = { }; }; AC5A53150AC098E400622F72 /* Source Control */ = { isa = PBXSourceControlManager; fallbackIsa = XCSourceControlManager; isSCMEnabled = 0; scmConfiguration = { }; scmType = ""; }; AC5A53160AC098E400622F72 /* Code sense */ = { isa = PBXCodeSenseManager; indexTemplatePath = ""; }; AC5A531F0AC0998E00622F72 /* XCBreakpointsBucket */ = { isa = XCBreakpointsBucket; name = "Project Breakpoints"; objects = ( ); }; AC5A53D30AC09A6400622F72 /* fweelin_audioio.cc */ = { uiCtxt = { sepNavIntBoundsRect = "{{0, 0}, {631, 4564}}"; sepNavSelRange = "{2864, 32}"; sepNavVisRect = "{{0, 1375}, {631, 417}}"; }; }; AC5A53D40AC09A6400622F72 /* fweelin_audioio.h */ = { uiCtxt = { sepNavIntBoundsRect = "{{0, 0}, {631, 1554}}"; sepNavSelRange = "{56, 0}"; sepNavVisRect = "{{0, 0}, {631, 417}}"; sepNavWindowFrame = "{{73, 252}, {950, 600}}"; }; }; AC5A53D50AC09A6400622F72 /* fweelin_block.cc */ = { uiCtxt = { sepNavIntBoundsRect = "{{0, 0}, {740, 30688}}"; sepNavSelRange = "{266, 0}"; sepNavVisRect = "{{0, 169}, {740, 180}}"; sepNavWindowFrame = "{{326, 119}, {750, 502}}"; }; }; AC5A53D60AC09A6400622F72 /* fweelin_block.h */ = { uiCtxt = { sepNavIntBoundsRect = "{{0, 0}, {638, 13706}}"; sepNavSelRange = "{190, 0}"; sepNavVisRect = "{{0, 31}, {631, 417}}"; sepNavWindowFrame = "{{349, 98}, {750, 502}}"; }; }; AC5A53D70AC09A6400622F72 /* fweelin_browser.cc */ = { uiCtxt = { sepNavIntBoundsRect = "{{0, 0}, {740, 13958}}"; sepNavSelRange = "{11863, 255}"; sepNavVisRect = "{{0, 6147}, {740, 180}}"; }; }; AC5A53D80AC09A6400622F72 /* fweelin_browser.h */ = { uiCtxt = { sepNavIntBoundsRect = "{{0, 0}, {631, 7560}}"; sepNavSelRange = "{11587, 0}"; sepNavVisRect = "{{0, 4847}, {631, 417}}"; sepNavWindowFrame = "{{50, 133}, {1131, 740}}"; }; }; AC5A53D90AC09A6400622F72 /* fweelin_config.cc */ = { uiCtxt = { sepNavIntBoundsRect = "{{0, 0}, {631, 42742}}"; sepNavSelRange = "{74954, 0}"; sepNavVisRect = "{{0, 40693}, {631, 417}}"; sepNavWindowFrame = "{{96, 231}, {950, 600}}"; }; }; AC5A53DA0AC09A6400622F72 /* fweelin_config.h */ = { uiCtxt = { sepNavIntBoundsRect = "{{0, 0}, {632, 13230}}"; sepNavSelRange = "{4861, 0}"; sepNavVisRect = "{{0, 2902}, {631, 417}}"; sepNavWindowFrame = "{{73, 252}, {950, 600}}"; }; }; AC5A53DB0AC09A6400622F72 /* fweelin_core_dsp.cc */ = { uiCtxt = { sepNavIntBoundsRect = "{{0, 0}, {680, 33222}}"; sepNavSelRange = "{11396, 0}"; sepNavVisRect = "{{0, 5530}, {631, 417}}"; sepNavWindowFrame = "{{165, 168}, {950, 600}}"; }; }; AC5A53DC0AC09A6400622F72 /* fweelin_core_dsp.h */ = { uiCtxt = { sepNavIntBoundsRect = "{{0, 0}, {631, 11186}}"; sepNavSelRange = "{8873, 0}"; sepNavVisRect = "{{0, 4095}, {631, 417}}"; sepNavWindowFrame = "{{142, 189}, {950, 600}}"; }; }; AC5A53DD0AC09A6400622F72 /* fweelin_core.cc */ = { uiCtxt = { sepNavIntBoundsRect = "{{0, 0}, {821, 45318}}"; sepNavSelRange = "{27861, 7}"; sepNavVisRect = "{{0, 12125}, {821, 321}}"; sepNavWindowFrame = "{{96, 329}, {750, 502}}"; }; }; AC5A53DE0AC09A6400622F72 /* fweelin_core.h */ = { uiCtxt = { sepNavIntBoundsRect = "{{0, 0}, {631, 13384}}"; sepNavSelRange = "{13013, 0}"; sepNavVisRect = "{{0, 6799}, {631, 417}}"; sepNavWindowFrame = "{{73, 350}, {750, 502}}"; }; }; AC5A53DF0AC09A6400622F72 /* fweelin_datatypes.cc */ = { uiCtxt = { sepNavIntBoundsRect = "{{0, 0}, {631, 518}}"; sepNavSelRange = "{0, 0}"; sepNavVisRect = "{{0, 0}, {631, 417}}"; }; }; AC5A53E00AC09A6400622F72 /* fweelin_datatypes.h */ = { uiCtxt = { sepNavIntBoundsRect = "{{0, 0}, {911, 7028}}"; sepNavSelRange = "{2136, 0}"; sepNavVisRect = "{{0, 955}, {911, 471}}"; sepNavWindowFrame = "{{414, 40}, {950, 600}}"; }; }; AC5A53E10AC09A6400622F72 /* fweelin_event.cc */ = { uiCtxt = { sepNavIntBoundsRect = "{{0, 0}, {631, 5418}}"; sepNavSelRange = "{11071, 0}"; sepNavVisRect = "{{0, 1431}, {631, 417}}"; }; }; AC5A53E20AC09A6400622F72 /* fweelin_event.h */ = { uiCtxt = { sepNavIntBoundsRect = "{{0, 0}, {848, 32620}}"; sepNavSelRange = "{60995, 0}"; sepNavVisRect = "{{0, 30576}, {631, 417}}"; sepNavWindowFrame = "{{50, 273}, {950, 600}}"; }; }; AC5A53E30AC09A6400622F72 /* fweelin_fluidsynth.cc */ = { uiCtxt = { sepNavIntBoundsRect = "{{0, 0}, {631, 3080}}"; sepNavSelRange = "{808, 0}"; sepNavVisRect = "{{0, 199}, {631, 417}}"; }; }; AC5A53E40AC09A6400622F72 /* fweelin_fluidsynth.h */ = { uiCtxt = { sepNavIntBoundsRect = "{{0, 0}, {631, 896}}"; sepNavSelRange = "{0, 0}"; sepNavVisRect = "{{0, 0}, {631, 417}}"; }; }; AC5A53E50AC09A6400622F72 /* fweelin_logo.h */ = { uiCtxt = { sepNavIntBoundsRect = "{{0, 0}, {730, 17430}}"; sepNavSelRange = "{266, 0}"; sepNavVisRect = "{{0, 0}, {730, 610}}"; }; }; AC5A53E60AC09A6400622F72 /* fweelin_mem.cc */ = { uiCtxt = { sepNavIntBoundsRect = "{{0, 0}, {631, 8820}}"; sepNavSelRange = "{3783, 0}"; sepNavVisRect = "{{0, 1965}, {631, 417}}"; sepNavWindowFrame = "{{119, 210}, {950, 600}}"; }; }; AC5A53E70AC09A6400622F72 /* fweelin_mem.h */ = { uiCtxt = { sepNavIntBoundsRect = "{{0, 0}, {911, 3220}}"; sepNavSelRange = "{210, 56}"; sepNavVisRect = "{{0, 0}, {911, 471}}"; sepNavWindowFrame = "{{96, 231}, {950, 600}}"; }; }; AC5A53E80AC09A6400622F72 /* fweelin_midiio.cc */ = { uiCtxt = { sepNavIntBoundsRect = "{{0, 0}, {884, 14364}}"; sepNavSelRange = "{26017, 0}"; sepNavVisRect = "{{0, 12359}, {631, 417}}"; sepNavWindowFrame = "{{257, 182}, {750, 502}}"; }; }; AC5A53E90AC09A6400622F72 /* fweelin_midiio.h */ = { uiCtxt = { sepNavIntBoundsRect = "{{0, 0}, {631, 2366}}"; sepNavSelRange = "{310, 0}"; sepNavVisRect = "{{0, 0}, {631, 417}}"; sepNavWindowFrame = "{{234, 203}, {750, 502}}"; }; }; AC5A53EA0AC09A6400622F72 /* fweelin_sdlio.cc */ = { uiCtxt = { sepNavIntBoundsRect = "{{0, 0}, {631, 10374}}"; sepNavSelRange = "{5696, 0}"; sepNavVisRect = "{{0, 5603}, {631, 417}}"; sepNavWindowFrame = "{{280, 161}, {750, 502}}"; }; }; AC5A53EB0AC09A6400622F72 /* fweelin_sdlio.h */ = { uiCtxt = { sepNavIntBoundsRect = "{{0, 0}, {631, 1484}}"; sepNavSelRange = "{1757, 0}"; sepNavVisRect = "{{0, 947}, {631, 417}}"; }; }; AC5A53EC0AC09A6400622F72 /* fweelin_videoio.cc */ = { uiCtxt = { sepNavIntBoundsRect = "{{0, 0}, {631, 34174}}"; sepNavSelRange = "{62264, 0}"; sepNavVisRect = "{{0, 32307}, {631, 417}}"; sepNavWindowFrame = "{{303, 140}, {750, 502}}"; }; }; AC5A53ED0AC09A6400622F72 /* fweelin_videoio.h */ = { uiCtxt = { sepNavIntBoundsRect = "{{0, 0}, {631, 2366}}"; sepNavSelRange = "{1931, 0}"; sepNavVisRect = "{{0, 1552}, {631, 417}}"; sepNavWindowFrame = "{{50, 371}, {750, 502}}"; }; }; AC5A53EE0AC09A6400622F72 /* fweelin.cc */ = { uiCtxt = { sepNavIntBoundsRect = "{{0, 0}, {631, 868}}"; sepNavSelRange = "{621, 0}"; sepNavVisRect = "{{0, 437}, {631, 417}}"; sepNavWindowFrame = "{{142, 49}, {1131, 740}}"; }; }; AC5A54D30AC0EA0200622F72 /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = AC5A53D40AC09A6400622F72 /* fweelin_audioio.h */; name = "fweelin_audioio.h: 1"; rLen = 0; rLoc = 0; rType = 0; vrLen = 452; vrLoc = 0; }; AC5A54E90AC0EA8500622F72 /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = AC5A53D30AC09A6400622F72 /* fweelin_audioio.cc */; name = "fweelin_audioio.cc: 1"; rLen = 0; rLoc = 0; rType = 0; vrLen = 388; vrLoc = 0; }; AC5A54EA0AC0EA8500622F72 /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = AC5A53EE0AC09A6400622F72 /* fweelin.cc */; name = "fweelin.cc: 1"; rLen = 0; rLoc = 0; rType = 0; vrLen = 195; vrLoc = 0; }; AC5A54EB0AC0EA8500622F72 /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = AC5A53EB0AC09A6400622F72 /* fweelin_sdlio.h */; name = "fweelin_sdlio.h: 1"; rLen = 0; rLoc = 0; rType = 0; vrLen = 427; vrLoc = 0; }; AC5A54EC0AC0EA8500622F72 /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = AC5A53EC0AC09A6400622F72 /* fweelin_videoio.cc */; name = "fweelin_videoio.cc: 3"; rLen = 0; rLoc = 31; rType = 0; vrLen = 374; vrLoc = 0; }; AC5A55D80AC2198F00622F72 /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = AC5A53E90AC09A6400622F72 /* fweelin_midiio.h */; name = "fweelin_midiio.h: 59"; rLen = 0; rLoc = 2747; rType = 0; vrLen = 654; vrLoc = 1266; }; AC5A55D90AC2198F00622F72 /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = AC5A53D90AC09A6400622F72 /* fweelin_config.cc */; name = "fweelin_config.cc: 2754"; rLen = 0; rLoc = 73093; rType = 0; vrLen = 499; vrLoc = 71055; }; AC5A56880AC2419A00622F72 /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = AC5A53E50AC09A6400622F72 /* fweelin_logo.h */; name = "fweelin_logo.h: 10"; rLen = 0; rLoc = 266; rType = 0; vrLen = 2955; vrLoc = 0; }; AC5A568E0AC2419A00622F72 /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = AC5A53E80AC09A6400622F72 /* fweelin_midiio.cc */; name = "fweelin_midiio.cc: 316"; rLen = 0; rLoc = 18290; rType = 0; vrLen = 1455; vrLoc = 7840; }; AC5A56900AC2419A00622F72 /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = AC5A53DA0AC09A6400622F72 /* fweelin_config.h */; name = "fweelin_config.h: 37"; rLen = 0; rLoc = 1544; rType = 0; vrLen = 1393; vrLoc = 0; }; AC5A56980AC2419A00622F72 /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = AC5A53DE0AC09A6400622F72 /* fweelin_core.h */; name = "fweelin_core.h: 17"; rLen = 0; rLoc = 279; rType = 0; vrLen = 827; vrLoc = 0; }; AC5A569A0AC2419A00622F72 /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = AC5A53DF0AC09A6400622F72 /* fweelin_datatypes.cc */; name = "fweelin_datatypes.cc: 1"; rLen = 0; rLoc = 0; rType = 0; vrLen = 649; vrLoc = 0; }; AC5A569C0AC2419A00622F72 /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = AC5A53E00AC09A6400622F72 /* fweelin_datatypes.h */; name = "fweelin_datatypes.h: 1"; rLen = 0; rLoc = 0; rType = 0; vrLen = 938; vrLoc = 0; }; AC5A569D0AC2419A00622F72 /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = AC5A53E20AC09A6400622F72 /* fweelin_event.h */; name = "fweelin_event.h: 1"; rLen = 0; rLoc = 0; rType = 0; vrLen = 993; vrLoc = 0; }; AC5A569E0AC2419A00622F72 /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = AC5A53E50AC09A6400622F72 /* fweelin_logo.h */; name = "fweelin_logo.h: 10"; rLen = 0; rLoc = 266; rType = 0; vrLen = 2955; vrLoc = 0; }; AC5A56FE0AC2448600622F72 /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = AC5A53DD0AC09A6400622F72 /* fweelin_core.cc */; name = "fweelin_core.cc: 9"; rLen = 0; rLoc = 156; rType = 0; vrLen = 975; vrLoc = 0; }; AC5A57660AC250C200622F72 /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = AC5A53EA0AC09A6400622F72 /* fweelin_sdlio.cc */; name = "fweelin_sdlio.cc: 413"; rLen = 0; rLoc = 5878; rType = 0; vrLen = 1018; vrLoc = 5128; }; AC6427D80AD883FA00752A08 /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = AC5A53EE0AC09A6400622F72 /* fweelin.cc */; name = "fweelin.cc: 49"; rLen = 0; rLoc = 621; rType = 0; vrLen = 543; vrLoc = 313; }; AC6427E70AD884EE00752A08 /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = AC5A53EA0AC09A6400622F72 /* fweelin_sdlio.cc */; name = "fweelin_sdlio.cc: 417"; rLen = 0; rLoc = 5696; rType = 0; vrLen = 741; vrLoc = 5260; }; AC642A1E0ADB317200752A08 /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = AC5A53D50AC09A6400622F72 /* fweelin_block.cc */; name = sndfile; rLen = 0; rLoc = 266; rType = 0; vrLen = 585; vrLoc = 0; }; AC642A270ADB317200752A08 /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = AC5A53D60AC09A6400622F72 /* fweelin_block.h */; name = "#include "; rLen = 0; rLoc = 190; rType = 0; vrLen = 601; vrLoc = 0; }; AC642A280ADB317200752A08 /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = AC5A53DB0AC09A6400622F72 /* fweelin_core_dsp.cc */; name = "fweelin_core_dsp.cc: 1"; rLen = 0; rLoc = 0; rType = 0; vrLen = 640; vrLoc = 0; }; AC776D5F0B69B290005E3D84 /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 089C165DFE840E0CC02AAC07 /* English */; name = "English: 5"; rLen = 0; rLoc = 176; rType = 0; vrLen = 131; vrLoc = 0; }; AC776D600B69B290005E3D84 /* PBXBookmark */ = { isa = PBXBookmark; fRef = AC776D460B69B161005E3D84 /* freewheeling.icns */; }; AC776D620B69B290005E3D84 /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 8D1107310486CEB800E47090 /* Info.plist */; name = "Info.plist: 8"; rLen = 0; rLoc = 288; rType = 0; vrLen = 860; vrLoc = 0; }; AC776D640B69B290005E3D84 /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 089C165DFE840E0CC02AAC07 /* English */; name = "English: 5"; rLen = 0; rLoc = 176; rType = 0; vrLen = 131; vrLoc = 0; }; AC776D650B69B290005E3D84 /* PBXBookmark */ = { isa = PBXBookmark; fRef = AC776D460B69B161005E3D84 /* freewheeling.icns */; }; ACA2C5CB0B06E03E00E02DC6 /* xmlmemory.h */ = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = xmlmemory.h; path = /Developer/SDKs/MacOSX10.4u.sdk/usr/include/libxml2/libxml/xmlmemory.h; sourceTree = ""; }; ACA2C5D60B06E0F700E02DC6 /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = ACA2C5CB0B06E03E00E02DC6 /* xmlmemory.h */; name = "#include "; rLen = 31; rLoc = 339; rType = 0; vrLen = 728; vrLoc = 0; }; ACA2C5D90B06E0F700E02DC6 /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = ACA2C5CB0B06E03E00E02DC6 /* xmlmemory.h */; name = "#include "; rLen = 31; rLoc = 339; rType = 0; vrLen = 728; vrLoc = 0; }; ACA2C6CD0B06EC6700E02DC6 /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = AC5A53ED0AC09A6400622F72 /* fweelin_videoio.h */; name = "fweelin_videoio.h: close"; rLen = 0; rLoc = 1931; rType = 0; vrLen = 766; vrLoc = 3092; }; ACA2C7B60B07C73900E02DC6 /* patches-channels.xml */ = { uiCtxt = { sepNavIntBoundsRect = "{{0, 0}, {631, 417}}"; sepNavSelRange = "{74, 0}"; sepNavVisRect = "{{0, 0}, {631, 417}}"; }; }; ACA2C7CF0B07C82F00E02DC6 /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = AC5A53D60AC09A6400622F72 /* fweelin_block.h */; name = "fweelin_block.h: 10"; rLen = 0; rLoc = 190; rType = 0; vrLen = 565; vrLoc = 52; }; ACA2C81F0B0830F900E02DC6 /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = AC5A53D70AC09A6400622F72 /* fweelin_browser.cc */; name = GetEvent; rLen = 8; rLoc = 11938; rType = 0; vrLen = 809; vrLoc = 11494; }; ACA2CB8A0B0AC86600E02DC6 /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = ACFC0A990AC99CDF00DAC478 /* FweelinMac.h */; name = "FweelinMac.h: 27"; rLen = 0; rLoc = 605; rType = 0; vrLen = 803; vrLoc = 32; }; ACA2CB8C0B0AC86600E02DC6 /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = ACFC0A9A0AC99CDF00DAC478 /* FweelinMac.mm */; name = "FweelinMac.mm: 56"; rLen = 0; rLoc = 1257; rType = 0; vrLen = 801; vrLoc = 872; }; ACA2CB8D0B0AC86600E02DC6 /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 002F3A2B09D0888800EBEB88 /* SDLMain.h */; name = "SDLMain.h: clearMIDIInputList"; rLen = 0; rLoc = 486; rType = 0; vrLen = 565; vrLoc = 0; }; ACA2CB9E0B0AC89600E02DC6 /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 002F3A2C09D0888800EBEB88 /* SDLMain.mm */; name = w; rLen = 1; rLoc = 2643; rType = 0; vrLen = 475; vrLoc = 2423; }; ACA2CE0D0B10369800E02DC6 /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = ACA2C7B60B07C73900E02DC6 /* patches-channels.xml */; name = "patches-channels.xml: 3"; rLen = 0; rLoc = 74; rType = 0; vrLen = 886; vrLoc = 0; }; ACA2CE0E0B10369800E02DC6 /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = ACA2C7B60B07C73900E02DC6 /* patches-channels.xml */; name = "patches-channels.xml: 3"; rLen = 0; rLoc = 74; rType = 0; vrLen = 886; vrLoc = 0; }; ACABFD0E0B6178C500CA3C21 /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = AC5A53E40AC09A6400622F72 /* fweelin_fluidsynth.h */; name = "fweelin_fluidsynth.h: 1"; rLen = 0; rLoc = 0; rType = 0; vrLen = 775; vrLoc = 0; }; ACABFDBC0B61895200CA3C21 /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = AC5A53D30AC09A6400622F72 /* fweelin_audioio.cc */; name = "app->getLOOPMGR()->GetCurPulse()"; rLen = 32; rLoc = 2864; rType = 0; vrLen = 1029; vrLoc = 2576; }; ACABFDF70B61D7DB00CA3C21 /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = AC5A53DF0AC09A6400622F72 /* fweelin_datatypes.cc */; name = "fweelin_datatypes.cc: 1"; rLen = 0; rLoc = 0; rType = 0; vrLen = 561; vrLoc = 0; }; ACABFE190B61E19100CA3C21 /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = AC5A53DE0AC09A6400622F72 /* fweelin_core.h */; name = "fweelin_core.h: 501"; rLen = 0; rLoc = 13013; rType = 0; vrLen = 882; vrLoc = 12575; }; ACABFE3E0B61E39100CA3C21 /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = AC5A53DC0AC09A6400622F72 /* fweelin_core_dsp.h */; name = "fweelin_core_dsp.h: SetMIDIClock"; rLen = 0; rLoc = 8873; rType = 0; vrLen = 1016; vrLoc = 8605; }; ACBF6FE70B72C07D004A69E7 /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = AC5A53E20AC09A6400622F72 /* fweelin_event.h */; name = "fweelin_event.h: 13"; rLen = 0; rLoc = 154; rType = 0; vrLen = 556; vrLoc = 0; }; ACBF6FE80B72C07D004A69E7 /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = AC5A53E20AC09A6400622F72 /* fweelin_event.h */; name = "fweelin_event.h: 13"; rLen = 0; rLoc = 154; rType = 0; vrLen = 556; vrLoc = 0; }; ACBF6FEF0B7326D6004A69E7 /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = AC5A53D90AC09A6400622F72 /* fweelin_config.cc */; name = "fweelin_config.cc: 2910"; rLen = 0; rLoc = 74954; rType = 0; vrLen = 902; vrLoc = 74829; }; ACBF6FF00B7326D6004A69E7 /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = AC5A53E10AC09A6400622F72 /* fweelin_event.cc */; name = "fweelin_event.cc: 310"; rLen = 0; rLoc = 11071; rType = 0; vrLen = 1199; vrLoc = 2596; }; ACBF6FF10B7326D6004A69E7 /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = AC5A53D90AC09A6400622F72 /* fweelin_config.cc */; name = "fweelin_config.cc: 2910"; rLen = 0; rLoc = 74954; rType = 0; vrLen = 902; vrLoc = 74829; }; ACBF6FF20B7326D6004A69E7 /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = AC5A53E10AC09A6400622F72 /* fweelin_event.cc */; name = "fweelin_event.cc: 310"; rLen = 0; rLoc = 11071; rType = 0; vrLen = 1199; vrLoc = 2596; }; ACBF6FF30B7326D6004A69E7 /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = AC5A53E20AC09A6400622F72 /* fweelin_event.h */; name = "fweelin_event.h: 13"; rLen = 0; rLoc = 154; rType = 0; vrLen = 556; vrLoc = 0; }; ACE0E72E0AC9CF47007E3ED2 /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = AC5A53D50AC09A6400622F72 /* fweelin_block.cc */; name = "fweelin_block.cc: 5"; rLen = 0; rLoc = 62; rType = 0; vrLen = 884; vrLoc = 0; }; ACE0E94B0ACA196D007E3ED2 /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = AC5A53E10AC09A6400622F72 /* fweelin_event.cc */; name = "fweelin_event.cc: 34"; rLen = 0; rLoc = 513; rType = 0; vrLen = 1168; vrLoc = 2155; }; ACE0E9A30ACA1CC1007E3ED2 /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = AC5A53EB0AC09A6400622F72 /* fweelin_sdlio.h */; name = "fweelin_sdlio.h: 80"; rLen = 0; rLoc = 1751; rType = 0; vrLen = 710; vrLoc = 1415; }; ACF227730B6826DC005CFC14 /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = AC5A53E30AC09A6400622F72 /* fweelin_fluidsynth.cc */; name = "fweelin_fluidsynth.cc: 30"; rLen = 0; rLoc = 808; rType = 0; vrLen = 1161; vrLoc = 201; }; ACF227B50B682D68005CFC14 /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = AC5A53DD0AC09A6400622F72 /* fweelin_core.cc */; name = "fweelin_core.cc: 2474"; rLen = 0; rLoc = 73066; rType = 0; vrLen = 725; vrLoc = 72581; }; ACF227B70B682D68005CFC14 /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = AC5A53D80AC09A6400622F72 /* fweelin_browser.h */; name = "fweelin_browser.h: 389"; rLen = 0; rLoc = 11587; rType = 0; vrLen = 998; vrLoc = 10225; }; ACF227EF0B689BAA005CFC14 /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = AC5A53E80AC09A6400622F72 /* fweelin_midiio.cc */; name = "fweelin_midiio.cc: 897"; rLen = 0; rLoc = 25753; rType = 0; vrLen = 890; vrLoc = 25697; }; ACF227F10B689BAA005CFC14 /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = AC5A53E90AC09A6400622F72 /* fweelin_midiio.h */; name = "fweelin_midiio.h: MIDI_CLOCK_FREQUENCY"; rLen = 0; rLoc = 310; rType = 0; vrLen = 645; vrLoc = 0; }; ACF227F20B689BAA005CFC14 /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = AC5A53DB0AC09A6400622F72 /* fweelin_core_dsp.cc */; name = "fweelin_core_dsp.cc: 399"; rLen = 0; rLoc = 11396; rType = 0; vrLen = 1162; vrLoc = 11269; }; ACF2F7A10B4C70B2005197BB /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = AC126C3E0AC8EED400FE916E /* .fweelin.rc */; name = ".fweelin.rc: 2635"; rLen = 0; rLoc = 104754; rType = 0; vrLen = 1528; vrLoc = 45506; }; ACFC0A990AC99CDF00DAC478 /* FweelinMac.h */ = { uiCtxt = { sepNavIntBoundsRect = "{{0, 0}, {631, 504}}"; sepNavSelRange = "{605, 0}"; sepNavVisRect = "{{0, 42}, {631, 417}}"; sepNavWindowFrame = "{{50, 133}, {1131, 740}}"; }; }; ACFC0A9A0AC99CDF00DAC478 /* FweelinMac.mm */ = { uiCtxt = { sepNavIntBoundsRect = "{{0, 0}, {1166, 980}}"; sepNavSelRange = "{902, 0}"; sepNavVisRect = "{{0, 498}, {1166, 279}}"; sepNavWindowFrame = "{{73, 112}, {1131, 740}}"; }; }; ACFC0AB00AC99E2E00DAC478 /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = ACFC0A990AC99CDF00DAC478 /* FweelinMac.h */; name = "FweelinMac.h: 9"; rLen = 0; rLoc = 163; rType = 0; vrLen = 105; vrLoc = 0; }; ACFC0AB10AC99E2E00DAC478 /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = ACFC0A9A0AC99CDF00DAC478 /* FweelinMac.mm */; name = "FweelinMac.mm: 8"; rLen = 0; rLoc = 1307; rType = 0; vrLen = 61; vrLoc = 0; }; ACFC0B910AC9A70300DAC478 /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = AC5A53DC0AC09A6400622F72 /* fweelin_core_dsp.h */; name = "fweelin_core_dsp.h: 25"; rLen = 0; rLoc = 603; rType = 0; vrLen = 1315; vrLoc = 0; }; } freewheeling-0.6.6/MacOSX/fweelin.xcodeproj/project.pbxproj000066400000000000000000001137021370736313100237720ustar00rootroot00000000000000// !$*UTF8*$! { archiveVersion = 1; classes = { }; objectVersion = 42; objects = { /* Begin PBXBuildFile section */ 002F39FA09D0881F00EBEB88 /* SDL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 002F39F909D0881F00EBEB88 /* SDL.framework */; }; 002F3A0009D0884600EBEB88 /* SDL.framework in Copy Frameworks into .app bundle */ = {isa = PBXBuildFile; fileRef = 002F39F909D0881F00EBEB88 /* SDL.framework */; }; 002F3A2E09D0888800EBEB88 /* SDLMain.mm in Sources */ = {isa = PBXBuildFile; fileRef = 002F3A2C09D0888800EBEB88 /* SDLMain.mm */; }; 3D8261B70E96C8B600B480B6 /* Jackmp.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3D8261B60E96C8B600B480B6 /* Jackmp.framework */; }; 3D82625C0E96CDC700B480B6 /* fweelin.xml in Resources */ = {isa = PBXBuildFile; fileRef = 3D8262480E96CDC700B480B6 /* fweelin.xml */; }; 3D82625D0E96CDC700B480B6 /* coreinterface.xml in Resources */ = {isa = PBXBuildFile; fileRef = 3D8262490E96CDC700B480B6 /* coreinterface.xml */; }; 3D82625E0E96CDC700B480B6 /* interfaces.xml in Resources */ = {isa = PBXBuildFile; fileRef = 3D82624A0E96CDC700B480B6 /* interfaces.xml */; }; 3D82625F0E96CDC700B480B6 /* patches2.xml in Resources */ = {isa = PBXBuildFile; fileRef = 3D82624B0E96CDC700B480B6 /* patches2.xml */; }; 3D8262600E96CDC700B480B6 /* pcr-m1.xml in Resources */ = {isa = PBXBuildFile; fileRef = 3D82624C0E96CDC700B480B6 /* pcr-m1.xml */; }; 3D8262610E96CDC700B480B6 /* pckeyboard.xml in Resources */ = {isa = PBXBuildFile; fileRef = 3D82624D0E96CDC700B480B6 /* pckeyboard.xml */; }; 3D8262620E96CDC700B480B6 /* patches-strings.xml in Resources */ = {isa = PBXBuildFile; fileRef = 3D82624E0E96CDC700B480B6 /* patches-strings.xml */; }; 3D8262630E96CDC700B480B6 /* mercury.xml in Resources */ = {isa = PBXBuildFile; fileRef = 3D82624F0E96CDC700B480B6 /* mercury.xml */; }; 3D8262640E96CDC700B480B6 /* bcf2000.xml in Resources */ = {isa = PBXBuildFile; fileRef = 3D8262500E96CDC700B480B6 /* bcf2000.xml */; }; 3D8262650E96CDC700B480B6 /* midifootswitch.xml in Resources */ = {isa = PBXBuildFile; fileRef = 3D8262510E96CDC700B480B6 /* midifootswitch.xml */; }; 3D8262660E96CDC700B480B6 /* dancemat.xml in Resources */ = {isa = PBXBuildFile; fileRef = 3D8262520E96CDC700B480B6 /* dancemat.xml */; }; 3D8262670E96CDC700B480B6 /* graphics.xml in Resources */ = {isa = PBXBuildFile; fileRef = 3D8262530E96CDC700B480B6 /* graphics.xml */; }; 3D8262680E96CDC700B480B6 /* patches-channels.xml in Resources */ = {isa = PBXBuildFile; fileRef = 3D8262540E96CDC700B480B6 /* patches-channels.xml */; }; 3D8262690E96CDC700B480B6 /* basics.xml in Resources */ = {isa = PBXBuildFile; fileRef = 3D8262550E96CDC700B480B6 /* basics.xml */; }; 3D82626A0E96CDC700B480B6 /* browsers.xml in Resources */ = {isa = PBXBuildFile; fileRef = 3D8262560E96CDC700B480B6 /* browsers.xml */; }; 3D82626B0E96CDC700B480B6 /* midikeyboard.xml in Resources */ = {isa = PBXBuildFile; fileRef = 3D8262570E96CDC700B480B6 /* midikeyboard.xml */; }; 3D82626C0E96CDC700B480B6 /* patches1.xml in Resources */ = {isa = PBXBuildFile; fileRef = 3D8262580E96CDC700B480B6 /* patches1.xml */; }; 3D82626E0E96CDC700B480B6 /* patches-b3.xml in Resources */ = {isa = PBXBuildFile; fileRef = 3D82625A0E96CDC700B480B6 /* patches-b3.xml */; }; 3D82626F0E96CDC700B480B6 /* patches3.xml in Resources */ = {isa = PBXBuildFile; fileRef = 3D82625B0E96CDC700B480B6 /* patches3.xml */; }; 8D11072B0486CEB800E47090 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 089C165CFE840E0CC02AAC07 /* InfoPlist.strings */; }; 8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */; }; AC12675D0AC8E0BE00FE916E /* CoreMIDI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AC12675C0AC8E0BE00FE916E /* CoreMIDI.framework */; }; AC126C440AC8EF4000FE916E /* verabd.ttf in Resources */ = {isa = PBXBuildFile; fileRef = AC126C420AC8EF4000FE916E /* verabd.ttf */; }; AC126C450AC8EF4000FE916E /* vera.ttf in Resources */ = {isa = PBXBuildFile; fileRef = AC126C430AC8EF4000FE916E /* vera.ttf */; }; AC5A532A0AC099C900622F72 /* Ogg.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AC5A53240AC099C900622F72 /* Ogg.framework */; }; AC5A532B0AC099C900622F72 /* SDL_gfx.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AC5A53250AC099C900622F72 /* SDL_gfx.framework */; }; AC5A532C0AC099C900622F72 /* SDL_ttf.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AC5A53260AC099C900622F72 /* SDL_ttf.framework */; }; AC5A532D0AC099C900622F72 /* Vorbis.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AC5A53270AC099C900622F72 /* Vorbis.framework */; }; AC5A53EF0AC09A6400622F72 /* fweelin_audioio.cc in Sources */ = {isa = PBXBuildFile; fileRef = AC5A53D30AC09A6400622F72 /* fweelin_audioio.cc */; }; AC5A53F10AC09A6400622F72 /* fweelin_block.cc in Sources */ = {isa = PBXBuildFile; fileRef = AC5A53D50AC09A6400622F72 /* fweelin_block.cc */; }; AC5A53F30AC09A6400622F72 /* fweelin_browser.cc in Sources */ = {isa = PBXBuildFile; fileRef = AC5A53D70AC09A6400622F72 /* fweelin_browser.cc */; }; AC5A53F50AC09A6400622F72 /* fweelin_config.cc in Sources */ = {isa = PBXBuildFile; fileRef = AC5A53D90AC09A6400622F72 /* fweelin_config.cc */; }; AC5A53F70AC09A6400622F72 /* fweelin_core_dsp.cc in Sources */ = {isa = PBXBuildFile; fileRef = AC5A53DB0AC09A6400622F72 /* fweelin_core_dsp.cc */; }; AC5A53F90AC09A6400622F72 /* fweelin_core.cc in Sources */ = {isa = PBXBuildFile; fileRef = AC5A53DD0AC09A6400622F72 /* fweelin_core.cc */; }; AC5A53FB0AC09A6400622F72 /* fweelin_datatypes.cc in Sources */ = {isa = PBXBuildFile; fileRef = AC5A53DF0AC09A6400622F72 /* fweelin_datatypes.cc */; }; AC5A53FD0AC09A6400622F72 /* fweelin_event.cc in Sources */ = {isa = PBXBuildFile; fileRef = AC5A53E10AC09A6400622F72 /* fweelin_event.cc */; }; AC5A53FF0AC09A6400622F72 /* fweelin_fluidsynth.cc in Sources */ = {isa = PBXBuildFile; fileRef = AC5A53E30AC09A6400622F72 /* fweelin_fluidsynth.cc */; }; AC5A54020AC09A6400622F72 /* fweelin_mem.cc in Sources */ = {isa = PBXBuildFile; fileRef = AC5A53E60AC09A6400622F72 /* fweelin_mem.cc */; }; AC5A54040AC09A6400622F72 /* fweelin_midiio.cc in Sources */ = {isa = PBXBuildFile; fileRef = AC5A53E80AC09A6400622F72 /* fweelin_midiio.cc */; }; AC5A54060AC09A6400622F72 /* fweelin_sdlio.cc in Sources */ = {isa = PBXBuildFile; fileRef = AC5A53EA0AC09A6400622F72 /* fweelin_sdlio.cc */; }; AC5A54080AC09A6400622F72 /* fweelin_videoio.cc in Sources */ = {isa = PBXBuildFile; fileRef = AC5A53EC0AC09A6400622F72 /* fweelin_videoio.cc */; }; AC5A540A0AC09A6400622F72 /* fweelin.cc in Sources */ = {isa = PBXBuildFile; fileRef = AC5A53EE0AC09A6400622F72 /* fweelin.cc */; }; AC6429D90AD9C85700752A08 /* Sndfile.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AC6429D80AD9C85700752A08 /* Sndfile.framework */; }; AC6429DC0AD9C85C00752A08 /* Sndfile.framework in Copy Frameworks into .app bundle */ = {isa = PBXBuildFile; fileRef = AC6429D80AD9C85700752A08 /* Sndfile.framework */; }; AC776D470B69B161005E3D84 /* freewheeling.icns in Resources */ = {isa = PBXBuildFile; fileRef = AC776D460B69B161005E3D84 /* freewheeling.icns */; }; ACA2C53F0B06DCB600E02DC6 /* SDLMain.nib in Resources */ = {isa = PBXBuildFile; fileRef = ACA2C53E0B06DCB600E02DC6 /* SDLMain.nib */; }; ACE0E9170ACA15B4007E3ED2 /* Ogg.framework in Copy Frameworks into .app bundle */ = {isa = PBXBuildFile; fileRef = AC5A53240AC099C900622F72 /* Ogg.framework */; }; ACE0E9180ACA15B4007E3ED2 /* SDL_gfx.framework in Copy Frameworks into .app bundle */ = {isa = PBXBuildFile; fileRef = AC5A53250AC099C900622F72 /* SDL_gfx.framework */; }; ACE0E9190ACA15B4007E3ED2 /* SDL_ttf.framework in Copy Frameworks into .app bundle */ = {isa = PBXBuildFile; fileRef = AC5A53260AC099C900622F72 /* SDL_ttf.framework */; }; ACE0E91A0ACA15B4007E3ED2 /* Vorbis.framework in Copy Frameworks into .app bundle */ = {isa = PBXBuildFile; fileRef = AC5A53270AC099C900622F72 /* Vorbis.framework */; }; ACFC0A9C0AC99CDF00DAC478 /* FweelinMac.mm in Sources */ = {isa = PBXBuildFile; fileRef = ACFC0A9A0AC99CDF00DAC478 /* FweelinMac.mm */; }; /* End PBXBuildFile section */ /* Begin PBXCopyFilesBuildPhase section */ 002F39FD09D0883400EBEB88 /* Copy Frameworks into .app bundle */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; dstPath = ""; dstSubfolderSpec = 10; files = ( AC6429DC0AD9C85C00752A08 /* Sndfile.framework in Copy Frameworks into .app bundle */, ACE0E9190ACA15B4007E3ED2 /* SDL_ttf.framework in Copy Frameworks into .app bundle */, ACE0E9180ACA15B4007E3ED2 /* SDL_gfx.framework in Copy Frameworks into .app bundle */, 002F3A0009D0884600EBEB88 /* SDL.framework in Copy Frameworks into .app bundle */, ACE0E9170ACA15B4007E3ED2 /* Ogg.framework in Copy Frameworks into .app bundle */, ACE0E91A0ACA15B4007E3ED2 /* Vorbis.framework in Copy Frameworks into .app bundle */, ); name = "Copy Frameworks into .app bundle"; runOnlyForDeploymentPostprocessing = 0; }; /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ 002F39F909D0881F00EBEB88 /* SDL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SDL.framework; path = /Library/Frameworks/SDL.framework; sourceTree = ""; }; 002F3A2B09D0888800EBEB88 /* SDLMain.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = SDLMain.h; sourceTree = SOURCE_ROOT; }; 002F3A2C09D0888800EBEB88 /* SDLMain.mm */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.objcpp; path = SDLMain.mm; sourceTree = ""; }; 089C165DFE840E0CC02AAC07 /* English */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = English; path = English.lproj/InfoPlist.strings; sourceTree = ""; }; 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = /System/Library/Frameworks/Cocoa.framework; sourceTree = ""; }; 29B97324FDCFA39411CA2CEA /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = /System/Library/Frameworks/AppKit.framework; sourceTree = ""; }; 29B97325FDCFA39411CA2CEA /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = ""; }; 32CA4F630368D1EE00C91783 /* fweelin_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = fweelin_Prefix.pch; sourceTree = ""; }; 3D8261B60E96C8B600B480B6 /* Jackmp.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Jackmp.framework; path = /Library/Frameworks/Jackmp.framework; sourceTree = ""; }; 3D8262480E96CDC700B480B6 /* fweelin.xml */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; name = fweelin.xml; path = ../data/fweelin.xml; sourceTree = SOURCE_ROOT; }; 3D8262490E96CDC700B480B6 /* coreinterface.xml */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; name = coreinterface.xml; path = ../data/coreinterface.xml; sourceTree = SOURCE_ROOT; }; 3D82624A0E96CDC700B480B6 /* interfaces.xml */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; name = interfaces.xml; path = ../data/interfaces.xml; sourceTree = SOURCE_ROOT; }; 3D82624B0E96CDC700B480B6 /* patches2.xml */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; name = patches2.xml; path = ../data/patches2.xml; sourceTree = SOURCE_ROOT; }; 3D82624C0E96CDC700B480B6 /* pcr-m1.xml */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; name = "pcr-m1.xml"; path = "../data/pcr-m1.xml"; sourceTree = SOURCE_ROOT; }; 3D82624D0E96CDC700B480B6 /* pckeyboard.xml */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; name = pckeyboard.xml; path = ../data/pckeyboard.xml; sourceTree = SOURCE_ROOT; }; 3D82624E0E96CDC700B480B6 /* patches-strings.xml */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; name = "patches-strings.xml"; path = "../data/patches-strings.xml"; sourceTree = SOURCE_ROOT; }; 3D82624F0E96CDC700B480B6 /* mercury.xml */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; name = mercury.xml; path = ../data/mercury.xml; sourceTree = SOURCE_ROOT; }; 3D8262500E96CDC700B480B6 /* bcf2000.xml */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; name = bcf2000.xml; path = ../data/bcf2000.xml; sourceTree = SOURCE_ROOT; }; 3D8262510E96CDC700B480B6 /* midifootswitch.xml */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; name = midifootswitch.xml; path = ../data/midifootswitch.xml; sourceTree = SOURCE_ROOT; }; 3D8262520E96CDC700B480B6 /* dancemat.xml */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; name = dancemat.xml; path = ../data/dancemat.xml; sourceTree = SOURCE_ROOT; }; 3D8262530E96CDC700B480B6 /* graphics.xml */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; name = graphics.xml; path = ../data/graphics.xml; sourceTree = SOURCE_ROOT; }; 3D8262540E96CDC700B480B6 /* patches-channels.xml */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; name = "patches-channels.xml"; path = "../data/patches-channels.xml"; sourceTree = SOURCE_ROOT; }; 3D8262550E96CDC700B480B6 /* basics.xml */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; name = basics.xml; path = ../data/basics.xml; sourceTree = SOURCE_ROOT; }; 3D8262560E96CDC700B480B6 /* browsers.xml */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; name = browsers.xml; path = ../data/browsers.xml; sourceTree = SOURCE_ROOT; }; 3D8262570E96CDC700B480B6 /* midikeyboard.xml */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; name = midikeyboard.xml; path = ../data/midikeyboard.xml; sourceTree = SOURCE_ROOT; }; 3D8262580E96CDC700B480B6 /* patches1.xml */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; name = patches1.xml; path = ../data/patches1.xml; sourceTree = SOURCE_ROOT; }; 3D82625A0E96CDC700B480B6 /* patches-b3.xml */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; name = "patches-b3.xml"; path = "../data/patches-b3.xml"; sourceTree = SOURCE_ROOT; }; 3D82625B0E96CDC700B480B6 /* patches3.xml */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; name = patches3.xml; path = ../data/patches3.xml; sourceTree = SOURCE_ROOT; }; 8D1107310486CEB800E47090 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist; path = Info.plist; sourceTree = ""; }; 8D1107320486CEB800E47090 /* fweelin.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = fweelin.app; sourceTree = BUILT_PRODUCTS_DIR; }; AC12675C0AC8E0BE00FE916E /* CoreMIDI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreMIDI.framework; path = /System/Library/Frameworks/CoreMIDI.framework; sourceTree = ""; }; AC126C420AC8EF4000FE916E /* verabd.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; name = verabd.ttf; path = ../data/verabd.ttf; sourceTree = SOURCE_ROOT; }; AC126C430AC8EF4000FE916E /* vera.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; name = vera.ttf; path = ../data/vera.ttf; sourceTree = SOURCE_ROOT; }; AC5A53240AC099C900622F72 /* Ogg.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Ogg.framework; path = /Library/Frameworks/Ogg.framework; sourceTree = ""; }; AC5A53250AC099C900622F72 /* SDL_gfx.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SDL_gfx.framework; path = /Library/Frameworks/SDL_gfx.framework; sourceTree = ""; }; AC5A53260AC099C900622F72 /* SDL_ttf.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SDL_ttf.framework; path = /Library/Frameworks/SDL_ttf.framework; sourceTree = ""; }; AC5A53270AC099C900622F72 /* Vorbis.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Vorbis.framework; path = /Library/Frameworks/Vorbis.framework; sourceTree = ""; }; AC5A53D30AC09A6400622F72 /* fweelin_audioio.cc */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = fweelin_audioio.cc; path = ../src/fweelin_audioio.cc; sourceTree = SOURCE_ROOT; tabWidth = 8; }; AC5A53D40AC09A6400622F72 /* fweelin_audioio.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = fweelin_audioio.h; path = ../src/fweelin_audioio.h; sourceTree = SOURCE_ROOT; tabWidth = 8; }; AC5A53D50AC09A6400622F72 /* fweelin_block.cc */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = fweelin_block.cc; path = ../src/fweelin_block.cc; sourceTree = SOURCE_ROOT; tabWidth = 8; }; AC5A53D60AC09A6400622F72 /* fweelin_block.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = fweelin_block.h; path = ../src/fweelin_block.h; sourceTree = SOURCE_ROOT; tabWidth = 8; }; AC5A53D70AC09A6400622F72 /* fweelin_browser.cc */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = fweelin_browser.cc; path = ../src/fweelin_browser.cc; sourceTree = SOURCE_ROOT; tabWidth = 8; }; AC5A53D80AC09A6400622F72 /* fweelin_browser.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = fweelin_browser.h; path = ../src/fweelin_browser.h; sourceTree = SOURCE_ROOT; tabWidth = 8; }; AC5A53D90AC09A6400622F72 /* fweelin_config.cc */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = fweelin_config.cc; path = ../src/fweelin_config.cc; sourceTree = SOURCE_ROOT; tabWidth = 8; }; AC5A53DA0AC09A6400622F72 /* fweelin_config.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = fweelin_config.h; path = ../src/fweelin_config.h; sourceTree = SOURCE_ROOT; tabWidth = 8; }; AC5A53DB0AC09A6400622F72 /* fweelin_core_dsp.cc */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = fweelin_core_dsp.cc; path = ../src/fweelin_core_dsp.cc; sourceTree = SOURCE_ROOT; tabWidth = 8; }; AC5A53DC0AC09A6400622F72 /* fweelin_core_dsp.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = fweelin_core_dsp.h; path = ../src/fweelin_core_dsp.h; sourceTree = SOURCE_ROOT; tabWidth = 8; }; AC5A53DD0AC09A6400622F72 /* fweelin_core.cc */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = fweelin_core.cc; path = ../src/fweelin_core.cc; sourceTree = SOURCE_ROOT; tabWidth = 8; }; AC5A53DE0AC09A6400622F72 /* fweelin_core.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = fweelin_core.h; path = ../src/fweelin_core.h; sourceTree = SOURCE_ROOT; tabWidth = 8; }; AC5A53DF0AC09A6400622F72 /* fweelin_datatypes.cc */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = fweelin_datatypes.cc; path = ../src/fweelin_datatypes.cc; sourceTree = SOURCE_ROOT; tabWidth = 8; }; AC5A53E00AC09A6400622F72 /* fweelin_datatypes.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = fweelin_datatypes.h; path = ../src/fweelin_datatypes.h; sourceTree = SOURCE_ROOT; tabWidth = 8; }; AC5A53E10AC09A6400622F72 /* fweelin_event.cc */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = fweelin_event.cc; path = ../src/fweelin_event.cc; sourceTree = SOURCE_ROOT; tabWidth = 8; }; AC5A53E20AC09A6400622F72 /* fweelin_event.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = fweelin_event.h; path = ../src/fweelin_event.h; sourceTree = SOURCE_ROOT; tabWidth = 8; }; AC5A53E30AC09A6400622F72 /* fweelin_fluidsynth.cc */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = fweelin_fluidsynth.cc; path = ../src/fweelin_fluidsynth.cc; sourceTree = SOURCE_ROOT; tabWidth = 8; }; AC5A53E40AC09A6400622F72 /* fweelin_fluidsynth.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = fweelin_fluidsynth.h; path = ../src/fweelin_fluidsynth.h; sourceTree = SOURCE_ROOT; tabWidth = 8; }; AC5A53E50AC09A6400622F72 /* fweelin_logo.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = fweelin_logo.h; path = ../src/fweelin_logo.h; sourceTree = SOURCE_ROOT; tabWidth = 8; }; AC5A53E60AC09A6400622F72 /* fweelin_mem.cc */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = fweelin_mem.cc; path = ../src/fweelin_mem.cc; sourceTree = SOURCE_ROOT; tabWidth = 8; }; AC5A53E70AC09A6400622F72 /* fweelin_mem.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = fweelin_mem.h; path = ../src/fweelin_mem.h; sourceTree = SOURCE_ROOT; tabWidth = 8; }; AC5A53E80AC09A6400622F72 /* fweelin_midiio.cc */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = fweelin_midiio.cc; path = ../src/fweelin_midiio.cc; sourceTree = SOURCE_ROOT; tabWidth = 8; }; AC5A53E90AC09A6400622F72 /* fweelin_midiio.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = fweelin_midiio.h; path = ../src/fweelin_midiio.h; sourceTree = SOURCE_ROOT; tabWidth = 8; }; AC5A53EA0AC09A6400622F72 /* fweelin_sdlio.cc */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = fweelin_sdlio.cc; path = ../src/fweelin_sdlio.cc; sourceTree = SOURCE_ROOT; tabWidth = 8; usesTabs = 1; }; AC5A53EB0AC09A6400622F72 /* fweelin_sdlio.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = fweelin_sdlio.h; path = ../src/fweelin_sdlio.h; sourceTree = SOURCE_ROOT; tabWidth = 8; }; AC5A53EC0AC09A6400622F72 /* fweelin_videoio.cc */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = fweelin_videoio.cc; path = ../src/fweelin_videoio.cc; sourceTree = SOURCE_ROOT; tabWidth = 8; }; AC5A53ED0AC09A6400622F72 /* fweelin_videoio.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = fweelin_videoio.h; path = ../src/fweelin_videoio.h; sourceTree = SOURCE_ROOT; tabWidth = 8; }; AC5A53EE0AC09A6400622F72 /* fweelin.cc */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = fweelin.cc; path = ../src/fweelin.cc; sourceTree = SOURCE_ROOT; tabWidth = 8; }; AC6429D80AD9C85700752A08 /* Sndfile.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Sndfile.framework; path = /Library/Frameworks/Sndfile.framework; sourceTree = ""; }; AC776D460B69B161005E3D84 /* freewheeling.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; path = freewheeling.icns; sourceTree = ""; }; ACA2C53E0B06DCB600E02DC6 /* SDLMain.nib */ = {isa = PBXFileReference; lastKnownFileType = wrapper.nib; path = SDLMain.nib; sourceTree = ""; }; ACFC0A990AC99CDF00DAC478 /* FweelinMac.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FweelinMac.h; sourceTree = ""; }; ACFC0A9A0AC99CDF00DAC478 /* FweelinMac.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FweelinMac.mm; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ 8D11072E0486CEB800E47090 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( 002F39FA09D0881F00EBEB88 /* SDL.framework in Frameworks */, 8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */, AC5A532A0AC099C900622F72 /* Ogg.framework in Frameworks */, AC5A532B0AC099C900622F72 /* SDL_gfx.framework in Frameworks */, AC5A532C0AC099C900622F72 /* SDL_ttf.framework in Frameworks */, AC5A532D0AC099C900622F72 /* Vorbis.framework in Frameworks */, AC12675D0AC8E0BE00FE916E /* CoreMIDI.framework in Frameworks */, AC6429D90AD9C85700752A08 /* Sndfile.framework in Frameworks */, 3D8261B70E96C8B600B480B6 /* Jackmp.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ 080E96DDFE201D6D7F000001 /* Classes */ = { isa = PBXGroup; children = ( AC5A53D30AC09A6400622F72 /* fweelin_audioio.cc */, AC5A53D40AC09A6400622F72 /* fweelin_audioio.h */, AC5A53D50AC09A6400622F72 /* fweelin_block.cc */, AC5A53D60AC09A6400622F72 /* fweelin_block.h */, AC5A53D70AC09A6400622F72 /* fweelin_browser.cc */, AC5A53D80AC09A6400622F72 /* fweelin_browser.h */, AC5A53D90AC09A6400622F72 /* fweelin_config.cc */, AC5A53DA0AC09A6400622F72 /* fweelin_config.h */, AC5A53DB0AC09A6400622F72 /* fweelin_core_dsp.cc */, AC5A53DC0AC09A6400622F72 /* fweelin_core_dsp.h */, AC5A53DD0AC09A6400622F72 /* fweelin_core.cc */, AC5A53DE0AC09A6400622F72 /* fweelin_core.h */, AC5A53DF0AC09A6400622F72 /* fweelin_datatypes.cc */, AC5A53E00AC09A6400622F72 /* fweelin_datatypes.h */, AC5A53E10AC09A6400622F72 /* fweelin_event.cc */, AC5A53E20AC09A6400622F72 /* fweelin_event.h */, AC5A53E30AC09A6400622F72 /* fweelin_fluidsynth.cc */, AC5A53E40AC09A6400622F72 /* fweelin_fluidsynth.h */, AC5A53E50AC09A6400622F72 /* fweelin_logo.h */, AC5A53E60AC09A6400622F72 /* fweelin_mem.cc */, AC5A53E70AC09A6400622F72 /* fweelin_mem.h */, AC5A53E80AC09A6400622F72 /* fweelin_midiio.cc */, AC5A53E90AC09A6400622F72 /* fweelin_midiio.h */, AC5A53EA0AC09A6400622F72 /* fweelin_sdlio.cc */, AC5A53EB0AC09A6400622F72 /* fweelin_sdlio.h */, AC5A53EC0AC09A6400622F72 /* fweelin_videoio.cc */, AC5A53ED0AC09A6400622F72 /* fweelin_videoio.h */, AC5A53EE0AC09A6400622F72 /* fweelin.cc */, ACFC0A990AC99CDF00DAC478 /* FweelinMac.h */, ACFC0A9A0AC99CDF00DAC478 /* FweelinMac.mm */, 002F3A2B09D0888800EBEB88 /* SDLMain.h */, 002F3A2C09D0888800EBEB88 /* SDLMain.mm */, ACA2C53E0B06DCB600E02DC6 /* SDLMain.nib */, ); name = Classes; sourceTree = ""; }; 1058C7A0FEA54F0111CA2CBB /* Linked Frameworks */ = { isa = PBXGroup; children = ( 3D8261B60E96C8B600B480B6 /* Jackmp.framework */, AC6429D80AD9C85700752A08 /* Sndfile.framework */, AC12675C0AC8E0BE00FE916E /* CoreMIDI.framework */, AC5A53240AC099C900622F72 /* Ogg.framework */, AC5A53250AC099C900622F72 /* SDL_gfx.framework */, AC5A53260AC099C900622F72 /* SDL_ttf.framework */, AC5A53270AC099C900622F72 /* Vorbis.framework */, 002F39F909D0881F00EBEB88 /* SDL.framework */, 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */, ); name = "Linked Frameworks"; sourceTree = ""; }; 1058C7A2FEA54F0111CA2CBB /* Other Frameworks */ = { isa = PBXGroup; children = ( 29B97324FDCFA39411CA2CEA /* AppKit.framework */, 29B97325FDCFA39411CA2CEA /* Foundation.framework */, ); name = "Other Frameworks"; sourceTree = ""; }; 19C28FACFE9D520D11CA2CBB /* Products */ = { isa = PBXGroup; children = ( 8D1107320486CEB800E47090 /* fweelin.app */, ); name = Products; sourceTree = ""; }; 29B97314FDCFA39411CA2CEA /* fweelin */ = { isa = PBXGroup; children = ( 080E96DDFE201D6D7F000001 /* Classes */, 29B97315FDCFA39411CA2CEA /* Other Sources */, 29B97317FDCFA39411CA2CEA /* Resources */, 29B97323FDCFA39411CA2CEA /* Frameworks */, 19C28FACFE9D520D11CA2CBB /* Products */, ); name = fweelin; sourceTree = ""; }; 29B97315FDCFA39411CA2CEA /* Other Sources */ = { isa = PBXGroup; children = ( 32CA4F630368D1EE00C91783 /* fweelin_Prefix.pch */, ); name = "Other Sources"; sourceTree = ""; }; 29B97317FDCFA39411CA2CEA /* Resources */ = { isa = PBXGroup; children = ( 3D8262480E96CDC700B480B6 /* fweelin.xml */, 3D8262490E96CDC700B480B6 /* coreinterface.xml */, 3D82624A0E96CDC700B480B6 /* interfaces.xml */, 3D82624B0E96CDC700B480B6 /* patches2.xml */, 3D82624C0E96CDC700B480B6 /* pcr-m1.xml */, 3D82624D0E96CDC700B480B6 /* pckeyboard.xml */, 3D82624E0E96CDC700B480B6 /* patches-strings.xml */, 3D82624F0E96CDC700B480B6 /* mercury.xml */, 3D8262500E96CDC700B480B6 /* bcf2000.xml */, 3D8262510E96CDC700B480B6 /* midifootswitch.xml */, 3D8262520E96CDC700B480B6 /* dancemat.xml */, 3D8262530E96CDC700B480B6 /* graphics.xml */, 3D8262540E96CDC700B480B6 /* patches-channels.xml */, 3D8262550E96CDC700B480B6 /* basics.xml */, 3D8262560E96CDC700B480B6 /* browsers.xml */, 3D8262570E96CDC700B480B6 /* midikeyboard.xml */, 3D8262580E96CDC700B480B6 /* patches1.xml */, 3D82625A0E96CDC700B480B6 /* patches-b3.xml */, 3D82625B0E96CDC700B480B6 /* patches3.xml */, AC776D460B69B161005E3D84 /* freewheeling.icns */, AC126C420AC8EF4000FE916E /* verabd.ttf */, AC126C430AC8EF4000FE916E /* vera.ttf */, 8D1107310486CEB800E47090 /* Info.plist */, 089C165CFE840E0CC02AAC07 /* InfoPlist.strings */, ); name = Resources; sourceTree = ""; }; 29B97323FDCFA39411CA2CEA /* Frameworks */ = { isa = PBXGroup; children = ( 1058C7A0FEA54F0111CA2CBB /* Linked Frameworks */, 1058C7A2FEA54F0111CA2CBB /* Other Frameworks */, ); name = Frameworks; sourceTree = ""; }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ 8D1107260486CEB800E47090 /* fweelin */ = { isa = PBXNativeTarget; buildConfigurationList = C01FCF4A08A954540054247B /* Build configuration list for PBXNativeTarget "fweelin" */; buildPhases = ( 8D1107290486CEB800E47090 /* Resources */, 8D11072C0486CEB800E47090 /* Sources */, 8D11072E0486CEB800E47090 /* Frameworks */, 002F39FD09D0883400EBEB88 /* Copy Frameworks into .app bundle */, ); buildRules = ( ); dependencies = ( ); name = fweelin; productInstallPath = "$(HOME)/Applications"; productName = fweelin; productReference = 8D1107320486CEB800E47090 /* fweelin.app */; productType = "com.apple.product-type.application"; }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ 29B97313FDCFA39411CA2CEA /* Project object */ = { isa = PBXProject; buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "fweelin" */; compatibilityVersion = "Xcode 2.4"; hasScannedForEncodings = 1; mainGroup = 29B97314FDCFA39411CA2CEA /* fweelin */; projectDirPath = ""; projectRoot = ""; targets = ( 8D1107260486CEB800E47090 /* fweelin */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ 8D1107290486CEB800E47090 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( 8D11072B0486CEB800E47090 /* InfoPlist.strings in Resources */, AC126C440AC8EF4000FE916E /* verabd.ttf in Resources */, AC126C450AC8EF4000FE916E /* vera.ttf in Resources */, ACA2C53F0B06DCB600E02DC6 /* SDLMain.nib in Resources */, AC776D470B69B161005E3D84 /* freewheeling.icns in Resources */, 3D82625C0E96CDC700B480B6 /* fweelin.xml in Resources */, 3D82625D0E96CDC700B480B6 /* coreinterface.xml in Resources */, 3D82625E0E96CDC700B480B6 /* interfaces.xml in Resources */, 3D82625F0E96CDC700B480B6 /* patches2.xml in Resources */, 3D8262600E96CDC700B480B6 /* pcr-m1.xml in Resources */, 3D8262610E96CDC700B480B6 /* pckeyboard.xml in Resources */, 3D8262620E96CDC700B480B6 /* patches-strings.xml in Resources */, 3D8262630E96CDC700B480B6 /* mercury.xml in Resources */, 3D8262640E96CDC700B480B6 /* bcf2000.xml in Resources */, 3D8262650E96CDC700B480B6 /* midifootswitch.xml in Resources */, 3D8262660E96CDC700B480B6 /* dancemat.xml in Resources */, 3D8262670E96CDC700B480B6 /* graphics.xml in Resources */, 3D8262680E96CDC700B480B6 /* patches-channels.xml in Resources */, 3D8262690E96CDC700B480B6 /* basics.xml in Resources */, 3D82626A0E96CDC700B480B6 /* browsers.xml in Resources */, 3D82626B0E96CDC700B480B6 /* midikeyboard.xml in Resources */, 3D82626C0E96CDC700B480B6 /* patches1.xml in Resources */, 3D82626E0E96CDC700B480B6 /* patches-b3.xml in Resources */, 3D82626F0E96CDC700B480B6 /* patches3.xml in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXResourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ 8D11072C0486CEB800E47090 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 002F3A2E09D0888800EBEB88 /* SDLMain.mm in Sources */, AC5A53EF0AC09A6400622F72 /* fweelin_audioio.cc in Sources */, AC5A53F10AC09A6400622F72 /* fweelin_block.cc in Sources */, AC5A53F30AC09A6400622F72 /* fweelin_browser.cc in Sources */, AC5A53F50AC09A6400622F72 /* fweelin_config.cc in Sources */, AC5A53F70AC09A6400622F72 /* fweelin_core_dsp.cc in Sources */, AC5A53F90AC09A6400622F72 /* fweelin_core.cc in Sources */, AC5A53FB0AC09A6400622F72 /* fweelin_datatypes.cc in Sources */, AC5A53FD0AC09A6400622F72 /* fweelin_event.cc in Sources */, AC5A53FF0AC09A6400622F72 /* fweelin_fluidsynth.cc in Sources */, AC5A54020AC09A6400622F72 /* fweelin_mem.cc in Sources */, AC5A54040AC09A6400622F72 /* fweelin_midiio.cc in Sources */, AC5A54060AC09A6400622F72 /* fweelin_sdlio.cc in Sources */, AC5A54080AC09A6400622F72 /* fweelin_videoio.cc in Sources */, AC5A540A0AC09A6400622F72 /* fweelin.cc in Sources */, ACFC0A9C0AC99CDF00DAC478 /* FweelinMac.mm in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin PBXVariantGroup section */ 089C165CFE840E0CC02AAC07 /* InfoPlist.strings */ = { isa = PBXVariantGroup; children = ( 089C165DFE840E0CC02AAC07 /* English */, ); name = InfoPlist.strings; sourceTree = ""; }; /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ C01FCF4B08A954540054247B /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { COPY_PHASE_STRIP = NO; GCC_DYNAMIC_NO_PIC = NO; GCC_ENABLE_FIX_AND_CONTINUE = YES; GCC_MODEL_TUNING = G5; GCC_OPTIMIZATION_LEVEL = 0; INFOPLIST_FILE = Info.plist; INSTALL_PATH = "$(HOME)/Applications"; PRODUCT_NAME = fweelin; WRAPPER_EXTENSION = app; ZERO_LINK = YES; }; name = Debug; }; C01FCF4C08A954540054247B /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ARCHS = ( ppc, i386, ); GCC_GENERATE_DEBUGGING_SYMBOLS = NO; GCC_MODEL_TUNING = G5; INFOPLIST_FILE = Info.plist; INSTALL_PATH = "$(HOME)/Applications"; PRODUCT_NAME = fweelin; WRAPPER_EXTENSION = app; }; name = Release; }; C01FCF4F08A954540054247B /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ARCHS = ( i386, ppc, ); FRAMEWORK_SEARCH_PATHS = ( "$(HOME)/Library/Frameworks", /Library/Frameworks, "$(FRAMEWORK_SEARCH_PATHS)", ); GCC_GENERATE_DEBUGGING_SYMBOLS = YES; GCC_OPTIMIZATION_LEVEL = 3; GCC_WARN_ABOUT_RETURN_TYPE = YES; GCC_WARN_UNUSED_VARIABLE = YES; HEADER_SEARCH_PATHS = ( "$(HOME)/Library/Frameworks/SDL.framework/Headers", /Library/Frameworks/SDL.framework/Headers, "$(HEADER_SEARCH_PATHS)", /usr/include/libxml2, ); OTHER_CFLAGS = ( "-D", __MACOSX__, "-fpermissive", ); OTHER_LDFLAGS = ( "-lcrypto", "-lxml2", ); PREBINDING = NO; PRODUCT_NAME = FreeWheeling; ZERO_LINK = NO; }; name = Debug; }; C01FCF5008A954540054247B /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ARCHS = ( i386, ppc, ); FRAMEWORK_SEARCH_PATHS = ( "$(HOME)/Library/Frameworks", /Library/Frameworks, "$(FRAMEWORK_SEARCH_PATHS)", ); GCC_GENERATE_DEBUGGING_SYMBOLS = YES; GCC_OPTIMIZATION_LEVEL = 3; GCC_WARN_ABOUT_RETURN_TYPE = YES; GCC_WARN_UNUSED_VARIABLE = YES; HEADER_SEARCH_PATHS = ( /Library/Frameworks/Jackmp.framework/Headers, "$(HOME)/Library/Frameworks/SDL.framework/Headers", /Library/Frameworks/SDL.framework/Headers, "$(HEADER_SEARCH_PATHS)", /usr/include/libxml2, ); OTHER_CFLAGS = ( "-D", __MACOSX__, "-fpermissive", ); OTHER_LDFLAGS = ( "-lcrypto", "-lxml2", ); PREBINDING = NO; PRODUCT_NAME = FreeWheeling; ZERO_LINK = NO; }; name = Release; }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ C01FCF4A08A954540054247B /* Build configuration list for PBXNativeTarget "fweelin" */ = { isa = XCConfigurationList; buildConfigurations = ( C01FCF4B08A954540054247B /* Debug */, C01FCF4C08A954540054247B /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; C01FCF4E08A954540054247B /* Build configuration list for PBXProject "fweelin" */ = { isa = XCConfigurationList; buildConfigurations = ( C01FCF4F08A954540054247B /* Debug */, C01FCF5008A954540054247B /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; rootObject = 29B97313FDCFA39411CA2CEA /* Project object */; } freewheeling-0.6.6/MacOSX/fweelin_Prefix.pch000066400000000000000000000002431370736313100207260ustar00rootroot00000000000000// // Prefix header for all source files of the 'fweelin' target in the 'fweelin' project // #include "SDL.h" #ifdef __OBJC__ #import #endif freewheeling-0.6.6/Makefile.am000066400000000000000000000000231370736313100162220ustar00rootroot00000000000000SUBDIRS = src data freewheeling-0.6.6/Makefile.in000066400000000000000000000572031370736313100162470ustar00rootroot00000000000000# Makefile.in generated by automake 1.16.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2018 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : subdir = . ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(top_srcdir)/configure \ $(am__configure_deps) $(am__DIST_COMMON) am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ configure.lineno config.status.lineno mkinstalldirs = $(install_sh) -d CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ ctags-recursive dvi-recursive html-recursive info-recursive \ install-data-recursive install-dvi-recursive \ install-exec-recursive install-html-recursive \ install-info-recursive install-pdf-recursive \ install-ps-recursive install-recursive installcheck-recursive \ installdirs-recursive pdf-recursive ps-recursive \ tags-recursive uninstall-recursive am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ distclean-recursive maintainer-clean-recursive am__recursive_targets = \ $(RECURSIVE_TARGETS) \ $(RECURSIVE_CLEAN_TARGETS) \ $(am__extra_recursive_targets) AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ cscope distdir distdir-am dist dist-all distcheck am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags CSCOPE = cscope DIST_SUBDIRS = $(SUBDIRS) am__DIST_COMMON = $(srcdir)/Makefile.in AUTHORS COPYING ChangeLog \ INSTALL NEWS README THANKS compile depcomp install-sh missing DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) distdir = $(PACKAGE)-$(VERSION) top_distdir = $(distdir) am__remove_distdir = \ if test -d "$(distdir)"; then \ find "$(distdir)" -type d ! -perm -200 -exec chmod u+w {} ';' \ && rm -rf "$(distdir)" \ || { sleep 5 && rm -rf "$(distdir)"; }; \ else :; fi am__post_remove_distdir = $(am__remove_distdir) am__relativize = \ dir0=`pwd`; \ sed_first='s,^\([^/]*\)/.*$$,\1,'; \ sed_rest='s,^[^/]*/*,,'; \ sed_last='s,^.*/\([^/]*\)$$,\1,'; \ sed_butlast='s,/*[^/]*$$,,'; \ while test -n "$$dir1"; do \ first=`echo "$$dir1" | sed -e "$$sed_first"`; \ if test "$$first" != "."; then \ if test "$$first" = ".."; then \ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ else \ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ if test "$$first2" = "$$first"; then \ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ else \ dir2="../$$dir2"; \ fi; \ dir0="$$dir0"/"$$first"; \ fi; \ fi; \ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ done; \ reldir="$$dir2" DIST_ARCHIVES = $(distdir).tar.gz GZIP_ENV = --best DIST_TARGETS = dist-gzip distuninstallcheck_listfiles = find . -type f -print am__distuninstallcheck_listfiles = $(distuninstallcheck_listfiles) \ | sed 's|^\./|$(prefix)/|' | grep -v '$(infodir)/dir$$' distcleancheck_listfiles = find . -type f -print ACLOCAL = @ACLOCAL@ ALLOCA = @ALLOCA@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CXX = @CXX@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ GREP = @GREP@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ OBJEXT = @OBJEXT@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ POW_LIB = @POW_LIB@ SDL_CFLAGS = @SDL_CFLAGS@ SDL_LIBS = @SDL_LIBS@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ XMKMF = @XMKMF@ X_CFLAGS = @X_CFLAGS@ X_EXTRA_LIBS = @X_EXTRA_LIBS@ X_LIBS = @X_LIBS@ X_PRE_LIBS = @X_PRE_LIBS@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build_alias = @build_alias@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host_alias = @host_alias@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ SUBDIRS = src data all: all-recursive .SUFFIXES: am--refresh: Makefile @: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ echo ' cd $(srcdir) && $(AUTOMAKE) --gnu'; \ $(am__cd) $(srcdir) && $(AUTOMAKE) --gnu \ && exit 0; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ echo ' $(SHELL) ./config.status'; \ $(SHELL) ./config.status;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) $(SHELL) ./config.status --recheck $(top_srcdir)/configure: $(am__configure_deps) $(am__cd) $(srcdir) && $(AUTOCONF) $(ACLOCAL_M4): $(am__aclocal_m4_deps) $(am__cd) $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS) $(am__aclocal_m4_deps): # This directory's subdirectories are mostly independent; you can cd # into them and run 'make' without going through this Makefile. # To change the values of 'make' variables: instead of editing Makefiles, # (1) if the variable is set in 'config.status', edit 'config.status' # (which will cause the Makefiles to be regenerated when you run 'make'); # (2) otherwise, pass the desired values on the 'make' command line. $(am__recursive_targets): @fail=; \ if $(am__make_keepgoing); then \ failcom='fail=yes'; \ else \ failcom='exit 1'; \ fi; \ dot_seen=no; \ target=`echo $@ | sed s/-recursive//`; \ case "$@" in \ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ *) list='$(SUBDIRS)' ;; \ esac; \ for subdir in $$list; do \ echo "Making $$target in $$subdir"; \ if test "$$subdir" = "."; then \ dot_seen=yes; \ local_target="$$target-am"; \ else \ local_target="$$target"; \ fi; \ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done; \ if test "$$dot_seen" = "no"; then \ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ fi; test -z "$$fail" ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-recursive TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ include_option=--etags-include; \ empty_fix=.; \ else \ include_option=--include; \ empty_fix=; \ fi; \ list='$(SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test ! -f $$subdir/TAGS || \ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ fi; \ done; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-recursive CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscope: cscope.files test ! -s cscope.files \ || $(CSCOPE) -b -q $(AM_CSCOPEFLAGS) $(CSCOPEFLAGS) -i cscope.files $(CSCOPE_ARGS) clean-cscope: -rm -f cscope.files cscope.files: clean-cscope cscopelist cscopelist: cscopelist-recursive cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags -rm -f cscope.out cscope.in.out cscope.po.out cscope.files distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) $(am__remove_distdir) test -d "$(distdir)" || mkdir "$(distdir)" @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ $(am__make_dryrun) \ || test -d "$(distdir)/$$subdir" \ || $(MKDIR_P) "$(distdir)/$$subdir" \ || exit 1; \ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ $(am__relativize); \ new_distdir=$$reldir; \ dir1=$$subdir; dir2="$(top_distdir)"; \ $(am__relativize); \ new_top_distdir=$$reldir; \ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ ($(am__cd) $$subdir && \ $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$$new_top_distdir" \ distdir="$$new_distdir" \ am__remove_distdir=: \ am__skip_length_check=: \ am__skip_mode_fix=: \ distdir) \ || exit 1; \ fi; \ done -test -n "$(am__skip_mode_fix)" \ || find "$(distdir)" -type d ! -perm -755 \ -exec chmod u+rwx,go+rx {} \; -o \ ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \ ! -type d ! -perm -400 -exec chmod a+r {} \; -o \ ! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \ || chmod -R a+r "$(distdir)" dist-gzip: distdir tardir=$(distdir) && $(am__tar) | eval GZIP= gzip $(GZIP_ENV) -c >$(distdir).tar.gz $(am__post_remove_distdir) dist-bzip2: distdir tardir=$(distdir) && $(am__tar) | BZIP2=$${BZIP2--9} bzip2 -c >$(distdir).tar.bz2 $(am__post_remove_distdir) dist-lzip: distdir tardir=$(distdir) && $(am__tar) | lzip -c $${LZIP_OPT--9} >$(distdir).tar.lz $(am__post_remove_distdir) dist-xz: distdir tardir=$(distdir) && $(am__tar) | XZ_OPT=$${XZ_OPT--e} xz -c >$(distdir).tar.xz $(am__post_remove_distdir) dist-tarZ: distdir @echo WARNING: "Support for distribution archives compressed with" \ "legacy program 'compress' is deprecated." >&2 @echo WARNING: "It will be removed altogether in Automake 2.0" >&2 tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z $(am__post_remove_distdir) dist-shar: distdir @echo WARNING: "Support for shar distribution archives is" \ "deprecated." >&2 @echo WARNING: "It will be removed altogether in Automake 2.0" >&2 shar $(distdir) | eval GZIP= gzip $(GZIP_ENV) -c >$(distdir).shar.gz $(am__post_remove_distdir) dist-zip: distdir -rm -f $(distdir).zip zip -rq $(distdir).zip $(distdir) $(am__post_remove_distdir) dist dist-all: $(MAKE) $(AM_MAKEFLAGS) $(DIST_TARGETS) am__post_remove_distdir='@:' $(am__post_remove_distdir) # This target untars the dist file and tries a VPATH configuration. Then # it guarantees that the distribution is self-contained by making another # tarfile. distcheck: dist case '$(DIST_ARCHIVES)' in \ *.tar.gz*) \ eval GZIP= gzip $(GZIP_ENV) -dc $(distdir).tar.gz | $(am__untar) ;;\ *.tar.bz2*) \ bzip2 -dc $(distdir).tar.bz2 | $(am__untar) ;;\ *.tar.lz*) \ lzip -dc $(distdir).tar.lz | $(am__untar) ;;\ *.tar.xz*) \ xz -dc $(distdir).tar.xz | $(am__untar) ;;\ *.tar.Z*) \ uncompress -c $(distdir).tar.Z | $(am__untar) ;;\ *.shar.gz*) \ eval GZIP= gzip $(GZIP_ENV) -dc $(distdir).shar.gz | unshar ;;\ *.zip*) \ unzip $(distdir).zip ;;\ esac chmod -R a-w $(distdir) chmod u+w $(distdir) mkdir $(distdir)/_build $(distdir)/_build/sub $(distdir)/_inst chmod a-w $(distdir) test -d $(distdir)/_build || exit 0; \ dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \ && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \ && am__cwd=`pwd` \ && $(am__cd) $(distdir)/_build/sub \ && ../../configure \ $(AM_DISTCHECK_CONFIGURE_FLAGS) \ $(DISTCHECK_CONFIGURE_FLAGS) \ --srcdir=../.. --prefix="$$dc_install_base" \ && $(MAKE) $(AM_MAKEFLAGS) \ && $(MAKE) $(AM_MAKEFLAGS) dvi \ && $(MAKE) $(AM_MAKEFLAGS) check \ && $(MAKE) $(AM_MAKEFLAGS) install \ && $(MAKE) $(AM_MAKEFLAGS) installcheck \ && $(MAKE) $(AM_MAKEFLAGS) uninstall \ && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \ distuninstallcheck \ && chmod -R a-w "$$dc_install_base" \ && ({ \ (cd ../.. && umask 077 && mkdir "$$dc_destdir") \ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \ distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \ } || { rm -rf "$$dc_destdir"; exit 1; }) \ && rm -rf "$$dc_destdir" \ && $(MAKE) $(AM_MAKEFLAGS) dist \ && rm -rf $(DIST_ARCHIVES) \ && $(MAKE) $(AM_MAKEFLAGS) distcleancheck \ && cd "$$am__cwd" \ || exit 1 $(am__post_remove_distdir) @(echo "$(distdir) archives ready for distribution: "; \ list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \ sed -e 1h -e 1s/./=/g -e 1p -e 1x -e '$$p' -e '$$x' distuninstallcheck: @test -n '$(distuninstallcheck_dir)' || { \ echo 'ERROR: trying to run $@ with an empty' \ '$$(distuninstallcheck_dir)' >&2; \ exit 1; \ }; \ $(am__cd) '$(distuninstallcheck_dir)' || { \ echo 'ERROR: cannot chdir into $(distuninstallcheck_dir)' >&2; \ exit 1; \ }; \ test `$(am__distuninstallcheck_listfiles) | wc -l` -eq 0 \ || { echo "ERROR: files left after uninstall:" ; \ if test -n "$(DESTDIR)"; then \ echo " (check DESTDIR support)"; \ fi ; \ $(distuninstallcheck_listfiles) ; \ exit 1; } >&2 distcleancheck: distclean @if test '$(srcdir)' = . ; then \ echo "ERROR: distcleancheck can only run from a VPATH build" ; \ exit 1 ; \ fi @test `$(distcleancheck_listfiles) | wc -l` -eq 0 \ || { echo "ERROR: files left in build directory after distclean:" ; \ $(distcleancheck_listfiles) ; \ exit 1; } >&2 check-am: all-am check: check-recursive all-am: Makefile installdirs: installdirs-recursive installdirs-am: install: install-recursive install-exec: install-exec-recursive install-data: install-data-recursive uninstall: uninstall-recursive install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-recursive install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-recursive clean-am: clean-generic mostlyclean-am distclean: distclean-recursive -rm -f $(am__CONFIG_DISTCLEAN_FILES) -rm -f Makefile distclean-am: clean-am distclean-generic distclean-tags dvi: dvi-recursive dvi-am: html: html-recursive html-am: info: info-recursive info-am: install-data-am: install-dvi: install-dvi-recursive install-dvi-am: install-exec-am: install-html: install-html-recursive install-html-am: install-info: install-info-recursive install-info-am: install-man: install-pdf: install-pdf-recursive install-pdf-am: install-ps: install-ps-recursive install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-recursive -rm -f $(am__CONFIG_DISTCLEAN_FILES) -rm -rf $(top_srcdir)/autom4te.cache -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-recursive mostlyclean-am: mostlyclean-generic pdf: pdf-recursive pdf-am: ps: ps-recursive ps-am: uninstall-am: .MAKE: $(am__recursive_targets) install-am install-strip .PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am \ am--refresh check check-am clean clean-cscope clean-generic \ cscope cscopelist-am ctags ctags-am dist dist-all dist-bzip2 \ dist-gzip dist-lzip dist-shar dist-tarZ dist-xz dist-zip \ distcheck distclean distclean-generic distclean-tags \ distcleancheck distdir distuninstallcheck dvi dvi-am html \ html-am info info-am install install-am install-data \ install-data-am install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-man install-pdf install-pdf-am \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs installdirs-am maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-generic pdf \ pdf-am ps ps-am tags tags-am uninstall uninstall-am .PRECIOUS: Makefile # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: freewheeling-0.6.6/NEWS000066400000000000000000000020101370736313100146630ustar00rootroot00000000000000Please see http://freewheeling.sourceforge.net for most recent news. 2005- Prereleases. 2004- Naraya @ Wolf Creek. Community ritual process. Moving towards general release. 4 new CDs of improvised audio. Polls hosted on website- open source or commercial software? Linux, Mac, or Windows? Thank you to all who responded and helped me decide on the open-source route! Tessa, Shaun, and Mercury start improvised singing circle. Tessa volunteers her laptop to be guinea pig, and it survives!-- now with a Linux looper. Thank You!, dear woman! 2003- Yoga school. Jude presents looper to his UNCA music class. Thanks, Jude. Shaun, Audrey, and the ACAD family in Calgary- looping sessions. Shaun and Mercury- live looping sets. Freewheeling evolves. Thanks guys! June 26, 2002- Eddie and Mercury are working on testing the Linux prototype with our chants and gurgles. Eddie lends his beautiful voice and creative juices on tap. 2000- Max/MSP version with 4 channels of keyboard controlled looping. Proof of concept. freewheeling-0.6.6/README000066400000000000000000000002661370736313100150570ustar00rootroot00000000000000Please read data/config-help.txt in the source tree The same file can also be found at ~/.fweelin/config-help.txt after freewheeling is installed and has run for the first time freewheeling-0.6.6/README.md000066400000000000000000000210251370736313100154520ustar00rootroot00000000000000 Introduction to Freewheeling ---------------------------- ![freewheeling screenshot][Freewheeling_Screenshot] ### Free and Open Source Audio Tool for Live Looping Freewheeling provides a highly configurable, intuitive, and fluid user interface for instrumentalists to capture audio loops in real-time. Best way to understand Freewheeling?? [See and hear it][Freewheeling_Screenshots] in action. [Demo Video][Freewheeling_Demo_Video]. ### Philosophy ``` Freewheeling is a new way 'to be' In The Muse-ical Moment. It's a live looping instrument that returns us to the joy of making music 'spontaneously'. ``` Freewheeling allows us to build repetitive grooves by sampling and directing loops from within spirited improvisation. It works because, down to the core, it's built around improv. We leave mice and menus, and dive into our own process of making sound. The principle author of Freewheeling is JP Mercury. Freewheeling was also originally a Max/MSP external. Since 2016, it is maintained by the user community. ### Technical Details Freewheeling runs under GNU/Linux (PC/Mac) and Mac OS X (PPC/Intel) using the [Jack Audio Connection Kit][JACK] sound server, and is Free and Open Source Software, released under the GNU GPL license. The ChangeLog is a good resource, because all major new features have been documented there. It is humble enough to run on modest hardware but can take advantage of the gobs of RAM on modern machines as well. The only limits are your imagination. **Focus on the ideation process:** - Freewheeling empowers the trance of immediate creativity by bringing us into a circular process. Time is utterly relative, and we are freed from the future-oriented mindset of product sequencing. If inspiration flows, later arranging and editing on a timeline can be done with other tools. See the [Technical Features][Technical_Features]. Getting Started --------------- ### Downloading Pre-compiled Freewheeling binaries are available for several of today's popular operating systems. If you prefer using your favorite graphical package manager (such as synaptic) or your distro's Add/Remove Software Control Panel, search for a package named *freewheeling* or *fweelin*. - Install one of the [OS Specific Packages][OS_Specific_Packages] - (recommended) - or, [Download][Freewheeling_Tarballs] a tarball - (advanced) - or, Debian, KxStudio, Mint, and Ubuntu users can download the sourecs with your package manager: - (advanced) ``` $ apt source freewheeling ``` - or, Checkout the latest git master - (advanced) ``` $ git clone https://github.com/free-wheeling/freewheeling.git $ git clone https://notabug.org/freewheeling/freewheeling.git ``` ### Installing - [OS Specific Packages][OS_Specific_Packages] - (recommended) - [Compiling][Compiling] - (advanced) - [Dependencies][Dependencies] ### Configuring - [Configuration Basics][Configuration_Basics] - how does it work? - [XML Configuration System][XML_Configuration_System] - the full Freewheeling XML API from config-help.txt in wiki form - [Configurations][Configurations] - a store for users to submit their custom interfaces, layouts, patches, etc ### Troubleshooting and Support - [FAQS][FAQS] - Freeq-wheely Asked Questions - [Known Issues][Known_Issues] - Resolutions to common pitfalls, snags, and glitches (notice i did not say bugs) - [Freewheeling Users Mailing List][Freewheeling_Users_Mailing_List] - If you're looking for help with Freewheeling, your question may already be answered there. If not, feel free to [join the mailing list][Freewheeling_Users_Mailing_List] and ask your question to the community - [Feature Requests][Freewheeling_Users_Mailing_List] - Please join the 'freewheeling-user' mailing list - [Bug Reporting][Github_Bug_Tracker] - Please reports bugs on the [GitHub issue tracker][Github_Bug_Tracker] or the [NotABug issue tracker][Notabug_Bug_Tracker] ### Using - [Quick Start Guide][Quick_Start_Guide] - handy defaults for the impatient user - [Freewheeling Video Tutorials][Freewheeling_Video_Tutorials] - watch freewheeling in action - [Controlling Freewheeling][Controlling_Freewheeling] - using external midi devices - [Default Key Bindings][Default_Key_Bindings] - what did I just pressed? - [Tips and Tricks for Studio and Live Use][Tips_and_Tricks_for_Studio_and_Live_Use] NOTE: You will also need the JACK audio server and a way to configure it (such as qJackCtl or Cadence). A very easy way to setup a GNU/Linux audio workstation is by installing the [KxStudio Operating System][KxStudio_Downloads]. NOTE: Debian (and derrivatives such as Trisquel, Ubuntu, and Mint) can transform their system into KxStudio simply by adding the [KxStudio repos][KxStudio_Repos] and installing the 'kxstudio-meta-all' package (or 'kxstudio-meta-audio' for just the pro-audio programs). It is highly recommended that you install at least the 'kxstudio-default-settings' package which optimizes your system performance for real-time audio use. NOTE: ArchLinux (and derrivatives such as Parabola, Hyperbola, and Manjaro) can simply install the 'pro-audio' package group, which includes Freewheeling. It is highly recommended that you install at least the 'realtime-privileges' package which configures your system for real-time audio use. The Freewheeling Community -------------------------- ### Community Interaction - [Music made with Freewheeling][Music_made_with_Freewheeling] - [Freewheeling Users Mailing List][Freewheeling_Users_Mailing_List] - technical support, new releases, shared ideas and music ### How can I help? - Submit or edit wiki articles - Submit your interfaces and layouts for specific hardware to the [Configurations][Configurations] article - Submit screen-casts demonstrating your interfaces or the advanced features of freewheeling - Submit audio/video creations to the [Music made with Freewheeling][Music_made_with_Freewheeling] article [Freewheeling_Screenshot]: http://freewheeling.sourceforge.net/flo-051-looptray-t.png [Freewheeling_Screenshots]: http://freewheeling.sourceforge.net/shots.shtml [Freewheeling_Demo_Video]: http://freewheeling.sourceforge.net/video/fw-demo1.avi [JACK]: http://jackaudio.org [Technical_Features]: https://github.com/free-wheeling/freewheeling/wiki/Technical-Features [OS_Specific_Packages]: https://github.com/free-wheeling/freewheeling/wiki/OS-Specific-Packages [Freewheeling_Tarballs]: https://github.com/free-wheeling/freewheeling/releases [Compiling]: https://github.com/free-wheeling/freewheeling/wiki/Compiling [Dependencies]: https://github.com/free-wheeling/freewheeling/wiki/Dependencies [Configuration_Basics]: https://github.com/free-wheeling/freewheeling/wiki/Configuration-Basics [XML_Configuration_System]: https://github.com/free-wheeling/freewheeling/wiki/XML-Configuration-System [Configurations]: https://github.com/free-wheeling/freewheeling/wiki/Configurations [FAQS]: https://github.com/free-wheeling/freewheeling/wiki/FAQS [Known_Issues]: https://github.com/free-wheeling/freewheeling/wiki/Known-Issues [Freewheeling_Users_Mailing_List]: https://github.com/free-wheeling/freewheeling/wiki/Freewheeling-Users-Mailing-List [Github_Bug_Tracker]: https://github.com/free-wheeling/freewheeling/issues [Notabug_Bug_Tracker]: https://notabug.org/freewheeling/freewheeling/issues [Quick_Start_Guide]: https://github.com/free-wheeling/freewheeling/wiki/Quick-Start-Guide [Freewheeling_Video_Tutorials]: https://github.com/free-wheeling/freewheeling/wiki/Freewheeling-Video-Tutorials [Controlling_Freewheeling]: https://github.com/free-wheeling/freewheeling/wiki/Controlling-Freewheeling [Default_Key_Bindings]: https://github.com/free-wheeling/freewheeling/wiki/Default-Key-Bindings [Tips_and_Tricks_for_Studio_and_Live_Use]: https://github.com/free-wheeling/freewheeling/wiki/Tips-and-Tricks-for-Studio-and-Live-Use [KxStudio_Downloads]: https://kxstudio.linuxaudio.org/Downloads [KxStudio_Repos]: https://kxstudio.linuxaudio.org/Repositories [Music_made_with_Freewheeling]: https://github.com/free-wheeling/freewheeling/wiki/Music-made-with-Freewheeling freewheeling-0.6.6/THANKS000066400000000000000000000025101370736313100151040ustar00rootroot00000000000000Grateful Pauses for This Beautiful Body for telling me when to stop. .. Mom, Dad, Holly, Aasha, Asha, Melchert, Macon, Jude, Eddie, Tangle, Steve Sandberg, Joshua James, Shaun Free Zen, Tessa, The Naraya and the Wolf Creek Faeries, and Cycling 74. The Linux community! The FSF, RT kernel developers, GNU and Debian people, without whom, FreeWheeling would not be possible. -Wolfgang Woehl, Mark Knecht, Shayne O'Connor, Esben Stien, Gregory Maxwell, Plutek, and Sune Mai, my evangelists, critics, funders, beta-testers, and visionaries. -Jesse Chappell for writing SooperLooper, and being so cool about sharing ideas. -Giuliano Pochini, whose outstanding work on drivers for Echo's CardBus audio line has helped me scale down my setup. -Takashi, Jaroslav and the ALSA development team. -Paul Davis and the JACK and Ardour teams. -Peter Hanappe, Josh Green and the giant FluidSynth team. -The SDL people. -Mark Knecht for his feedback and inspiration. -Sean Bolton and the DSSI softsynth team. -Steve Harris, Tim Goetze, Tom Szilagyi- the makers of fine LADSPA effects plugins. -Bob Ham, for his work on Jack-Rack. -Echo Audio for getting their act together and releasing specs for their audio interfaces. -Countless others Everyone who has been in touch and lended kind thoughts. Thank You All freewheeling-0.6.6/TUNING000066400000000000000000000016771370736313100151350ustar00rootroot00000000000000Some Suggestions for Tuning Freewheeling's Audio Performance: ************************************************************ on Linux Updated September, 2004 ----------------------- Run hdparm to set DMA & well behaved disk IO. Try: hdparm -c3 -d1 -m16 -A1 -u1 /dev/hda (do for /dev/hdb .. also) If you have a PCI audio interface, run setpci to set PCI latency. First, run 'lspci -v' and find the address of your audio board. Then run: setpci -s 00:07.5 latency_timer=F8 (if your audio is at 00:07.5) Set video depth to 8 or 16 bits. 24 and 32 bits are generally much slower. Use fluxbox, blackbox, or another lightweight window manager on slower machines. Use lower sampling rates to achieve lower latency. Try 64 samples, 32000 Hz, 3 periods per buffer. This works well on several low end audio boards such as ESS Maestro and AC 97. Lower latency is key for live looping! Otherwise, the latency will lag your timing and it will feel very awkward. freewheeling-0.6.6/aclocal.m4000066400000000000000000001524371370736313100160470ustar00rootroot00000000000000# generated automatically by aclocal 1.16.1 -*- Autoconf -*- # Copyright (C) 1996-2018 Free Software Foundation, Inc. # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])]) m4_ifndef([AC_AUTOCONF_VERSION], [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.69],, [m4_warning([this file was generated for autoconf 2.69. You have another version of autoconf. It may work, but is not guaranteed to. If you have problems, you may need to regenerate the build system entirely. To do so, use the procedure documented by the package, typically 'autoreconf'.])]) # pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*- # serial 11 (pkg-config-0.29.1) dnl Copyright © 2004 Scott James Remnant . dnl Copyright © 2012-2015 Dan Nicholson dnl dnl This program is free software; you can redistribute it and/or modify dnl it under the terms of the GNU General Public License as published by dnl the Free Software Foundation; either version 2 of the License, or dnl (at your option) any later version. dnl dnl This program is distributed in the hope that it will be useful, but dnl WITHOUT ANY WARRANTY; without even the implied warranty of dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU dnl General Public License for more details. dnl dnl You should have received a copy of the GNU General Public License dnl along with this program; if not, write to the Free Software dnl Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA dnl 02111-1307, USA. dnl dnl As a special exception to the GNU General Public License, if you dnl distribute this file as part of a program that contains a dnl configuration script generated by Autoconf, you may include it under dnl the same distribution terms that you use for the rest of that dnl program. dnl PKG_PREREQ(MIN-VERSION) dnl ----------------------- dnl Since: 0.29 dnl dnl Verify that the version of the pkg-config macros are at least dnl MIN-VERSION. Unlike PKG_PROG_PKG_CONFIG, which checks the user's dnl installed version of pkg-config, this checks the developer's version dnl of pkg.m4 when generating configure. dnl dnl To ensure that this macro is defined, also add: dnl m4_ifndef([PKG_PREREQ], dnl [m4_fatal([must install pkg-config 0.29 or later before running autoconf/autogen])]) dnl dnl See the "Since" comment for each macro you use to see what version dnl of the macros you require. m4_defun([PKG_PREREQ], [m4_define([PKG_MACROS_VERSION], [0.29.1]) m4_if(m4_version_compare(PKG_MACROS_VERSION, [$1]), -1, [m4_fatal([pkg.m4 version $1 or higher is required but ]PKG_MACROS_VERSION[ found])]) ])dnl PKG_PREREQ dnl PKG_PROG_PKG_CONFIG([MIN-VERSION]) dnl ---------------------------------- dnl Since: 0.16 dnl dnl Search for the pkg-config tool and set the PKG_CONFIG variable to dnl first found in the path. Checks that the version of pkg-config found dnl is at least MIN-VERSION. If MIN-VERSION is not specified, 0.9.0 is dnl used since that's the first version where most current features of dnl pkg-config existed. AC_DEFUN([PKG_PROG_PKG_CONFIG], [m4_pattern_forbid([^_?PKG_[A-Z_]+$]) m4_pattern_allow([^PKG_CONFIG(_(PATH|LIBDIR|SYSROOT_DIR|ALLOW_SYSTEM_(CFLAGS|LIBS)))?$]) m4_pattern_allow([^PKG_CONFIG_(DISABLE_UNINSTALLED|TOP_BUILD_DIR|DEBUG_SPEW)$]) AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility]) AC_ARG_VAR([PKG_CONFIG_PATH], [directories to add to pkg-config's search path]) AC_ARG_VAR([PKG_CONFIG_LIBDIR], [path overriding pkg-config's built-in search path]) if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then AC_PATH_TOOL([PKG_CONFIG], [pkg-config]) fi if test -n "$PKG_CONFIG"; then _pkg_min_version=m4_default([$1], [0.9.0]) AC_MSG_CHECKING([pkg-config is at least version $_pkg_min_version]) if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) PKG_CONFIG="" fi fi[]dnl ])dnl PKG_PROG_PKG_CONFIG dnl PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) dnl ------------------------------------------------------------------- dnl Since: 0.18 dnl dnl Check to see whether a particular set of modules exists. Similar to dnl PKG_CHECK_MODULES(), but does not set variables or print errors. dnl dnl Please remember that m4 expands AC_REQUIRE([PKG_PROG_PKG_CONFIG]) dnl only at the first occurence in configure.ac, so if the first place dnl it's called might be skipped (such as if it is within an "if", you dnl have to call PKG_CHECK_EXISTS manually AC_DEFUN([PKG_CHECK_EXISTS], [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl if test -n "$PKG_CONFIG" && \ AC_RUN_LOG([$PKG_CONFIG --exists --print-errors "$1"]); then m4_default([$2], [:]) m4_ifvaln([$3], [else $3])dnl fi]) dnl _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES]) dnl --------------------------------------------- dnl Internal wrapper calling pkg-config via PKG_CONFIG and setting dnl pkg_failed based on the result. m4_define([_PKG_CONFIG], [if test -n "$$1"; then pkg_cv_[]$1="$$1" elif test -n "$PKG_CONFIG"; then PKG_CHECK_EXISTS([$3], [pkg_cv_[]$1=`$PKG_CONFIG --[]$2 "$3" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes ], [pkg_failed=yes]) else pkg_failed=untried fi[]dnl ])dnl _PKG_CONFIG dnl _PKG_SHORT_ERRORS_SUPPORTED dnl --------------------------- dnl Internal check to see if pkg-config supports short errors. AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED], [AC_REQUIRE([PKG_PROG_PKG_CONFIG]) if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi[]dnl ])dnl _PKG_SHORT_ERRORS_SUPPORTED dnl PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND], dnl [ACTION-IF-NOT-FOUND]) dnl -------------------------------------------------------------- dnl Since: 0.4.0 dnl dnl Note that if there is a possibility the first call to dnl PKG_CHECK_MODULES might not happen, you should be sure to include an dnl explicit call to PKG_PROG_PKG_CONFIG in your configure.ac AC_DEFUN([PKG_CHECK_MODULES], [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl pkg_failed=no AC_MSG_CHECKING([for $1]) _PKG_CONFIG([$1][_CFLAGS], [cflags], [$2]) _PKG_CONFIG([$1][_LIBS], [libs], [$2]) m4_define([_PKG_TEXT], [Alternatively, you may set the environment variables $1[]_CFLAGS and $1[]_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details.]) if test $pkg_failed = yes; then AC_MSG_RESULT([no]) _PKG_SHORT_ERRORS_SUPPORTED if test $_pkg_short_errors_supported = yes; then $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$2" 2>&1` else $1[]_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$2" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD m4_default([$4], [AC_MSG_ERROR( [Package requirements ($2) were not met: $$1_PKG_ERRORS Consider adjusting the PKG_CONFIG_PATH environment variable if you installed software in a non-standard prefix. _PKG_TEXT])[]dnl ]) elif test $pkg_failed = untried; then AC_MSG_RESULT([no]) m4_default([$4], [AC_MSG_FAILURE( [The pkg-config script could not be found or is too old. Make sure it is in your PATH or set the PKG_CONFIG environment variable to the full path to pkg-config. _PKG_TEXT To get pkg-config, see .])[]dnl ]) else $1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS $1[]_LIBS=$pkg_cv_[]$1[]_LIBS AC_MSG_RESULT([yes]) $3 fi[]dnl ])dnl PKG_CHECK_MODULES dnl PKG_CHECK_MODULES_STATIC(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND], dnl [ACTION-IF-NOT-FOUND]) dnl --------------------------------------------------------------------- dnl Since: 0.29 dnl dnl Checks for existence of MODULES and gathers its build flags with dnl static libraries enabled. Sets VARIABLE-PREFIX_CFLAGS from --cflags dnl and VARIABLE-PREFIX_LIBS from --libs. dnl dnl Note that if there is a possibility the first call to dnl PKG_CHECK_MODULES_STATIC might not happen, you should be sure to dnl include an explicit call to PKG_PROG_PKG_CONFIG in your dnl configure.ac. AC_DEFUN([PKG_CHECK_MODULES_STATIC], [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl _save_PKG_CONFIG=$PKG_CONFIG PKG_CONFIG="$PKG_CONFIG --static" PKG_CHECK_MODULES($@) PKG_CONFIG=$_save_PKG_CONFIG[]dnl ])dnl PKG_CHECK_MODULES_STATIC dnl PKG_INSTALLDIR([DIRECTORY]) dnl ------------------------- dnl Since: 0.27 dnl dnl Substitutes the variable pkgconfigdir as the location where a module dnl should install pkg-config .pc files. By default the directory is dnl $libdir/pkgconfig, but the default can be changed by passing dnl DIRECTORY. The user can override through the --with-pkgconfigdir dnl parameter. AC_DEFUN([PKG_INSTALLDIR], [m4_pushdef([pkg_default], [m4_default([$1], ['${libdir}/pkgconfig'])]) m4_pushdef([pkg_description], [pkg-config installation directory @<:@]pkg_default[@:>@]) AC_ARG_WITH([pkgconfigdir], [AS_HELP_STRING([--with-pkgconfigdir], pkg_description)],, [with_pkgconfigdir=]pkg_default) AC_SUBST([pkgconfigdir], [$with_pkgconfigdir]) m4_popdef([pkg_default]) m4_popdef([pkg_description]) ])dnl PKG_INSTALLDIR dnl PKG_NOARCH_INSTALLDIR([DIRECTORY]) dnl -------------------------------- dnl Since: 0.27 dnl dnl Substitutes the variable noarch_pkgconfigdir as the location where a dnl module should install arch-independent pkg-config .pc files. By dnl default the directory is $datadir/pkgconfig, but the default can be dnl changed by passing DIRECTORY. The user can override through the dnl --with-noarch-pkgconfigdir parameter. AC_DEFUN([PKG_NOARCH_INSTALLDIR], [m4_pushdef([pkg_default], [m4_default([$1], ['${datadir}/pkgconfig'])]) m4_pushdef([pkg_description], [pkg-config arch-independent installation directory @<:@]pkg_default[@:>@]) AC_ARG_WITH([noarch-pkgconfigdir], [AS_HELP_STRING([--with-noarch-pkgconfigdir], pkg_description)],, [with_noarch_pkgconfigdir=]pkg_default) AC_SUBST([noarch_pkgconfigdir], [$with_noarch_pkgconfigdir]) m4_popdef([pkg_default]) m4_popdef([pkg_description]) ])dnl PKG_NOARCH_INSTALLDIR dnl PKG_CHECK_VAR(VARIABLE, MODULE, CONFIG-VARIABLE, dnl [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) dnl ------------------------------------------- dnl Since: 0.28 dnl dnl Retrieves the value of the pkg-config variable for the given module. AC_DEFUN([PKG_CHECK_VAR], [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl AC_ARG_VAR([$1], [value of $3 for $2, overriding pkg-config])dnl _PKG_CONFIG([$1], [variable="][$3]["], [$2]) AS_VAR_COPY([$1], [pkg_cv_][$1]) AS_VAR_IF([$1], [""], [$5], [$4])dnl ])dnl PKG_CHECK_VAR dnl PKG_WITH_MODULES(VARIABLE-PREFIX, MODULES, dnl [ACTION-IF-FOUND],[ACTION-IF-NOT-FOUND], dnl [DESCRIPTION], [DEFAULT]) dnl ------------------------------------------ dnl dnl Prepare a "--with-" configure option using the lowercase dnl [VARIABLE-PREFIX] name, merging the behaviour of AC_ARG_WITH and dnl PKG_CHECK_MODULES in a single macro. AC_DEFUN([PKG_WITH_MODULES], [ m4_pushdef([with_arg], m4_tolower([$1])) m4_pushdef([description], [m4_default([$5], [build with ]with_arg[ support])]) m4_pushdef([def_arg], [m4_default([$6], [auto])]) m4_pushdef([def_action_if_found], [AS_TR_SH([with_]with_arg)=yes]) m4_pushdef([def_action_if_not_found], [AS_TR_SH([with_]with_arg)=no]) m4_case(def_arg, [yes],[m4_pushdef([with_without], [--without-]with_arg)], [m4_pushdef([with_without],[--with-]with_arg)]) AC_ARG_WITH(with_arg, AS_HELP_STRING(with_without, description[ @<:@default=]def_arg[@:>@]),, [AS_TR_SH([with_]with_arg)=def_arg]) AS_CASE([$AS_TR_SH([with_]with_arg)], [yes],[PKG_CHECK_MODULES([$1],[$2],$3,$4)], [auto],[PKG_CHECK_MODULES([$1],[$2], [m4_n([def_action_if_found]) $3], [m4_n([def_action_if_not_found]) $4])]) m4_popdef([with_arg]) m4_popdef([description]) m4_popdef([def_arg]) ])dnl PKG_WITH_MODULES dnl PKG_HAVE_WITH_MODULES(VARIABLE-PREFIX, MODULES, dnl [DESCRIPTION], [DEFAULT]) dnl ----------------------------------------------- dnl dnl Convenience macro to trigger AM_CONDITIONAL after PKG_WITH_MODULES dnl check._[VARIABLE-PREFIX] is exported as make variable. AC_DEFUN([PKG_HAVE_WITH_MODULES], [ PKG_WITH_MODULES([$1],[$2],,,[$3],[$4]) AM_CONDITIONAL([HAVE_][$1], [test "$AS_TR_SH([with_]m4_tolower([$1]))" = "yes"]) ])dnl PKG_HAVE_WITH_MODULES dnl PKG_HAVE_DEFINE_WITH_MODULES(VARIABLE-PREFIX, MODULES, dnl [DESCRIPTION], [DEFAULT]) dnl ------------------------------------------------------ dnl dnl Convenience macro to run AM_CONDITIONAL and AC_DEFINE after dnl PKG_WITH_MODULES check. HAVE_[VARIABLE-PREFIX] is exported as make dnl and preprocessor variable. AC_DEFUN([PKG_HAVE_DEFINE_WITH_MODULES], [ PKG_HAVE_WITH_MODULES([$1],[$2],[$3],[$4]) AS_IF([test "$AS_TR_SH([with_]m4_tolower([$1]))" = "yes"], [AC_DEFINE([HAVE_][$1], 1, [Enable ]m4_tolower([$1])[ support])]) ])dnl PKG_HAVE_DEFINE_WITH_MODULES # Copyright (C) 2002-2018 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_AUTOMAKE_VERSION(VERSION) # ---------------------------- # Automake X.Y traces this macro to ensure aclocal.m4 has been # generated from the m4 files accompanying Automake X.Y. # (This private macro should not be called outside this file.) AC_DEFUN([AM_AUTOMAKE_VERSION], [am__api_version='1.16' dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to dnl require some minimum version. Point them to the right macro. m4_if([$1], [1.16.1], [], [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl ]) # _AM_AUTOCONF_VERSION(VERSION) # ----------------------------- # aclocal traces this macro to find the Autoconf version. # This is a private macro too. Using m4_define simplifies # the logic in aclocal, which can simply ignore this definition. m4_define([_AM_AUTOCONF_VERSION], []) # AM_SET_CURRENT_AUTOMAKE_VERSION # ------------------------------- # Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced. # This function is AC_REQUIREd by AM_INIT_AUTOMAKE. AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], [AM_AUTOMAKE_VERSION([1.16.1])dnl m4_ifndef([AC_AUTOCONF_VERSION], [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl _AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))]) # AM_AUX_DIR_EXPAND -*- Autoconf -*- # Copyright (C) 2001-2018 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets # $ac_aux_dir to '$srcdir/foo'. In other projects, it is set to # '$srcdir', '$srcdir/..', or '$srcdir/../..'. # # Of course, Automake must honor this variable whenever it calls a # tool from the auxiliary directory. The problem is that $srcdir (and # therefore $ac_aux_dir as well) can be either absolute or relative, # depending on how configure is run. This is pretty annoying, since # it makes $ac_aux_dir quite unusable in subdirectories: in the top # source directory, any form will work fine, but in subdirectories a # relative path needs to be adjusted first. # # $ac_aux_dir/missing # fails when called from a subdirectory if $ac_aux_dir is relative # $top_srcdir/$ac_aux_dir/missing # fails if $ac_aux_dir is absolute, # fails when called from a subdirectory in a VPATH build with # a relative $ac_aux_dir # # The reason of the latter failure is that $top_srcdir and $ac_aux_dir # are both prefixed by $srcdir. In an in-source build this is usually # harmless because $srcdir is '.', but things will broke when you # start a VPATH build or use an absolute $srcdir. # # So we could use something similar to $top_srcdir/$ac_aux_dir/missing, # iff we strip the leading $srcdir from $ac_aux_dir. That would be: # am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"` # and then we would define $MISSING as # MISSING="\${SHELL} $am_aux_dir/missing" # This will work as long as MISSING is not called from configure, because # unfortunately $(top_srcdir) has no meaning in configure. # However there are other variables, like CC, which are often used in # configure, and could therefore not use this "fixed" $ac_aux_dir. # # Another solution, used here, is to always expand $ac_aux_dir to an # absolute PATH. The drawback is that using absolute paths prevent a # configured tree to be moved without reconfiguration. AC_DEFUN([AM_AUX_DIR_EXPAND], [AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl # Expand $ac_aux_dir to an absolute path. am_aux_dir=`cd "$ac_aux_dir" && pwd` ]) # AM_CONDITIONAL -*- Autoconf -*- # Copyright (C) 1997-2018 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_CONDITIONAL(NAME, SHELL-CONDITION) # ------------------------------------- # Define a conditional. AC_DEFUN([AM_CONDITIONAL], [AC_PREREQ([2.52])dnl m4_if([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])], [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl AC_SUBST([$1_TRUE])dnl AC_SUBST([$1_FALSE])dnl _AM_SUBST_NOTMAKE([$1_TRUE])dnl _AM_SUBST_NOTMAKE([$1_FALSE])dnl m4_define([_AM_COND_VALUE_$1], [$2])dnl if $2; then $1_TRUE= $1_FALSE='#' else $1_TRUE='#' $1_FALSE= fi AC_CONFIG_COMMANDS_PRE( [if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then AC_MSG_ERROR([[conditional "$1" was never defined. Usually this means the macro was only invoked conditionally.]]) fi])]) # Copyright (C) 1999-2018 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # There are a few dirty hacks below to avoid letting 'AC_PROG_CC' be # written in clear, in which case automake, when reading aclocal.m4, # will think it sees a *use*, and therefore will trigger all it's # C support machinery. Also note that it means that autoscan, seeing # CC etc. in the Makefile, will ask for an AC_PROG_CC use... # _AM_DEPENDENCIES(NAME) # ---------------------- # See how the compiler implements dependency checking. # NAME is "CC", "CXX", "OBJC", "OBJCXX", "UPC", or "GJC". # We try a few techniques and use that to set a single cache variable. # # We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was # modified to invoke _AM_DEPENDENCIES(CC); we would have a circular # dependency, and given that the user is not expected to run this macro, # just rely on AC_PROG_CC. AC_DEFUN([_AM_DEPENDENCIES], [AC_REQUIRE([AM_SET_DEPDIR])dnl AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl AC_REQUIRE([AM_MAKE_INCLUDE])dnl AC_REQUIRE([AM_DEP_TRACK])dnl m4_if([$1], [CC], [depcc="$CC" am_compiler_list=], [$1], [CXX], [depcc="$CXX" am_compiler_list=], [$1], [OBJC], [depcc="$OBJC" am_compiler_list='gcc3 gcc'], [$1], [OBJCXX], [depcc="$OBJCXX" am_compiler_list='gcc3 gcc'], [$1], [UPC], [depcc="$UPC" am_compiler_list=], [$1], [GCJ], [depcc="$GCJ" am_compiler_list='gcc3 gcc'], [depcc="$$1" am_compiler_list=]) AC_CACHE_CHECK([dependency style of $depcc], [am_cv_$1_dependencies_compiler_type], [if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then # We make a subdir and do the tests there. Otherwise we can end up # making bogus files that we don't know about and never remove. For # instance it was reported that on HP-UX the gcc test will end up # making a dummy file named 'D' -- because '-MD' means "put the output # in D". rm -rf conftest.dir mkdir conftest.dir # Copy depcomp to subdir because otherwise we won't find it if we're # using a relative directory. cp "$am_depcomp" conftest.dir cd conftest.dir # We will build objects and dependencies in a subdirectory because # it helps to detect inapplicable dependency modes. For instance # both Tru64's cc and ICC support -MD to output dependencies as a # side effect of compilation, but ICC will put the dependencies in # the current directory while Tru64 will put them in the object # directory. mkdir sub am_cv_$1_dependencies_compiler_type=none if test "$am_compiler_list" = ""; then am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp` fi am__universal=false m4_case([$1], [CC], [case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac], [CXX], [case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac]) for depmode in $am_compiler_list; do # Setup a source with many dependencies, because some compilers # like to wrap large dependency lists on column 80 (with \), and # we should not choose a depcomp mode which is confused by this. # # We need to recreate these files for each test, as the compiler may # overwrite some of them when testing with obscure command lines. # This happens at least with the AIX C compiler. : > sub/conftest.c for i in 1 2 3 4 5 6; do echo '#include "conftst'$i'.h"' >> sub/conftest.c # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with # Solaris 10 /bin/sh. echo '/* dummy */' > sub/conftst$i.h done echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf # We check with '-c' and '-o' for the sake of the "dashmstdout" # mode. It turns out that the SunPro C++ compiler does not properly # handle '-M -o', and we need to detect this. Also, some Intel # versions had trouble with output in subdirs. am__obj=sub/conftest.${OBJEXT-o} am__minus_obj="-o $am__obj" case $depmode in gcc) # This depmode causes a compiler race in universal mode. test "$am__universal" = false || continue ;; nosideeffect) # After this tag, mechanisms are not by side-effect, so they'll # only be used when explicitly requested. if test "x$enable_dependency_tracking" = xyes; then continue else break fi ;; msvc7 | msvc7msys | msvisualcpp | msvcmsys) # This compiler won't grok '-c -o', but also, the minuso test has # not run yet. These depmodes are late enough in the game, and # so weak that their functioning should not be impacted. am__obj=conftest.${OBJEXT-o} am__minus_obj= ;; none) break ;; esac if depmode=$depmode \ source=sub/conftest.c object=$am__obj \ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ >/dev/null 2>conftest.err && grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && grep $am__obj sub/conftest.Po > /dev/null 2>&1 && ${MAKE-make} -s -f confmf > /dev/null 2>&1; then # icc doesn't choke on unknown options, it will just issue warnings # or remarks (even with -Werror). So we grep stderr for any message # that says an option was ignored or not supported. # When given -MP, icc 7.0 and 7.1 complain thusly: # icc: Command line warning: ignoring option '-M'; no argument required # The diagnosis changed in icc 8.0: # icc: Command line remark: option '-MP' not supported if (grep 'ignoring option' conftest.err || grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else am_cv_$1_dependencies_compiler_type=$depmode break fi fi done cd .. rm -rf conftest.dir else am_cv_$1_dependencies_compiler_type=none fi ]) AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type]) AM_CONDITIONAL([am__fastdep$1], [ test "x$enable_dependency_tracking" != xno \ && test "$am_cv_$1_dependencies_compiler_type" = gcc3]) ]) # AM_SET_DEPDIR # ------------- # Choose a directory name for dependency files. # This macro is AC_REQUIREd in _AM_DEPENDENCIES. AC_DEFUN([AM_SET_DEPDIR], [AC_REQUIRE([AM_SET_LEADING_DOT])dnl AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl ]) # AM_DEP_TRACK # ------------ AC_DEFUN([AM_DEP_TRACK], [AC_ARG_ENABLE([dependency-tracking], [dnl AS_HELP_STRING( [--enable-dependency-tracking], [do not reject slow dependency extractors]) AS_HELP_STRING( [--disable-dependency-tracking], [speeds up one-time build])]) if test "x$enable_dependency_tracking" != xno; then am_depcomp="$ac_aux_dir/depcomp" AMDEPBACKSLASH='\' am__nodep='_no' fi AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno]) AC_SUBST([AMDEPBACKSLASH])dnl _AM_SUBST_NOTMAKE([AMDEPBACKSLASH])dnl AC_SUBST([am__nodep])dnl _AM_SUBST_NOTMAKE([am__nodep])dnl ]) # Generate code to set up dependency tracking. -*- Autoconf -*- # Copyright (C) 1999-2018 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # _AM_OUTPUT_DEPENDENCY_COMMANDS # ------------------------------ AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS], [{ # Older Autoconf quotes --file arguments for eval, but not when files # are listed without --file. Let's play safe and only enable the eval # if we detect the quoting. # TODO: see whether this extra hack can be removed once we start # requiring Autoconf 2.70 or later. AS_CASE([$CONFIG_FILES], [*\'*], [eval set x "$CONFIG_FILES"], [*], [set x $CONFIG_FILES]) shift # Used to flag and report bootstrapping failures. am_rc=0 for am_mf do # Strip MF so we end up with the name of the file. am_mf=`AS_ECHO(["$am_mf"]) | sed -e 's/:.*$//'` # Check whether this is an Automake generated Makefile which includes # dependency-tracking related rules and includes. # Grep'ing the whole file directly is not great: AIX grep has a line # limit of 2048, but all sed's we know have understand at least 4000. sed -n 's,^am--depfiles:.*,X,p' "$am_mf" | grep X >/dev/null 2>&1 \ || continue am_dirpart=`AS_DIRNAME(["$am_mf"])` am_filepart=`AS_BASENAME(["$am_mf"])` AM_RUN_LOG([cd "$am_dirpart" \ && sed -e '/# am--include-marker/d' "$am_filepart" \ | $MAKE -f - am--depfiles]) || am_rc=$? done if test $am_rc -ne 0; then AC_MSG_FAILURE([Something went wrong bootstrapping makefile fragments for automatic dependency tracking. Try re-running configure with the '--disable-dependency-tracking' option to at least be able to build the package (albeit without support for automatic dependency tracking).]) fi AS_UNSET([am_dirpart]) AS_UNSET([am_filepart]) AS_UNSET([am_mf]) AS_UNSET([am_rc]) rm -f conftest-deps.mk } ])# _AM_OUTPUT_DEPENDENCY_COMMANDS # AM_OUTPUT_DEPENDENCY_COMMANDS # ----------------------------- # This macro should only be invoked once -- use via AC_REQUIRE. # # This code is only required when automatic dependency tracking is enabled. # This creates each '.Po' and '.Plo' makefile fragment that we'll need in # order to bootstrap the dependency handling code. AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS], [AC_CONFIG_COMMANDS([depfiles], [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS], [AMDEP_TRUE="$AMDEP_TRUE" MAKE="${MAKE-make}"])]) # Do all the work for Automake. -*- Autoconf -*- # Copyright (C) 1996-2018 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This macro actually does too much. Some checks are only needed if # your package does certain things. But this isn't really a big deal. dnl Redefine AC_PROG_CC to automatically invoke _AM_PROG_CC_C_O. m4_define([AC_PROG_CC], m4_defn([AC_PROG_CC]) [_AM_PROG_CC_C_O ]) # AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE]) # AM_INIT_AUTOMAKE([OPTIONS]) # ----------------------------------------------- # The call with PACKAGE and VERSION arguments is the old style # call (pre autoconf-2.50), which is being phased out. PACKAGE # and VERSION should now be passed to AC_INIT and removed from # the call to AM_INIT_AUTOMAKE. # We support both call styles for the transition. After # the next Automake release, Autoconf can make the AC_INIT # arguments mandatory, and then we can depend on a new Autoconf # release and drop the old call support. AC_DEFUN([AM_INIT_AUTOMAKE], [AC_PREREQ([2.65])dnl dnl Autoconf wants to disallow AM_ names. We explicitly allow dnl the ones we care about. m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl AC_REQUIRE([AC_PROG_INSTALL])dnl if test "`cd $srcdir && pwd`" != "`pwd`"; then # Use -I$(srcdir) only when $(srcdir) != ., so that make's output # is not polluted with repeated "-I." AC_SUBST([am__isrc], [' -I$(srcdir)'])_AM_SUBST_NOTMAKE([am__isrc])dnl # test to see if srcdir already configured if test -f $srcdir/config.status; then AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) fi fi # test whether we have cygpath if test -z "$CYGPATH_W"; then if (cygpath --version) >/dev/null 2>/dev/null; then CYGPATH_W='cygpath -w' else CYGPATH_W=echo fi fi AC_SUBST([CYGPATH_W]) # Define the identity of the package. dnl Distinguish between old-style and new-style calls. m4_ifval([$2], [AC_DIAGNOSE([obsolete], [$0: two- and three-arguments forms are deprecated.]) m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl AC_SUBST([PACKAGE], [$1])dnl AC_SUBST([VERSION], [$2])], [_AM_SET_OPTIONS([$1])dnl dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT. m4_if( m4_ifdef([AC_PACKAGE_NAME], [ok]):m4_ifdef([AC_PACKAGE_VERSION], [ok]), [ok:ok],, [m4_fatal([AC_INIT should be called with package and version arguments])])dnl AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl _AM_IF_OPTION([no-define],, [AC_DEFINE_UNQUOTED([PACKAGE], ["$PACKAGE"], [Name of package]) AC_DEFINE_UNQUOTED([VERSION], ["$VERSION"], [Version number of package])])dnl # Some tools Automake needs. AC_REQUIRE([AM_SANITY_CHECK])dnl AC_REQUIRE([AC_ARG_PROGRAM])dnl AM_MISSING_PROG([ACLOCAL], [aclocal-${am__api_version}]) AM_MISSING_PROG([AUTOCONF], [autoconf]) AM_MISSING_PROG([AUTOMAKE], [automake-${am__api_version}]) AM_MISSING_PROG([AUTOHEADER], [autoheader]) AM_MISSING_PROG([MAKEINFO], [makeinfo]) AC_REQUIRE([AM_PROG_INSTALL_SH])dnl AC_REQUIRE([AM_PROG_INSTALL_STRIP])dnl AC_REQUIRE([AC_PROG_MKDIR_P])dnl # For better backward compatibility. To be removed once Automake 1.9.x # dies out for good. For more background, see: # # AC_SUBST([mkdir_p], ['$(MKDIR_P)']) # We need awk for the "check" target (and possibly the TAP driver). The # system "awk" is bad on some platforms. AC_REQUIRE([AC_PROG_AWK])dnl AC_REQUIRE([AC_PROG_MAKE_SET])dnl AC_REQUIRE([AM_SET_LEADING_DOT])dnl _AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])], [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])], [_AM_PROG_TAR([v7])])]) _AM_IF_OPTION([no-dependencies],, [AC_PROVIDE_IFELSE([AC_PROG_CC], [_AM_DEPENDENCIES([CC])], [m4_define([AC_PROG_CC], m4_defn([AC_PROG_CC])[_AM_DEPENDENCIES([CC])])])dnl AC_PROVIDE_IFELSE([AC_PROG_CXX], [_AM_DEPENDENCIES([CXX])], [m4_define([AC_PROG_CXX], m4_defn([AC_PROG_CXX])[_AM_DEPENDENCIES([CXX])])])dnl AC_PROVIDE_IFELSE([AC_PROG_OBJC], [_AM_DEPENDENCIES([OBJC])], [m4_define([AC_PROG_OBJC], m4_defn([AC_PROG_OBJC])[_AM_DEPENDENCIES([OBJC])])])dnl AC_PROVIDE_IFELSE([AC_PROG_OBJCXX], [_AM_DEPENDENCIES([OBJCXX])], [m4_define([AC_PROG_OBJCXX], m4_defn([AC_PROG_OBJCXX])[_AM_DEPENDENCIES([OBJCXX])])])dnl ]) AC_REQUIRE([AM_SILENT_RULES])dnl dnl The testsuite driver may need to know about EXEEXT, so add the dnl 'am__EXEEXT' conditional if _AM_COMPILER_EXEEXT was seen. This dnl macro is hooked onto _AC_COMPILER_EXEEXT early, see below. AC_CONFIG_COMMANDS_PRE(dnl [m4_provide_if([_AM_COMPILER_EXEEXT], [AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"])])])dnl # POSIX will say in a future version that running "rm -f" with no argument # is OK; and we want to be able to make that assumption in our Makefile # recipes. So use an aggressive probe to check that the usage we want is # actually supported "in the wild" to an acceptable degree. # See automake bug#10828. # To make any issue more visible, cause the running configure to be aborted # by default if the 'rm' program in use doesn't match our expectations; the # user can still override this though. if rm -f && rm -fr && rm -rf; then : OK; else cat >&2 <<'END' Oops! Your 'rm' program seems unable to run without file operands specified on the command line, even when the '-f' option is present. This is contrary to the behaviour of most rm programs out there, and not conforming with the upcoming POSIX standard: Please tell bug-automake@gnu.org about your system, including the value of your $PATH and any error possibly output before this message. This can help us improve future automake versions. END if test x"$ACCEPT_INFERIOR_RM_PROGRAM" = x"yes"; then echo 'Configuration will proceed anyway, since you have set the' >&2 echo 'ACCEPT_INFERIOR_RM_PROGRAM variable to "yes"' >&2 echo >&2 else cat >&2 <<'END' Aborting the configuration process, to ensure you take notice of the issue. You can download and install GNU coreutils to get an 'rm' implementation that behaves properly: . If you want to complete the configuration process using your problematic 'rm' anyway, export the environment variable ACCEPT_INFERIOR_RM_PROGRAM to "yes", and re-run configure. END AC_MSG_ERROR([Your 'rm' program is bad, sorry.]) fi fi dnl The trailing newline in this macro's definition is deliberate, for dnl backward compatibility and to allow trailing 'dnl'-style comments dnl after the AM_INIT_AUTOMAKE invocation. See automake bug#16841. ]) dnl Hook into '_AC_COMPILER_EXEEXT' early to learn its expansion. Do not dnl add the conditional right here, as _AC_COMPILER_EXEEXT may be further dnl mangled by Autoconf and run in a shell conditional statement. m4_define([_AC_COMPILER_EXEEXT], m4_defn([_AC_COMPILER_EXEEXT])[m4_provide([_AM_COMPILER_EXEEXT])]) # When config.status generates a header, we must update the stamp-h file. # This file resides in the same directory as the config header # that is generated. The stamp files are numbered to have different names. # Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the # loop where config.status creates the headers, so we can generate # our stamp files there. AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK], [# Compute $1's index in $config_headers. _am_arg=$1 _am_stamp_count=1 for _am_header in $config_headers :; do case $_am_header in $_am_arg | $_am_arg:* ) break ;; * ) _am_stamp_count=`expr $_am_stamp_count + 1` ;; esac done echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count]) # Copyright (C) 2001-2018 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_PROG_INSTALL_SH # ------------------ # Define $install_sh. AC_DEFUN([AM_PROG_INSTALL_SH], [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl if test x"${install_sh+set}" != xset; then case $am_aux_dir in *\ * | *\ *) install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; *) install_sh="\${SHELL} $am_aux_dir/install-sh" esac fi AC_SUBST([install_sh])]) # Copyright (C) 2003-2018 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # Check whether the underlying file-system supports filenames # with a leading dot. For instance MS-DOS doesn't. AC_DEFUN([AM_SET_LEADING_DOT], [rm -rf .tst 2>/dev/null mkdir .tst 2>/dev/null if test -d .tst; then am__leading_dot=. else am__leading_dot=_ fi rmdir .tst 2>/dev/null AC_SUBST([am__leading_dot])]) # Check to see how 'make' treats includes. -*- Autoconf -*- # Copyright (C) 2001-2018 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_MAKE_INCLUDE() # ----------------- # Check whether make has an 'include' directive that can support all # the idioms we need for our automatic dependency tracking code. AC_DEFUN([AM_MAKE_INCLUDE], [AC_MSG_CHECKING([whether ${MAKE-make} supports the include directive]) cat > confinc.mk << 'END' am__doit: @echo this is the am__doit target >confinc.out .PHONY: am__doit END am__include="#" am__quote= # BSD make does it like this. echo '.include "confinc.mk" # ignored' > confmf.BSD # Other make implementations (GNU, Solaris 10, AIX) do it like this. echo 'include confinc.mk # ignored' > confmf.GNU _am_result=no for s in GNU BSD; do AM_RUN_LOG([${MAKE-make} -f confmf.$s && cat confinc.out]) AS_CASE([$?:`cat confinc.out 2>/dev/null`], ['0:this is the am__doit target'], [AS_CASE([$s], [BSD], [am__include='.include' am__quote='"'], [am__include='include' am__quote=''])]) if test "$am__include" != "#"; then _am_result="yes ($s style)" break fi done rm -f confinc.* confmf.* AC_MSG_RESULT([${_am_result}]) AC_SUBST([am__include])]) AC_SUBST([am__quote])]) # Fake the existence of programs that GNU maintainers use. -*- Autoconf -*- # Copyright (C) 1997-2018 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_MISSING_PROG(NAME, PROGRAM) # ------------------------------ AC_DEFUN([AM_MISSING_PROG], [AC_REQUIRE([AM_MISSING_HAS_RUN]) $1=${$1-"${am_missing_run}$2"} AC_SUBST($1)]) # AM_MISSING_HAS_RUN # ------------------ # Define MISSING if not defined so far and test if it is modern enough. # If it is, set am_missing_run to use it, otherwise, to nothing. AC_DEFUN([AM_MISSING_HAS_RUN], [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl AC_REQUIRE_AUX_FILE([missing])dnl if test x"${MISSING+set}" != xset; then case $am_aux_dir in *\ * | *\ *) MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; *) MISSING="\${SHELL} $am_aux_dir/missing" ;; esac fi # Use eval to expand $SHELL if eval "$MISSING --is-lightweight"; then am_missing_run="$MISSING " else am_missing_run= AC_MSG_WARN(['missing' script is too old or missing]) fi ]) # Helper functions for option handling. -*- Autoconf -*- # Copyright (C) 2001-2018 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # _AM_MANGLE_OPTION(NAME) # ----------------------- AC_DEFUN([_AM_MANGLE_OPTION], [[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])]) # _AM_SET_OPTION(NAME) # -------------------- # Set option NAME. Presently that only means defining a flag for this option. AC_DEFUN([_AM_SET_OPTION], [m4_define(_AM_MANGLE_OPTION([$1]), [1])]) # _AM_SET_OPTIONS(OPTIONS) # ------------------------ # OPTIONS is a space-separated list of Automake options. AC_DEFUN([_AM_SET_OPTIONS], [m4_foreach_w([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])]) # _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET]) # ------------------------------------------- # Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. AC_DEFUN([_AM_IF_OPTION], [m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])]) # Copyright (C) 1999-2018 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # _AM_PROG_CC_C_O # --------------- # Like AC_PROG_CC_C_O, but changed for automake. We rewrite AC_PROG_CC # to automatically call this. AC_DEFUN([_AM_PROG_CC_C_O], [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl AC_REQUIRE_AUX_FILE([compile])dnl AC_LANG_PUSH([C])dnl AC_CACHE_CHECK( [whether $CC understands -c and -o together], [am_cv_prog_cc_c_o], [AC_LANG_CONFTEST([AC_LANG_PROGRAM([])]) # Make sure it works both with $CC and with simple cc. # Following AC_PROG_CC_C_O, we do the test twice because some # compilers refuse to overwrite an existing .o file with -o, # though they will create one. am_cv_prog_cc_c_o=yes for am_i in 1 2; do if AM_RUN_LOG([$CC -c conftest.$ac_ext -o conftest2.$ac_objext]) \ && test -f conftest2.$ac_objext; then : OK else am_cv_prog_cc_c_o=no break fi done rm -f core conftest* unset am_i]) if test "$am_cv_prog_cc_c_o" != yes; then # Losing compiler, so override with the script. # FIXME: It is wrong to rewrite CC. # But if we don't then we get into trouble of one sort or another. # A longer-term fix would be to have automake use am__CC in this case, # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)" CC="$am_aux_dir/compile $CC" fi AC_LANG_POP([C])]) # For backward compatibility. AC_DEFUN_ONCE([AM_PROG_CC_C_O], [AC_REQUIRE([AC_PROG_CC])]) # Copyright (C) 2001-2018 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_RUN_LOG(COMMAND) # ------------------- # Run COMMAND, save the exit status in ac_status, and log it. # (This has been adapted from Autoconf's _AC_RUN_LOG macro.) AC_DEFUN([AM_RUN_LOG], [{ echo "$as_me:$LINENO: $1" >&AS_MESSAGE_LOG_FD ($1) >&AS_MESSAGE_LOG_FD 2>&AS_MESSAGE_LOG_FD ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD (exit $ac_status); }]) # Check to make sure that the build environment is sane. -*- Autoconf -*- # Copyright (C) 1996-2018 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_SANITY_CHECK # --------------- AC_DEFUN([AM_SANITY_CHECK], [AC_MSG_CHECKING([whether build environment is sane]) # Reject unsafe characters in $srcdir or the absolute working directory # name. Accept space and tab only in the latter. am_lf=' ' case `pwd` in *[[\\\"\#\$\&\'\`$am_lf]]*) AC_MSG_ERROR([unsafe absolute working directory name]);; esac case $srcdir in *[[\\\"\#\$\&\'\`$am_lf\ \ ]]*) AC_MSG_ERROR([unsafe srcdir value: '$srcdir']);; esac # Do 'set' in a subshell so we don't clobber the current shell's # arguments. Must try -L first in case configure is actually a # symlink; some systems play weird games with the mod time of symlinks # (eg FreeBSD returns the mod time of the symlink's containing # directory). if ( am_has_slept=no for am_try in 1 2; do echo "timestamp, slept: $am_has_slept" > conftest.file set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` if test "$[*]" = "X"; then # -L didn't work. set X `ls -t "$srcdir/configure" conftest.file` fi if test "$[*]" != "X $srcdir/configure conftest.file" \ && test "$[*]" != "X conftest.file $srcdir/configure"; then # If neither matched, then we have a broken ls. This can happen # if, for instance, CONFIG_SHELL is bash and it inherits a # broken ls alias from the environment. This has actually # happened. Such a system could not be considered "sane". AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken alias in your environment]) fi if test "$[2]" = conftest.file || test $am_try -eq 2; then break fi # Just in case. sleep 1 am_has_slept=yes done test "$[2]" = conftest.file ) then # Ok. : else AC_MSG_ERROR([newly created file is older than distributed files! Check your system clock]) fi AC_MSG_RESULT([yes]) # If we didn't sleep, we still need to ensure time stamps of config.status and # generated files are strictly newer. am_sleep_pid= if grep 'slept: no' conftest.file >/dev/null 2>&1; then ( sleep 1 ) & am_sleep_pid=$! fi AC_CONFIG_COMMANDS_PRE( [AC_MSG_CHECKING([that generated files are newer than configure]) if test -n "$am_sleep_pid"; then # Hide warnings about reused PIDs. wait $am_sleep_pid 2>/dev/null fi AC_MSG_RESULT([done])]) rm -f conftest.file ]) # Copyright (C) 2009-2018 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_SILENT_RULES([DEFAULT]) # -------------------------- # Enable less verbose build rules; with the default set to DEFAULT # ("yes" being less verbose, "no" or empty being verbose). AC_DEFUN([AM_SILENT_RULES], [AC_ARG_ENABLE([silent-rules], [dnl AS_HELP_STRING( [--enable-silent-rules], [less verbose build output (undo: "make V=1")]) AS_HELP_STRING( [--disable-silent-rules], [verbose build output (undo: "make V=0")])dnl ]) case $enable_silent_rules in @%:@ ((( yes) AM_DEFAULT_VERBOSITY=0;; no) AM_DEFAULT_VERBOSITY=1;; *) AM_DEFAULT_VERBOSITY=m4_if([$1], [yes], [0], [1]);; esac dnl dnl A few 'make' implementations (e.g., NonStop OS and NextStep) dnl do not support nested variable expansions. dnl See automake bug#9928 and bug#10237. am_make=${MAKE-make} AC_CACHE_CHECK([whether $am_make supports nested variables], [am_cv_make_support_nested_variables], [if AS_ECHO([['TRUE=$(BAR$(V)) BAR0=false BAR1=true V=1 am__doit: @$(TRUE) .PHONY: am__doit']]) | $am_make -f - >/dev/null 2>&1; then am_cv_make_support_nested_variables=yes else am_cv_make_support_nested_variables=no fi]) if test $am_cv_make_support_nested_variables = yes; then dnl Using '$V' instead of '$(V)' breaks IRIX make. AM_V='$(V)' AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)' else AM_V=$AM_DEFAULT_VERBOSITY AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY fi AC_SUBST([AM_V])dnl AM_SUBST_NOTMAKE([AM_V])dnl AC_SUBST([AM_DEFAULT_V])dnl AM_SUBST_NOTMAKE([AM_DEFAULT_V])dnl AC_SUBST([AM_DEFAULT_VERBOSITY])dnl AM_BACKSLASH='\' AC_SUBST([AM_BACKSLASH])dnl _AM_SUBST_NOTMAKE([AM_BACKSLASH])dnl ]) # Copyright (C) 2001-2018 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_PROG_INSTALL_STRIP # --------------------- # One issue with vendor 'install' (even GNU) is that you can't # specify the program used to strip binaries. This is especially # annoying in cross-compiling environments, where the build's strip # is unlikely to handle the host's binaries. # Fortunately install-sh will honor a STRIPPROG variable, so we # always use install-sh in "make install-strip", and initialize # STRIPPROG with the value of the STRIP variable (set by the user). AC_DEFUN([AM_PROG_INSTALL_STRIP], [AC_REQUIRE([AM_PROG_INSTALL_SH])dnl # Installed binaries are usually stripped using 'strip' when the user # run "make install-strip". However 'strip' might not be the right # tool to use in cross-compilation environments, therefore Automake # will honor the 'STRIP' environment variable to overrule this program. dnl Don't test for $cross_compiling = yes, because it might be 'maybe'. if test "$cross_compiling" != no; then AC_CHECK_TOOL([STRIP], [strip], :) fi INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" AC_SUBST([INSTALL_STRIP_PROGRAM])]) # Copyright (C) 2006-2018 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # _AM_SUBST_NOTMAKE(VARIABLE) # --------------------------- # Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in. # This macro is traced by Automake. AC_DEFUN([_AM_SUBST_NOTMAKE]) # AM_SUBST_NOTMAKE(VARIABLE) # -------------------------- # Public sister of _AM_SUBST_NOTMAKE. AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)]) # Check how to create a tarball. -*- Autoconf -*- # Copyright (C) 2004-2018 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # _AM_PROG_TAR(FORMAT) # -------------------- # Check how to create a tarball in format FORMAT. # FORMAT should be one of 'v7', 'ustar', or 'pax'. # # Substitute a variable $(am__tar) that is a command # writing to stdout a FORMAT-tarball containing the directory # $tardir. # tardir=directory && $(am__tar) > result.tar # # Substitute a variable $(am__untar) that extract such # a tarball read from stdin. # $(am__untar) < result.tar # AC_DEFUN([_AM_PROG_TAR], [# Always define AMTAR for backward compatibility. Yes, it's still used # in the wild :-( We should find a proper way to deprecate it ... AC_SUBST([AMTAR], ['$${TAR-tar}']) # We'll loop over all known methods to create a tar archive until one works. _am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none' m4_if([$1], [v7], [am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -'], [m4_case([$1], [ustar], [# The POSIX 1988 'ustar' format is defined with fixed-size fields. # There is notably a 21 bits limit for the UID and the GID. In fact, # the 'pax' utility can hang on bigger UID/GID (see automake bug#8343 # and bug#13588). am_max_uid=2097151 # 2^21 - 1 am_max_gid=$am_max_uid # The $UID and $GID variables are not portable, so we need to resort # to the POSIX-mandated id(1) utility. Errors in the 'id' calls # below are definitely unexpected, so allow the users to see them # (that is, avoid stderr redirection). am_uid=`id -u || echo unknown` am_gid=`id -g || echo unknown` AC_MSG_CHECKING([whether UID '$am_uid' is supported by ustar format]) if test $am_uid -le $am_max_uid; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) _am_tools=none fi AC_MSG_CHECKING([whether GID '$am_gid' is supported by ustar format]) if test $am_gid -le $am_max_gid; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) _am_tools=none fi], [pax], [], [m4_fatal([Unknown tar format])]) AC_MSG_CHECKING([how to create a $1 tar archive]) # Go ahead even if we have the value already cached. We do so because we # need to set the values for the 'am__tar' and 'am__untar' variables. _am_tools=${am_cv_prog_tar_$1-$_am_tools} for _am_tool in $_am_tools; do case $_am_tool in gnutar) for _am_tar in tar gnutar gtar; do AM_RUN_LOG([$_am_tar --version]) && break done am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"' am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"' am__untar="$_am_tar -xf -" ;; plaintar) # Must skip GNU tar: if it does not support --format= it doesn't create # ustar tarball either. (tar --version) >/dev/null 2>&1 && continue am__tar='tar chf - "$$tardir"' am__tar_='tar chf - "$tardir"' am__untar='tar xf -' ;; pax) am__tar='pax -L -x $1 -w "$$tardir"' am__tar_='pax -L -x $1 -w "$tardir"' am__untar='pax -r' ;; cpio) am__tar='find "$$tardir" -print | cpio -o -H $1 -L' am__tar_='find "$tardir" -print | cpio -o -H $1 -L' am__untar='cpio -i -H $1 -d' ;; none) am__tar=false am__tar_=false am__untar=false ;; esac # If the value was cached, stop now. We just wanted to have am__tar # and am__untar set. test -n "${am_cv_prog_tar_$1}" && break # tar/untar a dummy directory, and stop if the command works. rm -rf conftest.dir mkdir conftest.dir echo GrepMe > conftest.dir/file AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar]) rm -rf conftest.dir if test -s conftest.tar; then AM_RUN_LOG([$am__untar /dev/null 2>&1 && break fi done rm -rf conftest.dir AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool]) AC_MSG_RESULT([$am_cv_prog_tar_$1])]) AC_SUBST([am__tar]) AC_SUBST([am__untar]) ]) # _AM_PROG_TAR freewheeling-0.6.6/compile000077500000000000000000000163271370736313100155620ustar00rootroot00000000000000#! /bin/sh # Wrapper for compilers which do not understand '-c -o'. scriptversion=2018-03-07.03; # UTC # Copyright (C) 1999-2018 Free Software Foundation, Inc. # Written by Tom Tromey . # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, 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 . # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # This file is maintained in Automake, please report # bugs to or send patches to # . nl=' ' # We need space, tab and new line, in precisely that order. Quoting is # there to prevent tools from complaining about whitespace usage. IFS=" "" $nl" file_conv= # func_file_conv build_file lazy # Convert a $build file to $host form and store it in $file # Currently only supports Windows hosts. If the determined conversion # type is listed in (the comma separated) LAZY, no conversion will # take place. func_file_conv () { file=$1 case $file in / | /[!/]*) # absolute file, and not a UNC file if test -z "$file_conv"; then # lazily determine how to convert abs files case `uname -s` in MINGW*) file_conv=mingw ;; CYGWIN*) file_conv=cygwin ;; *) file_conv=wine ;; esac fi case $file_conv/,$2, in *,$file_conv,*) ;; mingw/*) file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'` ;; cygwin/*) file=`cygpath -m "$file" || echo "$file"` ;; wine/*) file=`winepath -w "$file" || echo "$file"` ;; esac ;; esac } # func_cl_dashL linkdir # Make cl look for libraries in LINKDIR func_cl_dashL () { func_file_conv "$1" if test -z "$lib_path"; then lib_path=$file else lib_path="$lib_path;$file" fi linker_opts="$linker_opts -LIBPATH:$file" } # func_cl_dashl library # Do a library search-path lookup for cl func_cl_dashl () { lib=$1 found=no save_IFS=$IFS IFS=';' for dir in $lib_path $LIB do IFS=$save_IFS if $shared && test -f "$dir/$lib.dll.lib"; then found=yes lib=$dir/$lib.dll.lib break fi if test -f "$dir/$lib.lib"; then found=yes lib=$dir/$lib.lib break fi if test -f "$dir/lib$lib.a"; then found=yes lib=$dir/lib$lib.a break fi done IFS=$save_IFS if test "$found" != yes; then lib=$lib.lib fi } # func_cl_wrapper cl arg... # Adjust compile command to suit cl func_cl_wrapper () { # Assume a capable shell lib_path= shared=: linker_opts= for arg do if test -n "$eat"; then eat= else case $1 in -o) # configure might choose to run compile as 'compile cc -o foo foo.c'. eat=1 case $2 in *.o | *.[oO][bB][jJ]) func_file_conv "$2" set x "$@" -Fo"$file" shift ;; *) func_file_conv "$2" set x "$@" -Fe"$file" shift ;; esac ;; -I) eat=1 func_file_conv "$2" mingw set x "$@" -I"$file" shift ;; -I*) func_file_conv "${1#-I}" mingw set x "$@" -I"$file" shift ;; -l) eat=1 func_cl_dashl "$2" set x "$@" "$lib" shift ;; -l*) func_cl_dashl "${1#-l}" set x "$@" "$lib" shift ;; -L) eat=1 func_cl_dashL "$2" ;; -L*) func_cl_dashL "${1#-L}" ;; -static) shared=false ;; -Wl,*) arg=${1#-Wl,} save_ifs="$IFS"; IFS=',' for flag in $arg; do IFS="$save_ifs" linker_opts="$linker_opts $flag" done IFS="$save_ifs" ;; -Xlinker) eat=1 linker_opts="$linker_opts $2" ;; -*) set x "$@" "$1" shift ;; *.cc | *.CC | *.cxx | *.CXX | *.[cC]++) func_file_conv "$1" set x "$@" -Tp"$file" shift ;; *.c | *.cpp | *.CPP | *.lib | *.LIB | *.Lib | *.OBJ | *.obj | *.[oO]) func_file_conv "$1" mingw set x "$@" "$file" shift ;; *) set x "$@" "$1" shift ;; esac fi shift done if test -n "$linker_opts"; then linker_opts="-link$linker_opts" fi exec "$@" $linker_opts exit 1 } eat= case $1 in '') echo "$0: No command. Try '$0 --help' for more information." 1>&2 exit 1; ;; -h | --h*) cat <<\EOF Usage: compile [--help] [--version] PROGRAM [ARGS] Wrapper for compilers which do not understand '-c -o'. Remove '-o dest.o' from ARGS, run PROGRAM with the remaining arguments, and rename the output as expected. If you are trying to build a whole package this is not the right script to run: please start by reading the file 'INSTALL'. Report bugs to . EOF exit $? ;; -v | --v*) echo "compile $scriptversion" exit $? ;; cl | *[/\\]cl | cl.exe | *[/\\]cl.exe | \ icl | *[/\\]icl | icl.exe | *[/\\]icl.exe ) func_cl_wrapper "$@" # Doesn't return... ;; esac ofile= cfile= for arg do if test -n "$eat"; then eat= else case $1 in -o) # configure might choose to run compile as 'compile cc -o foo foo.c'. # So we strip '-o arg' only if arg is an object. eat=1 case $2 in *.o | *.obj) ofile=$2 ;; *) set x "$@" -o "$2" shift ;; esac ;; *.c) cfile=$1 set x "$@" "$1" shift ;; *) set x "$@" "$1" shift ;; esac fi shift done if test -z "$ofile" || test -z "$cfile"; then # If no '-o' option was seen then we might have been invoked from a # pattern rule where we don't need one. That is ok -- this is a # normal compilation that the losing compiler can handle. If no # '.c' file was seen then we are probably linking. That is also # ok. exec "$@" fi # Name of file we expect compiler to create. cofile=`echo "$cfile" | sed 's|^.*[\\/]||; s|^[a-zA-Z]:||; s/\.c$/.o/'` # Create the lock directory. # Note: use '[/\\:.-]' here to ensure that we don't use the same name # that we are using for the .o file. Also, base the name on the expected # object file name, since that is what matters with a parallel build. lockdir=`echo "$cofile" | sed -e 's|[/\\:.-]|_|g'`.d while true; do if mkdir "$lockdir" >/dev/null 2>&1; then break fi sleep 1 done # FIXME: race condition here if user kills between mkdir and trap. trap "rmdir '$lockdir'; exit 1" 1 2 15 # Run the compile. "$@" ret=$? if test -f "$cofile"; then test "$cofile" = "$ofile" || mv "$cofile" "$ofile" elif test -f "${cofile}bj"; then test "${cofile}bj" = "$ofile" || mv "${cofile}bj" "$ofile" fi rmdir "$lockdir" exit $ret # Local Variables: # mode: shell-script # sh-indentation: 2 # eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC0" # time-stamp-end: "; # UTC" # End: freewheeling-0.6.6/configure000077500000000000000000007662371370736313100161270ustar00rootroot00000000000000#! /bin/sh # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.69 for fweelin 0.6.6. # # Report bugs to . # # # Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. # # # This configure script is free software; the Free Software Foundation # gives unlimited permission to copy, distribute and modify it. ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH # Use a proper internal environment variable to ensure we don't fall # into an infinite loop, continuously re-executing ourselves. if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then _as_can_reexec=no; export _as_can_reexec; # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. $as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 as_fn_exit 255 fi # We don't want this to propagate to other subprocesses. { _as_can_reexec=; unset _as_can_reexec;} if test "x$CONFIG_SHELL" = x; then as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which # is contrary to our usage. Disable this feature. alias -g '\${1+\"\$@\"}'='\"\$@\"' setopt NO_GLOB_SUBST else case \`(set -o) 2>/dev/null\` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi " as_required="as_fn_return () { (exit \$1); } as_fn_success () { as_fn_return 0; } as_fn_failure () { as_fn_return 1; } as_fn_ret_success () { return 0; } as_fn_ret_failure () { return 1; } exitcode=0 as_fn_success || { exitcode=1; echo as_fn_success failed.; } as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : else exitcode=1; echo positional parameters were not saved. fi test x\$exitcode = x0 || exit 1 test -x / || exit 1" as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 test \$(( 1 + 1 )) = 2 || exit 1" if (eval "$as_required") 2>/dev/null; then : as_have_required=yes else as_have_required=no fi if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR as_found=false for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. as_found=: case $as_dir in #( /*) for as_base in sh bash ksh sh5; do # Try only shells that exist, to save several forks. as_shell=$as_dir/$as_base if { test -f "$as_shell" || test -f "$as_shell.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : CONFIG_SHELL=$as_shell as_have_required=yes if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : break 2 fi fi done;; esac as_found=false done $as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : CONFIG_SHELL=$SHELL as_have_required=yes fi; } IFS=$as_save_IFS if test "x$CONFIG_SHELL" != x; then : export CONFIG_SHELL # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. $as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 exit 255 fi if test x$as_have_required = xno; then : $as_echo "$0: This script requires a shell more modern than all" $as_echo "$0: the shells that I found on your system." if test x${ZSH_VERSION+set} = xset ; then $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" $as_echo "$0: be upgraded to zsh 4.3.4 or later." else $as_echo "$0: Please tell bug-autoconf@gnu.org and $0: https://github.com/free-wheeling/freewheeling/issues $0: about your system, including any error possibly output $0: before this message. Then install a modern shell, or $0: manually run the script under such a shell if you do $0: have one." fi exit 1 fi fi fi SHELL=${CONFIG_SHELL-/bin/sh} export SHELL # Unset more variables known to interfere with behavior of common tools. CLICOLOR_FORCE= GREP_OPTIONS= unset CLICOLOR_FORCE GREP_OPTIONS ## --------------------- ## ## M4sh Shell Functions. ## ## --------------------- ## # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits as_lineno_1=$LINENO as_lineno_1a=$LINENO as_lineno_2=$LINENO as_lineno_2a=$LINENO eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) sed -n ' p /[$]LINENO/= ' <$as_myself | sed ' s/[$]LINENO.*/&-/ t lineno b :lineno N :loop s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ t loop s/-\n.*// ' >$as_me.lineno && chmod +x "$as_me.lineno" || { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } # If we had to re-execute with $CONFIG_SHELL, we're ensured to have # already done that, so ensure we don't try to do so again and fall # in an infinite loop. This has already happened in practice. _as_can_reexec=no; export _as_can_reexec # Don't try to exec as it changes $[0], causing all sort of problems # (the dirname of $[0] is not the place where we might find the # original and so on. Autoconf is especially sensitive to this). . "./$as_me.lineno" # Exit status is that of the last command. exit } ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" test -n "$DJDIR" || exec 7<&0 &1 # Name of the host. # hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, # so uname gets run too. ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` # # Initializations. # ac_default_prefix=/usr/local ac_clean_files= ac_config_libobj_dir=. LIBOBJS= cross_compiling=no subdirs= MFLAGS= MAKEFLAGS= # Identity of this package. PACKAGE_NAME='fweelin' PACKAGE_TARNAME='fweelin' PACKAGE_VERSION='0.6.6' PACKAGE_STRING='fweelin 0.6.6' PACKAGE_BUGREPORT='https://github.com/free-wheeling/freewheeling/issues' PACKAGE_URL='' ac_unique_file="src/fweelin.cc" # Factoring default headers for most tests. ac_includes_default="\ #include #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_STAT_H # include #endif #ifdef STDC_HEADERS # include # include #else # ifdef HAVE_STDLIB_H # include # endif #endif #ifdef HAVE_STRING_H # if !defined STDC_HEADERS && defined HAVE_MEMORY_H # include # endif # include #endif #ifdef HAVE_STRINGS_H # include #endif #ifdef HAVE_INTTYPES_H # include #endif #ifdef HAVE_STDINT_H # include #endif #ifdef HAVE_UNISTD_H # include #endif" ac_subst_vars='am__EXEEXT_FALSE am__EXEEXT_TRUE LTLIBOBJS POW_LIB LIBOBJS ALLOCA EGREP GREP SDL_LIBS SDL_CFLAGS PKG_CONFIG_LIBDIR PKG_CONFIG_PATH PKG_CONFIG X_EXTRA_LIBS X_LIBS X_PRE_LIBS X_CFLAGS CPP XMKMF am__fastdepCC_FALSE am__fastdepCC_TRUE CCDEPMODE ac_ct_CC CFLAGS CC am__fastdepCXX_FALSE am__fastdepCXX_TRUE CXXDEPMODE am__nodep AMDEPBACKSLASH AMDEP_FALSE AMDEP_TRUE am__include DEPDIR OBJEXT EXEEXT ac_ct_CXX CPPFLAGS LDFLAGS CXXFLAGS CXX AM_BACKSLASH AM_DEFAULT_VERBOSITY AM_DEFAULT_V AM_V am__untar am__tar AMTAR am__leading_dot SET_MAKE AWK mkdir_p MKDIR_P INSTALL_STRIP_PROGRAM STRIP install_sh MAKEINFO AUTOHEADER AUTOMAKE AUTOCONF ACLOCAL VERSION PACKAGE CYGPATH_W am__isrc INSTALL_DATA INSTALL_SCRIPT INSTALL_PROGRAM target_alias host_alias build_alias LIBS ECHO_T ECHO_N ECHO_C DEFS mandir localedir libdir psdir pdfdir dvidir htmldir infodir docdir oldincludedir includedir localstatedir sharedstatedir sysconfdir datadir datarootdir libexecdir sbindir bindir program_transform_name prefix exec_prefix PACKAGE_URL PACKAGE_BUGREPORT PACKAGE_STRING PACKAGE_VERSION PACKAGE_TARNAME PACKAGE_NAME PATH_SEPARATOR SHELL am__quote' ac_subst_files='' ac_user_opts=' enable_option_checking enable_silent_rules enable_fluidsynth enable_video enable_lcd enable_dependency_tracking with_x ' ac_precious_vars='build_alias host_alias target_alias CXX CXXFLAGS LDFLAGS LIBS CPPFLAGS CCC CC CFLAGS XMKMF CPP PKG_CONFIG PKG_CONFIG_PATH PKG_CONFIG_LIBDIR SDL_CFLAGS SDL_LIBS' # Initialize some variables set by options. ac_init_help= ac_init_version=false ac_unrecognized_opts= ac_unrecognized_sep= # The variables have the same names as the options, with # dashes changed to underlines. cache_file=/dev/null exec_prefix=NONE no_create= no_recursion= prefix=NONE program_prefix=NONE program_suffix=NONE program_transform_name=s,x,x, silent= site= srcdir= verbose= x_includes=NONE x_libraries=NONE # Installation directory options. # These are left unexpanded so users can "make install exec_prefix=/foo" # and all the variables that are supposed to be based on exec_prefix # by default will actually change. # Use braces instead of parens because sh, perl, etc. also accept them. # (The list follows the same order as the GNU Coding Standards.) bindir='${exec_prefix}/bin' sbindir='${exec_prefix}/sbin' libexecdir='${exec_prefix}/libexec' datarootdir='${prefix}/share' datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' infodir='${datarootdir}/info' htmldir='${docdir}' dvidir='${docdir}' pdfdir='${docdir}' psdir='${docdir}' libdir='${exec_prefix}/lib' localedir='${datarootdir}/locale' mandir='${datarootdir}/man' ac_prev= ac_dashdash= for ac_option do # If the previous option needs an argument, assign it. if test -n "$ac_prev"; then eval $ac_prev=\$ac_option ac_prev= continue fi case $ac_option in *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; *=) ac_optarg= ;; *) ac_optarg=yes ;; esac # Accept the important Cygnus configure options, so we can diagnose typos. case $ac_dashdash$ac_option in --) ac_dashdash=yes ;; -bindir | --bindir | --bindi | --bind | --bin | --bi) ac_prev=bindir ;; -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) bindir=$ac_optarg ;; -build | --build | --buil | --bui | --bu) ac_prev=build_alias ;; -build=* | --build=* | --buil=* | --bui=* | --bu=*) build_alias=$ac_optarg ;; -cache-file | --cache-file | --cache-fil | --cache-fi \ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) ac_prev=cache_file ;; -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) cache_file=$ac_optarg ;; --config-cache | -C) cache_file=config.cache ;; -datadir | --datadir | --datadi | --datad) ac_prev=datadir ;; -datadir=* | --datadir=* | --datadi=* | --datad=*) datadir=$ac_optarg ;; -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ | --dataroo | --dataro | --datar) ac_prev=datarootdir ;; -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) datarootdir=$ac_optarg ;; -disable-* | --disable-*) ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=no ;; -docdir | --docdir | --docdi | --doc | --do) ac_prev=docdir ;; -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) docdir=$ac_optarg ;; -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) ac_prev=dvidir ;; -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) dvidir=$ac_optarg ;; -enable-* | --enable-*) ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=\$ac_optarg ;; -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ | --exec | --exe | --ex) ac_prev=exec_prefix ;; -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ | --exec=* | --exe=* | --ex=*) exec_prefix=$ac_optarg ;; -gas | --gas | --ga | --g) # Obsolete; use --with-gas. with_gas=yes ;; -help | --help | --hel | --he | -h) ac_init_help=long ;; -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) ac_init_help=recursive ;; -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) ac_init_help=short ;; -host | --host | --hos | --ho) ac_prev=host_alias ;; -host=* | --host=* | --hos=* | --ho=*) host_alias=$ac_optarg ;; -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) ac_prev=htmldir ;; -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ | --ht=*) htmldir=$ac_optarg ;; -includedir | --includedir | --includedi | --included | --include \ | --includ | --inclu | --incl | --inc) ac_prev=includedir ;; -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ | --includ=* | --inclu=* | --incl=* | --inc=*) includedir=$ac_optarg ;; -infodir | --infodir | --infodi | --infod | --info | --inf) ac_prev=infodir ;; -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) infodir=$ac_optarg ;; -libdir | --libdir | --libdi | --libd) ac_prev=libdir ;; -libdir=* | --libdir=* | --libdi=* | --libd=*) libdir=$ac_optarg ;; -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ | --libexe | --libex | --libe) ac_prev=libexecdir ;; -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ | --libexe=* | --libex=* | --libe=*) libexecdir=$ac_optarg ;; -localedir | --localedir | --localedi | --localed | --locale) ac_prev=localedir ;; -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) localedir=$ac_optarg ;; -localstatedir | --localstatedir | --localstatedi | --localstated \ | --localstate | --localstat | --localsta | --localst | --locals) ac_prev=localstatedir ;; -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) localstatedir=$ac_optarg ;; -mandir | --mandir | --mandi | --mand | --man | --ma | --m) ac_prev=mandir ;; -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) mandir=$ac_optarg ;; -nfp | --nfp | --nf) # Obsolete; use --without-fp. with_fp=no ;; -no-create | --no-create | --no-creat | --no-crea | --no-cre \ | --no-cr | --no-c | -n) no_create=yes ;; -no-recursion | --no-recursion | --no-recursio | --no-recursi \ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) no_recursion=yes ;; -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ | --oldin | --oldi | --old | --ol | --o) ac_prev=oldincludedir ;; -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) oldincludedir=$ac_optarg ;; -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) ac_prev=prefix ;; -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) prefix=$ac_optarg ;; -program-prefix | --program-prefix | --program-prefi | --program-pref \ | --program-pre | --program-pr | --program-p) ac_prev=program_prefix ;; -program-prefix=* | --program-prefix=* | --program-prefi=* \ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) program_prefix=$ac_optarg ;; -program-suffix | --program-suffix | --program-suffi | --program-suff \ | --program-suf | --program-su | --program-s) ac_prev=program_suffix ;; -program-suffix=* | --program-suffix=* | --program-suffi=* \ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) program_suffix=$ac_optarg ;; -program-transform-name | --program-transform-name \ | --program-transform-nam | --program-transform-na \ | --program-transform-n | --program-transform- \ | --program-transform | --program-transfor \ | --program-transfo | --program-transf \ | --program-trans | --program-tran \ | --progr-tra | --program-tr | --program-t) ac_prev=program_transform_name ;; -program-transform-name=* | --program-transform-name=* \ | --program-transform-nam=* | --program-transform-na=* \ | --program-transform-n=* | --program-transform-=* \ | --program-transform=* | --program-transfor=* \ | --program-transfo=* | --program-transf=* \ | --program-trans=* | --program-tran=* \ | --progr-tra=* | --program-tr=* | --program-t=*) program_transform_name=$ac_optarg ;; -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) ac_prev=pdfdir ;; -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) pdfdir=$ac_optarg ;; -psdir | --psdir | --psdi | --psd | --ps) ac_prev=psdir ;; -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) psdir=$ac_optarg ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) silent=yes ;; -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ | --sbi=* | --sb=*) sbindir=$ac_optarg ;; -sharedstatedir | --sharedstatedir | --sharedstatedi \ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ | --sharedst | --shareds | --shared | --share | --shar \ | --sha | --sh) ac_prev=sharedstatedir ;; -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ | --sha=* | --sh=*) sharedstatedir=$ac_optarg ;; -site | --site | --sit) ac_prev=site ;; -site=* | --site=* | --sit=*) site=$ac_optarg ;; -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) ac_prev=srcdir ;; -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) srcdir=$ac_optarg ;; -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ | --syscon | --sysco | --sysc | --sys | --sy) ac_prev=sysconfdir ;; -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) sysconfdir=$ac_optarg ;; -target | --target | --targe | --targ | --tar | --ta | --t) ac_prev=target_alias ;; -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) target_alias=$ac_optarg ;; -v | -verbose | --verbose | --verbos | --verbo | --verb) verbose=yes ;; -version | --version | --versio | --versi | --vers | -V) ac_init_version=: ;; -with-* | --with-*) ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=\$ac_optarg ;; -without-* | --without-*) ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=no ;; --x) # Obsolete; use --with-x. with_x=yes ;; -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ | --x-incl | --x-inc | --x-in | --x-i) ac_prev=x_includes ;; -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) x_includes=$ac_optarg ;; -x-libraries | --x-libraries | --x-librarie | --x-librari \ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) ac_prev=x_libraries ;; -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) x_libraries=$ac_optarg ;; -*) as_fn_error $? "unrecognized option: \`$ac_option' Try \`$0 --help' for more information" ;; *=*) ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` # Reject names that are not valid shell variable names. case $ac_envvar in #( '' | [0-9]* | *[!_$as_cr_alnum]* ) as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; esac eval $ac_envvar=\$ac_optarg export $ac_envvar ;; *) # FIXME: should be removed in autoconf 3.0. $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" ;; esac done if test -n "$ac_prev"; then ac_option=--`echo $ac_prev | sed 's/_/-/g'` as_fn_error $? "missing argument to $ac_option" fi if test -n "$ac_unrecognized_opts"; then case $enable_option_checking in no) ;; fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; esac fi # Check all directory arguments for consistency. for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ libdir localedir mandir do eval ac_val=\$$ac_var # Remove trailing slashes. case $ac_val in */ ) ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` eval $ac_var=\$ac_val;; esac # Be sure to have absolute directory names. case $ac_val in [\\/$]* | ?:[\\/]* ) continue;; NONE | '' ) case $ac_var in *prefix ) continue;; esac;; esac as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" done # There might be people who depend on the old broken behavior: `$host' # used to hold the argument of --host etc. # FIXME: To remove some day. build=$build_alias host=$host_alias target=$target_alias # FIXME: To remove some day. if test "x$host_alias" != x; then if test "x$build_alias" = x; then cross_compiling=maybe elif test "x$build_alias" != "x$host_alias"; then cross_compiling=yes fi fi ac_tool_prefix= test -n "$host_alias" && ac_tool_prefix=$host_alias- test "$silent" = yes && exec 6>/dev/null ac_pwd=`pwd` && test -n "$ac_pwd" && ac_ls_di=`ls -di .` && ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || as_fn_error $? "working directory cannot be determined" test "X$ac_ls_di" = "X$ac_pwd_ls_di" || as_fn_error $? "pwd does not report name of working directory" # Find the source files, if location was not specified. if test -z "$srcdir"; then ac_srcdir_defaulted=yes # Try the directory containing this script, then the parent directory. ac_confdir=`$as_dirname -- "$as_myself" || $as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_myself" : 'X\(//\)[^/]' \| \ X"$as_myself" : 'X\(//\)$' \| \ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_myself" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` srcdir=$ac_confdir if test ! -r "$srcdir/$ac_unique_file"; then srcdir=.. fi else ac_srcdir_defaulted=no fi if test ! -r "$srcdir/$ac_unique_file"; then test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" fi ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" ac_abs_confdir=`( cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" pwd)` # When building in place, set srcdir=. if test "$ac_abs_confdir" = "$ac_pwd"; then srcdir=. fi # Remove unnecessary trailing slashes from srcdir. # Double slashes in file names in object file debugging info # mess up M-x gdb in Emacs. case $srcdir in */) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; esac for ac_var in $ac_precious_vars; do eval ac_env_${ac_var}_set=\${${ac_var}+set} eval ac_env_${ac_var}_value=\$${ac_var} eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} eval ac_cv_env_${ac_var}_value=\$${ac_var} done # # Report the --help message. # if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF \`configure' configures fweelin 0.6.6 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... To assign environment variables (e.g., CC, CFLAGS...), specify them as VAR=VALUE. See below for descriptions of some of the useful variables. Defaults for the options are specified in brackets. Configuration: -h, --help display this help and exit --help=short display options specific to this package --help=recursive display the short help of all the included packages -V, --version display version information and exit -q, --quiet, --silent do not print \`checking ...' messages --cache-file=FILE cache test results in FILE [disabled] -C, --config-cache alias for \`--cache-file=config.cache' -n, --no-create do not create output files --srcdir=DIR find the sources in DIR [configure dir or \`..'] Installation directories: --prefix=PREFIX install architecture-independent files in PREFIX [$ac_default_prefix] --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX [PREFIX] By default, \`make install' will install all the files in \`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify an installation prefix other than \`$ac_default_prefix' using \`--prefix', for instance \`--prefix=\$HOME'. For better control, use the options below. Fine tuning of the installation directories: --bindir=DIR user executables [EPREFIX/bin] --sbindir=DIR system admin executables [EPREFIX/sbin] --libexecdir=DIR program executables [EPREFIX/libexec] --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] --datadir=DIR read-only architecture-independent data [DATAROOTDIR] --infodir=DIR info documentation [DATAROOTDIR/info] --localedir=DIR locale-dependent data [DATAROOTDIR/locale] --mandir=DIR man documentation [DATAROOTDIR/man] --docdir=DIR documentation root [DATAROOTDIR/doc/fweelin] --htmldir=DIR html documentation [DOCDIR] --dvidir=DIR dvi documentation [DOCDIR] --pdfdir=DIR pdf documentation [DOCDIR] --psdir=DIR ps documentation [DOCDIR] _ACEOF cat <<\_ACEOF Program names: --program-prefix=PREFIX prepend PREFIX to installed program names --program-suffix=SUFFIX append SUFFIX to installed program names --program-transform-name=PROGRAM run sed PROGRAM on installed program names X features: --x-includes=DIR X include files are in DIR --x-libraries=DIR X library files are in DIR _ACEOF fi if test -n "$ac_init_help"; then case $ac_init_help in short | recursive ) echo "Configuration of fweelin 0.6.6:";; esac cat <<\_ACEOF Optional Features: --disable-option-checking ignore unrecognized --enable/--with options --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) --enable-FEATURE[=ARG] include FEATURE [ARG=yes] --enable-silent-rules less verbose build output (undo: "make V=1") --disable-silent-rules verbose build output (undo: "make V=0") --enable-fluidsynth use integrated FluidSynth softsynth (libfluidsynth) (default=auto) --disable-video disable video output --enable-lcd enable USB LCD display output --enable-dependency-tracking do not reject slow dependency extractors --disable-dependency-tracking speeds up one-time build Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) --with-x use the X Window System Some influential environment variables: CXX C++ compiler command CXXFLAGS C++ compiler flags LDFLAGS linker flags, e.g. -L if you have libraries in a nonstandard directory LIBS libraries to pass to the linker, e.g. -l CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if you have headers in a nonstandard directory CC C compiler command CFLAGS C compiler flags XMKMF Path to xmkmf, Makefile generator for X Window System CPP C preprocessor PKG_CONFIG path to pkg-config utility PKG_CONFIG_PATH directories to add to pkg-config's search path PKG_CONFIG_LIBDIR path overriding pkg-config's built-in search path SDL_CFLAGS C compiler flags for SDL, overriding pkg-config SDL_LIBS linker flags for SDL, overriding pkg-config Use these variables to override the choices made by `configure' or to help it to find libraries and programs with nonstandard names/locations. Report bugs to . _ACEOF ac_status=$? fi if test "$ac_init_help" = "recursive"; then # If there are subdirs, report their specific --help. for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue test -d "$ac_dir" || { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || continue ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix cd "$ac_dir" || { ac_status=$?; continue; } # Check for guested configure. if test -f "$ac_srcdir/configure.gnu"; then echo && $SHELL "$ac_srcdir/configure.gnu" --help=recursive elif test -f "$ac_srcdir/configure"; then echo && $SHELL "$ac_srcdir/configure" --help=recursive else $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 fi || ac_status=$? cd "$ac_pwd" || { ac_status=$?; break; } done fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF fweelin configure 0.6.6 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. _ACEOF exit fi ## ------------------------ ## ## Autoconf initialization. ## ## ------------------------ ## # ac_fn_cxx_try_compile LINENO # ---------------------------- # Try to compile conftest.$ac_ext, and return whether this succeeded. ac_fn_cxx_try_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_cxx_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_cxx_try_compile # ac_fn_c_try_compile LINENO # -------------------------- # Try to compile conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_compile # ac_fn_c_try_cpp LINENO # ---------------------- # Try to preprocess conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_cpp () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_cpp conftest.$ac_ext" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } > conftest.i && { test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || test ! -s conftest.err }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_cpp # ac_fn_c_try_link LINENO # ----------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_link () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext conftest$ac_exeext if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || test -x conftest$ac_exeext }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would # interfere with the next link command; also delete a directory that is # left behind by Apple's compiler. We do this before executing the actions. rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_link # ac_fn_c_check_func LINENO FUNC VAR # ---------------------------------- # Tests whether FUNC exists, setting the cache variable VAR accordingly ac_fn_c_check_func () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Define $2 to an innocuous variant, in case declares $2. For example, HP-UX 11i declares gettimeofday. */ #define $2 innocuous_$2 /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $2 (); below. Prefer to if __STDC__ is defined, since exists even on freestanding compilers. */ #ifdef __STDC__ # include #else # include #endif #undef $2 /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char $2 (); /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined __stub_$2 || defined __stub___$2 choke me #endif int main () { return $2 (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : eval "$3=yes" else eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_func # ac_fn_c_try_run LINENO # ---------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. Assumes # that executables *can* be run. ac_fn_c_try_run () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then : ac_retval=0 else $as_echo "$as_me: program exited with status $ac_status" >&5 $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=$ac_status fi rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_run # ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES # ------------------------------------------------------- # Tests whether HEADER exists, giving a warning if it cannot be compiled using # the include files in INCLUDES and setting the cache variable VAR # accordingly. ac_fn_c_check_header_mongrel () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if eval \${$3+:} false; then : { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } else # Is the header compilable? { $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5 $as_echo_n "checking $2 usability... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_header_compiler=yes else ac_header_compiler=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5 $as_echo "$ac_header_compiler" >&6; } # Is the header present? { $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5 $as_echo_n "checking $2 presence... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include <$2> _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : ac_header_preproc=yes else ac_header_preproc=no fi rm -f conftest.err conftest.i conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5 $as_echo "$ac_header_preproc" >&6; } # So? What about this header? case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #(( yes:no: ) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5 $as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 $as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} ;; no:yes:* ) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5 $as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5 $as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5 $as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5 $as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 $as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} ( $as_echo "## ------------------------------------------------------------------- ## ## Report this to https://github.com/free-wheeling/freewheeling/issues ## ## ------------------------------------------------------------------- ##" ) | sed "s/^/$as_me: WARNING: /" >&2 ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else eval "$3=\$ac_header_compiler" fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_mongrel # ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES # ------------------------------------------------------- # Tests whether HEADER exists and can be compiled using the include files in # INCLUDES, setting the cache variable VAR accordingly. ac_fn_c_check_header_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_c_try_compile "$LINENO"; then : eval "$3=yes" else eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_compile # ac_fn_c_find_intX_t LINENO BITS VAR # ----------------------------------- # Finds a signed integer type with width BITS, setting cache variable VAR # accordingly. ac_fn_c_find_intX_t () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for int$2_t" >&5 $as_echo_n "checking for int$2_t... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else eval "$3=no" # Order is important - never check a type that is potentially smaller # than half of the expected target width. for ac_type in int$2_t 'int' 'long int' \ 'long long int' 'short int' 'signed char'; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default enum { N = $2 / 2 - 1 }; int main () { static int test_array [1 - 2 * !(0 < ($ac_type) ((((($ac_type) 1 << N) << N) - 1) * 2 + 1))]; test_array [0] = 0; return test_array [0]; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default enum { N = $2 / 2 - 1 }; int main () { static int test_array [1 - 2 * !(($ac_type) ((((($ac_type) 1 << N) << N) - 1) * 2 + 1) < ($ac_type) ((((($ac_type) 1 << N) << N) - 1) * 2 + 2))]; test_array [0] = 0; return test_array [0]; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : else case $ac_type in #( int$2_t) : eval "$3=yes" ;; #( *) : eval "$3=\$ac_type" ;; esac fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if eval test \"x\$"$3"\" = x"no"; then : else break fi done fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_find_intX_t # ac_fn_c_check_type LINENO TYPE VAR INCLUDES # ------------------------------------------- # Tests whether TYPE exists after having included INCLUDES, setting cache # variable VAR accordingly. ac_fn_c_check_type () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else eval "$3=no" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { if (sizeof ($2)) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { if (sizeof (($2))) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : else eval "$3=yes" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_type # ac_fn_c_find_uintX_t LINENO BITS VAR # ------------------------------------ # Finds an unsigned integer type with width BITS, setting cache variable VAR # accordingly. ac_fn_c_find_uintX_t () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for uint$2_t" >&5 $as_echo_n "checking for uint$2_t... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else eval "$3=no" # Order is important - never check a type that is potentially smaller # than half of the expected target width. for ac_type in uint$2_t 'unsigned int' 'unsigned long int' \ 'unsigned long long int' 'unsigned short int' 'unsigned char'; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default int main () { static int test_array [1 - 2 * !((($ac_type) -1 >> ($2 / 2 - 1)) >> ($2 / 2 - 1) == 3)]; test_array [0] = 0; return test_array [0]; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : case $ac_type in #( uint$2_t) : eval "$3=yes" ;; #( *) : eval "$3=\$ac_type" ;; esac fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if eval test \"x\$"$3"\" = x"no"; then : else break fi done fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_find_uintX_t cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. It was created by fweelin $as_me 0.6.6, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ _ACEOF exec 5>>config.log { cat <<_ASUNAME ## --------- ## ## Platform. ## ## --------- ## hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` /bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` /bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` /usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` /bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` /bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` _ASUNAME as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. $as_echo "PATH: $as_dir" done IFS=$as_save_IFS } >&5 cat >&5 <<_ACEOF ## ----------- ## ## Core tests. ## ## ----------- ## _ACEOF # Keep a trace of the command line. # Strip out --no-create and --no-recursion so they do not pile up. # Strip out --silent because we don't want to record it for future runs. # Also quote any args containing shell meta-characters. # Make two passes to allow for proper duplicate-argument suppression. ac_configure_args= ac_configure_args0= ac_configure_args1= ac_must_keep_next=false for ac_pass in 1 2 do for ac_arg do case $ac_arg in -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) continue ;; *\'*) ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac case $ac_pass in 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; 2) as_fn_append ac_configure_args1 " '$ac_arg'" if test $ac_must_keep_next = true; then ac_must_keep_next=false # Got value, back to normal. else case $ac_arg in *=* | --config-cache | -C | -disable-* | --disable-* \ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ | -with-* | --with-* | -without-* | --without-* | --x) case "$ac_configure_args0 " in "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; esac ;; -* ) ac_must_keep_next=true ;; esac fi as_fn_append ac_configure_args " '$ac_arg'" ;; esac done done { ac_configure_args0=; unset ac_configure_args0;} { ac_configure_args1=; unset ac_configure_args1;} # When interrupted or exit'd, cleanup temporary files, and complete # config.log. We remove comments because anyway the quotes in there # would cause problems or look ugly. # WARNING: Use '\'' to represent an apostrophe within the trap. # WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. trap 'exit_status=$? # Save into config.log some information that might help in debugging. { echo $as_echo "## ---------------- ## ## Cache variables. ## ## ---------------- ##" echo # The following way of writing the cache mishandles newlines in values, ( for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( *${as_nl}ac_space=\ *) sed -n \ "s/'\''/'\''\\\\'\'''\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" ;; #( *) sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) echo $as_echo "## ----------------- ## ## Output variables. ## ## ----------------- ##" echo for ac_var in $ac_subst_vars do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo if test -n "$ac_subst_files"; then $as_echo "## ------------------- ## ## File substitutions. ## ## ------------------- ##" echo for ac_var in $ac_subst_files do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo fi if test -s confdefs.h; then $as_echo "## ----------- ## ## confdefs.h. ## ## ----------- ##" echo cat confdefs.h echo fi test "$ac_signal" != 0 && $as_echo "$as_me: caught signal $ac_signal" $as_echo "$as_me: exit $exit_status" } >&5 rm -f core *.core core.conftest.* && rm -f -r conftest* confdefs* conf$$* $ac_clean_files && exit $exit_status ' 0 for ac_signal in 1 2 13 15; do trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal done ac_signal=0 # confdefs.h avoids OS command line length limits that DEFS can exceed. rm -f -r conftest* confdefs.h $as_echo "/* confdefs.h */" > confdefs.h # Predefined preprocessor variables. cat >>confdefs.h <<_ACEOF #define PACKAGE_NAME "$PACKAGE_NAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_TARNAME "$PACKAGE_TARNAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_VERSION "$PACKAGE_VERSION" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_STRING "$PACKAGE_STRING" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_URL "$PACKAGE_URL" _ACEOF # Let the site file select an alternate cache file if it wants to. # Prefer an explicitly selected file to automatically selected ones. ac_site_file1=NONE ac_site_file2=NONE if test -n "$CONFIG_SITE"; then # We do not want a PATH search for config.site. case $CONFIG_SITE in #(( -*) ac_site_file1=./$CONFIG_SITE;; */*) ac_site_file1=$CONFIG_SITE;; *) ac_site_file1=./$CONFIG_SITE;; esac elif test "x$prefix" != xNONE; then ac_site_file1=$prefix/share/config.site ac_site_file2=$prefix/etc/config.site else ac_site_file1=$ac_default_prefix/share/config.site ac_site_file2=$ac_default_prefix/etc/config.site fi for ac_site_file in "$ac_site_file1" "$ac_site_file2" do test "x$ac_site_file" = xNONE && continue if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 $as_echo "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 . "$ac_site_file" \ || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "failed to load site script $ac_site_file See \`config.log' for more details" "$LINENO" 5; } fi done if test -r "$cache_file"; then # Some versions of bash will fail to source /dev/null (special files # actually), so we avoid doing that. DJGPP emulates it as a regular file. if test /dev/null != "$cache_file" && test -f "$cache_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 $as_echo "$as_me: loading cache $cache_file" >&6;} case $cache_file in [\\/]* | ?:[\\/]* ) . "$cache_file";; *) . "./$cache_file";; esac fi else { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 $as_echo "$as_me: creating cache $cache_file" >&6;} >$cache_file fi # Check that the precious variables saved in the cache have kept the same # value. ac_cache_corrupted=false for ac_var in $ac_precious_vars; do eval ac_old_set=\$ac_cv_env_${ac_var}_set eval ac_new_set=\$ac_env_${ac_var}_set eval ac_old_val=\$ac_cv_env_${ac_var}_value eval ac_new_val=\$ac_env_${ac_var}_value case $ac_old_set,$ac_new_set in set,) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} ac_cache_corrupted=: ;; ,set) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} ac_cache_corrupted=: ;; ,);; *) if test "x$ac_old_val" != "x$ac_new_val"; then # differences in whitespace do not lead to failure. ac_old_val_w=`echo x $ac_old_val` ac_new_val_w=`echo x $ac_new_val` if test "$ac_old_val_w" != "$ac_new_val_w"; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 $as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} ac_cache_corrupted=: else { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 $as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} eval $ac_var=\$ac_old_val fi { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 $as_echo "$as_me: former value: \`$ac_old_val'" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 $as_echo "$as_me: current value: \`$ac_new_val'" >&2;} fi;; esac # Pass precious variables to config.status. if test "$ac_new_set" = set; then case $ac_new_val in *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; *) ac_arg=$ac_var=$ac_new_val ;; esac case " $ac_configure_args " in *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. *) as_fn_append ac_configure_args " '$ac_arg'" ;; esac fi done if $ac_cache_corrupted; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 $as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 fi ## -------------------- ## ## Main body of script. ## ## -------------------- ## ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu am__api_version='1.16' ac_aux_dir= for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do if test -f "$ac_dir/install-sh"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install-sh -c" break elif test -f "$ac_dir/install.sh"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install.sh -c" break elif test -f "$ac_dir/shtool"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/shtool install -c" break fi done if test -z "$ac_aux_dir"; then as_fn_error $? "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$LINENO" 5 fi # These three variables are undocumented and unsupported, # and are intended to be withdrawn in a future Autoconf release. # They can cause serious problems if a builder's source tree is in a directory # whose full name contains unusual characters. ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. # Find a good install program. We prefer a C program (faster), # so one script is as good as another. But avoid the broken or # incompatible versions: # SysV /etc/install, /usr/sbin/install # SunOS /usr/etc/install # IRIX /sbin/install # AIX /bin/install # AmigaOS /C/install, which installs bootblocks on floppy discs # AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag # AFS /usr/afsws/bin/install, which mishandles nonexistent args # SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" # OS/2's system install, which has a completely different semantic # ./install, which can be erroneously created by make from ./install.sh. # Reject install programs that cannot install multiple files. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 $as_echo_n "checking for a BSD-compatible install... " >&6; } if test -z "$INSTALL"; then if ${ac_cv_path_install+:} false; then : $as_echo_n "(cached) " >&6 else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. # Account for people who put trailing slashes in PATH elements. case $as_dir/ in #(( ./ | .// | /[cC]/* | \ /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \ /usr/ucb/* ) ;; *) # OSF1 and SCO ODT 3.0 have their own names for install. # Don't use installbsd from OSF since it installs stuff as root # by default. for ac_prog in ginstall scoinst install; do for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then if test $ac_prog = install && grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # AIX install. It has an incompatible calling convention. : elif test $ac_prog = install && grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # program-specific install script used by HP pwplus--don't use. : else rm -rf conftest.one conftest.two conftest.dir echo one > conftest.one echo two > conftest.two mkdir conftest.dir if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" && test -s conftest.one && test -s conftest.two && test -s conftest.dir/conftest.one && test -s conftest.dir/conftest.two then ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" break 3 fi fi fi done done ;; esac done IFS=$as_save_IFS rm -rf conftest.one conftest.two conftest.dir fi if test "${ac_cv_path_install+set}" = set; then INSTALL=$ac_cv_path_install else # As a last resort, use the slow shell script. Don't cache a # value for INSTALL within a source directory, because that will # break other packages using the cache if that directory is # removed, or if the value is a relative name. INSTALL=$ac_install_sh fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 $as_echo "$INSTALL" >&6; } # Use test -z because SunOS4 sh mishandles braces in ${var-val}. # It thinks the first close brace ends the variable substitution. test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether build environment is sane" >&5 $as_echo_n "checking whether build environment is sane... " >&6; } # Reject unsafe characters in $srcdir or the absolute working directory # name. Accept space and tab only in the latter. am_lf=' ' case `pwd` in *[\\\"\#\$\&\'\`$am_lf]*) as_fn_error $? "unsafe absolute working directory name" "$LINENO" 5;; esac case $srcdir in *[\\\"\#\$\&\'\`$am_lf\ \ ]*) as_fn_error $? "unsafe srcdir value: '$srcdir'" "$LINENO" 5;; esac # Do 'set' in a subshell so we don't clobber the current shell's # arguments. Must try -L first in case configure is actually a # symlink; some systems play weird games with the mod time of symlinks # (eg FreeBSD returns the mod time of the symlink's containing # directory). if ( am_has_slept=no for am_try in 1 2; do echo "timestamp, slept: $am_has_slept" > conftest.file set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` if test "$*" = "X"; then # -L didn't work. set X `ls -t "$srcdir/configure" conftest.file` fi if test "$*" != "X $srcdir/configure conftest.file" \ && test "$*" != "X conftest.file $srcdir/configure"; then # If neither matched, then we have a broken ls. This can happen # if, for instance, CONFIG_SHELL is bash and it inherits a # broken ls alias from the environment. This has actually # happened. Such a system could not be considered "sane". as_fn_error $? "ls -t appears to fail. Make sure there is not a broken alias in your environment" "$LINENO" 5 fi if test "$2" = conftest.file || test $am_try -eq 2; then break fi # Just in case. sleep 1 am_has_slept=yes done test "$2" = conftest.file ) then # Ok. : else as_fn_error $? "newly created file is older than distributed files! Check your system clock" "$LINENO" 5 fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } # If we didn't sleep, we still need to ensure time stamps of config.status and # generated files are strictly newer. am_sleep_pid= if grep 'slept: no' conftest.file >/dev/null 2>&1; then ( sleep 1 ) & am_sleep_pid=$! fi rm -f conftest.file test "$program_prefix" != NONE && program_transform_name="s&^&$program_prefix&;$program_transform_name" # Use a double $ so make ignores it. test "$program_suffix" != NONE && program_transform_name="s&\$&$program_suffix&;$program_transform_name" # Double any \ or $. # By default was `s,x,x', remove it if useless. ac_script='s/[\\$]/&&/g;s/;s,x,x,$//' program_transform_name=`$as_echo "$program_transform_name" | sed "$ac_script"` # Expand $ac_aux_dir to an absolute path. am_aux_dir=`cd "$ac_aux_dir" && pwd` if test x"${MISSING+set}" != xset; then case $am_aux_dir in *\ * | *\ *) MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; *) MISSING="\${SHELL} $am_aux_dir/missing" ;; esac fi # Use eval to expand $SHELL if eval "$MISSING --is-lightweight"; then am_missing_run="$MISSING " else am_missing_run= { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: 'missing' script is too old or missing" >&5 $as_echo "$as_me: WARNING: 'missing' script is too old or missing" >&2;} fi if test x"${install_sh+set}" != xset; then case $am_aux_dir in *\ * | *\ *) install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; *) install_sh="\${SHELL} $am_aux_dir/install-sh" esac fi # Installed binaries are usually stripped using 'strip' when the user # run "make install-strip". However 'strip' might not be the right # tool to use in cross-compilation environments, therefore Automake # will honor the 'STRIP' environment variable to overrule this program. if test "$cross_compiling" != no; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. set dummy ${ac_tool_prefix}strip; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_STRIP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$STRIP"; then ac_cv_prog_STRIP="$STRIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_STRIP="${ac_tool_prefix}strip" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi STRIP=$ac_cv_prog_STRIP if test -n "$STRIP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 $as_echo "$STRIP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_STRIP"; then ac_ct_STRIP=$STRIP # Extract the first word of "strip", so it can be a program name with args. set dummy strip; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_STRIP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_STRIP"; then ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_STRIP="strip" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP if test -n "$ac_ct_STRIP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 $as_echo "$ac_ct_STRIP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_STRIP" = x; then STRIP=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac STRIP=$ac_ct_STRIP fi else STRIP="$ac_cv_prog_STRIP" fi fi INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a thread-safe mkdir -p" >&5 $as_echo_n "checking for a thread-safe mkdir -p... " >&6; } if test -z "$MKDIR_P"; then if ${ac_cv_path_mkdir+:} false; then : $as_echo_n "(cached) " >&6 else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/opt/sfw/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in mkdir gmkdir; do for ac_exec_ext in '' $ac_executable_extensions; do as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext" || continue case `"$as_dir/$ac_prog$ac_exec_ext" --version 2>&1` in #( 'mkdir (GNU coreutils) '* | \ 'mkdir (coreutils) '* | \ 'mkdir (fileutils) '4.1*) ac_cv_path_mkdir=$as_dir/$ac_prog$ac_exec_ext break 3;; esac done done done IFS=$as_save_IFS fi test -d ./--version && rmdir ./--version if test "${ac_cv_path_mkdir+set}" = set; then MKDIR_P="$ac_cv_path_mkdir -p" else # As a last resort, use the slow shell script. Don't cache a # value for MKDIR_P within a source directory, because that will # break other packages using the cache if that directory is # removed, or if the value is a relative name. MKDIR_P="$ac_install_sh -d" fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MKDIR_P" >&5 $as_echo "$MKDIR_P" >&6; } for ac_prog in gawk mawk nawk awk do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_AWK+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$AWK"; then ac_cv_prog_AWK="$AWK" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_AWK="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi AWK=$ac_cv_prog_AWK if test -n "$AWK"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5 $as_echo "$AWK" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$AWK" && break done { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5 $as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; } set x ${MAKE-make} ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'` if eval \${ac_cv_prog_make_${ac_make}_set+:} false; then : $as_echo_n "(cached) " >&6 else cat >conftest.make <<\_ACEOF SHELL = /bin/sh all: @echo '@@@%%%=$(MAKE)=@@@%%%' _ACEOF # GNU make sometimes prints "make[1]: Entering ...", which would confuse us. case `${MAKE-make} -f conftest.make 2>/dev/null` in *@@@%%%=?*=@@@%%%*) eval ac_cv_prog_make_${ac_make}_set=yes;; *) eval ac_cv_prog_make_${ac_make}_set=no;; esac rm -f conftest.make fi if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } SET_MAKE= else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } SET_MAKE="MAKE=${MAKE-make}" fi rm -rf .tst 2>/dev/null mkdir .tst 2>/dev/null if test -d .tst; then am__leading_dot=. else am__leading_dot=_ fi rmdir .tst 2>/dev/null # Check whether --enable-silent-rules was given. if test "${enable_silent_rules+set}" = set; then : enableval=$enable_silent_rules; fi case $enable_silent_rules in # ((( yes) AM_DEFAULT_VERBOSITY=0;; no) AM_DEFAULT_VERBOSITY=1;; *) AM_DEFAULT_VERBOSITY=1;; esac am_make=${MAKE-make} { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $am_make supports nested variables" >&5 $as_echo_n "checking whether $am_make supports nested variables... " >&6; } if ${am_cv_make_support_nested_variables+:} false; then : $as_echo_n "(cached) " >&6 else if $as_echo 'TRUE=$(BAR$(V)) BAR0=false BAR1=true V=1 am__doit: @$(TRUE) .PHONY: am__doit' | $am_make -f - >/dev/null 2>&1; then am_cv_make_support_nested_variables=yes else am_cv_make_support_nested_variables=no fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_make_support_nested_variables" >&5 $as_echo "$am_cv_make_support_nested_variables" >&6; } if test $am_cv_make_support_nested_variables = yes; then AM_V='$(V)' AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)' else AM_V=$AM_DEFAULT_VERBOSITY AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY fi AM_BACKSLASH='\' if test "`cd $srcdir && pwd`" != "`pwd`"; then # Use -I$(srcdir) only when $(srcdir) != ., so that make's output # is not polluted with repeated "-I." am__isrc=' -I$(srcdir)' # test to see if srcdir already configured if test -f $srcdir/config.status; then as_fn_error $? "source directory already configured; run \"make distclean\" there first" "$LINENO" 5 fi fi # test whether we have cygpath if test -z "$CYGPATH_W"; then if (cygpath --version) >/dev/null 2>/dev/null; then CYGPATH_W='cygpath -w' else CYGPATH_W=echo fi fi # Define the identity of the package. PACKAGE='fweelin' VERSION='0.6.6' cat >>confdefs.h <<_ACEOF #define PACKAGE "$PACKAGE" _ACEOF cat >>confdefs.h <<_ACEOF #define VERSION "$VERSION" _ACEOF # Some tools Automake needs. ACLOCAL=${ACLOCAL-"${am_missing_run}aclocal-${am__api_version}"} AUTOCONF=${AUTOCONF-"${am_missing_run}autoconf"} AUTOMAKE=${AUTOMAKE-"${am_missing_run}automake-${am__api_version}"} AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"} MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"} # For better backward compatibility. To be removed once Automake 1.9.x # dies out for good. For more background, see: # # mkdir_p='$(MKDIR_P)' # We need awk for the "check" target (and possibly the TAP driver). The # system "awk" is bad on some platforms. # Always define AMTAR for backward compatibility. Yes, it's still used # in the wild :-( We should find a proper way to deprecate it ... AMTAR='$${TAR-tar}' # We'll loop over all known methods to create a tar archive until one works. _am_tools='gnutar pax cpio none' am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -' # POSIX will say in a future version that running "rm -f" with no argument # is OK; and we want to be able to make that assumption in our Makefile # recipes. So use an aggressive probe to check that the usage we want is # actually supported "in the wild" to an acceptable degree. # See automake bug#10828. # To make any issue more visible, cause the running configure to be aborted # by default if the 'rm' program in use doesn't match our expectations; the # user can still override this though. if rm -f && rm -fr && rm -rf; then : OK; else cat >&2 <<'END' Oops! Your 'rm' program seems unable to run without file operands specified on the command line, even when the '-f' option is present. This is contrary to the behaviour of most rm programs out there, and not conforming with the upcoming POSIX standard: Please tell bug-automake@gnu.org about your system, including the value of your $PATH and any error possibly output before this message. This can help us improve future automake versions. END if test x"$ACCEPT_INFERIOR_RM_PROGRAM" = x"yes"; then echo 'Configuration will proceed anyway, since you have set the' >&2 echo 'ACCEPT_INFERIOR_RM_PROGRAM variable to "yes"' >&2 echo >&2 else cat >&2 <<'END' Aborting the configuration process, to ensure you take notice of the issue. You can download and install GNU coreutils to get an 'rm' implementation that behaves properly: . If you want to complete the configuration process using your problematic 'rm' anyway, export the environment variable ACCEPT_INFERIOR_RM_PROGRAM to "yes", and re-run configure. END as_fn_error $? "Your 'rm' program is bad, sorry." "$LINENO" 5 fi fi #AM_CONFIG_HEADER(config.h) # Check whether --enable-fluidsynth was given. if test "${enable_fluidsynth+set}" = set; then : enableval=$enable_fluidsynth; fi # Check whether --enable-video was given. if test "${enable_video+set}" = set; then : enableval=$enable_video; fi # Check whether --enable-lcd was given. if test "${enable_lcd+set}" = set; then : enableval=$enable_lcd; fi # Checks for programs. ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_cxx_compiler_gnu if test -z "$CXX"; then if test -n "$CCC"; then CXX=$CCC else if test -n "$ac_tool_prefix"; then for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CXX+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CXX"; then ac_cv_prog_CXX="$CXX" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CXX="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CXX=$ac_cv_prog_CXX if test -n "$CXX"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXX" >&5 $as_echo "$CXX" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$CXX" && break done fi if test -z "$CXX"; then ac_ct_CXX=$CXX for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CXX+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CXX"; then ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CXX="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CXX=$ac_cv_prog_ac_ct_CXX if test -n "$ac_ct_CXX"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CXX" >&5 $as_echo "$ac_ct_CXX" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_CXX" && break done if test "x$ac_ct_CXX" = x; then CXX="g++" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CXX=$ac_ct_CXX fi fi fi fi # Provide some information about the compiler. $as_echo "$as_me:${as_lineno-$LINENO}: checking for C++ compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then sed '10a\ ... rest of stderr output deleted ... 10q' conftest.err >conftest.er1 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" # Try to create an executable without -o first, disregard a.out. # It will help us diagnose broken compilers, and finding out an intuition # of exeext. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C++ compiler works" >&5 $as_echo_n "checking whether the C++ compiler works... " >&6; } ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` # The possible output files: ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" ac_rmfiles= for ac_file in $ac_files do case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; * ) ac_rmfiles="$ac_rmfiles $ac_file";; esac done rm -f $ac_rmfiles if { { ac_try="$ac_link_default" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link_default") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. # So ignore a value of `no', otherwise this would lead to `EXEEXT = no' # in a Makefile. We should not override ac_cv_exeext if it was cached, # so that the user can short-circuit this test for compilers unknown to # Autoconf. for ac_file in $ac_files '' do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; [ab].out ) # We found the default executable, but exeext='' is most # certainly right. break;; *.* ) if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; then :; else ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` fi # We set ac_cv_exeext here because the later test for it is not # safe: cross compilers may not add the suffix if given an `-o' # argument, so we may need to know it at that point already. # Even if this section looks crufty: it has the advantage of # actually working. break;; * ) break;; esac done test "$ac_cv_exeext" = no && ac_cv_exeext= else ac_file='' fi if test -z "$ac_file"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "C++ compiler cannot create executables See \`config.log' for more details" "$LINENO" 5; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for C++ compiler default output file name" >&5 $as_echo_n "checking for C++ compiler default output file name... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 $as_echo "$ac_file" >&6; } ac_exeext=$ac_cv_exeext rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 $as_echo_n "checking for suffix of executables... " >&6; } if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : # If both `conftest.exe' and `conftest' are `present' (well, observable) # catch `conftest.exe'. For instance with Cygwin, `ls conftest' will # work properly (i.e., refer to `conftest.exe'), while it won't with # `rm'. for ac_file in conftest.exe conftest conftest.*; do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` break;; * ) break;; esac done else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of executables: cannot compile and link See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest conftest$ac_cv_exeext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 $as_echo "$ac_cv_exeext" >&6; } rm -f conftest.$ac_ext EXEEXT=$ac_cv_exeext ac_exeext=$EXEEXT cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { FILE *f = fopen ("conftest.out", "w"); return ferror (f) || fclose (f) != 0; ; return 0; } _ACEOF ac_clean_files="$ac_clean_files conftest.out" # Check that the compiler produces executables we can run. If not, either # the compiler is broken, or we cross compile. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 $as_echo_n "checking whether we are cross compiling... " >&6; } if test "$cross_compiling" != yes; then { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if { ac_try='./conftest$ac_cv_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then cross_compiling=no else if test "$cross_compiling" = maybe; then cross_compiling=yes else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot run C++ compiled programs. If you meant to cross compile, use \`--host'. See \`config.log' for more details" "$LINENO" 5; } fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 $as_echo "$cross_compiling" >&6; } rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 $as_echo_n "checking for suffix of object files... " >&6; } if ${ac_cv_objext+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF rm -f conftest.o conftest.obj if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : for ac_file in conftest.o conftest.obj conftest.*; do test -f "$ac_file" || continue; case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` break;; esac done else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of object files: cannot compile See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest.$ac_cv_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 $as_echo "$ac_cv_objext" >&6; } OBJEXT=$ac_cv_objext ac_objext=$OBJEXT { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C++ compiler" >&5 $as_echo_n "checking whether we are using the GNU C++ compiler... " >&6; } if ${ac_cv_cxx_compiler_gnu+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : ac_compiler_gnu=yes else ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_cxx_compiler_gnu=$ac_compiler_gnu fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cxx_compiler_gnu" >&5 $as_echo "$ac_cv_cxx_compiler_gnu" >&6; } if test $ac_compiler_gnu = yes; then GXX=yes else GXX= fi ac_test_CXXFLAGS=${CXXFLAGS+set} ac_save_CXXFLAGS=$CXXFLAGS { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX accepts -g" >&5 $as_echo_n "checking whether $CXX accepts -g... " >&6; } if ${ac_cv_prog_cxx_g+:} false; then : $as_echo_n "(cached) " >&6 else ac_save_cxx_werror_flag=$ac_cxx_werror_flag ac_cxx_werror_flag=yes ac_cv_prog_cxx_g=no CXXFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : ac_cv_prog_cxx_g=yes else CXXFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : else ac_cxx_werror_flag=$ac_save_cxx_werror_flag CXXFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : ac_cv_prog_cxx_g=yes fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cxx_werror_flag=$ac_save_cxx_werror_flag fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_g" >&5 $as_echo "$ac_cv_prog_cxx_g" >&6; } if test "$ac_test_CXXFLAGS" = set; then CXXFLAGS=$ac_save_CXXFLAGS elif test $ac_cv_prog_cxx_g = yes; then if test "$GXX" = yes; then CXXFLAGS="-g -O2" else CXXFLAGS="-g" fi else if test "$GXX" = yes; then CXXFLAGS="-O2" else CXXFLAGS= fi fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu DEPDIR="${am__leading_dot}deps" ac_config_commands="$ac_config_commands depfiles" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} supports the include directive" >&5 $as_echo_n "checking whether ${MAKE-make} supports the include directive... " >&6; } cat > confinc.mk << 'END' am__doit: @echo this is the am__doit target >confinc.out .PHONY: am__doit END am__include="#" am__quote= # BSD make does it like this. echo '.include "confinc.mk" # ignored' > confmf.BSD # Other make implementations (GNU, Solaris 10, AIX) do it like this. echo 'include confinc.mk # ignored' > confmf.GNU _am_result=no for s in GNU BSD; do { echo "$as_me:$LINENO: ${MAKE-make} -f confmf.$s && cat confinc.out" >&5 (${MAKE-make} -f confmf.$s && cat confinc.out) >&5 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } case $?:`cat confinc.out 2>/dev/null` in #( '0:this is the am__doit target') : case $s in #( BSD) : am__include='.include' am__quote='"' ;; #( *) : am__include='include' am__quote='' ;; esac ;; #( *) : ;; esac if test "$am__include" != "#"; then _am_result="yes ($s style)" break fi done rm -f confinc.* confmf.* { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${_am_result}" >&5 $as_echo "${_am_result}" >&6; } # Check whether --enable-dependency-tracking was given. if test "${enable_dependency_tracking+set}" = set; then : enableval=$enable_dependency_tracking; fi if test "x$enable_dependency_tracking" != xno; then am_depcomp="$ac_aux_dir/depcomp" AMDEPBACKSLASH='\' am__nodep='_no' fi if test "x$enable_dependency_tracking" != xno; then AMDEP_TRUE= AMDEP_FALSE='#' else AMDEP_TRUE='#' AMDEP_FALSE= fi depcc="$CXX" am_compiler_list= { $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 $as_echo_n "checking dependency style of $depcc... " >&6; } if ${am_cv_CXX_dependencies_compiler_type+:} false; then : $as_echo_n "(cached) " >&6 else if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then # We make a subdir and do the tests there. Otherwise we can end up # making bogus files that we don't know about and never remove. For # instance it was reported that on HP-UX the gcc test will end up # making a dummy file named 'D' -- because '-MD' means "put the output # in D". rm -rf conftest.dir mkdir conftest.dir # Copy depcomp to subdir because otherwise we won't find it if we're # using a relative directory. cp "$am_depcomp" conftest.dir cd conftest.dir # We will build objects and dependencies in a subdirectory because # it helps to detect inapplicable dependency modes. For instance # both Tru64's cc and ICC support -MD to output dependencies as a # side effect of compilation, but ICC will put the dependencies in # the current directory while Tru64 will put them in the object # directory. mkdir sub am_cv_CXX_dependencies_compiler_type=none if test "$am_compiler_list" = ""; then am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` fi am__universal=false case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac for depmode in $am_compiler_list; do # Setup a source with many dependencies, because some compilers # like to wrap large dependency lists on column 80 (with \), and # we should not choose a depcomp mode which is confused by this. # # We need to recreate these files for each test, as the compiler may # overwrite some of them when testing with obscure command lines. # This happens at least with the AIX C compiler. : > sub/conftest.c for i in 1 2 3 4 5 6; do echo '#include "conftst'$i'.h"' >> sub/conftest.c # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with # Solaris 10 /bin/sh. echo '/* dummy */' > sub/conftst$i.h done echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf # We check with '-c' and '-o' for the sake of the "dashmstdout" # mode. It turns out that the SunPro C++ compiler does not properly # handle '-M -o', and we need to detect this. Also, some Intel # versions had trouble with output in subdirs. am__obj=sub/conftest.${OBJEXT-o} am__minus_obj="-o $am__obj" case $depmode in gcc) # This depmode causes a compiler race in universal mode. test "$am__universal" = false || continue ;; nosideeffect) # After this tag, mechanisms are not by side-effect, so they'll # only be used when explicitly requested. if test "x$enable_dependency_tracking" = xyes; then continue else break fi ;; msvc7 | msvc7msys | msvisualcpp | msvcmsys) # This compiler won't grok '-c -o', but also, the minuso test has # not run yet. These depmodes are late enough in the game, and # so weak that their functioning should not be impacted. am__obj=conftest.${OBJEXT-o} am__minus_obj= ;; none) break ;; esac if depmode=$depmode \ source=sub/conftest.c object=$am__obj \ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ >/dev/null 2>conftest.err && grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && grep $am__obj sub/conftest.Po > /dev/null 2>&1 && ${MAKE-make} -s -f confmf > /dev/null 2>&1; then # icc doesn't choke on unknown options, it will just issue warnings # or remarks (even with -Werror). So we grep stderr for any message # that says an option was ignored or not supported. # When given -MP, icc 7.0 and 7.1 complain thusly: # icc: Command line warning: ignoring option '-M'; no argument required # The diagnosis changed in icc 8.0: # icc: Command line remark: option '-MP' not supported if (grep 'ignoring option' conftest.err || grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else am_cv_CXX_dependencies_compiler_type=$depmode break fi fi done cd .. rm -rf conftest.dir else am_cv_CXX_dependencies_compiler_type=none fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CXX_dependencies_compiler_type" >&5 $as_echo "$am_cv_CXX_dependencies_compiler_type" >&6; } CXXDEPMODE=depmode=$am_cv_CXX_dependencies_compiler_type if test "x$enable_dependency_tracking" != xno \ && test "$am_cv_CXX_dependencies_compiler_type" = gcc3; then am__fastdepCXX_TRUE= am__fastdepCXX_FALSE='#' else am__fastdepCXX_TRUE='#' am__fastdepCXX_FALSE= fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. set dummy ${ac_tool_prefix}gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi else CC="$ac_cv_prog_CC" fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. set dummy ${ac_tool_prefix}cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi fi if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else ac_prog_rejected=no as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue fi ac_cv_prog_CC="cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS if test $ac_prog_rejected = yes; then # We found a bogon in the path, so make sure we never use it. set dummy $ac_cv_prog_CC shift if test $# != 0; then # We chose a different compiler from the bogus one. # However, it has the same basename, so the bogon will be chosen # first if we set CC to just the basename; use the full file name. shift ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" fi fi fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then for ac_prog in cl.exe do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$CC" && break done fi if test -z "$CC"; then ac_ct_CC=$CC for ac_prog in cl.exe do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_CC" && break done if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi fi fi test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "no acceptable C compiler found in \$PATH See \`config.log' for more details" "$LINENO" 5; } # Provide some information about the compiler. $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then sed '10a\ ... rest of stderr output deleted ... 10q' conftest.err >conftest.er1 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 $as_echo_n "checking whether we are using the GNU C compiler... " >&6; } if ${ac_cv_c_compiler_gnu+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_compiler_gnu=yes else ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 $as_echo "$ac_cv_c_compiler_gnu" >&6; } if test $ac_compiler_gnu = yes; then GCC=yes else GCC= fi ac_test_CFLAGS=${CFLAGS+set} ac_save_CFLAGS=$CFLAGS { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 $as_echo_n "checking whether $CC accepts -g... " >&6; } if ${ac_cv_prog_cc_g+:} false; then : $as_echo_n "(cached) " >&6 else ac_save_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes ac_cv_prog_cc_g=no CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes else CFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : else ac_c_werror_flag=$ac_save_c_werror_flag CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_c_werror_flag=$ac_save_c_werror_flag fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 $as_echo "$ac_cv_prog_cc_g" >&6; } if test "$ac_test_CFLAGS" = set; then CFLAGS=$ac_save_CFLAGS elif test $ac_cv_prog_cc_g = yes; then if test "$GCC" = yes; then CFLAGS="-g -O2" else CFLAGS="-g" fi else if test "$GCC" = yes; then CFLAGS="-O2" else CFLAGS= fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 $as_echo_n "checking for $CC option to accept ISO C89... " >&6; } if ${ac_cv_prog_cc_c89+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_prog_cc_c89=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include struct stat; /* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ struct buf { int x; }; FILE * (*rcsopen) (struct buf *, struct stat *, int); static char *e (p, i) char **p; int i; { return p[i]; } static char *f (char * (*g) (char **, int), char **p, ...) { char *s; va_list v; va_start (v,p); s = g (p, va_arg (v,int)); va_end (v); return s; } /* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has function prototypes and stuff, but not '\xHH' hex character constants. These don't provoke an error unfortunately, instead are silently treated as 'x'. The following induces an error, until -std is added to get proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an array size at least. It's necessary to write '\x00'==0 to get something that's true only with -std. */ int osf4_cc_array ['\x00' == 0 ? 1 : -1]; /* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters inside strings and character constants. */ #define FOO(x) 'x' int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; int test (int i, double x); struct s1 {int (*f) (int a);}; struct s2 {int (*f) (double a);}; int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); int argc; char **argv; int main () { return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; ; return 0; } _ACEOF for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_c89=$ac_arg fi rm -f core conftest.err conftest.$ac_objext test "x$ac_cv_prog_cc_c89" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi # AC_CACHE_VAL case "x$ac_cv_prog_cc_c89" in x) { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 $as_echo "none needed" >&6; } ;; xno) { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 $as_echo "unsupported" >&6; } ;; *) CC="$CC $ac_cv_prog_cc_c89" { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 $as_echo "$ac_cv_prog_cc_c89" >&6; } ;; esac if test "x$ac_cv_prog_cc_c89" != xno; then : fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC understands -c and -o together" >&5 $as_echo_n "checking whether $CC understands -c and -o together... " >&6; } if ${am_cv_prog_cc_c_o+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF # Make sure it works both with $CC and with simple cc. # Following AC_PROG_CC_C_O, we do the test twice because some # compilers refuse to overwrite an existing .o file with -o, # though they will create one. am_cv_prog_cc_c_o=yes for am_i in 1 2; do if { echo "$as_me:$LINENO: $CC -c conftest.$ac_ext -o conftest2.$ac_objext" >&5 ($CC -c conftest.$ac_ext -o conftest2.$ac_objext) >&5 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } \ && test -f conftest2.$ac_objext; then : OK else am_cv_prog_cc_c_o=no break fi done rm -f core conftest* unset am_i fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_prog_cc_c_o" >&5 $as_echo "$am_cv_prog_cc_c_o" >&6; } if test "$am_cv_prog_cc_c_o" != yes; then # Losing compiler, so override with the script. # FIXME: It is wrong to rewrite CC. # But if we don't then we get into trouble of one sort or another. # A longer-term fix would be to have automake use am__CC in this case, # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)" CC="$am_aux_dir/compile $CC" fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu depcc="$CC" am_compiler_list= { $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 $as_echo_n "checking dependency style of $depcc... " >&6; } if ${am_cv_CC_dependencies_compiler_type+:} false; then : $as_echo_n "(cached) " >&6 else if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then # We make a subdir and do the tests there. Otherwise we can end up # making bogus files that we don't know about and never remove. For # instance it was reported that on HP-UX the gcc test will end up # making a dummy file named 'D' -- because '-MD' means "put the output # in D". rm -rf conftest.dir mkdir conftest.dir # Copy depcomp to subdir because otherwise we won't find it if we're # using a relative directory. cp "$am_depcomp" conftest.dir cd conftest.dir # We will build objects and dependencies in a subdirectory because # it helps to detect inapplicable dependency modes. For instance # both Tru64's cc and ICC support -MD to output dependencies as a # side effect of compilation, but ICC will put the dependencies in # the current directory while Tru64 will put them in the object # directory. mkdir sub am_cv_CC_dependencies_compiler_type=none if test "$am_compiler_list" = ""; then am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` fi am__universal=false case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac for depmode in $am_compiler_list; do # Setup a source with many dependencies, because some compilers # like to wrap large dependency lists on column 80 (with \), and # we should not choose a depcomp mode which is confused by this. # # We need to recreate these files for each test, as the compiler may # overwrite some of them when testing with obscure command lines. # This happens at least with the AIX C compiler. : > sub/conftest.c for i in 1 2 3 4 5 6; do echo '#include "conftst'$i'.h"' >> sub/conftest.c # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with # Solaris 10 /bin/sh. echo '/* dummy */' > sub/conftst$i.h done echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf # We check with '-c' and '-o' for the sake of the "dashmstdout" # mode. It turns out that the SunPro C++ compiler does not properly # handle '-M -o', and we need to detect this. Also, some Intel # versions had trouble with output in subdirs. am__obj=sub/conftest.${OBJEXT-o} am__minus_obj="-o $am__obj" case $depmode in gcc) # This depmode causes a compiler race in universal mode. test "$am__universal" = false || continue ;; nosideeffect) # After this tag, mechanisms are not by side-effect, so they'll # only be used when explicitly requested. if test "x$enable_dependency_tracking" = xyes; then continue else break fi ;; msvc7 | msvc7msys | msvisualcpp | msvcmsys) # This compiler won't grok '-c -o', but also, the minuso test has # not run yet. These depmodes are late enough in the game, and # so weak that their functioning should not be impacted. am__obj=conftest.${OBJEXT-o} am__minus_obj= ;; none) break ;; esac if depmode=$depmode \ source=sub/conftest.c object=$am__obj \ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ >/dev/null 2>conftest.err && grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && grep $am__obj sub/conftest.Po > /dev/null 2>&1 && ${MAKE-make} -s -f confmf > /dev/null 2>&1; then # icc doesn't choke on unknown options, it will just issue warnings # or remarks (even with -Werror). So we grep stderr for any message # that says an option was ignored or not supported. # When given -MP, icc 7.0 and 7.1 complain thusly: # icc: Command line warning: ignoring option '-M'; no argument required # The diagnosis changed in icc 8.0: # icc: Command line remark: option '-MP' not supported if (grep 'ignoring option' conftest.err || grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else am_cv_CC_dependencies_compiler_type=$depmode break fi fi done cd .. rm -rf conftest.dir else am_cv_CC_dependencies_compiler_type=none fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5 $as_echo "$am_cv_CC_dependencies_compiler_type" >&6; } CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type if test "x$enable_dependency_tracking" != xno \ && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then am__fastdepCC_TRUE= am__fastdepCC_FALSE='#' else am__fastdepCC_TRUE='#' am__fastdepCC_FALSE= fi # Add Xtra Paths for Checking ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 $as_echo_n "checking how to run the C preprocessor... " >&6; } # On Suns, sometimes $CPP names a directory. if test -n "$CPP" && test -d "$CPP"; then CPP= fi if test -z "$CPP"; then if ${ac_cv_prog_CPP+:} false; then : $as_echo_n "(cached) " >&6 else # Double quotes because CPP needs to be expanded for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" do ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : break fi done ac_cv_prog_CPP=$CPP fi CPP=$ac_cv_prog_CPP else ac_cv_prog_CPP=$CPP fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 $as_echo "$CPP" >&6; } ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "C preprocessor \"$CPP\" fails sanity check See \`config.log' for more details" "$LINENO" 5; } fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking for X" >&5 $as_echo_n "checking for X... " >&6; } # Check whether --with-x was given. if test "${with_x+set}" = set; then : withval=$with_x; fi # $have_x is `yes', `no', `disabled', or empty when we do not yet know. if test "x$with_x" = xno; then # The user explicitly disabled X. have_x=disabled else case $x_includes,$x_libraries in #( *\'*) as_fn_error $? "cannot use X directory names containing '" "$LINENO" 5;; #( *,NONE | NONE,*) if ${ac_cv_have_x+:} false; then : $as_echo_n "(cached) " >&6 else # One or both of the vars are not set, and there is no cached value. ac_x_includes=no ac_x_libraries=no rm -f -r conftest.dir if mkdir conftest.dir; then cd conftest.dir cat >Imakefile <<'_ACEOF' incroot: @echo incroot='${INCROOT}' usrlibdir: @echo usrlibdir='${USRLIBDIR}' libdir: @echo libdir='${LIBDIR}' _ACEOF if (export CC; ${XMKMF-xmkmf}) >/dev/null 2>/dev/null && test -f Makefile; then # GNU make sometimes prints "make[1]: Entering ...", which would confuse us. for ac_var in incroot usrlibdir libdir; do eval "ac_im_$ac_var=\`\${MAKE-make} $ac_var 2>/dev/null | sed -n 's/^$ac_var=//p'\`" done # Open Windows xmkmf reportedly sets LIBDIR instead of USRLIBDIR. for ac_extension in a so sl dylib la dll; do if test ! -f "$ac_im_usrlibdir/libX11.$ac_extension" && test -f "$ac_im_libdir/libX11.$ac_extension"; then ac_im_usrlibdir=$ac_im_libdir; break fi done # Screen out bogus values from the imake configuration. They are # bogus both because they are the default anyway, and because # using them would break gcc on systems where it needs fixed includes. case $ac_im_incroot in /usr/include) ac_x_includes= ;; *) test -f "$ac_im_incroot/X11/Xos.h" && ac_x_includes=$ac_im_incroot;; esac case $ac_im_usrlibdir in /usr/lib | /usr/lib64 | /lib | /lib64) ;; *) test -d "$ac_im_usrlibdir" && ac_x_libraries=$ac_im_usrlibdir ;; esac fi cd .. rm -f -r conftest.dir fi # Standard set of common directories for X headers. # Check X11 before X11Rn because it is often a symlink to the current release. ac_x_header_dirs=' /usr/X11/include /usr/X11R7/include /usr/X11R6/include /usr/X11R5/include /usr/X11R4/include /usr/include/X11 /usr/include/X11R7 /usr/include/X11R6 /usr/include/X11R5 /usr/include/X11R4 /usr/local/X11/include /usr/local/X11R7/include /usr/local/X11R6/include /usr/local/X11R5/include /usr/local/X11R4/include /usr/local/include/X11 /usr/local/include/X11R7 /usr/local/include/X11R6 /usr/local/include/X11R5 /usr/local/include/X11R4 /usr/X386/include /usr/x386/include /usr/XFree86/include/X11 /usr/include /usr/local/include /usr/unsupported/include /usr/athena/include /usr/local/x11r5/include /usr/lpp/Xamples/include /usr/openwin/include /usr/openwin/share/include' if test "$ac_x_includes" = no; then # Guess where to find include files, by looking for Xlib.h. # First, try using that file with no special directory specified. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : # We can compile using X headers with no special include directory. ac_x_includes= else for ac_dir in $ac_x_header_dirs; do if test -r "$ac_dir/X11/Xlib.h"; then ac_x_includes=$ac_dir break fi done fi rm -f conftest.err conftest.i conftest.$ac_ext fi # $ac_x_includes = no if test "$ac_x_libraries" = no; then # Check for the libraries. # See if we find them without any special options. # Don't add to $LIBS permanently. ac_save_LIBS=$LIBS LIBS="-lX11 $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { XrmInitialize () ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : LIBS=$ac_save_LIBS # We can link X programs with no special library path. ac_x_libraries= else LIBS=$ac_save_LIBS for ac_dir in `$as_echo "$ac_x_includes $ac_x_header_dirs" | sed s/include/lib/g` do # Don't even attempt the hair of trying to link an X program! for ac_extension in a so sl dylib la dll; do if test -r "$ac_dir/libX11.$ac_extension"; then ac_x_libraries=$ac_dir break 2 fi done done fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi # $ac_x_libraries = no case $ac_x_includes,$ac_x_libraries in #( no,* | *,no | *\'*) # Didn't find X, or a directory has "'" in its name. ac_cv_have_x="have_x=no";; #( *) # Record where we found X for the cache. ac_cv_have_x="have_x=yes\ ac_x_includes='$ac_x_includes'\ ac_x_libraries='$ac_x_libraries'" esac fi ;; #( *) have_x=yes;; esac eval "$ac_cv_have_x" fi # $with_x != no if test "$have_x" != yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_x" >&5 $as_echo "$have_x" >&6; } no_x=yes else # If each of the values was on the command line, it overrides each guess. test "x$x_includes" = xNONE && x_includes=$ac_x_includes test "x$x_libraries" = xNONE && x_libraries=$ac_x_libraries # Update the cache value to reflect the command line values. ac_cv_have_x="have_x=yes\ ac_x_includes='$x_includes'\ ac_x_libraries='$x_libraries'" { $as_echo "$as_me:${as_lineno-$LINENO}: result: libraries $x_libraries, headers $x_includes" >&5 $as_echo "libraries $x_libraries, headers $x_includes" >&6; } fi if test "$no_x" = yes; then # Not all programs may use this symbol, but it does not hurt to define it. $as_echo "#define X_DISPLAY_MISSING 1" >>confdefs.h X_CFLAGS= X_PRE_LIBS= X_LIBS= X_EXTRA_LIBS= else if test -n "$x_includes"; then X_CFLAGS="$X_CFLAGS -I$x_includes" fi # It would also be nice to do this for all -L options, not just this one. if test -n "$x_libraries"; then X_LIBS="$X_LIBS -L$x_libraries" # For Solaris; some versions of Sun CC require a space after -R and # others require no space. Words are not sufficient . . . . { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -R must be followed by a space" >&5 $as_echo_n "checking whether -R must be followed by a space... " >&6; } ac_xsave_LIBS=$LIBS; LIBS="$LIBS -R$x_libraries" ac_xsave_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } X_LIBS="$X_LIBS -R$x_libraries" else LIBS="$ac_xsave_LIBS -R $x_libraries" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } X_LIBS="$X_LIBS -R $x_libraries" else { $as_echo "$as_me:${as_lineno-$LINENO}: result: neither works" >&5 $as_echo "neither works" >&6; } fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext ac_c_werror_flag=$ac_xsave_c_werror_flag LIBS=$ac_xsave_LIBS fi # Check for system-dependent libraries X programs must link with. # Do this before checking for the system-independent R6 libraries # (-lICE), since we may need -lsocket or whatever for X linking. if test "$ISC" = yes; then X_EXTRA_LIBS="$X_EXTRA_LIBS -lnsl_s -linet" else # Martyn Johnson says this is needed for Ultrix, if the X # libraries were built with DECnet support. And Karl Berry says # the Alpha needs dnet_stub (dnet does not exist). ac_xsave_LIBS="$LIBS"; LIBS="$LIBS $X_LIBS -lX11" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char XOpenDisplay (); int main () { return XOpenDisplay (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dnet_ntoa in -ldnet" >&5 $as_echo_n "checking for dnet_ntoa in -ldnet... " >&6; } if ${ac_cv_lib_dnet_dnet_ntoa+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldnet $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char dnet_ntoa (); int main () { return dnet_ntoa (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_dnet_dnet_ntoa=yes else ac_cv_lib_dnet_dnet_ntoa=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dnet_dnet_ntoa" >&5 $as_echo "$ac_cv_lib_dnet_dnet_ntoa" >&6; } if test "x$ac_cv_lib_dnet_dnet_ntoa" = xyes; then : X_EXTRA_LIBS="$X_EXTRA_LIBS -ldnet" fi if test $ac_cv_lib_dnet_dnet_ntoa = no; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dnet_ntoa in -ldnet_stub" >&5 $as_echo_n "checking for dnet_ntoa in -ldnet_stub... " >&6; } if ${ac_cv_lib_dnet_stub_dnet_ntoa+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldnet_stub $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char dnet_ntoa (); int main () { return dnet_ntoa (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_dnet_stub_dnet_ntoa=yes else ac_cv_lib_dnet_stub_dnet_ntoa=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dnet_stub_dnet_ntoa" >&5 $as_echo "$ac_cv_lib_dnet_stub_dnet_ntoa" >&6; } if test "x$ac_cv_lib_dnet_stub_dnet_ntoa" = xyes; then : X_EXTRA_LIBS="$X_EXTRA_LIBS -ldnet_stub" fi fi fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS="$ac_xsave_LIBS" # msh@cis.ufl.edu says -lnsl (and -lsocket) are needed for his 386/AT, # to get the SysV transport functions. # Chad R. Larson says the Pyramis MIS-ES running DC/OSx (SVR4) # needs -lnsl. # The nsl library prevents programs from opening the X display # on Irix 5.2, according to T.E. Dickey. # The functions gethostbyname, getservbyname, and inet_addr are # in -lbsd on LynxOS 3.0.1/i386, according to Lars Hecking. ac_fn_c_check_func "$LINENO" "gethostbyname" "ac_cv_func_gethostbyname" if test "x$ac_cv_func_gethostbyname" = xyes; then : fi if test $ac_cv_func_gethostbyname = no; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gethostbyname in -lnsl" >&5 $as_echo_n "checking for gethostbyname in -lnsl... " >&6; } if ${ac_cv_lib_nsl_gethostbyname+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lnsl $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char gethostbyname (); int main () { return gethostbyname (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_nsl_gethostbyname=yes else ac_cv_lib_nsl_gethostbyname=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_nsl_gethostbyname" >&5 $as_echo "$ac_cv_lib_nsl_gethostbyname" >&6; } if test "x$ac_cv_lib_nsl_gethostbyname" = xyes; then : X_EXTRA_LIBS="$X_EXTRA_LIBS -lnsl" fi if test $ac_cv_lib_nsl_gethostbyname = no; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gethostbyname in -lbsd" >&5 $as_echo_n "checking for gethostbyname in -lbsd... " >&6; } if ${ac_cv_lib_bsd_gethostbyname+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lbsd $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char gethostbyname (); int main () { return gethostbyname (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_bsd_gethostbyname=yes else ac_cv_lib_bsd_gethostbyname=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_bsd_gethostbyname" >&5 $as_echo "$ac_cv_lib_bsd_gethostbyname" >&6; } if test "x$ac_cv_lib_bsd_gethostbyname" = xyes; then : X_EXTRA_LIBS="$X_EXTRA_LIBS -lbsd" fi fi fi # lieder@skyler.mavd.honeywell.com says without -lsocket, # socket/setsockopt and other routines are undefined under SCO ODT # 2.0. But -lsocket is broken on IRIX 5.2 (and is not necessary # on later versions), says Simon Leinen: it contains gethostby* # variants that don't use the name server (or something). -lsocket # must be given before -lnsl if both are needed. We assume that # if connect needs -lnsl, so does gethostbyname. ac_fn_c_check_func "$LINENO" "connect" "ac_cv_func_connect" if test "x$ac_cv_func_connect" = xyes; then : fi if test $ac_cv_func_connect = no; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for connect in -lsocket" >&5 $as_echo_n "checking for connect in -lsocket... " >&6; } if ${ac_cv_lib_socket_connect+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lsocket $X_EXTRA_LIBS $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char connect (); int main () { return connect (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_socket_connect=yes else ac_cv_lib_socket_connect=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_socket_connect" >&5 $as_echo "$ac_cv_lib_socket_connect" >&6; } if test "x$ac_cv_lib_socket_connect" = xyes; then : X_EXTRA_LIBS="-lsocket $X_EXTRA_LIBS" fi fi # Guillermo Gomez says -lposix is necessary on A/UX. ac_fn_c_check_func "$LINENO" "remove" "ac_cv_func_remove" if test "x$ac_cv_func_remove" = xyes; then : fi if test $ac_cv_func_remove = no; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for remove in -lposix" >&5 $as_echo_n "checking for remove in -lposix... " >&6; } if ${ac_cv_lib_posix_remove+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lposix $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char remove (); int main () { return remove (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_posix_remove=yes else ac_cv_lib_posix_remove=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_posix_remove" >&5 $as_echo "$ac_cv_lib_posix_remove" >&6; } if test "x$ac_cv_lib_posix_remove" = xyes; then : X_EXTRA_LIBS="$X_EXTRA_LIBS -lposix" fi fi # BSDI BSD/OS 2.1 needs -lipc for XOpenDisplay. ac_fn_c_check_func "$LINENO" "shmat" "ac_cv_func_shmat" if test "x$ac_cv_func_shmat" = xyes; then : fi if test $ac_cv_func_shmat = no; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for shmat in -lipc" >&5 $as_echo_n "checking for shmat in -lipc... " >&6; } if ${ac_cv_lib_ipc_shmat+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lipc $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char shmat (); int main () { return shmat (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_ipc_shmat=yes else ac_cv_lib_ipc_shmat=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ipc_shmat" >&5 $as_echo "$ac_cv_lib_ipc_shmat" >&6; } if test "x$ac_cv_lib_ipc_shmat" = xyes; then : X_EXTRA_LIBS="$X_EXTRA_LIBS -lipc" fi fi fi # Check for libraries that X11R6 Xt/Xaw programs need. ac_save_LDFLAGS=$LDFLAGS test -n "$x_libraries" && LDFLAGS="$LDFLAGS -L$x_libraries" # SM needs ICE to (dynamically) link under SunOS 4.x (so we have to # check for ICE first), but we must link in the order -lSM -lICE or # we get undefined symbols. So assume we have SM if we have ICE. # These have to be linked with before -lX11, unlike the other # libraries we check for below, so use a different variable. # John Interrante, Karl Berry { $as_echo "$as_me:${as_lineno-$LINENO}: checking for IceConnectionNumber in -lICE" >&5 $as_echo_n "checking for IceConnectionNumber in -lICE... " >&6; } if ${ac_cv_lib_ICE_IceConnectionNumber+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lICE $X_EXTRA_LIBS $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char IceConnectionNumber (); int main () { return IceConnectionNumber (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_ICE_IceConnectionNumber=yes else ac_cv_lib_ICE_IceConnectionNumber=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ICE_IceConnectionNumber" >&5 $as_echo "$ac_cv_lib_ICE_IceConnectionNumber" >&6; } if test "x$ac_cv_lib_ICE_IceConnectionNumber" = xyes; then : X_PRE_LIBS="$X_PRE_LIBS -lSM -lICE" fi LDFLAGS=$ac_save_LDFLAGS fi #if test x"$no_x" = xyes; then # AC_ERROR([Can not find X11 development headers or libraries.]) #fi # Checks for libraries. #AC_CHECK_LIB([X11], [XOpenDisplay], , [AC_MSG_ERROR(VIDEO: You need libx11-dev installed)]) { $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -lnettle" >&5 $as_echo_n "checking for main in -lnettle... " >&6; } if ${ac_cv_lib_nettle_main+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lnettle $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { return main (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_nettle_main=yes else ac_cv_lib_nettle_main=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_nettle_main" >&5 $as_echo "$ac_cv_lib_nettle_main" >&6; } if test "x$ac_cv_lib_nettle_main" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBNETTLE 1 _ACEOF LIBS="-lnettle $LIBS" else as_fn_error $? "You need nettle-dev installed" "$LINENO" 5 fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -ldl" >&5 $as_echo_n "checking for main in -ldl... " >&6; } if ${ac_cv_lib_dl_main+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldl $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { return main (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_dl_main=yes else ac_cv_lib_dl_main=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_main" >&5 $as_echo "$ac_cv_lib_dl_main" >&6; } if test "x$ac_cv_lib_dl_main" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBDL 1 _ACEOF LIBS="-ldl $LIBS" else as_fn_error $? "You need libc6-dev installed" "$LINENO" 5 fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for FT_Init_FreeType in -lfreetype" >&5 $as_echo_n "checking for FT_Init_FreeType in -lfreetype... " >&6; } if ${ac_cv_lib_freetype_FT_Init_FreeType+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lfreetype $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char FT_Init_FreeType (); int main () { return FT_Init_FreeType (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_freetype_FT_Init_FreeType=yes else ac_cv_lib_freetype_FT_Init_FreeType=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_freetype_FT_Init_FreeType" >&5 $as_echo "$ac_cv_lib_freetype_FT_Init_FreeType" >&6; } if test "x$ac_cv_lib_freetype_FT_Init_FreeType" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBFREETYPE 1 _ACEOF LIBS="-lfreetype $LIBS" else as_fn_error $? "VIDEO: You need libfreetype6-dev installed. http://freetype.sourceforge.net/index2.html" "$LINENO" 5 fi # Check for SDL_gfx with different function names.. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -lSDL_gfx" >&5 $as_echo_n "checking for main in -lSDL_gfx... " >&6; } if ${ac_cv_lib_SDL_gfx_main+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lSDL_gfx $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { return main (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_SDL_gfx_main=yes else ac_cv_lib_SDL_gfx_main=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_SDL_gfx_main" >&5 $as_echo "$ac_cv_lib_SDL_gfx_main" >&6; } if test "x$ac_cv_lib_SDL_gfx_main" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBSDL_GFX 1 _ACEOF LIBS="-lSDL_gfx $LIBS" else as_fn_error $? "VIDEO: You need libsdl-gfx1.2-dev installed. http://www.ferzkopp.net/wordpress/2016/01/02/sdl_gfx-sdl2_gfx/" "$LINENO" 5 fi ac_fn_c_check_func "$LINENO" "filledPieRGBA" "ac_cv_func_filledPieRGBA" if test "x$ac_cv_func_filledPieRGBA" = xyes; then : $as_echo "#define CAPITAL_FILLED_PIE 1" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -lSDL_ttf" >&5 $as_echo_n "checking for main in -lSDL_ttf... " >&6; } if ${ac_cv_lib_SDL_ttf_main+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lSDL_ttf $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { return main (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_SDL_ttf_main=yes else ac_cv_lib_SDL_ttf_main=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_SDL_ttf_main" >&5 $as_echo "$ac_cv_lib_SDL_ttf_main" >&6; } if test "x$ac_cv_lib_SDL_ttf_main" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBSDL_TTF 1 _ACEOF LIBS="-lSDL_ttf $LIBS" else as_fn_error $? "VIDEO: You need libsdl-ttf2.0-dev installed. http://www.libsdl.org/projects/SDL_ttf/release-1.2.html" "$LINENO" 5 fi if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args. set dummy ${ac_tool_prefix}pkg-config; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_PKG_CONFIG+:} false; then : $as_echo_n "(cached) " >&6 else case $PKG_CONFIG in [\\/]* | ?:[\\/]*) ac_cv_path_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi PKG_CONFIG=$ac_cv_path_PKG_CONFIG if test -n "$PKG_CONFIG"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PKG_CONFIG" >&5 $as_echo "$PKG_CONFIG" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_path_PKG_CONFIG"; then ac_pt_PKG_CONFIG=$PKG_CONFIG # Extract the first word of "pkg-config", so it can be a program name with args. set dummy pkg-config; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_ac_pt_PKG_CONFIG+:} false; then : $as_echo_n "(cached) " >&6 else case $ac_pt_PKG_CONFIG in [\\/]* | ?:[\\/]*) ac_cv_path_ac_pt_PKG_CONFIG="$ac_pt_PKG_CONFIG" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_ac_pt_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi ac_pt_PKG_CONFIG=$ac_cv_path_ac_pt_PKG_CONFIG if test -n "$ac_pt_PKG_CONFIG"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_pt_PKG_CONFIG" >&5 $as_echo "$ac_pt_PKG_CONFIG" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_pt_PKG_CONFIG" = x; then PKG_CONFIG="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac PKG_CONFIG=$ac_pt_PKG_CONFIG fi else PKG_CONFIG="$ac_cv_path_PKG_CONFIG" fi fi if test -n "$PKG_CONFIG"; then _pkg_min_version=0.9.0 { $as_echo "$as_me:${as_lineno-$LINENO}: checking pkg-config is at least version $_pkg_min_version" >&5 $as_echo_n "checking pkg-config is at least version $_pkg_min_version... " >&6; } if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } PKG_CONFIG="" fi fi pkg_failed=no { $as_echo "$as_me:${as_lineno-$LINENO}: checking for SDL" >&5 $as_echo_n "checking for SDL... " >&6; } if test -n "$SDL_CFLAGS"; then pkg_cv_SDL_CFLAGS="$SDL_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"sdl >= 1.2 sdl < 1.3\""; } >&5 ($PKG_CONFIG --exists --print-errors "sdl >= 1.2 sdl < 1.3") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_SDL_CFLAGS=`$PKG_CONFIG --cflags "sdl >= 1.2 sdl < 1.3" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test -n "$SDL_LIBS"; then pkg_cv_SDL_LIBS="$SDL_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"sdl >= 1.2 sdl < 1.3\""; } >&5 ($PKG_CONFIG --exists --print-errors "sdl >= 1.2 sdl < 1.3") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_SDL_LIBS=`$PKG_CONFIG --libs "sdl >= 1.2 sdl < 1.3" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test $pkg_failed = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then SDL_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "sdl >= 1.2 sdl < 1.3" 2>&1` else SDL_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "sdl >= 1.2 sdl < 1.3" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$SDL_PKG_ERRORS" >&5 as_fn_error $? "VIDEO: You need libsdl1.2-dev installed. http://www.libsdl.org/" "$LINENO" 5 elif test $pkg_failed = untried; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } as_fn_error $? "VIDEO: You need libsdl1.2-dev installed. http://www.libsdl.org/" "$LINENO" 5 else SDL_CFLAGS=$pkg_cv_SDL_CFLAGS SDL_LIBS=$pkg_cv_SDL_LIBS { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -llo" >&5 $as_echo_n "checking for main in -llo... " >&6; } if ${ac_cv_lib_lo_main+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-llo $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { return main (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_lo_main=yes else ac_cv_lib_lo_main=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_lo_main" >&5 $as_echo "$ac_cv_lib_lo_main" >&6; } if test "x$ac_cv_lib_lo_main" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBLO 1 _ACEOF LIBS="-llo $LIBS" else as_fn_error $? "CONFIG: You need liblo-dev installed. http://http://liblo.sourceforge.net/" "$LINENO" 5 fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -lxml2" >&5 $as_echo_n "checking for main in -lxml2... " >&6; } if ${ac_cv_lib_xml2_main+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lxml2 $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { return main (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_xml2_main=yes else ac_cv_lib_xml2_main=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_xml2_main" >&5 $as_echo "$ac_cv_lib_xml2_main" >&6; } if test "x$ac_cv_lib_xml2_main" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBXML2 1 _ACEOF LIBS="-lxml2 $LIBS" else as_fn_error $? "CONFIG: You need libxml2-dev installed. http://www.xmlsoft.org/" "$LINENO" 5 fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sqrt in -lm" >&5 $as_echo_n "checking for sqrt in -lm... " >&6; } if ${ac_cv_lib_m_sqrt+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lm $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char sqrt (); int main () { return sqrt (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_m_sqrt=yes else ac_cv_lib_m_sqrt=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_m_sqrt" >&5 $as_echo "$ac_cv_lib_m_sqrt" >&6; } if test "x$ac_cv_lib_m_sqrt" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBM 1 _ACEOF LIBS="-lm $LIBS" else as_fn_error $? "CORE: You need libm installed" "$LINENO" 5 fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_self in -lpthread" >&5 $as_echo_n "checking for pthread_self in -lpthread... " >&6; } if ${ac_cv_lib_pthread_pthread_self+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lpthread $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char pthread_self (); int main () { return pthread_self (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_pthread_pthread_self=yes else ac_cv_lib_pthread_pthread_self=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthread_pthread_self" >&5 $as_echo "$ac_cv_lib_pthread_pthread_self" >&6; } if test "x$ac_cv_lib_pthread_pthread_self" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBPTHREAD 1 _ACEOF LIBS="-lpthread $LIBS" else as_fn_error $? "CORE: You need libpthread installed" "$LINENO" 5 fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -lasound" >&5 $as_echo_n "checking for main in -lasound... " >&6; } if ${ac_cv_lib_asound_main+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lasound $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { return main (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_asound_main=yes else ac_cv_lib_asound_main=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_asound_main" >&5 $as_echo "$ac_cv_lib_asound_main" >&6; } if test "x$ac_cv_lib_asound_main" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBASOUND 1 _ACEOF LIBS="-lasound $LIBS" else as_fn_error $? "AUDIO: You need ALSA installed (libasound2-dev). http://www.alsa-project.org/" "$LINENO" 5 fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for jack_client_open in -ljack" >&5 $as_echo_n "checking for jack_client_open in -ljack... " >&6; } if ${ac_cv_lib_jack_jack_client_open+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ljack $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char jack_client_open (); int main () { return jack_client_open (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_jack_jack_client_open=yes else ac_cv_lib_jack_jack_client_open=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_jack_jack_client_open" >&5 $as_echo "$ac_cv_lib_jack_jack_client_open" >&6; } if test "x$ac_cv_lib_jack_jack_client_open" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBJACK 1 _ACEOF LIBS="-ljack $LIBS" else as_fn_error $? "AUDIO: You need JACK audio library (libjack-dev) installed. http://jackit.sourceforge.net/" "$LINENO" 5 fi if test "$enable_fluidsynth" != "no"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -lfluidsynth" >&5 $as_echo_n "checking for main in -lfluidsynth... " >&6; } if ${ac_cv_lib_fluidsynth_main+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lfluidsynth $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { return main (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_fluidsynth_main=yes else ac_cv_lib_fluidsynth_main=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_fluidsynth_main" >&5 $as_echo "$ac_cv_lib_fluidsynth_main" >&6; } if test "x$ac_cv_lib_fluidsynth_main" = xyes; then : fluidsynth=yes else fluidsynth=no fi if test "$fluidsynth" = "yes"; then LIBS="$LIBS -lfluidsynth" $as_echo "#define USE_FLUIDSYNTH 1" >>confdefs.h echo "--- Enabling integrated FluidSynth synth ---"; else echo "--- No libfluidsynth -- FluidSynth support will not be built! ---"; fi else echo "--- Disabling integrated FluidSynth synth ---"; fi if test "$enable_video" == "no"; then $as_echo "#define NO_VIDEO 1" >>confdefs.h echo "--- Disabling video output --"; fi if test "$enable_lcd" == "yes"; then $as_echo "#define LCD_DISPLAY 1" >>confdefs.h echo "--- Enabling USB LCD display --"; fi #SDL_VERSION=1.2.4 #AM_PATH_SDL($SDL_VERSION, # :, # AC_MSG_ERROR([VIDEO: *** SDL version $SDL_VERSION not found! # http://www.libsdl.org/]) #) { $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -lvorbis" >&5 $as_echo_n "checking for main in -lvorbis... " >&6; } if ${ac_cv_lib_vorbis_main+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lvorbis $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { return main (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_vorbis_main=yes else ac_cv_lib_vorbis_main=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_vorbis_main" >&5 $as_echo "$ac_cv_lib_vorbis_main" >&6; } if test "x$ac_cv_lib_vorbis_main" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBVORBIS 1 _ACEOF LIBS="-lvorbis $LIBS" else as_fn_error $? "AUDIO: You need libvorbis-dev installed. http://www.xiph.org/ogg/vorbis/" "$LINENO" 5 fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -lvorbisfile" >&5 $as_echo_n "checking for main in -lvorbisfile... " >&6; } if ${ac_cv_lib_vorbisfile_main+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lvorbisfile $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { return main (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_vorbisfile_main=yes else ac_cv_lib_vorbisfile_main=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_vorbisfile_main" >&5 $as_echo "$ac_cv_lib_vorbisfile_main" >&6; } if test "x$ac_cv_lib_vorbisfile_main" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBVORBISFILE 1 _ACEOF LIBS="-lvorbisfile $LIBS" else as_fn_error $? "AUDIO: You need libvorbisfile installed. http://www.xiph.org/ogg/vorbis/" "$LINENO" 5 fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -lvorbisenc" >&5 $as_echo_n "checking for main in -lvorbisenc... " >&6; } if ${ac_cv_lib_vorbisenc_main+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lvorbisenc $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { return main (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_vorbisenc_main=yes else ac_cv_lib_vorbisenc_main=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_vorbisenc_main" >&5 $as_echo "$ac_cv_lib_vorbisenc_main" >&6; } if test "x$ac_cv_lib_vorbisenc_main" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBVORBISENC 1 _ACEOF LIBS="-lvorbisenc $LIBS" else as_fn_error $? "AUDIO: You need libvorbis-dev installed. http://www.xiph.org/ogg/vorbis/" "$LINENO" 5 fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -logg" >&5 $as_echo_n "checking for main in -logg... " >&6; } if ${ac_cv_lib_ogg_main+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-logg $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { return main (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_ogg_main=yes else ac_cv_lib_ogg_main=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ogg_main" >&5 $as_echo "$ac_cv_lib_ogg_main" >&6; } if test "x$ac_cv_lib_ogg_main" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBOGG 1 _ACEOF LIBS="-logg $LIBS" else as_fn_error $? "AUDIO: You need libogg-dev installed. http://www.xiph.org/ogg/vorbis/" "$LINENO" 5 fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -lsndfile" >&5 $as_echo_n "checking for main in -lsndfile... " >&6; } if ${ac_cv_lib_sndfile_main+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lsndfile $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { return main (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_sndfile_main=yes else ac_cv_lib_sndfile_main=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_sndfile_main" >&5 $as_echo "$ac_cv_lib_sndfile_main" >&6; } if test "x$ac_cv_lib_sndfile_main" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBSNDFILE 1 _ACEOF LIBS="-lsndfile $LIBS" else as_fn_error $? "AUDIO: you need libsndfile-dev installed. http://www.http://www.mega-nerd.com/libsndfile/" "$LINENO" 5 fi CFLAGS="$CFLAGS $SDL_CFLAGS" LIBS="$X_LIBS $X_PRE_LIBS -L/usr/X11R6/lib -lX11 $X_EXTRA_LIBS $LIBS" LIBS="$LIBS $SDL_LIBS" # Checks for header files. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for X" >&5 $as_echo_n "checking for X... " >&6; } # Check whether --with-x was given. if test "${with_x+set}" = set; then : withval=$with_x; fi # $have_x is `yes', `no', `disabled', or empty when we do not yet know. if test "x$with_x" = xno; then # The user explicitly disabled X. have_x=disabled else case $x_includes,$x_libraries in #( *\'*) as_fn_error $? "cannot use X directory names containing '" "$LINENO" 5;; #( *,NONE | NONE,*) if ${ac_cv_have_x+:} false; then : $as_echo_n "(cached) " >&6 else # One or both of the vars are not set, and there is no cached value. ac_x_includes=no ac_x_libraries=no rm -f -r conftest.dir if mkdir conftest.dir; then cd conftest.dir cat >Imakefile <<'_ACEOF' incroot: @echo incroot='${INCROOT}' usrlibdir: @echo usrlibdir='${USRLIBDIR}' libdir: @echo libdir='${LIBDIR}' _ACEOF if (export CC; ${XMKMF-xmkmf}) >/dev/null 2>/dev/null && test -f Makefile; then # GNU make sometimes prints "make[1]: Entering ...", which would confuse us. for ac_var in incroot usrlibdir libdir; do eval "ac_im_$ac_var=\`\${MAKE-make} $ac_var 2>/dev/null | sed -n 's/^$ac_var=//p'\`" done # Open Windows xmkmf reportedly sets LIBDIR instead of USRLIBDIR. for ac_extension in a so sl dylib la dll; do if test ! -f "$ac_im_usrlibdir/libX11.$ac_extension" && test -f "$ac_im_libdir/libX11.$ac_extension"; then ac_im_usrlibdir=$ac_im_libdir; break fi done # Screen out bogus values from the imake configuration. They are # bogus both because they are the default anyway, and because # using them would break gcc on systems where it needs fixed includes. case $ac_im_incroot in /usr/include) ac_x_includes= ;; *) test -f "$ac_im_incroot/X11/Xos.h" && ac_x_includes=$ac_im_incroot;; esac case $ac_im_usrlibdir in /usr/lib | /usr/lib64 | /lib | /lib64) ;; *) test -d "$ac_im_usrlibdir" && ac_x_libraries=$ac_im_usrlibdir ;; esac fi cd .. rm -f -r conftest.dir fi # Standard set of common directories for X headers. # Check X11 before X11Rn because it is often a symlink to the current release. ac_x_header_dirs=' /usr/X11/include /usr/X11R7/include /usr/X11R6/include /usr/X11R5/include /usr/X11R4/include /usr/include/X11 /usr/include/X11R7 /usr/include/X11R6 /usr/include/X11R5 /usr/include/X11R4 /usr/local/X11/include /usr/local/X11R7/include /usr/local/X11R6/include /usr/local/X11R5/include /usr/local/X11R4/include /usr/local/include/X11 /usr/local/include/X11R7 /usr/local/include/X11R6 /usr/local/include/X11R5 /usr/local/include/X11R4 /usr/X386/include /usr/x386/include /usr/XFree86/include/X11 /usr/include /usr/local/include /usr/unsupported/include /usr/athena/include /usr/local/x11r5/include /usr/lpp/Xamples/include /usr/openwin/include /usr/openwin/share/include' if test "$ac_x_includes" = no; then # Guess where to find include files, by looking for Xlib.h. # First, try using that file with no special directory specified. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : # We can compile using X headers with no special include directory. ac_x_includes= else for ac_dir in $ac_x_header_dirs; do if test -r "$ac_dir/X11/Xlib.h"; then ac_x_includes=$ac_dir break fi done fi rm -f conftest.err conftest.i conftest.$ac_ext fi # $ac_x_includes = no if test "$ac_x_libraries" = no; then # Check for the libraries. # See if we find them without any special options. # Don't add to $LIBS permanently. ac_save_LIBS=$LIBS LIBS="-lX11 $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { XrmInitialize () ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : LIBS=$ac_save_LIBS # We can link X programs with no special library path. ac_x_libraries= else LIBS=$ac_save_LIBS for ac_dir in `$as_echo "$ac_x_includes $ac_x_header_dirs" | sed s/include/lib/g` do # Don't even attempt the hair of trying to link an X program! for ac_extension in a so sl dylib la dll; do if test -r "$ac_dir/libX11.$ac_extension"; then ac_x_libraries=$ac_dir break 2 fi done done fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi # $ac_x_libraries = no case $ac_x_includes,$ac_x_libraries in #( no,* | *,no | *\'*) # Didn't find X, or a directory has "'" in its name. ac_cv_have_x="have_x=no";; #( *) # Record where we found X for the cache. ac_cv_have_x="have_x=yes\ ac_x_includes='$ac_x_includes'\ ac_x_libraries='$ac_x_libraries'" esac fi ;; #( *) have_x=yes;; esac eval "$ac_cv_have_x" fi # $with_x != no if test "$have_x" != yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_x" >&5 $as_echo "$have_x" >&6; } no_x=yes else # If each of the values was on the command line, it overrides each guess. test "x$x_includes" = xNONE && x_includes=$ac_x_includes test "x$x_libraries" = xNONE && x_libraries=$ac_x_libraries # Update the cache value to reflect the command line values. ac_cv_have_x="have_x=yes\ ac_x_includes='$x_includes'\ ac_x_libraries='$x_libraries'" { $as_echo "$as_me:${as_lineno-$LINENO}: result: libraries $x_libraries, headers $x_includes" >&5 $as_echo "libraries $x_libraries, headers $x_includes" >&6; } fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 $as_echo_n "checking for grep that handles long lines and -e... " >&6; } if ${ac_cv_path_GREP+:} false; then : $as_echo_n "(cached) " >&6 else if test -z "$GREP"; then ac_path_GREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in grep ggrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_GREP" || continue # Check for GNU ac_path_GREP and select it if it is found. # Check for GNU $ac_path_GREP case `"$ac_path_GREP" --version 2>&1` in *GNU*) ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'GREP' >> "conftest.nl" "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_GREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_GREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_GREP"; then as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_GREP=$GREP fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 $as_echo "$ac_cv_path_GREP" >&6; } GREP="$ac_cv_path_GREP" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 $as_echo_n "checking for egrep... " >&6; } if ${ac_cv_path_EGREP+:} false; then : $as_echo_n "(cached) " >&6 else if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 then ac_cv_path_EGREP="$GREP -E" else if test -z "$EGREP"; then ac_path_EGREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in egrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_EGREP" || continue # Check for GNU ac_path_EGREP and select it if it is found. # Check for GNU $ac_path_EGREP case `"$ac_path_EGREP" --version 2>&1` in *GNU*) ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'EGREP' >> "conftest.nl" "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_EGREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_EGREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_EGREP"; then as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_EGREP=$EGREP fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 $as_echo "$ac_cv_path_EGREP" >&6; } EGREP="$ac_cv_path_EGREP" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 $as_echo_n "checking for ANSI C header files... " >&6; } if ${ac_cv_header_stdc+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #include int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_header_stdc=yes else ac_cv_header_stdc=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if test $ac_cv_header_stdc = yes; then # SunOS 4.x string.h does not declare mem*, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "memchr" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "free" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. if test "$cross_compiling" = yes; then : : else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #if ((' ' & 0x0FF) == 0x020) # define ISLOWER(c) ('a' <= (c) && (c) <= 'z') # define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) #else # define ISLOWER(c) \ (('a' <= (c) && (c) <= 'i') \ || ('j' <= (c) && (c) <= 'r') \ || ('s' <= (c) && (c) <= 'z')) # define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) #endif #define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) int main () { int i; for (i = 0; i < 256; i++) if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) return 2; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : else ac_cv_header_stdc=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 $as_echo "$ac_cv_header_stdc" >&6; } if test $ac_cv_header_stdc = yes; then $as_echo "#define STDC_HEADERS 1" >>confdefs.h fi # On IRIX 5.3, sys/types and inttypes.h are conflicting. for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ inttypes.h stdint.h unistd.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default " if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done for ac_header in errno.h fcntl.h inttypes.h limits.h stdint.h stdlib.h string.h sys/resource.h sys/time.h termios.h unistd.h utime.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done # Checks for typedefs, structures, and compiler characteristics. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for an ANSI C-conforming const" >&5 $as_echo_n "checking for an ANSI C-conforming const... " >&6; } if ${ac_cv_c_const+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { #ifndef __cplusplus /* Ultrix mips cc rejects this sort of thing. */ typedef int charset[2]; const charset cs = { 0, 0 }; /* SunOS 4.1.1 cc rejects this. */ char const *const *pcpcc; char **ppc; /* NEC SVR4.0.2 mips cc rejects this. */ struct point {int x, y;}; static struct point const zero = {0,0}; /* AIX XL C 1.02.0.0 rejects this. It does not let you subtract one const X* pointer from another in an arm of an if-expression whose if-part is not a constant expression */ const char *g = "string"; pcpcc = &g + (g ? g-g : 0); /* HPUX 7.0 cc rejects these. */ ++pcpcc; ppc = (char**) pcpcc; pcpcc = (char const *const *) ppc; { /* SCO 3.2v4 cc rejects this sort of thing. */ char tx; char *t = &tx; char const *s = 0 ? (char *) 0 : (char const *) 0; *t++ = 0; if (s) return 0; } { /* Someone thinks the Sun supposedly-ANSI compiler will reject this. */ int x[] = {25, 17}; const int *foo = &x[0]; ++foo; } { /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */ typedef const int *iptr; iptr p = 0; ++p; } { /* AIX XL C 1.02.0.0 rejects this sort of thing, saying "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */ struct s { int j; const int *ap[3]; } bx; struct s *b = &bx; b->j = 5; } { /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */ const int foo = 10; if (!foo) return 0; } return !cs[0] && !zero.x; #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_c_const=yes else ac_cv_c_const=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_const" >&5 $as_echo "$ac_cv_c_const" >&6; } if test $ac_cv_c_const = no; then $as_echo "#define const /**/" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether time.h and sys/time.h may both be included" >&5 $as_echo_n "checking whether time.h and sys/time.h may both be included... " >&6; } if ${ac_cv_header_time+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include int main () { if ((struct tm *) 0) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_header_time=yes else ac_cv_header_time=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_time" >&5 $as_echo "$ac_cv_header_time" >&6; } if test $ac_cv_header_time = yes; then $as_echo "#define TIME_WITH_SYS_TIME 1" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for inline" >&5 $as_echo_n "checking for inline... " >&6; } if ${ac_cv_c_inline+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_c_inline=no for ac_kw in inline __inline__ __inline; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifndef __cplusplus typedef int foo_t; static $ac_kw foo_t static_foo () {return 0; } $ac_kw foo_t foo () {return 0; } #endif _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_c_inline=$ac_kw fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext test "$ac_cv_c_inline" != no && break done fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_inline" >&5 $as_echo "$ac_cv_c_inline" >&6; } case $ac_cv_c_inline in inline | yes) ;; *) case $ac_cv_c_inline in no) ac_val=;; *) ac_val=$ac_cv_c_inline;; esac cat >>confdefs.h <<_ACEOF #ifndef __cplusplus #define inline $ac_val #endif _ACEOF ;; esac ac_fn_c_find_intX_t "$LINENO" "32" "ac_cv_c_int32_t" case $ac_cv_c_int32_t in #( no|yes) ;; #( *) cat >>confdefs.h <<_ACEOF #define int32_t $ac_cv_c_int32_t _ACEOF ;; esac ac_fn_c_check_type "$LINENO" "pid_t" "ac_cv_type_pid_t" "$ac_includes_default" if test "x$ac_cv_type_pid_t" = xyes; then : else cat >>confdefs.h <<_ACEOF #define pid_t int _ACEOF fi ac_fn_c_check_type "$LINENO" "size_t" "ac_cv_type_size_t" "$ac_includes_default" if test "x$ac_cv_type_size_t" = xyes; then : else cat >>confdefs.h <<_ACEOF #define size_t unsigned int _ACEOF fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for stdbool.h that conforms to C99" >&5 $as_echo_n "checking for stdbool.h that conforms to C99... " >&6; } if ${ac_cv_header_stdbool_h+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #ifndef bool "error: bool is not defined" #endif #ifndef false "error: false is not defined" #endif #if false "error: false is not 0" #endif #ifndef true "error: true is not defined" #endif #if true != 1 "error: true is not 1" #endif #ifndef __bool_true_false_are_defined "error: __bool_true_false_are_defined is not defined" #endif struct s { _Bool s: 1; _Bool t; } s; char a[true == 1 ? 1 : -1]; char b[false == 0 ? 1 : -1]; char c[__bool_true_false_are_defined == 1 ? 1 : -1]; char d[(bool) 0.5 == true ? 1 : -1]; /* See body of main program for 'e'. */ char f[(_Bool) 0.0 == false ? 1 : -1]; char g[true]; char h[sizeof (_Bool)]; char i[sizeof s.t]; enum { j = false, k = true, l = false * true, m = true * 256 }; /* The following fails for HP aC++/ANSI C B3910B A.05.55 [Dec 04 2003]. */ _Bool n[m]; char o[sizeof n == m * sizeof n[0] ? 1 : -1]; char p[-1 - (_Bool) 0 < 0 && -1 - (bool) 0 < 0 ? 1 : -1]; /* Catch a bug in an HP-UX C compiler. See http://gcc.gnu.org/ml/gcc-patches/2003-12/msg02303.html http://lists.gnu.org/archive/html/bug-coreutils/2005-11/msg00161.html */ _Bool q = true; _Bool *pq = &q; int main () { bool e = &s; *pq |= q; *pq |= ! q; /* Refer to every declared value, to avoid compiler optimizations. */ return (!a + !b + !c + !d + !e + !f + !g + !h + !i + !!j + !k + !!l + !m + !n + !o + !p + !q + !pq); ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_header_stdbool_h=yes else ac_cv_header_stdbool_h=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdbool_h" >&5 $as_echo "$ac_cv_header_stdbool_h" >&6; } ac_fn_c_check_type "$LINENO" "_Bool" "ac_cv_type__Bool" "$ac_includes_default" if test "x$ac_cv_type__Bool" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE__BOOL 1 _ACEOF fi ac_fn_c_find_uintX_t "$LINENO" "32" "ac_cv_c_uint32_t" case $ac_cv_c_uint32_t in #( no|yes) ;; #( *) $as_echo "#define _UINT32_T 1" >>confdefs.h cat >>confdefs.h <<_ACEOF #define uint32_t $ac_cv_c_uint32_t _ACEOF ;; esac ac_fn_c_find_uintX_t "$LINENO" "8" "ac_cv_c_uint8_t" case $ac_cv_c_uint8_t in #( no|yes) ;; #( *) $as_echo "#define _UINT8_T 1" >>confdefs.h cat >>confdefs.h <<_ACEOF #define uint8_t $ac_cv_c_uint8_t _ACEOF ;; esac # Checks for library functions. # The Ultrix 4.2 mips builtin alloca declared by alloca.h only works # for constant arguments. Useless! { $as_echo "$as_me:${as_lineno-$LINENO}: checking for working alloca.h" >&5 $as_echo_n "checking for working alloca.h... " >&6; } if ${ac_cv_working_alloca_h+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { char *p = (char *) alloca (2 * sizeof (int)); if (p) return 0; ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_working_alloca_h=yes else ac_cv_working_alloca_h=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_working_alloca_h" >&5 $as_echo "$ac_cv_working_alloca_h" >&6; } if test $ac_cv_working_alloca_h = yes; then $as_echo "#define HAVE_ALLOCA_H 1" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for alloca" >&5 $as_echo_n "checking for alloca... " >&6; } if ${ac_cv_func_alloca_works+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __GNUC__ # define alloca __builtin_alloca #else # ifdef _MSC_VER # include # define alloca _alloca # else # ifdef HAVE_ALLOCA_H # include # else # ifdef _AIX #pragma alloca # else # ifndef alloca /* predefined by HP cc +Olibcalls */ void *alloca (size_t); # endif # endif # endif # endif #endif int main () { char *p = (char *) alloca (1); if (p) return 0; ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_func_alloca_works=yes else ac_cv_func_alloca_works=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_alloca_works" >&5 $as_echo "$ac_cv_func_alloca_works" >&6; } if test $ac_cv_func_alloca_works = yes; then $as_echo "#define HAVE_ALLOCA 1" >>confdefs.h else # The SVR3 libPW and SVR4 libucb both contain incompatible functions # that cause trouble. Some versions do not even contain alloca or # contain a buggy version. If you still want to use their alloca, # use ar to extract alloca.o from them instead of compiling alloca.c. ALLOCA=\${LIBOBJDIR}alloca.$ac_objext $as_echo "#define C_ALLOCA 1" >>confdefs.h { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether \`alloca.c' needs Cray hooks" >&5 $as_echo_n "checking whether \`alloca.c' needs Cray hooks... " >&6; } if ${ac_cv_os_cray+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #if defined CRAY && ! defined CRAY2 webecray #else wenotbecray #endif _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "webecray" >/dev/null 2>&1; then : ac_cv_os_cray=yes else ac_cv_os_cray=no fi rm -f conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_os_cray" >&5 $as_echo "$ac_cv_os_cray" >&6; } if test $ac_cv_os_cray = yes; then for ac_func in _getb67 GETB67 getb67; do as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define CRAY_STACKSEG_END $ac_func _ACEOF break fi done fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking stack direction for C alloca" >&5 $as_echo_n "checking stack direction for C alloca... " >&6; } if ${ac_cv_c_stack_direction+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : ac_cv_c_stack_direction=0 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default int find_stack_direction (int *addr, int depth) { int dir, dummy = 0; if (! addr) addr = &dummy; *addr = addr < &dummy ? 1 : addr == &dummy ? 0 : -1; dir = depth ? find_stack_direction (addr, depth - 1) : 0; return dir + dummy; } int main (int argc, char **argv) { return find_stack_direction (0, argc + !argv + 20) < 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : ac_cv_c_stack_direction=1 else ac_cv_c_stack_direction=-1 fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_stack_direction" >&5 $as_echo "$ac_cv_c_stack_direction" >&6; } cat >>confdefs.h <<_ACEOF #define STACK_DIRECTION $ac_cv_c_stack_direction _ACEOF fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for error_at_line" >&5 $as_echo_n "checking for error_at_line... " >&6; } if ${ac_cv_lib_error_at_line+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { error_at_line (0, 0, "", 0, "an error occurred"); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_error_at_line=yes else ac_cv_lib_error_at_line=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_error_at_line" >&5 $as_echo "$ac_cv_lib_error_at_line" >&6; } if test $ac_cv_lib_error_at_line = no; then case " $LIBOBJS " in *" error.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS error.$ac_objext" ;; esac fi for ac_header in vfork.h do : ac_fn_c_check_header_mongrel "$LINENO" "vfork.h" "ac_cv_header_vfork_h" "$ac_includes_default" if test "x$ac_cv_header_vfork_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_VFORK_H 1 _ACEOF fi done for ac_func in fork vfork do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF fi done if test "x$ac_cv_func_fork" = xyes; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for working fork" >&5 $as_echo_n "checking for working fork... " >&6; } if ${ac_cv_func_fork_works+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : ac_cv_func_fork_works=cross else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default int main () { /* By Ruediger Kuhlmann. */ return fork () < 0; ; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : ac_cv_func_fork_works=yes else ac_cv_func_fork_works=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_fork_works" >&5 $as_echo "$ac_cv_func_fork_works" >&6; } else ac_cv_func_fork_works=$ac_cv_func_fork fi if test "x$ac_cv_func_fork_works" = xcross; then case $host in *-*-amigaos* | *-*-msdosdjgpp*) # Override, as these systems have only a dummy fork() stub ac_cv_func_fork_works=no ;; *) ac_cv_func_fork_works=yes ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: result $ac_cv_func_fork_works guessed because of cross compilation" >&5 $as_echo "$as_me: WARNING: result $ac_cv_func_fork_works guessed because of cross compilation" >&2;} fi ac_cv_func_vfork_works=$ac_cv_func_vfork if test "x$ac_cv_func_vfork" = xyes; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for working vfork" >&5 $as_echo_n "checking for working vfork... " >&6; } if ${ac_cv_func_vfork_works+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : ac_cv_func_vfork_works=cross else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Thanks to Paul Eggert for this test. */ $ac_includes_default #include #ifdef HAVE_VFORK_H # include #endif /* On some sparc systems, changes by the child to local and incoming argument registers are propagated back to the parent. The compiler is told about this with #include , but some compilers (e.g. gcc -O) don't grok . Test for this by using a static variable whose address is put into a register that is clobbered by the vfork. */ static void #ifdef __cplusplus sparc_address_test (int arg) # else sparc_address_test (arg) int arg; #endif { static pid_t child; if (!child) { child = vfork (); if (child < 0) { perror ("vfork"); _exit(2); } if (!child) { arg = getpid(); write(-1, "", 0); _exit (arg); } } } int main () { pid_t parent = getpid (); pid_t child; sparc_address_test (0); child = vfork (); if (child == 0) { /* Here is another test for sparc vfork register problems. This test uses lots of local variables, at least as many local variables as main has allocated so far including compiler temporaries. 4 locals are enough for gcc 1.40.3 on a Solaris 4.1.3 sparc, but we use 8 to be safe. A buggy compiler should reuse the register of parent for one of the local variables, since it will think that parent can't possibly be used any more in this routine. Assigning to the local variable will thus munge parent in the parent process. */ pid_t p = getpid(), p1 = getpid(), p2 = getpid(), p3 = getpid(), p4 = getpid(), p5 = getpid(), p6 = getpid(), p7 = getpid(); /* Convince the compiler that p..p7 are live; otherwise, it might use the same hardware register for all 8 local variables. */ if (p != p1 || p != p2 || p != p3 || p != p4 || p != p5 || p != p6 || p != p7) _exit(1); /* On some systems (e.g. IRIX 3.3), vfork doesn't separate parent from child file descriptors. If the child closes a descriptor before it execs or exits, this munges the parent's descriptor as well. Test for this by closing stdout in the child. */ _exit(close(fileno(stdout)) != 0); } else { int status; struct stat st; while (wait(&status) != child) ; return ( /* Was there some problem with vforking? */ child < 0 /* Did the child fail? (This shouldn't happen.) */ || status /* Did the vfork/compiler bug occur? */ || parent != getpid() /* Did the file descriptor bug occur? */ || fstat(fileno(stdout), &st) != 0 ); } } _ACEOF if ac_fn_c_try_run "$LINENO"; then : ac_cv_func_vfork_works=yes else ac_cv_func_vfork_works=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_vfork_works" >&5 $as_echo "$ac_cv_func_vfork_works" >&6; } fi; if test "x$ac_cv_func_fork_works" = xcross; then ac_cv_func_vfork_works=$ac_cv_func_vfork { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: result $ac_cv_func_vfork_works guessed because of cross compilation" >&5 $as_echo "$as_me: WARNING: result $ac_cv_func_vfork_works guessed because of cross compilation" >&2;} fi if test "x$ac_cv_func_vfork_works" = xyes; then $as_echo "#define HAVE_WORKING_VFORK 1" >>confdefs.h else $as_echo "#define vfork fork" >>confdefs.h fi if test "x$ac_cv_func_fork_works" = xyes; then $as_echo "#define HAVE_WORKING_FORK 1" >>confdefs.h fi for ac_header in stdlib.h do : ac_fn_c_check_header_mongrel "$LINENO" "stdlib.h" "ac_cv_header_stdlib_h" "$ac_includes_default" if test "x$ac_cv_header_stdlib_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STDLIB_H 1 _ACEOF fi done { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU libc compatible malloc" >&5 $as_echo_n "checking for GNU libc compatible malloc... " >&6; } if ${ac_cv_func_malloc_0_nonnull+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : ac_cv_func_malloc_0_nonnull=no else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #if defined STDC_HEADERS || defined HAVE_STDLIB_H # include #else char *malloc (); #endif int main () { return ! malloc (0); ; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : ac_cv_func_malloc_0_nonnull=yes else ac_cv_func_malloc_0_nonnull=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_malloc_0_nonnull" >&5 $as_echo "$ac_cv_func_malloc_0_nonnull" >&6; } if test $ac_cv_func_malloc_0_nonnull = yes; then : $as_echo "#define HAVE_MALLOC 1" >>confdefs.h else $as_echo "#define HAVE_MALLOC 0" >>confdefs.h case " $LIBOBJS " in *" malloc.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS malloc.$ac_objext" ;; esac $as_echo "#define malloc rpl_malloc" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for working strtod" >&5 $as_echo_n "checking for working strtod... " >&6; } if ${ac_cv_func_strtod+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : ac_cv_func_strtod=no else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default #ifndef strtod double strtod (); #endif int main() { { /* Some versions of Linux strtod mis-parse strings with leading '+'. */ char *string = " +69"; char *term; double value; value = strtod (string, &term); if (value != 69 || term != (string + 4)) return 1; } { /* Under Solaris 2.4, strtod returns the wrong value for the terminating character under some conditions. */ char *string = "NaN"; char *term; strtod (string, &term); if (term != string && *(term - 1) == 0) return 1; } return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : ac_cv_func_strtod=yes else ac_cv_func_strtod=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_strtod" >&5 $as_echo "$ac_cv_func_strtod" >&6; } if test $ac_cv_func_strtod = no; then case " $LIBOBJS " in *" strtod.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS strtod.$ac_objext" ;; esac ac_fn_c_check_func "$LINENO" "pow" "ac_cv_func_pow" if test "x$ac_cv_func_pow" = xyes; then : fi if test $ac_cv_func_pow = no; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pow in -lm" >&5 $as_echo_n "checking for pow in -lm... " >&6; } if ${ac_cv_lib_m_pow+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lm $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char pow (); int main () { return pow (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_m_pow=yes else ac_cv_lib_m_pow=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_m_pow" >&5 $as_echo "$ac_cv_lib_m_pow" >&6; } if test "x$ac_cv_lib_m_pow" = xyes; then : POW_LIB=-lm else { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cannot find library containing definition of pow" >&5 $as_echo "$as_me: WARNING: cannot find library containing definition of pow" >&2;} fi fi fi for ac_func in atexit dup2 floor gettimeofday memset pow realpath select sqrt strcasecmp strchr strncasecmp strrchr strtol do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF fi done ac_config_files="$ac_config_files Makefile src/Makefile data/Makefile" cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure # scripts and configure runs, see configure's option --config-cache. # It is not useful on other systems. If it contains results you don't # want to keep, you may remove or edit it. # # config.status only pays attention to the cache file if you give it # the --recheck option to rerun configure. # # `ac_cv_env_foo' variables (set or unset) will be overridden when # loading this file, other *unset* `ac_cv_foo' will be assigned the # following values. _ACEOF # The following way of writing the cache mishandles newlines in values, # but we know of no workaround that is simple, portable, and efficient. # So, we kill variables containing newlines. # Ultrix sh set writes to stderr and can't be redirected directly, # and sets the high bit in the cache file unless we assign to the vars. ( for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space=' '; set) 2>&1` in #( *${as_nl}ac_space=\ *) # `set' does not quote correctly, so add quotes: double-quote # substitution turns \\\\ into \\, and sed turns \\ into \. sed -n \ "s/'/'\\\\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" ;; #( *) # `set' quotes correctly as required by POSIX, so do not add quotes. sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) | sed ' /^ac_cv_env_/b end t clear :clear s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ t end s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ :end' >>confcache if diff "$cache_file" confcache >/dev/null 2>&1; then :; else if test -w "$cache_file"; then if test "x$cache_file" != "x/dev/null"; then { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 $as_echo "$as_me: updating cache $cache_file" >&6;} if test ! -f "$cache_file" || test -h "$cache_file"; then cat confcache >"$cache_file" else case $cache_file in #( */* | ?:*) mv -f confcache "$cache_file"$$ && mv -f "$cache_file"$$ "$cache_file" ;; #( *) mv -f confcache "$cache_file" ;; esac fi fi else { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 $as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} fi fi rm -f confcache test "x$prefix" = xNONE && prefix=$ac_default_prefix # Let make expand exec_prefix. test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' # Transform confdefs.h into DEFS. # Protect against shell expansion while executing Makefile rules. # Protect against Makefile macro expansion. # # If the first sed substitution is executed (which looks for macros that # take arguments), then branch to the quote section. Otherwise, # look for a macro that doesn't take arguments. ac_script=' :mline /\\$/{ N s,\\\n,, b mline } t clear :clear s/^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*([^)]*)\)[ ]*\(.*\)/-D\1=\2/g t quote s/^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)/-D\1=\2/g t quote b any :quote s/[ `~#$^&*(){}\\|;'\''"<>?]/\\&/g s/\[/\\&/g s/\]/\\&/g s/\$/$$/g H :any ${ g s/^\n// s/\n/ /g p } ' DEFS=`sed -n "$ac_script" confdefs.h` ac_libobjs= ac_ltlibobjs= U= for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue # 1. Remove the extension, and $U if already installed. ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' ac_i=`$as_echo "$ac_i" | sed "$ac_script"` # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR # will be set to the directory where LIBOBJS objects are built. as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' done LIBOBJS=$ac_libobjs LTLIBOBJS=$ac_ltlibobjs { $as_echo "$as_me:${as_lineno-$LINENO}: checking that generated files are newer than configure" >&5 $as_echo_n "checking that generated files are newer than configure... " >&6; } if test -n "$am_sleep_pid"; then # Hide warnings about reused PIDs. wait $am_sleep_pid 2>/dev/null fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: done" >&5 $as_echo "done" >&6; } if test -n "$EXEEXT"; then am__EXEEXT_TRUE= am__EXEEXT_FALSE='#' else am__EXEEXT_TRUE='#' am__EXEEXT_FALSE= fi if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then as_fn_error $? "conditional \"AMDEP\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${am__fastdepCXX_TRUE}" && test -z "${am__fastdepCXX_FALSE}"; then as_fn_error $? "conditional \"am__fastdepCXX\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then as_fn_error $? "conditional \"am__fastdepCC\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi : "${CONFIG_STATUS=./config.status}" ac_write_fail=0 ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files $CONFIG_STATUS" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 $as_echo "$as_me: creating $CONFIG_STATUS" >&6;} as_write_fail=0 cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 #! $SHELL # Generated by $as_me. # Run this file to recreate the current configuration. # Compiler output produced by configure, useful for debugging # configure, is in config.log if it exists. debug=false ac_cs_recheck=false ac_cs_silent=false SHELL=\${CONFIG_SHELL-$SHELL} export SHELL _ASEOF cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" exec 6>&1 ## ----------------------------------- ## ## Main body of $CONFIG_STATUS script. ## ## ----------------------------------- ## _ASEOF test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Save the log message, to keep $0 and so on meaningful, and to # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" This file was extended by fweelin $as_me 0.6.6, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS CONFIG_LINKS = $CONFIG_LINKS CONFIG_COMMANDS = $CONFIG_COMMANDS $ $0 $@ on `(hostname || uname -n) 2>/dev/null | sed 1q` " _ACEOF case $ac_config_files in *" "*) set x $ac_config_files; shift; ac_config_files=$*;; esac cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # Files that config.status was made for. config_files="$ac_config_files" config_commands="$ac_config_commands" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 ac_cs_usage="\ \`$as_me' instantiates files and other configuration actions from templates according to the current configuration. Unless the files and actions are specified as TAGs, all are instantiated by default. Usage: $0 [OPTION]... [TAG]... -h, --help print this help, then exit -V, --version print version number and configuration settings, then exit --config print configuration, then exit -q, --quiet, --silent do not print progress messages -d, --debug don't remove temporary files --recheck update $as_me by reconfiguring in the same conditions --file=FILE[:TEMPLATE] instantiate the configuration file FILE Configuration files: $config_files Configuration commands: $config_commands Report bugs to ." _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ fweelin config.status 0.6.6 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" Copyright (C) 2012 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." ac_pwd='$ac_pwd' srcdir='$srcdir' INSTALL='$INSTALL' MKDIR_P='$MKDIR_P' AWK='$AWK' test -n "\$AWK" || AWK=awk _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # The default lists apply if the user does not specify any file. ac_need_defaults=: while test $# != 0 do case $1 in --*=?*) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` ac_shift=: ;; --*=) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg= ac_shift=: ;; *) ac_option=$1 ac_optarg=$2 ac_shift=shift ;; esac case $ac_option in # Handling of the options. -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) ac_cs_recheck=: ;; --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) $as_echo "$ac_cs_version"; exit ;; --config | --confi | --conf | --con | --co | --c ) $as_echo "$ac_cs_config"; exit ;; --debug | --debu | --deb | --de | --d | -d ) debug=: ;; --file | --fil | --fi | --f ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; '') as_fn_error $? "missing file argument" ;; esac as_fn_append CONFIG_FILES " '$ac_optarg'" ac_need_defaults=false;; --he | --h | --help | --hel | -h ) $as_echo "$ac_cs_usage"; exit ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil | --si | --s) ac_cs_silent=: ;; # This is an error. -*) as_fn_error $? "unrecognized option: \`$1' Try \`$0 --help' for more information." ;; *) as_fn_append ac_config_targets " $1" ac_need_defaults=false ;; esac shift done ac_configure_extra_args= if $ac_cs_silent; then exec 6>/dev/null ac_configure_extra_args="$ac_configure_extra_args --silent" fi _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 if \$ac_cs_recheck; then set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion shift \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 CONFIG_SHELL='$SHELL' export CONFIG_SHELL exec "\$@" fi _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 exec 5>>config.log { echo sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX ## Running $as_me. ## _ASBOX $as_echo "$ac_log" } >&5 _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # # INIT-COMMANDS # AMDEP_TRUE="$AMDEP_TRUE" MAKE="${MAKE-make}" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Handling of arguments. for ac_config_target in $ac_config_targets do case $ac_config_target in "depfiles") CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;; "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; "src/Makefile") CONFIG_FILES="$CONFIG_FILES src/Makefile" ;; "data/Makefile") CONFIG_FILES="$CONFIG_FILES data/Makefile" ;; *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; esac done # If the user did not use the arguments to specify the items to instantiate, # then the envvar interface is used. Set only those that are not. # We use the long form for the default assignment because of an extremely # bizarre bug on SunOS 4.1.3. if $ac_need_defaults; then test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands fi # Have a temporary directory for convenience. Make it in the build tree # simply because there is no reason against having it here, and in addition, # creating and moving files from /tmp can sometimes cause problems. # Hook for its removal unless debugging. # Note that there is a small window in which the directory will not be cleaned: # after its creation but before its name has been assigned to `$tmp'. $debug || { tmp= ac_tmp= trap 'exit_status=$? : "${ac_tmp:=$tmp}" { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status ' 0 trap 'as_fn_exit 1' 1 2 13 15 } # Create a (secure) tmp directory for tmp files. { tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && test -d "$tmp" } || { tmp=./conf$$-$RANDOM (umask 077 && mkdir "$tmp") } || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 ac_tmp=$tmp # Set up the scripts for CONFIG_FILES section. # No need to generate them if there are no CONFIG_FILES. # This happens for instance with `./config.status config.h'. if test -n "$CONFIG_FILES"; then ac_cr=`echo X | tr X '\015'` # On cygwin, bash can eat \r inside `` if the user requested igncr. # But we know of no other shell where ac_cr would be empty at this # point, so we can use a bashism as a fallback. if test "x$ac_cr" = x; then eval ac_cr=\$\'\\r\' fi ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then ac_cs_awk_cr='\\r' else ac_cs_awk_cr=$ac_cr fi echo 'BEGIN {' >"$ac_tmp/subs1.awk" && _ACEOF { echo "cat >conf$$subs.awk <<_ACEOF" && echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && echo "_ACEOF" } >conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` ac_delim='%!_!# ' for ac_last_try in false false false false false :; do . ./conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` if test $ac_delim_n = $ac_delim_num; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done rm -f conf$$subs.sh cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && _ACEOF sed -n ' h s/^/S["/; s/!.*/"]=/ p g s/^[^!]*!// :repl t repl s/'"$ac_delim"'$// t delim :nl h s/\(.\{148\}\)..*/\1/ t more1 s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ p n b repl :more1 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t nl :delim h s/\(.\{148\}\)..*/\1/ t more2 s/["\\]/\\&/g; s/^/"/; s/$/"/ p b :more2 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t delim ' >$CONFIG_STATUS || ac_write_fail=1 rm -f conf$$subs.awk cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACAWK cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && for (key in S) S_is_set[key] = 1 FS = "" } { line = $ 0 nfields = split(line, field, "@") substed = 0 len = length(field[1]) for (i = 2; i < nfields; i++) { key = field[i] keylen = length(key) if (S_is_set[key]) { value = S[key] line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) len += length(value) + length(field[++i]) substed = 1 } else len += 1 + keylen } print line } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" else cat fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 _ACEOF # VPATH may cause trouble with some makes, so we remove sole $(srcdir), # ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and # trailing colons and then remove the whole line if VPATH becomes empty # (actually we leave an empty line to preserve line numbers). if test "x$srcdir" = x.; then ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ h s/// s/^/:/ s/[ ]*$/:/ s/:\$(srcdir):/:/g s/:\${srcdir}:/:/g s/:@srcdir@:/:/g s/^:*// s/:*$// x s/\(=[ ]*\).*/\1/ G s/\n// s/^[^=]*=[ ]*$// }' fi cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 fi # test -n "$CONFIG_FILES" eval set X " :F $CONFIG_FILES :C $CONFIG_COMMANDS" shift for ac_tag do case $ac_tag in :[FHLC]) ac_mode=$ac_tag; continue;; esac case $ac_mode$ac_tag in :[FHL]*:*);; :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; :[FH]-) ac_tag=-:-;; :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; esac ac_save_IFS=$IFS IFS=: set x $ac_tag IFS=$ac_save_IFS shift ac_file=$1 shift case $ac_mode in :L) ac_source=$1;; :[FH]) ac_file_inputs= for ac_f do case $ac_f in -) ac_f="$ac_tmp/stdin";; *) # Look for the file first in the build tree, then in the source tree # (if the path is not absolute). The absolute path cannot be DOS-style, # because $ac_f cannot contain `:'. test -f "$ac_f" || case $ac_f in [\\/$]*) false;; *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; esac || as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; esac case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac as_fn_append ac_file_inputs " '$ac_f'" done # Let's still pretend it is `configure' which instantiates (i.e., don't # use $as_me), people would be surprised to read: # /* config.h. Generated by config.status. */ configure_input='Generated from '` $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' `' by configure.' if test x"$ac_file" != x-; then configure_input="$ac_file. $configure_input" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 $as_echo "$as_me: creating $ac_file" >&6;} fi # Neutralize special characters interpreted by sed in replacement strings. case $configure_input in #( *\&* | *\|* | *\\* ) ac_sed_conf_input=`$as_echo "$configure_input" | sed 's/[\\\\&|]/\\\\&/g'`;; #( *) ac_sed_conf_input=$configure_input;; esac case $ac_tag in *:-:* | *:-) cat >"$ac_tmp/stdin" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; esac ;; esac ac_dir=`$as_dirname -- "$ac_file" || $as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$ac_file" : 'X\(//\)[^/]' \| \ X"$ac_file" : 'X\(//\)$' \| \ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$ac_file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` as_dir="$ac_dir"; as_fn_mkdir_p ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix case $ac_mode in :F) # # CONFIG_FILE # case $INSTALL in [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; esac ac_MKDIR_P=$MKDIR_P case $MKDIR_P in [\\/$]* | ?:[\\/]* ) ;; */*) ac_MKDIR_P=$ac_top_build_prefix$MKDIR_P ;; esac _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # If the template does not know about datarootdir, expand it. # FIXME: This hack should be removed a few years after 2.60. ac_datarootdir_hack=; ac_datarootdir_seen= ac_sed_dataroot=' /datarootdir/ { p q } /@datadir@/p /@docdir@/p /@infodir@/p /@localedir@/p /@mandir@/p' case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in *datarootdir*) ac_datarootdir_seen=yes;; *@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 $as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_datarootdir_hack=' s&@datadir@&$datadir&g s&@docdir@&$docdir&g s&@infodir@&$infodir&g s&@localedir@&$localedir&g s&@mandir@&$mandir&g s&\\\${datarootdir}&$datarootdir&g' ;; esac _ACEOF # Neutralize VPATH when `$srcdir' = `.'. # Shell code in configure.ac might set extrasub. # FIXME: do we really want to maintain this feature? cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_sed_extra="$ac_vpsub $extrasub _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 :t /@[a-zA-Z_][a-zA-Z_0-9]*@/!b s|@configure_input@|$ac_sed_conf_input|;t t s&@top_builddir@&$ac_top_builddir_sub&;t t s&@top_build_prefix@&$ac_top_build_prefix&;t t s&@srcdir@&$ac_srcdir&;t t s&@abs_srcdir@&$ac_abs_srcdir&;t t s&@top_srcdir@&$ac_top_srcdir&;t t s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t s&@builddir@&$ac_builddir&;t t s&@abs_builddir@&$ac_abs_builddir&;t t s&@abs_top_builddir@&$ac_abs_top_builddir&;t t s&@INSTALL@&$ac_INSTALL&;t t s&@MKDIR_P@&$ac_MKDIR_P&;t t $ac_datarootdir_hack " eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ "$ac_tmp/out"`; test -z "$ac_out"; } && { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&5 $as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&2;} rm -f "$ac_tmp/stdin" case $ac_file in -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; esac \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; :C) { $as_echo "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5 $as_echo "$as_me: executing $ac_file commands" >&6;} ;; esac case $ac_file$ac_mode in "depfiles":C) test x"$AMDEP_TRUE" != x"" || { # Older Autoconf quotes --file arguments for eval, but not when files # are listed without --file. Let's play safe and only enable the eval # if we detect the quoting. # TODO: see whether this extra hack can be removed once we start # requiring Autoconf 2.70 or later. case $CONFIG_FILES in #( *\'*) : eval set x "$CONFIG_FILES" ;; #( *) : set x $CONFIG_FILES ;; #( *) : ;; esac shift # Used to flag and report bootstrapping failures. am_rc=0 for am_mf do # Strip MF so we end up with the name of the file. am_mf=`$as_echo "$am_mf" | sed -e 's/:.*$//'` # Check whether this is an Automake generated Makefile which includes # dependency-tracking related rules and includes. # Grep'ing the whole file directly is not great: AIX grep has a line # limit of 2048, but all sed's we know have understand at least 4000. sed -n 's,^am--depfiles:.*,X,p' "$am_mf" | grep X >/dev/null 2>&1 \ || continue am_dirpart=`$as_dirname -- "$am_mf" || $as_expr X"$am_mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$am_mf" : 'X\(//\)[^/]' \| \ X"$am_mf" : 'X\(//\)$' \| \ X"$am_mf" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$am_mf" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` am_filepart=`$as_basename -- "$am_mf" || $as_expr X/"$am_mf" : '.*/\([^/][^/]*\)/*$' \| \ X"$am_mf" : 'X\(//\)$' \| \ X"$am_mf" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$am_mf" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` { echo "$as_me:$LINENO: cd "$am_dirpart" \ && sed -e '/# am--include-marker/d' "$am_filepart" \ | $MAKE -f - am--depfiles" >&5 (cd "$am_dirpart" \ && sed -e '/# am--include-marker/d' "$am_filepart" \ | $MAKE -f - am--depfiles) >&5 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } || am_rc=$? done if test $am_rc -ne 0; then { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "Something went wrong bootstrapping makefile fragments for automatic dependency tracking. Try re-running configure with the '--disable-dependency-tracking' option to at least be able to build the package (albeit without support for automatic dependency tracking). See \`config.log' for more details" "$LINENO" 5; } fi { am_dirpart=; unset am_dirpart;} { am_filepart=; unset am_filepart;} { am_mf=; unset am_mf;} { am_rc=; unset am_rc;} rm -f conftest-deps.mk } ;; esac done # for ac_tag as_fn_exit 0 _ACEOF ac_clean_files=$ac_clean_files_save test $ac_write_fail = 0 || as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 # configure is writing to config.log, and then calls config.status. # config.status does its own redirection, appending to config.log. # Unfortunately, on DOS this fails, as config.log is still kept open # by configure, so config.status won't be able to write to it; its # output is simply discarded. So we exec the FD to /dev/null, # effectively closing config.log, so it can be properly (re)opened and # appended to by config.status. When coming back to configure, we # need to make the FD available again. if test "$no_create" != yes; then ac_cs_success=: ac_config_status_args= test "$silent" = yes && ac_config_status_args="$ac_config_status_args --quiet" exec 5>/dev/null $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false exec 5>>config.log # Use ||, not &&, to avoid exiting from the if with $? = 1, which # would make configure fail if this is the last instruction. $ac_cs_success || as_fn_exit 1 fi if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} fi freewheeling-0.6.6/configure.ac000066400000000000000000000115431370736313100164650ustar00rootroot00000000000000# -*- Autoconf -*- # Process this file with autoconf to produce a configure script. AC_PREREQ([2.69]) AC_INIT([fweelin],[0.6.6],[https://github.com/free-wheeling/freewheeling/issues]) AM_INIT_AUTOMAKE([subdir-objects]) AC_CONFIG_SRCDIR([src/fweelin.cc]) #AM_CONFIG_HEADER(config.h) AC_ARG_ENABLE(fluidsynth,[ --enable-fluidsynth use integrated FluidSynth softsynth (libfluidsynth) (default=auto) ]) AC_ARG_ENABLE(video,[ --disable-video disable video output ]) AC_ARG_ENABLE(lcd,[ --enable-lcd enable USB LCD display output ]) # Checks for programs. AC_PROG_CXX AC_PROG_CC # Add Xtra Paths for Checking AC_PATH_XTRA #if test x"$no_x" = xyes; then # AC_ERROR([Can not find X11 development headers or libraries.]) #fi # Checks for libraries. #AC_CHECK_LIB([X11], [XOpenDisplay], , [AC_MSG_ERROR(VIDEO: You need libx11-dev installed)]) AC_CHECK_LIB([nettle], [main], , [AC_MSG_ERROR(You need nettle-dev installed)]) AC_CHECK_LIB([dl], [main], , [AC_MSG_ERROR(You need libc6-dev installed)]) AC_CHECK_LIB([freetype], [FT_Init_FreeType], , [AC_MSG_ERROR(VIDEO: You need libfreetype6-dev installed. http://freetype.sourceforge.net/index2.html)]) # Check for SDL_gfx with different function names.. AC_CHECK_LIB([SDL_gfx], [main], , [AC_MSG_ERROR(VIDEO: You need libsdl-gfx1.2-dev installed. http://www.ferzkopp.net/wordpress/2016/01/02/sdl_gfx-sdl2_gfx/)]) AC_CHECK_FUNC(filledPieRGBA, [AC_DEFINE(CAPITAL_FILLED_PIE)]) AC_CHECK_LIB([SDL_ttf], [main], , [AC_MSG_ERROR(VIDEO: You need libsdl-ttf2.0-dev installed. http://www.libsdl.org/projects/SDL_ttf/release-1.2.html)]) PKG_CHECK_MODULES([SDL], [sdl >= 1.2 sdl < 1.3], , [AC_MSG_ERROR(VIDEO: You need libsdl1.2-dev installed. http://www.libsdl.org/)]) AC_CHECK_LIB([lo], [main], , [AC_MSG_ERROR(CONFIG: You need liblo-dev installed. http://http://liblo.sourceforge.net/)]) AC_CHECK_LIB([xml2], [main], , [AC_MSG_ERROR(CONFIG: You need libxml2-dev installed. http://www.xmlsoft.org/)]) AC_CHECK_LIB([m], [sqrt], , [AC_MSG_ERROR(CORE: You need libm installed)]) AC_CHECK_LIB([pthread], [pthread_self], , [AC_MSG_ERROR(CORE: You need libpthread installed)]) AC_CHECK_LIB([asound], [main], , [AC_MSG_ERROR(AUDIO: You need ALSA installed (libasound2-dev). http://www.alsa-project.org/)]) AC_CHECK_LIB([jack], [jack_client_open], , [AC_MSG_ERROR(AUDIO: You need JACK audio library (libjack-dev) installed. http://jackit.sourceforge.net/)]) if test "$enable_fluidsynth" != "no"; then AC_CHECK_LIB([fluidsynth], [main], fluidsynth=yes, fluidsynth=no) if test "$fluidsynth" = "yes"; then LIBS="$LIBS -lfluidsynth" AC_DEFINE(USE_FLUIDSYNTH, 1, [Define if FluidSynth support should be enabled]) echo "--- Enabling integrated FluidSynth synth ---"; else echo "--- No libfluidsynth -- FluidSynth support will not be built! ---"; fi else echo "--- Disabling integrated FluidSynth synth ---"; fi if test "$enable_video" == "no"; then AC_DEFINE(NO_VIDEO, 1, [Define if video output is disabled]) echo "--- Disabling video output --"; fi if test "$enable_lcd" == "yes"; then AC_DEFINE(LCD_DISPLAY, 1, [Define if USB LCD display is enabled]) echo "--- Enabling USB LCD display --"; fi #SDL_VERSION=1.2.4 #AM_PATH_SDL($SDL_VERSION, # :, # AC_MSG_ERROR([VIDEO: *** SDL version $SDL_VERSION not found! # http://www.libsdl.org/]) #) AC_CHECK_LIB([vorbis], [main], , [AC_MSG_ERROR(AUDIO: You need libvorbis-dev installed. http://www.xiph.org/ogg/vorbis/)]) AC_CHECK_LIB([vorbisfile], [main], , [AC_MSG_ERROR(AUDIO: You need libvorbisfile installed. http://www.xiph.org/ogg/vorbis/)]) AC_CHECK_LIB([vorbisenc], [main], , [AC_MSG_ERROR(AUDIO: You need libvorbis-dev installed. http://www.xiph.org/ogg/vorbis/)]) AC_CHECK_LIB([ogg], [main], , [AC_MSG_ERROR(AUDIO: You need libogg-dev installed. http://www.xiph.org/ogg/vorbis/)]) AC_CHECK_LIB([sndfile], [main], , [AC_MSG_ERROR(AUDIO: you need libsndfile-dev installed. http://www.http://www.mega-nerd.com/libsndfile/)]) CFLAGS="$CFLAGS $SDL_CFLAGS" LIBS="$X_LIBS $X_PRE_LIBS -L/usr/X11R6/lib -lX11 $X_EXTRA_LIBS $LIBS" LIBS="$LIBS $SDL_LIBS" # Checks for header files. AC_PATH_X AC_HEADER_STDC AC_CHECK_HEADERS([errno.h fcntl.h inttypes.h limits.h stdint.h stdlib.h string.h sys/resource.h sys/time.h termios.h unistd.h utime.h]) # Checks for typedefs, structures, and compiler characteristics. AC_C_CONST AC_HEADER_TIME AC_C_INLINE AC_TYPE_INT32_T AC_TYPE_PID_T AC_TYPE_SIZE_T AC_CHECK_HEADER_STDBOOL AC_TYPE_UINT32_T AC_TYPE_UINT8_T # Checks for library functions. AC_FUNC_ALLOCA AC_FUNC_ERROR_AT_LINE AC_FUNC_FORK AC_FUNC_MALLOC AC_FUNC_STRTOD AC_CHECK_FUNCS([atexit dup2 floor gettimeofday memset pow realpath select sqrt strcasecmp strchr strncasecmp strrchr strtol]) AC_OUTPUT(Makefile src/Makefile data/Makefile) freewheeling-0.6.6/data/000077500000000000000000000000001370736313100151045ustar00rootroot00000000000000freewheeling-0.6.6/data/Makefile.am000066400000000000000000000010041370736313100171330ustar00rootroot00000000000000fweelin_dirname=fweelin fonts_path=fonts/truetype/ttf-bitstream-vera fweelindir = $(datadir)/$(fweelin_dirname) fontsdir = ${datadir}/$(fweelin_dirname)/${fonts_path} fweelin_DATA = *.txt *.xml *.mid basic.sf2 gdb-stackdump-cmds fonts_DATA = fonts/truetype/ttf-bitstream-vera/* install-data-hook: sed -i "s///" $(DESTDIR)$(fweelindir)/fweelin.xml uninstall-hook: -cd ${fweelindir} && rmdir -p ${fonts_path} -rmdir $(fweelindir) freewheeling-0.6.6/data/Makefile.in000066400000000000000000000355651370736313100171670ustar00rootroot00000000000000# Makefile.in generated by automake 1.16.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2018 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : subdir = data ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__installdirs = "$(DESTDIR)$(fontsdir)" "$(DESTDIR)$(fweelindir)" DATA = $(fonts_DATA) $(fweelin_DATA) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) am__DIST_COMMON = $(srcdir)/Makefile.in DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ ALLOCA = @ALLOCA@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CXX = @CXX@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ GREP = @GREP@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ OBJEXT = @OBJEXT@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ POW_LIB = @POW_LIB@ SDL_CFLAGS = @SDL_CFLAGS@ SDL_LIBS = @SDL_LIBS@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ XMKMF = @XMKMF@ X_CFLAGS = @X_CFLAGS@ X_EXTRA_LIBS = @X_EXTRA_LIBS@ X_LIBS = @X_LIBS@ X_PRE_LIBS = @X_PRE_LIBS@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build_alias = @build_alias@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host_alias = @host_alias@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ fweelin_dirname = fweelin fonts_path = fonts/truetype/ttf-bitstream-vera fweelindir = $(datadir)/$(fweelin_dirname) fontsdir = ${datadir}/$(fweelin_dirname)/${fonts_path} fweelin_DATA = *.txt *.xml *.mid basic.sf2 gdb-stackdump-cmds fonts_DATA = fonts/truetype/ttf-bitstream-vera/* all: all-am .SUFFIXES: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu data/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu data/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-fontsDATA: $(fonts_DATA) @$(NORMAL_INSTALL) @list='$(fonts_DATA)'; test -n "$(fontsdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(fontsdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(fontsdir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(fontsdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(fontsdir)" || exit $$?; \ done uninstall-fontsDATA: @$(NORMAL_UNINSTALL) @list='$(fonts_DATA)'; test -n "$(fontsdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(fontsdir)'; $(am__uninstall_files_from_dir) install-fweelinDATA: $(fweelin_DATA) @$(NORMAL_INSTALL) @list='$(fweelin_DATA)'; test -n "$(fweelindir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(fweelindir)'"; \ $(MKDIR_P) "$(DESTDIR)$(fweelindir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(fweelindir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(fweelindir)" || exit $$?; \ done uninstall-fweelinDATA: @$(NORMAL_UNINSTALL) @list='$(fweelin_DATA)'; test -n "$(fweelindir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(fweelindir)'; $(am__uninstall_files_from_dir) tags TAGS: ctags CTAGS: cscope cscopelist: distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(DATA) installdirs: for dir in "$(DESTDIR)$(fontsdir)" "$(DESTDIR)$(fweelindir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-generic dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-fontsDATA install-fweelinDATA @$(NORMAL_INSTALL) $(MAKE) $(AM_MAKEFLAGS) install-data-hook install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-fontsDATA uninstall-fweelinDATA @$(NORMAL_INSTALL) $(MAKE) $(AM_MAKEFLAGS) uninstall-hook .MAKE: install-am install-data-am install-strip uninstall-am .PHONY: all all-am check check-am clean clean-generic cscopelist-am \ ctags-am distclean distclean-generic distdir dvi dvi-am html \ html-am info info-am install install-am install-data \ install-data-am install-data-hook install-dvi install-dvi-am \ install-exec install-exec-am install-fontsDATA \ install-fweelinDATA install-html install-html-am install-info \ install-info-am install-man install-pdf install-pdf-am \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-generic pdf \ pdf-am ps ps-am tags-am uninstall uninstall-am \ uninstall-fontsDATA uninstall-fweelinDATA uninstall-hook .PRECIOUS: Makefile install-data-hook: sed -i "s///" $(DESTDIR)$(fweelindir)/fweelin.xml uninstall-hook: -cd ${fweelindir} && rmdir -p ${fonts_path} -rmdir $(fweelindir) # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: freewheeling-0.6.6/data/basic.sf2000066400000000000000000000067701370736313100166130ustar00rootroot00000000000000RIFFð sfbkLIST†INFOifilisngEMU8000INAMexampleICRDIENGIPRDICOPICMTISFTSWAMI v0.9.1a:SWAMI v0.9.1aLISTh sdtasmpl\ ço)p6ÆB·7N1t+J&è!^ºý4ZcJúa"i&ø*í/,5Ž:@aEŒJdOÓS¹W[­]_Ï`;aå`Ë_þ]„[sXÚTÐPqLÖGC]>³9B51c-#*r'Z%ð#6#/#Ü#4%.'¹)É,C0480DïG@KN9P±QbR3RQOùKòGõB=O6À.…&¼|ñ 7ƒ÷ïí­äèÛ»ÓUÌÒÅ[À¼â¸ ·Š¶e·›¹/½Â,ÈrÏÂ×áë¼õäS ív#Å.«9ùC™MZV^»d/j`n?qÃrôrÐqfoÃkg2axZ÷RÏJ(B+9þ/Ô&Åý¡ Ï®ýM÷Çñ(ízéÉæåXäŒäžå…ç'êmí5ñiõæùþGèV r%]þýOéÊíd4eD ±}ýèøôeð¤ìZ锿qäøâ/â#âÊâ+ä;ææè)ìéïô‡ø'ýÜ‚ü *å ¯…ˆ¢Ò>Ì 0¹…ú¨òEêyácØ0ÏÆ½v´X¬ç¤Bž‹˜ß“X ŽNõŽõ‘A–Ì›Œ¢^ª4³ã¼HÇ9Ò‡Ýé­ô9 ×Õ)<1j8h>.C£F¾HzIØHäF©C3?¢93˜+]#…=©ìý8ô²ê{á¸ØŽÐÉe“¼§·º³Ã°È®Å­§­e®ñ¯3² µb¸¼À.ÄKÈJÌÐÓ…ÖÙóÚ;ÜÖÜÂÜôÛ{Ú[ØšÕNÒ„ÎYÊåÅ8Áx¼¼·&³Ó®Ïª?§8¤Ï¡  ŸÆžAŸ„ ƒ¢7¥˜¨¬±çµ»rÀæÅLˇÐpÕöÙñÝIáæã·å°æÀæàåäXá¶Ý>ÙÔ#ΰÇÅÀй%²´ªr£tœë•úÉŠ‚†/ƒ€_€‚ …r‰4>–—ž¨·²E¾¦Ê·×;å*ó>L( *š7ÚC7O£Yðbkêqkw“{Q~¾Ô¤~A|ÉxQtþnéhJbB[ïSL!Eô=7º0ó*Þ%!†ä,h‡~B»"Ò&i+_0¤5;„@ÝEKÏO/T XM[ä]Á_â`;aÒ`ª_Ë]D[#XTrP LjGªBì=O9à4Å0-Û)9'3%Ù#.#9#õ#Z%d'ü)-–0k4u8“<¨@–D?HƒKFNdPÎQfR%RôPÈN¦KŠGxB|<¡5.Á%ê¤ Sêv6FN/bgqM{¾Ú~2yŒoüb¢TÔE¾7y+ì!½7fýn&ó/•:jEnOÃW¸]Û`ð` ^~XÚPÞGd>H5h-v'ô#4#9%½)I08S@÷GN»Q=ROûG=Æ.¿ò ‚÷©äµÓËÅû»·]·'½%Ƚ×ëäðË.DdVÇdmnÑrÞqÐk=aS0B0É¢ ­ýÅñxéåˆä‚çkíhõþèt`íð7 çøcðWénä,âÇâ8æ&ìô'ýƒ+#ˆ¦‚1…úBê^ØÿÅl´Ü¤~˜JòŒèŽ4–¢+³Bǃݬô: ÙB1o>«F‚IíF;?3a#?ìý°ê³ØÉ‹¼°³¾®ž­è¯µ ¼'ÄDÌzÓÙ7ܽÜvÚ•Õ~ÎÞÅp¼³Åª-¤ ºžy ,¥„¬ÞµkÀFËkÕíÝâã­æÝåUá:ÙξÀ²g£Þ•»Š ƒ€÷d‰1– ¨=¾²×)óN¥*âC®Y kzw`~ãP|_töhM[ŠLû=À0â%çkÀ"n+«5Œ@ K9TX[Í_Gaµ_O[‰TL²BU9Ë0à)7%2#ù#h'-q4š<¤DŒKmPoRþP¯K€B¨5Æ%§SíÛ°Ëá¿¡¸…¶Ü¹ˆÂ%Ðãá·öh ƒ$¨:yNÉ^®j{qõr,ofÝYJa8&8#Äö‚6Dbh{ö~¥oµTÊ7ó!=ý/yEÖWð`^ëPr>r-ü#A%T0a@"NOR HÐ.ô £ä¾Åò¶½´×åÕ.wV†n÷qSa>BÏ­ýsé‚ägíþx÷_ðhäÀâ"ì&ý/Ž 2=êòÅȤ2ÏŽl¢5Ç©ôà}>’II?i#ìýªØ|¼¬®Ö¯þ»8Ìúض܌ÕÑÅ ³¤¥ž¥Îµ:ËæÝ¨æNáÎ ²Ç•ƒÛ–.¾&ó¯*ÁY”wÿyta[ >ê%í‡x+š@LTâ_Ê_œTÁBÖ0?%$%-¨ freewheeling-0.6.6/data/bcf2000-help.txt000066400000000000000000000032651370736313100176350ustar00rootroot00000000000000Mr Thraz & Folks, I've been remiss about not yet distributing my BCF-2000 setup for Freewheeling. But I'd like to give you guys somewhere to start configuring. So I've attached my current BCF-2000 preset for Freewheeling. Send it to your BCF-2000 with 'aplaymidi' or similar. Instructions for Use: Top row of 8 buttons: capture/play loops Bottom row of 8 buttons: 1- Shift (hold) Hold shift & press top 8 buttons to erase loops 2- Undo (erase last loop) 1 (Hold) + 2- Erase all loops 3- Previous page of 8 loops (or snapshots in snap mode) 4- Next page of 8 loops (or snapshots in snap mode) 5- Deselect all looops 6- Select playing loops 7- Toggle selected loops 8- Create pulse (press this after recording your first loop to lock other loops to it) Faders: 1-4 are input levels 5 is master input level 6 is master output level 7 is feedback 8 is a quick patch change slider (patches are not actually changed until you press a button- see below) Group 1 Knobs: Press 1-8 to toggle overdub for loops, Turn 1-8 to adjust loop levels Group 2 Knobs: Press 1-8 to select loops, Turn to adjust relative level of ALL selected loops Group 3 Knobs: Turn & Press Knob 8 to browse through and load scenes. Press Knob 7 to save a scene of all loops. 4 Buttons on bottom right of BCF: Top Left: Fader mode- switches BCF faders to toggle loop levels Top Right: Unused Bottom Left: Patch Change button (activate the MIDI patch you've browsed to). Bottom Right: Toggle Snap mode (In snap mode: Shows snapshots. Select snapshots with loop buttons 1-8 (top row of 8 buttons). Page through snapshots with buttons 3 and 4 on the bottom row of 8 buttons.) That's all for now. I hope this helps. -Mercury freewheeling-0.6.6/data/bcf2000-preset.mid000066400000000000000000000335051370736313100201410ustar00rootroot00000000000000MThd€MTrk7/ÿQ¡ ÿXWð 2 $rev F1÷ð 2 $preset÷ð+ 2  .name 'all controls '÷ð 2  .snapshot off÷ð 2  .request off÷ð 2  .egroups 4÷ð 2  .fkeys on÷ð 2  .lock off÷ð 2  .init÷ð 2 $encoder 1÷ð- 2 .easypar CC 16 90 0 127 relative-1÷ð 2 .showvalue on÷ð 2 .mode 12dot÷ð" 2 .resolution 96 96 96 96÷ð 2  .default 46÷ð 2 $encoder 2÷ð- 2  .easypar CC 16 91 0 127 relative-1÷ð 2  .showvalue on÷ð 2  .mode 12dot÷ð" 2  .resolution 96 96 96 96÷ð 2  .default 106÷ð 2 $encoder 3÷ð- 2  .easypar CC 16 92 0 127 relative-1÷ð 2  .showvalue on÷ð 2  .mode 12dot÷ð" 2  .resolution 96 96 96 96÷ð 2  .default 113÷ð 2 $encoder 4÷ð- 2  .easypar CC 16 93 0 127 relative-1÷ð 2  .showvalue on÷ð 2  .mode 12dot÷ð" 2  .resolution 96 96 96 96÷ð 2 .default 1÷ð 2 !$encoder 5÷ð- 2 " .easypar CC 16 94 0 127 relative-1÷ð 2 # .showvalue on÷ð 2 $ .mode 12dot÷ð" 2 % .resolution 96 96 96 96÷ð 2 & .default 83÷ð 2 '$encoder 6÷ð- 2 ( .easypar CC 16 95 0 127 relative-1÷ð 2 ) .showvalue on÷ð 2 * .mode 12dot÷ð" 2 + .resolution 96 96 96 96÷ð 2 , .default 30÷ð 2 -$encoder 7÷ð- 2 . .easypar CC 16 96 0 127 relative-1÷ð 2 / .showvalue on÷ð 2 0 .mode 12dot÷ð" 2 1 .resolution 96 96 96 96÷ð 2 2 .default 0÷ð 2 3$encoder 8÷ð- 2 4 .easypar CC 16 97 0 127 relative-1÷ð 2 5 .showvalue on÷ð 2 6 .mode 12dot÷ð" 2 7 .resolution 96 96 96 96÷ð 2 8 .default 79÷ð 2 9$encoder 9÷ð- 2 : .easypar CC 16 50 0 127 relative-1÷ð 2 ; .showvalue on÷ð 2 < .mode 12dot÷ð" 2 = .resolution 96 96 96 96÷ð 2 > .default 97÷ð 2 ?$encoder 10÷ð- 2 @ .easypar CC 16 51 0 127 relative-1÷ð 2 A .showvalue on÷ð 2 B .mode 12dot÷ð" 2 C .resolution 96 96 96 96÷ð 2 D .default 123÷ð 2 E$encoder 11÷ð- 2 F .easypar CC 16 52 0 127 relative-1÷ð 2 G .showvalue on÷ð 2 H .mode 12dot÷ð" 2 I .resolution 96 96 96 96÷ð 2 J .default 13÷ð 2 K$encoder 12÷ð- 2 L .easypar CC 16 53 0 127 relative-1÷ð 2 M .showvalue on÷ð 2 N .mode 12dot÷ð" 2 O .resolution 96 96 96 96÷ð 2 P .default 23÷ð 2 Q$encoder 13÷ð- 2 R .easypar CC 16 54 0 127 relative-1÷ð 2 S .showvalue on÷ð 2 T .mode 12dot÷ð" 2 U .resolution 96 96 96 96÷ð 2 V .default 38÷ð 2 W$encoder 14÷ð- 2 X .easypar CC 16 55 0 127 relative-1÷ð 2 Y .showvalue on÷ð 2 Z .mode 12dot÷ð" 2 [ .resolution 96 96 96 96÷ð 2 \ .default 45÷ð 2 ]$encoder 15÷ð- 2 ^ .easypar CC 16 56 0 127 relative-1÷ð 2 _ .showvalue on÷ð 2 ` .mode 12dot÷ð" 2 a .resolution 96 96 96 96÷ð 2 b .default 22÷ð 2 c$encoder 16÷ð- 2 d .easypar CC 16 57 0 127 relative-1÷ð 2 e .showvalue on÷ð 2 f .mode 12dot÷ð" 2 g .resolution 96 96 96 96÷ð 2 h .default 20÷ð 2 i$encoder 17÷ð* 2 j .easypar CC 1 17 0 127 absolute÷ð 2 k .showvalue on÷ð 2 l .mode 12dot÷ð" 2 m .resolution 96 96 96 96÷ð 2 n .default 0÷ð 2 o$encoder 18÷ð* 2 p .easypar CC 1 18 0 127 absolute÷ð 2 q .showvalue on÷ð 2 r .mode 12dot÷ð" 2 s .resolution 96 96 96 96÷ð 2 t .default 5÷ð 2 u$encoder 19÷ð* 2 v .easypar CC 1 19 0 127 absolute÷ð 2 w .showvalue on÷ð 2 x .mode 12dot÷ð" 2 y .resolution 96 96 96 96÷ð 2 z .default 4÷ð 2 {$encoder 20÷ð* 2 | .easypar CC 1 20 0 127 absolute÷ð 2 } .showvalue on÷ð 2 ~ .mode 12dot÷ð" 2  .resolution 96 96 96 96÷ð 2  .default 5÷ð 2 $encoder 21÷ð* 2  .easypar CC 1 21 0 127 absolute÷ð 2  .showvalue on÷ð 2  .mode 12dot÷ð" 2  .resolution 96 96 96 96÷ð 2  .default 4÷ð 2 $encoder 22÷ð* 2  .easypar CC 1 22 0 127 absolute÷ð 2  .showvalue on÷ð 2  .mode 12dot÷ð" 2  .resolution 96 96 96 96÷ð 2  .default 0÷ð 2  $encoder 23÷ð- 2  .easypar CC 16 74 0 127 relative-1÷ð 2  .showvalue on÷ð 2  .mode 12dot÷ð" 2  .resolution 96 96 96 96÷ð 2  .default 0÷ð 2 $encoder 24÷ð- 2  .easypar CC 16 75 0 127 relative-1÷ð 2  .showvalue on÷ð 2  .mode 12dot÷ð" 2  .resolution 96 96 96 96÷ð 2  .default 0÷ð 2 $encoder 25÷ð* 2  .easypar CC 1 25 0 127 absolute÷ð 2  .showvalue on÷ð 2  .mode 12dot÷ð" 2  .resolution 96 96 96 96÷ð 2  .default 5÷ð 2 $encoder 26÷ð* 2  .easypar CC 1 26 0 127 absolute÷ð 2 ! .showvalue on÷ð 2 " .mode 12dot÷ð" 2 # .resolution 96 96 96 96÷ð 2 $ .default 6÷ð 2 %$encoder 27÷ð* 2 & .easypar CC 1 27 0 127 absolute÷ð 2 ' .showvalue on÷ð 2 ( .mode 12dot÷ð" 2 ) .resolution 96 96 96 96÷ð 2 * .default 4÷ð 2 +$encoder 28÷ð* 2 , .easypar CC 1 28 0 127 absolute÷ð 2 - .showvalue on÷ð 2 . .mode 12dot÷ð" 2 / .resolution 96 96 96 96÷ð 2 0 .default 3÷ð 2 1$encoder 29÷ð* 2 2 .easypar CC 1 29 0 127 absolute÷ð 2 3 .showvalue on÷ð 2 4 .mode 12dot÷ð" 2 5 .resolution 96 96 96 96÷ð 2 6 .default 2÷ð 2 7$encoder 30÷ð* 2 8 .easypar CC 1 30 0 127 absolute÷ð 2 9 .showvalue on÷ð 2 : .mode 12dot÷ð" 2 ; .resolution 96 96 96 96÷ð 2 < .default 2÷ð 2 =$encoder 31÷ð* 2 > .easypar CC 1 31 0 127 absolute÷ð 2 ? .showvalue on÷ð 2 @ .mode 12dot÷ð" 2 A .resolution 96 96 96 96÷ð 2 B .default 4÷ð 2 C$encoder 32÷ð* 2 D .easypar CC 1 32 0 127 absolute÷ð 2 E .showvalue on÷ð 2 F .mode 12dot÷ð" 2 G .resolution 96 96 96 96÷ð 2 H .default 6÷ð 2 I$button 1÷ð- 2 J .easypar CC 16 100 127 0 toggleoff÷ð 2 K .showvalue off÷ð 2 L .default 0÷ð 2 M$button 2÷ð- 2 N .easypar CC 16 101 127 0 toggleoff÷ð 2 O .showvalue off÷ð 2 P .default 0÷ð 2 Q$button 3÷ð- 2 R .easypar CC 16 102 127 0 toggleoff÷ð 2 S .showvalue off÷ð 2 T .default 0÷ð 2 U$button 4÷ð- 2 V .easypar CC 16 103 127 0 toggleoff÷ð 2 W .showvalue off÷ð 2 X .default 0÷ð 2 Y$button 5÷ð- 2 Z .easypar CC 16 104 127 0 toggleoff÷ð 2 [ .showvalue off÷ð 2 \ .default 0÷ð 2 ]$button 6÷ð- 2 ^ .easypar CC 16 105 127 0 toggleoff÷ð 2 _ .showvalue off÷ð 2 ` .default 0÷ð 2 a$button 7÷ð- 2 b .easypar CC 16 106 127 0 toggleoff÷ð 2 c .showvalue off÷ð 2 d .default 0÷ð 2 e$button 8÷ð- 2 f .easypar CC 16 107 127 0 toggleoff÷ð 2 g .showvalue off÷ð 2 h .default 0÷ð 2 i$button 9÷ð, 2 j .easypar CC 16 40 127 0 toggleoff÷ð 2 k .showvalue off÷ð 2 l .default 0÷ð 2 m$button 10÷ð, 2 n .easypar CC 16 41 127 0 toggleoff÷ð 2 o .showvalue off÷ð 2 p .default 0÷ð 2 q$button 11÷ð, 2 r .easypar CC 16 42 127 0 toggleoff÷ð 2 s .showvalue off÷ð 2 t .default 0÷ð 2 u$button 12÷ð, 2 v .easypar CC 16 43 127 0 toggleoff÷ð 2 w .showvalue off÷ð 2 x .default 0÷ð 2 y$button 13÷ð, 2 z .easypar CC 16 44 127 0 toggleoff÷ð 2 { .showvalue off÷ð 2 | .default 0÷ð 2 }$button 14÷ð, 2 ~ .easypar CC 16 45 127 0 toggleoff÷ð 2  .showvalue off÷ð 2  .default 0÷ð 2 $button 15÷ð, 2  .easypar CC 16 46 127 0 toggleoff÷ð 2  .showvalue off÷ð 2  .default 0÷ð 2 $button 16÷ð, 2  .easypar CC 16 47 127 0 toggleoff÷ð 2  .showvalue off÷ð 2  .default 0÷ð 2  $button 17÷ð* 2  .easypar CC 1 49 127 0 toggleon÷ð 2  .showvalue on÷ð 2  .default 127÷ð 2  $button 18÷ð* 2  .easypar CC 1 50 127 0 toggleon÷ð 2  .showvalue on÷ð 2  .default 127÷ð 2 $button 19÷ð* 2  .easypar CC 1 51 127 0 toggleon÷ð 2  .showvalue on÷ð 2  .default 127÷ð 2 $button 20÷ð* 2  .easypar CC 1 52 127 0 toggleon÷ð 2  .showvalue on÷ð 2  .default 127÷ð 2 $button 21÷ð* 2  .easypar CC 1 53 127 0 toggleon÷ð 2  .showvalue on÷ð 2  .default 127÷ð 2 $button 22÷ð* 2  .easypar CC 1 54 127 0 toggleon÷ð 2  .showvalue on÷ð 2  .default 127÷ð 2 !$button 23÷ð, 2 " .easypar CC 16 77 127 0 toggleoff÷ð 2 # .showvalue off÷ð 2 $ .default 0÷ð 2 %$button 24÷ð, 2 & .easypar CC 16 76 127 0 toggleoff÷ð 2 ' .showvalue off÷ð 2 ( .default 0÷ð 2 )$button 25÷ð* 2 * .easypar CC 1 57 127 0 toggleon÷ð 2 + .showvalue on÷ð 2 , .default 127÷ð 2 -$button 26÷ð* 2 . .easypar CC 1 58 127 0 toggleon÷ð 2 / .showvalue on÷ð 2 0 .default 127÷ð 2 1$button 27÷ð* 2 2 .easypar CC 1 59 127 0 toggleon÷ð 2 3 .showvalue on÷ð 2 4 .default 127÷ð 2 5$button 28÷ð* 2 6 .easypar CC 1 60 127 0 toggleon÷ð 2 7 .showvalue on÷ð 2 8 .default 127÷ð 2 9$button 29÷ð* 2 : .easypar CC 1 61 127 0 toggleon÷ð 2 ; .showvalue on÷ð 2 < .default 127÷ð 2 =$button 30÷ð* 2 > .easypar CC 1 62 127 0 toggleon÷ð 2 ? .showvalue on÷ð 2 @ .default 127÷ð 2 A$button 31÷ð* 2 B .easypar CC 1 63 127 0 toggleon÷ð 2 C .showvalue on÷ð 2 D .default 127÷ð 2 E$button 32÷ð* 2 F .easypar CC 1 64 127 0 toggleon÷ð 2 G .showvalue on÷ð 2 H .default 127÷ð 2 I$button 33÷ð- 2 J .easypar CC 16 110 127 0 toggleoff÷ð 2 K .showvalue off÷ð 2 L .default 0÷ð 2 M$button 34÷ð- 2 N .easypar CC 16 111 127 0 toggleoff÷ð 2 O .showvalue off÷ð 2 P .default 0÷ð 2 Q$button 35÷ð- 2 R .easypar CC 16 112 127 0 toggleoff÷ð 2 S .showvalue off÷ð 2 T .default 0÷ð 2 U$button 36÷ð- 2 V .easypar CC 16 113 127 0 toggleoff÷ð 2 W .showvalue off÷ð 2 X .default 0÷ð 2 Y$button 37÷ð- 2 Z .easypar CC 16 114 127 0 toggleoff÷ð 2 [ .showvalue off÷ð 2 \ .default 0÷ð 2 ]$button 38÷ð- 2 ^ .easypar CC 16 115 127 0 toggleoff÷ð 2 _ .showvalue off÷ð 2 ` .default 0÷ð 2 a$button 39÷ð- 2 b .easypar CC 16 116 127 0 toggleoff÷ð 2 c .showvalue off÷ð 2 d .default 0÷ð 2 e$button 40÷ð- 2 f .easypar CC 16 117 127 0 toggleoff÷ð 2 g .showvalue off÷ð 2 h .default 0÷ð 2 i$button 41÷ð- 2 j .easypar CC 16 118 127 0 toggleoff÷ð 2 k .showvalue off÷ð 2 l .default 0÷ð 2 m$button 42÷ð- 2 n .easypar CC 16 119 127 0 toggleoff÷ð 2 o .showvalue off÷ð 2 p .default 0÷ð 2 q$button 43÷ð- 2 r .easypar CC 16 120 127 0 toggleoff÷ð 2 s .showvalue off÷ð 2 t .default 0÷ð 2 u$button 44÷ð- 2 v .easypar CC 16 121 127 0 toggleoff÷ð 2 w .showvalue off÷ð 2 x .default 0÷ð 2 y$button 45÷ð- 2 z .easypar CC 16 122 127 0 toggleoff÷ð 2 { .showvalue off÷ð 2 | .default 0÷ð 2 }$button 46÷ð- 2 ~ .easypar CC 16 123 127 0 toggleoff÷ð 2  .showvalue off÷ð 2  .default 0÷ð 2 $button 47÷ð- 2  .easypar CC 16 124 127 0 toggleoff÷ð 2  .showvalue off÷ð 2  .default 0÷ð 2 $button 48÷ð- 2  .easypar CC 16 125 127 0 toggleoff÷ð 2  .showvalue off÷ð 2  .default 0÷ð 2  $button 49÷ð, 2  .easypar CC 16 70 127 0 toggleoff÷ð 2  .showvalue off÷ð 2  .default 0÷ð 2  $button 50÷ð, 2  .easypar CC 16 71 127 0 toggleoff÷ð 2  .showvalue off÷ð 2  .default 0÷ð 2 $button 51÷ð, 2  .easypar CC 16 72 127 0 toggleoff÷ð 2  .showvalue off÷ð 2  .default 0÷ð 2 $button 52÷ð+ 2  .easypar CC 16 73 127 0 toggleon÷ð 2  .showvalue off÷ð 2  .default 0÷ð 2 $button 61÷ð+ 2  .easypar CC 1 67 127 0 toggleoff÷ð 2  .showvalue off÷ð 2  .default 0÷ð 2 $fader 1÷ð+ 2  .easypar CC 16 80 0 127 absolute÷ð 2  .showvalue on÷ð 2  .motor on÷ð 2 ! .override move÷ð 2 " .keyoverride off÷ð 2 # .default 111÷ð 2 $$fader 2÷ð+ 2 % .easypar CC 16 81 0 127 absolute÷ð 2 & .showvalue on÷ð 2 ' .motor on÷ð 2 ( .override move÷ð 2 ) .keyoverride off÷ð 2 * .default 111÷ð 2 +$fader 3÷ð+ 2 , .easypar CC 16 82 0 127 absolute÷ð 2 - .showvalue on÷ð 2 . .motor on÷ð 2 / .override move÷ð 2 0 .keyoverride off÷ð 2 1 .default 111÷ð 2 2$fader 4÷ð+ 2 3 .easypar CC 16 83 0 127 absolute÷ð 2 4 .showvalue on÷ð 2 5 .motor on÷ð 2 6 .override move÷ð 2 7 .keyoverride off÷ð 2 8 .default 111÷ð 2 9$fader 5÷ð+ 2 : .easypar CC 16 84 0 127 absolute÷ð 2 ; .showvalue on÷ð 2 < .motor on÷ð 2 = .override move÷ð 2 > .keyoverride off÷ð 2 ? .default 111÷ð 2 @$fader 6÷ð+ 2 A .easypar CC 16 85 0 127 absolute÷ð 2 B .showvalue on÷ð 2 C .motor on÷ð 2 D .override move÷ð 2 E .keyoverride off÷ð 2 F .default 111÷ð 2 G$fader 7÷ð+ 2 H .easypar CC 16 86 0 127 absolute÷ð 2 I .showvalue on÷ð 2 J .motor on÷ð 2 K .override move÷ð 2 L .keyoverride off÷ð 2 M .default 108÷ð 2 N$fader 8÷ð+ 2 O .easypar CC 16 87 0 127 absolute÷ð 2 P .showvalue on÷ð 2 Q .motor on÷ð 2 R .override move÷ð 2 S .keyoverride off÷ð 2 T .default 0÷ð 2 U$end÷—\ÿ/freewheeling-0.6.6/data/bcf2000-synthedit.xml000066400000000000000000000242051370736313100206760ustar00rootroot00000000000000 freewheeling-0.6.6/data/bcf2000.xml000066400000000000000000000761331370736313100166740ustar00rootroot00000000000000 freewheeling-0.6.6/data/browsers.xml000066400000000000000000000101301370736313100174670ustar00rootroot00000000000000 freewheeling-0.6.6/data/config-help.txt000066400000000000000000001101651370736313100200440ustar00rootroot00000000000000 The XML Configuration System **************************** FreeEheeling comfiguration is done through the .xml files in this directory. They are well documented within and you will want to read them to get the most out of FreeEheeling. These are the most important configuration files: * basics.xml - defines the main options for freewheeling * coreinterface.xml - defines the keyboard, mouse, MIDI, and internal event bindings * graphics.xml - defines options for the graphics system (window size, fonts, etc) * interfaces.xml - definees on-screen layouts corresponding to device interfaces Creating Bindings ***************** Each binding has two parts- 1) What input event and conditions trigger the binding? 2) What output event(s) are generated and what parameters are set for those events? For example- binding: input="key" conditions="key=escape and keydown=1" output="exit-freewheeling" Is triggered when the escape key is pressed. The key must match "escape" and keydown must match "1" (the key is pressed, not released). The event generated under these conditions is "exit-freewheeling". No parameters are set. Dynamic Parameters ****************** In the above table of input events, you can see that there are different input types that can trigger events. It's possible to use simple expressions in your bindings to dynamically check conditions and assign parameters. For example- This binding is for a MIDI keyboard with volume faders that transmit on different MIDI channels. Here, the volume faders are being used to fade loop levels: binding input="midicontroller" conditions="controlnum=7 and midichannel=0>15" output="set-loop-amplifier" parameters="loopid=midichannel+36 and amp=controlval/127*2" This binding is triggered when MIDI controller 7 (volume) changes are received on channels 0-15. Event "set-loop-amplifier" is generated (to change the volume of a given loop). The loop given is "midichannel+36". The volume to set the loop to is "controlval/127*2". So, a MIDI controller 7 input on channel 2 with controller value 127 will set loop #38 to volume 2.0 (200%). The example shows how input parameters, such as MIDI channel and controller value, can be referenced in your bindings along with simple algebra (+ - / *). Order of Operations ******************* When entering algebraic expressions, note that FreeWheeling does not evaluate with standard order of operations. The order of evaluation is always left to right. So: amp="3+3/6" will evaluate to 1 and not 3 and not 3.5. Algebra is evaluated conservatively with respect to type (I'm such a conservative!) That means that the expression: amp="1/2" will evaluate to 0 and not 0.5. For explicit floating point, use: amp="1.0/2" which evaluates to 0.5. Algebra on Ranges ***************** value="0>12 + 10" evaluates to "10>22". Both ends of the range are worked on. or value="0>5 + 1>5" evaluates to "1>10". Note that the types of each end of a range are always integers, so: value="0.5>1.5 + 0.5>1.5" evaluates to "0>2" User Variables ************** It is also possible to create your own user variables. These can then be referenced in your bindings, or changed during runtime, for a much more dynamic user interface. For example, the binding below will set trigger volume for loops across a range of notes. The binding checks to see that the MIDI note number matches the user variable "VAR_noterange". Since "VAR_noterange" is a range variable, this means that the binding will only trigger event "set-trigger-volume" if the note number is within the range specified by "VAR_noterange". binding input="midikey" conditions="VAR_cutmode=1 and notenum=VAR_noterange and keydown=1" output="set-trigger-volume" parameters="loopid=notenum and vol=velocity/127" **** Note that as of version 0.5pre3, FreeWheeling automatically indexes your bindings based on a hash key, so there is no need to specify wildcard cases (previously done with midikey="*"). **** Another example... The binding: binding input="midikey" conditions="VAR_xferloop=1 and notenum=VAR_noterange adn keydown=1" output="move-loop" parameters="oldloopid=VAR_xferidx and newloopid=notenum+VAR_loopid_pianostart" Checks these conditions: Input event is a MIDI Key Variable 'VAR_xferloop' equals 1? Input parameter notenum is within range of variable 'VAR_noterange' (When comparing against a range, a condition is true when the value is within the bounds of the range) Input parameter keydown equals 1 This binding is used to move a loop onto a piano key. Presumably, this is a special case where we have a loop in a holding place (such as a loop grabbed by a footswitch), and we want to move from that holding place onto the MIDI keyboard. Using a combination of user variables and careful configuration of bindings, a highly tailored user interface can be created. Order of Bindings ***************** The order in which we declare bindings in this file is important. Bindings are checked from top to bottom, so you will need to put special case bindings first. For example, if you want to modify the behavior of a binding when a certain variable is set or key is held, you will have to put the special case before the general case. The first matching binding is the only binding that is triggered. For an example, look under comment -Erase Loops-, and see that holding space while pressing a loop trigger key erases a loop, whereas if space is not held, it triggers the loop. System Variables **************** The following system variables may also be used in configuration. They are internal to FreeWheeling and are always available. You can not change the value of these variables with events like 'set-variable' and 'toggle-variable'.System variables have special events like 'set-master-in-volume' for control. Variables: SYSTEM_midi_transpose - semitones of current MIDI transpose - affects all outgoing MIDI events to FluidSynth and the external MIDI output port SYSTEM_master_in_volume - master input volume - 1.0 is full scale SYSTEM_master_out_volume master output volume - 1.0 is full scale SYSTEM_cur_pitchbend current value of MIDI pitchbender before offset SYSTEM_bender_tune - current offset of MIDI pitchbender (see set-midi-tuning) SYSTEM_cur_limiter_gain - current autolimiter gain - changes as audio levels change it's actually more of a soft compressor SYSTEM_audio_cpu_load - current audio CPU load SYSTEM_sync_active - nonzero if transport sync is sending or receiving beats/bars/ticks This will happen whenever you have a pulse, or if another audio app is transmitting sync information. SYSTEM_sync_transmit - nonzero if Freewheeling is transmitting sync information By default, Freewheeling tries to become timebase master. When the transport starts rolling, FW will transmit sync information. If another app is master, FW will receive sync information. SYSTEM_midisync_transmit - nonzero if Freewheeling is transmitting MIDI sync information. SYSTEM_fluidsynth_enabled - is FluidSynth enabled? SYSTEM_num_help_pages - number of help pages available SYSTEM_num_loops_in_map - total number of loops in the whole map SYSTEM_num_recording_loops_in_map - total number of loops currently recording or overdubbing in map watch this to see if you have runaway loops recording SYSTEM_num_patchbanks - total number of patch banks defined in configuration SYSTEM_cur_patchbank_tag - tag for currently selected patchbank- You can use this to change Freewheeling's behavior depending on which patchbank is selected. SYSTEM_loopid_lastrecord_0 SYSTEM_loopid_lastrecord_1 SYSTEM_loopid_lastrecord_2 ... - loop ids for those loops last recorded - lastrecord_0 is the most recently recorded loop, and so on.. the number of last record appears under loops, so you can see which loops were recorded more recently SYSTEM_in_1_volume SYSTEM_in_2_volume ... - current volumes for given inputs - up to the number of inputs you have defined SYSTEM_in_1_record SYSTEM_in_2_record ... - flag for each input that tells us whether the input is set to record SYSTEM_num_midi_outs number of MIDI outputs you have defined SYSTEM_snapshot_page_firstidx index of the first snapshot on the currently visible page of snapshots SYSTEM_num_switchable_interfaces number of switchable interfaces defined SYSTEM_cur_switchable_interface index of switchable interface currently selected Browser types: BROWSE_patch Patch browser BROWSE_loop Loop browser- loads loops from disk BROWSE_scene Scene browser- loads scenes from disk Triggering Multiple Outputs *************************** You can set up one event input to trigger many output events. To do this, specify your output events and parameters for each in a list. Have a look at the binding for input="start-freewheeling", which triggers a bunch of events when FreeWheeling is first started. ** Note that as of version 0.5pre3, this new syntax replaces the old start="1" and continued="1" syntax for startup and multiple output events. ** MIDI Echo ********* FreeWheeling echos incoming MIDI events to MIDI output. However, events that trigger a binding are not echoed. This allows you to connect a softsynth or other MIDI device to one of FreeWheeling's MIDI outputs. Then MIDI inputs which trigger your event bindings, such as triggering loops, will not go to your synth. Input Events ************ Here is a table of recognized input events. The input matrix is flexible in that different types of input events can be routed to different output events. There is also a parameter routing that connects input parameters like MIDI note velocity to control parameters within FreeWheeling. For example, you can specify that the number of the note pressed controls which loop is triggered. Event "key" binding input="key" conditions="keydown=1 and key=space" A keyboard key is pressed or released. "keydown": 1 if key was pressed, otherwise 0 "key": Name or number of the key (see above table) Event "midicontroller" binding input="midicontroller" conditions="controlnum=64 and midichannel=0 and controlval=64>127" A MIDI controller is changed. "outport": # of MIDI output to echo event to (1 is the first port) "midichannel": Channel of event (0 is the first channel) "controlnum": Number of control change "controlval": Value of control change "routethroughpatch": 1 sends this MIDI message through the port/channel(s) given by the current patch. 0 sends this message as described by outport/midichannel. Event "midikey" binding input="midikey" conditions="keydown=1 and midichannel=0 and notenum=VAR_noterange and velocity=1>127" A MIDI note is pressed or released. "outport": # of MIDI output to echo event to (1 is the first port) "keydown": 1 if note is pressed, 0 if note is released "midichannel": Channel of event (0 is the first channel) "notenum": Number of note "velocity": Velocity of noteon/noteoff "routethroughpatch": 1 sends this MIDI message through the port/channel(s) given by the current patch. 0 sends this message as described by outport/midichannel. Event "midichannelpressure" binding input="midichannelpressure" conditions="midichannel=0 and pressureval=64" A MIDI channel pressure (channel aftertouch) message. "outport": # of MIDI output to echo event to (1 is the first port) "midichannel": Channel of event (0 is the first channel) "pressureval": Pressure of keys "routethroughpatch": 1 sends this MIDI message through the port/channel(s) given by the current patch. 0 sends this message as described by outport/midichannel. Event "midiprogramchange" binding input="midiprogramchange" conditions="midichannel=0 and programval=64" A MIDI program change message. "outport": # of MIDI output to echo event to (1 is the first port) "midichannel": Channel of event (0 is the first channel) "programval": Program change # "routethroughpatch": 1 sends this MIDI message through the port/channel(s) given by the current patch. 0 sends this message as described by outport/midichannel. Event "midipitchbend" binding input="midipitchbend" conditions="midichannel=0 and pitchval=6000" A MIDI pitch bend message. "outport": # of MIDI output to echo event to (1 is the first port) "midichannel": Channel of event (0 is the first channel) "pitchval": Pitch bender value "routethroughpatch": 1 sends this MIDI message through the port/channel(s) given by the current patch. 0 sends this message as described by outport/midichannel. Event "joybutton" binding input="joybutton" conditions="joystick=1 and button=3 and down=1" A joystick button has been moved. "joystick": # of the joystick "button": # of the button "down": 1 if button is down, 0 if button is up Event "start-freewheeling" binding input="start-freewheeling" FreeWheeling has just been started. Event "go-sub" binding input="go-sub" Subroutine is being invoked- see "go-sub" in output events. The above input events can also be used as output events. For example, we can trigger a series of MIDI controller changes when a QWERTY key is pressed. Output Events ************* Here is a table of recognized output events, what they do and what parameters they accept: Event "exit-freewheeling" Quit! Event "slide-loop-amplifier-stop-all" Stops sliding amplitudes for all loops. Event "slide-loop-amplifier" Slides the amplitude of a given loop, like a fade. "loopid": the ID of the loop "slide": the speed at which to slide the amplitude. Successive events accelerate the sliding, until you reverse the speed or call set-loop-amplifier Event "set-loop-amplifier" Sets the amplitude of a given loop, and stops any sliding "loopid": the ID of the loop "amp": the amplitude to set it to (linear) Event "adjust-loop-amplifier" Adjusts the amplitude of a given loop, and stops any sliding "loopid": the ID of the loop "ampfactor": the factor to multiply the amplitude by Event "trigger-loop" Triggers a given loop- if no loop exists at that loopid, begins recording a new loop.. if a new loop is recording, the behavior depends: if overdub="1", switches to overdub.. if overdub="0", switches to play.. if a loop is playing, the behavior depends: if overdub="1", switches to overdub.. if overdub="0", switches off.. if a loop is overdubbing, switches to play. This is similar to an EDP style tapin-tapout-play/overdub. When recording a new loop, the length grows until we trigger-loop again. When overdubbing into an existing loop, the existing loop is blended with new input material. You can modify this behavior with the "engage" option. When "engage" is set to 1, the loop will -always- start. When "engage" is set to 0, the loop will -always- stop. If engage is not set, the behavior depends on the current state of the loop, as described above. You can modify the looping behavior with the "shot" option. When "shot" is set to 1, the loop will play through only once. When "shot" is not set, the loop will repeat indefinitely. "loopid": the ID of the loop "vol": the volume to trigger with- this combined with the loop amplitude determine the overall amplitude of the playing loop "shot": shot mode "engage": force on or off? "overdub": 1 or 0 determine whether to overdub or just play "overdubfeedback": Variable that holds the value of feedback to apply during overdub. Variable must be of type float (from 0.0 to 1.0). Variable can be continuously varied. Event "set-trigger-volume" Sets the volume of a given loop trigger. If you have a loop playing, you can change the volume with this event. It is different than the loop amplifier, because each time you trigger the loop you can have a different trigger volume, whereas the loop amplifier changes the volume of the loop once-and-for-all. "loopid": the ID of the loop "vol": the volume to set it to Event "erase-selected-loops" Erase selected loops that are in the given selection set. "setid": Number of the selection set to use (usually this will be 0) Event "erase-all-loops" Erases all loops and time meters. Event "erase-loop" Erases a given loop- if recording is happening on the given id, stops and erases recording. "loopid": the ID of the loop Event "move-loop" Moves a loop from "oldloopid" to "newloopid", if a loop exists there. This can be done at any time- when recording or playing a loop, or when it is inactive. "oldloopid": old loop ID "newloopid": new loop ID Event "slide-master-in-volume" Slides the master input volume at the speed given. A positive value increases volume. Actually, if you call slide-master-in-volume several times you cumulatively increase the speed of sliding. It is like a fade. This applies for other slide events too. "slide": speed of slide Event "slide-in-volume" Slides one input volume at the speed given. A positive value increases volume. "input": number of input to slide volume for "slide": speed of slide Event "slide-master-out-volume" Slides the master output volume at the speed given. A positive value increases volume. "slide": speed of slide Event "set-master-in-volume" Sets the master input volume. Stops sliding. "vol": new linear volume- 1.0 is 100% volume. or "fadervol": new logarithmic volume- specify fader throw (0.0 to 1.0). Event "set-master-out-volume" Sets the master output volume. Stops sliding. "vol": new linear volume- 1.0 is 100% volume. or "fadervol": new logarithmic volume- specify fader throw (0.0 to 1.0). Event "set-in-volume" Sets one input volume. Stops sliding. "input": number of input to set volume for "vol": new linear volume- 1.0 is 100% volume. or "fadervol": new logarithmic volume- specify fader throw (0.0 to 1.0). Event "toggle-input-record" Toggles recording of one input. Does not change monitoring for this input, only whether loops are recorded from the input. "input": number of input to toggle recording for Event "adjust-midi-transpose" Adjusts the pitch transpose for MIDI out. MIDI events that aren't used in an event are echoed back out the MIDI out and to the internal FluidSynth synthesizer. This parameter adjusts the transpose that is applied to MIDI notes before they are echoed. It does not affect the note numbers coming into FreeWheeling events. "adjust": amount to shift transpose (semitones) Event "fluidsynth-enable" Enables or disables processing for the integrated FluidSynth. When FluidSynth is disabled, the real-time DSP for FluidSynth is not active, so FreeWheeling runs faster. By default, this is done by the patch browser. When you select FluidSynth patches, FluidSynth is enabled. When you select other patches, FluidSynth is automatically disabled. "enable": 1 for enable or 0 for disable Event "set-midi-tuning" Retunes MIDI by the current value of the pitchbender. What this does is offset the zero position of pitchbender to a given value. You can easily tune to outside instruments by sweeping the pitchbender until you are in tune and then calling set-midi-tuning with the current value of the pitchbender (see system variables). "tuning": new zero position for MIDI pitchbender Event "set-midi-echo-port" DEPRECATED- FreeWheeling now sends to ports/channels as specified by the patch browser. Sets the MIDI port where incoming MIDI events are echoed. The only events echoed are those that do not trigger something in FreeWheeling. "echoport": new MIDI out port number to echo MIDI events (0 disables) Event "set-variable" Sets the user variable named "var" to the value "val". The value given must be convertible into the type of variable "var". "var": variable to set "value": what to set it to Event "toggle-variable" Toggles (increments) the user variable named "var" through an integer range of values, with a maximum of "maxvalue". Wraps to "minvalue" when maxvalue is exceeded. "var": variable to toggle "maxvalue": maximum value of variable "minvalue": minimum value of variable Event "video-show-loop" Change the range of loops shown onscreen- In the onscreen layout given by "layoutid", shows loops in the range "loopid". For example, if you specify layoutid 0 and loopid 15>30, then layout 0 will show the loop at id 15 in its first element (element id 0), up to loopid 30 in element 15. You will see these changes only if the layout is set to show onscreen, and when there are loops stored in the loopids given. "interfaceid": interface where layout is defined "layoutid": which layout to change the range of shown loops "loopid": new range of shown loops Event "video-show-layout" Shows or hides the layout given by "layoutid". If hideothers is "1", all other layouts are made hidden. "interfaceid": interface where layout is defined "layoutid": layout to show/hide "show": "1" for show and "0" for hide "hideothers": "1" to hide all other layouts Event "video-switch-interface" Switches to (shows) the interface given by "interfaceid". All displays and layouts defined in that interface are shown. All displays and layouts defined in other interfaces are hidden, EXCEPT those in non-switchable interfaces. "interfaceid": interface to switch to Event "video-show-help" Shows or hides help. FreeWheeling has an online help that can be overlaid on the screen while you are playing. This event shows a given page of that help (or hides it). The help text is user defined. Throughout this config file, you'll see comments which begin in "HELP:". Any comments that begin in this way become a part of the help text. If you have a second ":" in the help comment, it becomes a second column in the help text. "page": Help page number to show or "0" for hide Event "video-full-screen" Put FreeWheeling in a window, or let 'er hog the whole screen "fullscreen": "1" for hog fullscreen and "0" for window Event "select-pulse" Selects time pulse #pulse. If no pulse exists at the given #, creates a new one. The length and downbeat of a new pulse are taken from the last recorded loop. Once a pulse is created, it is automatically selected. The selected pulse determines the timing of all newly recorded loops. If a new pulse is selected, only those loops recorded from that point on are affected. To deselect all pulses and return to free time, set pulse="-1". "pulse": Number of the time pulse to create/select Event "delete-pulse" Delete time pulse #pulse. All loops attached to that pulse are also deleted. "pulse": Number of the time pulse to delete Event "show-debug-info" Shows or hides debugging information. The information is printed to the console. It includes input events like MIDI and keyboard keys, and information from bound events. It can help track down problems in your configuration, if FreeWheeling is not working as you imagined. But it introduces some performance latency, so I recommend leaving it off! "show": "1" for show debug info and "0" for hide Event "toggle-disk-output" Toggles output of the master outs to disk. This includes the input mix. OGG files are created in the library folder with the name 'live1.ogg', 'live2.ogg', etc.. The live mix is exactly what you hear from FreeWheeling's outputs. Accompanying each OGG file is a timing file named live.wav.usx, to be used in the GnuSound editor for doing precise splice edits on loop downbeats. Run oggdec on the OGG files and then load into GnuSound. You can also import timing information into Ardour from this .wav.usx file- see the file scripts/go-import-markers. If FreeWheeling is already writing to disk, this shuts the record off. The next write starts in a new folder. FreeWheeling no longer overwrites old files and folders. Existing save folders are skipped. Event "set-auto-loop-saving" Turns on/off auto loop saving. This saves all new loops to disk. The loops are saved in the current "save" folder (see toggle-disk-output), with the name 'loop???.ogg'. The loopID is given in the filename. Loop files are not overwritten- subsequent writes of 55, for example, will yield filenames 'loop55-0.ogg', 'loop55-1.ogg', etc. "save": "1" to turn on auto loop saving and "0" for off Event "save-loop" Saves the loop with given index. The file is named and saved as described above. "loopid": ID of loop to save Event "save-new-scene" Event "save-current-scene" Saves a new scene/overwrites current scene. A scene is a snapshot of all loaded loops and levels. It is like a save of the complete session. Event "create-snapshot" Create a snapshot. A snapshot is a memory of all playing and idle loops and their levels. This allows you to easily create and switch between song 'sections'. "snapid": ID # of snapshot to save Event "rename-snapshot" "snapid": ID # of snapshot to rename Event "trigger-snapshot" "snapid": ID # of snapshot to trigger Event "swap-snapshots" Swap two snapshots. "snapid1": ID # of first snapshot "snapid2": ID # of second snapshot Event "switch-metronome" Switches an audible metronome on or off for the given pulse. The metronome sounds on the downbeat of the pulse. "pulse": Number of the pulse "metronome": 1 for metronome on, 0 for off Event "tap-pulse" Taps a pulse- each tap gives a new downbeat. This allows you to tap tempo, instead of creating a pulse around an existing loop. If you tap a tempo and switch-metronome to on, it is like playing along with a click track. If you already have loops playing on a pulse, the effect is to change the timing when they loop to their start. The loops themselves do not change speed (yet). "pulse": Number of the pulse "newlen": 1 for change tempo, 0 for just hit downbeat Event "go-sub" Triggers event "go-sub", which you can bind to. The effect is like creating a subroutine of several event triggers. You can then trigger go-sub from many places, and have the same subroutine of events triggered. This allows you to have FreeWheeling do several predefined things in response to one input, like changing loop volumes and moving loops, or repeating some operation on several loops. You can have many subroutines, and each subroutine can accept parameters. Search for go-sub to find examples in this config. "sub": Number of the subroutine "param1": Integer parameter 1 "param2": Integer parameter 2 "param3": Integer parameter 3 Event "browser-move-to-item" Moves forward or back in a browser "browserid": Browser ID- as you have defined in 'display' section "adjust": Number of individual items to move by (+ is forward - is back) "jumpadjust": number of divisions to jump by divisions are placed depending on the type of browser- for example, for Fluidsynth patches, there are divisions between soundfonts Event "browser-select-item" Choose or select the current item in a browser. Different browser types behave differently when an item is selected For example, the loop browser loads the selected loop "browserid": Browser ID- as you have defined in 'display' section Event "browser-rename-item" Rename the current item in a browser. This is an interactive process where the user can make changes to the item name. Many of the regular keyboard bindings become disabled during renaming. During renaming, you can type a new name with the keyboard. ESC aborts renaming, and ENTER accepts the new name. "browserid": Browser ID- as you have defined in 'display' section Event "patchbrowser-move-to-bank" Switch patch browser banks. "direction": -1 or 1 to move backward or forward Event "patchbrowser-move-to-bank-by-index" Switch patch browser banks, choosing by index. "index": Index of patchbank to select Must be in the range of 0 to SYSTEM_num_patchbanks-1 Event "browser-item-browsed" This event is sent out by Freewheeling's browsers whenever a browser item is changed. This is useful in the patch browser- you can bind to browser-item-browsed and send out control changes or change MIDI echo ports whenever a new item is browsed. "browserid": Browser ID- as you have defined in 'display' section. Identifies which browser has had a change in item. Event "video-show-display" Show or hide a video display with the given ID- you define the displays and IDs in the video section below, and then you can turn them on or off as needed through this event. "interfaceid": interface where layout is defined "displayid": Display ID "show": 1 or 0 is show or hide display Event "set-load-loop-id" Sets the loop ID where to put a loop when it is loaded from disk. Loops are loaded by the loop browser when an item is selected (browser-select-item). Whenever a single loop is loaded from disk, it will appear in this loop ID. "loopid": ID to load loops into Event "set-default-loop-placement" Sets the range of loop IDs to be used by default. For example when loading external loops, FW can place them here if the requested IDs are not available. "looprange": Range of IDs to use as default Event "loop-clicked" This event is generated whenever the user clicks a mouse button on a loop slot on-screen. It allows you to respond to clicks on loops. "down": Mouse button down or up? (1 or 0) "button": Number of mouse button pressed/released "loopid": Number of the corresponding loopid clicked on "in": Zero if the loop was clicked in the loop tray One if the loop was clicked in a layout Event "set-sync-type" Set the type of sync for syncronizing to an external sequencer/app. Freewheeling uses a 'pulse' concept of timing. Instead of dividing time up into bars, beats, and ticks (sequencer style), Freewheeling simply defines time as a rhythmic pulsing. When you create a pulse, Freewheeling can optionally transmit or receive sync information for that pulse. Two syncronization mechanisms are provided- Jack and MIDI. Both represent time as bars, beats, and ticks. The sync type parameter controls whether we are mapping beats to pulses (beat sync) or bars to pulses (bar sync). "type": 1 for beat sync, 0 for bar sync Event "set-sync-speed" Set the number of beats/bars per pulse. This affects the translated speed between Freewheeling's internal clock and the external clock. "speed": Number of beats or bars (depending on sync type) to a single pulse. Event "set-midi-sync" Set whether to transmit MIDI sync. Note that to transmit MIDI sync, you also need to set 'midisyncouts' in the general config section, and you need to have a pulse running. "midisync": 1 to transmit MIDI sync. 0 for no MIDI sync. Event "toggle-select-loop" Freewheeling allows you to select and work with several loops at once. This event toggles one loop as selected/unselected. You can have several selection sets. "setid": Number of the selection set in which to toggle the loop (usually this will be 0) "loopid": ID of the loop to toggle Event "select-only-playing-loops" Make the selection include only those loops that are currently playing/ currently idle. "setid": Number of the selection set to change (usually this will be 0) "playing": 1 to include only playing loops 0 to include only idle loops Event "select-all-loops" Select/unselect all loops. "setid": Number of the selection set to change (usually this will be 0) "select": 1 to select all loops 0 to select no loops Event "invert-selection" Invert the selection- Select all loops not currently selected. "setid": Number of the selection set to change (usually this will be 0) Event "trigger-selected-loops" Trigger the selected loops. You can toggle them for playing/idle, or you can force them to play. "setid": Number of the selection set to use (usually this will be 0) "vol": Volume at which to trigger loops "toggleloops": 1 to toggle loops for playing, 0 to force playing. Event "set-selected-loops-trigger-volume" Set the volume of all selected loops. This only affects playing loops. This allows you to fade many loops together. "setid": Number of the selection set to use (usually this will be 0) "vol": Volume to set loops to Keyboard Keys ************* For your reference, here is a table that lists keyboard key #s and the corresponding key name (keysym). When referring to keys in the XML config files, use the name given in the second column. 008 - backspace 009 - tab 012 - clear 013 - return 019 - pause 027 - escape 032 - space 033 - exclamation 034 - dblquote 035 - numbersign 036 - dollarsign 038 - ampersand 039 - backquote 040 - openparen 041 - closeparen 042 - asterisk 043 - plus 044 - comma 045 - minus 046 - period 047 - slash 048 - zero 049 - one 050 - two 051 - three 052 - four 053 - five 054 - six 055 - seven 056 - eight 057 - nine 058 - colon 059 - semicolon 060 - lessthan 061 - equal 062 - greaterthan 063 - questionmark 064 - at 091 - squarebracketopen 092 - backslash 093 - squarebracketclose 094 - caret 095 - underscore 096 - tilde 097 - a 098 - b 099 - c 100 - d 101 - e 102 - f 103 - g 104 - h 105 - i 106 - j 107 - k 108 - l 109 - m 110 - n 111 - o 112 - p 113 - q 114 - r 115 - s 116 - t 117 - u 118 - v 119 - w 120 - x 121 - y 122 - z 127 - delete 160 - world0 161 - world1 162 - world2 163 - world3 164 - world4 165 - world5 166 - world6 167 - world7 168 - world8 169 - world9 170 - world10 171 - world11 172 - world12 173 - world13 174 - world14 175 - world15 176 - world16 177 - world17 178 - world18 179 - world19 180 - world20 181 - world21 182 - world22 183 - world23 184 - world24 185 - world25 186 - world26 187 - world27 188 - world28 189 - world29 190 - world30 191 - world31 192 - world32 193 - world33 194 - world34 195 - world35 196 - world36 197 - world37 198 - world38 199 - world39 200 - world40 201 - world41 202 - world42 203 - world43 204 - world44 205 - world45 206 - world46 207 - world47 208 - world48 209 - world49 210 - world50 211 - world51 212 - world52 213 - world53 214 - world54 215 - world55 216 - world56 217 - world57 218 - world58 219 - world59 220 - world60 221 - world61 222 - world62 223 - world63 224 - world64 225 - world65 226 - world66 227 - world67 228 - world68 229 - world69 230 - world70 231 - world71 232 - world72 233 - world73 234 - world74 235 - world75 236 - world76 237 - world77 238 - world78 239 - world79 240 - world80 241 - world81 242 - world82 243 - world83 244 - world84 245 - world85 246 - world86 247 - world87 248 - world88 249 - world89 250 - world90 251 - world91 252 - world92 253 - world93 254 - world94 255 - world95 256 - KP0 257 - KP1 258 - KP2 259 - KP3 260 - KP4 261 - KP5 262 - KP6 263 - KP7 264 - KP8 265 - KP9 266 - KPperiod 267 - KPslash 268 - KPasterisk 269 - KPminus 270 - KPplus 271 - enter 272 - equals 273 - up 274 - down 275 - right 276 - left 277 - insert 278 - home 279 - end 280 - pageup 281 - pagedown 282 - f1 283 - f2 284 - f3 285 - f4 286 - f5 287 - f6 288 - f7 289 - f8 290 - f9 291 - f10 292 - f11 293 - f12 294 - f13 295 - f14 296 - f15 300 - numlock 301 - capslock 302 - scrolllock 303 - rightshift 304 - leftshift 305 - rightctrl 306 - leftctrl 307 - rightalt 308 - leftalt 309 - rightmeta 310 - leftmeta 311 - leftsuper 312 - rightsuper 313 - altgr 314 - compose 315 - help 316 - printscreen 317 - sysreq 318 - break 319 - menu 320 - power 321 - euro 322 - undo freewheeling-0.6.6/data/coreinterface.xml000066400000000000000000001200041370736313100204340ustar00rootroot00000000000000 freewheeling-0.6.6/data/dancemat.xml000066400000000000000000000146641370736313100174150ustar00rootroot00000000000000 freewheeling-0.6.6/data/fonts/000077500000000000000000000000001370736313100162355ustar00rootroot00000000000000freewheeling-0.6.6/data/fonts/truetype/000077500000000000000000000000001370736313100201165ustar00rootroot00000000000000freewheeling-0.6.6/data/fonts/truetype/ttf-bitstream-vera/000077500000000000000000000000001370736313100236365ustar00rootroot00000000000000freewheeling-0.6.6/data/fonts/truetype/ttf-bitstream-vera/COPYING000066400000000000000000000044341370736313100246760ustar00rootroot00000000000000Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Bitstream Vera is a trademark of Bitstream, Inc. Permission is hereby granted, free of charge, to any person obtaining a copy of the fonts accompanying this license (“Fontsâ€) and associated documentation files (the “Font Softwareâ€), to reproduce and distribute the Font Software, including without limitation the rights to use, copy, merge, publish, distribute, and/or sell copies of the Font Software, and to permit persons to whom the Font Software is furnished to do so, subject to the following conditions: The above copyright and trademark notices and this permission notice shall be included in all copies of one or more of the Font Software typefaces. The Font Software may be modified, altered, or added to, and in particular the designs of glyphs or characters in the Fonts may be modified and additional glyphs or characters may be added to the Fonts, only if the fonts are renamed to names not containing either the words “Bitstream†or the word “Veraâ€. This License becomes null and void to the extent applicable to Fonts or Font Software that has been modified and is distributed under the “Bitstream Vera†names. The Font Software may be sold as part of a larger software package but no copy of one or more of the Font Software typefaces may be sold by itself. THE FONT SOFTWARE IS PROVIDED “AS ISâ€, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL BITSTREAM OR THE GNOME FOUNDATION BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE. Except as contained in this notice, the names of GNOME, the GNOME Foundation, and Bitstream Inc., shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Font Software without prior written authorization from the GNOME Foundation or Bitstream Inc., respectively. For further information, contact: fonts at gnome dot org. freewheeling-0.6.6/data/fonts/truetype/ttf-bitstream-vera/Vera.ttf000066400000000000000000002006141370736313100252550ustar00rootroot00000000000000OS/2´_ôcëpVPCLTÑŠ^—ëÈ6cmap¤Ãè ±lXcvt ÿÓ9üüfpgmç´ñÄ&`‹gaspH glyf tAÏ&ìŠ~hdmx4ð!ìHheadÝ„¢ÐT6hheaEoëL$hmtx ÆŽ²´Ä0kernÜRÕ™½ -ŠlocaóËÒ=»„maxpG:ë, nameټȵßpost´Z/»¸ôŽprep;ñ øh::_:: dM0­l  ƒ p t › &   Y &  &   c . 5 ` õ s 0¡ & {Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved.Bitstream Vera SansBitstreamVeraSans-RomanRelease 1.10Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Bitstream Vera is a trademark of Bitstream, Inc. Permission is hereby granted, free of charge, to any person obtaining a copy of the fonts accompanying this license ("Fonts") and associated documentation files (the "Font Software"), to reproduce and distribute the Font Software, including without limitation the rights to use, copy, merge, publish, distribute, and/or sell copies of the Font Software, and to permit persons to whom the Font Software is furnished to do so, subject to the following conditions: The above copyright and trademark notices and this permission notice shall be included in all copies of one or more of the Font Software typefaces. The Font Software may be modified, altered, or added to, and in particular the designs of glyphs or characters in the Fonts may be modified and additional glyphs or characters may be added to the Fonts, only if the fonts are renamed to names not containing either the words "Bitstream" or the word "Vera". This License becomes null and void to the extent applicable to Fonts or Font Software that has been modified and is distributed under the "Bitstream Vera" names. The Font Software may be sold as part of a larger software package but no copy of one or more of the Font Software typefaces may be sold by itself. THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL BITSTREAM OR THE GNOME FOUNDATION BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE. Except as contained in this notice, the names of Gnome, the Gnome Foundation, and Bitstream Inc., shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Font Software without prior written authorization from the Gnome Foundation or Bitstream Inc., respectively. For further information, contact: fonts at gnome dot org.http://www.bitstream.comCopyright (c) 2003 by Bitstream, Inc. All Rights Reserved.Bitstream Vera SansBitstreamVeraSans-RomanRelease 1.10Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Bitstream Vera is a trademark of Bitstream, Inc. Permission is hereby granted, free of charge, to any person obtaining a copy of the fonts accompanying this license ("Fonts") and associated documentation files (the "Font Software"), to reproduce and distribute the Font Software, including without limitation the rights to use, copy, merge, publish, distribute, and/or sell copies of the Font Software, and to permit persons to whom the Font Software is furnished to do so, subject to the following conditions: The above copyright and trademark notices and this permission notice shall be included in all copies of one or more of the Font Software typefaces. The Font Software may be modified, altered, or added to, and in particular the designs of glyphs or characters in the Fonts may be modified and additional glyphs or characters may be added to the Fonts, only if the fonts are renamed to names not containing either the words "Bitstream" or the word "Vera". This License becomes null and void to the extent applicable to Fonts or Font Software that has been modified and is distributed under the "Bitstream Vera" names. The Font Software may be sold as part of a larger software package but no copy of one or more of the Font Software typefaces may be sold by itself. THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL BITSTREAM OR THE GNOME FOUNDATION BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE. Except as contained in this notice, the names of Gnome, the Gnome Foundation, and Bitstream Inc., shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Font Software without prior written authorization from the Gnome Foundation or Bitstream Inc., respectively. For further information, contact: fonts at gnome dot org.http://www.bitstream.com5¸ËËÁªœ¦¸fqË ²…u¸Ãˉ-˦ðÓª‡ËªJ3ËÙôT´œ99N´R¸çÍ7sÍ`s3¢V¦V9Åɸßsºé3¼Dßͪåªˤ{¸o{RÇÍššoËÍžÓðºƒÕ˜HžÕÁËöƒT3fÓǤ͚sÕ þ+¤´œbœ-ÕÕÕð{T¤¸#Ӹ˦Ãì“ Ó\qÛ…#¨H99`Õš#fy```{œw`ªé`b{Å{´RÍf¼fwÍ;…‰{ÍJ/œœ}oo5jo{®²-–{öƒT7öœáföÍD)fîs¸€@ÿûþúù%ø2÷–öõþôþó%òñ–ð%ïŠAïþî–í–ìúëúêþé:èBçþæ2åäSå–äŠAäSãâ/ãúâ/áþàþß2ÞÝ–ÜþÛÚ}Ù»ØþÖŠAÖ}ÕÔGÕ}ÔGÓÒÓþÒÑþÐþÏþÎþÍ–ÌËÌþËÊ2ÉþÆ…ÆÅÄþÃþÂþÁþÀþ¿þ¾þ½þ¼þ»þº¹†%¹þ¸·»¸þ·¶]·»·€¶µ%¶]@ÿ¶@µ%´þ³–²þ±þ°þ¯þ®d­¬«%¬d«ª«%ª©ŠA©ú¨þ§þ¦þ¥¤þ£¢£2¢¡d ŠA –Ÿþž žþ œ›œd›š›š™ ˜þ—– —þ– •ŠA•–”“”(“’ú‘»‘þ]»€Ž%]@Ž%þŒ‹.Œþ‹.І%ŠA‰ˆ ‰ˆ ‡†%‡d†…†%…„þƒ‚ƒþ‚þ€þþ@ÿ~}}~þ}}|d{T{%zþyþxw v uþtúsúrúqúpþoþnþl!kþjBjSiþh}gBfþeþdþcþbþa:`ú^ ]þ[þZþYX YúX WW2VþUTUBTSSRQJQþP OþNMNþMLþKJKþJIJI IH GþF–E–DþC-CúB»AK@þ?þ>=>=<=<; <@ÿ; :þ9þ878ú76765 65 43 21 2þ1 0/ 0 / .- .- ,2+*%+d*)*%)('%(A'%&% &% $þ#þ"!! dú d BþúBBþdþþþþBþ-B}dþ  þ   þ  þ-þdþ@-þ-þ¸d…++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++¶, °%Id°@QX ÈY!-,°%Id°@QX ÈY!-,  °P° y ¸ÿÿPXY°°%°%#á °P° y ¸ÿÿPXY°°%á-,KPX °ýEDY!-,°%E`D-,KSX°%°%EDY!!-,ED-fþ–f¤@ ûû/ÄÔì1ÔìÔì0!%!!füsüåþ–øòr)5Õ @@ƒ ü<ì2991/äüÌ0K° TX½ @ ÿÀ878Y¶ P ]%3#3#5ËËË¢þþÕýqþ›eŪéÕM@„üüÜì1ô<ì20K°TK°T[X½@ÿÀ878Y@0 @ P ` p   ¿ ]#!#oª$ªÕýÕ+ýÕ+ž¾`@1 ‡  ‡   üÌ91/<Ô<<ü<<Ô<<Ä2ì220@   ]!! !3!!!!#!#!5!!5!þÝT%Dh$i g8þ¡R>þ›h gþÛg¡hþÅ`Tþ¾if…þ²‡þaŸþašþ²™þbžþbž™NšŸªþÓm!(/Õ@U" '&( /)/))/B" ) *!††#Љ*Љ- ) " & 0ü<ìô<ü<ôäì1/äìÄÔäì2Äîî99990KSXíí9í9íY"K° TX½0@00ÿÀ878YK° TK°T[K°T[X½0ÿÀ00@878Y#.'5.546753.'>54&´diÒjfÑoÝÉÚÌd]®SS¯\ãÖãÖdtzqá{þÓ---´@AÈ$¬–£¼ëè¯*.þU#´œ©Ãš jXV`ÕþOnZXhqÿã)ð #'3•@6$%&%&'$'B’ ’.’$’ &Œ($‘4'!%   ! + 1 4üÄìôìîöî991ä2ô<äìîöîî0KSXííY"K° TK° T[K° T[K°T[K°T[K° T[X½4@44ÿÀ878Y"32654&'2#"&546"32654&%3#2#"&546ÑWccWUccUžº» º»ü—VcbWWcd1 üZ ž¼»ŸŸ¹º‘”„‚••‚ƒ•Ü»»ÛÛ»¼Ûa•‚„””„–ùó Û»½ÚÛ¼ºÜÿãþð 0Í@–  † †  † †††  !         B  (('•+•'”$‘Œ .  .'.'!!1üìÄÔÔìÆî99999991/ÆäöæîîÆ9990KSXíí9í9í9í9í9íí9í9ííí9Y"²2]@² " ) **&:4D ^YZ UZZY0g{›š™—• “••"™-  ' (   2'') #**(/2; 49?2J LKFO2VZ Y UY\_2j i`2uy z““—•œœŸš › š 2 2°29]]3267 >73#'#"5467.54632.#"ò[UÔ _¦Iþ{ü;Bº h]ühäƒñþΆ†02Þ¸S¥UWžDiƒ;#Q¡X’Â?@ýøYËr„þþ~þã“YW×€ác?}<¢Å$$¶/1oX3gŪoÕB@ „üì1ôì0K°TK°T[X½@ÿÀ878Y@ @P`p ]#oªÕýÕ+°þò{ O@˜—  Üä2ì991üì0K°TX½@ÿÀ878YK°TX½ÿÀ@878Y#&547{†‚ƒ… –•”—æþ>ççþ;åëÆàßÄì¤þòo @˜— Ü<ôì991üì03#654¤ –••– …ƒƒìþ<ßàþ:ëåÅççÂ=JÃðN@,  ™ ™ ‘    Ô<ä2Ü<ä2991ôÔ<ì2Äì2990%#'%%73%Ãþ™g:þ°rþ°:gþ™:PrPßÂÃbËþ‡yËbÃÂcËyþ‡ËÙÛ #@ œ  Üü<ü<ì1/Ô<ü<Ä0!!#!5!®-ýÓ¨ýÓ-ýÓªýÓ-ª-žÿÃþ@ žƒüìÔÌ1üì073#ðÓ¤Rþ¬þÀ@d߃¶œÜÌ1Ôì0!!dý僤ۮþ·ƒüì1/ì073#ÛÓÓþþÿB²Õ-@BŸ/Ä991ôì0KSXííY"3#ªýøªÕùm‡ÿãð #@   ‘Œ üìôì1äôìî0"32'2#"‹œœû þ÷ûûþ÷ PþÍþÌþÍþÍ3343 þsþ†þ‡þsyzáZÕ K@B     ÔìÄüì1/ì2ôìÔì0KSXY"K°TX½ ÿÀ @878Y´]7!5%3!!þJþ™eÊJü¤ªsH¸HúÕª–Jð¥@'B¡”  ‘   üÄÔìÀÀ91/ì2ôìôì0KSXíí9Y"K°TK°T[K°T[X½@ÿÀ878Y@2UVVzzv‡tvust‚†‚‚‚¨¨]]%!!567>54&#"5>32‰ÁüLs3aM§†_ÓxzÔXèE[þôªªªw‘:m—Iw–BCÌ12èÂ\¥pþëœÿãsð({@. † †     “  “#‘Œ£)&  )üÄÄÔìôì991ìäôäìæîîîî90K°TK°T[X½)@))ÿÀ878Y@ daa d!]!"&'532654&+532654&#"5>32?‘£þÐþè^ÇjTÈm¾Ç¹¥®¶•ž£˜S¾rsÉYæ Ž%ÄÝò%%Ã12–„•¦wps{$&´ Ѳ|«d¤Õ Œ@   B     ÜÔ<Äì291/äÔ<ì290KSXÉÉY"K° TK° T[X½@ÿÀ878Y@* *HYiwŠ+&+6NO O Vfuz… ]] !33##!5þþ5þÕÕÉý^%üãÍü3¨þ `ÞÿãdÕu@#†  ‰   Œ¤  üÄÔìÄî1ääôìæîþÄî90K°TK°T[X½@ÿÀ878YK°TX½ÿÀ@878Y!!>32!"&'532654&#"Ýý ,X,ú$þÔþï^ÃhZÀk­ÊÊ­Q¡TÕªþ’þîêñþõ Ë10¶œœ¶$&ÿã–ð $X@$ †   ¥  ‰"‘Œ% " !%üììôìä1äôäüäîîî90@ËËÍÍÍËˤ²]]"32654&.#">32# !2¤ˆŸŸˆˆŸŸ L›LÈÓ;²káþðâþýþîPL›;º¢¡»»¡¢ºy¸$&þòþïW]þïëæþêyb¥¨hÕc@B üÌÄ991/ôì0KSXííY"K°TX½@ÿÀ878Y@X9Hg°°]]!#!¨ÀýâÓþý3ÕVú+‹ÿã‹ð #/C@%  ' - ‘Œ'£0 $*$ !0üÄìôÄìîî991ìäôìîî990"32654&%&&54632#"$54632654&#"‹¥¥¦¥þ¥‚‘ÿÞßþ‘’£þ÷÷÷þ÷¤H‘ƒ‚““‚ƒ‘Åš‡‡š›†‡šV ²€³Ðг€² "ÆÙèèÙÆat‚‚tt‚‚ÿã‡ð$X@#†  ¥ ‰ ‘Œ%!"" %üìäôìì1äôìæþõîî90@ÄÂÀÀÀÂμé]]7532#"543 !"&2654&#"áLœKÈÓ:²làþûâþ±þåLœ>ˆŸŸˆˆŸŸ¸$& V\ëæþsþ†þŸþ[—º¢¡»»¡¢ºðÃ#@ƒ¦ƒü<ì21/ìôì073#3#ðÓÓÓÓþþ#þžÿÃ# %@ƒžƒ¦  ü<ì2ÔÌ1äüìî03#3#ðÓÓÓ¤R#þýÙ¬þÀ@Ù^Û¦M@*œœœœB¨§$#üì291ôì90KSXííííY" 5Ûûøúþðþ‘þ“¶ѦÑÙ`Û¢@ œœ#ü<Ä21ÔìÔì0!!!!Ùúþúþ¢¨ðªÙ^Û¦O@+œœœœB¨§$#ü<ì91ôì90KSXííííY"55Ùúþð¶þ/¦þ/¶m“°ð$p@+$  †ˆ•‘ƒ   &%ÜÄüìÔìî99991/îöþôîÍ9990K° TX½%@%%ÿÀ878Y¶y z z ]%3##546?>54&#"5>32‡ËËÅ¿8ZZ93ƒlO³a^Ág¸ßHZX/'þþ‘še‚VY5^1YnFC¼98ŸL‰VV/5<4‡þœq¢ L•@2  ©©L43¬0©7¬$©7CM34( (+(I+*(I,=MÜìüìþýþ<Æî991ÔÄüìþíÔÆÅî2Äî990K° TK° T[K°T[K°T[K°T[X½MÿÀMM@878Y@ NN/N?N]32654&#"#"&5463253>54&'&$#"3267#"$'&5476$32úŽ|{zy!<›g¬×Ø«gœ;’¥?@hþÕ°{â`±smiùhZ}þÙ˜¹þ¸€€†ˆ~R½Ôk{KOþÂþè£¤ŽŒ¥¤þHMIùÈÈúKLƒý ß±k¼Pƒ‹A@fþµÁŸþêjhmWQoagƒ}}I½¶J}‡® bæ{þùþÐhÕ º@A       B•    ÔÄ91/<äÔì90KSXííííííííY"² ]@:XvpŒ VXP ghxv|rwx‡ˆ€ ˜™–]] !3#!#¼þî%þ{å9Òˆý_ˆÕý®ú+þÉìÕ C@#• •• ­ . !üì2üìÔì9991/ììôìî90²"]!2654&#!2654&#%!2#!“D££þ¼+”‘‘”þ çú€|•¥þðûýèÉý݇‹Œ…fþ>orqp¦À±‰¢ ˘ÈÚsÿã'ð6@ ¡® •¡®•‘Œ 0üì2ì1äôìôìîöî0´].# !267# !2'fç‚ÿþð‚çfjí„þ­þz†S†íbÕ_^þÇþØþÙþÇ^_ÓHHŸghŸGɰÕ.@• •  2 üìôì99991/ìôì0²`]3 !%! )“ô5þáþËþBŸ²–þhþPþa/ûw.,¦þ—þ€þ~þ–É‹Õ .@•••­   üì2ÔÄÄ1/ììôìî0² ]!!!!!!ɰýÇý9øü>ÕªþFªýãªÉ#Õ )@••­ üì2ÔÄ1/ìôìî0² ]!!!!#ÉZýpPý°ÊÕªþHªý7sÿã‹ð9@ ••¡®•‘Œ43 üìüäüÄ1äôìôìþÔî990%!5!# !2&&# !26Ãþ¶uþæ þ¢þu‹^’opü‹þîþík¨Õ‘¦ýSU™mn™HF×_`þÎþÑþÒþÎ%É;Õ ,@•­ 8  üì2üì21/<ä2üì0²P ]3!3#!#ÉÊÞÊÊý"ÊÕýœdú+Çý9É“Õ9·¯üì1/ì0K°TX½ÿÀ@878Y@ 0@P`Ÿ]3#ÉÊÊÕú+ÿ–þf“Õ M@ •° 9 üìä991äüì990K°TX½ ÿÀ @878Y@ 0 @ P ` Ÿ ]3+53265ÉÊÍãM?†nÕú“þòôª–ÂÉjÕ ï@(B¯  üì2ÔÄ91/<ì290KSXííííY"²]@’ ((764GFCUgvwƒˆ”›ç    (+*66650 A@E@@@ b`hgwp ‹‹Ž š¶µÅÅ×Öèéèê÷øù,]q]q3! !#ÉÊžýþöý3ÊÕý‰wýHüãÏý1ÉjÕ%@ •:üìì1/äì0@ 0P€€]3!!ÉÊ×ü_ÕúÕªÉÕ ¿@4  B ¯   >  üìüì91/<Äì290KSXííííY"²p]@V   && & 45 i|{y €‚‚  #,'( 4<VY ej vy •›]]! !###É-}-ÅþËþÄÕüøú+üúáÉ3Õ y@B¯6 üìüì991/<ì2990KSXííY"² ]@068HGif€ FIWXeiy…Š•šŸ ]]!3!#É–ÄþðýjÄÕûáú+áûsÿãÙð #@•• ‘Œ 3üìüì1äôìî0"32' ! 'ÜþýÜÜþÿÜ:xþˆþÆþÅþ‡yLþ¸þåþæþ¸HH¤þ[þžþŸþ[¤bb¥ÉÕ:@••   ? üì2üì91/ôìÔì0@ ?_¯]32654&#%!2+#“þššþ8ÈûþÿûþÊ/ýÏ’‡†’¦ãÛÝâý¨sþøÙð R@*  B ••‘Œ    3üìüì9991Ääôìî990KSXíí9Y""32#'# ! 'ÜþýÜÜþÿ? ôÝ!#þÅþ‡y;:xÑLþ¸þåþæþ¸HHúÏþÝï¥ab¥þ[þžþüþŽÉTÕ±@5  B• •   ?  üì2üÄì99991/<ôìÔì9990KSXíí9Y"²@]@Bz%%%&'&&& 66FFhuuwˆˆ˜˜]]#.+#! 32654&#A{>ÍÙ¿J‹xÜÊÈüƒý‰þ’••’¼~þh–bý‰ÕÖØºOýƒ…‡ÿã¢ð'~@<    B ¡”••”%‘Œ( "-"(ÜÄìüìä99991äôäìîöîÆ90KSXí9í9Y"²)]¶)/)O)].#"!"&'532654&/.54$32HsÌ_¥³w¦zâ×þÝþçjï€{ìr­¼‡š{âÊõiÚ¤Å76€vce+Ù¶Ùà0/ÐEFˆ~n|-À«Æä&ÿúéÕJ@•@@Ôäüä1/ôì20K° TX½@ÿÀ878Y@  @ p Ÿ ]!!#!ïýîËýîÕªúÕ+²ÿã)ÕK@ •Œ  8Aüìüì1ä2ôì99990K°TX½@ÿÀ878Y¶Ÿ]332653! ²Ë®Ã®ËþßþæþåþßÕüuðÓÓð‹ü\þÜþÖ*$hÕ·@'B¯ÔÄ91/ì290KSXííííY"²P]@b*GGZ}ƒ *&&))% 833<<7HEEIIGYVfiizvvyyu€˜—)]]!3 3JýÆÓÙÚÒýÇÕûéú+D¦Õ {@I      B ¯    ÔÌ91/<ì2290KSXííííííííY"²]@ò  ($ >>4 0 LMB @ Yjkg ` {|€ –•     !   # $ %  <:5306 9 ? 0FFJ@E@BBB@@ D M @@XVY Pfgab```d d d wv{xwtyywpx  †‡ˆ‰… Š —Ÿ¯[]]3 3 3# #DÌ:9ã:9Íþ‰þþÅþÂþÕûîûîú+úð=;Õ ]@F      B ¯   ÔÄÜÄ91/<ì290KSXííííííííY"K° TK° T[K°T[X½ ÿÀ @878Y@¸ '' 486 KX[fkww †€‡‹… ”—–     &()&(' ) 54<;:;4 4 8 ? H O X _ eejjhiil l xyyx}  x €€ƒˆ…„ƒ ”——•“ Ÿ ¯ @]]3 3 # #ÙsuÙþ Ùþ\þYÚÕýÕ+ý3üø{ý…ÿüçÕ”@(B¯@@ Ôäüä91/ì290KSXííííY"² ]@<5000F@@@QQQe„“ &)78@ ghxp Ÿ ]]3 3#Ùž›ÙýðËÕýšfüòý9Ç\Õ ›@B••B ÜÄÔä991/ìôì0KSXííY"K° TK° T[X½ @ ÿÀ878Y@@ )&8HGH    / 59? GJO UYfio wx Ÿ ]]!!!5!s•üPÇû=°ügÕšûoªš‘°þòXS@©²©±CÜüÌ21üìôì0K° TX½ÿÀ@878YK°TK°T[X½@ÿÀ878Y!#3!°¨ððþXùüÿB²Õ-@BŸ/Ä991ôì0KSXííY"#ªªýøÕùm“Çþòo<@©²©±Cü<Üì1üìôì0K°TK°T[X½ÿÀ@878Y!53#5oþXïïøÞÙ¨ÛÕ@ ÜÌ91ôÌ290##¼ÉþHþHÉÕýÓ‹þu-ÿìþþ¬µ©ÄÄ1Ôì0!5ûØþ¬ªð‰f1@ ´³DÜì1ôì0K° TK°T[X½ÿÀ@878Y #o™þºfþŠv{ÿã-{ %¼@'  ©¹ †º¹#¸Œ   E&üìÌÔì22991/ÄäôüôìÆîî9990@n0000 0!0"?'@@@@ @!@"PPPP P!P"P'p'…‡‡‡ ‡!…"' 'ð'000 0!@@@ @!PPP P!``` `!ppp p!€€€ €!]]"326=7#5#"&5463!54&#"5>32¾ß¬o™¹¸¸?¼ˆ¬Ëýû§—`¶Te¾Zóð3f{bsÙ´)LýªfaÁ¢½À‹..ª''üºÿ㤠8@¹  ¹Œ¸—G Füì22ôì1/ìäôÄìÆî0¶`€ ]4&#"326>32#"&'#3å§’’§§’’§ýŽ:±{ÌÿÿÌ{±:¹¹/ËççËËççRdaþ¼þøþøþ¼ad¨qÿãç{?@†ˆ† ˆ ¹¹¸Œ HEüä2ì1äôìþôîõî0@ € ].#"3267#"!2çNP³ÆÆ³PNM¥]ýþÖ-U¢5¬++ãÍÍã++ª$$>:#qÿãZ8@¹¹Œ¸—G Eüìôì221/ìäôÄìÄî0¶`€ ]3#5#"3232654&#"¢¸¸:±|ËÿÿË|±ýǧ’’¨¨’’§¶^ùì¨daDDaþËççËËççqÿã{p@$ †ˆ©¹ »¹¸ ŒKEüìôìÄ91äôìäîîôî90@)?p Ðð?????,// , ooooo ]q]!3267# 32.#"ü² Í·jÇbcÐkþôþÇ)ü⸥ˆš¹^Z¾Ç44®*,8 CþÝÄ—´®ž/øp@ ©‡—¼    Lü<Äü<ÄÄ991/ä2üìî2990K° TX½ÿÀ@878YK°TX½@ÿÀ878Y¶@P ]#"!!##535463ø°cM/þѹ°°®½™Phcü/ÑN»«qþVZ{ (J@#  †¹¹&#¸'¼ ¹½& G E)üÄìôì221/ÄäìäôÄìþÕî990¶`*€* *]4&#"326!"&'5326=#"3253¢¥•”¥¥”•¥¸þþúa¬QQžRµ´9²|ÎüüÎ|²9¸=ÈÜÜÈÇÜÜëþâþé³,*½¿[cb::bcªºd4@ ‡¸ — N  Füì2ôì1/<ìôÄì90²`]#4&#"#3>32d¸||•¬¹¹B³uÁƤý\žŸž¾¤ý‡ýžedïÁy+@¾±¼Fü<ì21/äüì0@  @ P ` p ]3#3#Á¸¸¸¸`û éÿÛþVy D@ ¾ ‡½¼ ±O  Fü<ì2ä991ìäôìî990@ @P`p]3+532653#Á¸£µF1iL¸¸`ûŒÖÀœa™(麜 ¼@)B¼— F üì2ÔÄ91/<ìä90KSXííííY"² ]@_ ')+Vfgsw‚‰Ž“–—£    ('(++@ h` ‰…‰š—ª§¶ÅÖ÷ð÷ð]q]33 ##º¹%ëý®kðýǹüiãýôý¬#ýÝÁy"·—Füì1/ì0@ @P`pð]3#Á¸¸ùìº{"Z@&  ‡ ¸¼PPF#üì2üüüì91/<<äô<Äì290@0$P$p$$ $ $¿$ß$ÿ$ ]>32#4&#"#4&#"#3>32)EÀ‚¯¾¹ru¦¹rw¦¹¹?°yz«‰|võâý\ž¡œ¾¤ý‡ž¢›¿£ý‡`®gb|ºd{6@ ‡¸ ¼ N  Füì2ôì1/<äôÄì90´`Ï]#4&#"#3>32d¸||•¬¹¹B³uÁƤý\žŸž¾¤ý‡`®edïqÿãu{ J@¹¹ ¸Œ QEüìôì1äôìî0@#?{{   {  { ð]"32654&'2#"s”¬«•“¬¬“ðþîðñþïßçÉÉçèÈÇéœþÈþìþíþÇ98ºþV¤{>@¹¹¸Œ½¼ GFüì22ôì1äääôÄìÄî0@ `€ à]%#3>32#"&4&#"326s¹¹:±{ÌÿÿÌ{±8§’’§§’’§¨ý® ªdaþ¼þøþøþ¼aëËççËËççqþVZ{ >@¹  ¹¸Œ½¼ GEüìôì221äääôÄìÆî0@ `€ à]32654&#"#"3253#/§’’¨¨’’§s:±|ËÿÿË|±:¸¸/ËççËËççý®daDDadªùöºJ{0@  ‡¸ ¼ FüÄì21/äôìÄÔÌ90´PŸ].#"#3>32JI,œ§¹¹:º….´˾ý²`®fcoÿãÇ{'ç@<  S  SB †‰†‰¹¹%¸Œ( R"E(üÄìÔìä99991äôìþõîõî90KSXí9í9Y"²']@m   . , , , ; ; ; ; $( ( *//*(() )!$'† † † †      '/)?)_))€)) )ð)]]q.#"#"&'532654&/.54632‹N¨Z‰‰b”?Ä¥÷ØZÃlfÆa‚Œe«@«˜àÎf´?®((TT@I!*™‰œ¶##¾55YQKP%$•‚ž¬7òž8@©¼‡  Fü<Äü<Ä2991/ìô<Äì2990²¯]!!;#"&5#53w{þ…Ks½½Õ¢‡‡žþÂý ‰NšŸÒ`>®ÿãX`6@ ‡Œ ¼  NFüìôì21/ä2ôÄì90´`Ï]332653#5#"&®¸||•­¸¸C±uÁȺ¦ýaŸŸ¾¤{û ¬fcð=`@'B¿ÔÄ91/ì290KSXííííY"K° TX½ÿÀ@878YK°TK°T[X½@ÿÀ878Y@ŽHj{†€‘¤  &&)) 55::0FFIIFH@VVYYPffiigh`ut{{uz……‰‰‰†––—š˜˜—¨§°Àßÿ>]]3 3#=Ã^^Ãþ\ú`üT¬û V5` @IU U U U   B ¿    ÔÌ91/<ì2290KSXííííííííY"K° TK°T[K°T[K°T[K° T[X½ ÿÀ @878YK° TK° T[K°T[X½ @ ÿÀ878Y@ÿ" 5 IIF @ [[U P nnf yy‡™˜” ¼¼ÎÇÏ         %%#'!%""%' $ ! # 9669 0FHF@B@@@D D D @@VVVPQRRPS T U cdejejjjn a g ouuy}x}zzxy  { v } ‡ˆ——”“œ›˜˜™@/– Ÿ¦¦¤¤««©©«¤ ¯µ±½»¸ ¿ÄÃÌÊy]]333# #V¸æåÙæå¸þÛÙñòÙ`ü–jü–jû –üj;y` Z@F      B ¿  ÔÄÔÄ91/<ì290KSXííííííííY"K° TK°T[K°T[K°T[X½ ÿÀ @878YK°TX½ @ ÿÀ878Y@˜   & =1 UWX f vzvt ‚ ™Ÿ—’ ¦©¯¥£       )&% * :9746 9 0 IFE J @ YVYYWVYVV Y P o x ›”«¤° Ï ß ÿ /]] # # 3 dþkªÙþºþºÙ³þrÙ))`ýßýÁ¸þHJþq=þV`¢@C        B  ‡½ ¼  ÔÄÄ91ä2ôì9990KSXíííííí2Y"K° TK°T[X½ÿÀ@878YK°TX½@ÿÀ878Y@ð     # 5 I O N Z Z j ‡ € “        '$$  )( % $ $ ' ** 755008 6 6 8 990A@@@@@@@@B E G II@TQQUPPVUVW W U U YYPffh ii`{xx‰Š … … ‰ ‰‰™ • • šš¤ ¤ ««°Ïßÿe]]+5326?3 3“N”|“lLT3!þ;Ã^^ÃhÈzšH†TNü”lXÛ` ´@B©¼© ÜÄ2Ä991/ìôì0KSXííY"K° TK° T[X½ @ ÿÀ878YK°TX½ ÿÀ @878Y@B&GI  + 690 @@E@@CWY_ ``f``b € ¯ ]]!!!5!qjýL´ü}´ýe`¨üÛ“¨%þ²$‚@4 %   ! © ©À ©±% $  C %Ô<Äü<Ä299999991üìÄôìî99999990K° TX½%ÿÀ%%@878Y²&]#"&=4&+5326=46;#"3>ù©lŽ==k©ù>DV[noZV¾”Ýï—ts•ðÝ“XøŽŽœøXþ®·±Ôì1üÌ0#®ªøþ²$ž@6%   ©©#À©±%#C %Ô<Ä2ü<Ä99999991üìÄôìî99999990K° TX½%@%%ÿÀ878YK°TX½%ÿÀ%%@878Y²&]326=467.=4&+532;#"+FŒUZooZUŒF?ù§lŽ>>Žl§ù?¾VøœŽŽøŽW“Ýð•st—ïÝ”ÙÓÛ1#@ œœ ÔÄ1ÔüÔìÀ990#"'&'&'&#"56632326Ûi³an’ ›^X¬bi³an“ ›^V©1²OD;>MS²OE<>LÿÿhN'$¼uhm !Ë@T   !!  ! !!!B  Á • Ž  !  VV!"ÔÄÔì2Ôî299999991/<æÖîÔî9990KSXííííííííY"² #]@  s › P#f iu {yyv v!€# ]]4&#"326!.54632#!#TY?@WX??Y˜þð!þX=>Ÿsr¡?<Òˆý_ˆÕZ?YWA?XXþóýN)sIs ¡rFv)ú‹þÿÿsþu'ð'&Ý-ÿÿÉ‹k'(žuÿÿÉ3^'1þuÿÿsÿãÙN'2'uÿÿ²ÿã)N'8îuÿÿ{ÿã-f'DRÿÿ{ÿã-f'DCRÿÿ{ÿã-f'D×Rÿÿ{ÿã-'DŽRÿÿ{ÿã-7'DØRÿÿ{ÿã-'DÜRÿÿqþuç{'FÝÿÿqÿãf'H‹ÿÿqÿãf'HC‹ÿÿqÿãf'H׋ÿÿqÿã'HŽ‹ÿÿof'ÖÿÿÿÿǦf'ÖCÿÿÿÿÞ\f'Ö×ÿÿÿÿôF'ÖŽÿÿÿºd7'Qؘÿÿqÿãuf'Rsÿÿqÿãuf'RCsÿÿqÿãuf'R×sÿÿqÿãu'RŽsÿÿqÿãu7'RØsÿÿ®ÿãXf'X{ÿÿ®ÿãXf'XC{ÿÿ®ÿãXf'X×{ÿÿ®ÿãX'XŽ{9ÿ;ÇÕ '@¹  YW Y Ô<ìü<ì1äôÔ<ì203!!#!5!¨°oþ‘°þ‘oÕþ\™û£]™Ãu=ð  @ÃÄà ‘ Z[ZÜìüì1ôìüì0"32654&'2#"&546PnnPPnoO@v+..¹†‡´¸ooPOmmOOp1.-rB„·´‡†º¬þÇ#˜!Q@+  †ˆ †ˆ ¹ ¹¸Œ"  "ÜìÔ<Ô<<ì221äô<ÄìÄþôîõî9990%&&'667#&73¦“¤¤JˆDF‰HA‰Mfñþ÷ ñfI‰ƒX⸹⡬)*ü *'ª#þä 32þá!bð`@!† ©  ”‘   Ü<ÌÌü<ÄÔÄ1/ì2ôäìÔ<î2î990K° TX½ÿÀ@878Y´66].#"!!!!53#535632NLˆ=”t‡þy-üìÇÇÖè=—´¶))›Ô×þ/ªªÑîó\ÿ=¢ð >‘@54&.#"#"&'532654/.5467.54632{?>‹ú?>ÌS8alÎÓƒ\]>9Ì­IšXW”:fqÝÖ€][;;ȦI™¨.Z.L…‡-[.Kˆ“¤''PGZswšeZŒ54m@ލ¤''TLf{x™f[1,pE‚Ÿ3Ñ…! · Ç \ Ôì1Ôì04632#"&3­~|«¬}}¬ú|««|}¬¬žÿ;9Õ %@Á]] ÔÔüÜì91Ä2ôì90!###&&54$yÀ¾Ž×ëÕùfùáNݸ¾èºÿã¬/š@0-'!  *†¹*¹—Œ.  !' $'$-F0üÄüÌÆîÔîî99991/äþîþÕî990@@'(Š Š     ! "&  : :!MM I!I"jj ¥¥¦ ]]4632#"&'532654&/.5467.#"#ºïÚÐÛ—¨:A9¦`áÓ@ˆIPŒAtx;e\`W§—ƒq‚ˆ»qÈÛèàs`/Q*%jŽd¬·¤_[?T>7;‡[¬gp‹ƒû“åÍ/8L`@6EBC?2ÉH0É9JCÊ 9ÊÉÈ É$HE301BKL?gwyVpMIßÑ`3þœDåÍ/IC@&=Ë>:ÌAÊ$1Ë04ÌGÊÉÈ$É 7aD=0^* D^ JÜÌüìþí2î1/îöþýîÖîýîÖî02#"$'&5476$"32676654&'&&&&#"3267#"&54632˜mmllmmþù˜˜þùmmllmm˜ƒâ^^``^^⃄ã^]]^\^ã§B‚B•§«›@zBC‰FØûûØIˆÍnmmþúš˜þûmmnnmm˜šmmng^^^å‚ã^^__^]⃅ã]^^õ! ¯Ÿ®"ôÐÑò'“FÕ >@!  É  b b cbcÔäüäÔìÔì91ô<<ì2Ô<<Ä903#######5J®¤ªqÃ7ËrqËrÉÕÿý¾äþÑ/þB^þä^sîRf1@ ´³DÔì1ôì0K° TK°T[X½ÿÀ@878Y3#‹Çþº™fþˆ×F)’@ÎÍddÜüÔì1ü<ì20K° TK° T[X½@ÿÀ878YK° TK° T[K°T[K°T[X½ÿÀ@878YK°TK°T[X½@ÿÀ878Y@````pppp]3#%3#^ËËþyËËÊÊÊÙ'ÛÝ>@" Ïœ Ï œ  Ü<Ä291Ô<Ì2ü<ìþ<ì990!!!!!'7!5!7!Ù}®/þHÃ{üúþþ}®þÕ¶Ãý‡¢;fÕ¨ðªþÇfÓªðHÕ‡@9  B• ••••­    ÔÔ<ì2ÔÄÄ91/<ììÄôììîî0KSXííííY"²€]@gww† …– ¿ ]!!!!!!#!5ýÇý9øü=ýð Íq‹þ¶ËÕªþFªýãªþÕžüðfÿºå +ž@< +,  )&  *&•& •‘&Œ,+,* # )#3,üìüìÀ999999991äôìîÀÀ99999990@*WZWU!je!{vu! FYVjddj(|svz( ]] 324&'.#"&5!27!"&''¶ý3>¡_Ü'y=¡_Üþý''†NOy;‚ÝW¢fªNPþˆþÆ€Ý[¢gXü²@CHp¸¸@Cþ¸þåp¼Džf b¥MK¿YÆgþöžþŸþ[KK¿XÝÝÏî /ÿ@- !$'!!0 $*0ÔÄÔÄ99991ÔÄÔÄÀ9990@¾     $$$   $$ $ ***///***55500055 5 :::???:::EEE@@@EE E JJJOOOJJJV´° °!°"°&°'°(´)]]32654&#".#"326#"&54632>32#"&“1†Te€vYR…Ä1…UfvYR†F^ˆº§†_™HDža†¼§†^•/XZ‡ie†‡7XX„je†ˆ‡ߦ¯Ø~ŠŠƒá§¯ÖwÙÛ .@МР œ   Ô<ì2ü<ì21/ìÔ<ìü<ì0!!#!5!!!®-ýÓ¨ýÓ-ýÓúþþ}ªþ}ƒªƒû¦ªÙÛ¨ T@.œœœœBѧœ $# ü<ì2291/ìôì90KSXííííY" 5!!Ûü@Àúþúþúþøþëþî²pªoüªÙÛ¨ V@/œœœœBѧœ$ # ü<<ì291/ìôì90KSXííííY"55!5ÙúþÁAúþø°þ‘ªþ²ýǪªRÃÕÆ@F  B Ó Ó   fe f eÔ<ì2ìüì2ì99991/ä2Ô<ì2Ô<ì290KSXííííY"K° TX½ÿÀ@878Y@(†¦ µ' ' ')((79‡ ˆ¦ ¥ª©]]!#!5!5'!5!3 3!!!þcÉþ` Tþ´þþ{y¿þÂþµTŸÇþ9Ç{3›{JýD¼ý¶{›3®þVå` M@% ‡Œ ¼½!   NF!üì2ôìÄ91ää2ô<ìÜÄ990¶"`"Ï"]3326533267#"&'#"&'®¸Š‡”•¸#% )I#ER2‘bf*þV ýH‘”¨¨ü¢<9 ”NPOONNý×hÿçÁ-)b@'! '!Õ* $$*ÔÌÜÌ9991äÌÜÌÎÎ990K° TK° T[K°T[K°T[K°T[X½*@**ÿÀ878Y>54&#"#"&54632#"&54324&#"32ôIH7$$0e´ÖþßÕ˜ËÝ¢e‚ WOmVPmmW£Kƒt,>bþÊþùþ±þFØ£Æ[àt}þþÏt{þw;Á ]@    ÔÄ91ÄÔÌÎ990@0QVPZ spvupz €€ Z pp{ t €€ ]]!! !!5 7êüA ýJïúÞÕýIÁÁý3ýÀ•!ãœþwqÁ@×Ö¯ggÔìÔì1üìì20!#!#œÕðý ïÁø¶}ùƒÿáÿðª/#Ë@1 ÚÙ"ØÕ $ #" #h#$ÔÔÔì9999991/<äôì22î9990K° TX½$ÿÀ$$@878Y@V             ##(]]#3267#"&5467!##"#>3!‡¶i/7.%7vy"PþºÂµÃ)6<  ¥y‘þJ\:1fd.¡xüo‘@E¦}/þú%&@ Û Ûܱ& iji&Üìüì1üìÜäÞä026732#"&'&&#"#"&546327j ¾ÊPd@7*8  k½ÄOeD=!0 þú°l9¼TA6?&#Hý•Ánþ!þbSA8?SsÕ;ð)_@3(%ãÝá%Ý ßÞÝ à‘* "(kl"k *ÜìÌüì22ÀÀ9991ôäüôìÄîíÖîî99990!!#5#"&5463354&#"56632"32655‹°ýP®•,]€˜¿¼¶uu>ˆDI‘E·³þì¡~bRh‚P{¸þ@p?D‡q‡Š[[""°ðCO@Mr`Õdð.@ãáÝ àÝ‘ klk Üìüì991ôìôìüì0!!2#"&546"32654&‹°ýPX³Îγ³Ðгi~hi}|P{Ý¿¿Ûܾ¿Ýs¡ˆ…  …‰ NÏç@@" å‘å  mm  ÔììÔììÀÀ9991/<ì2ôì0%!5654#"!5!&5! Ïý¨±ÆþøØØþ÷Dzý¨?ž‘1/Ž¡²²²aLÊð"þÝïÊþ´a²²‹*¸>ŠþwþËÂþØ{ÿão{3>@C'-%= 4©%†ˆ©:¹.†-º*¹»1 ¸Œ%?47&%7& =&-7"E?üìÌÔü<ÔìÄ999991Ää2ô<Ääü<ôìÄî2îôîî9990@0+0,0-0.0/00@+@,@-@.@/@0P+P,P-P.P/P0…+…0€@@ @°@À@Ð@à@à@ð@??? ??0,0-0.0/@,@-@.@/P,P-P.P/ooo oo`,`-`.`/p,p-p.p/€,€-€.€/]q].#">32!3267#"&'#"&5463!54&#"5>32"326=¶¥‰™¹DJÔ„âü² Ì·hÈddÐj§øMIؽÒýû§—`¶Te¾ZŽÕï߬o™¹”—´®ž0Z^þÝúZ¿È55®*,ywxx»¨½À‹..ª''`þf{bsÙ´)Hÿ¢œ¼ +ä@<+,&  )&  *&¹& ¹¸&Œ,+,* # #Q)E,üì2ôì2À9999991äôìîÀÀ99999990@p(?-YVUV jf!{    { z{ {!"#$%{&›•%¨ -ð-&YVUZ(ifej(ztvz(‰•š$¢­$]] 32654&'.#".5327#"&''‰þ)gA“¬\*g>—©}66ñ]ŸC‹_’56þîð`¡?‹`!ý°*(èÈOuš))ëÓHn.—MÅw834¨O³MÆxþíþÇ43¨Nÿã¬Õ $†@/ †ˆ !ƒ# •Œ#%" " "!& %ÜìÔüìÔì99991äôìþÍôî9990K°TK°T[K°T[X½%ÿÀ%%@878Y@ ttttv]33267#"&546?>7>5#53ô¾7ZZ:3ƒmN´`^Àg¸àIYX0&ÄÊÊDœe‚WX5^1YnFC¼98ŸL‰VV/5<6þ5Õ b@ƒ ü<ì2991/ôüÌ0K° TX½ @ ÿÀ878YK°TK°T[K°T[X½ ÿÀ @878Y¶ P ]#53#3ËËË¢×þú+eþ›ÙÛ^@ œÜÔì1ÔÄì0!#!Ù¨û¦^ýÁ•=ÿ×} *@    ÔÌ91ÔÌÄ903##'%\½sý®BþÁ}}`ùºs-Pbý;þV#Š@@   B   ©Šæ©Šæ©!—$  $ÔÌ91Ä2Äüìôìîöîî299990KSXí2í9Y"K° TX½$ÿÀ$$@878Y.#"!!#"&'53267#5!>32&P,`r<þÃ:¼º:d/4a/am"‰ø?$Æ—5dð¤z„þÉý…þãÓ¦!!‰¦­J·ÃÙÛô;?@.9*-" *œ19œ"œ œ<-<Ô<Ä21ÔìÔìÜüÔìÀ9999990#"'&'&'&#"56632326#"'&'&'&#"56632326Ûi³an’ ›^X¬bi³an“ ›^V©gi³an’ ›^X¬bi³an“ ›^V©o³NE;=LT³NE;=KÚ²OE;=LS²NE;=Kÿú`Á8@ÔÌ91/ÄÌ90@cmpxyvn]] !3!¬þ^DýïàCúšîûÄú?ž%# †@Ièèèè è è è  è B  ç¦ o o nüü<Ôì2991ô<ì2990KSXííííííííY"55%þÓ-þ+#þÓ-þ+#¿þôþô¿¢R¢¿þôþô¿¢RÁH# †@I è è è è èèèèB  ç¦ o opü<üÔ<ì991ô<ì2990KSXííííííííY"5%5ÁÕþ+-þÓ²Õþ+-þÓ#þ^Rþ^¿  ¿þ^Rþ^¿  ìþ #@ƒ   ÔüÔìÔì1/<<ì220%3#%3#%3#–ÔÔ©ÕÕú­ÕÕþþþþþþÿÿhk'$¼uÿÿh^'$¼uÿÿsÿãÙ^'2'us Õ;@•••­   üìÔÄÄÔì299991/ìì2ôì2î0!!!!! !# !3úýÇý9øû×þOþA¿±gþ¿þÀ@AÕªþFªýãª|pm|ªþáþàþßþßqÿãÃ{'3„@1†ˆ ©. ¹(¹»"%¸Œ4"1 K1 Q+E4üìôüôìÄ9991ä2ô<Ääì2Äî2îôî90@%?5_5p5Ÿ5Ï5Ð5ð5????? ooooo ]q].#"!3267#"&'#"32>32%"32654& ¤‰™¹Hü² Ì·jÈbdÐj òQGÑŒñþïñŒÓBNèâú°”¬«•“¬¬”˜³®ž5Z¾Ç44®*,nmnm98olkpþ݇çÉÉçèÈÇééy¶©é/Æ1üì0!!üyéyµ©/Ì1Ôì0!!øy®émÕ '@ž   ÜüÌÔÌþÔÎ1ô<ì20#53#53Ó¤RšÓ¤Ré­?þÁ­­?þÁ®émÕ '@ ž  ÜìÔÌÜîÔÎ1ô<ì203#%3#Ó¤RšÓ¤RÕ¬þÀ@¬¬þÀ@®éÓÕ@ žÜüÔÌ1ôì0#53Ó¤Ré­?þÁ²þ×Õ@ žqÜìÔÌ1ôì03#Ó¤RÕ˜þÁ?Ù–Ûo )@êêœ r ÜÔ<ü<Ä1ÔÄüÄîî03#3#!!ßööööýúúþoöþõAªþ#îu"@ÔÌ91ÔÌ990 úþþôþ þ üÏüÇ9%ûÛûÓ-ÿÿ=þV'\Ž^ÿÿÿüçN'<suþ‰ÿãÍð+@BŒ‘ÔÌ1ää0KSXííY"3#- ü\ ðùó^R¼²#/ƒ@I -'! - -¹ëì'¹ë!0 *$0* $ $(st*(s0Üäìôäì9999999991ÔäìôäìÀ9999999907'#"&''7&&5467'766324&#"326{ÏrÎ%$&(ÑrÏ;t=:x=ÏqÏ%%&&ÏsÏ7t@?s9ÏqÏ(&%%ÏsÎ>v:@t8ÎsÏ'%$þ|pššprœžs#G@%èèèèBç¦onüì291ôì90KSXííííY"5sþÓ-þ+#¿þôþô¿¢RÁ–#I@&èèèèBç¦opü<ì91ôì90KSXííííY"5ÁÕþ+-þÓ#þ^Rþ^¿  /J›@( ©‡¾±— ¼ Lü<Ä2Äü<Äî2991/<æ2îþîîî2990K° TX½ÿÀ@878YK°TX½@ÿÀ878Y@0P€€€ Ðï]]#!##53546;#"3#J¹þ¹°°­³¹°cMù¹¹`û Ñü/ÑN·¯™Phc²é/J„@! © ‡— ¼   Lü<ÄÄü<Äî991/<æ2þîî2990K° TX½ÿÀ@878YK°TX½@ÿÀ878Y@0P€ € € Ðï]!#!"!!##53546J¹þ·cM/þѹ°°®ùì{Phcü/ÑN»«9ÿ;ÇÕ>@ ¹¹  ÂY W Y Ô<<ì2ü<<ì21äôÄ2Ä2î2î20%!#!5!!5!3!!!Çþ‘°þ‘oþ‘o°oþ‘oßþ\¤š™¤þ\™ýáÛH®F·ƒÔì1Ôì03#ÛÓÓFþ®ÿÓþ@ žƒÔìÔÌ1üì0%3#Ó¤Rþ¬þÀ@®ÿmþ '@ žƒ   ÜìÔÌÜîÔÎ1ü<ì20%3#%3#šÓ¤RþfÓ¤Rþ¬þÀ@¬¬þÀ@qÿã Lð #'3?K®@D$%&%&'$'B@’ .’(’F’4 :&Œ$‘L%IC'1+C =  1 =I 7+ ! LüäìÔÄìäîîöîî991ä2ô<<ä2ì2îöîî20KSXííY"K°TK° T[K° T[K° T[K° T[K°T[X½L@LLÿÀ878Y"32654&'2#"&5462#"&546!3#"32654&2#"&546"32654&ôWddWUccUžº» º»ùtž¼»ŸŸ¹º% üZ VcbWWcd²žº» º»ŸWccWUcc‘”„‚••‚ƒ•Ü»»ÛÛ»¼ÛàÛ»½ÚÛ¼ºÜùóŽ•‚„””„–ýŸÜ»»ÛÛ»¼Û”„‚••‚ƒ•ÿÿhm'$¼uÿÿÉ‹m'(žuÿÿhk'$¼uÿÿÉ‹N'(žuÿÿÉ‹k'(žuÿÿ¢k',ÿ/uÿÿÿþ`m',ÿ/uÿÿXN',ÿ/uÿÿ;ºk',ÿ/uÿÿsÿãÙk'2'uÿÿsÿãÙm'2'uÿÿsÿãÙk'2'uÿÿ²ÿã)k'8îuÿÿ²ÿã)m'8îuÿÿ²ÿã)k'8îuÁy` ·¿Füì1/ì0@ @P`p]3#Á¸¸`û Áî?f7@ ´³uÜì91ôì290K° TK°T[X½ÿÀ@878Y3#'#¶”õ‹´´‹fþˆõõ¶J7c@$  Ãà íVwVvôìüì99991ü<üÔ<ì99990K° TK° T[X½ÿÀ@878Y'.#"#>3232673#"&ü9! &$}f[&@%9! &$}f[&@Z7IR‡“!7IR‡“Õb+ö/·ïîÔÌ1üì0K° TK°T[X½ÿÀ@878Y!!ÕVýªö”Ç)9H W@ ð³VVÜìÔì1ô<Ôì0K° TX½ÿÀ@878YK°TK°T[K°T[X½@ÿÀ878Y332673#"&Çv aWV` v ž‘‘žHKKJLšDf,@ ÎÍdÔì1üì0K° TX½ÿÀ@878Y3#šÌÌÌîá _@Áò ÁñV xVÔìôì1ôìôì0K° TK° T[X½ÿÀ@878YK° TK° T[K° T[X½ÿÀ@878Y4&#"3267#"&54632˜X@AWWA@XzŸssŸŸssŸô?XW@AWX@s  ssŸŸ#þuÁ@  ó' ÜÔìÔÌ1/ÔüÄ90!#"&'532654&'T76xv.W+"J/;<+->i0Y[ ƒ0.W=ðî®fB@´³ÔÜÔÌ991ô<ì20K° TK°T[X½ÿÀ@878Y3#3#ü²ø‡ªß‰fþˆxþˆLþuÁ @  óô 'ÔìÄÔÌ1/üüÄ90!33267#"&546¸w-+76 >&Dzs5=X..… W]0iÁî?f7@ ´³uÜì91ô<ì90K° TK°T[X½ÿÀ@878Y373¶õ‹´´‹õîxõõþˆÿòuÕ ?@ •  : yô<ìÄü<Ä991/äì90´0P]3%!!'7ÓË9Pþw×ü^”MáÕý˜Ûoþîýãª;jnžH ^@ — z z Ô<äü<ä991/ì90K°TX½ @ ÿÀ878Y@ @ P ` sz p à ð ]37#'7Ǹ}Lɸ{JÅý¦ZjüãšXjÿÿ‡ÿã¢m'6‹uÿÿoÿãÇf'Vàÿÿ\m'=¾uÿÿXÛf']àþ¢®˜@ õõÜ<ì21ÔìÔì0##®ªªª˜ý öý ö ºÕ g@  © ••  2  yô<ì2ÄôìÄ91/Æ2îöîî20@( °Ÿ Ÿ Ÿ Ÿ ŸŸŸŸ¿ ¿ ¿ ¿ ¿¿¿¿]]! )#53!!3 !Ó ±–þiþPþ`ÉÉËPþ°ó5þáþËÕþ—þ€þ~þ–¼ãþýê.,qÿãu('@^%{&%#${##{#({'(#&'('%$%(('"#" ! B('&%"! ##¹ ¹Œ#±)&' ! (%#" QE)üìôì99999991ìÄôìî9990KSXÉÉÉÉííííY"²?*]@v%+("/#/$)%-&-'*(6%F%X X!` `!f"u u!u"%#%$&&&''(6$6%F$E%Z Z!b b!z{     {zzv v!x" *ð*']].#"32654&#"5432''%'3%F2X)§¹®’‘®6 ~rþäæçþåÝ4*ŸþÁ!µäM!þÙ“ØÃ¼ÞÞ¼z¼&þà­ÿþÉ7ÿú7´kc\Ì‘oabÿÿÿüçk'<suÿÿ=þVf'\^ÉÕ =@• •ö  ? üì22üì91/ôüìÔì0@ ?_]332+#32654&#ÉÊþûþÿûþÊÊþš™ŽÕþøáÜÜâþ®'ýÑ’††‘ºþV¤>@¹¹Œ¸½— GFüì22ôì1ìääôÄìÆî0@ `€ à]%#3>32#"&4&#"326s¹¹:±{ÌÿÿÌ{±8§’’§§’’§¨ý®¾ý¢daþ¼þøþøþ¼aëËççËËççÙ-Û×¶œÔÄ1Ôì0!!Ùúþת?œÅ …@M œ  œœœœœ œ œ B   Ô<Ì291Ô<Ì290KSXííííííííY" '7œþ7Éwþ5þ5vÈþ8vËËLþ5þ7yËþ5yÉËyþ5ˉœÅß ,@Ý ÝÝ ÷‘ |]|| Üôäüä1ôììÔìî2035733!œÌßæ‰Íý× c)t'ý+n^œ´ðJ@$}}BÝÝ÷ Ý‘~ÜÄÔÄì91ôÄìüìî90KSXí2íY"!!56754&#"56632 ¨ýª"?XhU4zHM…9‘®þµ8rn81^BQ##{„l‹þä0bÍð(H@' Ý Ý Ý Ý ø÷Ý ø#‘)~&~ )ÜÄÄÔìÔì9991ôäìüäìÔìîî90#"&'532654&##532654&#"56632 \e¾±9}F4wCmxolV^^ad_(fQI€7©Z`mR|†yOFJLl?<:=svcE`ÿÿ‰ÿãð'ð'¼5 ‹ýdÿÿ‰ÿã?ð'ð'¼5ñ‹ýdÿÿbÿãð'ò'¼5 ‹ýdÿÿsÿã‹m'* uÿÿqþVZH'JÚ‹ÿÿÉ•P', ÿ/uÿÿ‡þu¢ð'6Ý‹ÿÿoþuÇ{'VÝÿÿsÿã'k'&-uÿÿqÿãçf'F‰ÿÿsÿã'm'&-uÿÿqÿãçf'Fà‰qÿãô$J@$Ó ù"¹¹ Œ¸—   GE%üìô<Äü<Ä1/ìäôÄìÄîý<î20¶`&€& &]!5!533##5#"3232654&#"¢þºF¸šš¸:±|ËÿÿË|±ýǧ’’¨¨’’§¶N}““}úü¨daDDaþËççËËççd߃¶œÜÌ1Ôì0!!dý僤ÛH®F·ƒÔì1Ôì03#ÛÓÓFþÿãð1@: Ó"+Ó ¡®•¡®•/‘Œ) 2+"!)#&  , & &*!/<ÔÄ2üÄÄ99999999991Ä2äôìôìîöîî2Ý<î20K° TK° T[K° T[K°T[K°T[K°T[X½2ÿÀ22@878Y@z  1Ti lnooooiko o!o"o#n$l%i'i-ŸŸŸ Ÿ Ÿ Ÿ Ÿ ŸŸŸŸŸŸ–Ÿ Ÿ!Ÿ"Ÿ#Ÿ$Ÿ%Ÿ&Ÿ'Ÿ(Ÿ)Ÿ*Ÿ+Ÿ,-2   USjg ]].#"!!!!3267#"#734&5465#7332[©fÊ A7ýæ¾8þŠ Êf©[Y¹`íþË(Ó7‹Â7œ(6ìb¹bÕiZÈ»{.# .{»ÊZiÓHH"{/ #/{"G×)Ù¥@ ÎddÔüÜì1Ô<ì20K°TK°T[X½@ÿÀ878YK°TK° T[K°T[X½ÿÀ@878YK°TK°T[X½@ÿÀ878YK°TX½ÿÀ@878Y@````pppp]3#%3#^ËËþyËËÙËËËsîðö@BúÄÀ1ôÌ0KSXÉÉY"K° TX½ÿÀ@878YK°TX½@ÿÀ878Y@ %%6FVjg //]]3#7¹ä™öþø¶Jéu@!  ÃÃúVV ÔìÔì99991ô<ìÔì2990K° TX½ÿÀ@878YK°TX½@ÿÀ878Y´ ]'.#"#4632326=3#"&ü9 $(}gV$=09" (}gT";9! 2-ev 3)dw î‹ö‰@BúÄÀ1ôÌ0KSXÉÉY"K° TX½ÿÀ@878YK°TX½@ÿÀ878Y@*$$5CUUŸŸ¯¯//]]#ÇÄ™æöþøÏî1øw@ úÔÄ91ô<Ä90K° TX½ÿÀ@878YK°TX½@ÿÀ878YK°TX½ÿÀ@878Y@ //- ]3#'#¢¼Ó‹¦¦‹øþö²²Ïî1ø†@ úÔÄ91ôÄ290K° TK° T[K° T[K° T[X½ÿÀ@878YK°TX½@ÿÀ878YK°TX½ÿÀ@878Y@ "  ]373¢Ó‹¦¦‹Óî ²²þö?œôß Ô@ Ý ÷‘ ] ÜÔ<Äì291ôüÔ<ì290K°TK°T[K°T[K°T[K° T[K° T[X½@ÿÀ878YK°TK°T[X½ÿÀ@878Y@T /9IFYi‹«»       "5GK S[ e„¥µ]] !33##5!5ÝþË5¦‡‡þbfþ]ýämººyÇ9ø j@à úVVÔìÔì1ôüÄ20K° TX½ÿÀ@878YK°TX½@ÿÀ878YK°TK°T[X½ÿÀ@878Y332673#"&Çv cSRav  Ÿø6978w{zšfÛ¶úÔÌ1ôÌ03#šÌÌÛÍ  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßà>: ~ÿ1BSax~’ÇÝ©À & 0 : ¬!""""+"H"e%Êûÿÿ   0AR^x}’ÆØ©À  0 9 ¬!""""+"H"`%ÊûÿÿÿãÿõÿØÿ ÿ^ÿCÿhÿüöüÛà–à…àVßjÞqÞ_Úï¿8ôüúúü (B¬£„…½–熎‹©¤ŠÙƒ“ñò—ˆÃÝðžªóôõ¢­ÉÇ®bcdËeÈÊÏÌÍÎèfÒÐѯgï‘ÕÓÔhêì‰jikmln oqprsutvwéxzy{}|¸¡~€ëíºýþÿøÖùúãä×àÚÛÜßØÞ²³¶·Ä´µÅ‚‡«˜¨š™î¼¥’”•Íf‹‹55®Å´žªšq=3ۤ=´Ù‹žãd‹Û²‡á–œdž¨‹²ð²ž´Ù´Ù´Ù?“‡y}É–s)ÉÉšÉ3sÉ\É\ÿ–?ÉuÉçÉüÉLsÓÉLsɇãÿúÛ²yéD{=ãÿü{\°²Ç´Ùÿìªç{ºfqqìqÑ/qº9Á9ÿÛ¢º9Á˺ºåqºqJº+o#7®¼=‹V¼;¼=3X²´Ùyy–sÉüÉLsÛ²ç{ç{ç{ç{ç{ç{fqìqìqìqìq99ÿÇ9ÿÞ9ÿôºåqåqåqåqåq®®®®9ì\¸3ž º's×´ÙËLfªÝ´Ù´Ù´ÙR®#hdœ¶ÿá+/ÅsÅ`NÛ{åH?55´Ù=´ÙZÿúåžåÁìyyLss/q%®%®‹®‹²´Ùô¼=ãÿüVþ‰^3ž3Á / /9‹Û‹®%® ¼qyÉyÉÉ\¢\ÿþ\\;LsLsLsÛ²Û²Û²9ÁÁ¶ÕÇšî#ðLÁÿòF‡+o{\3X²3 åqãÿü¼=×ɺ´Ù´5‰5^5bÁ‰Á‰Áb3sq\ɇ+o–sfq–sfqqãd‹Û×s¶ ÏÏ5?Çšÿ+   !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóõôöøùúûüýþÿ     sfthyphenperiodcenteredEuroc6459c6460c6461c6462c6463c6466c6467c6468c6469""""X“ÿ¶Oƒ²ö!n˜´ÊÞE‚~áL·üeÏî  R s ®  ß X ° û : i “ æ  = z /¬E…ëuñ)pཊëP‹±á@Ö"m¹#{ßC€øw³R¡Ø‡Äº‡wè [ r ó!5!B!â!ï!ü" ""#"0"="J"W"d"q"~"‹"˜"¥"²"¿"Ì"Ù"æ"ó## ##'#4#A#N#[#h#”#Ï$4$%3%S%&&º'K''·((X(Ã)_*%*\*£*é+z+Ó,D,,±-P- ..R.ª/‡0A0½11!1P1Ï2H2z2ß3F3p3p3}3Š3—3æ4z44£4Ñ4ÿ5595g5‘5ž5«5Ï6[6“6Í7C7©7ë888J999)969C9P9]9j9w9„9‘9ž9«9¸9Å9Ò9ï::{: :å;;^;Ž;Ä;ô<"<_<§<´<Á<Î<Û<þ=c>;>H>U>˜>ç>ý?a??Ü@:@K@\@m@z@‡@”@¡@®@»@È@Õ@âA@AVAkBEBªB÷C_C²CÿDUDÛE*E?-†” x$ÿÓ%ÿ·&')*K+-r./2934K57ÿD9ÿˆ:ÿ­;ÿš<ÿ =IQR&UYÿÉZ\ÿÜbÿÓdg9xy&z&{&|&}&‰­ÿÓ®ÿÓ¯9ºÿÜ»ÿ ÇÿÓÉÿÓÐ9Ñ9Ò9åéêÿ ëÿÜìöKûý$ÿÓ$ÿÜ$ÿÜ$$9$&ÿÜ$*ÿÜ$2ÿÜ$4ÿÜ$6$7ÿa$8$9ÿ}$:ÿ$;$<ÿa$FÿÜ$GÿÜ$HÿÜ$Iÿ·$RÿÜ$TÿÜ$WÿÜ$X$Yÿˆ$Zÿ­$\ÿu$b9$dÿÜ$gÿÜ$h$oÿÜ$pÿÜ$qÿÜ$rÿÜ$sÿÜ$yÿÜ$zÿÜ${ÿÜ$|ÿÜ$}ÿÜ$~$$€$$©ÿ·$ª$­9$®9$¯ÿÜ$´þø$µÿ$ºÿu$»ÿa$Å/$Ç9$É9$ÐÿÜ$ÑÿÜ$ÒÿÜ$Ó$Ô$Õ$ã$êÿa$ëÿu$öÿÜ$ù$ûÿÜ$üÿÜ$ýÿÜ$þÿÜ%%&ÿÜ%*ÿÜ%2ÿÜ%6ÿÜ%9ÿÁ%:ÿ·%<ÿ%dÿÜ%gÿÜ%©ÿÁ%ªÿÜ%¯ÿÜ%´ÿ%µÿ%»ÿ%Åÿ­%ÐÿÜ%ÑÿÜ%ÒÿÜ%ãÿÜ%êÿ%öÿÜ%ùÿÜ%ûÿÜ%ýÿÜ&&$&6&<ÿÜ&b&©ÿÜ&ªÿÜ&­&®&´&µ&&»ÿÜ&Å&Ç&É&ã&êÿÜ&ù''$ÿÜ'9ÿÜ':'<ÿ'bÿÜ'©ÿÜ'ªÿÜ'­ÿÜ'®ÿÜ'´ÿÓ'µÿÉ'»ÿ'ÅÿD'ÇÿÜ'ÉÿÜ'êÿ))þ·)ÿa)$ÿD)6ÿÜ)7ÿÜ)DÿD)Hÿ)Lÿk)Rÿ·)Uÿk)Xÿ)\ÿD)bÿD)iÿD)jÿD)kÿD)lÿD)mÿD)nÿD)pÿ)qÿ)rÿ)sÿ)yÿ·)zÿ·){ÿ·)|ÿ·)}ÿ·)~ÿ)ÿ)€ÿ)ÿ)©)ª)­ÿD)®ÿD)´ÿÓ)µ)ºÿD)Åþˆ)ÇÿD)ÉÿD)ãÿÜ)ëÿD)ùÿÜ**$*7ÿ·*:*<ÿš*b*©ÿÜ*ªÿÜ*­*®*´ÿÓ*µÿÓ*»ÿš*ÅÿÉ*Ç*É*êÿš++ÿÜ++©+ª+´ÿ·+µÿÁ+Åÿ·-ÿ·-$ÿÜ-bÿÜ-©ÿÜ-ªÿÜ-­ÿÜ-®ÿÜ-´ÿ·-µÿÁ-Åÿ-ÇÿÜ-ÉÿÜ.ÿ).$ÿÜ.&ÿ.2ÿ.7ÿa.8ÿÉ.:ÿ·.<ÿ·.DÿÜ.Hÿš.Rÿš.Xÿš.\ÿk.bÿÜ.dÿ.gÿ.hÿÉ.iÿÜ.jÿÜ.kÿÜ.lÿÜ.mÿÜ.nÿÜ.pÿš.qÿš.rÿš.sÿš.yÿš.zÿš.{ÿš.|ÿš.}ÿš.~ÿš.ÿš.€ÿš.ÿš.©ÿ}.ª.­ÿÜ.®ÿÜ.¯ÿ.´ÿÁ.µÿÁ.ºÿk.»ÿ·.Å.ÇÿÜ.ÉÿÜ.Ðÿ.Ñÿ.Òÿ.ÓÿÉ.ÔÿÉ.ÕÿÉ.êÿ·.ëÿk.ûÿ.ýÿ/ÿÜ/$//2ÿ·/7þæ/8ÿš/9ÿ/:ÿD/<þð/D/HÿÜ/RÿÜ/XÿÜ/\ÿD/b//gÿ·/hÿš/i/j/k/l/m/n/pÿÜ/qÿÜ/rÿÜ/sÿÜ/yÿÜ/zÿÜ/{ÿÜ/|ÿÜ/}ÿÜ/~ÿÜ/ÿÜ/€ÿÜ/ÿÜ/©/ª/­//®//¯ÿ·/´þa/µýæ/ºÿD/»þð/Å/Ç//É//Ðÿ·/Ñÿ·/Òÿ·/Óÿš/Ôÿš/Õÿš/êþð/ëÿD292ÿ­2ÿÜ2$ÿÜ29ÿÜ2;ÿ}2<ÿ2bÿÜ2©ÿÜ2ª2­ÿÜ2®ÿÜ2´ÿÓ2µÿÜ2»ÿ2ÅÿD2ÇÿÜ2ÉÿÜ2êÿ3ÿÓ3þÁ33$ÿ}383:3<ÿÓ3Dÿ¤3Hÿ·3LÿÓ3QÿÜ3Rÿ·3UÿÜ3VÿÜ3XÿÜ3\3bÿ}3h3iÿ¤3jÿ¤3kÿ¤3lÿ¤3mÿ¤3nÿ¤3pÿ·3qÿ·3rÿ·3sÿ·3xÿÜ3yÿ·3zÿ·3{ÿ·3|ÿ·3}ÿ·3~ÿÜ3ÿÜ3€ÿÜ3ÿÜ3©ÿÜ3ª3­ÿ}3®ÿ}3´&3µ&3º3»ÿÓ3Åþ·3Çÿ}3Éÿ}3Ó3Ô3Õ3äÿÜ3êÿÓ3ë3úÿÜ494©4ª4´ÿÓ4µÿÜ4Åÿ}5ÿ­5ÿ·5ÿÁ5$ÿ­5&ÿš57ÿk59ÿ5:ÿ­5<ÿ}5DÿÓ5Hÿ¤5Rÿ¤5Xÿ¤5\ÿ5bÿ­5dÿš5iÿÓ5jÿÓ5kÿÓ5lÿÓ5mÿÓ5nÿÓ5pÿ¤5qÿ¤5rÿ¤5sÿ¤5yÿ¤5zÿ¤5{ÿ¤5|ÿ¤5}ÿ¤5~ÿ¤5ÿ¤5€ÿ¤5ÿ¤5©ÿ5ªÿÜ5­ÿ­5®ÿ­5´ÿk5µÿ}5ºÿ5»ÿ}5ÅÿÜ5Çÿ­5Éÿ­5êÿ}5ëÿ5ûÿš5ýÿš6$&6&6*6264666b&6d6g6­&6®&6¯6Ç&6É&6Ð6Ñ6Ò6ã6ö6ù6û6ý7ÿD7ÿ 7ÿ7$ÿa7&ÿˆ77ÿÜ7Dþ­7Fþ¤7Hþ¤7LÿÁ7Rþ¤7UþÓ7Vþ­7XþÉ7Zþ­7\þÁ7bÿa7dÿˆ7iþ­7jþ­7kþ­7lþ­7mþ­7nþ­7oþ¤7pþ¤7qþ¤7rþ¤7sþ¤7yþ¤7zþ¤7{þ¤7|þ¤7}þ¤7~þÉ7þÉ7€þÉ7þÉ7©ÿD7ªÿ7­ÿa7®ÿa7´7µÿÓ7ºþÁ7Åþø7Çÿa7Éÿa7äþ­7ëþÁ7úþ­7ûÿˆ7üþ¤7ýÿˆ7þþ¤8$8-8=ÿÜ8b8­8®8Ç8É8åÿÜ9ÿˆ9þø9ÿY9$ÿ}92ÿÜ9Dÿa9Hÿa9LÿÓ9Rÿa9Xÿu9\ÿÉ9bÿ}9gÿÜ9iÿa9jÿa9kÿa9lÿa9mÿa9nÿa9pÿa9qÿa9rÿa9sÿa9yÿa9zÿa9{ÿa9|ÿa9}ÿa9~ÿu9ÿu9€ÿu9ÿu9©ÿN9ªÿ9­ÿ}9®ÿ}9¯ÿÜ9´9µ9ºÿÉ9Åþæ9Çÿ}9Éÿ}9ÐÿÜ9ÑÿÜ9ÒÿÜ9ëÿÉ:ÿ­:ÿ:ÿˆ:$ÿ:Dÿ}:Hÿˆ:LÿÓ:Rÿˆ:Uÿ¤:Xÿ·:\ÿÜ:bÿ:iÿ}:jÿ}:kÿ}:lÿ}:mÿ}:nÿ}:pÿˆ:qÿˆ:rÿˆ:sÿˆ:yÿˆ:zÿˆ:{ÿˆ:|ÿˆ:}ÿˆ:~ÿ·:ÿ·:€ÿ·:ÿ·:©ÿ:ªÿÜ:­ÿ:®ÿ:´ÿÜ:µ:ºÿÜ:Åþø:Çÿ:Éÿ:ëÿÜ;ÿš;$;&ÿk;2ÿ};7ÿÜ;Hÿ¤;b;dÿk;gÿ};pÿ¤;qÿ¤;rÿ¤;sÿ¤;©ÿ;ª;­;®;¯ÿ};´ÿa;µÿ­;ÅÿÓ;Ç;É;Ðÿ};Ñÿ};Òÿ};ûÿk;ýÿk<ÿ <þa<þð<$ÿa<&ÿ<2ÿ<Dþæ<Hþð<Lÿ·<Rþð<Xÿ<bÿa<dÿ<gÿ<iþæ<jþæ<kþæ<lþæ<mþæ<nþæ<pþð<qþð<rþð<sþð<yþð<zþð<{þð<|þð<}þð<~ÿ<ÿ<€ÿ<ÿ<©ÿ<ªÿk<­ÿa<®ÿa<¯ÿ<´ÿ<µÿÜ<Åþø<Çÿa<Éÿa<Ðÿ<Ñÿ<Òÿ<ûÿ<ýÿ=ÿÜ=©=ª=´ÿÜ=µÿÜ=ÅÿÜH[ÿÜIÿIÿkIÿ·IWÿÜIZÿÜI\ÿÜI©ÿ·IªÿÜI´AIµIºÿÜIÅÿIëÿÜNDÿÜNHÿ·NRÿ·NXÿÁN\ÿ·NiÿÜNjÿÜNkÿÜNlÿÜNmÿÜNnÿÜNpÿ·Nqÿ·Nrÿ·Nsÿ·Nyÿ·Nzÿ·N{ÿ·N|ÿ·N}ÿ·N~ÿÁNÿÁN€ÿÁNÿÁNºÿ·Nëÿ·QQQQ©QªQ´ÿkQµÿQÅÿ¤R&RÿÜRR[ÿÁR©RªR´ÿkRµÿ·RÅÿ}Uÿ}UÿDUÿÜUFÿÓUGÿÜUHÿÓUIUJÿÜUKÿÜUPÿÜUQÿÜURÿÓUTÿÜUUÿÜUXUYUZU[ÿÉU\U]UoÿÓUpÿÓUqÿÓUrÿÓUsÿÓUxÿÜUyÿÓUzÿÓU{ÿÓU|ÿÓU}ÿÓU~UU€UU©ÿ·UªU´UµVUºUÅþÉUæUëU÷ÿÜUüÿÓUþÿÓYÿÉYÿaYÿY©ÿÜYªÿÜY´YµÿÜYÅþðZZÿDZÿZ©ÿÜZªÿÜZ´ZµZÅÿ)[FÿÜ[HÿÁ[RÿÁ[oÿÜ[pÿÁ[qÿÁ[rÿÁ[sÿÁ[yÿÁ[zÿÁ[{ÿÁ[|ÿÁ[}ÿÁ[üÿÜ[þÿÜ\ÿÜ\þÜ\ÿk\©ÿÜ\ªÿÜ\´\µ\ÅþÓbÿÓbÿÜbÿÜb$9b&ÿÜb*ÿÜb2ÿÜb4ÿÜb6b7ÿab8b9ÿ}b:ÿb;b<ÿabFÿÜbGÿÜbHÿÜbIÿ·bRÿÜbTÿÜbWÿÜbXbYÿˆbZÿ­b\ÿubb9bdÿÜbgÿÜbhboÿÜbpÿÜbqÿÜbrÿÜbsÿÜbyÿÜbzÿÜb{ÿÜb|ÿÜb}ÿÜb~bb€bb©ÿ·bªb­9b®9b¯ÿÜb´þøbµÿbºÿub»ÿabÅ/bÇ9bÉ9bÐÿÜbÑÿÜbÒÿÜbÓbÔbÕbãbêÿabëÿuböÿÜbùbûÿÜbüÿÜbýÿÜbþÿÜdd$d6d<ÿÜdbd©ÿÜdªÿÜd­d®d´dµ&d»ÿÜdÅdÇdÉdãdêÿÜdùg9gÿ­gÿÜg$ÿÜg9ÿÜg;ÿ}g<ÿgbÿÜg©ÿÜgªg­ÿÜg®ÿÜg´ÿÓgµÿÜg»ÿgÅÿDgÇÿÜgÉÿÜgêÿh$h-h=ÿÜhbh­h®hÇhÉhåÿÜp[ÿÜq[ÿÜr[ÿÜs[ÿÜxxxx©xªx´ÿkxµÿxÅÿ¤y&yÿÜyy[ÿÁy©yªy´ÿkyµÿ·yÅÿ}z&zÿÜzz[ÿÁz©zªz´ÿkzµÿ·zÅÿ}{&{ÿÜ{{[ÿÁ{©{ª{´ÿk{µÿ·{Åÿ}|&|ÿÜ||[ÿÁ|©|ª|´ÿk|µÿ·|Åÿ}}&}ÿÜ}}[ÿÁ}©}ª}´ÿk}µÿ·}Åÿ}‰&‰©‰ª‰´ÿ‰µÿ‰Åÿ­©ª´ÿ­µÿ¤Åÿ©$©%ÿÜ©&ÿÜ©'ÿÜ©)©*ÿÜ©+©-ÿÜ©.©/©2©3©4©5©7ÿ©9ÿ©:ÿÜ©;©<ÿk©=©I©Q©R©U©YÿÜ©ZÿÜ©\ÿÜ©b©dÿÜ©g©x©y©z©{©|©}©‰©—©­©®©¯©ºÿÜ©»ÿk©Ç©É©Ð©Ñ©Ò©å©é©êÿk©ëÿÜ©ì©öÿÜ©ûÿÜ©ýÿܪ$ÿ·ª%ÿ·ª&ÿܪ'ÿܪ)ª*ª+ª-ÿܪ.ª/ª2ÿܪ3ª4ª5ª7ÿDª9ÿNª:ÿª;ÿª<ÿª=ªIªQªRªUªYÿܪZÿܪ\ÿܪbÿ·ªdÿܪgÿܪxªyªzª{ª|ª}ª‰ªª­ÿ·ª®ÿ·ª¯ÿܪºÿܪ»ÿªÇÿ·ªÉÿ·ªÐÿܪÑÿܪÒÿܪåªéªêÿªëÿܪìªöªûÿܪýÿÜ­ÿÓ­ÿÜ­ÿÜ­$9­&ÿÜ­*ÿÜ­2ÿÜ­4ÿÜ­6­7ÿa­8­9ÿ}­:ÿ­;­<ÿa­FÿÜ­GÿÜ­HÿÜ­Iÿ·­RÿÜ­TÿÜ­WÿÜ­X­Yÿˆ­Zÿ­­\ÿu­b9­dÿÜ­gÿÜ­h­oÿÜ­pÿÜ­qÿÜ­rÿÜ­sÿÜ­yÿÜ­zÿÜ­{ÿÜ­|ÿÜ­}ÿÜ­~­­€­­©ÿ·­ª­­9­®9­¯ÿÜ­´þø­µÿ­ºÿu­»ÿa­Å/­Ç9­É9­ÐÿÜ­ÑÿÜ­ÒÿÜ­Ó­Ô­Õ­ã­êÿa­ëÿu­öÿÜ­ù­ûÿÜ­üÿÜ­ýÿÜ­þÿÜ®ÿÓ®ÿÜ®ÿÜ®$9®&ÿÜ®*ÿÜ®2ÿÜ®4ÿÜ®6®7ÿa®8®9ÿ}®:ÿ®;®<ÿa®FÿÜ®GÿÜ®HÿÜ®Iÿ·®RÿÜ®TÿÜ®WÿÜ®X®Yÿˆ®Zÿ­®\ÿu®b9®dÿÜ®gÿÜ®h®oÿÜ®pÿÜ®qÿÜ®rÿÜ®sÿÜ®yÿÜ®zÿÜ®{ÿÜ®|ÿÜ®}ÿÜ®~®®€®®©ÿ·®ª®­9®®9®¯ÿÜ®´þø®µÿ®ºÿu®»ÿa®Å/®Ç9®É9®ÐÿÜ®ÑÿÜ®ÒÿܮӮԮծã®êÿa®ëÿu®öÿÜ®ù®ûÿÜ®üÿÜ®ýÿÜ®þÿܯ9¯ÿ­¯ÿܯ$ÿܯ9ÿܯ;ÿ}¯<ÿ¯bÿܯ©ÿܯª¯­ÿܯ®ÿܯ´ÿÓ¯µÿܯ»ÿ¯ÅÿD¯ÇÿܯÉÿܯêÿ´$þø´%ÿÁ´&ÿ·´'ÿÁ´)ÿÁ´*ÿ·´+ÿÁ´-ÿÁ´.ÿÁ´/ÿÁ´2ÿ·´3ÿÁ´4ÿ·´5ÿÁ´7´9´:´;ÿˆ´<´=ÿÜ´Iÿ·´Qÿ´Rÿk´Uÿ´Yÿ·´Zÿ·´\ÿ·´bþø´dÿ·´gÿ·´xÿ´yÿk´zÿk´{ÿk´|ÿk´}ÿk´‰ÿÁ´þ}´­þø´®þø´¯ÿ·´ºÿ·´»´Çþø´Éþø´Ðÿ·´Ñÿ·´Òÿ·´åÿÜ´éÿ·´ê´ëÿ·´ìÿÁ´öÿ·´ûÿ·´ýÿ·ºÿܺþܺÿkº©ÿܺªÿܺ´ºµºÅþÓ»ÿ »þa»þð»$ÿa»&ÿ»2ÿ»Dþæ»Hþð»Lÿ·»Rþð»Xÿ»bÿa»dÿ»gÿ»iþæ»jþæ»kþæ»lþæ»mþæ»nþæ»pþð»qþð»rþð»sþð»yþð»zþð»{þð»|þð»}þð»~ÿ»ÿ»€ÿ»ÿ»©ÿ»ªÿk»­ÿa»®ÿa»¯ÿ»´ÿ»µÿÜ»Åþø»Çÿa»Éÿa»Ðÿ»Ñÿ»Òÿ»ûÿ»ýÿÅ$&Å%ÿ·Å&ÿÅ'ÿ·Å)ÿ·Å*ÿ·Å+ÿ·Å-/Å.ÿ·Å/ÿ·Å2ÿÅ3ÿ·Å4ÿÅ5ÿ·Å7þæÅ9þˆÅ:ÿÅ;ÿ·Å<þˆÅ=ÅIÿÜÅQÿ·ÅRÿ·ÅUÿ·ÅYÿÅZÿ<Å\ÿÅb&ÅdÿÅgÿÅxÿ·Åyÿ·Åzÿ·Å{ÿ·Å|ÿ·Å}ÿ·Å‰ÿ·Å&Å­&Å®&ůÿźÿÅ»þˆÅÇ&ÅÉ&ÅÐÿÅÑÿÅÒÿÅåÅéÿ·ÅêþˆÅëÿÅìÿ·Åöÿ·ÅûÿÅýÿÇÿÓÇÿÜÇÿÜÇ$9Ç&ÿÜÇ*ÿÜÇ2ÿÜÇ4ÿÜÇ6Ç7ÿaÇ8Ç9ÿ}Ç:ÿÇ;Ç<ÿaÇFÿÜÇGÿÜÇHÿÜÇIÿ·ÇRÿÜÇTÿÜÇWÿÜÇXÇYÿˆÇZÿ­Ç\ÿuÇb9ÇdÿÜÇgÿÜÇhÇoÿÜÇpÿÜÇqÿÜÇrÿÜÇsÿÜÇyÿÜÇzÿÜÇ{ÿÜÇ|ÿÜÇ}ÿÜÇ~ÇÇ€ÇÇ©ÿ·ÇªÇ­9Ç®9ǯÿÜÇ´þøÇµÿǺÿuÇ»ÿaÇÅ/ÇÇ9ÇÉ9ÇÐÿÜÇÑÿÜÇÒÿÜÇÓÇÔÇÕÇãÇêÿaÇëÿuÇöÿÜÇùÇûÿÜÇüÿÜÇýÿÜÇþÿÜÉÿÓÉÿÜÉÿÜÉ$9É&ÿÜÉ*ÿÜÉ2ÿÜÉ4ÿÜÉ6É7ÿaÉ8É9ÿ}É:ÿÉ;É<ÿaÉFÿÜÉGÿÜÉHÿÜÉIÿ·ÉRÿÜÉTÿÜÉWÿÜÉXÉYÿˆÉZÿ­É\ÿuÉb9ÉdÿÜÉgÿÜÉhÉoÿÜÉpÿÜÉqÿÜÉrÿÜÉsÿÜÉyÿÜÉzÿÜÉ{ÿÜÉ|ÿÜÉ}ÿÜÉ~ÉÉ€ÉÉ©ÿ·ÉªÉ­9É®9ɯÿÜÉ´þøÉµÿɺÿuÉ»ÿaÉÅ/ÉÇ9ÉÉ9ÉÐÿÜÉÑÿÜÉÒÿÜÉÓÉÔÉÕÉãÉêÿaÉëÿuÉöÿÜÉùÉûÿÜÉüÿÜÉýÿÜÉþÿÜÐ9Ðÿ­ÐÿÜÐ$ÿÜÐ9ÿÜÐ;ÿ}Ð<ÿÐbÿÜЩÿÜЪЭÿÜЮÿÜдÿÓеÿÜлÿÐÅÿDÐÇÿÜÐÉÿÜÐêÿÑ9Ñÿ­ÑÿÜÑ$ÿÜÑ9ÿÜÑ;ÿ}Ñ<ÿÑbÿÜÑ©ÿÜѪѭÿÜÑ®ÿÜÑ´ÿÓѵÿÜÑ»ÿÑÅÿDÑÇÿÜÑÉÿÜÑêÿÒ9Òÿ­ÒÿÜÒ$ÿÜÒ9ÿÜÒ;ÿ}Ò<ÿÒbÿÜÒ©ÿÜÒªÒ­ÿÜÒ®ÿÜÒ´ÿÓÒµÿÜÒ»ÿÒÅÿDÒÇÿÜÒÉÿÜÒêÿÓ$Ó-Ó=ÿÜÓbÓ­Ó®ÓÇÓÉÓåÿÜÔ$Ô-Ô=ÿÜÔbÔ­Ô®ÔÇÔÉÔåÿÜÕ$Õ-Õ=ÿÜÕbÕ­Õ®ÕÇÕÉÕåÿÜã$&ã&ã*ã2ã4ã6ãb&ãdãgã­&ã®&ã¯ãÇ&ãÉ&ãÐãÑãÒãããöãùãûãýåÿÜå©åªå´ÿÜåµÿÜåÅÿÜéé©éªé´ÿ¤éµÿéÅÿ·êÿ êþaêþðê$ÿaê&ÿê2ÿêDþæêHþðêLÿ·êRþðêXÿêbÿaêdÿêgÿêiþæêjþæêkþæêlþæêmþæênþæêpþðêqþðêrþðêsþðêyþðêzþðê{þðê|þðê}þðê~ÿêÿê€ÿêÿê©ÿêªÿkê­ÿaê®ÿaê¯ÿê´ÿêµÿÜêÅþøêÇÿaêÉÿaêÐÿêÑÿêÒÿêûÿêýÿëÿÜëþÜëÿkë©ÿÜëªÿÜë´ëµëÅþÓììÿkìÿ·ì©ìªì´ÿÜìµìÅÿDöö$ö7ÿ·ö:ö<ÿšöbö©ÿÜöªÿÜö­ö®ö´ÿÓöµÿÓö»ÿšöÅÿÉöÇöÉöêÿšù$&ù&ù*ù2ù4ù6ùb&ùdùgù­&ù®&ù¯ùÇ&ùÉ&ùÐùÑùÒùãùöùùùûùýûû$û6û<ÿÜûbû©ÿÜûªÿÜû­û®û´ûµ&û»ÿÜûÅûÇûÉûãûêÿÜûùýý$ý6ý<ÿÜýbý©ÿÜýªÿÜý­ý®ý´ýµ&ý»ÿÜýÅýÇýÉýãýêÿÜýù MB@hmþ ¼þ‰þ‰ L GÌþBGÌSf €¯ JBits@ ûþšmãB±‹`#cÕVeraSansÿÿÿÿ6ÿÿþ628R00@                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        "                      "       #                       #     $               $    &              &    ÿÿ P ì_<õº¹ð¸ºÂg‘þ‰þ Lmfreewheeling-0.6.6/data/fonts/truetype/ttf-bitstream-vera/VeraBd.ttf000066400000000000000000001625341370736313100255330ustar00rootroot00000000000000OS/2µ‰÷=Ï@VPCLT,e‰Ï˜6cmap¤Ãè ­¸Xcvt >¹-âRfpgmÆp9)Œgaspå glyf4Þh¥)„&hdmxE¼úÏÐHheadóO«“å$6hhea. Ï$hmtxyò€®±,kernÔê¹ÜlocaXùz[·Ämaxp}Îü name·YÍ¿ëpostø¡xúµ<†prep|a¢ç!\§::N:: R^0±p  ‡ t t Ÿ &   ; 0  0   C , [ `   0­ & ‡Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved.Bitstream Vera Sans BoldRelease 1.10BitstreamVeraSans-BoldCopyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Bitstream Vera is a trademark of Bitstream, Inc. Permission is hereby granted, free of charge, to any person obtaining a copy of the fonts accompanying this license ("Fonts") and associated documentation files (the "Font Software"), to reproduce and distribute the Font Software, including without limitation the rights to use, copy, merge, publish, distribute, and/or sell copies of the Font Software, and to permit persons to whom the Font Software is furnished to do so, subject to the following conditions: The above copyright and trademark notices and this permission notice shall be included in all copies of one or more of the Font Software typefaces. The Font Software may be modified, altered, or added to, and in particular the designs of glyphs or characters in the Fonts may be modified and additional glyphs or characters may be added to the Fonts, only if the fonts are renamed to names not containing either the words "Bitstream" or the word "Vera". This License becomes null and void to the extent applicable to Fonts or Font Software that has been modified and is distributed under the "Bitstream Vera" names. The Font Software may be sold as part of a larger software package but no copy of one or more of the Font Software typefaces may be sold by itself. THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL BITSTREAM OR THE GNOME FOUNDATION BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE. Except as contained in this notice, the names of Gnome, the Gnome Foundation, and Bitstream Inc., shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Font Software without prior written authorization from the Gnome Foundation or Bitstream Inc., respectively. For further information, contact: fonts at gnome dot org.http://www.bitstream.comCopyright (c) 2003 by Bitstream, Inc. All Rights Reserved.Bitstream Vera Sans BoldRelease 1.10BitstreamVeraSans-BoldCopyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Bitstream Vera is a trademark of Bitstream, Inc. Permission is hereby granted, free of charge, to any person obtaining a copy of the fonts accompanying this license ("Fonts") and associated documentation files (the "Font Software"), to reproduce and distribute the Font Software, including without limitation the rights to use, copy, merge, publish, distribute, and/or sell copies of the Font Software, and to permit persons to whom the Font Software is furnished to do so, subject to the following conditions: The above copyright and trademark notices and this permission notice shall be included in all copies of one or more of the Font Software typefaces. The Font Software may be modified, altered, or added to, and in particular the designs of glyphs or characters in the Fonts may be modified and additional glyphs or characters may be added to the Fonts, only if the fonts are renamed to names not containing either the words "Bitstream" or the word "Vera". This License becomes null and void to the extent applicable to Fonts or Font Software that has been modified and is distributed under the "Bitstream Vera" names. The Font Software may be sold as part of a larger software package but no copy of one or more of the Font Software typefaces may be sold by itself. THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL BITSTREAM OR THE GNOME FOUNDATION BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE. Except as contained in this notice, the names of Gnome, the Gnome Foundation, and Bitstream Inc., shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Font Software without prior written authorization from the Gnome Foundation or Bitstream Inc., respectively. For further information, contact: fonts at gnome dot org.http://www.bitstream.comf3f¼é=¢úff¬Tì¼bf…Tfm¤fÍ3bq%¤¼ºåfHZfmöÃð99Xm=²²fuf°f9Ñœ{Ï{X3fLfL¬šJ#ššDDÍÁf?š;ËËÕÕP¬¬w Çò/X²#öö/55îç3˜ÑX š˜¼ÍååòsfÕ+ÕÃá×åj-ÕÕð¨jìáÕ!føìƒ¦ø#^Í`lj켺3B3\Õššáfy```{ìø;ÝÕj\{šÝ®º…®`bššXîššÑÍšPËË‹‹1öðL`¨Á%Á!J–Jƒ¨7{ÉÁÁÁÁ–'žì}3˜ÑXyÍ9bœœœ“¸“¸sA„€&þ%$!:$ú#"!:"þ!: ú»dþþþþþþþþþ}þ}  Œ þ À  Y Œ €  & Y @ & þþ €²—.Aúúþúú@ÿ}ÿ>þþüû,üþû,úþùøGù}øG÷úöþõþôþó»òþñþðþïîþíì íþì ì@ëê ë2ê éúè‘èþçúæúå‘åþäþãþâþáþàþßþÞúÝÜÝdÜÛ ÛdÚÙ%ÚúÙ%ØÑ%Øú×Ö×ÖÕÖÕÔÓ Ô Ó ÒÑ%ÒúÑ‘Ñ%Д Ð#ÏÎÏ&ÎÍÎÍÌ‘ÌËÊÉ»ÊþÉÈ]ɻɀÈ@ÿÇ%È]È@Ç%ÆþÅdÄÄþÃÂþÁþÀ¿:Àú¿­¿:¾½¾2½¼½¼»¼»º »º ¹‘¹þ¸þ·¶µþ´þ³þ²±°¯­¯ú®­®ú­‘­¬‘¬}«þª&©þ¨þ§þ¦þ¥ ¤þ£¢£þ¢¢@¡ ¡ú ‘ Ÿ‘Ÿúž” žþœ›»œþ›š]›»›€š%š]š@™þ˜—.˜þ—.–‘–@ÿ•” • ” “‘“K’‘’þ‘‘%ŽþþŒþ‹þŠþ‰þˆ‡%ˆþ‡%†þ…þ„2ƒ–‚þþ€ ~þ}þ|þ{úzúyþwv¦wþv¦utuútsúr}qþpo,o,númúlúkþjþiþhc h2gþf2ed eþd d@cb c b a`a–``_ ^þ]þ\\þ[Z[þZZYþXúWþV@ÿVþUþTSRQRúQQPOPúONONMLKLKJKJIJIHúGFGFEúDCDCBA%BúAA%@?@þ?>?>=< =< ;d:þ98þ7656%5455À4 44€32 33@2 10¦1þ00¦/ .-,:-ú,%,:+d*d)þ(''& %$#@+$#" "ú!!@  %¸@‘ K}Kþ%ú%dþþdÀ€  ú 2   €  @ þþþ þ @údþ  ¸d…++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++¶, °%Id°@QX ÈY!-,°%Id°@QX ÈY!-,  °P° y ¸ÿÿPXY°°%°%#á °P° y ¸ÿÿPXY°°%á-,KPX ¸(EDY!-,°%E`D-,KSX°%°%EDY!!-,ED-fþ–f¤¼&&¶‰/ÄÔì1ÔìÔì0!%!!füsüåþ–øòr)‡Õ @Œ‹ Ô<ì2991/äüì0!!!!h3þþ3hþ˜ÕýÃþ^¢ýÌþœÃªhÕ@ŽüüÜì1ô<ì20###híËíÕýÕ+ýÕ+‹)¾K@1’ ’    ÔÌ91/<ä2Ô<<ì22Ô<<ì220!3!!!!#!#!5!!5!!!`aÝaþ¶Eþ°`Ý`þø`ß`þéHFþåR`PþøF¾þþÕþî×þþ×Õýªþî þÓ#*1s@? %$ + ,#–•,–•“,“ (/($ +/ 2ÔÄüÔ<ü<ÔüÄ991/ÄìÔÄüôìõî99999990#&&''&&546773&&'6654&¢}êosëy!ïÉõã¢dÈedÈe þÍô÷¢GUNðWWPþÓ-.);?7*´©³É çã"þ*/þá(»·¸ÅBE5;Cþ±þêBBDCBÿãÃð '3c@5  % ."™( ™˜œ41+  1 +%4ÜÄìôìîöî991ä2ô<äìîöîî0KSXííY""32654&'2#"&546#3!2#"&546"32654&3GNMHHLMGºÖÖºº××ý%Ý¥ÞûºÕÕººÕÕºHNNHHMNh{rs{{sr{¨Ø½½ÛÛ½¼ÙüÓ Ù½½ÚÚ½½Ù¨|rs}}sr|{ÿã¤ð&06@Y     ,-./+0()'%0' - ‘-¡!Ÿžœ˜ '*$ 0$*$  *  1üìÄÔÔìÆî99999991/Æäöæîîî99990KSXí9í9íí9Y"²']@„   ' 0   0%/ / %&? ? @K K K/K0ZZUZ Z U(\.\0X2_2dig`i i d&€2, ' '* 9 5005@J I'I(WW\ ['ggl ]] >7!!'# 5467.54632.#"3267™577oc%þXbiè‚þùþ»¢*(þÓ[Åk^¨PMU1—ABªwCt2ßþ>F®n¶þäkþ¾mFDÛ’áj5j:£Äþê0.;6"WþÓ/wGs¢))ê°Õ@ Žüì1ôì0#°íÕýÕ+°þò @¤£ üüÄ2991üì0!&547!þ×™’“˜)€€þò÷½ÛÛÁõíþ;ÝÝþ:¤þòø @ ¤£  ÔÄ2ì991üì0654'!¤€€€€)˜“’™þòîÆÝÝÅíõþ?ÛÛþC÷)9ðF@(  ¥ œ   Ô<Ä2Ü<Ä2991ôÄ2ôÄ290%#'%%73%þ¶JLþ³ªþ²LNþ²LNªMÁ­®¸þ¨X¸®­¶Xþ¨¶ÙÛ "@§ ¦  Ô<Äü<Ä1/ô<ü<Ä0!!#!5!Ñ ýöîýö ýôìýô ì mþÝ9ƒ@ ©¨üìÔÌ1üì0!#Ñh÷ÕdƒþÏþ‹uo¼ãß·«ªÔÄ1ôì0!!otýŒßþÝÑ9ƒ·¨üì1/ì0!!Ñhþ˜ƒþ}ÿBìÕ·/Ä991ôÌ03#ÞýñÝÕùmbÿã/ð #@ ¬¬œ˜ üìüì1äôìî0&#"326! ! ®i||jj|{jþÀþÚþÙþÀ@'&@ìååþèþåèèþþm“st“þmçÕ (@®®®  ÔÄìÄüì1/ì2ôìÔì0!%!!!ðTþ£[nTûì ÅHHû5þö¢ßð–@)% ¬œ¯ÜÄüÔì9991/ì2ôìÔì990KSXí9íY"K° TX½@ÿÀ878Y@&**"""555BJFF]]!!>54&#">3 N‘ûÃ!IFuZÖz‚þz )~ÊþåáB~Di€MLH+-ìÓzÓ±‰ÿãîð(L@+¬ – ± ¬ –±¬°#œ˜)& )üäÄüìÔì9991äôäüôìþõîî90!"&'32654&##532654&#"663 º—þ¬þºsçqlÕg™£§£š¢‘ŽŠ~]¾^ràl#!Š%'Á•Þç%%)67jcfiø[]V^*) ¿Àƒ§\3Õ C@ !  ! % ®   üÔ<Äì291/äÔ<ì290KSXííY"!!3#!!òþZ¦@¬ÕÕþ”ýj˜ý®üRþéþðJžÿãÕ=@"•¬–•¬² ¯ ˜" ÜÄüìÄî1äôìæþõîþä90!!663 !"&'32654&#"Ù½ýv,Y00þµþÚù{zÛaŒ¡¡ŒS¼lÕþåç þïôòþî12/FF‰uvˆ+-ÿã#î $7@¬¬ – •¬"œ˜% %$%üìüäîÄ1äôüôìîÖî90"32654&&&#"6632! !2åeeeefeev_¨P¬ÀBš[åþÆþøþÝþÁuEgÂჃƒƒƒƒƒƒÍþì-+¿¼11þôÙðþ߉ir§ ‰îÕE@%¯ÜÌ91/ôì0KSXííY"²]@ &5F]!!!‰eýºþ‰'ý1ÕÙûº}ÿãð #/G@( '¬¬°-¬œ˜0 $*& '&!$0üäìüìôìî991äôìäîî990"32654&%&&54$! ! $54632654&#"Élttlkrrþ|ˆŠ‹ˆ˜›þÙþÞþÝþ×›òc\ZbbZ\cœvnnuunou)ª½ÆÅ¾ª)*½ÞããÞ½UY``YY_`jÿãî$7@¬ –•¬ ¬œ˜%%" $%üìÄüüä1äôìÄþõîî9073267#"54! !"&2654&#"Í\¨R¬ÀDšZåþç9$@þŠþºiÀeffeeff!++¿¼22 Úñ"þvþ˜þŽþY‚„„‚ƒƒåN`@¨³¨ü<ì21/ìôì0!!!!åiþ—iþ—`þ}þ¦þ}þÝN` %@¨©¨³  ü<ì2ÔÄ1äüìî0!#!!åiøÕdiþ—ƒþÏþ‹uþ}Ù=ÛÇ@µ´ÔÄ291ôì90 5Ûü<ÄúþÍþ´þ¶úÏìÏÙ'ÛÛ@ §¶§Ô<Ä21Ôìüì0!!!!ÙúþúþÛëÜíÙ=ÛÇ@µ´Ô<Ä91ôì9055ÙúþÅÍúþ1ìþ1úJð!H@'Œ‘• ¡‹   "Ô<ì2ÔÔì99991/ìôüôìí9990!546776654&#"6632!!Åþ—Bj@95`VQ¼fyÈ]ôN^@D*þ—iþ—ø1Rb:4\.FOCB:*(Ç¿b›Y9>K-Áþœ‡þœo  Ml@: 40LM3 ¸30 ¸0¸·7$¸·CN34L **)(I(*)4=NÔÄììÔììîþ<Æ991ôììÔììÄîÄî299999032654&#"#"&54632536654&'&$#"3267#"$'&5476$32!#?iZYjkZXiš…Y¬×Ø«Y…Ñ|Ž:;_þã¦tÔZ”¥ked“~üYk}þÙ˜¹þ¸€€†ˆ~~O´àn{KMþºþ×'{ŽzyþZGOùÈÈúPGƒýKÉd¯Iz„=;bþɵ•þûdbg^P¢agƒ}}I½¶J}|ˆ«¡bå~þñþÔ 'Õ @@     % ®   ÔÄ91/<äÔì90KSXííííííííY"K° TX½ ÿÀ @878Y@€ / V f  t Š Ÿ ¿ ¿ Ï Ï ß   %* IFGH XYVWhifg` t{zu{t ‰††‰ ™–•š ¶¹ ËÅÅËÂÍ ÙÖÖÙÕÚ /]]!!!!!Fý¦_þ})Ë)þ}ý¨™ÌþðÕú+%R¼‰Õ P@%¹¾¹ ¹   !üì2ÔìÔì99991/ìôìôì90@ ""/"P"]2654&+2654&+)! [^^[ÕâtutuâH|ˆþÜþÖýB7f“PNMQþÄýsbcaaþy$ÂØÔÕ¼Ïm™fÿã\ð;@   ®® œ˜- +üÄ2ì1äôìþÄÅ990´/_]%# !2.#"3267\jæ}þ‹þL´u}æjkÐsÎììÎsÐkR78¡ef¡87þËIDþøèçþøDI¼9Õ.@À À -. üìüì99991/ìôì0²P]32654&#! )=Šìùøíýõ–TMwiffixþ°þ°þj²üqêßÞè#ateþø§©þ÷eta¼áÕ 0@À¾ÀÀ   üì2ÔÄÄ1/ìôìôì0¶ P p ]!!!!!!¼ýrgý™¤ûÛÕþÝþêþÝþªþݼËÕ +@À¾À üì2ÔÄ1/ôìôì0¶ P p ]!!!!!¼ýrgý™þÕþÝþêþÝý‡fÿãúðK@%   ¹®® œ˜1 3/-+üìôäüÄ1ÄäôìîîÅ9990²_]%# !2.#"3267#!úþÊ¥þ‹þL¼‚•y}÷|æùðÝ@À¾   üì2Ôì21/<ô<ôì0@P ` p Ÿ ]!!!!!!¼8þýÈþÕýÇ9ú+yý‡¼=Õ7·Áüì1/ì0K°TK°T[X½ÿÀ@878Y¶@P]!!¼þÕú+ÿþf=Õ L@ À  üÄì991äüì990K°TK°T[X½ ÿÀ @878Y¶ @ P ]!!#3265¼þÑþÍN3IO@UZfi ]]!!!!¼®mþRýáþ“Õüú+üfÿãfð 2@®® œ˜ -7-+üìüì1äôìî0@ /?]"3254 ! f°Â°±Â±h˜þhþ˜þ™þg™Ùþüìëþüëìþdþ•þ–þdœjkœ¼‰Õ 1@ ® ®  - üì2Ôì99991/ôìÔì0²]! !#!32654&#¼1þÏþãþþÕpzzpÕýêëýýú¾þ_mddlfþÕfðb@ ®®œ˜  - 7-+üìüì9991Ääôìî90@,  '/V S f ` w w p  Y Y YXj i x ]]# ! !"3254þþf™gk•×Ê-þ‘þã°Â¾´±Â˜lkœþhþ‘üþ”\þ°þüìðÿëì¼Õ‡@2% ® ®     üì2ÔÄì9991/<ôìÔì9990KSXíí9Y"²]@66EEVVPee`]2654&+!! !.#ßyiiy¢þL'O}@Ñþf¶7q^?ZgfXþþöýËÕÆÖ”¾-þXspR“ÿã-ð'§@*% Ãî®%œ˜( "(ÜìÄÔìÄ99991äôìþåå9990@Tp)9999 JJJ X ]\^^ Z!joooh o n!t t t || |!– — ›šœ š!¦ ¦ ¦ ªªªª ª!(]].#"!"$'32654&/.54$!2Ë{êhŠ„Yu¤ùÒþÛþÓŽþâ |~†[ˆ•àÏ {¦þÄ78LP@À88Ôìüì1/ôì20K° TK°T[X½ÿÀ@878Y²@ ]!!!! `þþþÕþÝûN²¼ÿãÃÕ3@ À˜  9üìüì1ä2ôì90¶@pŸ]!3265!! ¼y‰ŠyþÂþºþ»þÂÕü¹ŸŸ¹üþÃþÊ6= 'Õ˜@'%ÁÔÄ91/ì290KSXííííY"K° TK°T[X½ÿÀ@878Y@, ° GGHHEJWX]]! !! ƒŒ‹ƒý×þ5Õû²Nú+=“Õ x@J 6  6 6 6   % Á    ÔÌ91/<ì2290KSXííííííííY"K° TK° T[K° T[K° T[X½ ÿÀ @878Y@Ì  % :?:?3 0 0 @ @ @ ^^a ¸± ° °         '('(%* /66220002 4 6 ?IFHE J ]]ZZUURRRZ U ] ooonhheh k n i o wwx v x ˆ…‰ ·º¶¸±¾ K]]! ! !! !=qsnþ þDþñþôþDÕûÃ=ûÃ=ú+oû‘'Õ û@E    %  Á   ÔÄÜÄ91/<ì290KSXííííííííY"K° TK°T[K°T[X½ ÿÀ @878Y@X  /& <3 _P € ¿°    ++%$%+ :55: P ejo ¹µµº ]] ! ! ! !üþoþ£þ¦þmþ’GF”úýþþúÛþáÿìßÕ @(%Á:: Ôìüì91/ì290KSXííííY"K° TK° T[K°T[X½ ÿÀ @878Y@, %%0@P`° %*5:0 O o ]]! !!¥TT¦ýÇþÕýìü ý‹u\qÕ w@%ÀÀ ÔÄÜÄ991/ìôì0KSXííY"K° TK° T[X½ ÿÀ @878Y@ %)69? FHO V_ o ]!!!5!sçüß8úë!üöÕéü7þÝéɰþò@ĤģüüÌ21üìüì0!!!!°mþçý“áú áÿBìÕ·/Ä991ôÌ03ýòݾ“ùm‹þòø@ĤÄ£ÔÌ2ì1üìüì0!5!!5!øý“þçmþòá`áϨåÕ@ ÔÌ91ôÌ290##ÕñþfþgòÕýÓ-þÓ-þþÛ´/Ä1ÔÌ0!5üþÛ¾¾^î“fN·ÆÅÔÌ1ôì0K° TK°T[X½ÿÀ@878YK° TX½ÿÀ@878Y´] #yÄþfþˆxXÿãÅ{ %@*  ÒÏŸÐ ÌËŸ#ʘ # = ;&üìÄôì229991/äôüôìæîöî9990@L/'= =!?'M M!] ]!n n!~ ~!p'Œ Œ! !­ ­!½ ½!20C@SPc`…€“¢ ²°]]"326=%!5#"&54$!354&#">3 ¢pq[QeŠiþ—H´®Ù"Ó†ŽsÆUsèt/ øLJDM‘m)‡ý¦f]ˢŸUO..ï¬ÿã^ 8@¡ С˜Ê£ÐB@ üì22ôì1/äìäôìæî0´O`]%2654&#">32#"&'!!syyss{{{J´uÏ þöÏu´Jþšf稠 ¨©ŸŸ©Õb]þ·þýþýþ·]b¢Xÿã5{7@ÌÔÌ Ô ¡¡Ê˜B ;üÄ2ì1äôìþôîõî0´_].#"3267# !25I“O–§§–T—@T­WþÑþªV/X«=þÜ20¯¯21þÛ77\ÿã8@¡Ð¡Ð˜Ê£ @B ;üìôì221/ìäôäìäî0´O`]!!5#"322654&#"¦hþ˜J²uÏþö Ït³¢syysryy¼Xùì¢c\II]üɨ  ¨¨  ¨Xÿã {C@!Ø ÌÔŸ ×ŸÊ ˜ D ;üìôìÄ91äôìäþôîî90´/?]!3267# ! 4&#" ü» œŒqí}þþÐþ¯K"=þw`h‚3f~~CDþì015:þ“f}un'`@ ¡Ÿ£³   E Ü<ìü<ÄÄ991/ä2üìî2990K° TK°T[X½ÿÀ@878Y@ €€]#"!!!#35463ÆL<2þÎþš²²ÌÖë7DNÿü `N·¯\þFy(K@&ÌÔŸ¡ Ð Ê ³#¡ÚÐ& @ B;)üìÄôì221/ääìäôäìþõî990´O*`*]%#"54325!!"&'3265"32654&¦J²uÍþô Íu²Jhþ«þ¼iÄc^´[°¤ìo|xsp||¾b\CúûA\c¦üþòþã !65š¤¤–šŸ¤•–¤¬5@  ÛÐÊ£ G üì2ôì1/<ìôäì9990´`€]!54&'.#"!!>32þ˜ H.p€þšfQ¶nÂɪýVo™“n#'­™ýÙý¨b]î¬)@ݳ£ ü<ì21/ìôì0@ P ` p € ]!!!!¬fþšfþš`û þÜÿ¼þF =@ ŸݳÚ £  ü<ì2Ä991ìäôìî990@ P`p€]!+53265!!¬fØÍ±>fLfþš`û´áíë\‡þܬy Œ@³£   üì2ÔÄ91/<ìä90@`;IIZ]X_ogvv{ˆ…‡‹Ÿ•–›¹:DGJV]g`ewpv|‡ˆ‹’—›]]!! !!¬fœ ýÝNþNþKþšü±›ýþý¢Óþ-¬·£ üì1/ì0@ P`p€]!!¬fþšù쪴{%t@)  Û Ð#ʳ  H H &üü<üìüì991/<<äô<äì29990K°TX½&ÿÀ&&@878Y@'0'P'p'€''¯']>32!>54&#"!4&#"!!>32ºD»pÁÊþ˜FNfoþ˜@Rgpþ˜hB«gt²¦hmîãýVH wk¨ŸýÚHºk©ýÙ`¤_`p¬{5@  ÛÐʳ G üì2ôì1/<äôäì9990´`€]!54&'.#"!!>32þ˜ H.p€þšfQ¶nÂɪýVo›‘n#'­™ýÙ`¤b]îXÿã'{ -@¡¡ ʘ BLB;üìüì1äôìî0¶7?G]"32654& ! Áw}}wu||u!Eþ»þßþÞþ¹G{«¡¡««¡¡«þÈþìþìþÈ88¬þV^{;@¡Ð¡Ðʘ޳B @ üì22ôì1äääôäìäî0´O`]%!!>32#"&"32654&þšfJ´uÏ þöÏu´¤s{{ssyy¢ý´ ¤b]þ·þýþýþ·]7©ŸŸ©¨  ¨\þVy ;@¡ СÐʳޘ @B;üìôì221äääôäìæî0´O`]"32654&#"325!!ºryyrsyyyJ²uÏþö Ïu²Jhþ˜w¨  ¨¨  ¨ý+c\IG\c¦ùö¬ì{C@ À ”Ê ³  üÄì21/äôäüÄ990K°TX½@ÿÀ878Y.#"!!>32ì/]/Š•þšfE³}*(/±¥ýü`¸nejÿãb{'Ü@@  6  6% ÌÔÌÔŸŸ%ʘ( SRP"M(üìÄÔìä99991äôìþõîõî90KSXí9í9Y"² ]@^ #  ,. . . . . ) 9; ; ; : : K J J J H w w ºº º º º º %  7 ?)_) ]].#"!"&'32654&/.54632sÖ_fcKa?¾þøþúoí}kátijIm?ïÀôücÚ=þð0035+. # «³´##44:90/ ¢¥²¬¤žx@¡³¡    Tü<Äü<ÄÄ991/Äìô<ì2990K°TK°T[K°T[K°T[X½ÿÀ@878Y@??PPP`` ]]!!;!"&5#33qþ>\¸þÍÔ±²²žþÂÿþ%N7ÿ±ÔÛ> ÿã`;@ ÛИ³ G üìôì291/ä2ôäì9990´`€]!3265!!5#"& hG.p€fþšQµmÂË´¬p[þí.‡w#&¬™)û ¢b]î`è@'%ßÔÄ91/ì290KSXííííY"K° TK°T[X½ÿÀ@878Y@| 0@Vf€ °°°°ÀÀÐÐàààðð  &$+)64990FFII`x‡ˆ‡ˆ––™™•š¨¶¹$]]! !!fgþGþw`üúû H` @J 4  4 4 4   % ß    ÔÌ91/<ì2290KSXííííííííY"K° TK° T[K° T[X½ ÿÀ @878Y@æ 550 G @ @ _ l  °°°°° ÀÀÑ Ð ààï    &$+)*+ $ % /554;::78 ?GIFHGH YVV[ T Y _f`b```d ` upspppt p ‡ˆ„‰ † ‹ ”› ¦©¦©¥© ¦ ª ¶¹¶¹ ÆÄÊÉÕÙ×Úåé æ ê []]!!!! !H\¼½+¼½\þÙþy½¼þy`üüýüû üþ ` „@F    % ß   ÔÄÔÄ91/<ì290KSXííííííííY"K° TK°T[K°T[K°T[X½ ÿÀ @878Y@Ú  / 3< CL R\ bl sz € ——œ Ÿ  ¯ °°°¿ ¿ ¿ ÀÀÏ Ï ÐÐß ß ààï ï ÷ð÷ÿ 2     $++$ 4;;4 0 DKKD o †€‰€ —•š™š– §°¿¿° ÀÏÏÀ ×ÐߨßÐ çàïèïà ùö:]] !! ! !Çþl{åè{þl¨þ…üùþ…=#þ´LýßýÁbþžþF`A@C %  ŸÚ³  ÔÄ91ä2ôì9990KSXííííí9íY"K° TK°T[K°T[X½ÿÀ@878Y@¤ @Pet†€” ´°°°ÀÀÔÐàà $$$5586699EEJJEEge†††ˆ ˆ—––™ ™¨ªª©©µ¼¸° ° ¿ ¹ ¹ÈË ËÉÖå9]]! !+5326?f-fþ)G½›Ïp[S `ýøû6»•ë:K\F` ž@%¡³¡ ÔÄÌ2991/ìôì0KSXííY"K° TK° T[X½ ÿÀ @878Y@DYVifyv„“ &)/ 9? J_ Žž±½ÀÏÐßãì]]!!!5!uÑý²NüNýË`úýšÿúfþ²²$^@1 %   ! Ä áÄàÄ£% $  %Ô<Ìü<Ä299999991üìôìôì99999990#"&554&##5326554633#"3²ÙÚÈlŽ==ŽlÈÚÙEUZnoYUmá°ÁÀ–ußt–ÍÁ¯áWަŽŽœ¦Wþç¶Ôì1ÔÌ0#çãøþ²²$`@2%   ÄáÄ#àÄ£%# %Ô<Ì2ü<Ì99999991üìôìôì9999999032655467&&554&##53233#"##FŒUZooZUŒFÙÚÈlŽ==ŽlÈÚÙmW¦œŽަŽWá¯ÁÍ–tßu–ÀÁ°Ù²ÛR#@ § §ÔÄ1ÔìÜìÀ990#"'&'&'&#"56632326Ûj³`k›^X¬bk²`k›^V©RôPE:=MSôPE:=Kÿÿ 'k'$u 'm!{@S!! ! !%!®â !  UU "ÔÄÔìÔî9999999991/<ÆæÖîî9990KSXííííííííY"K° TX½"ÿÀ""@878Y@À/!/!:!o! ¶ ¶º·°°°·ºº¿¿¿º¿!¿! # ///  /// "+ #EKUZ` ` ` ooo``ooo`fi `#tuyz{t …Š…Š •š° ° ° ° ¿¿¿¿°°¿¿¿·°³¼ D]] !!!.54632%32654&#"!þ}^ý¦_þ}§vt¨þwM66MN56MJ™Ì¸úHþð¸"K+u¨¨u/L{6MM66MMûŸRÿÿfþo\ð'&Ýsÿÿ¼ák'(´uÿÿ¼öm'15uÿÿfÿãfk'2Nuÿÿ¼ÿãÃk'8'uÿÿXÿãÅf'DºÿÿXÿãÅf'DCºÿÿXÿãÅf'D׺ÿÿXÿãÅ1'DŽºÿÿXÿãÅ9'DغÿÿXÿãÅ'DܺÿÿXþo5{'FݸÿÿXÿã f'HÙÿÿXÿã f'HCÙÿÿXÿã f'H×ÙÿÿXÿã 1'HŽÙÿÿ¬f'ÖÿwÿÿÿÕf'ÖCÿwÿÿÿþðf'Ö×ÿwÿÿ<²1'ÖŽÿwÿÿ¬9'QØòÿÿXÿã'f'R×ÿÿXÿã'f'RC×ÿÿXÿã'f'R××ÿÿXÿã'1'RŽ×ÿÿXÿã'9'RØ×ÿÿ ÿãf'Xòÿÿ ÿãf'XCòÿÿ ÿãf'X×òÿÿ ÿã1'XŽò5ÿ;ÃÕ *@åã ä WV W Ô<äü<ä1ä2ôìî20!!!!!5!VJ#þÝþ¶þß!ÕþƒîûÑ/î²dLþ @æçæ  XYXÔìüì1Ôìüì0"32654&'2#"&546HdcIHdeGBz0/11-0|D¿Á\dHHbcGHd¢3/0xDCy-03¿Á®þlj˜#W@. ÌÔ ÌÔ ¡ ¡!ʘ$   B$ÔüÔ<<Ä2ì22991Ääô<ìÄþôîõî9990&&##667###$4%3¾NMMNËJAY—9S’: ¢þúþö¢G“Z,“lm”*9þÜ02ýi2/þÛ þä (.ô##þá}çð@@!–• Ÿ¬œ ¬ Ô<ÄÄü<ÄÔÄ1/Ä2ì2ôìî2õî990&&#"!!!!3#5356!2ÛF”Mvquþ‹û–ãÂÂþ\µºþâ'&}ƒªïþºþö Fïªøÿ=øð3?k@8@1:4 %+èè1œ@ =!+%74:!=\.!\=[.7[(@ÜÄìÄÔÄìÔìî9999991ÄôìþÅÅ999990&&#"#"&'532654'&'&&5467&&546326654&ucž9KL¼ ÒŸquMKòÕUµfs¶9AN´$Ë oqKAåÉT´þšDC{¶AFжã''1/CO Y­}uŸ0)qI‘§í)+2(FJW³‚hš33oK¢ý…L2CbBO4Cj'‘ö`·é ]Ôì1Ôì04676632#"&'&&'535‚IIƒ245633ƒJI‚326úJ‚235624IJƒ336633ƒÿ;dÕ &@ ^^ÔìÔìÄ91Ä2ôÄÌ0!###&&54$\¾½¾ÌÞÕùfùùNÛ²¾è¬ÿãh0j@4.(" !+ŸŸ+Ÿ£˜/"!(%  a%.(a_ . 1üìÔìôìÝî99991/äþîþÕî990@ /2O2p2Ÿ2]4$! #"&'532654&/.5467.#"!¬ —1]EtkåçAŠJ8s6HX7bFXT‹‘`[efþšZÞÜàÚG NJ%94%@©u½¼ôH9/D7'1‡Ztž2UYnmû´åÍ 4Lb@8-*+'î0î!ëæ5í æ2+ëA'*,$0-+$!1g3f$cX;eX3cGMÔììüìüìî299991/ì2îþîüîÖî9990"32676654&'&&#32654&'2#'&&###2#"$'&5476$yÐWWWWWVÑy{ÎWWWWWXϲ##NOM+°®i`)Goåk&: Õ1˜mmllmmþù˜˜þùmmllmm3WWWÏzyÏWVVUWWÏyzÏWXVþÙÏ5442ŠwyVpP:ÝÕNAþœD7nmmþúš˜þûmmnnmm˜šmmnåÍ1IH@(  ïïëæ2í&æë>f,X c8e XhDJÔììüì2ìî1/ìîþîüþÅþÄ990&&#"3267#"&54632'"32676654&'&&'2#"$'&5476$+9o9q~r@s.Aƒ>ÓþþÓE€îyÐWWWWWVÑy{ÎWWWWWXÏy˜mmllmmþù˜˜þùmmllmmf×%#€rs~$#ÕêÂÃé·WWWÏzyÏWVVUWWÏyzÏWXVšnmmþúš˜þûmmnnmm˜šmmn'“RÕ v@>  %  î  ji i jiÔìäÔìÔìä91ô<<ì2Ô<<Ä9990KSXÉÉÉÉY"73#######5ww㪉L‰¬q®¬¬Õããý¾µÿþKBþM³mî¢f7·ÆÅÔÌ1ôì0K° TK°T[X½ÿÀ@878Y´]!#‡þÄfþˆÅ;;1\@ñðÔüÔì1ô<ì20K° TK° T[K°T[K°T[X½@ÿÀ878YK° TX½ÿÀ@878Y3#%3#Åëë‹ëë1öööÙÿöÛ =@!   §¶ §  Ô<Ä291Ô<ì2ü<ì2.À990!3!!!'7#5!7!Ùü•‘ëþ^®Püêü–’쨰ý¨Û1}´ëÜíþϲíÜÕ¡@7%À ®À ¾ À  /ÔÄÄÔ<ì291/<Äìôäìîî90KSXííííY"K° TK° T[X½ÿÀ@878Y@&W††³³µµ ] !!!!!!!!!{ÿyþ}‘ýsfýš¤ûÛþ“þÕýžbþÝþêþÝþªþÝ^þ¢-ÿ¶– +è@> +,   )*&®& ®œ&˜,+,* # )-#7-+,üìüìÀ999999991äôìîÀÀ99999990@p- -*'&!/-976!9)?-GYVT!Y(Y)jege!j%j($'))68)KFE I)Z^SVV T!V"[(j ejlaf c!k(x ™ ˜ ª ]]3254&/.#".5!27!"&''\4ƒS±ÂM3‚R°ÂþêJJ™gšøfÇqÉMLþhþ˜™ÿfÊqs>;ëDu1“:9þüì@q.þêdú—kœKMÇsÇcÿšþ–þdOOËqúé /B@#  $'!ó-ôó!ò0 $k*k0ÔìÔì99991üìü<ìÀ999032654&#"&&#"326#"&546326632#"&¼+vIZqgLHwþñ+tKZqfMGz©DŸa‹Æ¯ŒZ™cGž_ŒÅ¯Œ[–1CDeOMeeCCdOMeia‚~ó³¼êq„~ò´½ënÙÛ .@õ§õ  § l l Ô<ì2ü<ì21/ìÔ<ìü<ì0!!#!5!!!Ñ ýöîýö ýöúþþžìþžbìbûêîÙÛ¨ '@  § ö Ô<Ä2291/äüÌ90%!55ÛúþüúþîîîÆÑÑóPëNÙÛ¨ '@ §ö  Ô<<Ä291/äüÄ907!!55%Ùúþúþîî´ôþ²ëþ°óÑyÕ´@B  % ÷ ÷   nm n mÔ<ì2ìü<ì2ì999991/ä2Ô<ü<Ô<ì290KSXííííY"²]@, $+6:FI   0@€€°° ]]!!!5!5'!5!! !!!!Nþ9þƒþ:Æ1þk$þ±! þ°%þj1Ç þ` ÂBVÀþ3ÍýåÀVB®þT¢` :@! Û˜ ³Þ!   !üì2ÜÄì91ää2ô<ì990!3265!3267#"&'#"&'®idfgdh!'!5]-Yq#/‡YJhþT ýutqqt‹ýG8 úKSOO/0þ;ÿçR)8@'! '!ù* $$*ÔÌÜÌ9991äÌÜÌÎÎ9906654&#"#"&54632#"&54324&#"32þ;'#ÂS0@ºÒõþ»ÿ¶êï³e‹ID`IFa~¬qº9WzºC2Eqþ¾þèþ¨þGé·Ë Uór|þïÒtx)þw“Á O@  ûûú  ÔÄÜÄÄ91Äüìî990@ &#)  ) ( ) 8 ]]!! !!5 Bü’lý’¥ú–ºý_Áþ÷ý{ýNþö¬²–þw²Á@ýüúppÔìÔì1üìì20!!!!–þ¨ý”þ¨Áø¶)ù×ÿÝJD/@    ÔÌ991/<ÔÌ22990#!#!#"663J'°šþá˜î—þá˜7: Õ¼ÙDàüœdüœd>DÇœ3þ‹°,B²*#¸²ÿº @ÿþ- *(&  qr q-Üìüì991üììüìì9026732#"&54&#"#"&54632jcãìi‚RA@Ae '&>ÄkTF32°-üÓÓ…hB:Yr õ7Œ^‘¤Òâ‰YUW¦O\©KàØ=ÈÄ4>3:rWTþ@LH†t„8;##´¯uuð 9A  @œ  uu ÔìÔì991ôìôìüì02#"&546!!"32654&BÕ÷öÖÖ÷÷Æ7üÉœT[[TS[[ðÞ¾¾Üܾ¾ÞüMÈÑ~tt||tt~7îåF³ ½  @  xwx w ÔììÔììÀÀ9991/<ì2üì990!!654&#"!!&5! Ë#ýŸ~„˲±Ë„~ýŸ#~zx89xzÿ#V¥Ëééˤþ÷UþÝy¤9yþ‡þǤþêXÿã{>Ì@B8>6Ò6Ø'Ì&Ô# Ÿ6Ï-*Ì>Ë;Ÿ×Ê0*˜? - 6 & 7 3;?üÄìÔü<ÔìÄ999991ä2ô<Ääü<ôìÄæþ<ôîîî9990@N>>?@MMO@^^_@nno@@@­­½½2=0>B=@>R=P>b=`>ƒ=€>’=>¤= >²=°>]]4&#""326=>32>3 !3267#"$'#"&54$!354&#"w`g€ýápq[QeŠý^wßa–ÙGMÌz =üº›qí}ÿ~³þ÷Heß‹Ââ"Ó†ŽsÆUªf}un²LJDM‘m)JMOMOþÂþöf~~CDþì01kdkdŨŸUO..Nÿ¢)Á +¸@> )+ *& ¡&¡Ê&˜++, #* #)B#LB;,üìüìÀ999999991/äôìîÀÀ9999990@@:5 ;75!8)?-IF KGD!H)[VT!U(ikfe!e(5:)EJ)U^(i em( ]].#"32654&'.5!27!"&''XK/w}HO0u|ý;CDG"j³K“mFEþ»þßl¶M”pD«¡)A‹«¡+CýäNÈ{8,,že•PÊ~þìþÈ--›^ÿãÕ!M@*‘• Œ‹ ¡˜ "  "ÜìÔÔ<ì299991äôìþíôî9990!3267#"$54677665%!!çiAm@84`VQ½ewË\ôÿN^@D*iþ—iÛ1Q~d:3\/FPDBþÆ*(Ǿc›X:=L-Ãd‡Õ @Œ‹ Ü<ì2991/ôüì0!!!33þ˜h=¢þ^ýÃqdþœÙÛ@ §ÔÔì1ÔÄì0!#!Ùëûéý’Lÿ×Z² n@*      %  º@  ÔÄ91Äüì90KSXÉÉÉÉÉÉY"3##'%ƒ×`ý²wþÍ‘%hß²•ùºN7ý…þV7#w@I #"!   %  ¬”¬” ŸŸŸ!£Þ$Ä2äüìîî2õîõî99990KSXí9í2Y"&&#"!!#"&'53267#5!766327.T*Zd!þ´…)å¿A…D.U)Ycuò!3*ã¾B„ìþs¨îý_ÎÌþsMîüÎËÙáÛ#;C@!.9* 1§ §"§9*§1<-<Ô<Ä21ÄÔìÜìîÜîÀ9999990#"'&'&'&#"56632326#"'&'&'&#"56632326Ûj³`k›^X¬bi³an“ ›^V©gj³`k ›^X¬bk²`k›^V©#ôPE:=MSôNE;=Kþ³ôPE:=LTôPE:>K“Á ²¸ @ ú/Î91/îî90!!!Éþºþ#-3úmVüªÁú?ž‰j' 5³  »@  y yÔü<Ôì2991ô<ì299055‹þÛ%þÌþÜ$þ'òÝÝòqºsòÝÝòqºÁ‰' 5³  »@ yy Ô<üÔ<ì991ô<ì29905-5%% íþ%þÛþ!ëþ$þÜ'þºþòÝÝòþºþòÝÝ¢^ƒ #@¨   ÜüÔüÔì1/<<ì220!!!!!!öhþ˜ú¬hþ˜ªhþ˜ƒþ}ƒþ}ƒþ}ÿÿ 'k'$uÿÿ 'm'$uÿÿfÿãfm'2NufÿþÁ×P@" À¾ À À   -+ üìÔÄÄÔì299991/ì2ôì2ôìÀÀ0@ !!?!O!_!]# !3!!!!!!"# !2œiþßþâ iZhýsfýš¤û / þFþ&Úº 0²âäåä²þÝþêþÝþªþÝ…ihƒXÿã^{'3t@2" ØÌÔ Ÿ.¡(¡×Ÿ%ʘ4"1 1 +B;4üìÔüÔÄì9991ä2ô<ìäìîþôîî9990@/5?5O5O5_5o5o55F"]]4&#"!3267#"&'# !2>3 %"32654&îw`h‚Aü» œŒqí}~ÿ~¥ÖHRÕ‚þÞþ¹G"†ÎQRLJBúcw}}wu||ªf}unwf~~CDþì01QWTT88RVWQþÆ:«¡¡««¡¡«°²¹´ª/Æ1ôì0!!ü²þþ°²¹´ª/Ì1ôì0!!ø²þþÓX…Õ +º@    ÜüÌÔÌþÔÎ1ô<ì20!3!3!þ¬ãÕdþþ¬ãÕdXbþžþå`þ ¼XoÕ +º @  ÜìÔÌÜîÔÎ1ô<ì20!#!#!TäÕeúTäÕeÕþãþ `þáþ¢^ÓX‹Õ¹@ ÜüÔÌ1ôì0!3'þ¬ãÕdX`þ X9Õ¹@ ÜìÔÌ1ôì0!#åTãÕdÕþãþ `ÙVÛ® 0¼@ §¦ z{z Ô<ìü<ì1ôÄüÔìî0!!!!!!Á3þÍ3þÍþúþ‹þËXþËìþ#îuv@A%ÔÄ91ÜÌ990KSXÉÉÉÉÉÉÉÉY" úþþôþ þ üÏüÇ9%ûÛûÓ-ÿÿþF1'\Žœÿÿÿìßk'<Íuþhÿãîð+@55%˜œÔÌ1ää0KSXííY"#3¸à¦à J=ÏÅ#/@ ! ! $A !* @&00   '}|~-} |0Üìì2üìì29999991Ôìì2üìì2À999990'7&&5467'766327'#"&72654&#"²Ï™ÏÑ™Ï0l=6l9ϘÏÏšÏ.j?:l¦[€\[€~ ÏšÏ1k??l.ÍšÏÏšÏ7n6?i/ϙζ\\\]~ž‰‹'¼¶yÔì291ôì905‹þÛ%þ'òÝÝòqºÁ‰®'¼¶yÔ<ì91ôì905%%Áíþ$þÜ'þºþòÝÝ+Bu@& ¡Ý Ÿ£ ³    ETü<ìì2ô<ü<Ì991/<ä2ü<ìíî2990K°TK°T[K°T[K°T[X½ÿÀ@878Y´@€]!!#"!!!!#35463Ùiþ—JÆK:þþ—þkþ—°°ÌÖþÜ$ë7DNû `ü `N·¯'Bl@! ¡ Ÿ£ ³     ETü<ìì2ôüÌ991/<ä2üìî2990K°TK°T[K°T[K°T[X½ÿÀ@878Y´@€]!!!"!!!#3546{Çþ—þîL<þçþš²²Ìùì)7DNÿü `N·¯3ÿ;ÃÕ?@!å å ãä W VW Ô<<äü<<ä291ä2ôüÔ<ì2î20!!!!!!!5!!5!VJ#þÝ#þÝþ¶þÝ#þß!Õþƒîþ<îþƒ}îÄîÑ9‰·üì1ÔÌ0!!Ñhþ˜‰þ}“ÿLƒ¹@ ¨ÜìÔÌ1üì0!#øTæÓeƒþãþ `“ÿFƒ +º @¨  ÜìÔÌÜîÔÎ1ü<ì20!#!#øTæÓeúTäÕeƒþãþ `þáþ¢^Bÿã Vð #/3?K|@C3 2211 003%@ *™$F4 ™:0˜2$œL3IC1!  C=!'= I7' -LÜäìÔÌìäîîîöî991ä2ô<<ä2ì2îöîî20KSXííY""32654&'2#"&546"32654&'2#"&546#32#"&546"32654& ÇHNNHGLLGºÕÖ¹ºØ×øÅHNNHHMNGºÕÕººÕՇݥ޺ÖÖºº×׺GNMHHLMh{rs{{sr{¨Ø½½ÛÛ½¼Ù8|rs}}sr|¨Ù½½ÚÚ½½Ùùó ý ؽ½ÛÛ½¼Ù¨{rs{{sr{ÿÿ 'k'$uÿÿ¼ák'(´uÿÿ 'k'$uÿÿ¼ák'(´uÿÿ¼ák'(´uÿÿ¼²k',ÿduÿÿÿëÝk',ÿduÿÿ)Ÿk',ÿduÿÿ=k',ÿduÿÿfÿãfk'2Nuÿÿfÿãfk'2Nuÿÿfÿãfk'2Nuÿÿ¼ÿãÃk'8'uÿÿ¼ÿãÃk'8'uÿÿ¼ÿãÃk'8'u¬`·ß üì1/ì0@ P`p€]!!¬fþš`û ‡îyf6@ ÆÅÔÌ91ôì290K° TK°T[X½ÿÀ@878Y3#'#‡ò²ÇDzfþˆáá¤\9É@  ¼@ Å€€ ÔìÔì99991ôìüì9999990K° TK°T[X½ÿÀ@878Y@T              ( ]]'&'&#"#4632326=3#"&7/$&‹g]$I)=%$(‹g]$CT%>;ˆ”+@9ˆ”ÅX;EµÔÄ1ÔÌ0K° TK°T[X½@ÿÀ878YK°TX½ÿÀ@878Y!!Åvýм°PF i@  ÔìÔì1Ô<ÔÌ0K° TK°T[K°T[X½@ÿÀ878YK° TX½ÿÀ@878Y@]332673#"&° cSSc ®œœ®FFJJF™™w;‰1*·ñ‚Ôì1Ôì0K° TX½@ÿÀ878Y!!wþî1öãá C½ @ ƒ:ƒ Ôìüì1Ôìüì0K° TK°T[X½ÿÀ@878Y32654&#"4632#"&}M67LM67Lš§vv§§vv§þ7LM66MM6v§§vv§§þoË5@   ÔÔÌ991/ÔÌÔÌ0K° TX½ÿÀ@878Y!#"&/32654&'Z:7{0f42S!:A+->j/_[ ˜.(R<ÁîÕfE@ÅÔÌÜÜÌÌ991ô<Ì20K° TK°T[X½ÿÀ@878Y3#3#ƒÙø£-çþð®fþˆxþˆVþo@   ÔÄÌ991/ÔÌÔÌ0!33267#"&546Å2&;1'M(7^)s{6CI'1œ \V5m‡îyf6@ ÆÅÔÌ91ô<ì90K° TK°T[X½ÿÀ@878Y 373‡ÿ²ÇDzÿîxããþˆÿ¤ìÕ `@2 % À   „ü<ü<Ä.9991/äì90KSXÉÉÉÉY"!7!!'%Çþþs¤ûÛ”#Õþ`¹ÁþðþþÝ j¾ÅÿÛ ~@-   % £   T ü<ì2.À991/ì90KSXÉÉÉÉY"² ]@utƒ@ P ` ` tp p €€ ]]!7!'7Çhoðþ˜}oìþ Xš¤üÇVš£ÿÿ“ÿã-k'6Éuÿÿjÿãbf'Vàbÿÿ\qk'=Ïuÿÿ\Ff']àTþ¢ç˜@ Ô<ì21ÄÔÄÆ0##çããã˜ý öüý ö!LÕ •@¹À À  -. „ ü<ì2ÄüìÄ91/îöîÖ<î20@X!P!`!////////OOOOOOOO________ŸŸŸŸŸŸŸŸ¿¿¿¿¿¿¿¿(]]3#32654&#! )#3Pëë‰ìùøíýö•ULxhgghyþ°þ°þk®®²þ¿þüþ¶êßÞè#ateþø§©þ÷etamXÿã'(õ@Y&'('%$%(('"#" ! "! 5((5(%('&%"! ##¡ ¡˜#£)'& !#(%" BB;)üìÔì99991ìÄôìî9990KSXí9í2ÉÉÉÉY"K°TK°T[X½)@))ÿÀ878Y@6f!/*76"?*O*oooooooooo]].#"32654&! 4!2''%'!%˜7l4u‚ru| £ujþ»þßþÞþ¹-.N$¾þ‹%3¼`ox#þÅç…y”¨«¡-\”ˆþÿ”þìþÈ8ç ÛwaÊtr`ÿÿÿìßk'<ÍuÿÿþFf'\œ¼‰Õ Œ@® ® - üì22Ôì99991/äÔìÔì0K° TK° T[K°T[K°T[K°T[X½ÿÀ@878Y@,0000PPPP    °°°°]]!!3 !32654&#=þþ1þÏþãþÕpzzpþþÕþüýëêýºþ]mcen¬þV^;@¡Ð¡Ð˜ÊÞ£B @ üì22ôì1ìääôäìæî0´O`]%!!>32#"&"32654&þšfJ´uÏ þöÏu´¤s{{ssyy¢ý´¾ý¨b]þ·þýþýþ·]7©ŸŸ©¨  ¨Ù Ûø·§¦ÔÄ1ôì0!!Ùúþøì)´Û /@   Ô<Ì291Ô<Ì290 '7´þN²¨þNþN¨²þN¨²²3þNþP¨°þP¨°²¨þN²{œß 7´¾  @ š …†… ÔäÄüä1ôìÔìî29035733!ÏáåâÌý9 4 1ýZmœð]@% ¸ ² º"@œˆÜÄÔÔì9991ôìüÄî9990KSXÉ9ÉY"!!56654&#"56632œrý_9=4I;>ŽTW£Kž´GeD¨™ 5P(2>-/ºoHyVZð(W@ #  ¸"²¼"#@#œ)ˆ&ˆ )ÜÄÄÔìÔì9991ôììüÄþÅÎ9990#"&'532654&##532654&#"56632P\fÆÉQ”DB€<_hkrJTbZNP4{FA—W§±Z`nQ®$%@;@=‰/3--¦piE`dÿã¨ð ›@     %¸²¾´œ ¸@˜œ    †…†…Ä2ÔÄäüäì2ÄÆ9991/æäîÄ2öîÖîî2î2990KSXÉÉííY"333##5!5#335733!9ïïø‰‰æþyþ+ߦßùôÍàæßÍýþ¼ýù›¢¢¨þ™ ýI 4 1ýZdÿãåð'¬@   %!   ¸$²$¾& !&²"œº@ ˜œ#ˆ%…#†… (ÄÔÄÔÄÄäþäî9991/æäîîöîÖîî2þÄ99990KSXÉ9ÉííY"%!!56654&#"56632#335733!qtý];>3J<>‹UX¡JŸ³Icûªß¦ßùôÍàæßÍý¨¨š 5N'2?-0»oH|Tþ• ýI 4 1ýZhÿã¨ð 6:Á@ : 9988 77: %.1* #! ¸´#!¸$²-*¼$!#µ91œ7˜¸@$$8'" :!'"4  †'ˆ4ˆ-";Ä2ÔÄÄÔìÔìî2ÄÆ9999991/Ä2îäö<îîþÄþÅÎî299990KSXÉÉííY"33##5!53#"&'532654&##532654&#"56632#3'ø‰‰æþy‡ïïü%]fÇÉQ”DB€<_hjsJTb[OO5zGA˜V§±Z-ߦßDýù›¢¢¨7þ¼#nQ®$%@;@=‰/3--¦piE`ûq ÿÿfÿãúk'* 1uÿÿ\þFF'JÚÝÿÿ¼=k', ÿduÿÿ“þo-ð'6ÝÝÿÿjþob{'VÝbÿÿfÿã\k'&fuÿÿXÿãuf'FÓÿÿfÿã\k'&fuÿÿXÿãLf'FàÓ\ÿã¨$Kº%@" ¡Ð¡ Иʣ    @"B;%üìô<Äü<Ä1/ìäôäìäîÝ<î20²O&]!5!5!3#!5#"322654&#"¦þºFhššþ˜J²uÏþö Ït³¢syysryy¼ÍrrÍû+¢c\II]üɨ  ¨¨  ¨o¼ãß·«ªÔÄ1ôì0!!otýŒßþÝÑ9‰·üì1ÔÌ0!!Ñhþ˜‰þ}ÿÙÿãð1r@;.*÷(÷1.®®œ˜!2*("%!) 2 +) )% 2ÔÄ2Ä2üÄÄ99999999991Ä2äôüÄþÄî2Ý<î2990%# '#73&&5467#736!2&&#"!!!!3267_Ïpþúþ™KÙXbºXMepÏ_Q¸c³-Vþ­YþÕ2¯~cµTR78õà Ãö87þËNO{vÃ$$ ÃzzOOÅ;ö@ ñÔüÔì1Ô<ì203#%3#Åëë‹ëëöööömîNö8µÔÄ1ÔÄ0K° TX½ÿÀ@878Y@ //]!#3þãÄöþø¤î\ø#Ã@  »@! $ €€ $ÔìÔìÀ999991Ô<ìÔì29990K° TX½$ÿÀ$$@878Y@\             ##+]]'&'&#"#465463232653#"&8- (‹kW%J';'%'‹kW&F#<2j‚'<9j²î“ö8µÔÄ1ÔÄ0K° TX½ÿÀ@878Y@ //]#ÍÆÄþãöþø‡îyöE@ ÔÄ91Ô<Ä90K° TX½ÿÀ@878Y@/// ]!#'#f4ß²ÇDzöþø¡¡‡îyöK@ ÔÄ91ÔÄ290K° TX½ÿÀ@878Y@//// ]373fß²ÇDzßþø°îPö S@  ÔìÔì1ÔÄ2Ì0K° TX½ÿÀ@878Y@///// / ]332673#"&°`LL`¬””¬ö=<<=‡‡w‰ö*·ñ‚Ôì1Ôì0K° TX½ÿÀ@878Y!!wþîöö  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßà>: ~ÿ1BSax~’ÇÝ©À & 0 : ¬!""""+"H"e%Êûÿÿ   0AR^x}’ÆØ©À  0 9 ¬!""""+"H"`%ÊûÿÿÿãÿõÿØÿ ÿ^ÿCÿhÿüöüÛà–à…àVßjÞqÞ_Úï¿8ôüúúü (B¬£„…½–熎‹©¤ŠÙƒ“ñò—ˆÃÝðžªóôõ¢­ÉÇ®bcdËeÈÊÏÌÍÎèfÒÐѯgï‘ÕÓÔhêì‰jikmln oqprsutvwéxzy{}|¸¡~€ëíºýþÿøÖùúãä×àÚÛÜßØÞ²³¶·Ä´µÅ‚‡«˜¨š™î¼¥’”•ÍfÉɦ+ô‹‘ Bú{sè°¨¤/)´Ù mRo Ñì‘b‘ç‘¢‘‰‘\‘ž‘‘‰‘}‘j3å3´Ù´Ù´Ù¤‡1 ¼ßf¤¼w¼w¼‘f²¼ú¼úÿ3¼¼ö¼²¼ÍfݼÍf)¼Óu ¼1 Ó=+'ËÿìÍ\¨°ì¨‹´Ï^fXº¬¾Xº\mX{'º\²¬¾¬¾ÿ¼R¬¾¬Vª²¬Xº¬º\ò¬ÃjÓ² 7dH)7¨\²ì²´Ù1 1 ßfw¼²¼Íf¼fXfXfXfXfXfX¾XmXmXmXmX¾¬¾ÿÕ¾ÿþ¾<²¬XXXXX² ² ² ² 5²‘®‘}'Á¬'mÅ´Ù®Í-ªÃ´Ù´Ù´Ù‘ã®Z;¾)L–'ÿÝá3ƒžƒu'7bXN¤¦´ÙVL‘´Ù“+ž+Á¢‘1 1 Íf VfÁXBÓB¼ Ó ´Ùô7ËÿìVþhJLžLÁî+î'3 Ñ “B“ …B1 w¼1 w¼w¼ú¼úÿëú)úÍfÍfÍf¼¼¼¾¬‡¤Å°wãÁV‡#ÿ¤øÿÛÓÃjÍ\¨\ì´!XËÿì7缺¬´Ù´{mZHdHdHh‘fº\ú¼ÓÃjßf¾Xßf¾Xº\Ro Ñ‘ÿÙÅm¤²‡‡°wÿ   !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóõôöøùúûüýþÿ    sfthyphenperiodcenteredEuroc6459c6460c6461c6462c6463c6466c6467c6468%%%%NqÓ]ÜÆÞ 6©ÇÞô N{òU•å?uã<_НÐóOû ¡ K Á í G € © è E a ç > ‡ Ä*Ÿ2e¡àç:\u—¹ÍÚ#pÅ|¿è$†£ZŸí<~*‰ÑZ@!âIªÀ"dqjw„‘ž«¸ÅÒßìù   - : G T a n { ˆ • ¢ ¯ ¼ É Ö ã ð!!]!È""¨"Ú##†$.$Á%!%K%‹%Î&H''n'¥'Ô((Š(Ú)6){)ž)Ø*<*Ê++p,5,Ú-8-a-}-Î.B.½.ä//\/Œ/Œ/™/¦/³00¢0¹0Ð1161U1t1¨1ü2 2292É2ì33v3Ò44-4L4~5*575D5Q5^5k5x5…5’5Ÿ5¬5¹5Æ5Ó5à5í6 676Ê6ú7H7k7³7ï8'8W8†8Ô9-9:9G9T9a9„::Ç:Ô:á;O;ž;´;í<ª>·>Ä>Ñ>Þ>ë>ø?????–?­@4@T@AA@AuA­AðB‚ 7þÓ9ÿk:ÿ¤;ÿY<þÓ»þÓêþÓ$&$&$&$&$7ÿa$8ÿÁ$9ÿu$:ÿ¤$<ÿ<$Yÿ·$\ÿ·$hÿÁ$µÿD$·ÿD$ºÿ·$»ÿ<$Är$År$ÓÿÁ$ÔÿÁ$ÕÿÁ$êÿ<$ëÿ·%9ÿ­%:ÿ%<ÿ%»ÿ%êÿ&/&6&&µK&·K&ã&&ù&'&'<ÿk'»ÿk'ÄÿÜ'ÅÿÜ'êÿk)þ·)ÿÁ)þÓ)ÿ)ÿ)$ÿ)Dÿˆ)Hÿ­)Rÿ­)Uÿ})Xÿš)\ÿ)bÿ)iÿˆ)jÿˆ)kÿˆ)lÿˆ)mÿˆ)nÿˆ)pÿ­)qÿ­)rÿ­)sÿ­)yÿ­)zÿ­){ÿ­)|ÿ­)}ÿ­)~ÿš)ÿš)€ÿš)ÿš) ÿˆ)¡ÿ­)­ÿ)®ÿ)±ÿ­)·&)ºÿ)Äþ­)Åþ­)Çÿ)Éÿ)ëÿ*7ÿÜ*<ÿÓ*»ÿÓ*êÿÓ.ÿN.&ÿ¤.2ÿ¤.8ÿÜ.HÿÜ.RÿÜ.XÿÜ.\ÿ}.dÿ¤.gÿ¤.hÿÜ.pÿÜ.qÿÜ.rÿÜ.sÿÜ.yÿÜ.zÿÜ.{ÿÜ.|ÿÜ.}ÿÜ.~ÿÜ.ÿÜ.€ÿÜ.ÿÜ.‘ÿÉ.¡ÿÜ.¯ÿ¤.°ÿš.±ÿÜ.ºÿ}.Ä&.Å&.Ðÿ¤.Ñÿ¤.Òÿ¤.ÓÿÜ.ÔÿÜ.ÕÿÜ.ëÿ}.ûÿ¤.ýÿ¤/2ÿ·/7þ­/8ÿ·/9þæ/:ÿa/<þÁ/\ÿu/gÿ·/hÿ·/‘ÿ·/¯ÿ·/°ÿ·/µþ/·þ)/ºÿu/»þÁ/Ðÿ·/Ñÿ·/Òÿ·/Óÿ·/Ôÿ·/Õÿ·/êþÁ/ëÿu2ÿÓ2&2ÿÓ2$ÿÉ29ÿÉ2;ÿ·2<ÿ·2bÿÉ2­ÿÉ2®ÿÉ2»ÿ·2ÇÿÉ2ÉÿÉ2êÿ·3þˆ3ÿÜ3þˆ3$ÿD3DÿÉ3VÿÜ3\&3bÿD3iÿÉ3jÿÉ3kÿÉ3lÿÉ3mÿÉ3nÿÉ3 ÿÉ3­ÿD3®ÿD3µ&3·93º&3Äþa3Åþa3ÇÿD3ÉÿD3äÿÜ3ë&3úÿÜ4&5&5&57ÿ¤5<ÿ5\ÿ¤5ºÿ¤5»ÿ5êÿ5ëÿ¤66ÿ¤6ãÿ¤6ùÿ¤7þÜ7þÓ7þÉ7ÿ7ÿ7$ÿa77/7Dþø7Fþð7Hþð7Rþð7Uÿ7Vþð7Xÿ7Zÿ7\ÿ 7bÿa7iþø7jþø7kþø7lþø7mþø7nþø7oþð7pþð7qþð7rþð7sþð7yþð7zþð7{þð7|þð7}þð7~ÿ7ÿ7€ÿ7ÿ7 ÿ<7¡ÿa7­ÿa7®ÿa7±ÿa7ºÿ 7Äþø7Åþø7Çÿa7Éÿa7äþð7ëÿ 7úþð7üþð7þþð8$ÿÁ8bÿÁ8­ÿÁ8®ÿÁ8ÇÿÁ8ÉÿÁ9þø9ÿk9þø9ÿ¤9ÿ¤9$ÿu92ÿÜ9Dÿ9Hÿ9LÿÜ9Rÿ9Xÿ·9bÿu9gÿÜ9iÿ9jÿ9kÿ9lÿ9mÿ9nÿ9pÿ9qÿ9rÿ9sÿ9yÿ9zÿ9{ÿ9|ÿ9}ÿ9~ÿ·9ÿ·9€ÿ·9ÿ·9‘ÿÜ9 ÿ9¡ÿ9­ÿu9®ÿu9¯ÿÜ9°ÿÜ9±ÿ9Äÿ9ÅÿD9Çÿu9Éÿu9ÐÿÜ9ÑÿÜ9ÒÿÜ:ÿY:ÿ¤:ÿY:ÿÁ:ÿÁ:$ÿ¤:Dÿ·:Hÿ·:Rÿ·:UÿÜ:bÿ¤:iÿ·:jÿ·:kÿ·:lÿ·:mÿ·:nÿ·:pÿ·:qÿ·:rÿ·:sÿ·:yÿ·:zÿ·:{ÿ·:|ÿ·:}ÿ·: ÿ·:¡ÿ·:­ÿ¤:®ÿ¤:±ÿ·:Çÿ¤:Éÿ¤;ÿY;&ÿ·;2ÿ·;HÿÉ;dÿ·;gÿ·;pÿÉ;qÿÉ;rÿÉ;sÿÉ;‘ÿ·;¯ÿ·;°ÿ·;Ä&;Å&;Ðÿ·;Ñÿ·;Òÿ·;ûÿ·;ýÿ·<þ­<þÓ<þ­<ÿN<ÿN<$ÿ<<&ÿ·<2ÿ·<DÿD<HÿD<RÿD<Xÿk<bÿ<<dÿ·<gÿ·<iÿD<jÿD<kÿD<lÿD<mÿD<nÿD<pÿD<qÿD<rÿD<sÿD<yÿD<zÿD<{ÿD<|ÿD<}ÿD<~ÿk<ÿk<€ÿk<ÿk<‘ÿÜ< ÿD<¡ÿD<­ÿ<<®ÿ<<¯ÿ·<°ÿ¤<±ÿD<Äþˆ<ÅþÓ<Çÿ<<Éÿ<<Ðÿ·<Ñÿ·<Òÿ·<ûÿ·<ýÿ·=ÿÜD\ÿÁDºÿÁDëÿÁIÿIÿÜIÿIµVI·NHÿÉNRÿÉNpÿÉNqÿÉNrÿÉNsÿÉNyÿÉNzÿÉN{ÿÉN|ÿÉN}ÿÉN¡ÿÓN±ÿÉUþÓUþÜUµ&U·VYÿYYÿYZÿ}Zÿ}\ÿa\ÿDb&b&b&b&b7ÿab8ÿÁb9ÿub:ÿ¤b<ÿ<bYÿ·b\ÿ·bhÿÁbµÿDb·ÿDbºÿ·b»ÿ<bÄrbÅrbÓÿÁbÔÿÁbÕÿÁbêÿ<bëÿ·d/d6&dµKd·Kdã&dù&gÿÓg&gÿÓg$ÿÉg9ÿÉg;ÿ·g<ÿ·gbÿÉg­ÿÉg®ÿÉg»ÿ·gÇÿÉgÉÿÉgêÿ·h$ÿÁhbÿÁh­ÿÁh®ÿÁhÇÿÁhÉÿÁi\ÿÁiºÿÁiëÿÁj\ÿÁjºÿÁjëÿÁk\ÿÁkºÿÁkëÿÁl\ÿÁlºÿÁlëÿÁm\ÿÁmºÿÁmëÿÁn\ÿÁnºÿÁnëÿÁÿÜ‘ÿÓ‘&‘ÿÓ‘$ÿÜ‘9ÿÜ‘;ÿ·‘<ÿÜ‘bÿÜ‘­ÿÜ‘®ÿÜ‘»ÿÜ‘ÇÿÜ‘ÉÿÜ‘êÿÜ­&­&­&­&­7ÿa­8ÿÁ­9ÿu­:ÿ¤­<ÿ<­Yÿ·­\ÿ·­hÿÁ­µÿD­·ÿD­ºÿ·­»ÿ<­Är­År­ÓÿÁ­ÔÿÁ­ÕÿÁ­êÿ<­ëÿ·®&®&®&®&®7ÿa®8ÿÁ®9ÿu®:ÿ¤®<ÿ<®Yÿ·®\ÿ·®hÿÁ®µÿD®·ÿD®ºÿ·®»ÿ<®Är®År®ÓÿÁ®ÔÿÁ®ÕÿÁ®êÿ<®ëÿ·¯ÿÓ¯&¯ÿÓ¯$ÿɯ9ÿɯ;ÿ·¯<ÿ·¯bÿɯ­ÿɯ®ÿɯ»ÿ·¯ÇÿɯÉÿɯêÿ·´$þø´-ÿ¤´<&´bþø´þÓ´­þø´®þø´»&´Çþø´Éþø´ê&¶$ÿ¶-ÿ¤¶9&¶<K¶bÿ¶þø¶­ÿ¶®ÿ¶»K¶Çÿ¶Éÿ¶êKºÿaºÿD»þ­»þÓ»þ­»ÿN»ÿN»$ÿ<»&ÿ·»2ÿ·»DÿD»HÿD»RÿD»Xÿk»bÿ<»dÿ·»gÿ·»iÿD»jÿD»kÿD»lÿD»mÿD»nÿD»pÿD»qÿD»rÿD»sÿD»yÿD»zÿD»{ÿD»|ÿD»}ÿD»~ÿk»ÿk»€ÿk»ÿk»‘ÿÜ» ÿD»¡ÿD»­ÿ<»®ÿ<»¯ÿ·»°ÿ¤»±ÿD»Äþˆ»ÅþÓ»Çÿ<»Éÿ<»Ðÿ·»Ñÿ·»Òÿ·»ûÿ·»ýÿ·Ä7þaÄ9þæÄ:ÿ)Ä<þšÄ»þšÄêþšÅ7þaÅ9þæÅ:ÿ)Å<þšÅ»þšÅêþšÇ&Ç&Ç&Ç&Ç7ÿaÇ8ÿÁÇ9ÿuÇ:ÿ¤Ç<ÿ<ÇYÿ·Ç\ÿ·ÇhÿÁǵÿDÇ·ÿDǺÿ·Ç»ÿ<ÇÄrÇÅrÇÓÿÁÇÔÿÁÇÕÿÁÇêÿ<Çëÿ·É&É&É&É&É7ÿaÉ8ÿÁÉ9ÿuÉ:ÿ¤É<ÿ<ÉYÿ·É\ÿ·ÉhÿÁɵÿDÉ·ÿDɺÿ·É»ÿ<ÉÄrÉÅrÉÓÿÁÉÔÿÁÉÕÿÁÉêÿ<Éëÿ·ÐÿÓÐ&ÐÿÓÐ$ÿÉÐ9ÿÉÐ;ÿ·Ð<ÿ·ÐbÿÉЭÿÉЮÿÉлÿ·ÐÇÿÉÐÉÿÉÐêÿ·ÑÿÓÑ&ÑÿÓÑ$ÿÉÑ9ÿÉÑ;ÿ·Ñ<ÿ·ÑbÿÉÑ­ÿÉÑ®ÿÉÑ»ÿ·ÑÇÿÉÑÉÿÉÑêÿ·ÒÿÓÒ&ÒÿÓÒ$ÿÉÒ9ÿÉÒ;ÿ·Ò<ÿ·ÒbÿÉÒ­ÿÉÒ®ÿÉÒ»ÿ·ÒÇÿÉÒÉÿÉÒêÿ·Ó$ÿÁÓbÿÁÓ­ÿÁÓ®ÿÁÓÇÿÁÓÉÿÁÔ$ÿÁÔbÿÁÔ­ÿÁÔ®ÿÁÔÇÿÁÔÉÿÁÕ$ÿÁÕbÿÁÕ­ÿÁÕ®ÿÁÕÇÿÁÕÉÿÁá2ÿ·á7þ­á8ÿ·á9þæá:ÿaá<þÁá\ÿuágÿ·áhÿ·á‘ÿ·á¯ÿ·á°ÿ·áµþˆá·þ­áºÿuá»þÁáÐÿ·áÑÿ·áÒÿ·áÓÿ·áÔÿ·áÕÿ·áêþÁáëÿuã6ÿ¤ããÿ¤ãùÿ¤åÿÜè&è<ÿkè»ÿkèÄÿÜèÅÿÜèêÿkêþ­êþÓêþ­êÿNêÿNê$ÿ<ê&ÿ·ê2ÿ·êDÿDêHÿDêRÿDêXÿkêbÿ<êdÿ·êgÿ·êiÿDêjÿDêkÿDêlÿDêmÿDênÿDêpÿDêqÿDêrÿDêsÿDêyÿDêzÿDê{ÿDê|ÿDê}ÿDê~ÿkêÿkê€ÿkêÿkê‘ÿÜê ÿDê¡ÿDê­ÿ<ê®ÿ<ê¯ÿ·ê°ÿ¤ê±ÿDêÄþˆêÅþÓêÇÿ<êÉÿ<êÐÿ·êÑÿ·êÒÿ·êûÿ·êýÿ·ëÿaëÿDö7ÿÜö<ÿÓö»ÿÓöêÿÓù6ÿ¤ùãÿ¤ùùÿ¤û/û6&ûµKû·Kûã&ûù&ý/ý6&ýµKý·Kýã&ýù& NE@í§mþ …þhþh V •¼GÌþBGÌSf €¯ JBits ûþšmãB³É`#cÕVeraSansBdÿÿÿÿ6ÿÿþ628B00@                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               !                        !        #                     #        $                       $        %                       %        '                   '       (             !   (       ÿÿÿð_<õº¹Ìº¼–²þhþ Vmfreewheeling-0.6.6/data/fweelin.xml000066400000000000000000000033661370736313100172670ustar00rootroot00000000000000 ]> &basics; &graphics; &interfaces; freewheeling-0.6.6/data/gdb-stackdump-cmds000066400000000000000000000003151370736313100204770ustar00rootroot00000000000000set prompt echo \n\n*** Stacktrace\n where echo \n\n*** Symbols\n frame 4 set $x = 50 while ($x) info locals up set $x-- end echo \n*** Backtrace All Threads\n\n thread apply all bt echo \n--- detach quit freewheeling-0.6.6/data/graphics.xml000066400000000000000000000120521370736313100174260ustar00rootroot00000000000000 freewheeling-0.6.6/data/interfaces.xml000066400000000000000000000027561370736313100177630ustar00rootroot00000000000000 freewheeling-0.6.6/data/mercury.xml000066400000000000000000000302661370736313100173230ustar00rootroot00000000000000 freewheeling-0.6.6/data/midifootswitch.xml000066400000000000000000000065261370736313100206730ustar00rootroot00000000000000 freewheeling-0.6.6/data/midikeyboard.xml000066400000000000000000000246171370736313100203030ustar00rootroot00000000000000 freewheeling-0.6.6/data/patches-b3.xml000066400000000000000000000006411370736313100175600ustar00rootroot00000000000000 freewheeling-0.6.6/data/patches-channels.xml000066400000000000000000000015661370736313100210560ustar00rootroot00000000000000 freewheeling-0.6.6/data/patches1.xml000066400000000000000000000614141370736313100173440ustar00rootroot00000000000000 freewheeling-0.6.6/data/patches2.xml000066400000000000000000000612621370736313100173460ustar00rootroot00000000000000 freewheeling-0.6.6/data/patches3.xml000066400000000000000000000110171370736313100173400ustar00rootroot00000000000000 freewheeling-0.6.6/data/pckeyboard.xml000066400000000000000000000161351370736313100177570ustar00rootroot00000000000000 freewheeling-0.6.6/data/pcr-m1.xml000066400000000000000000000361521370736313100167340ustar00rootroot00000000000000 freewheeling-0.6.6/data/rme-hdsp.xml000066400000000000000000000114771370736313100173570ustar00rootroot00000000000000 freewheeling-0.6.6/data/synthedit.xml000066400000000000000000000255161370736313100176520ustar00rootroot00000000000000 freewheeling-0.6.6/depcomp000077500000000000000000000560201370736313100155530ustar00rootroot00000000000000#! /bin/sh # depcomp - compile a program generating dependencies as side-effects scriptversion=2018-03-07.03; # UTC # Copyright (C) 1999-2018 Free Software Foundation, Inc. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, 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 . # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # Originally written by Alexandre Oliva . case $1 in '') echo "$0: No command. Try '$0 --help' for more information." 1>&2 exit 1; ;; -h | --h*) cat <<\EOF Usage: depcomp [--help] [--version] PROGRAM [ARGS] Run PROGRAMS ARGS to compile a file, generating dependencies as side-effects. Environment variables: depmode Dependency tracking mode. source Source file read by 'PROGRAMS ARGS'. object Object file output by 'PROGRAMS ARGS'. DEPDIR directory where to store dependencies. depfile Dependency file to output. tmpdepfile Temporary file to use when outputting dependencies. libtool Whether libtool is used (yes/no). Report bugs to . EOF exit $? ;; -v | --v*) echo "depcomp $scriptversion" exit $? ;; esac # Get the directory component of the given path, and save it in the # global variables '$dir'. Note that this directory component will # be either empty or ending with a '/' character. This is deliberate. set_dir_from () { case $1 in */*) dir=`echo "$1" | sed -e 's|/[^/]*$|/|'`;; *) dir=;; esac } # Get the suffix-stripped basename of the given path, and save it the # global variable '$base'. set_base_from () { base=`echo "$1" | sed -e 's|^.*/||' -e 's/\.[^.]*$//'` } # If no dependency file was actually created by the compiler invocation, # we still have to create a dummy depfile, to avoid errors with the # Makefile "include basename.Plo" scheme. make_dummy_depfile () { echo "#dummy" > "$depfile" } # Factor out some common post-processing of the generated depfile. # Requires the auxiliary global variable '$tmpdepfile' to be set. aix_post_process_depfile () { # If the compiler actually managed to produce a dependency file, # post-process it. if test -f "$tmpdepfile"; then # Each line is of the form 'foo.o: dependency.h'. # Do two passes, one to just change these to # $object: dependency.h # and one to simply output # dependency.h: # which is needed to avoid the deleted-header problem. { sed -e "s,^.*\.[$lower]*:,$object:," < "$tmpdepfile" sed -e "s,^.*\.[$lower]*:[$tab ]*,," -e 's,$,:,' < "$tmpdepfile" } > "$depfile" rm -f "$tmpdepfile" else make_dummy_depfile fi } # A tabulation character. tab=' ' # A newline character. nl=' ' # Character ranges might be problematic outside the C locale. # These definitions help. upper=ABCDEFGHIJKLMNOPQRSTUVWXYZ lower=abcdefghijklmnopqrstuvwxyz digits=0123456789 alpha=${upper}${lower} if test -z "$depmode" || test -z "$source" || test -z "$object"; then echo "depcomp: Variables source, object and depmode must be set" 1>&2 exit 1 fi # Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po. depfile=${depfile-`echo "$object" | sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`} tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`} rm -f "$tmpdepfile" # Avoid interferences from the environment. gccflag= dashmflag= # Some modes work just like other modes, but use different flags. We # parameterize here, but still list the modes in the big case below, # to make depend.m4 easier to write. Note that we *cannot* use a case # here, because this file can only contain one case statement. if test "$depmode" = hp; then # HP compiler uses -M and no extra arg. gccflag=-M depmode=gcc fi if test "$depmode" = dashXmstdout; then # This is just like dashmstdout with a different argument. dashmflag=-xM depmode=dashmstdout fi cygpath_u="cygpath -u -f -" if test "$depmode" = msvcmsys; then # This is just like msvisualcpp but w/o cygpath translation. # Just convert the backslash-escaped backslashes to single forward # slashes to satisfy depend.m4 cygpath_u='sed s,\\\\,/,g' depmode=msvisualcpp fi if test "$depmode" = msvc7msys; then # This is just like msvc7 but w/o cygpath translation. # Just convert the backslash-escaped backslashes to single forward # slashes to satisfy depend.m4 cygpath_u='sed s,\\\\,/,g' depmode=msvc7 fi if test "$depmode" = xlc; then # IBM C/C++ Compilers xlc/xlC can output gcc-like dependency information. gccflag=-qmakedep=gcc,-MF depmode=gcc fi case "$depmode" in gcc3) ## gcc 3 implements dependency tracking that does exactly what ## we want. Yay! Note: for some reason libtool 1.4 doesn't like ## it if -MD -MP comes after the -MF stuff. Hmm. ## Unfortunately, FreeBSD c89 acceptance of flags depends upon ## the command line argument order; so add the flags where they ## appear in depend2.am. Note that the slowdown incurred here ## affects only configure: in makefiles, %FASTDEP% shortcuts this. for arg do case $arg in -c) set fnord "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" "$arg" ;; *) set fnord "$@" "$arg" ;; esac shift # fnord shift # $arg done "$@" stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi mv "$tmpdepfile" "$depfile" ;; gcc) ## Note that this doesn't just cater to obsosete pre-3.x GCC compilers. ## but also to in-use compilers like IMB xlc/xlC and the HP C compiler. ## (see the conditional assignment to $gccflag above). ## There are various ways to get dependency output from gcc. Here's ## why we pick this rather obscure method: ## - Don't want to use -MD because we'd like the dependencies to end ## up in a subdir. Having to rename by hand is ugly. ## (We might end up doing this anyway to support other compilers.) ## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like ## -MM, not -M (despite what the docs say). Also, it might not be ## supported by the other compilers which use the 'gcc' depmode. ## - Using -M directly means running the compiler twice (even worse ## than renaming). if test -z "$gccflag"; then gccflag=-MD, fi "$@" -Wp,"$gccflag$tmpdepfile" stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" echo "$object : \\" > "$depfile" # The second -e expression handles DOS-style file names with drive # letters. sed -e 's/^[^:]*: / /' \ -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile" ## This next piece of magic avoids the "deleted header file" problem. ## The problem is that when a header file which appears in a .P file ## is deleted, the dependency causes make to die (because there is ## typically no way to rebuild the header). We avoid this by adding ## dummy dependencies for each header file. Too bad gcc doesn't do ## this for us directly. ## Some versions of gcc put a space before the ':'. On the theory ## that the space means something, we add a space to the output as ## well. hp depmode also adds that space, but also prefixes the VPATH ## to the object. Take care to not repeat it in the output. ## Some versions of the HPUX 10.20 sed can't process this invocation ## correctly. Breaking it into two sed invocations is a workaround. tr ' ' "$nl" < "$tmpdepfile" \ | sed -e 's/^\\$//' -e '/^$/d' -e "s|.*$object$||" -e '/:$/d' \ | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; hp) # This case exists only to let depend.m4 do its work. It works by # looking at the text of this script. This case will never be run, # since it is checked for above. exit 1 ;; sgi) if test "$libtool" = yes; then "$@" "-Wp,-MDupdate,$tmpdepfile" else "$@" -MDupdate "$tmpdepfile" fi stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files echo "$object : \\" > "$depfile" # Clip off the initial element (the dependent). Don't try to be # clever and replace this with sed code, as IRIX sed won't handle # lines with more than a fixed number of characters (4096 in # IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines; # the IRIX cc adds comments like '#:fec' to the end of the # dependency line. tr ' ' "$nl" < "$tmpdepfile" \ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' \ | tr "$nl" ' ' >> "$depfile" echo >> "$depfile" # The second pass generates a dummy entry for each header file. tr ' ' "$nl" < "$tmpdepfile" \ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \ >> "$depfile" else make_dummy_depfile fi rm -f "$tmpdepfile" ;; xlc) # This case exists only to let depend.m4 do its work. It works by # looking at the text of this script. This case will never be run, # since it is checked for above. exit 1 ;; aix) # The C for AIX Compiler uses -M and outputs the dependencies # in a .u file. In older versions, this file always lives in the # current directory. Also, the AIX compiler puts '$object:' at the # start of each line; $object doesn't have directory information. # Version 6 uses the directory in both cases. set_dir_from "$object" set_base_from "$object" if test "$libtool" = yes; then tmpdepfile1=$dir$base.u tmpdepfile2=$base.u tmpdepfile3=$dir.libs/$base.u "$@" -Wc,-M else tmpdepfile1=$dir$base.u tmpdepfile2=$dir$base.u tmpdepfile3=$dir$base.u "$@" -M fi stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" exit $stat fi for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" do test -f "$tmpdepfile" && break done aix_post_process_depfile ;; tcc) # tcc (Tiny C Compiler) understand '-MD -MF file' since version 0.9.26 # FIXME: That version still under development at the moment of writing. # Make that this statement remains true also for stable, released # versions. # It will wrap lines (doesn't matter whether long or short) with a # trailing '\', as in: # # foo.o : \ # foo.c \ # foo.h \ # # It will put a trailing '\' even on the last line, and will use leading # spaces rather than leading tabs (at least since its commit 0394caf7 # "Emit spaces for -MD"). "$@" -MD -MF "$tmpdepfile" stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" # Each non-empty line is of the form 'foo.o : \' or ' dep.h \'. # We have to change lines of the first kind to '$object: \'. sed -e "s|.*:|$object :|" < "$tmpdepfile" > "$depfile" # And for each line of the second kind, we have to emit a 'dep.h:' # dummy dependency, to avoid the deleted-header problem. sed -n -e 's|^ *\(.*\) *\\$|\1:|p' < "$tmpdepfile" >> "$depfile" rm -f "$tmpdepfile" ;; ## The order of this option in the case statement is important, since the ## shell code in configure will try each of these formats in the order ## listed in this file. A plain '-MD' option would be understood by many ## compilers, so we must ensure this comes after the gcc and icc options. pgcc) # Portland's C compiler understands '-MD'. # Will always output deps to 'file.d' where file is the root name of the # source file under compilation, even if file resides in a subdirectory. # The object file name does not affect the name of the '.d' file. # pgcc 10.2 will output # foo.o: sub/foo.c sub/foo.h # and will wrap long lines using '\' : # foo.o: sub/foo.c ... \ # sub/foo.h ... \ # ... set_dir_from "$object" # Use the source, not the object, to determine the base name, since # that's sadly what pgcc will do too. set_base_from "$source" tmpdepfile=$base.d # For projects that build the same source file twice into different object # files, the pgcc approach of using the *source* file root name can cause # problems in parallel builds. Use a locking strategy to avoid stomping on # the same $tmpdepfile. lockdir=$base.d-lock trap " echo '$0: caught signal, cleaning up...' >&2 rmdir '$lockdir' exit 1 " 1 2 13 15 numtries=100 i=$numtries while test $i -gt 0; do # mkdir is a portable test-and-set. if mkdir "$lockdir" 2>/dev/null; then # This process acquired the lock. "$@" -MD stat=$? # Release the lock. rmdir "$lockdir" break else # If the lock is being held by a different process, wait # until the winning process is done or we timeout. while test -d "$lockdir" && test $i -gt 0; do sleep 1 i=`expr $i - 1` done fi i=`expr $i - 1` done trap - 1 2 13 15 if test $i -le 0; then echo "$0: failed to acquire lock after $numtries attempts" >&2 echo "$0: check lockdir '$lockdir'" >&2 exit 1 fi if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" # Each line is of the form `foo.o: dependent.h', # or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'. # Do two passes, one to just change these to # `$object: dependent.h' and one to simply `dependent.h:'. sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile" # Some versions of the HPUX 10.20 sed can't process this invocation # correctly. Breaking it into two sed invocations is a workaround. sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" \ | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; hp2) # The "hp" stanza above does not work with aCC (C++) and HP's ia64 # compilers, which have integrated preprocessors. The correct option # to use with these is +Maked; it writes dependencies to a file named # 'foo.d', which lands next to the object file, wherever that # happens to be. # Much of this is similar to the tru64 case; see comments there. set_dir_from "$object" set_base_from "$object" if test "$libtool" = yes; then tmpdepfile1=$dir$base.d tmpdepfile2=$dir.libs/$base.d "$@" -Wc,+Maked else tmpdepfile1=$dir$base.d tmpdepfile2=$dir$base.d "$@" +Maked fi stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile1" "$tmpdepfile2" exit $stat fi for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" do test -f "$tmpdepfile" && break done if test -f "$tmpdepfile"; then sed -e "s,^.*\.[$lower]*:,$object:," "$tmpdepfile" > "$depfile" # Add 'dependent.h:' lines. sed -ne '2,${ s/^ *// s/ \\*$// s/$/:/ p }' "$tmpdepfile" >> "$depfile" else make_dummy_depfile fi rm -f "$tmpdepfile" "$tmpdepfile2" ;; tru64) # The Tru64 compiler uses -MD to generate dependencies as a side # effect. 'cc -MD -o foo.o ...' puts the dependencies into 'foo.o.d'. # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put # dependencies in 'foo.d' instead, so we check for that too. # Subdirectories are respected. set_dir_from "$object" set_base_from "$object" if test "$libtool" = yes; then # Libtool generates 2 separate objects for the 2 libraries. These # two compilations output dependencies in $dir.libs/$base.o.d and # in $dir$base.o.d. We have to check for both files, because # one of the two compilations can be disabled. We should prefer # $dir$base.o.d over $dir.libs/$base.o.d because the latter is # automatically cleaned when .libs/ is deleted, while ignoring # the former would cause a distcleancheck panic. tmpdepfile1=$dir$base.o.d # libtool 1.5 tmpdepfile2=$dir.libs/$base.o.d # Likewise. tmpdepfile3=$dir.libs/$base.d # Compaq CCC V6.2-504 "$@" -Wc,-MD else tmpdepfile1=$dir$base.d tmpdepfile2=$dir$base.d tmpdepfile3=$dir$base.d "$@" -MD fi stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" exit $stat fi for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" do test -f "$tmpdepfile" && break done # Same post-processing that is required for AIX mode. aix_post_process_depfile ;; msvc7) if test "$libtool" = yes; then showIncludes=-Wc,-showIncludes else showIncludes=-showIncludes fi "$@" $showIncludes > "$tmpdepfile" stat=$? grep -v '^Note: including file: ' "$tmpdepfile" if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" echo "$object : \\" > "$depfile" # The first sed program below extracts the file names and escapes # backslashes for cygpath. The second sed program outputs the file # name when reading, but also accumulates all include files in the # hold buffer in order to output them again at the end. This only # works with sed implementations that can handle large buffers. sed < "$tmpdepfile" -n ' /^Note: including file: *\(.*\)/ { s//\1/ s/\\/\\\\/g p }' | $cygpath_u | sort -u | sed -n ' s/ /\\ /g s/\(.*\)/'"$tab"'\1 \\/p s/.\(.*\) \\/\1:/ H $ { s/.*/'"$tab"'/ G p }' >> "$depfile" echo >> "$depfile" # make sure the fragment doesn't end with a backslash rm -f "$tmpdepfile" ;; msvc7msys) # This case exists only to let depend.m4 do its work. It works by # looking at the text of this script. This case will never be run, # since it is checked for above. exit 1 ;; #nosideeffect) # This comment above is used by automake to tell side-effect # dependency tracking mechanisms from slower ones. dashmstdout) # Important note: in order to support this mode, a compiler *must* # always write the preprocessed file to stdout, regardless of -o. "$@" || exit $? # Remove the call to Libtool. if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi # Remove '-o $object'. IFS=" " for arg do case $arg in -o) shift ;; $object) shift ;; *) set fnord "$@" "$arg" shift # fnord shift # $arg ;; esac done test -z "$dashmflag" && dashmflag=-M # Require at least two characters before searching for ':' # in the target name. This is to cope with DOS-style filenames: # a dependency such as 'c:/foo/bar' could be seen as target 'c' otherwise. "$@" $dashmflag | sed "s|^[$tab ]*[^:$tab ][^:][^:]*:[$tab ]*|$object: |" > "$tmpdepfile" rm -f "$depfile" cat < "$tmpdepfile" > "$depfile" # Some versions of the HPUX 10.20 sed can't process this sed invocation # correctly. Breaking it into two sed invocations is a workaround. tr ' ' "$nl" < "$tmpdepfile" \ | sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \ | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; dashXmstdout) # This case only exists to satisfy depend.m4. It is never actually # run, as this mode is specially recognized in the preamble. exit 1 ;; makedepend) "$@" || exit $? # Remove any Libtool call if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi # X makedepend shift cleared=no eat=no for arg do case $cleared in no) set ""; shift cleared=yes ;; esac if test $eat = yes; then eat=no continue fi case "$arg" in -D*|-I*) set fnord "$@" "$arg"; shift ;; # Strip any option that makedepend may not understand. Remove # the object too, otherwise makedepend will parse it as a source file. -arch) eat=yes ;; -*|$object) ;; *) set fnord "$@" "$arg"; shift ;; esac done obj_suffix=`echo "$object" | sed 's/^.*\././'` touch "$tmpdepfile" ${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@" rm -f "$depfile" # makedepend may prepend the VPATH from the source file name to the object. # No need to regex-escape $object, excess matching of '.' is harmless. sed "s|^.*\($object *:\)|\1|" "$tmpdepfile" > "$depfile" # Some versions of the HPUX 10.20 sed can't process the last invocation # correctly. Breaking it into two sed invocations is a workaround. sed '1,2d' "$tmpdepfile" \ | tr ' ' "$nl" \ | sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \ | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" "$tmpdepfile".bak ;; cpp) # Important note: in order to support this mode, a compiler *must* # always write the preprocessed file to stdout. "$@" || exit $? # Remove the call to Libtool. if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi # Remove '-o $object'. IFS=" " for arg do case $arg in -o) shift ;; $object) shift ;; *) set fnord "$@" "$arg" shift # fnord shift # $arg ;; esac done "$@" -E \ | sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \ -e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \ | sed '$ s: \\$::' > "$tmpdepfile" rm -f "$depfile" echo "$object : \\" > "$depfile" cat < "$tmpdepfile" >> "$depfile" sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; msvisualcpp) # Important note: in order to support this mode, a compiler *must* # always write the preprocessed file to stdout. "$@" || exit $? # Remove the call to Libtool. if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi IFS=" " for arg do case "$arg" in -o) shift ;; $object) shift ;; "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI") set fnord "$@" shift shift ;; *) set fnord "$@" "$arg" shift shift ;; esac done "$@" -E 2>/dev/null | sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::\1:p' | $cygpath_u | sort -u > "$tmpdepfile" rm -f "$depfile" echo "$object : \\" > "$depfile" sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::'"$tab"'\1 \\:p' >> "$depfile" echo "$tab" >> "$depfile" sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::\1\::p' >> "$depfile" rm -f "$tmpdepfile" ;; msvcmsys) # This case exists only to let depend.m4 do its work. It works by # looking at the text of this script. This case will never be run, # since it is checked for above. exit 1 ;; none) exec "$@" ;; *) echo "Unknown depmode $depmode" 1>&2 exit 1 ;; esac exit 0 # Local Variables: # mode: shell-script # sh-indentation: 2 # eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC0" # time-stamp-end: "; # UTC" # End: freewheeling-0.6.6/examples/000077500000000000000000000000001370736313100160115ustar00rootroot00000000000000freewheeling-0.6.6/examples/README000066400000000000000000000052371370736313100167000ustar00rootroot00000000000000Loops and Scenes Examples ------------------------- You can find sample loops and scenes in the 'Remix Playground' area of the Freewheeling website. http://freewheeling.sourceforge.net/#scenes NEW in V0.5.3- Combination Zone Patches --------------------------------------- * More flexible MIDI patch routing. - Combination patches allow you to split one MIDI controller into a range of zones. This allows you to control several different sounds or softsynths from one MIDI control source. A patch defines the zones, as well as the output port and channel that each zone sends to. You can also send MIDI program and bank change messages for each zone, allowing you to switch programs on external synths. All of this functionality is integrated into the patch browser, so you can seamlessly control other synth apps and sound modules from within FreeWheeling. See 'examples/combipatchdemo.xml' for an example configuration. Patch Browser Definition Example -------------------------------- The file patches1.xml contains an example for how to define patches for an external soft synth. In this case it's an example for a Ghostess DSSI host running one instance of WhySynth and one instance of Hexter. To use this example, copy 'examples/patches1.xml' to the ~/.fweelin/ folder (this folder is created by version 0.5.2 and forward). The WhySynth instance is on channel 0 (first channel), and the Hexter instance is on channel 1 (second channel). When you specify this patch list in Freewheeling's .fweelin.rc configuration file: you will then be able to play both your WhySynth and your Hexter patches, and switch between them. The WhySynth and Hexter patches will appear in separate sections of the patch browser. ------------------------------------------------------------------------------------------- You can automatically generate a patch list from a set of DSSI plugin patches. This saves the work of manually entering all of your patch information. To do this, apply the included patch to Ghostess (scripts/patch-ghostess-xml-patchlist). The patch modifies Ghostess so that when you select 'Save Configuration...' from the File menu, you get both a script to startup Ghostess with the current config and patchset, -as well as- an .XML file with the same base name, that contains the patch list for Freewheeling. I've submitted this patch to Sean Bolton for inclusion in an upcoming Ghostess release. Please nudge him if it has been useful for you (http://home.jps.net/~musound/). ------------------------------------------------------------------------------------------- freewheeling-0.6.6/examples/combipatchdemo.xml000066400000000000000000000026771370736313100215250ustar00rootroot00000000000000 freewheeling-0.6.6/examples/patches1.xml000066400000000000000000000617171370736313100202570ustar00rootroot00000000000000 freewheeling-0.6.6/install-sh000077500000000000000000000360101370736313100161770ustar00rootroot00000000000000#!/bin/sh # install - install a program, script, or datafile scriptversion=2018-03-11.20; # UTC # This originates from X11R5 (mit/util/scripts/install.sh), which was # later released in X11R6 (xc/config/util/install.sh) with the # following copyright and license. # # Copyright (C) 1994 X Consortium # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to # deal in the Software without restriction, including without limitation the # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or # sell copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN # AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- # TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # # Except as contained in this notice, the name of the X Consortium shall not # be used in advertising or otherwise to promote the sale, use or other deal- # ings in this Software without prior written authorization from the X Consor- # tium. # # # FSF changes to this file are in the public domain. # # Calling this script install-sh is preferred over install.sh, to prevent # 'make' implicit rules from creating a file called install from it # when there is no Makefile. # # This script is compatible with the BSD install script, but was written # from scratch. tab=' ' nl=' ' IFS=" $tab$nl" # Set DOITPROG to "echo" to test this script. doit=${DOITPROG-} doit_exec=${doit:-exec} # Put in absolute file names if you don't have them in your path; # or use environment vars. chgrpprog=${CHGRPPROG-chgrp} chmodprog=${CHMODPROG-chmod} chownprog=${CHOWNPROG-chown} cmpprog=${CMPPROG-cmp} cpprog=${CPPROG-cp} mkdirprog=${MKDIRPROG-mkdir} mvprog=${MVPROG-mv} rmprog=${RMPROG-rm} stripprog=${STRIPPROG-strip} posix_mkdir= # Desired mode of installed file. mode=0755 chgrpcmd= chmodcmd=$chmodprog chowncmd= mvcmd=$mvprog rmcmd="$rmprog -f" stripcmd= src= dst= dir_arg= dst_arg= copy_on_change=false is_target_a_directory=possibly usage="\ Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE or: $0 [OPTION]... SRCFILES... DIRECTORY or: $0 [OPTION]... -t DIRECTORY SRCFILES... or: $0 [OPTION]... -d DIRECTORIES... In the 1st form, copy SRCFILE to DSTFILE. In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. In the 4th, create DIRECTORIES. Options: --help display this help and exit. --version display version info and exit. -c (ignored) -C install only if different (preserve the last data modification time) -d create directories instead of installing files. -g GROUP $chgrpprog installed files to GROUP. -m MODE $chmodprog installed files to MODE. -o USER $chownprog installed files to USER. -s $stripprog installed files. -t DIRECTORY install into DIRECTORY. -T report an error if DSTFILE is a directory. Environment variables override the default commands: CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG RMPROG STRIPPROG " while test $# -ne 0; do case $1 in -c) ;; -C) copy_on_change=true;; -d) dir_arg=true;; -g) chgrpcmd="$chgrpprog $2" shift;; --help) echo "$usage"; exit $?;; -m) mode=$2 case $mode in *' '* | *"$tab"* | *"$nl"* | *'*'* | *'?'* | *'['*) echo "$0: invalid mode: $mode" >&2 exit 1;; esac shift;; -o) chowncmd="$chownprog $2" shift;; -s) stripcmd=$stripprog;; -t) is_target_a_directory=always dst_arg=$2 # Protect names problematic for 'test' and other utilities. case $dst_arg in -* | [=\(\)!]) dst_arg=./$dst_arg;; esac shift;; -T) is_target_a_directory=never;; --version) echo "$0 $scriptversion"; exit $?;; --) shift break;; -*) echo "$0: invalid option: $1" >&2 exit 1;; *) break;; esac shift done # We allow the use of options -d and -T together, by making -d # take the precedence; this is for compatibility with GNU install. if test -n "$dir_arg"; then if test -n "$dst_arg"; then echo "$0: target directory not allowed when installing a directory." >&2 exit 1 fi fi if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then # When -d is used, all remaining arguments are directories to create. # When -t is used, the destination is already specified. # Otherwise, the last argument is the destination. Remove it from $@. for arg do if test -n "$dst_arg"; then # $@ is not empty: it contains at least $arg. set fnord "$@" "$dst_arg" shift # fnord fi shift # arg dst_arg=$arg # Protect names problematic for 'test' and other utilities. case $dst_arg in -* | [=\(\)!]) dst_arg=./$dst_arg;; esac done fi if test $# -eq 0; then if test -z "$dir_arg"; then echo "$0: no input file specified." >&2 exit 1 fi # It's OK to call 'install-sh -d' without argument. # This can happen when creating conditional directories. exit 0 fi if test -z "$dir_arg"; then if test $# -gt 1 || test "$is_target_a_directory" = always; then if test ! -d "$dst_arg"; then echo "$0: $dst_arg: Is not a directory." >&2 exit 1 fi fi fi if test -z "$dir_arg"; then do_exit='(exit $ret); exit $ret' trap "ret=129; $do_exit" 1 trap "ret=130; $do_exit" 2 trap "ret=141; $do_exit" 13 trap "ret=143; $do_exit" 15 # Set umask so as not to create temps with too-generous modes. # However, 'strip' requires both read and write access to temps. case $mode in # Optimize common cases. *644) cp_umask=133;; *755) cp_umask=22;; *[0-7]) if test -z "$stripcmd"; then u_plus_rw= else u_plus_rw='% 200' fi cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;; *) if test -z "$stripcmd"; then u_plus_rw= else u_plus_rw=,u+rw fi cp_umask=$mode$u_plus_rw;; esac fi for src do # Protect names problematic for 'test' and other utilities. case $src in -* | [=\(\)!]) src=./$src;; esac if test -n "$dir_arg"; then dst=$src dstdir=$dst test -d "$dstdir" dstdir_status=$? else # Waiting for this to be detected by the "$cpprog $src $dsttmp" command # might cause directories to be created, which would be especially bad # if $src (and thus $dsttmp) contains '*'. if test ! -f "$src" && test ! -d "$src"; then echo "$0: $src does not exist." >&2 exit 1 fi if test -z "$dst_arg"; then echo "$0: no destination specified." >&2 exit 1 fi dst=$dst_arg # If destination is a directory, append the input filename. if test -d "$dst"; then if test "$is_target_a_directory" = never; then echo "$0: $dst_arg: Is a directory" >&2 exit 1 fi dstdir=$dst dstbase=`basename "$src"` case $dst in */) dst=$dst$dstbase;; *) dst=$dst/$dstbase;; esac dstdir_status=0 else dstdir=`dirname "$dst"` test -d "$dstdir" dstdir_status=$? fi fi case $dstdir in */) dstdirslash=$dstdir;; *) dstdirslash=$dstdir/;; esac obsolete_mkdir_used=false if test $dstdir_status != 0; then case $posix_mkdir in '') # Create intermediate dirs using mode 755 as modified by the umask. # This is like FreeBSD 'install' as of 1997-10-28. umask=`umask` case $stripcmd.$umask in # Optimize common cases. *[2367][2367]) mkdir_umask=$umask;; .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;; *[0-7]) mkdir_umask=`expr $umask + 22 \ - $umask % 100 % 40 + $umask % 20 \ - $umask % 10 % 4 + $umask % 2 `;; *) mkdir_umask=$umask,go-w;; esac # With -d, create the new directory with the user-specified mode. # Otherwise, rely on $mkdir_umask. if test -n "$dir_arg"; then mkdir_mode=-m$mode else mkdir_mode= fi posix_mkdir=false case $umask in *[123567][0-7][0-7]) # POSIX mkdir -p sets u+wx bits regardless of umask, which # is incompatible with FreeBSD 'install' when (umask & 300) != 0. ;; *) # Note that $RANDOM variable is not portable (e.g. dash); Use it # here however when possible just to lower collision chance. tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ trap 'ret=$?; rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" 2>/dev/null; exit $ret' 0 # Because "mkdir -p" follows existing symlinks and we likely work # directly in world-writeable /tmp, make sure that the '$tmpdir' # directory is successfully created first before we actually test # 'mkdir -p' feature. if (umask $mkdir_umask && $mkdirprog $mkdir_mode "$tmpdir" && exec $mkdirprog $mkdir_mode -p -- "$tmpdir/a/b") >/dev/null 2>&1 then if test -z "$dir_arg" || { # Check for POSIX incompatibilities with -m. # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or # other-writable bit of parent directory when it shouldn't. # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. test_tmpdir="$tmpdir/a" ls_ld_tmpdir=`ls -ld "$test_tmpdir"` case $ls_ld_tmpdir in d????-?r-*) different_mode=700;; d????-?--*) different_mode=755;; *) false;; esac && $mkdirprog -m$different_mode -p -- "$test_tmpdir" && { ls_ld_tmpdir_1=`ls -ld "$test_tmpdir"` test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" } } then posix_mkdir=: fi rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" else # Remove any dirs left behind by ancient mkdir implementations. rmdir ./$mkdir_mode ./-p ./-- "$tmpdir" 2>/dev/null fi trap '' 0;; esac;; esac if $posix_mkdir && ( umask $mkdir_umask && $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" ) then : else # The umask is ridiculous, or mkdir does not conform to POSIX, # or it failed possibly due to a race condition. Create the # directory the slow way, step by step, checking for races as we go. case $dstdir in /*) prefix='/';; [-=\(\)!]*) prefix='./';; *) prefix='';; esac oIFS=$IFS IFS=/ set -f set fnord $dstdir shift set +f IFS=$oIFS prefixes= for d do test X"$d" = X && continue prefix=$prefix$d if test -d "$prefix"; then prefixes= else if $posix_mkdir; then (umask=$mkdir_umask && $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break # Don't fail if two instances are running concurrently. test -d "$prefix" || exit 1 else case $prefix in *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; *) qprefix=$prefix;; esac prefixes="$prefixes '$qprefix'" fi fi prefix=$prefix/ done if test -n "$prefixes"; then # Don't fail if two instances are running concurrently. (umask $mkdir_umask && eval "\$doit_exec \$mkdirprog $prefixes") || test -d "$dstdir" || exit 1 obsolete_mkdir_used=true fi fi fi if test -n "$dir_arg"; then { test -z "$chowncmd" || $doit $chowncmd "$dst"; } && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } && { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false || test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1 else # Make a couple of temp file names in the proper directory. dsttmp=${dstdirslash}_inst.$$_ rmtmp=${dstdirslash}_rm.$$_ # Trap to clean up those temp files at exit. trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 # Copy the file name to the temp name. (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") && # and set any options; do chmod last to preserve setuid bits. # # If any of these fail, we abort the whole thing. If we want to # ignore errors from any of these, just make sure not to ignore # errors from the above "$doit $cpprog $src $dsttmp" command. # { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } && { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } && { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } && # If -C, don't bother to copy if it wouldn't change the file. if $copy_on_change && old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` && new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` && set -f && set X $old && old=:$2:$4:$5:$6 && set X $new && new=:$2:$4:$5:$6 && set +f && test "$old" = "$new" && $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1 then rm -f "$dsttmp" else # Rename the file to the real destination. $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null || # The rename failed, perhaps because mv can't rename something else # to itself, or perhaps because mv is so ancient that it does not # support -f. { # Now remove or move aside any old file at destination location. # We try this two ways since rm can't unlink itself on some # systems and the destination file might be busy for other # reasons. In this case, the final cleanup might fail but the new # file should still install successfully. { test ! -f "$dst" || $doit $rmcmd -f "$dst" 2>/dev/null || { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; } } || { echo "$0: cannot unlink or rename $dst" >&2 (exit 1); exit 1 } } && # Now rename the file to the real destination. $doit $mvcmd "$dsttmp" "$dst" } fi || exit 1 trap '' 0 fi done # Local variables: # eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC0" # time-stamp-end: "; # UTC" # End: freewheeling-0.6.6/missing000077500000000000000000000153361370736313100156020ustar00rootroot00000000000000#! /bin/sh # Common wrapper for a few potentially missing GNU programs. scriptversion=2018-03-07.03; # UTC # Copyright (C) 1996-2018 Free Software Foundation, Inc. # Originally written by Fran,cois Pinard , 1996. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, 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 . # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. if test $# -eq 0; then echo 1>&2 "Try '$0 --help' for more information" exit 1 fi case $1 in --is-lightweight) # Used by our autoconf macros to check whether the available missing # script is modern enough. exit 0 ;; --run) # Back-compat with the calling convention used by older automake. shift ;; -h|--h|--he|--hel|--help) echo "\ $0 [OPTION]... PROGRAM [ARGUMENT]... Run 'PROGRAM [ARGUMENT]...', returning a proper advice when this fails due to PROGRAM being missing or too old. Options: -h, --help display this help and exit -v, --version output version information and exit Supported PROGRAM values: aclocal autoconf autoheader autom4te automake makeinfo bison yacc flex lex help2man Version suffixes to PROGRAM as well as the prefixes 'gnu-', 'gnu', and 'g' are ignored when checking the name. Send bug reports to ." exit $? ;; -v|--v|--ve|--ver|--vers|--versi|--versio|--version) echo "missing $scriptversion (GNU Automake)" exit $? ;; -*) echo 1>&2 "$0: unknown '$1' option" echo 1>&2 "Try '$0 --help' for more information" exit 1 ;; esac # Run the given program, remember its exit status. "$@"; st=$? # If it succeeded, we are done. test $st -eq 0 && exit 0 # Also exit now if we it failed (or wasn't found), and '--version' was # passed; such an option is passed most likely to detect whether the # program is present and works. case $2 in --version|--help) exit $st;; esac # Exit code 63 means version mismatch. This often happens when the user # tries to use an ancient version of a tool on a file that requires a # minimum version. if test $st -eq 63; then msg="probably too old" elif test $st -eq 127; then # Program was missing. msg="missing on your system" else # Program was found and executed, but failed. Give up. exit $st fi perl_URL=https://www.perl.org/ flex_URL=https://github.com/westes/flex gnu_software_URL=https://www.gnu.org/software program_details () { case $1 in aclocal|automake) echo "The '$1' program is part of the GNU Automake package:" echo "<$gnu_software_URL/automake>" echo "It also requires GNU Autoconf, GNU m4 and Perl in order to run:" echo "<$gnu_software_URL/autoconf>" echo "<$gnu_software_URL/m4/>" echo "<$perl_URL>" ;; autoconf|autom4te|autoheader) echo "The '$1' program is part of the GNU Autoconf package:" echo "<$gnu_software_URL/autoconf/>" echo "It also requires GNU m4 and Perl in order to run:" echo "<$gnu_software_URL/m4/>" echo "<$perl_URL>" ;; esac } give_advice () { # Normalize program name to check for. normalized_program=`echo "$1" | sed ' s/^gnu-//; t s/^gnu//; t s/^g//; t'` printf '%s\n' "'$1' is $msg." configure_deps="'configure.ac' or m4 files included by 'configure.ac'" case $normalized_program in autoconf*) echo "You should only need it if you modified 'configure.ac'," echo "or m4 files included by it." program_details 'autoconf' ;; autoheader*) echo "You should only need it if you modified 'acconfig.h' or" echo "$configure_deps." program_details 'autoheader' ;; automake*) echo "You should only need it if you modified 'Makefile.am' or" echo "$configure_deps." program_details 'automake' ;; aclocal*) echo "You should only need it if you modified 'acinclude.m4' or" echo "$configure_deps." program_details 'aclocal' ;; autom4te*) echo "You might have modified some maintainer files that require" echo "the 'autom4te' program to be rebuilt." program_details 'autom4te' ;; bison*|yacc*) echo "You should only need it if you modified a '.y' file." echo "You may want to install the GNU Bison package:" echo "<$gnu_software_URL/bison/>" ;; lex*|flex*) echo "You should only need it if you modified a '.l' file." echo "You may want to install the Fast Lexical Analyzer package:" echo "<$flex_URL>" ;; help2man*) echo "You should only need it if you modified a dependency" \ "of a man page." echo "You may want to install the GNU Help2man package:" echo "<$gnu_software_URL/help2man/>" ;; makeinfo*) echo "You should only need it if you modified a '.texi' file, or" echo "any other file indirectly affecting the aspect of the manual." echo "You might want to install the Texinfo package:" echo "<$gnu_software_URL/texinfo/>" echo "The spurious makeinfo call might also be the consequence of" echo "using a buggy 'make' (AIX, DU, IRIX), in which case you might" echo "want to install GNU make:" echo "<$gnu_software_URL/make/>" ;; *) echo "You might have modified some files without having the proper" echo "tools for further handling them. Check the 'README' file, it" echo "often tells you about the needed prerequisites for installing" echo "this package. You may also peek at any GNU archive site, in" echo "case some other package contains this missing '$1' program." ;; esac } give_advice "$1" | sed -e '1s/^/WARNING: /' \ -e '2,$s/^/ /' >&2 # Propagate the correct exit status (expected to be 127 for a program # not found, 63 for a program that failed due to version mismatch). exit $st # Local variables: # eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC0" # time-stamp-end: "; # UTC" # End: freewheeling-0.6.6/scripts/000077500000000000000000000000001370736313100156625ustar00rootroot00000000000000freewheeling-0.6.6/scripts/README000066400000000000000000000037411370736313100165470ustar00rootroot00000000000000Managing A Library Of Loops & Scenes ------------------------------------ ** godelete-date, gomv-date, goarchive-date scripts Delete/Move, and Archive loops & scenes by date. See individual files for instructions. ** goarchive-scene script Archive a scene and all the loops it uses. Connecting FreeWheeling with Other Linux Audio apps --------------------------------------------------- -Hexter -Jack-Rack Example Scripts and Presets: --------------------------- Several Jack-Racks that use tube amp sims and reverb, and some scripts to load FreeWheeling and Hexter, a killer DX7 synth emulator. - Running 'gofweel' will load FreeWheeling and hook it up to reverb and tube amp. Your live mix will still be saved to disk dry, so you can tweak the FX later. - Running 'godx7' will load Hexter DX7 emulator and connect to tube amp. If FreeWheeling is running, DX7 becomes an input into FreeWheeling (channel 2). If not, DX7 is loaded standalone. - Running 'gofweel-dx7' will load FreeWheeling and DX7 as above, and connect them. You get the DX7 synth connected through a light phaser, then into FreeWheeling. FreeWheeling is channeled through valve saturation and tube amp plugins, and a wide open reverb. This is the whole enchilada. *** You will have to tweak the scripts to change your MIDI hardware name- see script 'waitalsaports'. *** *** You will also have to patch Jack-Rack (see included patch-) to load a .rack at startup. This is a feature that the author, I think, intends to implement, but I have done it for him. The scripts use this feature to autoload a rack. For more info, type 'jack-rack -?' after patching and recompiling and look at the -f option. *** *** Note these scripts are rather aggressive at killing tasks. If you have running versions of freewheeling, ghostess, jack-dssi-host, or jack-rack, expect them to suddenly stop! ** *** I recommend ghostess for hosting your DSSI synths- it allows you to save patch banks for auto startup. Good Luck! -Mercury freewheeling-0.6.6/scripts/go-import-markers000077500000000000000000000025601370736313100211720ustar00rootroot00000000000000if [ -z $1 ]; then echo "This script imports timing (downbeat) information from a Freewheeling session stream into an Ardour session." echo echo This is useful when you want to make a mix using live material from Freewheeling. echo "Freewheeling dumps timing information to Gnusound format (.wav.usx). For every live stream," echo Freewheeling also creates a .wav.usx file. echo echo To use a Freewheeling stream in Ardour: echo echo 1- Run 'oggdec live??.ogg'. echo 2- Create or load your Ardour project. echo 3- Add a track, and import 'live??.wav' as a source echo 4- Save your Ardour session, and close it. echo echo Now run go-import-markers session.ardour live??.wav.usx echo This script makes a backup of your session.ardour. echo The timing information is imported as location markers. echo echo Reload your Ardour project. echo You can now grab, copy, and work with regions on the downbeat, making editing a lot easier. echo echo "Usage: go-import-markers " else echo Importing markers from $2 into $1... mv $1 $1.orig awk -v USX="$2" '$1 == "" { loc = 1; } loc == 0 { print; } loc == 1 { print; while ($1 != "[Markers") { getline < USX; } while (getline < USX) { split($1,A,"="); print " "; } loc = 0; }' $1.orig > $1 fi freewheeling-0.6.6/scripts/goarchive-date000077500000000000000000000012411370736313100204700ustar00rootroot00000000000000# Aid for managing loop/scene libraries # # This script can be used in the FreeWheeling library folder (fw-lib/ by default) # to archive all loops & scenes with a specific date- # # For example: goarchive-date "Apr 15" test archives all files from April 15 to archive 'test.tar.bz2'. # Don't forget quotes! # goarchive-date "Apr 16 21:" old archives all files from April 16 from 9pm-10pm to archive 'old.tar.bz2'. # # No files are archived before prompting you. # echo Found these files.. ls -lt | grep "$1" echo "Archive these files to $2.tar.bz2? (Enter=Yes, CTRL-C=Abort)" read tar cjvf $2.tar.bz2 `ls -lt | grep "$1" | awk '{ print $9 }'` freewheeling-0.6.6/scripts/goarchive-scene000077500000000000000000000020301370736313100206450ustar00rootroot00000000000000# Aid for managing loop/scene libraries # # This script can be used in the FreeWheeling library folder (fw-lib/ by default) # to archive -one scene plus all the loops it uses- # # This is useful for sharing scenes between people. You simply archive up the scene with the loops, # send the archive to the person, and they extract it into their fw-lib/ folder. Then they can # build on your improvisation. # # For example: goarchive-scene "scene-504B642155558670C0DD84717E4B4DF8-Hacking the Database 2.xml" hacking # archives the above named scene and all loops it refers to into the archive 'hacking.tar.bz2' # # No files are archived before prompting you. # echo Files to archive: awk '{ if ($1 == "\n"); if (fprintf(fp, "#!/bin/sh\n") < 0) goto error; if (dssi_path) { @@ -878,6 +896,7 @@ for (instno = 0; instances[instno].id != id; instno++); instance = &instances[instno]; + // Write config escape_for_shell(&arg1, instance->friendly_name); if (fprintf(fp, "-comment %s \\\n", arg1) < 0) goto error; @@ -910,14 +929,59 @@ escape_for_shell(&arg1, instance->plugin->dll->name); escape_for_shell(&arg2, instance->plugin->label); if (fprintf(fp, " %s:%s \\\n", arg1, arg2) < 0) goto error; + + // Write patch list + +#if 0 + instance->pluginProgramCount = i; + instance->pluginPrograms = (DSSI_Program_Descriptor *) + malloc(i * sizeof(DSSI_Program_Descriptor)); + while (i > 0) { + const DSSI_Program_Descriptor *descriptor; + --i; + descriptor = instance->plugin->descriptor-> + get_program(instanceHandles[instance->number], i); + instance->pluginPrograms[i].Bank = descriptor->Bank; + instance->pluginPrograms[i].Program = descriptor->Program; + instance->pluginPrograms[i].Name = strdup(descriptor->Name); + ghss_debug(GDB_PROGRAM, " %s: program %d is MIDI bank %lu program %lu, named '%s'", + instance->friendly_name, i, + instance->pluginPrograms[i].Bank, + instance->pluginPrograms[i].Program, + instance->pluginPrograms[i].Name); + } +#endif + + for (i = 0; i < instance->pluginProgramCount; i++) { + // Replace < and > characters in name (bad XML) + strncpy(tmp,instance->pluginPrograms[i].Name,254); + tmp[254] = '\0'; + slen = strlen(tmp); + for (j = 0; j < slen; j++) + if (tmp[j] == '<' || + tmp[j] == '>') + tmp[j] = ' '; + + fprintf(fp2,"\n", + instance->channel, + tmp, + (int) instance->pluginPrograms[i].Bank, + (int) instance->pluginPrograms[i].Program); + } } if (fprintf(fp, "\n") < 0) goto error; rc = 1; + fprintf(fp2,"\n"); + error: if (arg1) free(arg1); if (arg2) free(arg2); + fclose(fp); + fclose(fp2); + return rc; } @@ -1670,7 +1734,10 @@ if (itemplate->program_set) { instance->currentBank = itemplate->bank; instance->currentProgram = itemplate->program; - instance->pendingProgramChange = 0; + // JPM-Changed pendingProgramChange from 0 to -1 + // was causing program list to not be dumped when + // -prog specified + instance->pendingProgramChange = -1; } else { instance->currentBank = 0; instance->currentProgram = 0; diff -u ghostess-20050916/src/ghostess.h ghostess-20050916-nw/src/ghostess.h --- ghostess-20050916/src/ghostess.h 2005-09-16 09:12:13.000000000 -0700 +++ ghostess-20050916-nw/src/ghostess.h 2006-03-29 11:05:57.000000000 -0800 @@ -188,7 +188,7 @@ extern int midi_thread_running; extern pthread_mutex_t midiEventBufferMutex; -int write_configuration(FILE *fp); +int write_configuration(char *filename); void ui_osc_free(d3h_instance_t *instance); void start_ui(d3h_instance_t *instance); diff -u ghostess-20050916/src/gui_callbacks.c ghostess-20050916-nw/src/gui_callbacks.c --- ghostess-20050916/src/gui_callbacks.c 2005-09-16 10:09:22.000000000 -0700 +++ ghostess-20050916-nw/src/gui_callbacks.c 2006-03-29 11:08:32.000000000 -0800 @@ -120,8 +120,6 @@ void on_save_file_ok( GtkWidget *widget, gpointer data ) { - FILE *fp; - gtk_widget_hide(save_file_selection); file_selection_last_filename = (gchar *)gtk_file_selection_get_filename( GTK_FILE_SELECTION(save_file_selection)); @@ -129,14 +127,9 @@ ghss_debug(GDB_GUI, " on_save_file_ok: file '%s' selected", file_selection_last_filename); - if ((fp = fopen(file_selection_last_filename, "w")) == NULL) { - display_notice("Save Configuration failed:", strerror(errno)); - return; - } - if (!write_configuration(fp)) { + if (!write_configuration(file_selection_last_filename)) { display_notice("Save Configuration failed:", strerror(errno)); } - fclose(fp); display_notice("Configuration Saved.", ""); } freewheeling-0.6.6/scripts/patch-jack-rack-loadfile000066400000000000000000000013501370736313100223040ustar00rootroot00000000000000--- jack-rack-1.4.3/src/main.c +++ jack-rack-1.4.3/src/main.c 96a97 > printf(" -f, --file %s\n", _("Load .rack at start")); 106,107c107,109 < < const char * options = "hps:ionc:tD:"; --- > char *loadfile = 0; > > const char * options = "hps:ionc:tDf:"; 118a121 > { "file", 1, NULL, 'f' }, 211a215,219 > > case 'f': > loadfile = (char *) malloc(sizeof(char) * (strlen(optarg)+1)); > strcpy(loadfile,optarg); > break; 237c245,256 < --- > > /* Load a file at startup? */ > if (loadfile) { > int err; > > printf("Loading file: '%s'\n",loadfile); > err = ui_open_file (global_ui, loadfile); > > if (!err) > ui_set_filename (global_ui, loadfile); > } > freewheeling-0.6.6/scripts/phat1-basic.rack000066400000000000000000000005261370736313100206230ustar00rootroot00000000000000‹ÕU]Oƒ0}߯@~@?øbj÷ {4šl/{"Ôv@ڲ鋿Ý22QB‘³&Mî==÷¤9÷6%‹·½°\ª¬Èom ½ 3ruÿx·Þ<-­¿J³­Õfµ^>XvªuyaYÉ[¦R Rø!Y kjTs# èÄ6Bçz:³,§,ϹPø×ŠíKÁ%ÓœzFˆÀoHM(EµËò:4I–Pìà@4ÏÙVð„jYqÏYsvä:Jä{tFŸ™P†Ô…’LT\5 O)5æœMÞ”À¾¹–…ű#‚€ã÷ˆtù*8žëx¼>Æ `¸>výAÛ¦÷ô]lÿ]ìÌç׿60Ä!nß°yAè]¦yfpÚäõÞb¼>ªßßÉ7øoQ&¶H`û |ú ¹ofreewheeling-0.6.6/scripts/phat1-echo.rack000066400000000000000000000007171370736313100204620ustar00rootroot00000000000000‹íWKs‚0¾û+¨÷æŠtR<´;íŒ^<1QR±Fpj{éooú¢p«Ì0“ÝïË~Éf³ ´û9ÆŠËx…M P³ë6èÝóëÓ`øÖ3>Øx&Õkô‡ýAïÅhI²x€p±”F,@ÀoɘR½”ëa@€ŸøMh;ßm, ¹ˆ]Bánœ1›/—,á®ea„(<𤄅XN¦a:TÆÔw1Á…jyxÈF‚ûn"—œÂ­•akžx¾üò¶Þw&bEÊ»É"ÏvñrÎc抉%3§roLW¥qóP˜Ùg {™Ãˆ4ÕdBü®dkeØ8  ­w)ရFY¦ewôËÒ¢ê r*WÉ"›XíBÙ¿h²WBuYZwœ¢ÝjÐ:dIénµh^–Âý5ÓÜ8t»qŸ &F¶iƒ­£pÒ2í"Y zY1ØŽu+†KOÛn•,KƒÖQ We£º¬êtˆ´Šdµh=²e»Õ¢7ÙKek(©òþ‚‰ù/ú‹&óÙ¤û³’X!ëò•àR¾B„óÄw¦<1qÛ$8ÖÉì+‘ÂýïÊI+G freewheeling-0.6.6/scripts/vocalverb.rack000066400000000000000000000004401370736313100205050ustar00rootroot00000000000000‹¥’Mnà …÷9õcÙJSMɢͲj¥d“•El»!Øœ´›ž½8–ócEQ«"!Í{óø@N?·Šì¤±e¥FÃ`ÊGx÷üú´X¾ÍȇÈ6ÆO2_γÎÕucÖ’®„-¨-àÛˆÚhÚfSF#š»<ð ~=‚Y!´–ÊòáX· +¶µ’F8É㘅!™ÓjÕ¬KÝ–^”9gãI‚à‹Î‘Z¬”̹3DèU×ÛK—ææ+íÝw¡¬ í˰ª²Í‘70/“;¡i;ÓÛÉý5B§Ñ=msNĬÒÎTÊTû$¤÷l2‰£d˜¿¸zŠ?’X2ãø&¡{„ÓgúXƒ¶·freewheeling-0.6.6/scripts/waitalsaports000077500000000000000000000015431370736313100205100ustar00rootroot00000000000000# Script to wait for named ALSA midi ports to appear # # usage: waitalsaports # # where name is the full or partial client name (grep search will be done) # # prints the port numbers for system MIDI input and client MIDI input, # respectively # # typically they are 72:0 128:0 ALSA_NAME=$1 # **** You will have to change the following line to reflect the name of your MIDI hardware # On my system aconnect -li reports client 72: 'MidiSport 2x2', so the name can be any subset of that: #ALSA_IN_NAME=MidiSport #ALSA_IN_NAME=PCR ALSA_IN_NAME=BCF while ((`aconnect -lo | grep $ALSA_NAME | awk 'END { print NR }'` == 0)) do sleep 0.1 done ALSA_SYSTEM_MIDI=`aconnect -lo | grep $ALSA_IN_NAME | grep client | awk '{ print $2 }'`0 ALSA_CLIENT_MIDI=`aconnect -lo | grep $ALSA_NAME | grep client | awk '{ print $2 }'`0 echo $ALSA_SYSTEM_MIDI $ALSA_CLIENT_MIDI freewheeling-0.6.6/scripts/waitjackports000077500000000000000000000005251370736313100204770ustar00rootroot00000000000000# Script to wait for named JACK ports to appear # # usage: waitjackports # # where name is the full or partial client name (grep search will be done) # # prints all ports belonging to the named client JACK_NAME=$1 while ((`jack_lsp | grep $JACK_NAME | awk 'END { print NR }'` == 0)) do sleep 0.1 done jack_lsp | grep $JACK_NAME freewheeling-0.6.6/src/000077500000000000000000000000001370736313100147625ustar00rootroot00000000000000freewheeling-0.6.6/src/Makefile.am000066400000000000000000000034241370736313100170210ustar00rootroot00000000000000#LIBTOOL = libtool # #COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ # $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) #LTCOMPILE = $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) \ # $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) #CCLD = $(CC) #LINK = $(LIBTOOL) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ # $(AM_LDFLAGS) $(LDFLAGS) -o $@ ## CFLAGS = @CFLAGS@ #CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ # $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) #LTCXXCOMPILE = $(LIBTOOL) --mode=compile $(CXX) $(DEFS) \ # $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ # $(AM_CXXFLAGS) $(CXXFLAGS) #CXXLD = $(CXX) #CXXLINK = $(LIBTOOL) --mode=link $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) \ # $(AM_LDFLAGS) $(LDFLAGS) -o $@ ## CXXFLAGS = @CXXFLAGS@ bin_PROGRAMS = fweelin fweelin_SOURCES = stacktrace.c fweelin.cc fweelin_datatypes.cc fweelin_rcu.cc fweelin_osc.cc fweelin_event.cc fweelin_config.cc fweelin_paramset.cc fweelin_browser.cc fweelin_audioio.cc fweelin_sdlio.cc fweelin_midiio.cc fweelin_amixer.cc fweelin_videoio.cc fweelin_videoio_displays.cc fweelin_core.cc fweelin_mem.cc fweelin_block.cc fweelin_core_dsp.cc fweelin_fluidsynth.cc fweelindir = $(datadir)/fweelin FWEELIN_CFLAGS = -I. -g -Wall -Wextra -Wno-write-strings -D_REENTRANT -DPTHREADS -DNDEBUG -DVERSION=\"$(VERSION)\" -DFWEELIN_DATADIR=\"$(fweelindir)\" -DADDON_DIR=\"/usr/local/lib/jack\" -I/usr/include/freetype2 -I/usr/include/libxml2 -funroll-loops -finline-functions -fomit-frame-pointer -ffast-math -fexpensive-optimizations -fstrict-aliasing -falign-loops=2 -falign-jumps=2 -falign-functions=2 -O9 FWEELIN_CXXFLAGS = -Wno-non-virtual-dtor AM_CFLAGS = $(CFLAGS) $(FWEELIN_CFLAGS) AM_CXXFLAGS = $(CFLAGS) $(CXXFLAGS) $(FWEELIN_CFLAGS) $(FWEELIN_CXXFLAGS) freewheeling-0.6.6/src/Makefile.in000066400000000000000000000617171370736313100170430ustar00rootroot00000000000000# Makefile.in generated by automake 1.16.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2018 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ #LIBTOOL = libtool # #COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ # $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) #LTCOMPILE = $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) \ # $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) #CCLD = $(CC) #LINK = $(LIBTOOL) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ # $(AM_LDFLAGS) $(LDFLAGS) -o $@ #CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ # $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) #LTCXXCOMPILE = $(LIBTOOL) --mode=compile $(CXX) $(DEFS) \ # $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ # $(AM_CXXFLAGS) $(CXXFLAGS) #CXXLD = $(CXX) #CXXLINK = $(LIBTOOL) --mode=link $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) \ # $(AM_LDFLAGS) $(LDFLAGS) -o $@ VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : bin_PROGRAMS = fweelin$(EXEEXT) subdir = src ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__installdirs = "$(DESTDIR)$(bindir)" PROGRAMS = $(bin_PROGRAMS) am_fweelin_OBJECTS = stacktrace.$(OBJEXT) fweelin.$(OBJEXT) \ fweelin_datatypes.$(OBJEXT) fweelin_rcu.$(OBJEXT) \ fweelin_osc.$(OBJEXT) fweelin_event.$(OBJEXT) \ fweelin_config.$(OBJEXT) fweelin_paramset.$(OBJEXT) \ fweelin_browser.$(OBJEXT) fweelin_audioio.$(OBJEXT) \ fweelin_sdlio.$(OBJEXT) fweelin_midiio.$(OBJEXT) \ fweelin_amixer.$(OBJEXT) fweelin_videoio.$(OBJEXT) \ fweelin_videoio_displays.$(OBJEXT) fweelin_core.$(OBJEXT) \ fweelin_mem.$(OBJEXT) fweelin_block.$(OBJEXT) \ fweelin_core_dsp.$(OBJEXT) fweelin_fluidsynth.$(OBJEXT) fweelin_OBJECTS = $(am_fweelin_OBJECTS) fweelin_LDADD = $(LDADD) AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ depcomp = $(SHELL) $(top_srcdir)/depcomp am__maybe_remake_depfiles = depfiles am__depfiles_remade = ./$(DEPDIR)/fweelin.Po \ ./$(DEPDIR)/fweelin_amixer.Po ./$(DEPDIR)/fweelin_audioio.Po \ ./$(DEPDIR)/fweelin_block.Po ./$(DEPDIR)/fweelin_browser.Po \ ./$(DEPDIR)/fweelin_config.Po ./$(DEPDIR)/fweelin_core.Po \ ./$(DEPDIR)/fweelin_core_dsp.Po \ ./$(DEPDIR)/fweelin_datatypes.Po ./$(DEPDIR)/fweelin_event.Po \ ./$(DEPDIR)/fweelin_fluidsynth.Po ./$(DEPDIR)/fweelin_mem.Po \ ./$(DEPDIR)/fweelin_midiio.Po ./$(DEPDIR)/fweelin_osc.Po \ ./$(DEPDIR)/fweelin_paramset.Po ./$(DEPDIR)/fweelin_rcu.Po \ ./$(DEPDIR)/fweelin_sdlio.Po ./$(DEPDIR)/fweelin_videoio.Po \ ./$(DEPDIR)/fweelin_videoio_displays.Po \ ./$(DEPDIR)/stacktrace.Po am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) AM_V_CXX = $(am__v_CXX_@AM_V@) am__v_CXX_ = $(am__v_CXX_@AM_DEFAULT_V@) am__v_CXX_0 = @echo " CXX " $@; am__v_CXX_1 = CXXLD = $(CXX) CXXLINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) \ -o $@ AM_V_CXXLD = $(am__v_CXXLD_@AM_V@) am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@) am__v_CXXLD_0 = @echo " CXXLD " $@; am__v_CXXLD_1 = SOURCES = $(fweelin_SOURCES) DIST_SOURCES = $(fweelin_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ ALLOCA = @ALLOCA@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CXX = @CXX@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ GREP = @GREP@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ OBJEXT = @OBJEXT@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ POW_LIB = @POW_LIB@ SDL_CFLAGS = @SDL_CFLAGS@ SDL_LIBS = @SDL_LIBS@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ XMKMF = @XMKMF@ X_CFLAGS = @X_CFLAGS@ X_EXTRA_LIBS = @X_EXTRA_LIBS@ X_LIBS = @X_LIBS@ X_PRE_LIBS = @X_PRE_LIBS@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build_alias = @build_alias@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host_alias = @host_alias@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ fweelin_SOURCES = stacktrace.c fweelin.cc fweelin_datatypes.cc fweelin_rcu.cc fweelin_osc.cc fweelin_event.cc fweelin_config.cc fweelin_paramset.cc fweelin_browser.cc fweelin_audioio.cc fweelin_sdlio.cc fweelin_midiio.cc fweelin_amixer.cc fweelin_videoio.cc fweelin_videoio_displays.cc fweelin_core.cc fweelin_mem.cc fweelin_block.cc fweelin_core_dsp.cc fweelin_fluidsynth.cc fweelindir = $(datadir)/fweelin FWEELIN_CFLAGS = -I. -g -Wall -Wextra -Wno-write-strings -D_REENTRANT -DPTHREADS -DNDEBUG -DVERSION=\"$(VERSION)\" -DFWEELIN_DATADIR=\"$(fweelindir)\" -DADDON_DIR=\"/usr/local/lib/jack\" -I/usr/include/freetype2 -I/usr/include/libxml2 -funroll-loops -finline-functions -fomit-frame-pointer -ffast-math -fexpensive-optimizations -fstrict-aliasing -falign-loops=2 -falign-jumps=2 -falign-functions=2 -O9 FWEELIN_CXXFLAGS = -Wno-non-virtual-dtor AM_CFLAGS = $(CFLAGS) $(FWEELIN_CFLAGS) AM_CXXFLAGS = $(CFLAGS) $(CXXFLAGS) $(FWEELIN_CFLAGS) $(FWEELIN_CXXFLAGS) all: all-am .SUFFIXES: .SUFFIXES: .c .cc .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu src/Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-binPROGRAMS: $(bin_PROGRAMS) @$(NORMAL_INSTALL) @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(bindir)'"; \ $(MKDIR_P) "$(DESTDIR)$(bindir)" || exit 1; \ fi; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p \ ; then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' \ -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ } \ ; done uninstall-binPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' \ `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(bindir)" && rm -f $$files clean-binPROGRAMS: -test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS) fweelin$(EXEEXT): $(fweelin_OBJECTS) $(fweelin_DEPENDENCIES) $(EXTRA_fweelin_DEPENDENCIES) @rm -f fweelin$(EXEEXT) $(AM_V_CXXLD)$(CXXLINK) $(fweelin_OBJECTS) $(fweelin_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fweelin.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fweelin_amixer.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fweelin_audioio.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fweelin_block.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fweelin_browser.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fweelin_config.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fweelin_core.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fweelin_core_dsp.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fweelin_datatypes.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fweelin_event.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fweelin_fluidsynth.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fweelin_mem.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fweelin_midiio.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fweelin_osc.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fweelin_paramset.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fweelin_rcu.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fweelin_sdlio.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fweelin_videoio.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fweelin_videoio_displays.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stacktrace.Po@am__quote@ # am--include-marker $(am__depfiles_remade): @$(MKDIR_P) $(@D) @echo '# dummy' >$@-t && $(am__mv) $@-t $@ am--depfiles: $(am__depfiles_remade) .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .cc.o: @am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ @am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ @am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ $< .cc.obj: @am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ @am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ @am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(PROGRAMS) installdirs: for dir in "$(DESTDIR)$(bindir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-binPROGRAMS clean-generic mostlyclean-am distclean: distclean-am -rm -f ./$(DEPDIR)/fweelin.Po -rm -f ./$(DEPDIR)/fweelin_amixer.Po -rm -f ./$(DEPDIR)/fweelin_audioio.Po -rm -f ./$(DEPDIR)/fweelin_block.Po -rm -f ./$(DEPDIR)/fweelin_browser.Po -rm -f ./$(DEPDIR)/fweelin_config.Po -rm -f ./$(DEPDIR)/fweelin_core.Po -rm -f ./$(DEPDIR)/fweelin_core_dsp.Po -rm -f ./$(DEPDIR)/fweelin_datatypes.Po -rm -f ./$(DEPDIR)/fweelin_event.Po -rm -f ./$(DEPDIR)/fweelin_fluidsynth.Po -rm -f ./$(DEPDIR)/fweelin_mem.Po -rm -f ./$(DEPDIR)/fweelin_midiio.Po -rm -f ./$(DEPDIR)/fweelin_osc.Po -rm -f ./$(DEPDIR)/fweelin_paramset.Po -rm -f ./$(DEPDIR)/fweelin_rcu.Po -rm -f ./$(DEPDIR)/fweelin_sdlio.Po -rm -f ./$(DEPDIR)/fweelin_videoio.Po -rm -f ./$(DEPDIR)/fweelin_videoio_displays.Po -rm -f ./$(DEPDIR)/stacktrace.Po -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-binPROGRAMS install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f ./$(DEPDIR)/fweelin.Po -rm -f ./$(DEPDIR)/fweelin_amixer.Po -rm -f ./$(DEPDIR)/fweelin_audioio.Po -rm -f ./$(DEPDIR)/fweelin_block.Po -rm -f ./$(DEPDIR)/fweelin_browser.Po -rm -f ./$(DEPDIR)/fweelin_config.Po -rm -f ./$(DEPDIR)/fweelin_core.Po -rm -f ./$(DEPDIR)/fweelin_core_dsp.Po -rm -f ./$(DEPDIR)/fweelin_datatypes.Po -rm -f ./$(DEPDIR)/fweelin_event.Po -rm -f ./$(DEPDIR)/fweelin_fluidsynth.Po -rm -f ./$(DEPDIR)/fweelin_mem.Po -rm -f ./$(DEPDIR)/fweelin_midiio.Po -rm -f ./$(DEPDIR)/fweelin_osc.Po -rm -f ./$(DEPDIR)/fweelin_paramset.Po -rm -f ./$(DEPDIR)/fweelin_rcu.Po -rm -f ./$(DEPDIR)/fweelin_sdlio.Po -rm -f ./$(DEPDIR)/fweelin_videoio.Po -rm -f ./$(DEPDIR)/fweelin_videoio_displays.Po -rm -f ./$(DEPDIR)/stacktrace.Po -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-binPROGRAMS .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \ clean-binPROGRAMS clean-generic cscopelist-am ctags ctags-am \ distclean distclean-compile distclean-generic distclean-tags \ distdir dvi dvi-am html html-am info info-am install \ install-am install-binPROGRAMS install-data install-data-am \ install-dvi install-dvi-am install-exec install-exec-am \ install-html install-html-am install-info install-info-am \ install-man install-pdf install-pdf-am install-ps \ install-ps-am install-strip installcheck installcheck-am \ installdirs maintainer-clean maintainer-clean-generic \ mostlyclean mostlyclean-compile mostlyclean-generic pdf pdf-am \ ps ps-am tags tags-am uninstall uninstall-am \ uninstall-binPROGRAMS .PRECIOUS: Makefile # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: freewheeling-0.6.6/src/fweelin.cc000066400000000000000000000070441370736313100167270ustar00rootroot00000000000000/* ************ FreeWheeling ************ What is music, if it is not shared in community, held in friendship, alive and breathing, soil and soul? THANKS & PRAISE */ /* Copyright 2004-2011 Jan Pekau This file is part of Freewheeling. Freewheeling is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. Freewheeling 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 Freewheeling. If not, see . */ #include #include #include #include #include #include #include #include #include #include #include #include "stacktrace.h" #include "fweelin_midiio.h" #include "fweelin_videoio.h" #include "fweelin_sdlio.h" #include "fweelin_audioio.h" #include "fweelin_core.h" #include "fweelin_core_dsp.h" pid_t main_pid; void signal_handler (int iSignal) { switch (iSignal) { case SIGINT: return; #if defined(WIN32) #else case SIGSEGV: printf(">>> FATAL ERROR: Segmentation fault (SIGSEGV) occured! <<<\n"); break; case SIGBUS: printf(">>> FATAL ERROR: Access to undefined portion of a memory object (SIGBUS) occured! <<<\n"); break; case SIGILL: printf(">>> FATAL ERROR: Illegal instruction (SIGILL) occured! <<<\n"); break; case SIGFPE: printf(">>> FATAL ERROR: Erroneous arithmetic operation (SIGFPE) occured! <<<\n"); break; case SIGUSR1: printf(">>> User defined signal 1 (SIGUSR1) received <<<\n"); break; case SIGUSR2: printf(">>> User defined signal 2 (SIGUSR2) received <<<\n"); break; #endif default: { // this should never happen, as we register for the signals we want printf(">>> FATAL ERROR: Unknown signal received! <<<\n"); break; } } signal(iSignal, SIG_DFL); // Reinstall default handler to prevent race conditions printf("Saving stack trace to file 'fweelin-stackdump'...\n"); char buf[256]; snprintf(buf,255,"%s%s",FWEELIN_DATADIR,"/gdb-stackdump-cmds"); StackTrace(buf); sleep(10); printf("Exit Freewheeling...\n"); // Use abort() if we want to generate a core dump. kill(main_pid, SIGKILL); } #ifndef NO_COMPILE_MAIN int main (int /*argc*/, char *argv[]) { #if !defined(WIN32) main_pid = getpid(); #endif // WIN32 // Initialize the stack trace mechanism StackTraceInit(argv[0], -1); signal(SIGINT, signal_handler); #if !defined(WIN32) // Register signal handlers struct sigaction sact; sigemptyset(&sact.sa_mask); sact.sa_flags = 0; sact.sa_handler = signal_handler; sigaction(SIGSEGV, &sact, NULL); sigaction(SIGBUS, &sact, NULL); sigaction(SIGILL, &sact, NULL); sigaction(SIGFPE, &sact, NULL); sigaction(SIGUSR1, &sact, NULL); sigaction(SIGUSR2, &sact, NULL); #endif // WIN32 Fweelin flo; printf("FreeWheeling %s\n",VERSION); printf("May we return to the circle.\n\n"); if (!flo.setup()) flo.go(); else printf("Error starting FreeWheeling!\n"); return 0; } #endif // NO_COMPILE_MAIN // Improvisation is loving what is. freewheeling-0.6.6/src/fweelin_amixer.cc000066400000000000000000000546331370736313100203020ustar00rootroot00000000000000/* Control is such a trick-- We can guide the ship but are we ever really in control of where we land? */ /* Copyright 2004-2011 Jan Pekau This file is part of Freewheeling. Freewheeling is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. Freewheeling 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 Freewheeling. If not, see . */ /* This file contains code from amixer.c, ALSA's command line mixer utility: * * ALSA command line mixer utility * Copyright (c) 1999-2000 by Jaroslav Kysela * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "fweelin_amixer.h" #include #define NO_CHECK 0 #define LEVEL_BASIC (1<<0) #define LEVEL_INACTIVE (1<<1) #define LEVEL_ID (1<<2) const char *HardwareMixerInterface::control_type(snd_ctl_elem_info_t *info) { return snd_ctl_elem_type_name(snd_ctl_elem_info_get_type(info)); } const char *HardwareMixerInterface::control_access(snd_ctl_elem_info_t *info) { static char result[10]; char *res = result; *res++ = snd_ctl_elem_info_is_readable(info) ? 'r' : '-'; *res++ = snd_ctl_elem_info_is_writable(info) ? 'w' : '-'; *res++ = snd_ctl_elem_info_is_inactive(info) ? 'i' : '-'; *res++ = snd_ctl_elem_info_is_volatile(info) ? 'v' : '-'; *res++ = snd_ctl_elem_info_is_locked(info) ? 'l' : '-'; *res++ = snd_ctl_elem_info_is_tlv_readable(info) ? 'R' : '-'; *res++ = snd_ctl_elem_info_is_tlv_writable(info) ? 'W' : '-'; *res++ = snd_ctl_elem_info_is_tlv_commandable(info) ? 'C' : '-'; *res++ = '\0'; return result; } #define convert_prange1(val, min, max) \ ceil((val) * ((max) - (min)) * 0.01 + (min)) #define check_range(val, min, max) \ (NO_CHECK ? (val) : ((val < min) ? (min) : (val > max) ? (max) : (val))) long HardwareMixerInterface::get_integer(char **ptr, long min, long max) { long val = min; char *p = *ptr, *s; if (*p == ':') p++; if (*p == '\0' || (!isdigit(*p) && *p != '-')) goto out; s = p; val = strtol(s, &p, 10); if (*p == '.') { p++; strtol(p, &p, 10); } if (*p == '%') { val = (long)convert_prange1(strtod(s, NULL), min, max); p++; } val = check_range(val, min, max); if (*p == ',') p++; out: *ptr = p; return val; } long HardwareMixerInterface::get_integer64(char **ptr, long long min, long long max) { long long val = min; char *p = *ptr, *s; if (*p == ':') p++; if (*p == '\0' || (!isdigit(*p) && *p != '-')) goto out; s = p; val = strtol(s, &p, 10); if (*p == '.') { p++; strtol(p, &p, 10); } if (*p == '%') { val = (long long)convert_prange1(strtod(s, NULL), min, max); p++; } val = check_range(val, min, max); if (*p == ',') p++; out: *ptr = p; return val; } int HardwareMixerInterface::parse_control_id(const char *str, snd_ctl_elem_id_t *id) { int c, size, numid; char *ptr; while (*str == ' ' || *str == '\t') str++; if (!(*str)) return -EINVAL; snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_MIXER); /* default */ while (*str) { if (!strncasecmp(str, "numid=", 6)) { str += 6; numid = atoi(str); if (numid <= 0) { printf( "amixer: Invalid numid %d\n", numid); return -EINVAL; } snd_ctl_elem_id_set_numid(id, atoi(str)); while (isdigit(*str)) str++; } else if (!strncasecmp(str, "iface=", 6)) { str += 6; if (!strncasecmp(str, "card", 4)) { snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_CARD); str += 4; } else if (!strncasecmp(str, "mixer", 5)) { snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_MIXER); str += 5; } else if (!strncasecmp(str, "pcm", 3)) { snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_PCM); str += 3; } else if (!strncasecmp(str, "rawmidi", 7)) { snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_RAWMIDI); str += 7; } else if (!strncasecmp(str, "timer", 5)) { snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_TIMER); str += 5; } else if (!strncasecmp(str, "sequencer", 9)) { snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_SEQUENCER); str += 9; } else { return -EINVAL; } } else if (!strncasecmp(str, "name=", 5)) { char buf[64]; str += 5; ptr = buf; size = 0; if (*str == '\'' || *str == '\"') { c = *str++; while (*str && *str != c) { if (size < (int)sizeof(buf)) { *ptr++ = *str; size++; } str++; } if (*str == c) str++; } else { while (*str && *str != ',') { if (size < (int)sizeof(buf)) { *ptr++ = *str; size++; } str++; } *ptr = '\0'; } snd_ctl_elem_id_set_name(id, buf); } else if (!strncasecmp(str, "index=", 6)) { str += 6; snd_ctl_elem_id_set_index(id, atoi(str)); while (isdigit(*str)) str++; } else if (!strncasecmp(str, "device=", 7)) { str += 7; snd_ctl_elem_id_set_device(id, atoi(str)); while (isdigit(*str)) str++; } else if (!strncasecmp(str, "subdevice=", 10)) { str += 10; snd_ctl_elem_id_set_subdevice(id, atoi(str)); while (isdigit(*str)) str++; } if (*str == ',') { str++; } else { if (*str) return -EINVAL; } } return 0; } const char *HardwareMixerInterface::control_iface(snd_ctl_elem_id_t *id) { return snd_ctl_elem_iface_name(snd_ctl_elem_id_get_interface(id)); } void HardwareMixerInterface::show_control_id(snd_ctl_elem_id_t *id) { unsigned int index, device, subdevice; printf("numid=%u,iface=%s,name='%s'", snd_ctl_elem_id_get_numid(id), control_iface(id), snd_ctl_elem_id_get_name(id)); index = snd_ctl_elem_id_get_index(id); device = snd_ctl_elem_id_get_device(id); subdevice = snd_ctl_elem_id_get_subdevice(id); if (index) printf(",index=%i", index); if (device) printf(",device=%i", device); if (subdevice) printf(",subdevice=%i", subdevice); } void HardwareMixerInterface::print_spaces(unsigned int spaces) { while (spaces-- > 0) putc(' ', stdout); } void HardwareMixerInterface::print_dB(long dB) { printf("%li.%02lidB", dB / 100, (dB < 0 ? -dB : dB) % 100); } void HardwareMixerInterface::decode_tlv(unsigned int spaces, unsigned int *tlv, unsigned int tlv_size) { unsigned int type = tlv[0]; unsigned int size; unsigned int idx = 0; if (tlv_size < 2 * sizeof(unsigned int)) { printf("TLV size error!\n"); return; } print_spaces(spaces); printf("| "); type = tlv[idx++]; size = tlv[idx++]; tlv_size -= 2 * sizeof(unsigned int); if (size > tlv_size) { printf("TLV size error (%i, %i, %i)!\n", type, size, tlv_size); return; } switch (type) { case SND_CTL_TLVT_CONTAINER: size += sizeof(unsigned int) -1; size /= sizeof(unsigned int); while (idx < size) { if (tlv[idx+1] > (size - idx) * sizeof(unsigned int)) { printf("TLV size error in compound!\n"); return; } decode_tlv(spaces + 2, tlv + idx, tlv[idx+1]); idx += 2 + (tlv[1] + sizeof(unsigned int) - 1) / sizeof(unsigned int); } break; case SND_CTL_TLVT_DB_SCALE: printf("dBscale-"); if (size != 2 * sizeof(unsigned int)) { while (size > 0) { printf("0x%08x,", tlv[idx++]); size -= sizeof(unsigned int); } } else { printf("min="); print_dB((int)tlv[2]); printf(",step="); print_dB(tlv[3] & 0xffff); printf(",mute=%i", (tlv[3] >> 16) & 1); } break; #ifdef SND_CTL_TLVT_DB_LINEAR case SND_CTL_TLVT_DB_LINEAR: printf("dBlinear-"); if (size != 2 * sizeof(unsigned int)) { while (size > 0) { printf("0x%08x,", tlv[idx++]); size -= sizeof(unsigned int); } } else { printf("min="); print_dB(tlv[2]); printf(",max="); print_dB(tlv[3]); } break; #endif #ifdef SND_CTL_TLVT_DB_RANGE case SND_CTL_TLVT_DB_RANGE: printf("dBrange-\n"); if ((size / (6 * sizeof(unsigned int))) != 0) { while (size > 0) { printf("0x%08x,", tlv[idx++]); size -= sizeof(unsigned int); } break; } idx = 0; while (idx < size) { print_spaces(spaces + 2); printf("rangemin=%i,", tlv[0]); printf(",rangemax=%i\n", tlv[1]); decode_tlv(spaces + 4, tlv + 2, 6 * sizeof(unsigned int)); idx += 6 * sizeof(unsigned int); } break; #endif #ifdef SND_CTL_TLVT_DB_MINMAX case SND_CTL_TLVT_DB_MINMAX: case SND_CTL_TLVT_DB_MINMAX_MUTE: if (type == SND_CTL_TLVT_DB_MINMAX_MUTE) printf("dBminmaxmute-"); else printf("dBminmax-"); if (size != 2 * sizeof(unsigned int)) { while (size > 0) { printf("0x%08x,", tlv[idx++]); size -= sizeof(unsigned int); } } else { printf("min="); print_dB(tlv[2]); printf(",max="); print_dB(tlv[3]); } break; #endif default: printf("unk-%i-", type); while (size > 0) { printf("0x%08x,", tlv[idx++]); size -= sizeof(unsigned int); } break; } putc('\n', stdout); } int HardwareMixerInterface::show_control(char *card, const char *space, snd_hctl_elem_t *elem, int level) { int err; unsigned int item, idx, count, *tlv; snd_ctl_elem_type_t type; snd_ctl_elem_id_t *id; snd_ctl_elem_info_t *info; snd_ctl_elem_value_t *control; snd_aes_iec958_t iec958; snd_ctl_elem_id_alloca(&id); snd_ctl_elem_info_alloca(&info); snd_ctl_elem_value_alloca(&control); if ((err = snd_hctl_elem_info(elem, info)) < 0) { printf("Control %s snd_hctl_elem_info error: %s\n", card, snd_strerror(err)); return err; } if (level & LEVEL_ID) { snd_hctl_elem_get_id(elem, id); show_control_id(id); printf("\n"); } count = snd_ctl_elem_info_get_count(info); type = snd_ctl_elem_info_get_type(info); printf("%s; type=%s,access=%s,values=%i", space, control_type(info), control_access(info), count); switch (type) { case SND_CTL_ELEM_TYPE_INTEGER: printf(",min=%li,max=%li,step=%li\n", snd_ctl_elem_info_get_min(info), snd_ctl_elem_info_get_max(info), snd_ctl_elem_info_get_step(info)); break; case SND_CTL_ELEM_TYPE_INTEGER64: printf(",min=%Li,max=%Li,step=%Li\n", snd_ctl_elem_info_get_min64(info), snd_ctl_elem_info_get_max64(info), snd_ctl_elem_info_get_step64(info)); break; case SND_CTL_ELEM_TYPE_ENUMERATED: { unsigned int items = snd_ctl_elem_info_get_items(info); printf(",items=%u\n", items); for (item = 0; item < items; item++) { snd_ctl_elem_info_set_item(info, item); if ((err = snd_hctl_elem_info(elem, info)) < 0) { printf("Control %s element info error: %s\n", card, snd_strerror(err)); return err; } printf("%s; Item #%u '%s'\n", space, item, snd_ctl_elem_info_get_item_name(info)); } break; } default: printf("\n"); break; } if (level & LEVEL_BASIC) { if (!snd_ctl_elem_info_is_readable(info)) goto __skip_read; if ((err = snd_hctl_elem_read(elem, control)) < 0) { printf("Control %s element read error: %s\n", card, snd_strerror(err)); return err; } printf("%s: values=", space); for (idx = 0; idx < count; idx++) { if (idx > 0) printf(","); switch (type) { case SND_CTL_ELEM_TYPE_BOOLEAN: printf("%s", snd_ctl_elem_value_get_boolean(control, idx) ? "on" : "off"); break; case SND_CTL_ELEM_TYPE_INTEGER: printf("%li", snd_ctl_elem_value_get_integer(control, idx)); break; case SND_CTL_ELEM_TYPE_INTEGER64: printf("%Li", snd_ctl_elem_value_get_integer64(control, idx)); break; case SND_CTL_ELEM_TYPE_ENUMERATED: printf("%u", snd_ctl_elem_value_get_enumerated(control, idx)); break; case SND_CTL_ELEM_TYPE_BYTES: printf("0x%02x", snd_ctl_elem_value_get_byte(control, idx)); break; case SND_CTL_ELEM_TYPE_IEC958: snd_ctl_elem_value_get_iec958(control, &iec958); printf("[AES0=0x%02x AES1=0x%02x AES2=0x%02x AES3=0x%02x]", iec958.status[0], iec958.status[1], iec958.status[2], iec958.status[3]); break; default: printf("?"); break; } } printf("\n"); __skip_read: if (!snd_ctl_elem_info_is_tlv_readable(info)) goto __skip_tlv; tlv = (unsigned int *) malloc(4096); if ((err = snd_hctl_elem_tlv_read(elem, tlv, 4096)) < 0) { printf("Control %s element TLV read error: %s\n", card, snd_strerror(err)); free(tlv); return err; } decode_tlv(strlen(space), tlv, 4096); free(tlv); } __skip_tlv: return 0; } int HardwareMixerInterface::get_ctl_enum_item_index(snd_ctl_t *handle, snd_ctl_elem_info_t *info, char **ptrp) { char *ptr = *ptrp; int items, i, len; const char *name; items = snd_ctl_elem_info_get_items(info); if (items <= 0) return -1; for (i = 0; i < items; i++) { snd_ctl_elem_info_set_item(info, i); if (snd_ctl_elem_info(handle, info) < 0) return -1; name = snd_ctl_elem_info_get_item_name(info); len = strlen(name); if (! strncmp(name, ptr, len)) { if (! ptr[len] || ptr[len] == ',' || ptr[len] == '\n') { ptr += len; *ptrp = ptr; return i; } } } return -1; } int HardwareMixerInterface::cset(char *card, int argc, char *argv[], int roflag, int keep_handle, int debugflag) { int err; static snd_ctl_t *handle = NULL; snd_ctl_elem_info_t *info; snd_ctl_elem_id_t *id; snd_ctl_elem_value_t *control; char *ptr; unsigned int idx, count; long tmp; snd_ctl_elem_type_t type; snd_ctl_elem_info_alloca(&info); snd_ctl_elem_id_alloca(&id); snd_ctl_elem_value_alloca(&control); if (argc < 1) { printf( "Specify a full control identifier: [[iface=,][name='name',][index=,][device=,][subdevice=]]|[numid=]\n"); return -EINVAL; } if (parse_control_id(argv[0], id)) { printf( "Wrong control identifier: %s\n", argv[0]); return -EINVAL; } if (debugflag) { printf("VERIFY ID: "); show_control_id(id); printf("\n"); } if (handle == NULL && (err = snd_ctl_open(&handle, card, 0)) < 0) { printf("Control %s open error: %s\n", card, snd_strerror(err)); return err; } snd_ctl_elem_info_set_id(info, id); if ((err = snd_ctl_elem_info(handle, info)) < 0) { printf("Cannot find the given element from control %s\n", card); if (! keep_handle) { snd_ctl_close(handle); handle = NULL; } return err; } snd_ctl_elem_info_get_id(info, id); /* FIXME: Remove it when hctl find works ok !!! */ type = snd_ctl_elem_info_get_type(info); count = snd_ctl_elem_info_get_count(info); snd_ctl_elem_value_set_id(control, id); if (!roflag) { ptr = argv[1]; for (idx = 0; idx < count && idx < 128 && ptr && *ptr; idx++) { switch (type) { case SND_CTL_ELEM_TYPE_BOOLEAN: tmp = 0; if (!strncasecmp(ptr, "on", 2) || !strncasecmp(ptr, "up", 2)) { tmp = 1; ptr += 2; } else if (!strncasecmp(ptr, "yes", 3)) { tmp = 1; ptr += 3; } else if (!strncasecmp(ptr, "toggle", 6)) { tmp = snd_ctl_elem_value_get_boolean(control, idx); tmp = tmp > 0 ? 0 : 1; ptr += 6; } else if (isdigit(*ptr)) { tmp = atoi(ptr) > 0 ? 1 : 0; while (isdigit(*ptr)) ptr++; } else { while (*ptr && *ptr != ',') ptr++; } snd_ctl_elem_value_set_boolean(control, idx, tmp); break; case SND_CTL_ELEM_TYPE_INTEGER: tmp = get_integer(&ptr, snd_ctl_elem_info_get_min(info), snd_ctl_elem_info_get_max(info)); snd_ctl_elem_value_set_integer(control, idx, tmp); break; case SND_CTL_ELEM_TYPE_INTEGER64: tmp = get_integer64(&ptr, snd_ctl_elem_info_get_min64(info), snd_ctl_elem_info_get_max64(info)); snd_ctl_elem_value_set_integer64(control, idx, tmp); break; case SND_CTL_ELEM_TYPE_ENUMERATED: tmp = get_ctl_enum_item_index(handle, info, &ptr); if (tmp < 0) tmp = get_integer(&ptr, 0, snd_ctl_elem_info_get_items(info) - 1); snd_ctl_elem_value_set_enumerated(control, idx, tmp); break; case SND_CTL_ELEM_TYPE_BYTES: tmp = get_integer(&ptr, 0, 255); snd_ctl_elem_value_set_byte(control, idx, tmp); break; default: break; } if (!strchr(argv[1], ',')) ptr = argv[1]; else if (*ptr == ',') ptr++; } if ((err = snd_ctl_elem_write(handle, control)) < 0) { printf("Control %s element write error: %s\n", card, snd_strerror(err)); if (!keep_handle) { snd_ctl_close(handle); handle = NULL; } return err; } } if (! keep_handle) { snd_ctl_close(handle); handle = NULL; } if (debugflag) { snd_hctl_t *hctl; snd_hctl_elem_t *elem; if ((err = snd_hctl_open(&hctl, card, 0)) < 0) { printf("Control %s open error: %s\n", card, snd_strerror(err)); return err; } if ((err = snd_hctl_load(hctl)) < 0) { printf("Control %s load error: %s\n", card, snd_strerror(err)); return err; } elem = snd_hctl_find_elem(hctl, id); if (elem) show_control(card, " ", elem, LEVEL_BASIC | LEVEL_ID); else printf("Could not find the specified element\n"); snd_hctl_close(hctl); } return 0; } int HardwareMixerInterface::ALSAMixerControlSet(int hwid, int numid, int val1, int val2, int val3, int val4) { // Generate amixer style control string based on IDs char numid_str[256], val_str[256]; if (numid < 0) { printf("AMIXER: Invalid ALSA mixer setting - no numid specified.\n"); return -1; } snprintf(numid_str,255,"numid=%d",numid); if (val4 != -1) snprintf(val_str,255,"%d,%d,%d,%d", val1,val2,val3,val4); else if (val3 != -1) snprintf(val_str,255,"%d,%d,%d", val1,val2,val3); else if (val2 != -1) snprintf(val_str,255,"%d,%d", val1,val2); else if (val1 != -1) snprintf(val_str,255,"%d", val1); else { printf("AMIXER: Invalid ALSA mixer setting - no control values specified.\n"); return -1; } char cardstr[256]; snprintf(cardstr,255,"hw:%d",hwid); char *cset_args[] = {numid_str,val_str}; if (hwid != prev_hwid) { prev_hwid = hwid; if (CRITTERS) printf("AMIXER: Same card (hw:%d), optimizing\n",hwid); return cset(cardstr,2,cset_args,0,0,CRITTERS); } else // Same hwid as last time, don't reopen hctl - optimize return cset(cardstr,2,cset_args,0,1,CRITTERS); } freewheeling-0.6.6/src/fweelin_amixer.h000066400000000000000000000065471370736313100201450ustar00rootroot00000000000000#ifndef __FWEELIN_AMIXER_H #define __FWEELIN_AMIXER_H /* Copyright 2004-2011 Jan Pekau This file is part of Freewheeling. Freewheeling is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. Freewheeling 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 Freewheeling. If not, see . */ /* This file contains code from amixer.c, ALSA's command line mixer utility: * * ALSA command line mixer utility * Copyright (c) 1999-2000 by Jaroslav Kysela * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include #include #include #include #ifndef __MACOSX__ #include #endif #include "fweelin_core.h" class Fweelin; /** * Interface class for directly talking to the audio hardware (ALSA) mixer * * Taken almost verbatim from amixer.c in alsa-utils, with minor changes to fit * Freewheeling. */ class HardwareMixerInterface { public: HardwareMixerInterface(Fweelin *app) : app(app), prev_hwid(-1) {}; #ifndef __MACOSX__ /* * Set an ALSA Mixer control * * Parameters: * the HW id (ie hw:0, hw:1, etc) * the control numid (ie numid=5) * and between 1 and 4 values. * * Returns zero on success. */ int ALSAMixerControlSet(int hwid, int numid, int val1, int val2 = -1, int val3 = -1, int val4 = -1); private: const char *control_type(snd_ctl_elem_info_t *info); const char *control_access(snd_ctl_elem_info_t *info); long get_integer(char **ptr, long min, long max); long get_integer64(char **ptr, long long min, long long max); int parse_control_id(const char *str, snd_ctl_elem_id_t *id); const char *control_iface(snd_ctl_elem_id_t *id); void show_control_id(snd_ctl_elem_id_t *id); void print_spaces(unsigned int spaces); void print_dB(long dB); void decode_tlv(unsigned int spaces, unsigned int *tlv, unsigned int tlv_size); int show_control(char *card, const char *space, snd_hctl_elem_t *elem, int level); int get_ctl_enum_item_index(snd_ctl_t *handle, snd_ctl_elem_info_t *info, char **ptrp); int cset(char *card, int argc, char *argv[], int roflag, int keep_handle, int debugflag); #endif Fweelin *app; int prev_hwid; // Previous cset call, what was the hwid? }; #endif freewheeling-0.6.6/src/fweelin_audioio.cc000066400000000000000000000253021370736313100204350ustar00rootroot00000000000000/* Does power come from fancy toys or does power come from the integrity of our walk? */ /* Copyright 2004-2011 Jan Pekau This file is part of Freewheeling. Freewheeling is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. Freewheeling 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 Freewheeling. If not, see . */ #include #include #include #include #include #include #include #include #include #include #include "fweelin_config.h" #include "fweelin_audioio.h" #include "fweelin_core_dsp.h" #if USE_FLUIDSYNTH #include "fweelin_fluidsynth.h" #endif // **************** SYSTEM LEVEL AUDIO int AudioIO::process (nframes_t nframes, void *arg) { AudioIO *inst = static_cast(arg); if (inst->audio_thread == 0) inst->audio_thread = pthread_self(); // Check if EMG or MEM needs wakeup inst->app->getEMG()->WakeupIfNeeded(); inst->app->getMMG()->WakeupIfNeeded(); // Get CPU load inst->cpuload = jack_cpu_load(inst->client); // Get JACK transport timing and status int tmp_roll = (jack_transport_query(inst->client,&(inst->jpos)) == JackTransportRolling); if (inst->jpos.valid & JackPositionBBT) inst->sync_active = 1; else inst->sync_active = 0; // Get buffers from jack AudioBuffers *ab = inst->app->getABUFS(); for (int i = 0; i < ab->numins_ext; i++) { // Left/mono channel ab->ins[0][i] = (sample_t *) jack_port_get_buffer (inst->iport[0][i], nframes); // Right channel ab->ins[1][i] = (inst->iport[1][i] != 0 ? (sample_t *) jack_port_get_buffer (inst->iport[1][i], nframes) : 0); } for (int i = 0; i < ab->numouts; i++) { // Left/mono channel ab->outs[0][i] = (sample_t *) jack_port_get_buffer (inst->oport[0][i], nframes); // Right channel ab->outs[1][i] = (inst->oport[1][i] != 0 ? (sample_t *) jack_port_get_buffer (inst->oport[1][i], nframes) : 0); } if (inst->rp != 0) { if (nframes != inst->app->getBUFSZ()) { printf("AUDIO: We've got a problem, honey!--\n"); printf("Audio buffer size has changed: %d->%d\n", inst->app->getBUFSZ(),nframes); exit(1); } // Run through audio processors inst->rp->process(0, nframes, ab); } inst->timebase_master = 0; // Reset timebase master flag- // callback will set to 1 if we are the master inst->transport_roll = tmp_roll; // Set transport rolling status return 0; } // Reposition JACK transport to the given position // Used for syncing external apps void AudioIO::RelocateTransport(nframes_t pos) { if (timebase_master) { jack_transport_locate(client,pos); repos = 1; } }; void AudioIO::timebase_callback(jack_transport_state_t /*state*/, jack_nframes_t /*nframes*/, jack_position_t *pos, int new_pos, void *arg) { AudioIO *inst = static_cast(arg); // Set timebase master flag inst->timebase_master = 1; /* printf("timebase called back (frame: %d, framerate: %d)!\n", pos->frame,pos->frame_rate); */ // Use our pulse information plus JACK's frame information // to calculate bars and beats and ticks Pulse *p = inst->app->getLOOPMGR()->GetCurPulse(); if (p != 0) { if (new_pos) { if (inst->repos) inst->repos = 0; // JACK telling us we have moved- but we initiated // the move, so ignore else { // Somebody has started the transport at a new position- // signal back that we want to start at a new position-- // based on the current pulse position. // printf("relocate: posframe: %d to %d\n",pos->frame,p->GetPos()); jack_transport_locate(inst->client,p->GetPos()); inst->repos = 1; #if 0 inst->sync_start_frame = pos->frame + (p->GetLength()-p->GetPos()); printf("posframe: %d syncstartframe set: %d\n",pos->frame, inst->sync_start_frame); #endif inst->sync_start_frame = 0; //pos->frame; } } #define TICKS_PER_BEAT 1920 int32_t rel_frame = (int) pos->frame - inst->sync_start_frame; float rel_bar = (float) rel_frame*inst->app->GetSyncSpeed()/p->GetLength(); if (inst->app->GetSyncType() != 0) // Beat sync, adjust bar by SYNC_BEATS_PER_BAR rel_bar /= SYNC_BEATS_PER_BAR; pos->valid = JackPositionBBT; pos->bar = (int32_t) rel_bar; float bar_frac = rel_bar - pos->bar; pos->beat = (int) (bar_frac * SYNC_BEATS_PER_BAR); pos->beats_per_bar = SYNC_BEATS_PER_BAR; if (inst->app->GetSyncType() == 0) pos->beats_per_minute = SYNC_BEATS_PER_BAR* 60.0*(double) pos->frame_rate/p->GetLength(); else pos->beats_per_minute = 60.0*(double) pos->frame_rate/p->GetLength(); pos->beat_type = SYNC_BEATS_PER_BAR; pos->ticks_per_beat = TICKS_PER_BEAT; float beat_frac = bar_frac*SYNC_BEATS_PER_BAR - (float)pos->beat; pos->tick = (int) (beat_frac * TICKS_PER_BEAT); pos->bar++; pos->beat++; //pos->tick++; pos->bar_start_tick = pos->bar * SYNC_BEATS_PER_BAR * TICKS_PER_BEAT; //printf("ticks per beat: %f\n",pos->ticks_per_beat); //printf("rel bar: %f, bar: %d, beat: %d, tick: %d\n",rel_bar, pos->bar, // pos->beat, pos->tick); } } int AudioIO::srate_callback (nframes_t nframes, void *arg) { AudioIO *inst = static_cast(arg); printf ("AUDIO: Sample rate is now %d/sec\n", nframes); inst->srate = nframes; return 0; } void AudioIO::audio_shutdown (void */*arg*/) { printf("AUDIO: shutdown! exiting..\n"); exit(1); } int AudioIO::activate (Processor *rp) { const char **ports; // Store the rootprocessor passed as beginning of signal chain this->rp = rp; // Start rolling audio through JACK server if (jack_activate (client)) { printf("AUDIO: ERROR: Cannot activate client!\n"); return 1; } // Connect ports //AudioBuffers *ab = app->getABUFS(); // INPUT // No longer connect audio ports because the mapping isn't clear with // multi stereoins/outs if ((ports = jack_get_ports (client, NULL, NULL, JackPortIsPhysical|JackPortIsOutput)) == NULL) printf("AUDIO: WARNING: Cannot find any physical capture ports!\n"); #if 0 for (int i = 0; i < ab->numins_ext && ports[i] != 0; i++) if (jack_connect (client, ports[i], jack_port_name (iport[i]))) { printf("AUDIO: Cannot connect input port %d->%s!\n",i, jack_port_name(iport[i])); } #endif free(ports); // OUTPUT if ((ports = jack_get_ports (client, NULL, NULL, JackPortIsPhysical|JackPortIsInput)) == NULL) printf("AUDIO: WARNING: Cannot find any physical playback ports!"); #if 0 for (int i = 0; i < ab->numouts && ports[i] != 0; i++) if (jack_connect (client, jack_port_name (oport[i]), ports[i])) { printf("AUDIO: Cannot connect output port %d->%s!\n",i, jack_port_name(oport[i])); } #endif free(ports); while (audio_thread == 0) // Wait for first process callback to register audio thread usleep(10000); RT_RWThreads::RegisterReaderOrWriter(audio_thread); return 0; } nframes_t AudioIO::getbufsz() { return jack_get_buffer_size (client); } void AudioIO::close () { jack_release_timebase (client); jack_client_close (client); delete[] iport[0]; delete[] iport[1]; delete[] oport[0]; delete[] oport[1]; printf("AUDIO: end\n"); } int AudioIO::open () { // **** AUDIO startup // Try to become a client of the JACK server client = jack_client_open("FreeWheeling", JackNoStartServer, NULL); if (!client) { fprintf (stderr, "AUDIO: ERROR: Jack server not running!\n"); return 1; } /* tell the JACK server to call `process()' whenever there is work to be done. */ jack_set_process_callback (client, process, this); jack_nframes_t bufsz = jack_get_buffer_size (client); printf ("AUDIO: Audio buffer size is: %d\n", bufsz); /* tell the JACK server to call `srate_callback()' whenever the sample rate of the system changes. */ jack_set_sample_rate_callback (client, srate_callback, this); /* tell the JACK server to call `jack_shutdown()' if it ever shuts down, either entirely, or if it just decides to stop calling us. */ jack_on_shutdown (client, audio_shutdown, this); // Set timebase callback jack_set_timebase_callback (client, 1, timebase_callback, this); /* display the current sample rate. once the client is activated (see below), you should rely on your own sample rate callback (see above) for this value. */ srate = jack_get_sample_rate (client); printf ("AUDIO: Engine sample rate is %d\n", srate); // Set time scale timescale = (float) bufsz/srate; repos = 0; // Create buffers AudioBuffers *ab = app->getABUFS(); printf("AUDIO: Using %d external inputs, %d total inputs\n", ab->numins_ext,ab->numins); iport[0] = new jack_port_t *[ab->numins_ext]; iport[1] = new jack_port_t *[ab->numins_ext]; oport[0] = new jack_port_t *[ab->numouts]; oport[1] = new jack_port_t *[ab->numouts]; // Create ports char tmp[255]; for (int i = 0; i < ab->numins_ext; i++) { char stereo = ab->IsStereoInput(i); snprintf(tmp,255,"in_%d%s",i+1,(stereo ? "L" : "")); iport[0][i] = jack_port_register(client, tmp, JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0); if (stereo) { snprintf(tmp,255,"in_%d%s",i+1,"R"); iport[1][i] = jack_port_register(client, tmp, JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0); } else iport[1][i] = 0; } for (int i = 0; i < ab->numouts; i++) { char stereo = ab->IsStereoOutput(i); snprintf(tmp,255,"out_%d%s",i+1,(stereo ? "L" : "")); oport[0][i] = jack_port_register(client, tmp, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0); if (stereo) { snprintf(tmp,255,"out_%d%s",i+1,"R"); oport[1][i] = jack_port_register(client, tmp, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0); } else oport[1][i] = 0; } return 0; } freewheeling-0.6.6/src/fweelin_audioio.h000066400000000000000000000075651370736313100203120ustar00rootroot00000000000000#ifndef __FWEELIN_AUDIOIO_H #define __FWEELIN_AUDIOIO_H /* Copyright 2004-2011 Jan Pekau This file is part of Freewheeling. Freewheeling is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. Freewheeling 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 Freewheeling. If not, see . */ extern "C" { #include } typedef jack_default_audio_sample_t sample_t; typedef jack_nframes_t nframes_t; class Fweelin; class Processor; // **************** SYSTEM LEVEL AUDIO class AudioIO { public: AudioIO(Fweelin *app) : sync_start_frame(0), timebase_master(0), sync_active(0), audio_thread(0), app(app) {}; // Open up system level audio int open (); // Activate system level audio int activate (Processor *rp); // Close system level audio void close (); // Get realtime buffer size nframes_t getbufsz(); // **Callbacks** // Realtime process function.. the beginning of the DSP chain static int process (nframes_t nframes, void *arg); // Timebase (jack transport sync) callback static void timebase_callback(jack_transport_state_t /*state*/, jack_nframes_t /*nframes*/, jack_position_t *pos, int new_pos, void *arg); // Sampling rate change callback static int srate_callback (nframes_t nframes, void *arg); // Callback for audio shutdown static void audio_shutdown (void */*arg*/); // Get current sampling rate inline nframes_t get_srate() { return srate; }; // Get approximate audio CPU load inline float GetAudioCPULoad() { return cpuload; }; inline float GetTimeScale() { return timescale; }; // Transport sync methods // Reposition transport to the given position // Used for syncing external apps void RelocateTransport(nframes_t pos); // Get current bar in transport mechanism inline int GetTransport_Bar() { return jpos.bar; }; // Get current beat in transport mechaniasm inline int GetTransport_Beat() { return jpos.beat; }; // Get current BPM in transport mechanism inline double GetTransport_BPM() { return jpos.beats_per_minute; }; // Get current # of beats per bar in transport mechanism inline float GetTransport_BPB() { return jpos.beats_per_bar; }; // Are we sending or receiving sync? inline char IsSync() { return sync_active; }; // Are we the timebase master? inline char IsTimebaseMaster() { return timebase_master; }; // Is the transport rolling? inline char IsTransportRolling() { return transport_roll; }; // Audio system client jack_client_t *client; // Inputs and outputs- stereo pairs jack_port_t **iport[2], **oport[2]; float cpuload; // Current approximate audio CPU load float timescale; // fragment length/sample rate = length (s) of one fragment nframes_t srate; // Sampling rate // Variables for audio (Jack transport) sync // Jack frame where the first bar began in transport int32_t sync_start_frame; char repos; // Nonzero if we have repositioned JACK internally jack_position_t jpos; // Current JACK position char timebase_master; // Nonzero if we are the JACK timebase master char sync_active; // Nonzero if sync is active char transport_roll; // Nonzero if the transport is rolling volatile pthread_t audio_thread; // RT audio thread (created by JACK) // Pointer to the main app Fweelin *app; // Processor which is basically the root of the signal flow Processor *rp; }; #endif freewheeling-0.6.6/src/fweelin_block.cc000066400000000000000000001773241370736313100201120ustar00rootroot00000000000000/* Things, in their Essence, are not of this world. */ /* Copyright 2004-2011 Jan Pekau This file is part of Freewheeling. Freewheeling is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. Freewheeling 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 Freewheeling. If not, see . */ #include #include #include #include #include #include #include #include #include #include #include "fweelin_block.h" #include "fweelin_core.h" iFileDecoder::iFileDecoder(Fweelin *app) : app(app), infd(0) {}; SndFileDecoder::SndFileDecoder(Fweelin *app, codec type) : iFileDecoder(app), filetype(type) { memset (&sfinfo, 0, sizeof (sfinfo)) ; samplesize = sizeof(float); sfinfd = NULL; // rbsize = 0; }; SndFileDecoder::~SndFileDecoder() {}; int SndFileDecoder::ReadFromFile(FILE *in, nframes_t rbuf_len) { if (!(sfinfd = sf_open_fd(fileno(in), SFM_READ, &sfinfo, SF_FALSE) )) { printf("DISK: unable to open file for reading \n"); return 1; } if (sfinfo.channels == 2) { printf("DISK: (SndFile) Stereo loop\n"); stereo = 1; } else if (sfinfo.channels == 1) { printf("DISK: (SndFile) Mono loop\n"); stereo = 0; } else { printf("DISK: (SndFile) Unknown # of audio channels %d\n",sfinfo.channels); return 1; } rbuf = new float[sfinfo.channels*rbuf_len]; obuf[0] = new float[rbuf_len]; if (stereo) obuf[1] = new float[rbuf_len]; if (sfinfo.samplerate != (signed int) app->getAUDIO()->get_srate()) { printf("DISK: (SndFile) Audio encoded at %dHz but we are running at " "%dHz.\n" "Samplerate conversion not yet supported.\n", (int) sfinfo.samplerate, app->getAUDIO()->get_srate()); return 1; } infd = in; return 0; }; int SndFileDecoder::ReadSamples(AudioBlockIterator *it, nframes_t max_len) { int len = 0; if (stereo) { if (filetype == FLAC){ // need to convert from int24 len = sf_read_float(sfinfd,rbuf,sfinfo.channels*max_len); len /= sfinfo.channels; } else { // everything else is currently native float len = sf_read_raw(sfinfd,rbuf,sfinfo.channels*max_len*samplesize); len /= (sfinfo.channels *samplesize); } for (nframes_t i = 0; i < max_len; i++) { // deinterleave channels using brute strength obuf[0][i] = rbuf[2*i]; obuf[1][i] = rbuf[2*i+1]; } if (len > 0) { it->PutFragment(obuf[0],obuf[1],len,1); it->NextFragment(); } } else { if (filetype == FLAC) { // need to convert from int24 len = sf_read_float(sfinfd,obuf[0],sfinfo.channels*max_len); } else { // everything else is currently native float len = sf_read_raw(sfinfd,obuf[0],sfinfo.channels*max_len*samplesize); } if (len > 0) { it->PutFragment(obuf[0],0,len,1); it->NextFragment(); } } return len; }; void SndFileDecoder::Stop(){ if(rbuf != NULL) delete[] rbuf; if(obuf[0] != NULL) delete[] obuf[0]; if(obuf[1] != NULL) delete[] obuf[1]; sf_close(sfinfd); } VorbisDecoder::VorbisDecoder(Fweelin *app) : iFileDecoder(app) {}; VorbisDecoder::~VorbisDecoder() {}; // Returns nonzero on error int VorbisDecoder::ReadFromFile(FILE *in, nframes_t /*rbuf_len*/) { if (ov_open(in, &vf, NULL, 0) < 0) { printf("DISK: (VorbisFile) Input does not appear to be an Ogg " "bitstream.\n"); return 1; } vorbis_info *vi = ov_info(&vf,-1); if (vi->channels == 2) { printf("DISK: (VorbisFile) Stereo loop\n"); stereo = 1; } else if (vi->channels == 1) { printf("DISK: (VorbisFile) Mono loop\n"); stereo = 0; } else { printf("DISK: (VorbisFile) Unknown # of audio channels %d\n",vi->channels); return 1; } if (vi->rate != (signed int) app->getAUDIO()->get_srate()) { printf("DISK: (VorbisFile) Audio encoded at %dHz but we are running at " "%dHz.\n" "Samplerate conversion not yet supported.\n", (int) vi->rate,app->getAUDIO()->get_srate()); return 1; } infd = in; return 0; }; int VorbisDecoder::ReadSamples(AudioBlockIterator *i, nframes_t max_len) { int len; float **outb; len = ov_read_float(&vf,&outb,max_len,¤t_section); if (len > 0) { if (stereo) i->PutFragment(outb[0],outb[1],len,1); else i->PutFragment(outb[0],0,len,1); i->NextFragment(); } return len; }; // int VorbisDecoder::Decode(float **pcm_channels, nframes_t max_len) { // return ov_read_float(&vf,&pcm_channels,max_len,¤t_section); // }; iFileEncoder::iFileEncoder(Fweelin *app, char stereo) : app(app), stereo(stereo), outfd(0) { }; SndFileEncoder::SndFileEncoder (Fweelin *app, nframes_t maxframes, char stereo, codec format) : iFileEncoder(app,stereo), tbuf(0) { filetype = format; memset(&sfinfo, 0, sizeof (sfinfo)) ; // set params sfinfo.samplerate = app->getAUDIO()->get_srate(); sfinfo.frames = 0x7FFFFFFF; if (stereo) { sfinfo.channels = 2; tbuf = new float[maxframes*sfinfo.channels]; } else sfinfo.channels = 1; if (filetype == FLAC) sfinfo.format = (SF_FORMAT_FLAC | SF_FORMAT_PCM_24); else sfinfo.format = (SF_FORMAT_WAV | SF_FORMAT_FLOAT); samplesize = sizeof(float); // buffer = NULL; // printf("SndFileEncoder init\n"); }; int SndFileEncoder::SetupFileForWriting (FILE *file) { if (!(sndoutfd = sf_open_fd(fileno(file), SFM_WRITE, &sfinfo, SF_FALSE))) { printf("DISK: Couldn't open output sound file!\n"); return 1; } return 0; }; long int SndFileEncoder::WriteSamplesToDisk (sample_t **ibuf, nframes_t startframe, nframes_t numframes) { if (stereo) { for (nframes_t i = 0; i < numframes; i++) { tbuf[2*i] = ibuf[0][startframe+i]; tbuf[2*i+1] = ibuf[1][startframe+i]; } if (filetype == FLAC) // FIXME: perhaps some error checking sf_write_float(sndoutfd, tbuf, numframes*sfinfo.channels); else sf_write_raw(sndoutfd, static_cast(tbuf), numframes*samplesize*sfinfo.channels); } else { if (filetype == FLAC) // FIXME: perhaps some error checking sf_write_float(sndoutfd, ibuf[0], numframes); else sf_write_raw(sndoutfd, ibuf[0], numframes*samplesize); } return (long int) numframes; } void SndFileEncoder::PrepareFileForClosing(){ sf_close(sndoutfd); } VorbisEncoder::VorbisEncoder(Fweelin *app, char stereo) : iFileEncoder(app,stereo) { // Setup vorbis vorbis_info_init(&vi); if (vorbis_encode_init_vbr(&vi,(stereo ? 2 : 1),app->getAUDIO()->get_srate(), app->getCFG()->GetVorbisEncodeQuality())) return; // Comment vorbis_comment_init(&vc); vorbis_comment_add_tag(&vc,"ENCODER","FreeWheeling"); // Analysis state/Aux encoding storage vorbis_analysis_init(&vd,&vi); vorbis_block_init(&vd,&vb); /* set up our packet->stream encoder */ /* pick a random serial number; that way we can more likely build chained streams just by concatenation */ srand(time(NULL)); ogg_stream_init(&os,rand()); }; VorbisEncoder::~VorbisEncoder() { /* Vorbis clean up and exit. vorbis_info_clear() must be called last */ ogg_stream_clear(&os); vorbis_block_clear(&vb); vorbis_dsp_clear(&vd); vorbis_comment_clear(&vc); vorbis_info_clear(&vi); }; int VorbisEncoder::SetupFileForWriting(FILE *out) { outfd = out; // Write vorbis header ogg_packet header; ogg_packet header_comm; ogg_packet header_code; vorbis_analysis_headerout(&vd,&vc,&header,&header_comm,&header_code); ogg_stream_packetin(&os,&header); /* automatically placed in its own page */ ogg_stream_packetin(&os,&header_comm); ogg_stream_packetin(&os,&header_code); while(1) { int result = ogg_stream_flush(&os,&og); if (result == 0) break; fwrite(og.header,1,og.header_len,outfd); fwrite(og.body,1,og.body_len,outfd); } return 0; }; long int VorbisEncoder::WriteSamplesToDisk (sample_t **ibuf, nframes_t startframe, nframes_t numframes) { // Here we make assumption that sample_t is equivalent to float // And that there is only 1 vorbis channel of data float **obuf = GetAnalysisBuffer(numframes); if (stereo) { memcpy(obuf[0], &ibuf[0][startframe], sizeof(float) * numframes); memcpy(obuf[1], &ibuf[1][startframe], sizeof(float) * numframes); } else { memcpy(obuf[0], &ibuf[0][startframe], sizeof(float) * numframes); } WroteToBuffer(numframes); Encode(); return (long int) numframes; }; // This analyzes and dumps any remaining frames out to file long int VorbisEncoder::Encode() { if (outfd != 0) { long int outputsize = 0; // Now do the real analysis!! Meat n potatoes! while(vorbis_analysis_blockout(&vd,&vb) == 1) { /* analysis, assume we want to use bitrate management */ vorbis_analysis(&vb,NULL); vorbis_bitrate_addblock(&vb); while(vorbis_bitrate_flushpacket(&vd,&op)) { /* weld the packet into the bitstream */ ogg_stream_packetin(&os,&op); /* write out pages (if any) */ char eos = 0; while (!eos) { int result = ogg_stream_pageout(&os,&og); if (result == 0) break; fwrite(og.header,1,og.header_len,outfd); fwrite(og.body,1,og.body_len,outfd); // Add to the output size outputsize += og.header_len; outputsize += og.body_len; if (ogg_page_eos(&og)) eos = 1; } } } return outputsize; } else { printf("BLOCK: ERROR: OGG encoder finished but Encode() called!\n"); return 0; } } void VorbisEncoder::Preprocess(sample_t *l, sample_t *r, nframes_t len) { if (r == 0) //mono for (nframes_t i = 0; i < len; i++) l[i] *= 0.9; else { for (nframes_t i = 0; i < len; i++) { l[i] *= 0.9; r[i] *= 0.9; } } }; BlockReadManager::BlockReadManager(FILE *in, AutoReadControl *arc, BlockManager *bmg, nframes_t peaksavgs_chunksize) : ManagedChain(0,0), in(in), smooth_end(0), arc(arc), dec(0), bmg(bmg), pa_mgr(0), peaksavgs_chunksize(peaksavgs_chunksize) { pthread_mutex_init(&decode_lock,0); }; BlockReadManager::~BlockReadManager() { if (in != 0) { End(0); } pthread_mutex_destroy (&decode_lock); }; void BlockReadManager::SetLoopType (codec looptype){ // printf("DISK: Looptype: %s\n", bmg->GetApp()->getCFG()->GetCodecName(looptype)); filetype = looptype; }; // Start decoding from the given file void BlockReadManager::Start(FILE *new_in) { if (dec != 0) return; // Already running if (in == 0 && new_in != 0) { // New input specified in = new_in; } if (in != 0) { // Start vorbis decoder switch (filetype) { case VORBIS: dec = new VorbisDecoder(bmg->GetApp()); break; case WAV: dec = new SndFileDecoder(bmg->GetApp(),WAV); break; case FLAC: dec = new SndFileDecoder(bmg->GetApp(),FLAC); break; case AU: dec = new SndFileDecoder(bmg->GetApp(),AU); break; default: dec = new VorbisDecoder(bmg->GetApp()); break; } b = (AudioBlock *) bmg->GetApp()->getPRE_AUDIOBLOCK()->RTNewWithWait(); i = new AudioBlockIterator(b,DECODE_CHUNKSIZE, bmg->GetApp()->getPRE_EXTRACHANNEL()); // Compute audio peaks & averages for display if (peaksavgs_chunksize != 0) { AudioBlock *peaks = (AudioBlock *) b->RTNew(), *avgs = (AudioBlock *) b->RTNew(); if (peaks == 0 || avgs == 0) { printf("BlockReadManager: ERROR: No free blocks for peaks/avgs\n"); if (peaks != 0) peaks->RTDelete(); if (avgs != 0) avgs->RTDelete(); pa_mgr = 0; } else { b->AddExtendedData(new BED_PeaksAvgs(peaks,avgs,peaksavgs_chunksize)); pa_mgr = bmg->PeakAvgOn(b,i,1); } } // Tell decoder to read from file if (dec->ReadFromFile(in,DECODE_CHUNKSIZE)) // End in error, freeing vorbis End(1); } }; void BlockReadManager::End(char error) { // Can't end while decoding- lock mutex pthread_mutex_lock (&decode_lock); // Stop decoder if (dec != 0) { dec->Stop(); delete dec; // Chop block to current position i->EndChain(); // End peaks avgs compute now if (pa_mgr != 0) { // Catchup then end pa_mgr->Manage(); pa_mgr->End(); bmg->PeakAvgOff(b); pa_mgr = 0; } delete i; i = 0; dec = 0; } if (in != 0) { // printf("DISK: Close input.\n"); // Vorbis decoder closes file through ov_clear! in = 0; } if (b != 0) { if (error) { // If error, delete chain and send zero to ReadComplete b->DeleteChain(); b = 0; } else { // Finished read, handle looppoint smoothing // if (smooth_end) // New way // printf("blen: %d\n",b->GetTotalLen()); // b->Smooth(0,BlockWriteManager::ENCODE_CROSSOVER_LEN); if (!smooth_end) { // Old way b->Smooth(1,BlockReadManager::SMOOTH_FIX_LEN); // We will have to adjust the pulselength because we are changing the // length of the loop here } } // Callback if (arc != 0) arc->ReadComplete(b); b = 0; } pthread_mutex_unlock(&decode_lock); }; int BlockReadManager::Manage() { if (in == 0) { // Not currently decoding if (arc != 0) { // We have a callback, get a chain to load arc->GetReadBlock(&in,&smooth_end); if (in != 0) // We got a chain to load, so begin Start(); } else { // No callback, so we are done! return 1; } } if (in != 0) { // Make sure we have started on this blockchain if (dec == 0) Start(); // Continue decoding pthread_mutex_lock (&decode_lock); // Now that we have the lock, make sure we are still active if (in != 0) { for (int pass = 0; in != 0 && pass < NUM_DECODE_PASSES; pass++) { // Make sure we have an extra block in our chain if (i->GetCurBlock()->next == 0) { AudioBlock *nw = (AudioBlock *) i->GetCurBlock()->RTNew(); if (nw == 0) { // Pause decode until block is here printf("BlockReadManager: Waiting for block.\n"); pthread_mutex_unlock (&decode_lock); return 0; } i->GetCurBlock()->Link(nw); } // Decode samples int len = dec->ReadSamples(i,DECODE_CHUNKSIZE); if (len == 0) { // EOF pthread_mutex_unlock (&decode_lock); End(0); } else if (len < 0) { // Stream error- just continue printf("BlockReadManager: Stream read error!\n"); } } } pthread_mutex_unlock (&decode_lock); } return 0; }; BlockWriteManager::BlockWriteManager(FILE *out, AutoWriteControl *awc, BlockManager *bmg, AudioBlock *b, AudioBlockIterator *i) : ManagedChain(b,i), out(out), len(0), awc(awc), enc(0), bmg(bmg) { pthread_mutex_init(&encode_lock,0); }; BlockWriteManager::~BlockWriteManager() { if (b != 0) { End(); } pthread_mutex_destroy (&encode_lock); }; // Start encoding the given block chain to the given file void BlockWriteManager::Start(FILE *new_out, AudioBlock *new_b, AudioBlockIterator *new_i, nframes_t new_len) { if (enc != 0) return; // Already running if (b == 0 && new_b != 0) { // New chain specified // printf("start: new chain b: %p new_b: %p\n",b,new_b); b = new_b; i = new_i; out = new_out; len = new_len; } if (b != 0) { //printf("start: out: %p new_out: %p, b: %p new_b: %p\n",out,new_out, // b,new_b); // Encode an extra ENCODE_CROSSOVER_LEN frames at the end // because OGG loops are not sample aligned from end-to-begin // len += ENCODE_CROSSOVER_LEN; // printf("slen: %d\n", len); pos = 0; // Start File encoder Fweelin *app = bmg->GetApp(); switch (app->getCFG()->GetLoopOutFormat()) { case VORBIS: enc = new VorbisEncoder(app,b->IsStereo()); break; case WAV: enc = new SndFileEncoder(app,ENCODE_CHUNKSIZE,b->IsStereo(),WAV); break; case FLAC: enc = new SndFileEncoder(app,ENCODE_CHUNKSIZE,b->IsStereo(),FLAC); break; case AU: enc = new SndFileEncoder(app,ENCODE_CHUNKSIZE,b->IsStereo(),AU); break; default: enc = new VorbisEncoder(app,b->IsStereo()); break; }; ei = new AudioBlockIterator(b,ENCODE_CHUNKSIZE); // Set encoder to dump to file enc->SetupFileForWriting(out); } }; void BlockWriteManager::End() { // Can't end while encoding- lock mutex pthread_mutex_lock (&encode_lock); // Stop encoder if (enc != 0) { enc->PrepareFileForClosing(); delete enc; delete ei; enc = 0; } if (out != 0) { printf("DISK: Close output.\n"); fclose(out); out = 0; } b = 0; i = 0; len = 0; pthread_mutex_unlock(&encode_lock); }; int BlockWriteManager::Manage() { if (b == 0) { // Not currently encoding if (awc != 0) { // We have a callback, get a chain to save awc->GetWriteBlock(&out,&b,&i,&len); if (b != 0) // We got a chain to save, so begin Start(); } else { // No callback, so we are done! return 1; } } if (b != 0) { // Make sure we have started on this blockchain if (enc == 0) Start(); // Continue encoding pthread_mutex_lock (&encode_lock); // Now that we have the lock, make sure we are still active if (b != 0) { nframes_t remaining = len-pos, num = MIN(ENCODE_CHUNKSIZE,remaining); sample_t *ibuf[2]; if (enc->IsStereo()) { // Stereo ei->GetFragment(&ibuf[0],&ibuf[1]); pos += enc->WriteSamplesToDisk(ibuf,0,num); } else { // Mono ei->GetFragment(&ibuf[0],0); pos += enc->WriteSamplesToDisk(ibuf,0,num); } if (remaining <= ENCODE_CHUNKSIZE) { // Finished encoding pthread_mutex_unlock (&encode_lock); End(); } else ei->NextFragment(); } pthread_mutex_unlock (&encode_lock); } return 0; }; BED_PeaksAvgs::~BED_PeaksAvgs() { peaks->DeleteChain(); avgs->DeleteChain(); }; int BED_MarkerPoints::CountMarkers() { TimeMarker *cur = markers; int markcnt = 0; while (cur != 0) { markcnt++; cur = cur->next; }; return markcnt; }; BED_MarkerPoints::~BED_MarkerPoints() { TimeMarker *cur = markers; while (cur != 0) { TimeMarker *tmp = cur->next; cur->RTDelete(); cur = tmp; } }; // Returns the nth marker before (in time) the current offset passed // This method correctly handles a reverse wrap case when the // marker NBeforeCur is farther ahead in the attached block than the // current offset TimeMarker *BED_MarkerPoints::GetMarkerNBeforeCur(int n, nframes_t curofs) { TimeMarker *cur = markers; signed int markcnt = 0; int totalmarks = CountMarkers(); if (totalmarks == 0) return 0; // No solution because there are no markers! else { while (cur != 0 && cur->markofs < curofs) { markcnt++; cur = cur->next; } // Markcnt now indexes the next marker after curofs // Go N before! markcnt -= n; while (markcnt < 0) { // Reverse wrap case markcnt += totalmarks; } // Now get marker indexed by markcnt cur = markers; int markcnt2 = 0; while (cur != 0 && markcnt2 != markcnt) { markcnt2++; cur = cur->next; } // & return it return cur; } }; // Create a new extra channel BED_ExtraChannel::BED_ExtraChannel(nframes_t len) { if (len > 0) { //printf("allocating origbuf..\n"); origbuf = buf = new sample_t[len]; //printf("done: origbuf %p: buf %p!..\n",origbuf,buf); } else origbuf = buf = 0; }; BED_ExtraChannel::~BED_ExtraChannel() { if (origbuf != 0) { //printf("deleting origbuf %p: buf %p!..\n",origbuf,buf); delete[] origbuf; //printf("done!\n"); } }; // Create a new audioblock as the beginning of a block list AudioBlock::AudioBlock(nframes_t len) : len(len), next(0), first(this), xt(0) { if (len > 0) origbuf = buf = new sample_t[len]; } // Create a new audioblock and link up the specified block to it AudioBlock::AudioBlock(AudioBlock *prev, nframes_t len) : len(len), next(0), first(prev->first), xt(0) { prev->next = this; if (len > 0) origbuf = buf = new sample_t[len]; } AudioBlock::~AudioBlock() { //printf("~AudioBlock len: %d dsz: %d\n",len,sizeof(*buf)); if (origbuf != 0) delete[] origbuf; } // Clears this block chain- not changing length void AudioBlock::Zero() { AudioBlock *cur = first; while (cur != 0) { memset(cur->buf,0,sizeof(sample_t)*cur->len); cur = cur->next; } }; // Link us up to the specified block void AudioBlock::Link(AudioBlock *to) { to->first = first; to->next = 0; next = to; } // RT safe void AudioBlock::ChopChain() { // Chop off the chain at this block // Freeing unused blocks AudioBlock *cur = next; next = 0; while (cur != 0) { AudioBlock *tmp = cur->next; if (cur->xt != 0) printf("BLOCK: WARNING: XT data not freed in ChopChain! " "Possible leak.\n"); cur->RTDelete(); cur = tmp; } } // Smooth an audio block- // either smooth the beginning into the end (smoothtype == 1) // or smooth the end into the beginning (smoothtype == 0) void AudioBlock::Smooth(char smoothtype, nframes_t smoothlen) { // Smooth the end of this chain into the beginning for looping AudioBlock *smoothblk; nframes_t smoothofs, smoothcnt, totallen = GetTotalLen(); if (totallen >= smoothlen) smoothcnt = totallen - smoothlen; else return; // Very short chain, can't smooth it // Get block & offset for start of smooth SetPtrsFromAbsOffset(&smoothblk, &smoothofs, smoothcnt); if (smoothblk == 0) { // Shouldn't happen printf("AudioBlock: ERROR: Block position mismatch in Smooth.\n"); exit(1); } AudioBlock *startblk = first; nframes_t startofs = 0; // Second channel? BED_ExtraChannel *rightstartblk = (BED_ExtraChannel *) startblk->GetExtendedData(T_BED_ExtraChannel), *rightsmoothblk = (BED_ExtraChannel *) smoothblk->GetExtendedData(T_BED_ExtraChannel); char stereo = 0; if (rightstartblk != 0 && rightsmoothblk != 0) stereo = 1; float mix = 0.0, dmix = 1./(float)smoothlen; for (nframes_t i = 0; i < smoothlen; i++, mix += dmix) { if (smoothtype) { // Write beginning into end smoothblk->buf[smoothofs] = mix*startblk->buf[startofs] + (1.0-mix)*smoothblk->buf[smoothofs]; if (stereo) rightsmoothblk->buf[smoothofs] = mix*rightstartblk->buf[startofs] + (1.0-mix)*rightsmoothblk->buf[smoothofs]; } else { // Write end into beginning startblk->buf[startofs] = mix*startblk->buf[startofs] + (1.0-mix)*smoothblk->buf[smoothofs]; if (stereo) rightstartblk->buf[startofs] = mix*rightstartblk->buf[startofs] + (1.0-mix)*rightsmoothblk->buf[smoothofs]; } smoothofs++; startofs++; if (smoothofs >= smoothblk->len) { smoothblk = smoothblk->next; smoothofs = 0; if (smoothblk == 0) { if (i+1 < smoothlen) { // Shouldn't happen printf("AudioBlock: ERROR: (smoothblk) Block size mismatch in " "Smooth: i: %d\n", i); exit(1); } rightsmoothblk = 0; } else { rightsmoothblk = (BED_ExtraChannel *) smoothblk->GetExtendedData(T_BED_ExtraChannel); if (stereo && rightsmoothblk == 0) { // Shouldn't happen printf("AudioBlock: ERROR: (smoothblk) Right channel " "disappeared!\n"); exit(1); } } } if (startofs >= startblk->len) { startblk = startblk->next; startofs = 0; if (startblk == 0) { if (i+1 < smoothlen) { // Shouldn't happen printf("AudioBlock: ERROR: (startblk) Block size mismatch in " "Smooth.\n"); exit(1); } rightstartblk = 0; } else { rightstartblk = (BED_ExtraChannel *) startblk->GetExtendedData(T_BED_ExtraChannel); if (stereo && rightstartblk == 0) { // Shouldn't happen printf("AudioBlock: ERROR: (startblk) Right channel disappeared!\n"); exit(1); } } } } if (smoothtype) { // Adjust first buf to skip samples that were smoothed into end if (first->len < smoothlen) { printf("AudioBlock: WARNING: First block is very short, " "no adjust in Smooth.\n"); } else { first->buf += smoothlen; first->len -= smoothlen; BED_ExtraChannel *rightfirst = (BED_ExtraChannel *) first->GetExtendedData(T_BED_ExtraChannel); if (rightfirst != 0) rightfirst->buf += smoothlen; } } else { // Shorten the chain to skip end which is now smoothed into beginning HackTotalLengthBy(smoothlen); } //printf("endsmooth: startofs: %d smoothofs: %d len: %d\n", // startofs, smoothofs, totallen); } // not RT safe void AudioBlock::DeleteChain() { AudioBlock *cur = first; while (cur != 0) { // First erase any extended data BlockExtendedData *curxt = cur->xt; while (curxt != 0) { BlockExtendedData *tmpxt = curxt->next; if (curxt->GetType() == T_BED_ExtraChannel) ((BED_ExtraChannel *)curxt)->RTDelete(); else delete curxt; curxt = tmpxt; } // Then the block itself! AudioBlock *tmp = cur->next; cur->RTDelete(); cur = tmp; } } // Returns the total length of this audio chain nframes_t AudioBlock::GetTotalLen() { nframes_t tally = 0; AudioBlock *cur = first; while (cur != 0) { tally += cur->len; cur = cur->next; } return tally; }; // Gets extended data for this block BlockExtendedData *AudioBlock::GetExtendedData(BlockExtendedDataType x) { BlockExtendedData *cur = xt; while (cur!=0 && cur->GetType()!=x) cur = cur->next; return cur; }; // Add this extended data to the list of extended data for this block void AudioBlock::AddExtendedData(BlockExtendedData *nw) { nw->next = xt; xt = nw; }; // Finds the audioblock and offset into that block that correspond // to the provided absolute offset into this chain void AudioBlock::SetPtrsFromAbsOffset(AudioBlock **ptr, nframes_t *blkofs, nframes_t absofs) { AudioBlock *cur = first, *prev = 0; nframes_t curofs = 0, prevofs = 0; while (cur != 0 && curofs <= absofs) { prevofs = curofs; curofs += cur->len; prev = cur; cur = cur->next; } if (curofs < absofs || prev == 0) { // We're at the end and we still haven't traversed far enough! // Return err *ptr = 0; return; } *ptr = prev; *blkofs = absofs-prevofs; }; // Generates a subchain of AudioBlocks by copying the samples between offsets // from & to.. offsets expressed absolutely with reference to // beginning of this chain! // Samples are copied up to but not including toofs // If toofs < fromofs, generates a subblock that includes the end of // the block and the beginning up to toofs (wrap case) // Returns the last block in the new subchain // Flag sets whether to copy stereo channel if there is one // Realtime safe? AudioBlock *AudioBlock::GenerateSubChain(nframes_t fromofs, nframes_t toofs, char copystereo) { if (toofs == fromofs) return 0; // Handle wrap case if (toofs < fromofs) toofs += GetTotalLen(); // Stereo? BED_ExtraChannel *rightfirst = (BED_ExtraChannel *) first->GetExtendedData(T_BED_ExtraChannel); char stereo = (copystereo && rightfirst != 0); // Get enough new blocks to fit the subblock size nframes_t sublen = toofs - fromofs, suballoc = 0; AudioBlock *subfirst = 0, *subcur = 0; while (suballoc < sublen) { if (subfirst == 0) { subcur = subfirst = (AudioBlock *)RTNew(); if (subfirst == 0) { printf("Err: GenerateSubChain- No new blocks available\n"); return 0; } } else { AudioBlock *tmp = (AudioBlock *)RTNew(); if (tmp == 0) { printf("Err: GenerateSubChain- No new blocks available\n"); return 0; } subcur->Link(tmp); subcur = subcur->next; } if (stereo) { BED_ExtraChannel *rightsub = (BED_ExtraChannel*)rightfirst->RTNew(); if (rightsub == 0) { printf("Err: GenerateSubChain- No new right blocks available\n"); return 0; } subcur->AddExtendedData(rightsub); } suballoc += subcur->len; } // Find starting pos in chain AudioBlock *cur; nframes_t curofs = 0; SetPtrsFromAbsOffset(&cur,&curofs,fromofs); subcur = subfirst; nframes_t subofs = 0, remaining = sublen; // Extra channel BED_ExtraChannel *subright = (stereo ? (BED_ExtraChannel *) subcur->GetExtendedData(T_BED_ExtraChannel) : 0), *right = (stereo ? (BED_ExtraChannel *) cur->GetExtendedData(T_BED_ExtraChannel) : 0); do { nframes_t n = MIN(cur->len-curofs,remaining); n = MIN(n,subcur->len-subofs); memcpy(&subcur->buf[subofs],&cur->buf[curofs],n*sizeof(sample_t)); if (stereo) memcpy(&subright->buf[subofs],&right->buf[curofs],n*sizeof(sample_t)); subofs += n; curofs += n; remaining -= n; if (curofs >= cur->len) { cur = cur->next; curofs = 0; if (cur == 0) // Past the end of the block chain-- wrap around to first cur = first; if (stereo) right = (BED_ExtraChannel *) cur->GetExtendedData(T_BED_ExtraChannel); } if (subofs >= subcur->len) { subcur = subcur->next; subofs = 0; if (subcur == 0 && remaining) { // This should never happen, because we make the destination // chain long enough to hold the subblock printf("Err: GenerateSubChain destination block size mismatch\n"); exit(1); } if (stereo) subright = (BED_ExtraChannel *) subcur->GetExtendedData(T_BED_ExtraChannel); } } while (remaining); // Truncate the last presized subblock to the right length subcur->len = subofs; // And return the last block in the chain return subcur; }; // *** To be tested! *** // // Removes the last 'hacklen' samples from this block chain // Returns nonzero on error! // Realtime safe? int AudioBlock::HackTotalLengthBy(nframes_t hacklen) { // Compute the position of hack nframes_t chainlen = GetTotalLen(); //printf("Hack (b): %ld\n",chainlen); AudioBlock *hackblk; nframes_t hackofs = 0; if (chainlen <= hacklen) return 1; SetPtrsFromAbsOffset(&hackblk,&hackofs,chainlen-hacklen); // Now hackblk[hackofs] should be the first sample to erase at the // end of the chain hackblk->len = hackofs; // Truncate length of block // Note: Block memory isnt resized, so some extra memory lingers until // the block is erased AudioBlock *tmp = hackblk->next; hackblk->next = 0; // End of chain at hack position // Erase remaining blocks in chain hackblk = tmp; while (hackblk != 0) { tmp = hackblk->next; // First erase any extended data BlockExtendedData *hackxt = hackblk->xt; while (hackxt != 0) { BlockExtendedData *tmpxt = hackxt->next; delete hackxt; hackxt = tmpxt; } // Then the block itself hackblk->RTDelete(); hackblk = tmp; } //printf("Hack (e): %ld\n",GetTotalLen()); return 0; }; // Inserts the new blockchain at the beginning of this block chain // Returns a pointer to the new first block AudioBlock *AudioBlock::InsertFirst(AudioBlock *nw) { // Move to the end of the passed chain while (nw->next != 0) nw = nw->next; // Link new block to the beginning of our chain nw->next = first; // Link all first pointers to first block in new chain AudioBlock *cur = first; while (cur != 0) { cur->first = nw->first; cur = cur->next; } return nw->first; }; AudioBlockIterator::AudioBlockIterator(AudioBlock *firstblock, nframes_t fragmentsize, PreallocatedType *pre_extrachannel) : pre_extrachannel(pre_extrachannel), currightblock(0), nextrightblock(0), currightblock_w(0), nextrightblock_w(0), curblock(firstblock), nextblock(0), curblock_w(0), nextblock_w(0), curblkofs(0), nextblkofs(0), curcnt(0), nextcnt(0), curblkofs_w(0), nextblkofs_w(0), curcnt_w(0), nextcnt_w(0), fragmentsize(fragmentsize), stopped(0) { fragment[0] = new sample_t[fragmentsize]; fragment[1] = new sample_t[fragmentsize]; } AudioBlockIterator::~AudioBlockIterator() { delete[] fragment[0]; delete[] fragment[1]; }; // Stores in cnt the absolute count corresponding to the given // block and offset void AudioBlockIterator::GenCnt(AudioBlock *blk, nframes_t blkofs, nframes_t *cnt) { AudioBlock *cur = curblock->first; nframes_t curofs = 0; while (cur != 0 && cur != blk) { // Add the length of this whole block curofs += cur->len; cur = cur->next; } if (cur == 0) { // Given block not found! *cnt = 0; } else { // We are now on the given block- add only current block offset curofs += blkofs; *cnt = curofs; } } void AudioBlockIterator::Jump(nframes_t ofs) { // Quantize the specified offset to within the limits of the blockchain ofs = ofs % curblock->GetTotalLen(); nframes_t cb_ofs = 0; curblock->SetPtrsFromAbsOffset(&curblock,&cb_ofs,ofs); curblkofs = cb_ofs; if (curblock == 0) { printf("Err: AudioBlockIterator::Jump- Pointer/size mismatch\n"); exit(1); } currightblock = 0; nextrightblock = 0; nextblock = 0; nextblkofs = 0; curcnt = ofs; nextcnt = 0; } void AudioBlockIterator::GenConstants() { // Need to recompute curcnt to account for extra blocks? nframes_t tmp; GenCnt(curblock,(nframes_t) curblkofs,&tmp); curcnt = tmp; GenCnt(nextblock,(nframes_t) nextblkofs,&tmp); nextcnt = tmp; } // Moves iterator to start position void AudioBlockIterator::Zero() { currightblock = 0; nextrightblock = 0; curblock = curblock->first; curblkofs = 0; curcnt = 0; nextblock = 0; } // Advances to the next fragment void AudioBlockIterator::NextFragment() { // Only advance if not stopped if (!stopped) { // We must first get a fragment before advancing if (nextblock == 0) GetFragment(0,0); currightblock = nextrightblock; nextrightblock = 0; curblock = nextblock; curblkofs = nextblkofs; curcnt = nextcnt; nextblock = 0; // Also advance write block (if rate scaling) char ratescale = 0; if (ratescale) { currightblock_w = nextrightblock_w; nextrightblock_w = 0; curblock_w = nextblock_w; curblkofs_w = nextblkofs_w; curcnt_w = nextcnt_w; nextblock_w = 0; } } } // PutFragment stores the specified fragment into this AudioBlock // returns nonzero if the end of the block is reached, and we wrap to next int AudioBlockIterator::PutFragment (sample_t *frag_l, sample_t *frag_r, nframes_t size_override, char wait_alloc) { nframes_t fragofs = 0; nframes_t n = (size_override == 0 ? fragmentsize : size_override); int wrap = 0; char ratescale = 0; // Keep local track of pointers // Since we have to be threadsafe BED_ExtraChannel *lclrightblock; AudioBlock *lclblock; double lclblkofs, lclcnt; if (ratescale) { // Use write block lclrightblock = currightblock_w; lclblock = curblock_w; lclblkofs = curblkofs_w; lclcnt = curcnt_w; } else { // Write to read block (no scaling on read, // so same buffers can be used) lclrightblock = currightblock; lclblock = curblock; lclblkofs = curblkofs; lclcnt = curcnt; } nframes_t nextbit; do { nframes_t lclblkofs_d = (nframes_t) lclblkofs; nextbit = MIN((nframes_t) n, lclblock->len - lclblkofs_d); // Copy into block // Left memcpy(&lclblock->buf[lclblkofs_d], &frag_l[fragofs], sizeof(sample_t)*nextbit); // If right channel is given and we don't know the right block, find it if (frag_r != 0) { if (lclrightblock == 0) { lclrightblock = (BED_ExtraChannel *) lclblock->GetExtendedData(T_BED_ExtraChannel); if (lclrightblock == 0) { // No right channel exists but we are being told to put data there-- // so create a right channel! if (pre_extrachannel == 0) { printf("BLOCK: ERROR: Need to make right channel buffer but no " "preallocator was passed!\n"); return 0; } else { do { lclrightblock = (BED_ExtraChannel *) pre_extrachannel->RTNew(); if (lclrightblock == 0 && wait_alloc) { printf("BLOCK: Waiting for BED_ExtraChannel.\n"); usleep(10000); // Wait then try again } } while (lclrightblock == 0 && wait_alloc); if (lclrightblock != 0) lclblock->AddExtendedData(lclrightblock); else { printf("BLOCK: ERROR: RTNew() failed for BED_ExtraChannel.\n"); return 0; } } } } // Right memcpy(&lclrightblock->buf[lclblkofs_d], &frag_r[fragofs], sizeof(sample_t)*nextbit); } fragofs += nextbit; lclblkofs += nextbit; lclcnt += nextbit; n -= nextbit; if (lclblkofs >= lclblock->len) { // If we get here, it means this block has been fully dumped // so we need the next block wrap = 1; if (lclblock->next == 0) { // END OF AUDIOBLOCK LIST, LOOP TO BEGINNING lclblock = lclblock->first; lclblkofs = 0; lclcnt = lclblkofs; lclrightblock = 0; } else { lclblock = lclblock->next; lclblkofs = 0; lclrightblock = 0; } } } while (n); if (ratescale) { nextblock_w = lclblock; nextrightblock_w = lclrightblock; nextblkofs_w = lclblkofs; nextcnt_w = lclcnt; } else { nextblock = lclblock; nextrightblock = lclrightblock; nextblkofs = lclblkofs; nextcnt = lclcnt; } return wrap; } // Returns the current fragment of audio // nextblock and nextblkofs become the new block pointer and offset // for the next fragment void AudioBlockIterator::GetFragment(sample_t **frag_l, sample_t **frag_r) { // Keep local track of pointers // Since we have to be threadsafe BED_ExtraChannel *lclrightblock = currightblock; AudioBlock *lclblock = curblock; double lclblkofs = curblkofs, lclcnt = curcnt; char ratescale = 0; float rate = 2.0; if (ratescale) { double n = fragmentsize*rate; if (lclblkofs + n + 1 >= lclblock->len) { // Wrap happens here- check bounds in loop for (nframes_t cnt = 0; cnt < fragmentsize; cnt++) { // Linear interpolation rate scale nframes_t decofs = (nframes_t) lclblkofs; float fracofs = lclblkofs - decofs; if (frag_r != 0) { if (lclrightblock == 0) { lclrightblock = (BED_ExtraChannel *) lclblock->GetExtendedData(T_BED_ExtraChannel); if (lclrightblock == 0) { // No right channel exists but we are being told to get data-- printf("BLOCK: ERROR: Iterator asked for right channel but none " "exists!\n"); return; } } } sample_t s1 = lclblock->buf[decofs], s2, s1r, s2r; if (frag_r != 0) s1r = lclrightblock->buf[decofs]; nframes_t decofs_p1 = decofs+1; if (decofs_p1 < lclblock->len) { s2 = lclblock->buf[decofs_p1]; if (frag_r != 0) s2r = lclrightblock->buf[decofs_p1]; } else { AudioBlock *next_b; if (lclblock->next != 0) next_b = lclblock->next; else next_b = lclblock->first; s2 = next_b->buf[0]; if (frag_r != 0) { BED_ExtraChannel *tmp_r = (BED_ExtraChannel *) next_b->GetExtendedData(T_BED_ExtraChannel); if (tmp_r != 0) s2r = tmp_r->buf[0]; else s2r = s1r; } } float fracofs_om = 1.0-fracofs; fragment[0][cnt] = fracofs*s2 + fracofs_om*s1; if (frag_r != 0) fragment[1][cnt] = fracofs*s2r + fracofs_om*s1r; lclblkofs += rate; lclcnt += rate; if (lclblkofs >= lclblock->len) { // If we get here, it means this block is at an end // so we need the next block lclblkofs -= lclblock->len; if (lclblock->next == 0) { // END OF AUDIOBLOCK LIST, LOOP TO BEGINNING lclcnt = lclblkofs; lclblock = lclblock->first; lclrightblock = 0; } else { lclblock = lclblock->next; lclrightblock = 0; } } } } else { // No wrap- don't check bounds for (nframes_t cnt = 0; cnt < fragmentsize; cnt++, lclblkofs += rate, lclcnt += rate) { // Linear interpolation rate scale nframes_t decofs = (nframes_t) lclblkofs; float fracofs = lclblkofs - decofs; if (frag_r != 0) { if (lclrightblock == 0) { lclrightblock = (BED_ExtraChannel *) lclblock->GetExtendedData(T_BED_ExtraChannel); if (lclrightblock == 0) { // No right channel exists but we are being told to get data-- printf("BLOCK: ERROR: Iterator asked for right channel but none " "exists!\n"); return; } } } nframes_t decofs_p1 = decofs+1; sample_t s1 = lclblock->buf[decofs], s2 = lclblock->buf[decofs_p1]; float fracofs_om = 1.0-fracofs; fragment[0][cnt] = fracofs*s2 + fracofs_om*s1; if (frag_r != 0) { sample_t s1r = lclrightblock->buf[decofs], s2r = lclrightblock->buf[decofs_p1]; fragment[1][cnt] = fracofs*s2r + fracofs_om*s1r; } } } } else { // No rate scale nframes_t fragofs = 0; nframes_t n = fragmentsize; nframes_t nextbit; do { nframes_t lclblkofs_d = (nframes_t) lclblkofs; nextbit = MIN((nframes_t) n, lclblock->len - lclblkofs_d); if (nextbit) { // Left memcpy(&fragment[0][fragofs], &lclblock->buf[lclblkofs_d], sizeof(sample_t)*nextbit); // If right channel is given and we don't know the right block, find it if (frag_r != 0) { if (lclrightblock == 0) { lclrightblock = (BED_ExtraChannel *) lclblock->GetExtendedData(T_BED_ExtraChannel); if (lclrightblock == 0) { // No right channel exists but we are being told to get data-- printf("BLOCK: ERROR: Iterator asked for right channel but none " "exists!\n"); return; } } // Right memcpy(&fragment[1][fragofs], &lclrightblock->buf[lclblkofs_d], sizeof(sample_t)*nextbit); } else // Make -sure- we don't jump blocks and keep old rightblock lclrightblock = 0; fragofs += nextbit; lclblkofs += nextbit; lclcnt += nextbit; n -= nextbit; } if (lclblkofs >= lclblock->len) { // If we get here, it means this block is at an end // so we need the next block if (lclblock->next == 0) { // END OF AUDIOBLOCK LIST, LOOP TO BEGINNING lclblock = lclblock->first; lclblkofs = 0; lclcnt = lclblkofs; lclrightblock = 0; } else { lclblock = lclblock->next; lclblkofs = 0; // Beginning of next block lclrightblock = 0; } } } while (n); } nextblock = lclblock; nextrightblock = lclrightblock; nextblkofs = lclblkofs; nextcnt = lclcnt; // Return fragment buffers if (frag_l != 0) *frag_l = fragment[0]; if (frag_r != 0) *frag_r = fragment[1]; }; // RT safe void AudioBlockIterator::EndChain() { // Mark iterator stopped stopped = 1; //printf("Crop: %ld to %ld\n", curblock->len, curblkofs); if (curblkofs < (nframes_t) fragmentsize) { //printf("WARNING: REALLY SHORT BLOCK: %d\n",curblkofs); curblock->len = fragmentsize; } else curblock->len = (nframes_t) curblkofs; // Stop the chain at this place curblock->ChopChain(); } int GrowChainManager::Manage() { // Manage chain growth if (!i->IsStopped()) if (i->GetCurBlock()->next == 0) { // Iterator is running and no more blocks at the end // of this chain! Get another and link it up. AudioBlock *nw = (AudioBlock *) i->GetCurBlock()->RTNew(); if (nw == 0) { printf("GrowChainManager: ERROR: No free blocks to grow chain\n"); return 0; } i->GetCurBlock()->Link(nw); // Second channel allocating is done as needed by PutFragment // in the iterator } return 0; }; void PeaksAvgsManager::Setup() { // Setup iterators pa = (BED_PeaksAvgs *)(b->GetExtendedData(T_BED_PeaksAvgs)); // To do: Optimize this to bypass iterator- // it would be faster since we are moving one sample at a time! peaksi = new AudioBlockIterator(pa->peaks,1); avgsi = new AudioBlockIterator(pa->avgs,1); mi = new AudioBlockIterator(b,1); stereo = b->IsStereo(); if (grow) { // Grow peaks & avgs blocks bmg->GrowChainOn(pa->peaks,peaksi); bmg->GrowChainOn(pa->avgs,avgsi); } }; PeaksAvgsManager::~PeaksAvgsManager() { if (bmg != 0) { End(); delete peaksi; delete avgsi; delete mi; } }; void PeaksAvgsManager::End() { if (!ended) { ended = 1; if (grow) { // End chain at current pos! peaksi->EndChain(); avgsi->EndChain(); bmg->GrowChainOff(pa->peaks); bmg->GrowChainOff(pa->avgs); } } } int PeaksAvgsManager::Manage() { // Stop if ended.. if (ended) return 1; // Compute running peaks and averages char wrap; do { wrap = 0; // Get current position in iterator nframes_t curcnt = i->GetTotalLength2Cur(); if (curcnt < lastcnt) { // We have a wrap condition!- loop // printf("Wrap! Now at: %ld\n",curcnt); curcnt = b->GetTotalLen(); wrap = 1; } // Update peaks & averages to current position while (lastcnt < curcnt) { sample_t *sptr[2]; sample_t s_l, s_r; if (stereo) { mi->GetFragment(&sptr[0],&sptr[1]); s_l = *sptr[0]; s_r = *sptr[1]; } else { mi->GetFragment(&sptr[0],0); s_l = *sptr[0]; s_r = 0; } // If chunkcnt is -1, we have temporarily stopped until a wrap if (go) { if (s_l > runmax) runmax = s_l; if (s_l < runmin) runmin = s_l; if (stereo) { if (s_r > runmax) runmax = s_r; if (s_r < runmin) runmin = s_r; runtally += (fabs(s_l)+fabs(s_r))/2; } else runtally += fabs(s_l); chunkcnt++; if (chunkcnt >= pa->chunksize) { // One chunk done sample_t peak = runmax-runmin, avg = (sample_t) (runtally/pa->chunksize); if (peaksi->PutFragment(&peak,0) || avgsi->PutFragment(&avg,0)) { // Peaks should not be wrapping before main buf, stop! // // Note that this does happen!! go = 0; } else { peaksi->NextFragment(); avgsi->NextFragment(); chunkcnt = 0; } runtally = 0; runmax = 0; runmin = 0; } } mi->NextFragment(); lastcnt++; } if (wrap) { /* printf("Main wrap!: MI: %ld PI: %ld AI: %ld\n", mi->GetTotalLength2Cur(), peaksi->GetTotalLength2Cur(), avgsi->GetTotalLength2Cur()); */ mi->Zero(); peaksi->Zero(); avgsi->Zero(); lastcnt = 0; // Wrap to beginning, and do the samples there go = 1; chunkcnt = 0; runtally = 0; runmax = 0; runmin = 0; } } while (wrap); return 0; }; void StripeBlockManager::Setup() { // Does this block have BED_MarkerPoints? mp = (BED_MarkerPoints *)(b->GetExtendedData(T_BED_MarkerPoints)); if (mp == 0) { // No marker block b->AddExtendedData(mp = new BED_MarkerPoints()); } }; int StripeBlockManager::Manage() { // This is called whenever a time marker should be striped // to the block char wrap = 0; do { if (wrap) wrap = 2; // Special case if we just wrapped and are on a 2nd pass else wrap = 0; // Get current iterated offset into block nframes_t curcnt = i->GetTotalLength2Cur(); if (curcnt < lastcnt) { // We have a wrap condition!- loop // printf("Wrap! Now at: %ld\n",curcnt); curcnt = b->GetTotalLen(); wrap = 1; } // Scan through time markers for a good place to insert a new one TimeMarker *cur = mp->markers, *prev = 0; if (wrap == 2) { // On 2nd pass, delete markers at 0. wrap = 0; while (cur != 0 && cur->markofs < lastcnt) { prev = cur; cur = cur->next; } } else { while (cur != 0 && cur->markofs <= lastcnt) { prev = cur; cur = cur->next; } } // Delete any markers between last position & current while (cur != 0 && cur->markofs <= curcnt) { TimeMarker *tmp = cur->next; cur->RTDelete(); cur = tmp; if (prev != 0) prev->next = cur; else mp->markers = cur; } if (!wrap) { // Now insert a new marker in this position // Use realtime new method- no problem TimeMarker *nw = (TimeMarker *) pre_tm->RTNew(); if (nw == 0) { printf("StripeBlockManager: ERROR: No free TimeMarkers\n"); return 0; } nw->markofs = curcnt; nw->next = cur; if (prev != 0) prev->next = nw; else mp->markers = nw; // Update counters lastcnt = curcnt; } else lastcnt = 0; // Start again from beginning to curcnt } while (wrap); return 0; }; BlockManager::BlockManager (Fweelin *app) : manageblocks(0), himanageblocks(0), threadgo(1), app(app) { pre_growchain = new PreallocatedType(app->getMMG(), ::new GrowChainManager(), sizeof(GrowChainManager)); pre_peaksavgs = new PreallocatedType(app->getMMG(), ::new PeaksAvgsManager(), sizeof(PeaksAvgsManager)); pre_hipri = new PreallocatedType(app->getMMG(), ::new HiPriManagedChain(), sizeof(HiPriManagedChain)); pre_stripeblock = new PreallocatedType(app->getMMG(), ::new StripeBlockManager(), sizeof(StripeBlockManager)); pthread_mutex_init(&manage_thread_lock,0); const static size_t STACKSIZE = 1024*128; pthread_attr_t attr; pthread_attr_init(&attr); pthread_attr_setstacksize(&attr,STACKSIZE); printf("BLOCK: Stacksize: %zd.\n",STACKSIZE); // Start a block managing thread int ret = pthread_create(&manage_thread, &attr, run_manage_thread, static_cast(this)); if (ret != 0) { printf("(blockmanager) pthread_create failed, exiting"); exit(1); } RT_RWThreads::RegisterReaderOrWriter(manage_thread); struct sched_param schp; memset(&schp, 0, sizeof(schp)); // Manage thread calls delete- can't be SCHED_FIFO schp.sched_priority = sched_get_priority_max(SCHED_OTHER); // schp.sched_priority = sched_get_priority_min(SCHED_FIFO); if (pthread_setschedparam(manage_thread, SCHED_OTHER, &schp) != 0) { printf("BLOCK: Can't set realtime thread, will use nonRT!\n"); } } BlockManager::~BlockManager () { // Terminate the management thread threadgo = 0; pthread_join(manage_thread,0); pthread_mutex_destroy (&manage_thread_lock); delete pre_growchain; delete pre_peaksavgs; delete pre_hipri; delete pre_stripeblock; } // Turns on automatic allocation of new blocks at the end of the // specified chain. We work in conjunction with the specified iterator, // so that when the iterator approaches the end of the block chain, // the chain grows automatically void BlockManager::GrowChainOn (AudioBlock *b, AudioBlockIterator *i) { // Check if the block is already being watched DelManager(&manageblocks,b,T_MC_GrowChain); // Tell the manage thread to grow this chain GrowChainManager *nw = (GrowChainManager *) pre_growchain->RTNewWithWait(); nw->b = b; nw->i = i; AddManager(&manageblocks,nw); } void BlockManager::GrowChainOff (AudioBlock *b) { DelManager(&manageblocks,b,T_MC_GrowChain); } // Turns on computation of running sample peaks and averages // for the specified Block & Iterator // We compute as the currenty iterated position advances PeaksAvgsManager *BlockManager::PeakAvgOn (AudioBlock *b, AudioBlockIterator *i, char grow) { // Check if the block is already being watched DelManager(&manageblocks,b,T_MC_PeaksAvgs); // Tell the manage thread to compute peaks & averages PeaksAvgsManager *nw = (PeaksAvgsManager *) pre_peaksavgs->RTNewWithWait(); nw->bmg = this; nw->b = b; nw->i = i; nw->grow = grow; nw->Setup(); AddManager(&manageblocks,nw); return nw; } void BlockManager::PeakAvgOff (AudioBlock *b) { DelManager(&manageblocks,b,T_MC_PeaksAvgs); } void BlockManager::StripeBlockOn (void *trigger, AudioBlock *b, AudioBlockIterator *i) { // Check if the block is already being watched DelHiManager(&himanageblocks,b,T_MC_StripeBlock,trigger); // Tell the manage thread to stripe beats on blocks StripeBlockManager *nw = (StripeBlockManager *) pre_stripeblock-> RTNewWithWait(); nw->pre_tm = app->getPRE_TIMEMARKER(); nw->b = b; nw->i = i; nw->trigger = trigger; nw->Setup(); AddHiManager(&himanageblocks,nw); } void BlockManager::StripeBlockOff (void *trigger, AudioBlock *b) { DelHiManager(&himanageblocks,b,T_MC_StripeBlock,trigger); } // Generic delete/add functions for managers (not hipri) void BlockManager::DelManager (ManagedChain *m) { DelManager(&manageblocks,m); }; void BlockManager::AddManager (ManagedChain *nw) { AddManager(&manageblocks,nw); }; void BlockManager::DelManager (ManagedChain **first, ManagedChain *m) { ManagedChain *cur = *first; // Search for manager 'm' in our list while (cur != 0 && (cur != m || cur->status == T_MC_PendingDelete)) cur = cur->next; if (cur != 0) // Flag for deletion cur->status = T_MC_PendingDelete; }; void BlockManager::RefDeleted (ManagedChain **first, void *ref) { ManagedChain *cur = *first; while (cur != 0) { if (cur->status == T_MC_Running && cur->RefDeleted(ref)) // Flag for deletion cur->status = T_MC_PendingDelete; // Next chain cur = cur->next; } } void BlockManager::HiRefDeleted (HiPriManagedChain **first, void *ref) { HiPriManagedChain *cur = *first; while (cur != 0) { if (cur->status == T_MC_Running && cur->RefDeleted(ref)) // Flag for deletion cur->status = T_MC_PendingDelete; // Next chain cur = (HiPriManagedChain *) cur->next; } } // Notify all Managers that the object pointed to has been deleted- // To avoid broken dependencies void BlockManager::RefDeleted (void *ref) { RefDeleted(&manageblocks,ref); HiRefDeleted(&himanageblocks,ref); } // Activate a hipriority trigger- all hiprimanagedchains with // specified trigger pointer will have manage() method called // Safe to call in realtime! void BlockManager::HiPriTrigger (void *trigger) { HiPriManagedChain *cur = himanageblocks; //printf("HIPRITRIG: %ld\n", mgrcnt); cur = himanageblocks; while (cur != 0) { if (cur->status == T_MC_Running && (cur->trigger == trigger || cur->trigger == 0)) // Ok, right trigger or no trigger specified, call 'em! if (cur->Manage()) // Flag for delete cur->status = T_MC_PendingDelete; // Next chain cur = (HiPriManagedChain *) cur->next; } } // Returns the 1st chain manager associated with block b // that has type t ManagedChain *BlockManager::GetBlockManager(AudioBlock *o, ManagedChainType t) { ManagedChain *cur = manageblocks; // Search for block 'o' && type t in our list while (cur != 0 && (cur->status == T_MC_PendingDelete || cur->b != o || cur->GetType() != t)) cur = cur->next; return cur; }; void BlockManager::AddManager (ManagedChain **first, ManagedChain *nw) { nw->status = T_MC_Running; // Possibility of priority inversion if AddManager is run in RT, // because non-RT manage thread also locks here. So far, AddManager shouldn't // be run in RT if (pthread_mutex_trylock (&manage_thread_lock) == 0) { ManagedChain *cur = *first; if (cur == 0) *first = nw; // That was easy, now we have 1 item else { while (cur->next != 0) cur = cur->next; cur->next = nw; // Link up the last item to new1 } pthread_mutex_unlock (&manage_thread_lock); } else // Priority inversion printf("BLOCK: WARNING: Priority inversion during AddManager\n"); } void BlockManager::AddHiManager (HiPriManagedChain **first, HiPriManagedChain *nw) { nw->status = T_MC_Running; // Possibility of priority inversion if AddHiManager is run in RT, // because non-RT manage thread also locks here. // So far, AddHiManager shouldn't be run in RT if (pthread_mutex_trylock (&manage_thread_lock) == 0) { HiPriManagedChain *cur = *first; if (cur == 0) *first = nw; // That was easy, now we have 1 item else { while (cur->next != 0) cur = (HiPriManagedChain *) cur->next; cur->next = nw; // Link up the last item to new1 } pthread_mutex_unlock (&manage_thread_lock); } else // Priority inversion printf("BLOCK: WARNING: Priority inversion during AddHiManager\n"); } // Delete a managed chain for block o and manager type t // If t is T_MC_None, removes the first managed chain for 'o' // of any type void BlockManager::DelManager (ManagedChain **first, AudioBlock *o, ManagedChainType t) { ManagedChain *cur = *first; // Search for block 'o' in our list of type 't' while (cur != 0 && (cur->status == T_MC_PendingDelete || cur->b != o || (cur->GetType() != t && t != T_MC_None))) cur = cur->next; if (cur != 0) // Flag for deletion cur->status = T_MC_PendingDelete; } // Delete a hiprimanaged chain for block o and manager type t // with specified trigger. // If t is T_MC_None, removes the first managed chain for 'o' // with specified trigger, of any type void BlockManager::DelHiManager (HiPriManagedChain **first, AudioBlock *o, ManagedChainType t, void *trigger) { HiPriManagedChain *cur = *first; // Search for block 'o' in our list of type 't' while (cur != 0 && (cur->status == T_MC_PendingDelete || cur->b != o || cur->trigger != trigger || (cur->GetType() != t && t != T_MC_None))) cur = (HiPriManagedChain *) cur->next; if (cur != 0) // Flag for deletion cur->status = T_MC_PendingDelete; } void *BlockManager::run_manage_thread (void *ptr) { BlockManager *inst = static_cast(ptr); while (inst->threadgo) { // Manage the blocks we have ManagedChain *cur = inst->manageblocks; while (cur != 0) { if (cur->status == T_MC_Running) if (cur->Manage()) // Flag for deletion cur->status = T_MC_PendingDelete; // Next chain cur = cur->next; } // Delete managers cur = inst->manageblocks; ManagedChain *prev = 0; while (cur != 0) { if (cur->status == T_MC_PendingDelete) { // printf("MGR %p DELETE\n",cur); // Remove chain pthread_mutex_lock (&inst->manage_thread_lock); ManagedChain *tmp = cur->next; if (prev != 0) prev->next = tmp; else inst->manageblocks = tmp; pthread_mutex_unlock (&inst->manage_thread_lock); //printf("end mgr\n"); cur->RTDelete(); cur = tmp; } else { // Next chain prev = cur; cur = cur->next; } } HiPriManagedChain *hcur = inst->himanageblocks, *hprev = 0; while (hcur != 0) { if (hcur->status == T_MC_PendingDelete) { // printf("HI-MGR %p DELETE\n",hcur); // Remove chain pthread_mutex_lock (&inst->manage_thread_lock); HiPriManagedChain *tmp = (HiPriManagedChain *) hcur->next; if (hprev != 0) hprev->next = tmp; else inst->himanageblocks = tmp; pthread_mutex_unlock (&inst->manage_thread_lock); //printf("end mgr\n"); hcur->RTDelete(); hcur = tmp; } else { // Next chain hprev = hcur; hcur = (HiPriManagedChain *) hcur->next; } } // Produce status report? FloConfig *fs = inst->app->getCFG(); if (fs->status_report == FS_REPORT_BLOCKMANAGER) { fs->status_report++; printf("BLOCKMANAGER REPORT:\n"); ManagedChain *cur = inst->manageblocks; while (cur != 0) { printf(" bmg mgr: type(%d) status(%d)\n",cur->GetType(),cur->status); cur = cur->next; } cur = inst->himanageblocks; while (cur != 0) { printf(" bmg HiPrimgr: type(%d) status(%d)\n",cur->GetType(), cur->status); cur = cur->next; } } // 10 ms delay between management tasks usleep(10000); } // Delete all blockmanagers now ManagedChain *cur = inst->manageblocks; while (cur != 0) { ManagedChain *tmp = cur->next; cur->RTDelete(); cur = tmp; } cur = inst->himanageblocks; while (cur != 0) { ManagedChain *tmp = cur->next; cur->RTDelete(); cur = tmp; } return 0; } freewheeling-0.6.6/src/fweelin_block.h000066400000000000000000001001311370736313100177320ustar00rootroot00000000000000#ifndef __FWEELIN_BLOCK_H #define __FWEELIN_BLOCK_H /* Copyright 2004-2011 Jan Pekau This file is part of Freewheeling. Freewheeling is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. Freewheeling 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 Freewheeling. If not, see . */ #include #include #include #ifdef __MACOSX__ #include #else #include #endif #include "fweelin_audioio.h" #include "fweelin_mem.h" #include "fweelin_event.h" // Types of audio codecs supported typedef enum { UNKNOWN = -1, FIRST_FORMAT = 0, VORBIS = 0, WAV = 1, FLAC = 2, AU = 3, END_OF_FORMATS = 4 } codec; #ifndef MIN #define MIN(a,b) ((a) < (b) ? (a) : (b)) #endif #ifndef MAX #define MAX(a,b) ((a) > (b) ? (a) : (b)) #endif class Fweelin; class Loop; class AudioBlock; class BlockManager; class PeaksAvgsManager; // A list of all block extended data types // Used as a kind of RTTI for getting BED of a certain type at runtime enum BlockExtendedDataType { T_BED_None, T_BED_ExtraChannel, T_BED_PeaksAvgs, T_BED_MarkerPoints }; class BlockExtendedData { public: BlockExtendedData() : next(0) {}; BlockExtendedData(BlockExtendedData *prev) : next(0) { prev->next = this; }; virtual ~BlockExtendedData() {}; virtual BlockExtendedDataType GetType() { return T_BED_None; }; // Pointer to next bit of extended data in list BlockExtendedData *next; }; // A type of block extended data that allows // peaks & averages across audioblocks to be stored inside them. // Used for things like scope computations which are autocalculated // and stored inside blocks as BED_PeaksAvgs class BED_PeaksAvgs : public BlockExtendedData { public: BED_PeaksAvgs(AudioBlock *peaks, AudioBlock *avgs, nframes_t chunksize) : peaks(peaks), avgs(avgs), chunksize(chunksize) {}; ~BED_PeaksAvgs(); virtual BlockExtendedDataType GetType() { return T_BED_PeaksAvgs; }; // Peaks & averages AudioBlock *peaks, *avgs; // Chunk size across which peaks & averages are computed // Length of peaks & avgs blocks = length of parent block / chunksize nframes_t chunksize; }; class TimeMarker : public Preallocated { public: TimeMarker(nframes_t markofs = 0, long data = 0) : markofs(markofs), data(data), next(0) {}; // FWMEM_DEFINE_DELBLOCK; virtual void Recycle() { markofs = 0; data = 0; next = 0; }; // Block mode allocate /* virtual Preallocated *NewInstance() { return ::new TimeMarker[GetMgr()->GetBlockSize()]; }; */ virtual Preallocated *NewInstance() { return ::new TimeMarker(); }; nframes_t markofs; // Marker position measured in samples long data; // Unspecified extra data (use as req'd) TimeMarker *next; // Next time marker }; // A type of block extended data that stores time markers into a block class BED_MarkerPoints : public BlockExtendedData { public: BED_MarkerPoints() : markers(0) {}; ~BED_MarkerPoints(); virtual BlockExtendedDataType GetType() { return T_BED_MarkerPoints; }; int CountMarkers(); // Returns the nth marker before (in time) the current offset passed // This method correctly handles a reverse wrap case when the // marker NBeforeCur is farther ahead in the attached block than the // current offset TimeMarker *GetMarkerNBeforeCur(int n, nframes_t curofs); TimeMarker *markers; }; class AudioBlock : public Preallocated { public: // Default length of new audio blocks (samples) static const nframes_t AUDIOBLOCK_DEFAULT_LEN = 20000, AUDIOBLOCK_SMOOTH_ENDPOINTS_LEN = 64; // Create a new audioblock as the beginning of a block list AudioBlock(nframes_t len = AUDIOBLOCK_DEFAULT_LEN); // Create a new audioblock and link up the specified block to it AudioBlock(AudioBlock *prev, nframes_t len); virtual ~AudioBlock(); virtual Preallocated *NewInstance() { return ::new AudioBlock(); }; // Is this block stereo? (does it have a BED_ExtraChannel attached?) inline char IsStereo() { return (GetExtendedData(T_BED_ExtraChannel) != 0); }; // Link us up to the specified block void Link(AudioBlock *to); // Clears this block chain- not changing length void Zero(); // Erases any blocks in the chain after this block- this one // becomes the last void ChopChain(); // Smooth an audio chain- // either smooth the beginning into the end (smoothtype == 1) // or smooth the end into the beginning (smoothtype == 0) void Smooth(char smoothtype = 1, nframes_t smoothlen = AUDIOBLOCK_SMOOTH_ENDPOINTS_LEN); // Erases this whole audioblock chain from first to last // Also erases any extended data! // RT safe void DeleteChain(); // Returns the total length of this audio chain nframes_t GetTotalLen(); // Gets extended data for this block BlockExtendedData *GetExtendedData(BlockExtendedDataType x); // Add this extended data to the list of extended data for this block void AddExtendedData(BlockExtendedData *nw); // Finds the audioblock and offset into that block that correspond // to the provided absolute offset into this chain void SetPtrsFromAbsOffset(AudioBlock **ptr, nframes_t *blkofs, nframes_t absofs); // Generates a subchain of AudioBlocks by copying the samples between offsets // from & to.. offsets expressed absolutely with reference to // beginning of this chain! // Samples are copied up to but not including toofs // If toofs < fromofs, generates a subblock that includes the end of // the block and the beginning up to toofs (wrap case) // Realtime safe? AudioBlock *GenerateSubChain(nframes_t fromofs, nframes_t toofs, char copystereo); // Removes the last 'hacklen' samples from this block chain // Returns nonzero on error! // Not realtime safe! int HackTotalLengthBy(nframes_t hacklen); // Inserts the new block at the beginning of this block chain // Returns a pointer to the new first block AudioBlock *InsertFirst(AudioBlock *nw); sample_t *buf, // Samples for block- this pointer can be adjusted if the // block is shortened as in Smooth() *origbuf; // Original unmodified sample pointer nframes_t len; // Length of block AudioBlock *next, // Next block *first; // First block in chain // Extended data list for this block BlockExtendedData *xt; }; // A type of block extended data that allows // an extra channel of audio to be attached to an audioblock // Used for stereo loops class BED_ExtraChannel : public Preallocated, public BlockExtendedData { public: BED_ExtraChannel(nframes_t len = AudioBlock::AUDIOBLOCK_DEFAULT_LEN); virtual ~BED_ExtraChannel(); virtual Preallocated *NewInstance() { return ::new BED_ExtraChannel(); }; virtual BlockExtendedDataType GetType() { return T_BED_ExtraChannel; }; // Sample data for extra channel- each stereo block must have an instance // of BED_ExtraChannel with a sample buffer that matches length with // the parent AudioBlock sample_t *buf, // This pointer can be adjusted in Smooth() *origbuf; // Original unmodified sample pointer }; // Iterator for storing/extracting data in audio blocks. // Freewheeling stores audio in small blocks, which are linked together // in a chain. // // The main functions for iteration are GetFragment (retrieves an audio // fragment from block(s)), PutFragment (stores an audio fragment into // block(s)), and NextFragment (advances the iterator). // // The iterator can also perform rate scaling. // // When rate scaling, the iterator writes to a different block chain than // it reads from. The chain can then grow/shrink as the rate scaling // changes. class AudioBlockIterator /*: public Elastin_SampleFeed*/ { public: // Optionally pass preallocatedtype for extrachannel if you want // extra channels to be added as needed when putting fragments AudioBlockIterator(AudioBlock *firstblock, nframes_t fragmentsize, PreallocatedType *pre_extrachannel = 0); ~AudioBlockIterator(); inline float round(float num) { if (num-(long)num < 0.5) return floor(num); else return ceil(num); } // Stores in cnt the absolute count corresponding to the given // block and offset void GenCnt(AudioBlock *blk, nframes_t blkofs, nframes_t *cnt); void GenConstants(); // Moves iterator to start position void Zero(); // Advances to the next fragment void NextFragment(); // Jumps to an absolute offset within the blockchain void Jump(nframes_t ofs); // PutFragment stores the specified fragment back into this AudioBlock // (optional right channel) // Returns nonzero if the end of the block is reached, and we wrap to next // Optional size_override puts a different size fragment into the block- // any size can be put so long as the chain is long enough // Optional wait_alloc waits for allocation of new extra channels if needed // (don't use this flag in RT!) // If rate scaling is active, the iterator always writes to a new // block, because the length of the newly stored sample may be // different than the length of the original (see 'write block' // variables). No scaling is done in PutFragment, just a choice of // which block chain to write to int PutFragment (sample_t *frag_l, sample_t *frag_r, nframes_t size_override = 0, char wait_alloc = 0); // Returns the current fragment of audio // Points frag_l and frag_r buffers to the current fragment // frag_r is optional // nextblock and nextblkofs become the new block pointer and offset // for the next fragment void GetFragment(sample_t **frag_l, sample_t **frag_r); // Adjusts the block chain so that the current iterator position // becomes the new end of the chain void EndChain(); inline nframes_t GetTotalLength2Cur() { return (nframes_t) curcnt; } inline char IsStopped() { return stopped; }; inline void Stop() { stopped = 1; }; // Returns the block currently being iterated through inline AudioBlock *GetCurBlock() { return curblock; }; private: // Optional right audio channel for the block we are iterating PreallocatedType *pre_extrachannel; // Preallocator for 2nd channel blocks BED_ExtraChannel *currightblock, *nextrightblock, // Values for write block *currightblock_w, *nextrightblock_w; AudioBlock *curblock, *nextblock, // Values for write block *curblock_w, *nextblock_w; double curblkofs, // Use doubles for position (rate scale needs them) nextblkofs, curcnt, nextcnt, // Values for write block curblkofs_w, nextblkofs_w, curcnt_w, nextcnt_w; // Buffers for storing smaller fragments from within AudioBlocks nframes_t fragmentsize; sample_t *fragment[2]; char stopped; // Nonzero if this iterator is stopped }; // List of all types of chain managers enum ManagedChainType { T_MC_None, T_MC_GrowChain, T_MC_PeaksAvgs, T_MC_BlockRead, T_MC_BlockWrite, T_MC_HiPri, T_MC_StripeBlock }; // Status of managed chain enum ManagedChainStatus { T_MC_Running, T_MC_PendingDelete }; // Generic class specifying a chain of blocks & iterator to manage // Management happens when blockmanager periodically calls // the Manage() method for all managed chains. // Different types of manager classes do different management tasks // with blocks. class ManagedChain : public Preallocated { public: ManagedChain(AudioBlock *b = 0, AudioBlockIterator *i = 0) : b(b), i(i), next(0) {}; virtual ~ManagedChain() {}; virtual Preallocated *NewInstance() { return ::new ManagedChain(); }; // Called periodically to manage a block // Return zero to proceed normally // Return nonzero to delete this manager virtual int Manage() { return 0; }; // This method is called whenever an object (ref) is deleted // that Managed Chains might want to know about. For example, // RootProcessor notifies BlockManager whenever child processors // are deleted. This allows ManagedChains to react, if they depend // on the deleted object. If we return nonzero, this manager is // deleted. virtual int RefDeleted(void *ref) { if (ref == b || ref == i) // Block or iterator gone!! End this manager! return 1; else return 0; }; virtual ManagedChainType GetType() { return T_MC_None; }; AudioBlock *b; AudioBlockIterator *i; ManagedChainStatus status; ManagedChain *next; }; // GrowChainManager periodically grows a block chain so that the // iterator i never reaches its end-- good for unlimited length records class GrowChainManager : public ManagedChain { public: GrowChainManager(AudioBlock *b = 0, AudioBlockIterator *i = 0) : ManagedChain(b,i) {}; virtual Preallocated *NewInstance() { return ::new GrowChainManager(); }; virtual ManagedChainType GetType() { return T_MC_GrowChain; }; virtual int Manage(); }; // Base class for different types of file encoders class iFileEncoder { public: iFileEncoder (Fweelin *app, char stereo); virtual ~iFileEncoder() {}; // Tell the encoder to dump to this file we have just opened // This writes the files header information // Returns nonzero on error. virtual int SetupFileForWriting (FILE *file) = 0; // Get the samples from the relevant buffer (ibuf) and write them to file, // (startframe) tells us what index to start copying from the input buffer, // (numframes) tells us how many frames to encode. // Returns the number of frames written. virtual long int WriteSamplesToDisk (sample_t **ibuf, nframes_t startframe, nframes_t numframes) = 0; // Stop encoding and finish up- but don't close output file! virtual void PrepareFileForClosing () = 0; // Vorbis in particular needs to a bit of scaling down to avoid clipping... // any simular processing should be put here virtual void Preprocess (sample_t *l, sample_t *r, nframes_t len) = 0; inline char IsStereo() { return stereo; }; protected: Fweelin *app; char stereo; FILE *outfd; }; class SndFileEncoder : public iFileEncoder { public: // Encoder for libSndfile formats- at the moment, WAV, AU and FLAC. // Maxframes is maximum number of frames to write in one call to // WriteSamplesToDisk // Codec type is one of those values. // We also specify wether we are using Mono or Stereo Encoding SndFileEncoder (Fweelin *app, nframes_t maxframes, char stereo, codec type); ~SndFileEncoder() { if (tbuf != 0) delete[] tbuf; }; int SetupFileForWriting (FILE *file); long int WriteSamplesToDisk (sample_t **ibuf, nframes_t startframe, nframes_t numframes); void PrepareFileForClosing (void); void Preprocess (sample_t */*left*/, sample_t */*right*/, nframes_t /*n_frames*/) {}; private: codec filetype; int samplesize; SF_INFO sfinfo; SNDFILE *sndoutfd; float *tbuf; // Temporary audio buffer for saving }; class VorbisEncoder : public iFileEncoder { public: // Vorbis encoder library init/end are done in constructor/destructor // We specify stereo or mono encoding VorbisEncoder (Fweelin *app, char stereo); virtual ~VorbisEncoder(); int SetupFileForWriting (FILE *file); long int WriteSamplesToDisk (sample_t **ibuf, nframes_t startframe, nframes_t numframes); void PrepareFileForClosing (void) { // Tell vorbis we are done with the stream vorbis_analysis_wrote(&vd,0); // Encode any remaining stuff Encode(); }; void Preprocess (sample_t *l, sample_t *r, nframes_t len); private: // Returns vorbis encoder's analysis buffers for len frames // Depending on mono/stereo it is an array of 1/2 by len samples float **GetAnalysisBuffer(nframes_t len) { return vorbis_analysis_buffer(&vd,len); }; // Tell vorbis we wrote some samples to its analysis buffer void WroteToBuffer(nframes_t len) { vorbis_analysis_wrote(&vd,len); }; // Runs the encoder, returns number of bytes written long int Encode(); // Vorbis encoder stuff ogg_stream_state os; /* take physical pages, weld into a logical stream of packets */ ogg_page og; /* one Ogg bitstream page. Vorbis packets are inside */ ogg_packet op; /* one raw packet of data for decode */ vorbis_info vi; /* struct that stores all the static vorbis bitstream settings */ vorbis_comment vc; /* struct that stores all the user comments */ vorbis_dsp_state vd; /* central working state for the packet->PCM decoder */ vorbis_block vb; /* local working space for packet->PCM decode */ }; class iFileDecoder { public: iFileDecoder (Fweelin *app); virtual ~iFileDecoder () {}; // Tell the decoder to decode from a given file // This reads the files header virtual int ReadFromFile(FILE *in, nframes_t /*rbuf_len*/) = 0; // Decode a maximum of max_len samples and return buffers in pcm_channels // (format as per VorbisFile ov_read_float) // Returns # of samples read, 0 if EOF, <0 if error virtual int ReadSamples(AudioBlockIterator *i, nframes_t max_len) = 0; // Stop decoding and finish up-- and close the input file! // ??? -- old note? FIXME workaround for memory managment issue virtual void Stop() = 0; // Are we decoding in stereo? inline char IsStereo() { return stereo; }; protected: // Fweelin Fweelin *app; // Stereo decoding? char stereo; // Input from this file FILE *infd; }; class SndFileDecoder : public iFileDecoder { public: SndFileDecoder(Fweelin *app, codec type); ~SndFileDecoder(); int ReadFromFile (FILE *in, nframes_t rbuf_len); // int Decode (float **pcm_channels, nframes_t max_len); int ReadSamples(AudioBlockIterator *it, nframes_t max_len); void Stop(); private: codec filetype; int samplesize; SF_INFO sfinfo; SNDFILE *sfinfd; float *obuf[2]; float *rbuf; }; class VorbisDecoder : public iFileDecoder { public: // Vorbis library init/end are done in constructor/destructor VorbisDecoder(Fweelin *app); ~VorbisDecoder(); // Decode a maximum of max_len samples and return buffers in pcm_channels // (format as per VorbisFile ov_read_float) // Returns # of samples read, 0 if EOF, <0 if error int ReadSamples(AudioBlockIterator *i, nframes_t max_len); // int Decode(float **pcm_channels, nframes_t max_len); // Stop decoding and finish up-- and close the input file! void Stop() { // Tell vorbis we are done with the stream ov_clear(&vf); }; // Tell the decoder to decode from a given file // This reads the vorbis header int ReadFromFile(FILE *in, nframes_t /*rbuf_len*/); private: // Vorbis decoder stuff OggVorbis_File vf; int current_section; char pcmout[]; }; class AutoWriteControl { public: // This callback method is called periodically by BlockWriteManager // to get the next block chain to write. This allows the main app to // decide which loops to save, while the BlockManager thread does the work // in the background virtual void GetWriteBlock(FILE **out, AudioBlock **b, AudioBlockIterator **i, nframes_t *len) = 0; }; class AutoReadControl { public: // This callback method is called periodically by BlockReadManager // to get the next block chain to read. This allows the main app to // decide which loops to load, while the BlockManager thread does the work // in the background // // GetReadBlock sets 'smooth_end' to nonzero to request for // BlockReadManager to smooth the end of the block into the beginning. // This is the new way to deal with begin-end inconsistencies when loading // OGG loops. To accomodate loops saved without the extra data at the end, // we can set 'smooth_end' to zero. virtual void GetReadBlock(FILE **in, char *smooth_end) = 0; // When the audio data read is complete, BlockReadManager calls ReadComplete // which tells you that you have a new loop in memory virtual void ReadComplete(AudioBlock *b) = 0; }; // BlockReadManager reads & uncompresses an audio block chain // this implementation is used for loading loops. class BlockReadManager : public ManagedChain { public: // Crossfade length when loading old loops (not the new format ones) const static nframes_t SMOOTH_FIX_LEN = 64, DECODE_CHUNKSIZE = 2048; // Increase this number will result in faster decoding but slower response // during decoding (less CPU given up for other Manage tasks) const static int NUM_DECODE_PASSES = 100; BlockReadManager(FILE *in = 0, AutoReadControl *arc = 0, BlockManager *bmg = 0, nframes_t peaksavgs_chunksize = 0); virtual ~BlockReadManager(); virtual Preallocated *NewInstance() { return ::new BlockReadManager(); }; void SetLoopType (codec looptype); // BlockReadManager's RefDeleted may block to avoid block data being // deleted while we are still encoding- we finish up our current decode pass // and then return virtual int RefDeleted(void *ref) { if (ref == arc) { // AutoReadControl is ending, so we should end too arc = 0; return 1; } else return 0; }; // Start decoding into memory from the given file void Start(FILE *new_in = 0); // Ends reading- with error (nonzero) or without error (zero) void End(char error); virtual ManagedChainType GetType() { return T_MC_BlockRead; }; virtual int Manage(); FILE *in; // File to read from char smooth_end; // Smooth end of loop into beginning? AutoReadControl *arc; // A way to ask app what blocks to read iFileDecoder *dec; // Decoder BlockManager *bmg; codec filetype; PeaksAvgsManager *pa_mgr; // Computer for peaks/avgs during load nframes_t peaksavgs_chunksize; pthread_mutex_t decode_lock; }; // BlockWriteManager compresses and writes a block chain (OGG vorbis format) // this implementation is used for saving loops, // unlike the BlockStreamer implementation in core_dsp, which streams // real-time // // Two modes are provided- // 1) follow iterator i-- compresses behind iterator i // 2) compress the whole chain // // We can also choose to invoke BlockWriteManager with AutoWriteControl, // providing a callback which we invoke after writing a block chain. // The callback tells us whether to write another chain, and if so, // gives us the new block and iterator pointers as well as a file out class BlockWriteManager : public ManagedChain { public: const static nframes_t ENCODE_CHUNKSIZE = 10000, ENCODE_CROSSOVER_LEN = 1000; BlockWriteManager(FILE *out = 0, AutoWriteControl *awc = 0, BlockManager *bmg = 0, AudioBlock *b = 0, AudioBlockIterator *i = 0); virtual ~BlockWriteManager(); virtual Preallocated *NewInstance() { return ::new BlockWriteManager(); }; // BlockWriteManager's RefDeleted may block to avoid block data being // deleted while we are still encoding- we finish up our current encode pass // and then return virtual int RefDeleted(void *ref) { if (ref == awc) { // AutoWriteControl is ending, so we should end too awc = 0; return 1; } else if (ref == b || ref == i) { // Block or iterator gone!! The chain we are encoding has been erased- // so stop encoding printf("DISK: Blocks deleted while saving- abort!\n"); End(); if (awc != 0) // Auto save, so keep running return 0; else // Single save, so stop return 1; } else return 0; }; // Start encoding the given block chain to the given file void Start(FILE *new_out = 0, AudioBlock *new_b = 0, AudioBlockIterator *new_i = 0, nframes_t new_len = 0); // Ends writing void End(); virtual ManagedChainType GetType() { return T_MC_BlockWrite; }; virtual int Manage(); FILE *out; // File to write this loop to AudioBlockIterator *ei; // Encode iterator nframes_t len, // Length of block to save pos; // Current save position AutoWriteControl *awc; // A way to ask app what blocks to write iFileEncoder *enc; BlockManager *bmg; pthread_mutex_t encode_lock; }; // PeaksAvgsManager periodically calculates peaks and averages for // blockchain b, keeping up with iterator i // using BlockExtendedData to store peaks & averages class PeaksAvgsManager : public ManagedChain { public: PeaksAvgsManager(BlockManager *bmg = 0, AudioBlock *b = 0, AudioBlockIterator *i = 0, char grow = 0) : ManagedChain(b,i), bmg(bmg), runmax(0), runmin(0), runtally(0), lastcnt(0), chunkcnt(0), stereo(0), grow(grow), go(1), ended(0) {}; virtual ~PeaksAvgsManager(); virtual Preallocated *NewInstance() { return ::new PeaksAvgsManager(); }; virtual int RefDeleted(void *ref) { if (ref == b || ref == i) { // Block or iterator gone!! End this manager! b = 0; return 1; } else return 0; }; // Call before starting! void Setup(); // Ends computation of peaks & averages, chopping the // peaks & averages blocks at this length.. void End(); AudioBlockIterator *GetPeaksI() { return peaksi; }; AudioBlockIterator *GetAvgsI() { return avgsi; }; AudioBlock *GetPeaks() { return pa->peaks; }; AudioBlock *GetAvgs() { return pa->avgs; }; virtual ManagedChainType GetType() { return T_MC_PeaksAvgs; }; virtual int Manage(); BlockManager *bmg; // Target place to store peaks & averages BED_PeaksAvgs *pa; // Iterators for blocks storing peaks & averages AudioBlockIterator *peaksi, *avgsi, *mi; // Iterator for block b for this manager // Used to keep syncronized up to latest changes to block b sample_t runmax, // Running sample maximum runmin, // Running sample minimum runtally; // Running sample tally nframes_t lastcnt, // Last count (curcnt) in iterator i chunkcnt; // Count in current chunk // (where peaks & avgs are calculated) char stereo; // Computing peaks from stereo block? char grow, // Nonzero if peaks & avgs data should be grown // (if input block b is also growing) go, // Nonzero if we are computing peaks & averages ended; // Nonzero if we have ended for good }; // Base class for hipriority managed blocks-- // When a block becomes HiPriManaged it specifies a trigger pointer // A realtime process can then call BlockManager with a trigger pointer // and invoke the Manage() method for all blocks managed with matching // trigger. This allows blocks to interact with other realtime // components, such as time pulses, without knowing what they are. // Manage() is not called periodically, like it is with other // manager types-- so Manage methods must work in realtime class HiPriManagedChain : public ManagedChain { public: HiPriManagedChain(void *trigger = 0, AudioBlock *b = 0, AudioBlockIterator *i = 0) : ManagedChain(b,i), trigger(trigger), lastcnt(0) {}; virtual Preallocated *NewInstance() { return ::new HiPriManagedChain(); }; virtual int RefDeleted(void *ref) { if (ref == b || ref == i || ref == trigger) // Block, iterator, or trigger gone! End this manager! return 1; else return 0; }; virtual ManagedChainType GetType() { return T_MC_HiPri; }; void *trigger; nframes_t lastcnt; // Last iterated pos in block }; // StripeBlockManager is a special hipriority block manager // that stripes blocks with time markers whenever it is invoked // through BlockManager with the specified trigger pointer. // This allows a block to register that some other realtime process // (for example, a time pulse), can trigger time points to be // striped! // We use BED_MarkerPoints to store time markers in the block class StripeBlockManager : public HiPriManagedChain { public: StripeBlockManager(PreallocatedType *pre_tm = 0, void *trigger = 0, AudioBlock *b = 0, AudioBlockIterator *i = 0) : HiPriManagedChain(trigger,b,i), pre_tm(pre_tm) {}; // Call before starting! void Setup(); virtual Preallocated *NewInstance() { return ::new StripeBlockManager(); }; // Do we need a destructor that erases all striped marks?? // Depends on desired functionality-- // do marks persist after the managers that created them are gone? virtual ManagedChainType GetType() { return T_MC_StripeBlock; }; virtual int Manage(); // Target place to store markers BED_MarkerPoints *mp; // Preallocated manager for time markers PreallocatedType *pre_tm; }; // BlockManager handles different maintenance tasks related to // audio blocks. // // It handles -periodic maintenance-, such as resizing a block chain, // performing peak calculations, saving to disk, and analysis on a chain. // // It also handles -time-critical events-, such as firing off pulse sync // messages. This second function may soon be moved to the EventManager. class BlockManager { public: BlockManager (Fweelin *app); ~BlockManager (); Fweelin *GetApp() { return app; }; // Turns on automatic allocation of new blocks at the end of the // specified chain. We work in conjunction with the specified iterator, // so that when the iterator approaches the end of the block chain, // the chain grows automatically void GrowChainOn (AudioBlock *b, AudioBlockIterator *i); void GrowChainOff (AudioBlock *b); // Turns on computation of running sample peaks and averages // for the specified Block & Iterator // We compute as the currenty iterated position advances PeaksAvgsManager *PeakAvgOn (AudioBlock *b, AudioBlockIterator *i, char grow = 0); void PeakAvgOff (AudioBlock *b); // Stripes the specified chain with TimeMarkers according to the specified // trigger. Works in conjunction with RT threads that call HiPriTrigger. void StripeBlockOn (void *trigger, AudioBlock *b, AudioBlockIterator *i); // Removes striping from the specified trigger on blockchain b void StripeBlockOff (void *trigger, AudioBlock *b); // Notify all Managers that the object pointed to has been deleted- // To avoid broken dependencies void RefDeleted (void *ref); // Activate a hipriority trigger- all hiprimanagedchains with // specified trigger pointer will have manage() method called // RT safe! void HiPriTrigger (void *trigger); // Returns the 1st chain manager associated with block o // that has type t ManagedChain *GetBlockManager(AudioBlock *o, ManagedChainType t); // Generic delete/add functions for managers (not hipri) void DelManager (ManagedChain *m); void AddManager (ManagedChain *nw); protected: void DelManager (ManagedChain **first, ManagedChain *m); void AddManager (ManagedChain **first, ManagedChain *nw); void AddHiManager (HiPriManagedChain **first, HiPriManagedChain *nw); void RefDeleted (ManagedChain **first, void *ref); void HiRefDeleted (HiPriManagedChain **first, void *ref); // Delete a managed chain for block o and manager type t // If t is T_MC_None, removes the first managed chain for 'o' // of any type void DelManager (ManagedChain **first, AudioBlock *o, ManagedChainType t = T_MC_None); // Delete a hiprimanaged chain for block o and manager type t // with specified trigger. // If t is T_MC_None, removes the first managed chain for 'o' // with specified trigger, of any type void DelHiManager (HiPriManagedChain **first, AudioBlock *o, ManagedChainType t, void *trigger); // NEED TO MAKE/USE GENERALIZED LIST CLASS // ^^ speed issues? static void *run_manage_thread (void *ptr); ManagedChain *manageblocks; HiPriManagedChain *himanageblocks; pthread_t manage_thread; pthread_mutex_t manage_thread_lock; int threadgo; // ****************** PREALLOCATED TYPE MANAGERS PreallocatedType *pre_growchain, *pre_peaksavgs, *pre_hipri, *pre_stripeblock; // Parent app Fweelin *app; }; #endif freewheeling-0.6.6/src/fweelin_browser.cc000066400000000000000000000730651370736313100205000ustar00rootroot00000000000000/* Copyright 2004-2011 Jan Pekau This file is part of Freewheeling. Freewheeling is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. Freewheeling 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 Freewheeling. If not, see . */ #include #include #include #include #include #include #include #include #include #include #include "fweelin_core.h" #include "fweelin_fluidsynth.h" #include "fweelin_browser.h" const double ItemRenamer::BLINK_DELAY = 0.5; ItemRenamer::ItemRenamer (Fweelin *app, RenameCallback *cb, char *oldname) : app(app), cb(cb) { if (oldname == 0) strcpy(rename_tmpbuf,""); else if (strlen(oldname)+1 >= (unsigned int) RENAME_BUF_SIZE) { strncpy(rename_tmpbuf,oldname,RENAME_BUF_SIZE-1); rename_tmpbuf[RENAME_BUF_SIZE-1] = '\0'; } else strcpy(rename_tmpbuf,oldname); if (app->getCFG()->AddEventHook(this)) { printf("RENAME: You can only rename one item at a time.\n"); renaming = 0; } else { app->getSDLIO()->EnableUNICODE(1); app->getSDLIO()->EnableKeyRepeat(1); renaming = 1; } }; char ItemRenamer::HookEvent(Event *ev, EventProducer */*from*/) { switch (ev->GetType()) { case T_EV_Input_Key : { KeyInputEvent *kev = (KeyInputEvent *) ev; // Intercept alphanumeric keys (use UNICODE translation) if ((kev->unicode > 32 && kev->unicode < 127) || (kev->unicode > 160 && kev->unicode < 256)) { if (kev->down) Rename_Append((char) (kev->unicode & 0xFF)); return 1; } else if (kev->keysym == SDLK_BACKSPACE) { if (kev->down) Rename_Backspace(); return 1; } else if (kev->keysym == SDLK_SPACE) { if (kev->down) Rename_Append(' '); } else if (kev->keysym == SDLK_RETURN || kev->keysym == SDLK_KP_ENTER) { if (kev->down) { app->getCFG()->RemoveEventHook(this); app->getSDLIO()->EnableUNICODE(0); app->getSDLIO()->EnableKeyRepeat(0); // Notify callback that item has been renamed cb->ItemRenamed(rename_tmpbuf); // Callback may delete -this- } return 1; } else if (kev->keysym == SDLK_ESCAPE) { if (kev->down) { app->getCFG()->RemoveEventHook(this); app->getSDLIO()->EnableUNICODE(0); app->getSDLIO()->EnableKeyRepeat(0); // Stop cb->ItemRenamed(0); // Callback may delete -this- } return 1; } return 0; } break; default: break; } return 0; }; // Add an item to this browser // (Doubley linked list add with sort) // Nonzero if we should sort (according to the BrowserItem::Compare() method) void Browser::AddItem(BrowserItem *nw, char sort) { LockBrowser(); if (first == 0) { first = nw; cur = first; // printf("BROWSER: (id: %d) First item now: %s\n",id,first->name); } else { BrowserItem *cur = first; if (sort && nw->Compare(cur) < 0) { // Insert before first if that's where she goes nw->next = first; nw->prev = 0; first->prev = nw; first = nw; } else { // Insert at end or in the right place if sorting if (sort) { while (cur->next != 0 && nw->Compare(cur->next) >= 0) cur = cur->next; } else { while (cur->next != 0) cur = cur->next; } // Insert after cur nw->next = cur->next; if (cur->next != 0) cur->next->prev = nw; nw->prev = cur; cur->next = nw; } } UnlockBrowser(); }; // Remove an item from this browser // For each item we call the MatchItem(itemmatch) method in BrowserItem // until MatchItem returns zero. Then we remove that item. void Browser::RemoveItem(int itemmatch) { LockBrowser(); BrowserItem *curi = first; while (curi != 0 && curi->MatchItem(itemmatch)) curi = curi->next; if (curi != 0) { // Found, remove if (curi->prev != 0) curi->prev->next = curi->next; else first = curi->next; if (curi->next != 0) curi->next->prev = curi->prev; // Move currently selected item if we just removed it if (cur == curi) cur = (curi->prev != 0 ? curi->prev : curi->next); delete curi; } UnlockBrowser(); }; void Browser::ItemRenamed(char *nw) { if (nw != 0) { // Assign new name and stop RenameItem(cur,nw); delete renamer; renamer = 0; // Notify callback of new name if (callback != 0) callback->ItemRenamed(cur); // If edit is blank, assign default name for onscreen display if (strlen(cur->name) == 0) { char tmp[FWEELIN_OUTNAME_LEN]; if (GetType() == B_Loop) GetDisplayName(((LoopBrowserItem *) cur)->filename, &((LoopBrowserItem *) cur)->time, tmp,FWEELIN_OUTNAME_LEN); else if (GetType() == B_Scene) GetDisplayName(((SceneBrowserItem *) cur)->filename, &((SceneBrowserItem *) cur)->time, tmp,FWEELIN_OUTNAME_LEN); RenameItem(cur,tmp); cur->default_name = 1; } else cur->default_name = 0; } else { // Rename was aborted delete renamer; renamer = 0; } }; // Via this method, a browser is notified of a change to the on-disk name // of an item. For example, when a Loop in memory is renamed, we also // rename it on disk, and the loop browser must be notified of this new name. void Browser::ItemRenamedOnDisk(char *old_filename, char *new_filename, char *new_name) { if (old_filename == 0 || new_filename == 0) return; BrowserItem *cur = first; char found = 0; while (cur != 0 && !found) { char *filename = 0; if (cur->GetType() == B_Loop) filename = ((LoopBrowserItem *) cur)->filename; else if (cur->GetType() == B_Scene) filename = ((SceneBrowserItem *) cur)->filename; // printf("looking for oldfilename: %s .. cur: %s\n", // old_filename, filename); if (filename != 0 && !strcmp(filename,old_filename)) found = 1; else cur = cur->next; } if (found) { // Found this item in our browser-- rename in our browser // Assign new filename char *filename = 0; if (cur->GetType() == B_Loop) filename = ((LoopBrowserItem *) cur)->filename; else if (cur->GetType() == B_Scene) filename = ((SceneBrowserItem *) cur)->filename; delete[] filename; filename = new char[strlen(new_filename)+1]; strcpy(filename,new_filename); if (cur->GetType() == B_Loop) ((LoopBrowserItem *) cur)->filename = filename; else if (cur->GetType() == B_Scene) ((SceneBrowserItem *) cur)->filename = filename; // Assign new name and stop RenameItem(cur,new_name); // If new name is blank, assign default name for onscreen display if (cur->name == 0 || strlen(cur->name) == 0) { char tmp[FWEELIN_OUTNAME_LEN]; if (GetType() == B_Loop) GetDisplayName(((LoopBrowserItem *) cur)->filename, &((LoopBrowserItem *) cur)->time, tmp,FWEELIN_OUTNAME_LEN); else if (GetType() == B_Scene) GetDisplayName(((SceneBrowserItem *) cur)->filename, &((SceneBrowserItem *) cur)->time, tmp,FWEELIN_OUTNAME_LEN); RenameItem(cur,tmp); cur->default_name = 1; } else cur->default_name = 0; } }; // Get the onscreen display name for a file with given name. // (filename must refer to a file of the type this browser handles) // Write the name to outbuf, with max maxlen characters. // Returns nonzero if we used a 'default' name. char Browser::GetDisplayName(char *filename, time_t *filetime, char *outbuf, int maxlen) { // Loop exists, use combination of time and hash as name int baselen = strlen(app->getCFG()->GetLibraryPath()) + 1; if (btype == B_Loop) baselen += strlen(FWEELIN_OUTPUT_LOOP_NAME); else if (btype == B_Scene) baselen += strlen(FWEELIN_OUTPUT_SCENE_NAME); else { printf("BROWSER: We don't support getting a display name for type %d\n", btype); return 1; } char sf_basename[FWEELIN_OUTNAME_LEN], sf_hash[FWEELIN_OUTNAME_LEN], sf_objname[FWEELIN_OUTNAME_LEN]; if (Saveable::SplitFilename(filename, baselen, sf_basename, sf_hash, sf_objname,FWEELIN_OUTNAME_LEN) || strlen(sf_objname) == 0) { // No object name given in filename // Compute default name char hashshort_1 = 'X', hashshort_2 = 'X'; Saveable::GetHashFirst(filename,baselen,&hashshort_1,&hashshort_2); // Compose name for item snprintf(outbuf,maxlen,"%c%c %s",hashshort_1,hashshort_2,ctime(filetime)); outbuf[maxlen-1] = '\0'; outbuf[strlen(outbuf)-1] = '\0'; // Cut off return character return 1; } else { // Use name given in filename strncpy(outbuf,sf_objname,maxlen); outbuf[maxlen-1] = '\0'; return 0; } } Browser::~Browser() { if (app != 0) { app->getEMG()->UnlistenEvent(this,0,T_EV_BrowserMoveToItem); app->getEMG()->UnlistenEvent(this,0,T_EV_BrowserSelectItem); } ClearAllItems(); pthread_mutex_destroy (&browser_lock); }; void Browser::ClearAllItems() { LockBrowser(); BrowserItem *cur = first; first = 0; while (cur != 0) { BrowserItem *tmp = cur->next; delete cur; cur = tmp; }; UnlockBrowser(); }; void Browser::Setup(Fweelin *a, BrowserCallback *c) { app = a; callback = c; app->getEMG()->ListenEvent(this,0,T_EV_BrowserMoveToItem); app->getEMG()->ListenEvent(this,0,T_EV_BrowserMoveToItemAbsolute); app->getEMG()->ListenEvent(this,0,T_EV_BrowserSelectItem); app->getEMG()->ListenEvent(this,0,T_EV_BrowserRenameItem); }; // Add divisions between browser items using the Compare function- // whenever two neighbouring items have difference greater than maxdelta, // a division is inserted. In browsing files, for example, this allows us // to group files that where created close to one another in time // // We also put divisions around any items that have been given a unique // name void Browser::AddDivisions(int maxdelta) { if (first != 0) { BrowserItem *cur = first; char go = 1; do { while (cur->next != 0 && cur->next->Compare(cur) < maxdelta && ((cur->default_name && cur->next->default_name) || cur->GetType() == B_Division || cur->next->GetType() == B_Division)) cur = cur->next; if (cur->next != 0) { // Add a division between cur and cur->next BrowserItem *div = new BrowserDivision(); div->prev = cur; div->next = cur->next; cur->next->prev = div; cur->next = div; cur = div->next; } else // Done go = 0; } while (go); } }; void Browser::MoveTo(int adjust, int jumpadjust) { LockBrowser(); if (xpand) { xpand_lastactivity = mygettime(); xpanded = 1; } if (cur == 0) cur = first; if (cur != 0) { // Jump by jumpadjust int adjdir = (jumpadjust >= 0 ? 1 : -1), adjmag = (adjdir == 1 ? abs(jumpadjust) : abs(jumpadjust)+1); BrowserItem *prev = cur; for (int i = 0; cur != 0 && i < adjmag; i++) { prev = cur; while (cur != 0 && cur->GetType() != B_Division) cur = (adjdir == 1 ? cur->next : cur->prev); if (cur != 0) // We are on the division, skip over it which way? cur = (adjdir == 1 || i+1 >= adjmag ? cur->next : cur->prev); if (cur == 0) { if (adjdir == -1 && i+1 >= adjmag) { // Going back to beginning of list cur = first; } else // Went too far, go back cur = prev; } } // Move by adjust adjdir = (adjust >= 0 ? 1 : -1); adjmag = abs(adjust); for (int i = 0; cur != 0 && i < adjmag; i++) { prev = cur; cur = (adjdir == 1 ? cur->next : cur->prev); if (cur != 0 && cur->GetType() == B_Division) i--; // Don't count divisions } if (cur == 0) cur = prev; } else { printf("BROWSER: No elements to move to for browser '%s'\n", GetTypeName(GetType())); } // Call browser virtual method for item browsed- // derived types of browsers may need to do internal updates ItemBrowsed(); // Send out 'item-browsed' event-- which can be bound to // in the config file. BrowserItemBrowsedEvent *bievt = (BrowserItemBrowsedEvent *) Event::GetEventByType(T_EV_BrowserItemBrowsed); bievt->browserid = id; // printf("BROWSER: itembrowsed send %p id: %d\n",bievt,id); app->getEMG()->BroadcastEventNow(bievt, this); if (cur != 0 && callback != 0) callback->ItemBrowsed(cur); UnlockBrowser(); }; void Browser::Select() { if (cur != 0 && callback != 0) callback->ItemSelected(cur); }; void Browser::Rename() { if (cur != 0 && renamer == 0 && (GetType() == B_Loop || GetType() == B_Scene)) { renamer = new ItemRenamer(app,this,(cur->default_name ? 0 : cur->name)); if (!renamer->IsRenaming()) { delete renamer; renamer = 0; } } }; void Browser::ReceiveEvent(Event *ev, EventProducer */*from*/) { switch (ev->GetType()) { case T_EV_BrowserMoveToItem : { BrowserMoveToItemEvent *bev = (BrowserMoveToItemEvent *) ev; // Meant for this browser? if (bev->browserid == id) { if (CRITTERS) printf("BROWSER: Received BrowserMoveToItem " "(browser id: %d, adjust: %d, jumpadjust: %d)\n", bev->browserid, bev->adjust, bev->jumpadjust); MoveTo(bev->adjust, bev->jumpadjust); } } break; case T_EV_BrowserMoveToItemAbsolute : { BrowserMoveToItemAbsoluteEvent *bev = (BrowserMoveToItemAbsoluteEvent *) ev; // Meant for this browser? if (bev->browserid == id) { if (CRITTERS) printf("BROWSER: Received BrowserMoveToItemAbsolute " "(browser id: %d, idx: %d)\n", bev->browserid, bev->idx); MoveToBeginning(); MoveTo(bev->idx, 0); } } break; case T_EV_BrowserSelectItem : { BrowserSelectItemEvent *bev = (BrowserSelectItemEvent *) ev; // Meant for this browser? if (bev->browserid == id) { if (CRITTERS) printf("BROWSER: Received BrowserSelectItem\n"); Select(); } } break; case T_EV_BrowserRenameItem : { BrowserRenameItemEvent *bev = (BrowserRenameItemEvent *) ev; // Meant for this browser? if (bev->browserid == id) { if (CRITTERS) printf("BROWSER: Received BrowserRenameItem\n"); Rename(); } } break; default: break; } } LoopTray::~LoopTray() { if (app != 0) { app->getEMG()->UnlistenEvent(this,0,T_EV_TriggerSet); app->getEMG()->UnlistenEvent(this,0,T_EV_RenameLoop); } }; void LoopTray::Setup(Fweelin *a, BrowserCallback *c) { Browser::Setup(a,c); basepos = app->getCFG()->XCvt(0.016); iconsize = app->getCFG()->XCvt(0.03); xpanded = xpand; app->getEMG()->ListenEvent(this,0,T_EV_TriggerSet); app->getEMG()->ListenEvent(this,0,T_EV_RenameLoop); }; void LoopTray::ReceiveEvent(Event *ev, EventProducer *from) { switch (ev->GetType()) { case T_EV_TriggerSet : { TriggerSetEvent *tev = (TriggerSetEvent *) ev; // printf("tmap set: %d->%p\n",tev->idx,tev->nw); if (tev->nw == 0) { // Delete, // Scan for a LoopTrayItem corresponding to this index RemoveItem(tev->idx); touchtray = 1; } else { // Get the placename- where the loop is mapped char *pname = 0; FloLayout *curl = app->getCFG()->GetLayouts(); while (curl != 0) { if (tev->idx >= curl->loopids.lo && tev->idx <= curl->loopids.hi) { // Loop is mapped to an element in this layout- get the name int firstid = curl->loopids.lo; FloLayoutElement *curel = curl->elems; while (curel != 0 && firstid + curel->id != tev->idx) curel = curel->next; if (curel != 0) pname = curel->name; } curl = curl->next; } // Add, LoopTrayItem *nw = new LoopTrayItem(tev->nw,tev->idx, tev->nw->name, (tev->nw->name == 0 ? 1 : 0), pname); AddItem(nw,1); touchtray = 1; } } break; case T_EV_RenameLoop : { RenameLoopEvent *rev = (RenameLoopEvent *) ev; if (rev->in == 0) { Rename(rev->loopid); if (CRITTERS) printf("LOOPTRAY: Received RenameLoop(loopid: %d)\n",rev->loopid); } } break; default: // Let base class handle it Browser::ReceiveEvent(ev,from); break; } }; // A loop was renamed from outside the loop tray // (loops can be renamed in layouts) // (or on disk) void LoopTray::ItemRenamedFromOutside(Loop *l, char *nw) { if (l != 0 && nw != 0) { // Find the item that has been renamed { LoopTrayItem *curl = (LoopTrayItem *) first; while (curl != 0 && curl->l != l) curl = (LoopTrayItem *) curl->next; cur = curl; } if (cur != 0) { // Assign new name RenameItem(cur,nw); cur->default_name = 0; touchtray = 1; } } }; void LoopTray::ItemRenamed(char *nw) { if (nw != 0) { // Assign new name and stop RenameItem(cur,nw); delete renamer; renamer = 0; // Notify callback of new name if (callback != 0) callback->ItemRenamed(cur); cur->default_name = 0; touchtray = 1; } else { // Rename was aborted delete renamer; renamer = 0; } }; void LoopTray::Rename(int loopid) { if (renamer == 0) { // Find the LoopTrayItem with the given 'loopid' { LoopTrayItem *curl = (LoopTrayItem *) first; while (curl != 0 && curl->loopid != loopid) curl = (LoopTrayItem *) curl->next; cur = curl; } if (cur != 0) { if (CRITTERS) printf("RENAME: Item: %p\n",cur); renamer = new ItemRenamer(app,this,(cur->default_name ? 0 : cur->name)); if (!renamer->IsRenaming()) { delete renamer; renamer = 0; } } } }; char LoopTray::MouseMotion(MouseMotionInputEvent *mev) { if (resize_win != RS_Off) { int xdelta = mev->x - resize_xhand, ydelta = mev->y - resize_yhand; if (resize_win == RS_Move) { xpand_x1 = old_xpand_x1 + xdelta; xpand_y1 = old_xpand_y1 + ydelta; xpand_x2 = old_xpand_x2 + xdelta; xpand_y2 = old_xpand_y2 + ydelta; } else { if ((resize_win == RS_Right || resize_win == RS_TopRight || resize_win == RS_BottomRight) && xpand_x1+basepos*2 <= old_xpand_x2+xdelta) { xpand_x2 = old_xpand_x2 + xdelta; } else if ((resize_win == RS_Left || resize_win == RS_TopLeft || resize_win == RS_BottomLeft) && old_xpand_x1+xdelta+basepos*2 <= xpand_x2) { xpand_x1 = old_xpand_x1 + xdelta; } if ((resize_win == RS_Bottom || resize_win == RS_BottomLeft || resize_win == RS_BottomRight) && xpand_y1+basepos*2 <= old_xpand_y2+ydelta) { xpand_y2 = old_xpand_y2 + ydelta; } else if ((resize_win == RS_Top || resize_win == RS_TopLeft || resize_win == RS_TopRight) && old_xpand_y1+ydelta+basepos*2 <= xpand_y2) { xpand_y1 = old_xpand_y1 + ydelta; } touchtray = 1; } return 1; } return 0; } char LoopTray::MouseButton(MouseButtonInputEvent *mev) { if (resize_win != RS_Off && mev->button == resize_button && !mev->down) { // Mouse release on resize resize_win = RS_Off; return 1; } int mx = mev->x, my = mev->y; // Check if mouse event inside tray if (mx >= xpand_x1 && mx <= xpand_x2 && my >= xpand_y1 && my <= xpand_y2) { // Mouse inside tray if (mx > xpand_x1+basepos && my > xpand_y1+basepos && mx < xpand_x2-basepos && my < xpand_y2-basepos) { // Mouse in inner region if (mev->down) { // Check if the mouse is clicking in any loop LoopTrayItem *curl = (LoopTrayItem *) first; char go = 1, found = 0; while (curl != 0 && go) { if (curl->xpos != -1) { int relx = mx-xpand_x1-(curl->xpos+loopmap->map_xs/2), rely = my-xpand_y1-(curl->ypos+loopmap->map_ys/2); if (relx*relx+rely*rely <= loopsize*loopsize/4) { // Mouse is clicking within this loop found = 1; // Issue 'loop clicked' event LoopClickedEvent *lcevt = (LoopClickedEvent *) Event::GetEventByType(T_EV_LoopClicked); lcevt->button = mev->button; lcevt->down = mev->down; lcevt->loopid = curl->loopid; lcevt->in = 0; // In=0 means clicked in looptray app->getEMG()->BroadcastEvent(lcevt, this); } } else go = 0; curl = (LoopTrayItem *) curl->next; } if (!found) { // Not clicking inside any loop-- // Start moving resize_win = RS_Move; resize_button = mev->button; resize_xhand = mx; resize_yhand = my; old_xpand_x1 = xpand_x1; old_xpand_y1 = xpand_y1; old_xpand_x2 = xpand_x2; old_xpand_y2 = xpand_y2; } } } else { // Mouse in border region if (mev->down) { // Start resizing char bord_l = 0, bord_lm = 0, bord_r = 0, bord_rm = 0, bord_t = 0, bord_tm = 0, bord_b = 0, bord_bm = 0; int bord_mid_thresh = basepos*3; if (mx >= xpand_x1 && mx <= xpand_x1+basepos) { bord_l = 1; bord_lm = 1; } else if (mx >= xpand_x2-basepos && mx <= xpand_x2) { bord_r = 1; bord_rm = 1; } else if (mx >= xpand_x1 && mx <= xpand_x1+bord_mid_thresh) { bord_lm = 1; } else if (mx >= xpand_x2-bord_mid_thresh && mx <= xpand_x2) { bord_rm = 1; } if (my >= xpand_y1 && my <= xpand_y1+basepos) { bord_t = 1; bord_tm = 1; } else if (my >= xpand_y2-basepos && my <= xpand_y2) { bord_b = 1; bord_bm = 1; } else if (my >= xpand_y1 && my <= xpand_y1+bord_mid_thresh) { bord_tm = 1; } else if (my >= xpand_y2-bord_mid_thresh && my <= xpand_y2) { bord_bm = 1; } if (bord_l) { if (bord_tm) resize_win = RS_TopLeft; else if (bord_bm) resize_win = RS_BottomLeft; else resize_win = RS_Left; } else if (bord_r) { if (bord_tm) resize_win = RS_TopRight; else if (bord_bm) resize_win = RS_BottomRight; else resize_win = RS_Right; } else if (bord_t) { if (bord_lm) resize_win = RS_TopLeft; else if (bord_rm) resize_win = RS_TopRight; else resize_win = RS_Top; } else if (bord_b) { if (bord_lm) resize_win = RS_BottomLeft; else if (bord_rm) resize_win = RS_BottomRight; else resize_win = RS_Bottom; } else { printf("BROWSER: Error in mouse border algorithm!\n"); resize_win = RS_Off; } resize_button = mev->button; resize_xhand = mev->x; resize_yhand = mev->y; old_xpand_x1 = xpand_x1; old_xpand_y1 = xpand_y1; old_xpand_x2 = xpand_x2; old_xpand_y2 = xpand_y2; } } // Eat event return 1; } else if (mx >= xpos && mx <= xpos+iconsize && my >= ypos && my <= ypos+iconsize) { if (mev->down) { // Mouse clicked on icon xpanded = (xpanded ? 0 : 1); touchtray = 1; } return 1; } else { // Mouse outside tray, ignore return 0; } }; PatchBrowser::~PatchBrowser() { // Invoke our special ClearAllItems method ClearAllItems(); if (app != 0) { app->getEMG()->UnlistenEvent(this,0,T_EV_PatchBrowserMoveToBank); app->getEMG()->UnlistenEvent(this,0,T_EV_PatchBrowserMoveToBankByIndex); } }; void PatchBrowser::ClearAllItems() { LockBrowser(); cur = 0; first = 0; // Delete all items in all patch banks PatchBank *curpb = pb_first; pb_first = 0; while (curpb != 0) { BrowserItem *cur = curpb->first; curpb->first = 0; curpb->cur = 0; while (cur != 0) { BrowserItem *tmp = cur->next; delete cur; cur = tmp; } curpb = curpb->next; }; // *** Do we need to clear all patchbanks too? UnlockBrowser(); }; void PatchBrowser::PB_MoveTo (int direction) { LockBrowser(); if (xpand) { xpand_lastactivity = mygettime(); xpanded = 1; } // Update pb_cur if (pb_cur != 0) { pb_cur->cur = cur; pb_cur->first = first; } else pb_cur = pb_first; if (pb_cur != 0) { if (direction > 0) { // Forward if (pb_cur->next != 0) pb_cur = pb_cur->next; } else { // Slow way to move backwards in a singly linked list PatchBank *tmp = pb_first; while (tmp != 0 && tmp->next != pb_cur) tmp = tmp->next; if (tmp != 0) pb_cur = tmp; } // Assign patch 'cur' and 'first' pointers based on this patch bank first = pb_cur->first; cur = pb_cur->cur; pb_cur_tag = pb_cur->tag; // Don't update when moving // SetMIDIForPatch(); } else pb_cur_tag = -1; UnlockBrowser(); }; void PatchBrowser::PB_MoveToIndex (int index) { LockBrowser(); if (xpand) { xpand_lastactivity = mygettime(); xpanded = 1; } // Update pb_cur if (pb_cur != 0) { pb_cur->cur = cur; pb_cur->first = first; } else pb_cur = pb_first; // Count to right patchbank pb_cur = pb_first; for (int i = 0; i < index && pb_cur != 0; i++, pb_cur = pb_cur->next); if (pb_cur == 0) pb_cur = pb_first; else { // Assign patch 'cur' and 'first' pointers based on this patch bank first = pb_cur->first; cur = pb_cur->cur; // Don't update when moving // SetMIDIForPatch(); } if (pb_cur != 0) pb_cur_tag = pb_cur->tag; else pb_cur_tag = -1; UnlockBrowser(); }; void PatchBrowser::Setup(Fweelin *a, BrowserCallback *c) { Browser::Setup(a,c); app->getEMG()->ListenEvent(this,0,T_EV_PatchBrowserMoveToBank); app->getEMG()->ListenEvent(this,0,T_EV_PatchBrowserMoveToBankByIndex); }; void PatchBrowser::ReceiveEvent(Event *ev, EventProducer *from) { switch (ev->GetType()) { case T_EV_PatchBrowserMoveToBank : { PatchBrowserMoveToBankEvent *pbev = (PatchBrowserMoveToBankEvent *) ev; PB_MoveTo(pbev->direction); if (CRITTERS) printf("PATCH BROWSER: Received PatchBrowserMoveToBank " "(direction: %d)\n", pbev->direction); } break; case T_EV_PatchBrowserMoveToBankByIndex : { PatchBrowserMoveToBankByIndexEvent *pbev = (PatchBrowserMoveToBankByIndexEvent *) ev; PB_MoveToIndex(pbev->index); if (CRITTERS) printf("PATCH BROWSER: Received PatchBrowserMoveToBankByIndex " "(index: %d)\n", pbev->index); } break; default: // Let base class handle it Browser::ReceiveEvent(ev,from); break; } }; // Sets the right MIDI port(s) and channel(s) for echo based on this // patches' settings void PatchBrowser::SetMIDIForPatch() { /* printf("pb cur: %p port: %d\n",pb_cur,pb_cur->port); printf("cur: %p\n",cur); printf("app: %p\n",app); if (app != 0) printf("getmidi: %p\n",app->getMIDI()); */ if (app != 0 && app->getMIDI() != 0) app->getMIDI()->SetMIDIForPatch((pb_cur == 0 ? 0 : pb_cur->port), (cur != 0 && cur->GetType() == B_Patch ? (PatchItem *) cur : 0)); }; void FloDisplaySnapshots::Rename (int idx) { Snapshot *s = app->getSNAP(idx); if (renamer == 0 && s != 0 && s->exists) { renamer = new ItemRenamer(app,this,s->name); rename_idx = idx; if (!renamer->IsRenaming()) { delete renamer; renamer = 0; } // Keep display showing while we interactively rename forceshow = 1; } }; void FloDisplaySnapshots::ItemRenamed(char *nw) { forceshow = 0; if (nw != 0) { // printf("NEW SNAPSHOT NAME: %s\n",nw); Snapshot *s = app->getSNAP(rename_idx); if (s != 0) { LockSnaps(); if (s->name != 0) delete[] s->name; if (nw != 0) { s->name = new char[strlen(nw)+1]; strcpy(s->name,nw); } else s->name = 0; UnlockSnaps(); } delete renamer; renamer = 0; } else { // Rename was aborted delete renamer; renamer = 0; } }; freewheeling-0.6.6/src/fweelin_browser.h000066400000000000000000000453321370736313100203360ustar00rootroot00000000000000#ifndef __FWEELIN_BROWSER_H #define __FWEELIN_BROWSER_H /* Copyright 2004-2011 Jan Pekau This file is part of Freewheeling. Freewheeling is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. Freewheeling 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 Freewheeling. If not, see . */ #include "fweelin_event.h" #include "fweelin_config.h" class CircularMap; class MouseButtonInputEvent; class MouseMotionInputEvent; enum ResizeType { RS_Off, RS_Move, // Move only RS_Top, RS_Bottom, RS_Left, RS_Right, RS_TopLeft, RS_TopRight, RS_BottomLeft, RS_BottomRight }; enum BrowserItemType { B_Undefined = 0, B_Loop_Tray, // Loop tray (loaded loops) B_Scene_Tray, // Scene tray (loaded scenes) B_Loop, // Loop (all loops in library) B_Scene, // Scene (all scenes in library) B_Patch, B_Division, B_Last }; class BrowserItem { public: // Initialize a browser item with name n BrowserItem(const char *n = 0, char default_name = 1) : default_name(default_name), next(0), prev(0) { if (n == 0) name = 0; else { name = new char[strlen(n)+1]; strcpy(name,n); } }; virtual ~BrowserItem() { if (name != 0) delete[] name; }; virtual BrowserItemType GetType() = 0; // Compare this item to a second item and return whether this item is // greater than (>0), less than (<0), or equal to (==0) second // Used for sorting browser items virtual int Compare(BrowserItem */*second*/) { return 0; }; // Return zero if the item described by 'itemmatch' matches this item // This is a type-neutral compare function to be overridden to provide // meaningful matches for different browsers virtual int MatchItem(int /*itemmatch*/) { return 1; }; char default_name; // Nonzero if the name for this item is a default name char *name; BrowserItem *next, *prev; }; class BrowserDivision : public BrowserItem { public: virtual BrowserItemType GetType() { return B_Division; }; }; class BrowserCallback { public: virtual void ItemBrowsed(BrowserItem *i) = 0; virtual void ItemSelected(BrowserItem *i) = 0; virtual void ItemRenamed(BrowserItem *i) = 0; }; class RenameCallback { public: virtual void ItemRenamed(char *nw) = 0; }; class RenameUIVars { public: RenameUIVars() : rename_cursor_blinktime(0), rename_cursor_toggle(0) {}; double rename_cursor_blinktime; char rename_cursor_toggle; }; // This class encapsulates the UI for renaming an item class ItemRenamer : public EventHook { public: const static int RENAME_BUF_SIZE = 512; // Maximum length of item name const static double BLINK_DELAY; ItemRenamer(Fweelin *app, RenameCallback *cb, char *oldname); virtual ~ItemRenamer() {}; // Hook events for typing new names virtual char HookEvent(Event *ev, EventProducer */*from*/); inline char *GetCurName() { return rename_tmpbuf; }; inline RenameUIVars *UpdateUIVars() { double t = mygettime(); if (t-rui.rename_cursor_blinktime >= BLINK_DELAY) { rui.rename_cursor_blinktime = t; rui.rename_cursor_toggle = (rui.rename_cursor_toggle ? 0 : 1); } return &rui; }; inline char IsRenaming() { return renaming; }; private: inline void Rename_Append(char c) { int rblen = strlen(rename_tmpbuf); if (rblen+1 < RENAME_BUF_SIZE) { rename_tmpbuf[rblen] = c; // printf("KEY: %c\n",rename_tmpbuf[rblen]); rename_tmpbuf[++rblen] = '\0'; } }; inline void Rename_Backspace() { int rblen = strlen(rename_tmpbuf); if (rblen > 0) rename_tmpbuf[rblen-1] = '\0'; }; Fweelin *app; RenameCallback *cb; // Way to notify the caller when we are done renaming char rename_tmpbuf[RENAME_BUF_SIZE]; // Buffer for new name RenameUIVars rui; char renaming; // Nonzero if we are renaming }; class Browser : public FloDisplay, public EventListener, public EventProducer, public RenameCallback { public: Browser (int iid, BrowserItemType btype, char xpand, int xpand_x1, int xpand_y1, int xpand_x2, int xpand_y2, float xpand_delay) : FloDisplay(iid), renamer(0), app(0), btype(btype), callback(0), first(0), cur(0), xpand_x1(xpand_x1), xpand_y1(xpand_y1), xpand_x2(xpand_x2), xpand_y2(xpand_y2), xpand_centery(-1), xpand_liney(-1), xpand_spread(-1), xpand_lastactivity(0.0), xpand_delay(xpand_delay), xpand(xpand), xpanded(0) { pthread_mutex_init (&browser_lock,0); if (btype >= B_Last || (int) btype < 0) { printf("BROWSER: Invalid browsetype %d!\n",btype); btype = (BrowserItemType) 0; } }; virtual ~Browser(); // Call after construction when we have app & callback ready virtual void Setup(Fweelin *a, BrowserCallback *c); // Move to the beginning of the browser list // Does not fully update, so MoveTo must be called after inline void MoveToBeginning() { LockBrowser(); cur = first; UnlockBrowser(); }; // Move to a new item, relative to the current void MoveTo(int adjust, int jumpadjust); // Select the current item void Select(); // Rename the current item void Rename(); // Mouse button pressed (return nonzero to eat event, zero to ignore) virtual char MouseButton(MouseButtonInputEvent */*evt*/) { return 0; }; // Mouse moved (return nonzero to eat event, zero to ignore) virtual char MouseMotion(MouseMotionInputEvent */*evt*/) { return 0; }; // Get the onscreen display name for a file with given name. // (filename must refer to a file of the type this browser handles) // Write the name to outbuf, with max maxlen characters. // Returns nonzero if we used a 'default' name. char GetDisplayName(char *filename, time_t *filetime, char *outbuf, int maxlen); ItemRenamer *renamer; // Renamer instance, or null if we are not renaming virtual void ItemRenamed(char *nw); // Callback for renamer // Via this method, a browser is notified of a change to the on-disk name // of an item. For example, when a Loop in memory is renamed, we also // rename it on disk, and the loop browser must be notified of this new name. void ItemRenamedOnDisk(char *old_filename, char *new_filename, char *new_name); inline BrowserItemType GetType() { return btype; }; virtual FloDisplayType GetFloDisplayType() { return FD_Browser; }; inline static char *GetTypeName(BrowserItemType b) { switch (b) { case B_Scene_Tray : return "Scene Tray"; case B_Loop_Tray : return "Loop Tray"; case B_Loop : return "Loop"; case B_Scene : return "Scene"; case B_Division : return "Division"; case B_Patch : return "Patch"; default : return "**UNKNOWN**"; } }; // Receive events virtual void ReceiveEvent(Event *ev, EventProducer */*from*/); // Draw to screen virtual void Draw(SDL_Surface *screen); virtual void Draw_Item(SDL_Surface *screen, BrowserItem *i, int x, int y); virtual void ClearAllItems(); // Add divisions between browser items using the Compare function- // whenever two neighbouring items have difference greater than maxdelta, // a division is inserted. In browsing files, for example, this allows us // to group files that where created close to one another in time void AddDivisions(int maxdelta); // Add an item to this browser // (Doubley linked list add with sort) // Nonzero if we should sort (according to the BrowserItem::Compare() method) virtual void AddItem(BrowserItem *nw, char sort = 0); // Remove an item from this browser // For each item we call the MatchItem(itemmatch) method in BrowserItem // until MatchItem returns zero. Then we remove that item. virtual void RemoveItem(int itemmatch); // Return current browser item inline BrowserItem *GetCurItem() { return cur; }; // Threadsafe item rename inline void RenameItem(BrowserItem *i, char *nw) { LockBrowser(); if (i->name != 0) delete[] i->name; if (nw != 0) { i->name = new char[strlen(nw)+1]; strcpy(i->name,nw); } else i->name = 0; UnlockBrowser(); }; inline void LockBrowser() { pthread_mutex_lock (&browser_lock); }; inline void UnlockBrowser() { pthread_mutex_unlock (&browser_lock); }; protected: // Internal update function called when a new item is browsed- // derived classes may override virtual void ItemBrowsed() {}; Fweelin *app; BrowserItemType btype; // Browser type BrowserCallback *callback; // Callback to notify of browser events BrowserItem *first, // First item *cur; // Current item // Dimensions of expanded browser view when moving between items: int xpand_x1, xpand_y1, xpand_x2, xpand_y2, xpand_centery, xpand_liney, xpand_spread; double xpand_lastactivity, // Time of last activity in browser- // controls when to expand xpand_delay; // Time to hold up expanded browser char xpand, // Nonzero if we should expand when moving xpanded; // Nonzero if we are expanded pthread_mutex_t browser_lock; // A way to lock up a browser so two threads // don't race on it }; class LoopTray : public Browser { public: LoopTray (int iid, BrowserItemType btype, char xpand, int xpand_x1, int xpand_y1, int xpand_x2, int xpand_y2, int loopsize) : Browser(iid,btype,xpand,xpand_x1,xpand_y1,xpand_x2,xpand_y2,0.0), loopsize(loopsize), basepos(0), iconsize(0), resize_win(RS_Off), touchtray(0), loopmap(0) {}; virtual ~LoopTray(); // Call after construction when we have app & callback ready virtual void Setup(Fweelin *a, BrowserCallback *c); // Draw to screen virtual void Draw(SDL_Surface *screen); virtual void Draw_Item(SDL_Surface *screen, BrowserItem *i, int x, int y); // Receive events virtual void ReceiveEvent(Event *ev, EventProducer *from); // Mouse updates virtual char MouseButton(MouseButtonInputEvent *mev); virtual char MouseMotion(MouseMotionInputEvent *mev); // Renaming void Rename(int loopid); virtual void ItemRenamed(char *nw); void ItemRenamedFromOutside(Loop *l, char *nw); int loopsize, // Size of loops in tray basepos, // Base (border) size in tray iconsize; // Size of iconified tray // Window move/resize variables ResizeType resize_win; int resize_button, resize_xhand, resize_yhand, old_xpand_x1, old_xpand_x2, old_xpand_y1, old_xpand_y2; // Has the tray been changed and coordinates need recalculating? char touchtray; CircularMap *loopmap; // Mapping to draw circular loops }; class CombiZone { public: void SetupZone (int kr_lo = 0, int kr_hi = 0, char port_r = 0, int port = 0, int bank = -1, int prog = -1, int channel = 0, char bypasscc = 0, int bypasschannel = -1, float bypasstime1 = 0.0, float bypasstime2 = 10.0) { this->kr_lo = kr_lo; this->kr_hi = kr_hi; this->port_r = port_r; this->port = port; this->bank = bank; this->prog = prog; this->channel = channel; this->bypasscc = bypasscc; this->bypasschannel = bypasschannel; this->bypasstime1 = bypasstime1; this->bypasstime2 = bypasstime2; }; int kr_lo, // Bottom key for this zone kr_hi; // Top key for this zone char port_r; // Nonzero if we should transmit to the MIDI port given below int port, // By default, a zone transmits to the MIDI port given by // a given patchbank. But it is also possible to redirect // a zone to output to any MIDI port. 0 is the internal // FluidSynth port. bank, // Bank select for zone (-1 for none) prog, // Program change for zone (-1 for none) channel; // Transmit channel # for zone char bypasscc; // MIDI CC to send for bypass int bypasschannel; // MIDI channel to send bypass to (or -1 to use regular channel) float bypasstime1, // Length of time (s) before auto-bypass when notes are sustaining (with or without pedal) bypasstime2; // Length of time (s) before auto-bypass when notes have been released }; // Small class to encapsulate patches class PatchItem : public BrowserItem { public: PatchItem (int id = 0, int bank = 0, int prog = 0, int channel = 0, const char *name = 0, char bypasscc = 0, int bypasschannel = -1, float bypasstime1 = 0.0, float bypasstime2 = 10.0) : BrowserItem(name), id(id), bank(bank), prog(prog), channel(channel), bypasscc(bypasscc), bypasschannel(bypasschannel), bypasstime1(bypasstime1), bypasstime2(bypasstime2), zones(0), numzones(0) {}; virtual ~PatchItem() { if (zones != 0) delete[] zones; }; inline void SetupZones (int numzones) { this->numzones = numzones; zones = new CombiZone[numzones]; } inline CombiZone *GetZone (int idx) { if (idx >= 0 && idx < numzones) return &zones[idx]; else return 0; }; // Is this a combi patch (multizone) (returns nonzero) // or just a regular patch? (returns zero) inline char IsCombi() { return numzones > 0; }; virtual BrowserItemType GetType() { return B_Patch; }; int id, // Unique patch ID bank, // Bank select for patch prog, // Program change for patch channel; // Channel # for patch char bypasscc; // MIDI CC to send for bypass int bypasschannel; // MIDI channel to send bypass to (or -1 to use regular channel) float bypasstime1, // Length of time (s) before auto-bypass when notes are sustaining (with or without pedal) bypasstime2; // Length of time (s) before auto-bypass when notes have been released // For a combination patch, we have an array of all zones CombiZone *zones; int numzones; }; // Patch browser is unique in that it manages -several- lists of // BrowserItems-- one for each MIDI port and, optionally, each channel // to which patch names are assigned. // // Each list of patches is called a PatchBank: #define MIDI_BANKCHANGE_MSB 0 #define MIDI_BANKCHANGE_LSB 32 class PatchBank { public: PatchBank (int port, int tag, char suppresschg) : port(port), tag(tag), suppresschg(suppresschg), first(0), cur(0), next(0) {}; int port, // MIDI output port for this patch bank // (or -1 for internal FluidSynth patch bank) tag; // Tag for identifying patchbank- can be // used by the user config to change FW behavior when // a given patchbank is active char suppresschg; // Suppress program/bank change messages being sent // for this patch bank? BrowserItem *first, // First item *cur; // Current item PatchBank *next; }; class PatchBrowser : public Browser { friend class Fweelin; public: // Every DIV_SPACING patches, we insert a divider in the browser const static int DIV_SPACING = 10; PatchBrowser (int iid, BrowserItemType btype, char xpand, int xpand_x1, int xpand_y1, int xpand_x2, int xpand_y2, float xpand_delay) : Browser(iid,btype,xpand,xpand_x1,xpand_y1,xpand_x2,xpand_y2,xpand_delay), pb_first(0), pb_cur(0), pb_cur_tag(-1), num_pb(0) {}; virtual ~PatchBrowser(); virtual void ClearAllItems(); virtual void Setup(Fweelin *a, BrowserCallback *c); virtual void ReceiveEvent(Event *ev, EventProducer *from); // Add patch bank void PB_Add (PatchBank *pb) { LockBrowser(); num_pb++; // Update pb_cur if (pb_cur != 0) { pb_cur->cur = cur; pb_cur->first = first; } // Insert at end of list if (pb_first == 0) pb_first = pb_cur = pb; else { PatchBank *pb_i = pb_first; while (pb_i->next != 0) pb_i = pb_i->next; pb_i->next = pb_cur = pb; } // And set cur & first pointers cur = pb->cur; first = pb->first; pb_cur_tag = pb->tag; SetMIDIForPatch(); UnlockBrowser(); }; // Add patch bank at beginning of patchbanks void PB_AddBegin (PatchBank *pb) { LockBrowser(); num_pb++; // Update pb_cur if (pb_cur != 0) { pb_cur->cur = cur; pb_cur->first = first; } // Insert at beginning of list pb->next = pb_first; pb_first = pb_cur = pb; // And set cur & first pointers cur = pb->cur; first = pb->first; pb_cur_tag = pb->tag; SetMIDIForPatch(); UnlockBrowser(); }; // Move to the next (+ve direction) or previous (-ve direction) patch bank void PB_MoveTo (int direction); // Move to a patchbank given by index void PB_MoveToIndex (int index); inline PatchBank *GetCurPatchBank() const { return pb_cur; }; // Sets the right MIDI port(s) and channel(s) for echo & auto-bypass based on this // patches' settings void SetMIDIForPatch(); protected: // Select patch automatically when we browse to it // ** Disabled // virtual void ItemBrowsed() { SetMIDIForPatch(); }; private: PatchBank *pb_first, // List of patchbanks *pb_cur; // Current patchbank int pb_cur_tag, // Tag from current patchbank num_pb; // Number of patchbanks defined }; class FloDisplaySnapshots : public FloDisplay, public RenameCallback { public: FloDisplaySnapshots (Fweelin *app, int iid) : FloDisplay(iid), renamer(0), app(app), firstidx(0), numdisp(-1) { pthread_mutex_init (&snaps_lock,0); }; ~FloDisplaySnapshots() { pthread_mutex_destroy (&snaps_lock); }; virtual FloDisplayType GetFloDisplayType() { return FD_Snapshots; }; virtual void Draw(SDL_Surface *screen); ItemRenamer *renamer; // Renamer instance, or null if we are not renaming int rename_idx; // Index of snapshot we are renaming virtual void ItemRenamed(char *nw); // Callback for renamer // Rename the snapshot with given index void Rename (int idx); inline void LockSnaps() { pthread_mutex_lock (&snaps_lock); }; inline void UnlockSnaps() { pthread_mutex_unlock (&snaps_lock); }; Fweelin *app; int firstidx, // Index of first snapshot to display numdisp; // Number of snapshots to display int sx, sy, // Size of snapshots list margin; // Margin for text protected: pthread_mutex_t snaps_lock; // A way to lock up snapshot display so two threads // don't race on it }; #endif freewheeling-0.6.6/src/fweelin_config.cc000066400000000000000000003421551370736313100202610ustar00rootroot00000000000000// A deer crossed my path today // // It said // // Why all this pressure // to change the world?? // // Accept the world as it is. // That is peace. // That is healing. // // It is not idleness. // It is precise action, // Energy conservation. /* Copyright 2004-2011 Jan Pekau This file is part of Freewheeling. Freewheeling is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. Freewheeling 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 Freewheeling. If not, see . */ #include #include #include #include #include #include #include #include #include #include #include #include #include "fweelin_config.h" #include "fweelin_midiio.h" #include "fweelin_sdlio.h" #include "fweelin_core.h" #include "fweelin_core_dsp.h" #include "fweelin_paramset.h" // *********** CONFIG #ifdef __MACOSX__ #import /* for MAXPATHLEN */ char FWEELIN_datadir[MAXPATHLEN]; char *FWEELIN_DATADIR = FWEELIN_datadir; #endif const char CfgMathOperation::operators[] = {'/', '*', '+', '-'}; const int CfgMathOperation::numops = 4; const int FloConfig::NUM_PREALLOCATED_AUDIO_BLOCKS = 40; const int FloConfig::NUM_PREALLOCATED_TIME_MARKERS = 40; const float FloConfig::AUDIO_MEMORY_LEN = 10.0; const int FloConfig::CFG_PATH_MAX = 2048; // Copies configuration file 'cfgname' from shared to ~/.fweelin // If copyall is set, copies *all* .XML files from shared to ~/.fweelin // Backups are made if needed void FloConfig::CopyConfigFile (char *cfgname, char copyall) { char buf[CFG_PATH_MAX]; char *homedir = getenv("HOME"); if (copyall) { // Copy all .xml files in shared: glob_t globbuf; snprintf(buf,CFG_PATH_MAX,"%s/*%s", FWEELIN_DATADIR,FWEELIN_CONFIG_EXT); printf("INIT: Copying all config files from shared folder...\n"); if (glob(buf, 0, NULL, &globbuf) == 0) { for (size_t i = 0; i < globbuf.gl_pathc; i++) { // Strip path and send filename char *lastslash = strrchr(globbuf.gl_pathv[i],'/'); if (lastslash == 0) CopyConfigFile(globbuf.gl_pathv[i],0); else CopyConfigFile(lastslash+1,0); } globfree(&globbuf); } } else { // Config file exists? (need to backup?) snprintf(buf,CFG_PATH_MAX,"%s/%s/%s",homedir, FWEELIN_CONFIG_DIR,cfgname); struct stat st; if (stat(buf,&st) == 0) { // Find backup name unsigned int tmp2_size = CFG_PATH_MAX + 20; char tmp2[tmp2_size]; unsigned char bCnt = 1; char go = 1; do { snprintf(tmp2,tmp2_size,"%s.backup.%d",buf,bCnt); if (stat(tmp2,&st) != 0) go = 0; // Free backup filename else bCnt++; } while (go && bCnt % 256) ; // Backup printf("Backing up your old configuration to: %s\n",tmp2); unsigned int tmp3_size = (CFG_PATH_MAX * 2) + 20; char tmp3[tmp3_size]; snprintf(tmp3,tmp3_size,"cp \"%s\" \"%s\"",buf,tmp2); printf("INIT: Copying: %s\n",tmp3); system(tmp3); } // Copy over from shared char buf2[CFG_PATH_MAX*2]; snprintf(buf2,CFG_PATH_MAX*2,"cp \"%s/%s\" \"%s/%s\"", FWEELIN_DATADIR,cfgname, homedir,FWEELIN_CONFIG_DIR); printf("INIT: Copying: %s\n",buf2); system(buf2); } }; char *FloConfig::PrepareLoadConfigFile (char *cfgname, char basecfg) { static char buf[CFG_PATH_MAX]; char *homedir = getenv("HOME"); // Look for config file char go = 1; do { snprintf(buf,CFG_PATH_MAX,"%s/%s/%s",homedir, FWEELIN_CONFIG_DIR,cfgname); struct stat st; if (stat(buf,&st) != 0) { if (go == 2) { // Already tried to copy config file from shared. // Config file not found printf("INIT: Can't find configuration file '%s'.\n",buf); return 0; } else { // 1st try- // Can't find config file in config dir- printf("INIT: Configuration file '%s' not in usual place. " "Checking.\n",buf); // Check if config dir exists? snprintf(buf,CFG_PATH_MAX,"%s/%s",homedir,FWEELIN_CONFIG_DIR); if (mkdir(buf,S_IRWXU)) { if (errno != EEXIST) { printf("INIT: Error %d creating config folder '%s'- " "do you have write permission there?\n", errno,buf); } } else { printf("INIT: *** Created new config folder '%s'.\n",buf); printf("INIT: Copying static files from shared folder...\n"); // copy static assets to user config dir CopyConfigFile("bcf2000-help.txt",0); CopyConfigFile("bcf2000-preset.mid",0); CopyConfigFile("config-help.txt",0); } // Copy configuration file(s) from shared folder CopyConfigFile(cfgname,basecfg); go = 2; } } else go = 0; // Found, end search } while (go); return buf; }; void UserVariable::Print(char *str, int maxlen) { if (name != 0 && str == 0) printf("'%s'[",name); switch (type) { case T_char : if (str != 0) snprintf(str,maxlen,"%d",(int) *this); else printf("%d",(int) *this); break; case T_int : if (str != 0) snprintf(str,maxlen,"%d",(int) *this); else printf("%d",(int) *this); break; case T_long : if (str != 0) snprintf(str,maxlen,"%ld",(long) *this); else printf("%ld",(long) *this); break; case T_float : if (str != 0) snprintf(str,maxlen,"%.2f",(float) *this); else printf("%.2f",(float) *this); break; case T_range : { Range r = *this; if (str != 0) snprintf(str,maxlen,"%d>%d",r.lo,r.hi); else printf("%d>%d",r.lo,r.hi); } break; case T_variable : if (str != 0) snprintf(str,maxlen,"variable"); else printf("variable"); break; case T_variableref : if (str != 0) snprintf(str,maxlen,"variable reference"); else printf("variable reference"); break; case T_invalid : if (str != 0) snprintf(str,maxlen,"invalid"); else printf("invalid"); break; } if (name != 0 && str == 0) printf("]"); }; void CfgToken::Print() { switch (cvt) { case T_CFG_None : printf("[none]\n"); break; case T_CFG_Static : val.Print(); break; case T_CFG_EventParameter : printf("'%s'",evparam.name); break; case T_CFG_UserVariable : var->Print(); break; } }; // Evaluate the current value of this token to dst // Using event ev as a reference for event parameter // If overwritetype is nonzero, sets dst to be of the appropriate data type // Otherwise, converts to existing type of dst void CfgToken::Evaluate(UserVariable *dst, Event *ev, char overwritetype) { switch (cvt) { case T_CFG_None : break; case T_CFG_Static : if (overwritetype) dst->type = val.type; dst->SetFrom(val); break; case T_CFG_EventParameter : if (ev != 0) { UserVariable tmp; tmp.type = evparam.dtype; char *evofs = (char *)ev + evparam.ofs; switch (evparam.dtype) { case T_char : memcpy(tmp.value,evofs,sizeof(char)); break; case T_int : memcpy(tmp.value,evofs,sizeof(int)); break; case T_long : memcpy(tmp.value,evofs,sizeof(long)); break; case T_float : memcpy(tmp.value,evofs,sizeof(float)); break; default : printf(" CfgToken: Can't evaluate invalid data type\n"); } if (overwritetype) dst->type = tmp.type; dst->SetFrom(tmp); } break; case T_CFG_UserVariable : if (overwritetype) dst->type = var->type; dst->SetFrom(*var); break; } }; char ParsedExpression::IsStatic() { if (start.cvt != T_CFG_Static) return 0; // Check math ops for nonstatics CfgMathOperation *cur = ops; while (cur != 0) { if (cur->operand.cvt != T_CFG_Static) return 0; cur = cur->next; } return 1; }; void ParsedExpression::Print() { // Print starting token start.Print(); CfgMathOperation *cop = ops; while (cop != 0) { printf("%c",cop->otype); cop->operand.Print(); cop = cop->next; } }; // Evaluate this expression UserVariable ParsedExpression::Evaluate(Event *input) { // Starting token.. UserVariable cur; start.Evaluate(&cur,input,1); // Setup cur with evaluation of start token // Move through the math.. CfgMathOperation *cop = ops; while (cop != 0) { // Evaluate the operand UserVariable tmp; cop->operand.Evaluate(&tmp,input,1); switch (cop->otype) { case '/' : cur /= tmp; break; case '*' : cur *= tmp; break; case '+' : cur += tmp; break; case '-' : cur -= tmp; break; default : printf("Evaluate Expression: Invalid math operand\n"); } cop = cop->next; } return cur; }; EventBinding::~EventBinding() { // Erase prototype event if (boundproto != 0) boundproto->RTDelete(); { // Erase dynamic token conditions DynamicToken *cur = tokenconds; while (cur != 0) { DynamicToken *tmp = cur->next; delete cur; cur = tmp; } } { // Erase dynamic parameter sets DynamicToken *cur = paramsets; while (cur != 0) { DynamicToken *tmp = cur->next; delete cur; cur = tmp; } } }; InputMatrix::InputMatrix(Fweelin *app) : vars(0), app(app) { // Setup input bindings array input_bind = new EventBinding **[T_EV_Last_Bindable]; for (int i = 0; i < T_EV_Last_Bindable; i++) input_bind[i] = 0; }; void InputMatrix::Start() { // Setup IM to listen!- this can not be done earlier because, during // configuration, EMG is not active // Listen for input events if (app->getEMG() == 0) { printf("INIT: Error: Event Manager not yet active!\n"); exit(1); } app->getEMG()->ListenEvent(this,0,T_EV_SetVariable); app->getEMG()->ListenEvent(this,0,T_EV_ToggleVariable); app->getEMG()->ListenEvent(this,0,T_EV_SplitVariableMSBLSB); app->getEMG()->ListenEvent(this,0,T_EV_LogFaderVolToLinear); app->getEMG()->ListenEvent(this,0,T_EV_ShowDebugInfo); app->getEMG()->ListenEvent(this,0,T_EV_AdjustMidiTranspose); // Input events int evnum = (int) EventType(T_EV_Last_Bindable); for (int i = 0; i < evnum; i++) if (i == (int) EventType(T_EV_GoSub) || i == (int) EventType(T_EV_StartInterface)) // Listen for GoSub/StartInterface, // but allow us to call ourselves because // that is what gosub does! app->getEMG()->ListenEvent(this,0,(EventType) i); else // Listen for input events, blocking receive of calls from ourself to // prevent infinite loops on event echo app->getEMG()->ListenEvent(this,0,(EventType) i,1); }; InputMatrix::~InputMatrix() { EventBinding *cur, *tmp; app->getEMG()->UnlistenEvent(this,0,T_EV_SetVariable); app->getEMG()->UnlistenEvent(this,0,T_EV_ToggleVariable); app->getEMG()->UnlistenEvent(this,0,T_EV_SplitVariableMSBLSB); app->getEMG()->UnlistenEvent(this,0,T_EV_LogFaderVolToLinear); app->getEMG()->UnlistenEvent(this,0,T_EV_ShowDebugInfo); app->getEMG()->UnlistenEvent(this,0,T_EV_AdjustMidiTranspose); // Input events int evnum = (int) EventType(T_EV_Last_Bindable); for (int i = 0; i < evnum; i++) { // Stop listening app->getEMG()->UnlistenEvent(this,0,(EventType) i); EventBinding **cur_hash = input_bind[i]; if (cur_hash != 0) { // & Free data structures int pidx = Event::GetParamIdxByType((EventType) i); if (pidx == -1) delete cur_hash; // No hash array, just one else { Event *tmpev = Event::GetEventByType((EventType) i,1); int hashsz = tmpev->GetParam(pidx).max_index+1; tmpev->RTDelete(); for (int j = 0; j < hashsz; j++) { cur = cur_hash[j]; while (cur != 0) { tmp = cur->next; delete cur; cur = tmp; } }; delete[] cur_hash; } } } delete[] input_bind; { UserVariable *cur = vars; while (cur != 0) { UserVariable *tmp = cur->next; delete cur; cur = tmp; } } }; // Removes leading and trailing spaces from string str // Modifies the end of string str and returns a pointer to the new // beginning after spaces char *InputMatrix::RemoveSpaces (char *str) { char *curptr = str; while (*curptr == ' ') curptr++; int n = strlen(str)-1; while (n > 0 && str[n] == ' ') { str[n] = '\0'; n--; } return curptr; }; // Adds one key to the given list based on the keysym name // Returns the new first pointer SDLKeyList *InputMatrix::AddOneKey (SDLKeyList *first, char *str) { // Remove leading and trailing spaces str = RemoveSpaces(str); SDLKey kh_sym = SDLIO::GetSDLKey(str); if (kh_sym != SDLK_UNKNOWN) { printf("'%s' + ",str); // Link it in! if (first == 0) first = new SDLKeyList(kh_sym); else { SDLKeyList *cur = first; while (cur->next != 0) cur = cur->next; cur->next = new SDLKeyList(kh_sym); } } else printf("** UNKNOWN KEY '%s' ** + ",str); return first; }; // Extracts named keys from the given string and returns a list // of the keysyms (named keys are separated by ,) SDLKeyList *InputMatrix::ExtractKeys (char *str) { char buf[255]; // Copy buf char *delim = ","; // Go through list of keys specified: char *cur = strpbrk(str,delim); int firstopidx; if (cur != 0) firstopidx = (long)cur-(long)str; else firstopidx = -1; // First key if (firstopidx == -1) { strncpy(buf,str,255); buf[254] = '\0'; } else { long len = MIN(firstopidx,254); memcpy(buf,str,len); buf[len] = '\0'; } // Parse it SDLKeyList *first = 0; first = AddOneKey(first,buf); while (cur != 0) { cur++; char *next = strpbrk(cur,delim); // Copy the key name long len; if (next != 0) len = (long)next-(long)cur; else len = strlen(cur); if (len >= 255) len = 254; memcpy(buf,cur,len); buf[len] = '\0'; // And parse it first = AddOneKey(first,buf); cur = next; } return first; }; void InputMatrix::SetVariable (UserVariable *var, char *value) { // First, parse the value based on the variable type switch (var->type) { case T_char : *var = (char) atoi(value); break; case T_int : *var = (int) atoi(value); break; case T_long : *var = (long) atol(value); break; case T_float : *var = (float) atof(value); break; case T_range : { char tmp[255]; strncpy(tmp,value,255); tmp[254] = '\0'; char *delim = strchr(tmp,'>'); if (delim != 0) { *delim = '\0'; delim++; } int lo = atoi(tmp), hi = (delim != 0 ? atoi(delim) : 0); Range r(lo,hi); *var = r; } break; case T_variable : case T_variableref : case T_invalid : printf("SetVariable: Invalid variable type!\n"); break; } }; void InputMatrix::CreateVariable (xmlNode *declare) { UserVariable *nw = new UserVariable(); // Name xmlChar *name = xmlGetProp(declare, (const xmlChar *)"var"); if (name == 0) { printf(FWEELIN_ERROR_COLOR_ON "*** INIT: WARNING: Variable name not specified when declaring.\n" FWEELIN_ERROR_COLOR_OFF); delete nw; return; } nw->name = new char[xmlStrlen(name)+1]; strcpy(nw->name,(char *)name); xmlFree(name); // Type xmlChar *type = xmlGetProp(declare, (const xmlChar *)"type"); if (type == 0) { printf(FWEELIN_ERROR_COLOR_ON "*** INIT: WARNING: Variable type not specified when declaring.\n" FWEELIN_ERROR_COLOR_OFF); delete nw; return; } nw->type = GetCoreDataType((char *) type); if (nw->type == T_invalid) { printf(FWEELIN_ERROR_COLOR_ON "*** INIT: WARNING: Invalid variable type.\n" FWEELIN_ERROR_COLOR_OFF); delete nw; return; } // Value xmlChar *value = xmlGetProp(declare, (const xmlChar *)"init"); if (value == 0) memset(nw->value,0,CFG_VAR_SIZE); else SetVariable(nw,(char *) value); // Insert into variable list nw->next = vars; vars = nw; printf(" declare: variable '%s' type '%s' value '%s'\n", nw->name, type, value); xmlFree(type); if (value != 0) xmlFree(value); }; // Scans in the given binding for settings for output event parameters // and sets us up to handle those void InputMatrix::CreateParameterSets (int interfaceid, EventBinding *bind, xmlNode *binding, Event *input, unsigned char contnum) { const static char *delim = " and "; const static char *str_base = "parameters"; int str_len = strlen(str_base)+4; char basebuf[str_len]; if (contnum == 0) sprintf(basebuf,"%s",str_base); else snprintf(basebuf,str_len,"%s%d",str_base,contnum); // Interface ID set explicitly? char interfaceset = 0; xmlChar *paramstr = xmlGetProp(binding, (const xmlChar *)basebuf); if (paramstr != 0) { // Config specifies param sets // Separate into each param set int buf_len = xmlStrlen(paramstr)+1; char *buf = new char[buf_len], *curp = (char *)paramstr, *nextp; do { nextp = strstr(curp,delim); int len = (nextp == 0 ? strlen(curp) : (int) (nextp-curp)); strncpy(buf,curp,buf_len); buf[len] = '\0'; // Now buf contains one parameter- parse it // Get LValue char *sep = strchr(buf,'='); if (sep != 0) { *sep = '\0'; // Remove leading and trailing spaces char *lv = RemoveSpaces(buf); // Find extra tokens not properly formatted if (strchr(sep+1,'=') != 0) { char *rv = RemoveSpaces(sep+1); printf(FWEELIN_ERROR_COLOR_ON "*** INIT: WARNING: Missing 'and' in parameters token: " "'%s=%s'\n" FWEELIN_ERROR_COLOR_OFF, lv,rv); } // Get RValue char *rv = RemoveSpaces(sep+1); // Check LValue against output parameters char found = 0; for (int i = 0; !found && i < bind->boundproto->GetNumParams(); i++) { EventParameter param = bind->boundproto->GetParam(i); if (!strcmp(lv,param.name)) { // Config specifies a param set for this parameter found = 1; if (!strcmp(param.name,INTERFACEID)) // Parameter is interface ID interfaceset = 1; // Parse RValue expression that specifies set. char enable_keynames = (bind->boundproto->GetType() == T_EV_Input_Key && !strcmp(param.name,"key")); ParsedExpression *exp = ParseExpression(rv, input, enable_keynames); // OK, check if expression is static if (exp->IsStatic()) { // Yup, so evaluate now UserVariable val = exp->Evaluate(input); // Store directly in output prototype event char *nwofs = (char *)bind->boundproto + param.ofs; // Data location StoreParameter(nwofs,param.dtype,&val); printf(" -set '%s' = ",param.name); val.Print(); printf("\n"); delete exp; } else { // Dynamic expression DynamicToken *nwset = new DynamicToken(); CfgToken token; token.cvt = T_CFG_EventParameter; token.evparam = param; nwset->token = token; nwset->exp = exp; nwset->next = bind->paramsets; bind->paramsets = nwset; printf(" -set '%s' = ",param.name); exp->Print(); printf("\n"); } } } // Debugging for invalid paramset if (!found) { printf(FWEELIN_ERROR_COLOR_ON "*** INIT: WARNING: Invalid parameters token: '%s=%s'\n" FWEELIN_ERROR_COLOR_OFF, lv,rv); } } // Next condition curp = (nextp == 0 ? 0 : nextp+strlen(delim)); } while (curp != 0); delete[] buf; xmlFree(paramstr); } if (!interfaceset) { // Interface ID not set explicitly as parameter- check if // the event we're binding for output has 'interfaceid'- // if so, set implicitly based on what interface this binding is // defined in char found = 0; for (int i = 0; !found && i < bind->boundproto->GetNumParams(); i++) { EventParameter param = bind->boundproto->GetParam(i); if (!strcmp(param.name,INTERFACEID)) { // Yup, set implicitly found = 1; char tmp[20]; snprintf(tmp,20,"%d",interfaceid); // Set from interface ID ParsedExpression *exp = ParseExpression(tmp, input); // OK, check if expression is static if (exp->IsStatic()) { // Yup, so evaluate now UserVariable val = exp->Evaluate(input); // Store directly in output prototype event char *nwofs = (char *)bind->boundproto + param.ofs; // Data location StoreParameter(nwofs,param.dtype,&val); printf(" -implicitly set '%s' = ",param.name); val.Print(); printf("\n"); delete exp; } else { // Dynamic expression DynamicToken *nwset = new DynamicToken(); CfgToken token; token.cvt = T_CFG_EventParameter; token.evparam = param; nwset->token = token; nwset->exp = exp; nwset->next = bind->paramsets; bind->paramsets = nwset; printf(" -implicitly set '%s' = ",param.name); exp->Print(); printf("\n"); } } } } }; // Scans in the given binding for conditions on input event parameters // or user variables, and sets us up to handle those // Returns the hash index for this binding, based on an indexed parameter, // or 0 if this binding is not indexed int InputMatrix::CreateConditions (int interfaceid, EventBinding *bind, xmlNode *binding, Event *input, int paramidx) { const static char *delim = " and "; // Return index int ret_index = 0; // Interface ID set explicitly? char interfaceset = 0; xmlChar *cond = xmlGetProp(binding, (const xmlChar *)"conditions"); if (cond != 0) { // Config specifies conditions // Separate into each condition int buf_len = xmlStrlen(cond)+1; char *buf = new char[buf_len], *curc = (char *)cond, *nextc; do { nextc = strstr(curc,delim); int len = (nextc == 0 ? strlen(curc) : (int) (nextc-curc)); strncpy(buf,curc,buf_len); buf[len] = '\0'; // Now buf contains one condition- parse it // Get LValue char *sep = strchr(buf,'='); if (sep != 0) { *sep = '\0'; // Remove leading and trailing spaces char *lv = RemoveSpaces(buf); // Find extra tokens not properly formatted if (strchr(sep+1,'=') != 0) { char *rv = RemoveSpaces(sep+1); printf(FWEELIN_ERROR_COLOR_ON "*** INIT: WARNING: Missing 'and' in conditions token: " "'%s=%s'\n" FWEELIN_ERROR_COLOR_OFF, lv,rv); } // Get RValue char *rv = RemoveSpaces(sep+1); // Check LValue against input parameters char found = 0; if (input != 0) { for (int i = 0; !found && i < input->GetNumParams(); i++) { EventParameter param = input->GetParam(i); if (!strcmp(lv,param.name)) { // Config specifies a condition for this parameter found = 1; if (!strcmp(param.name,INTERFACEID)) // Condition is interface ID interfaceset = 1; // Parse RValue expression that specifies condition. char enable_keynames = (input->GetType() == T_EV_Input_Key && !strcmp(param.name,"key")); ParsedExpression *exp = ParseExpression(rv, input, enable_keynames); // Is this parameter indexed? if (i == paramidx) { // OK, is the RValue static (ie can we store the binding // in a hash or do we need to compute during runtime)? if (exp->IsStatic()) { // Yup, so evaluate now UserVariable val = exp->Evaluate(input); // Return hash value ret_index = (int) val % param.max_index; } else { // Indexed parameter, but value is not static- // Use wildcard slot in hash ret_index = param.max_index; } } // Create DynamicToken to hold condition DynamicToken *nwcond = new DynamicToken(); CfgToken token; token.cvt = T_CFG_EventParameter; token.evparam = param; nwcond->token = token; nwcond->exp = exp; nwcond->next = bind->tokenconds; bind->tokenconds = nwcond; printf(" -condition '%s' == ",param.name); exp->Print(); if (enable_keynames) printf(" [%s]",rv); printf("\n"); } } } // Check LValue against user variables UserVariable *cur = vars; while (!found && cur != 0) { if (cur->name != 0) { if (!strcmp(lv,cur->name)) { // Config specifies a condition for this variable found = 1; // Parse RValue expression that specifies condition. ParsedExpression *exp = ParseExpression(rv, input); // Create DynamicToken to hold condition DynamicToken *nwcond = new DynamicToken(); CfgToken token; token.cvt = T_CFG_UserVariable; token.var = cur; nwcond->token = token; nwcond->exp = exp; nwcond->next = bind->tokenconds; bind->tokenconds = nwcond; printf(" -condition '%s' == ",cur->name); exp->Print(); printf("\n"); } } cur = cur->next; } // Debugging for invalid condition if (!found) { printf(FWEELIN_ERROR_COLOR_ON "*** INIT: WARNING: Invalid conditions token: '%s=%s'\n" FWEELIN_ERROR_COLOR_OFF, lv,rv); } } // Next condition curc = (nextc == 0 ? 0 : nextc+strlen(delim)); } while (curc != 0); delete[] buf; xmlFree(cond); } if (!interfaceset) { // Interface ID not set explicitly as condition- check if // the event we're binding for input has 'interfaceid'- // if so, set implicitly based on what interface this binding is // defined in char found = 0; for (int i = 0; !found && i < input->GetNumParams(); i++) { EventParameter param = input->GetParam(i); if (!strcmp(param.name,INTERFACEID)) { // Yup, set implicitly found = 1; char tmp[20]; snprintf(tmp,20,"%d",interfaceid); // Set from interface ID ParsedExpression *exp = ParseExpression(tmp, input); // Is this parameter indexed? if (i == paramidx) { // OK, is the RValue static (ie can we store the binding // in a hash or do we need to compute during runtime)? if (exp->IsStatic()) { // Yup, so evaluate now UserVariable val = exp->Evaluate(input); // Return hash value ret_index = (int) val % param.max_index; } else { // Indexed parameter, but value is not static- // Use wildcard slot in hash ret_index = param.max_index; } } // Create DynamicToken to hold condition DynamicToken *nwcond = new DynamicToken(); CfgToken token; token.cvt = T_CFG_EventParameter; token.evparam = param; nwcond->token = token; nwcond->exp = exp; nwcond->next = bind->tokenconds; bind->tokenconds = nwcond; printf(" -implicit condition '%s' == ",param.name); exp->Print(); printf("\n"); } } } // printf(" (hash %d)\n",ret_index); return ret_index; } void InputMatrix::CreateBinding (int interfaceid, xmlNode *binding) { EventBinding *nw = 0, *prev = 0; // Input event xmlChar *instr = xmlGetProp(binding, (const xmlChar *)"input"); if (instr == 0) { printf(FWEELIN_ERROR_COLOR_ON " [Invalid binding: No input event!]\n" FWEELIN_ERROR_COLOR_OFF); } else { printf(" binding: input '%s'", (char *) instr); // Go from the named event to an Event* prototype // Wait for an instance if none available Event *inproto = Event::GetEventByName((char *)instr,1); if (inproto == 0) printf(FWEELIN_ERROR_COLOR_ON " [Invalid event!]\n" FWEELIN_ERROR_COLOR_OFF); else { int typ = inproto->GetType(); if (typ >= T_EV_Last_Bindable) printf(FWEELIN_ERROR_COLOR_ON " [This event type can't be an input!]\n" FWEELIN_ERROR_COLOR_OFF); else { int pidx = Event::GetParamIdxByType((EventType) typ); if (input_bind[typ] == 0) { // No bindings yet for this type- set it up if (pidx == -1) { // No index for this type input_bind[typ] = new EventBinding *; input_bind[typ][0] = 0; } else { // Create hashtable for this type // Store one extra element for wildcard case int hashsz = inproto->GetParam(pidx).max_index+1; printf("\nCONFIG: Create '%s' parameter hashtable[%d] for input " "event '%s'\n",inproto->GetParam(pidx).name, hashsz,Event::GetEventName((EventType) typ)); input_bind[typ] = new EventBinding *[hashsz]; for (int i = 0; i < hashsz; i++) input_bind[typ][i] = 0; } } // OK, create a binding nw = new EventBinding(); // Echo? xmlChar *echo = xmlGetProp(binding, (const xmlChar *)"echo"); if (echo != 0) { nw->echo = atoi((char *)echo); if (nw->echo) printf(" (echo)"); xmlFree(echo); } // Conditions printf("\n"); int store_idx = CreateConditions(interfaceid, nw,binding,inproto,pidx); // Output event(s) unsigned char contnum = 0; char go = 1, first = 1; do { const static char *str_base = "output"; int str_len = strlen(str_base)+4; char buf[str_len]; if (contnum == 0) sprintf(buf,"%s",str_base); else snprintf(buf,str_len,"%s%d",str_base,contnum); xmlChar *outstr = xmlGetProp(binding, (const xmlChar *)buf); if (outstr == 0) { // Try at least "output" and "output1" if (contnum > 0) go = 0; } else { printf(" -> output '%s'", (char *) outstr); if (nw == 0) { // OK, we need another binding (continued) nw = new EventBinding(); } // Go from the named event to an Event* prototype // Wait for an instance if none available nw->boundproto = Event::GetEventByName((char *)outstr,1); if (nw->boundproto == 0) printf(FWEELIN_ERROR_COLOR_ON " [*** Invalid event! ***]\n" FWEELIN_ERROR_COLOR_OFF); else { printf("\n"); // Create parameter settings CreateParameterSets(interfaceid,nw,binding,inproto,contnum); if (prev != 0) { // So flag previous binding as 'continued' prev->continued = 1; // And link it up to this new binding //prev->next = nw; } // Store binding //printf("typ: %d store_idx: %d\n",typ,store_idx); //printf("ib_one: %p\n",input_bind[typ]); if (input_bind[typ][store_idx] == 0) input_bind[typ][store_idx] = nw; else { EventBinding *cur = input_bind[typ][store_idx]; while (cur->next != 0) cur = cur->next; cur->next = nw; } prev = nw; nw = 0; first = 0; } xmlFree(outstr); } contnum++; } while (go && contnum % 256); if (first) printf(FWEELIN_ERROR_COLOR_ON " [*** No output event specified! ***]\n" FWEELIN_ERROR_COLOR_OFF); if (nw != 0) { // Erase unstored binding delete nw; nw = 0; } } // Erase input prototype used for querying inproto->RTDelete(); } xmlFree(instr); } }; // Parses the given token (no math ops!) into dst // Correctly identifies when variables or event parameters are referenced // enable_keynames means that the token is first interpreted as a keyboard // key name void InputMatrix::ParseToken(char *str, CfgToken *dst, Event *ref, char enable_keynames) { //printf("parse token: %s\n",str); // First, remove leading or trailing spaces // Careful, we **overwrite 'str'** while (*str == ' ') str++; char *tmp = strchr(str,' '); if (tmp != 0) *tmp = '\0'; // Parse key name? if (enable_keynames) { int keysym = SDLIO::GetSDLKey((char *) str); if (keysym != SDLK_UNKNOWN && keysym >= SDLK_FIRST && keysym < SDLK_LAST) { // Token references a keyboard key! dst->cvt = T_CFG_Static; // Interpret as static dst->val.type = T_int; dst->val = keysym; return; } } // Check if token references an event parameter if (ref != 0) for (int j = 0; j < ref->GetNumParams(); j++) { EventParameter evparam = ref->GetParam(j); if (!strcmp(str,evparam.name)) { // Matching parameter dst->cvt = T_CFG_EventParameter; dst->evparam = evparam; return; } } // Check if token references a user variable UserVariable *cur = vars; while (cur != 0) { if (!strcmp(str,cur->name)) { // Matching user variable dst->cvt = T_CFG_UserVariable; dst->var = cur; return; } cur = cur->next; } // No matches to variables or parameters, interpret as static token char *ascii_scalar = " 0123456789.>,"; if (strlen(str) > 0 && strpbrk(str,ascii_scalar) != str) { // Wait a second, this isn't a scalar, it probably has letters! printf(FWEELIN_ERROR_COLOR_ON "\n*** INIT: WARNING: Invalid token: %s\n" FWEELIN_ERROR_COLOR_OFF, str); dst->cvt = T_CFG_None; dst->var = 0; return; } // Figure out what type of static the token is dst->cvt = T_CFG_Static; char *rng_delim = strchr(str,'>'); if (rng_delim != 0) { // Range character found dst->val.type = T_range; } else { char *float_delim = strchr(str,'.'); if (float_delim != 0) { // Float character found dst->val.type = T_float; } else { // Assume scalar is 'int'-- // This affects runtime performance in that all dynamic evaluations // of the parent expression are computed using this type! dst->val.type = T_int; } } // Given the type, set the variable! SetVariable(&(dst->val),str); }; // Parses a given expression string, extracting tokens // for example: 'VAR_curnote+12' references variable VAR_curnote and // creates 1 math operation +12 // The expression may also reference parameters in event 'ref' // and these references will be extracted ParsedExpression *InputMatrix::ParseExpression(char *str, Event *ref, char enable_keynames) { char opstr[CfgMathOperation::numops+1]; char buf[255]; // Copy buf CfgMathOperation *first = 0, *last = 0; signed int firstopidx = -1; //printf("parse expression: %s\n",str); // Create list of operators int i; for (i = 0; i < CfgMathOperation::numops; i++) opstr[i] = CfgMathOperation::operators[i]; opstr[i] = '\0'; // Find the first occurance of an operator in string str char *cur = strpbrk(str,opstr); if (cur != 0) firstopidx = (long)cur-(long)str; else firstopidx = -1; // Now, begin creating parsed expression ParsedExpression *exp = new ParsedExpression(); // Parse beginning token if (firstopidx == -1) { strncpy(buf,str,255); buf[254] = '\0'; } else { long len = MIN(firstopidx,254); memcpy(buf,str,len); buf[len] = '\0'; } ParseToken(buf,&(exp->start),ref,enable_keynames); while (cur != 0) { char op = *cur; // Store operand cur++; char *next = strpbrk(cur,opstr); // Copy the operand long len; if (next != 0) len = (long)next-(long)cur; else len = strlen(cur); if (len >= 255) len = 254; memcpy(buf,cur,len); buf[len] = '\0'; // Now we have operator 'op' and operand in 'buf' CfgMathOperation *nw = new CfgMathOperation(); nw->otype = op; ParseToken(buf,&(nw->operand),ref,enable_keynames); if (first == 0) first = last = nw; else { last->next = nw; last = nw; } cur = next; } exp->ops = first; return exp; }; // Stores in ptr the value val given that ptr is of type dtype void InputMatrix::StoreParameter(char *ptr, CoreDataType dtype, UserVariable *val) { switch (dtype) { case T_char : *ptr = (char) *val; break; case T_int : *((int *) ptr) = (int) *val; break; case T_long : *((long *) ptr) = (long) *val; break; case T_float : *((float *) ptr) = (float) *val; break; case T_range : *((Range *) ptr) = (Range) *val; break; case T_variable : *((UserVariable *) ptr) = *val; break; case T_variableref : *((UserVariable **) ptr) = val; break; default : printf("Unrecognized event parameter type!\n"); break; } }; // Using the eventbinding's parametersets as a template, dynamically // sets parameters in the output event void InputMatrix::SetDynamicParameters(Event *input, Event *output, EventBinding *bind) { // Go through the settings DynamicToken *cur = bind->paramsets; while (cur != 0) { if (cur->token.cvt == T_CFG_EventParameter) { // Get ptr to output parameter char *outofs = (char *)output + cur->token.evparam.ofs; if (cur->token.evparam.dtype == T_variableref) { // Output event wants a reference to a variable-- not an evaluation! // See if the starting token is a UserVariable if (cur->exp->start.cvt == T_CFG_UserVariable) StoreParameter(outofs,T_variableref,cur->exp->start.var); else { printf("CONFIG: SetDynamicParameters: Event expects UserVariable but" " another type is given by config!\n"); StoreParameter(outofs,T_variableref,0); } } else { // Evaluate expression with dynamic input & variable parameters UserVariable val = cur->exp->Evaluate(input); // Store the output data correctly StoreParameter(outofs,cur->token.evparam.dtype,&val); } } else printf("CONFIG: SetDynamicParameters: Unknown destination in token!\n"); cur = cur->next; } }; // Are the conditions in the EventBinding bind matched by the // given input event and user variables? char InputMatrix::CheckConditions(Event *input, EventBinding *bind) { char match = 1; // Check dynamic token conditions DynamicToken *cur = bind->tokenconds; while (cur != 0 && match) { // Compare evaluations of token and expression UserVariable cmp1; cur->token.Evaluate(&cmp1,input,1); UserVariable cmp2 = cur->exp->Evaluate(input); if (cmp1 != cmp2) match = 0; else cur = cur->next; } return match; }; // Traverses through the list of event bindings beginning at 'start' // looking for a binding that matches current user variables and input // event 'ev' EventBinding *InputMatrix::MatchBinding(Event *ev, EventBinding *start) { #if 0 { EventBinding *cur = start; int count = 0; while (cur != 0) { count++; cur = cur->next; } printf(" [SCAN] Hash size: %d",count); } #endif EventBinding *cur = start; char go = 1, prevcont = 0; while (cur != 0 && go) { if (!prevcont && CheckConditions(ev,cur)) go = 0; else { prevcont = cur->continued; cur = cur->next; } } #if 0 if (cur != 0) printf(" HIT!\n"); else printf("\n"); #endif return cur; }; void InputMatrix::ReceiveEvent(Event *ev, EventProducer *from) { char echo = 1; EventBinding *match = 0; // Input events int i = ev->GetType(); if (ev->GetType() < T_EV_Last_Bindable) { EventHook *ev_hook = app->getCFG()->ev_hook; if (ev_hook == 0 || !ev_hook->HookEvent(ev,from)) { if (CRITTERS && ev->GetType() == T_EV_GoSub) printf("CONFIG: GoSub(%d)\n",((GoSubEvent *) ev)->sub); if (input_bind[i] != 0) { EventBinding **cur_hash = input_bind[i]; // Find indexed parameter EventBinding *search = 0; EventParameter param; int pidx = Event::GetParamIdxByType((EventType) i); if (pidx == -1) { //printf("noidx "); search = *cur_hash; } else { param = ev->GetParam(pidx); if (param.dtype != T_int) { // Error! printf("CONFIG: Error: Indexed event parameters must be " "integers!\n"); } else { // Get value of indexed parameter in input event char *evofs = (char *)ev + param.ofs; int hashval = *((int *) evofs) % param.max_index; //printf("hashidx: %d ",hashval); // Search in the right list of bindings- based on the hash index search = cur_hash[hashval]; } } // Now, check for matching binding in the search list if (search != 0) match = MatchBinding(ev,search); if (match == 0 && pidx != -1 && cur_hash[param.max_index] != 0) // OK, no match on the exact hash! -- check wildcards stored at the // end of the hashtable match = MatchBinding(ev,cur_hash[param.max_index]); } // First matching binding, check if she says to echo if (match != 0) echo = match->echo; else if (ev->GetType() == T_EV_GoSub || ev->GetType() == T_EV_StartInterface) echo = 0; // Never echo back unmatched GoSub/StartInterface- // we'll get into a loop // printf("CONFIG: Binding match %p (echo %d)\n",match,echo); while (match != 0) { // So we have a binding.. trigger the bound event! Event *shot = (Event *) match->boundproto->RTNew(); if (shot == 0) printf("CONFIG: WARNING: Can't send event- RTNew() failed\n"); else { *shot = *match->boundproto; // Copy from prototype SetDynamicParameters(ev,shot,match); app->getEMG()->BroadcastEventNow(shot, this); } // Trigger any continued bindings.. if (match->continued) match = match->next; else match = 0; } // Echo the incoming event back? if (echo) { Event *echo = (Event *) ev->RTNew(); if (echo == 0) printf("CONFIG: WARNING: Can't send event- RTNew() failed\n"); else { *echo = *ev; // Copy from incoming input echo->echo = 1; // Set echo flag app->getEMG()->BroadcastEventNow(echo, this); } } } else if (ev_hook != 0) { // Hook swallowed event if (CRITTERS) printf("CONFIG: Hook swallowed event (type %d).\n",ev->GetType()); } } else { switch (ev->GetType()) { // *** Internal events case T_EV_SetVariable : { SetVariableEvent *sv = (SetVariableEvent *) ev; // Set the variable to the given value if (sv->var == 0 || sv->var->IsSystemVariable()) printf(" SetVariableEvent: Invalid variable!\n"); else { // Check if variable change is within maxjump char goset = 1; if (sv->maxjumpcheck) { // Maxjump check enabled // Compute change in variable UserVariable jump = sv->var->GetDelta(sv->value); if (jump > sv->maxjump) goset = 0; // Don't set variable } if (goset) { if (CRITTERS) { printf("CONFIG: SetVariable: "); sv->var->Print(); printf(" -> "); sv->var->SetFrom(sv->value); sv->var->Print(); printf("\n"); } else sv->var->SetFrom(sv->value); } else { // Don't set variable if (CRITTERS) { printf("CONFIG: SetVariable: "); sv->var->Print(); printf(" -> [NOT SET- Max jump exceeded!]\n"); } } } } break; case T_EV_ToggleVariable : { ToggleVariableEvent *tv = (ToggleVariableEvent *) ev; // Set the variable to the given value if (tv->var == 0 || tv->var->IsSystemVariable()) printf(" ToggleVariableEvent: Invalid variable!\n"); else { int tmp = (int) (*(tv->var)); tmp++; if (tmp > tv->maxvalue) tmp = tv->minvalue; UserVariable v; v.type = T_int; v = tmp; if (CRITTERS) { printf("CONFIG: ToggleVariable: "); tv->var->Print(); printf(" -> "); tv->var->SetFrom(v); tv->var->Print(); printf("\n"); } else tv->var->SetFrom(v); } } break; case T_EV_SplitVariableMSBLSB : { SplitVariableMSBLSBEvent *sv = (SplitVariableMSBLSBEvent *) ev; // Set the MSB/LSB from the given variable if (sv->msb == 0 || sv->msb->IsSystemVariable()) printf(" SplitVariableMSBLSBEvent: 'msb': Invalid variable!\n"); else if (sv->lsb == 0 || sv->lsb->IsSystemVariable()) printf(" SplitVariableMSBLSBEvent: 'lsb': Invalid variable!\n"); else { int value_of_var = (int) sv->var, msb = (value_of_var & 0xFF00) >> 8, lsb = (value_of_var & 0x00FF); *sv->msb = msb; *sv->lsb = lsb; if (CRITTERS) printf("CONFIG: SplitVariableMSBLSB: var: %d split and stored into: msb: %d lsb: %d\n",value_of_var,msb,lsb); } } break; case T_EV_LogFaderVolToLinear : { LogFaderVolToLinearEvent *sv = (LogFaderVolToLinearEvent *) ev; // Set the variable based on the linear version of the given value if (sv->var == 0 || sv->var->IsSystemVariable()) printf(" LogFaderVolToLinearEvent: Invalid variable!\n"); else { // Get fadervol float fv = (float) sv->fadervol, db = AudioLevel::fader_to_dB(fv, app->getCFG()->GetFaderMaxDB()), lin = DB2LIN(db); lin *= sv->scale; if (sv->var->GetType() != T_float) printf("CONFIG: LogFaderVolToLinear 'var' must be of type float."); else { if (CRITTERS) printf("CONFIG: LogFaderVolToLinear: Fadervol: %f -> dB: %f -> linear (scale: %f): %f\n", fv,db,sv->scale,lin); *sv->var = lin; } } } break; case T_EV_ShowDebugInfo : { ShowDebugInfoEvent *dev = (ShowDebugInfoEvent *) ev; app->getCFG()->showdebug = dev->show; if (CRITTERS) printf("CONFIG: show debugging info = %s\n", (dev->show ? "on" : "off")); } break; case T_EV_AdjustMidiTranspose : { AdjustMidiTransposeEvent *tev = (AdjustMidiTransposeEvent *) ev; app->getCFG()->transpose += tev->adjust; if (CRITTERS) printf("CONFIG: adjust transpose midi by %d: transpose = %d.\n", tev->adjust,app->getCFG()->transpose); } break; default: break; } } }; void FloConfig::ConfigureEventBindings(xmlDocPtr /*doc*/, xmlNode *events, int interfaceid, char firstpass) { xmlNode *cur_node; for (cur_node = events->children; cur_node != NULL; cur_node = cur_node->next) { // Check for a help node if (firstpass) CheckForHelp(cur_node); // First pass, only configure declarations if (firstpass && !xmlStrcmp(cur_node->name, (const xmlChar *)"declare")) { // Variable declaration im.CreateVariable(cur_node); } else if (!firstpass && !xmlStrcmp(cur_node->name, (const xmlChar *)"binding")) { // Binding im.CreateBinding(interfaceid,cur_node); } } }; void FloConfig::ConfigureBasics(xmlDocPtr /*doc*/, xmlNode *gen) { xmlNode *cur_node; for (cur_node = gen->children; cur_node != NULL; cur_node = cur_node->next) { // Check for a help node CheckForHelp(cur_node); if ((!xmlStrcmp(cur_node->name, (const xmlChar *)"var"))) { // System variable setting // Check xmlChar *n = 0; if ((n = xmlGetProp(cur_node, (const xmlChar *)"numloopids")) != 0) { num_triggers = atoi((char *) n); if (num_triggers < 1) num_triggers = 1; printf("CONFIG: Starting with %d triggers.\n",num_triggers); } else if ((n = xmlGetProp(cur_node, (const xmlChar *)"maxsnapshots")) != 0) { max_snapshots = atoi((char *) n); if (max_snapshots < 1) max_snapshots = 1; printf("CONFIG: Starting with %d max snapshots.\n",max_snapshots); } else if ((n = xmlGetProp(cur_node, (const xmlChar *)"librarypath")) != 0) { if (xmlStrchr(n,'~') == n) { // Reference to home dir char *homedir = getenv("HOME"); librarypath = new char[strlen(homedir)+xmlStrlen(n)+1]; strcpy(librarypath,homedir); strcat(librarypath,(char *) &n[1]); } else { librarypath = new char[xmlStrlen(n)+1]; strcpy(librarypath,(char *) n); } char *ptr = strrchr(librarypath,'/'); if (ptr != 0 && strlen(ptr) == 1) // Trailing backslash? // Remove *ptr = '\0'; printf("CONFIG: Library path: '%s'\n",librarypath); // Ensure library path exists if (mkdir(librarypath,S_IRWXU)) { if (errno != EEXIST) { printf("DISK: Error %d creating library folder '%s'- " "do you have write permission there?\n", errno,librarypath); } } else printf("DISK: Created new library @ '%s'\n",librarypath); } else if ((n = xmlGetProp(cur_node, (const xmlChar *)"maxplayvol")) != 0) { maxplayvol = atof((char *) n); if (maxplayvol < 0.0) maxplayvol = 0.0; if (maxplayvol != 0.0) printf("CONFIG: Maximum play volume set to %.2f%%.\n", maxplayvol*100); else printf("CONFIG: No maximum play volume set! Watch your levels!\n"); } else if ((n = xmlGetProp(cur_node, (const xmlChar *)"maxlimitergain")) != 0) { maxlimitergain = atof((char *) n); if (maxlimitergain < 0.0) maxlimitergain = 1.0; printf("CONFIG: Maximum limiter gain set to %.2f%%.\n", maxlimitergain*100); } else if ((n = xmlGetProp(cur_node, (const xmlChar *)"limiterthreshhold")) != 0) { limiterthreshhold = atof((char *) n); if (limiterthreshhold < 0.0) limiterthreshhold = 0.9; printf("CONFIG: Limiter threshhold set to %.2f%%.\n", limiterthreshhold*100); } else if ((n = xmlGetProp(cur_node, (const xmlChar *)"limiterreleaserate")) != 0) { limiterreleaserate = atof((char *) n); if (limiterreleaserate < 0.0) limiterreleaserate = 0.000020; printf("CONFIG: Limiter release rate set to %.2f%%.\n", limiterreleaserate*100); } else if ((n = xmlGetProp(cur_node, (const xmlChar *)"fadermaxdb")) != 0) { fadermaxdb = atof((char *) n); printf("CONFIG: Fader max dB set to %.2f.\n", fadermaxdb); } else if ((n = xmlGetProp(cur_node, (const xmlChar *)"loopoutformat")) != 0) { loopoutformat = GetCodecFromName((const char *) n); if (loopoutformat == UNKNOWN) printf(FWEELIN_ERROR_COLOR_ON "CONFIG: Invalid loop output format: %s\n" FWEELIN_ERROR_COLOR_OFF,n); else printf("CONFIG: Loop out format is: %s\n", GetCodecName(loopoutformat)); } else if ((n = xmlGetProp(cur_node, (const xmlChar *)"streamoutformat")) != 0) { streamoutformat = GetCodecFromName((const char *) n); if (streamoutformat == UNKNOWN) printf(FWEELIN_ERROR_COLOR_ON "CONFIG: Invalid stream output format: %s\n" FWEELIN_ERROR_COLOR_OFF,n); else printf("CONFIG: Stream out format is: %s\n", GetCodecName(streamoutformat)); } else if ((n = xmlGetProp(cur_node, (const xmlChar *)"oggquality")) != 0) { float q = atof((char *) n); if (q <= 0.0) printf(FWEELIN_ERROR_COLOR_ON "CONFIG: Invalid OGG quality: %f\n" FWEELIN_ERROR_COLOR_OFF,q); else { vorbis_encode_quality = q; printf("CONFIG: OGG Quality: %f\n",vorbis_encode_quality); } } else if ((n = xmlGetProp(cur_node, (const xmlChar *)"midiouts")) != 0) { midiouts = atoi((char *) n); if (midiouts < 1) midiouts = 1; printf("CONFIG: Config sets %d MIDI outputs.\n",midiouts); } else if ((n = xmlGetProp(cur_node, (const xmlChar *)"midisyncouts")) != 0) { msouts = ExtractArrayInt((char *)n, &msnumouts); printf("CONFIG: Set %d MIDI sync outputs: ",msnumouts); for (int i = 0; i < msnumouts; i++) { printf("%d ",msouts[i]); msouts[i]--; // Adjust so that 0 is the first output } printf("\n"); } else if ((n = xmlGetProp(cur_node, (const xmlChar *)"streamfinalmix")) != 0) { if (n[0] == 'Y' || n[0] == 'y') stream_final = 1; else stream_final = 0; printf("CONFIG: %s final stream\n",(stream_final ? "Enable" : "Disable")); } else if ((n = xmlGetProp(cur_node, (const xmlChar *)"streamloopmix")) != 0) { if (n[0] == 'Y' || n[0] == 'y') stream_loops = 1; else stream_loops = 0; printf("CONFIG: %s loop stream\n",(stream_loops ? "Enable" : "Disable")); } else if ((n = xmlGetProp(cur_node, (const xmlChar *)"streaminputs")) != 0) { int intaudioins = AudioBuffers::GetIntAudioIns(); stream_inputs = new char[extaudioins + intaudioins]; // Assign stream status for each input for (int i = 0; i < extaudioins + intaudioins; i++) { if (i < xmlStrlen(n)) { switch (n[i]) { case 'Y' : case 'y' : stream_inputs[i] = 1; printf("CONFIG: Input #%d is streamed\n",i+1); break; case 'N' : case 'n' : stream_inputs[i] = 0; printf("CONFIG: Input #%d is not streamed\n",i+1); break; default: printf(FWEELIN_ERROR_COLOR_ON "*** INIT: WARNING: I don't understand streaming input #%d = %c\n" "Assuming input is not streamed.\n" FWEELIN_ERROR_COLOR_OFF, i+1,n[i]); stream_inputs[i] = 0; break; } } else stream_inputs[i] = 0; // Assume not streamed } } else if ((n = xmlGetProp(cur_node, (const xmlChar *)"audioinputmonitoring")) != 0) { int intaudioins = AudioBuffers::GetIntAudioIns(); monitor_inputs = new char[extaudioins + intaudioins]; // Assign stereo/mono and create input variables for (int i = 0; i < extaudioins + intaudioins; i++) { if (i < extaudioins && i < xmlStrlen(n)) { switch (n[i]) { case 'Y' : case 'y' : monitor_inputs[i] = 1; printf("CONFIG: Input #%d is monitored\n",i+1); break; case 'N' : case 'n' : monitor_inputs[i] = 0; printf("CONFIG: Input #%d is not monitored\n",i+1); break; default: printf(FWEELIN_ERROR_COLOR_ON "*** INIT: WARNING: I don't understand input monitoring #%d = %c\n" "Assuming input is monitored.\n" FWEELIN_ERROR_COLOR_OFF, i+1,n[i]); monitor_inputs[i] = 1; break; } } else monitor_inputs[i] = 1; // Assume monitoring } } else if ((n = xmlGetProp(cur_node, (const xmlChar *)"externalaudioinputs")) != 0) { // # of inputs extaudioins = xmlStrlen(n); if (extaudioins < 1) extaudioins = 1; int intaudioins = AudioBuffers::GetIntAudioIns(); printf("CONFIG: Starting with %d external audio input(s)\n" " and %d internal audio input(s)--\n", extaudioins,intaudioins); ms_inputs = new char[extaudioins + intaudioins]; // Assign stereo/mono and create input variables char tmp[255]; for (int i = 0; i < extaudioins + intaudioins; i++) { if (i < extaudioins) { switch (n[i]) { case 'S' : case 's' : ms_inputs[i] = 1; printf("CONFIG: Input #%d is stereo\n",i+1); break; case 'M' : case 'm' : ms_inputs[i] = 0; printf("CONFIG: Input #%d is mono\n",i+1); break; default: printf(FWEELIN_ERROR_COLOR_ON "*** INIT: WARNING: I don't understand input #%d = %c\n" "Assuming input is mono.\n" FWEELIN_ERROR_COLOR_OFF, i+1,n[i]); ms_inputs[i] = 0; break; } } else ms_inputs[i] = 0; snprintf(tmp,255,"SYSTEM_in_%d_volume",i+1); AddEmptyVariable(tmp); snprintf(tmp,255,"SYSTEM_in_%d_record",i+1); AddEmptyVariable(tmp); snprintf(tmp,255,"SYSTEM_in_%d_peak",i+1); AddEmptyVariable(tmp); } } if (n != 0) xmlFree(n); } #if USE_FLUIDSYNTH else if ((!xmlStrcmp(cur_node->name, (const xmlChar *)"fluidsynth"))) { // FluidSynth setting // Check xmlChar *n = 0; if ((n = xmlGetProp(cur_node, (const xmlChar *)"param")) != 0) { xmlChar *val = 0; if ((val = xmlGetProp(cur_node, (const xmlChar *)"setint")) != 0) { AddFluidParam(new FluidSynthParam_Int((char *)n, atoi((char *)val))); } else if ((val = xmlGetProp(cur_node, (const xmlChar *)"setnum")) != 0) { AddFluidParam(new FluidSynthParam_Num((char *)n, atof((char *)val))); } else if ((val = xmlGetProp(cur_node, (const xmlChar *)"setstr")) != 0) { AddFluidParam(new FluidSynthParam_Str((char *)n,(char *)val)); } if (val != 0) xmlFree(val); } else if ((n = xmlGetProp(cur_node, (const xmlChar *)"soundfont")) != 0) { AddFluidFont(new FluidSynthSoundFont((char *)n)); } else if ((n = xmlGetProp(cur_node, (const xmlChar *)"interpolation")) != 0) { fsinterp = atoi((char *)n); } else if ((n = xmlGetProp(cur_node, (const xmlChar *)"tuning")) != 0) { fstuning = atof((char *)n); } else if ((n = xmlGetProp(cur_node, (const xmlChar *)"channel")) != 0) { fschannel = atoi((char *)n); } else if ((n = xmlGetProp(cur_node, (const xmlChar *)"stereo")) != 0) { fsstereo = atoi((char *)n); if (ms_inputs != 0) { ms_inputs[extaudioins] = fsstereo; printf("CONFIG: FluidSynth running in %s\n", (fsstereo ? "stereo" : "mono")); } else printf(FWEELIN_ERROR_COLOR_ON "*** INIT: WARNING: FluidSynth stereo can't be set before " "externalaudioinputs is set- check config!\n" FWEELIN_ERROR_COLOR_OFF); } if (n != 0) xmlFree(n); } #endif } // Print whether master is stereo printf("CONFIG: FreeWheeling is running in %s", (IsStereoMaster() ? "stereo.\n * Please be aware, this " "significantly increases memory usage. *\n" : "mono.\n")); }; char FloConfig::IsStereoMaster() { // Check inputs int numins = extaudioins + AudioBuffers::GetIntAudioIns(); for (int i = 0; i < numins; i++) if (ms_inputs[i]) return 1; // Yep, one input is stereo, so we have to run in stereo // No stereo inputs, run in mono! return 0; }; // Extracts an array of floats (delimited by character delim_char) // from the given string- returns size of array in 'size' float *FloConfig::ExtractArray(char *n, int *size, char delim_char) { char buf[255]; strncpy(buf,n,254); buf[254] = '\0'; char *delim = buf; *size = 0; while (delim != 0) { (*size)++; delim = strchr(delim+1,delim_char); } if (*size == 0) return 0; float *array = new float[*size]; delim = buf; int i = 0; while (i < *size) { char *nd = strchr(delim,delim_char); if (nd != 0) { *nd = '\0'; nd++; } //printf("%d: %s\n",i,delim); array[i++] = atof(delim); delim = nd; } return array; }; int *FloConfig::ExtractArrayInt(char *n, int *size, char delim_char) { char buf[255]; strncpy(buf,n,254); buf[254] = '\0'; char *delim = buf; *size = 0; while (delim != 0) { (*size)++; delim = strchr(delim+1,delim_char); } if (*size == 0) return 0; int *array = new int[*size]; delim = buf; int i = 0; while (i < *size) { char *nd = strchr(delim,delim_char); if (nd != 0) { *nd = '\0'; nd++; } //printf("%d: %s\n",i,delim); array[i++] = atoi(delim); delim = nd; } return array; }; void FloConfig::ConfigureElement(xmlDocPtr /*doc*/, xmlNode *elemn, FloLayoutElement *elem, float xscale, float yscale) { xmlNode *cur_node; for (cur_node = elemn->children; cur_node != NULL; cur_node = cur_node->next) { // Check for a help node CheckForHelp(cur_node); if ((!xmlStrcmp(cur_node->name, (const xmlChar *)"box"))) { // Box declaration FloLayoutBox *nw = new FloLayoutBox(); printf(" Box: "); xmlChar *n = xmlGetProp(cur_node, (const xmlChar *)"outline"); if (n != 0) { nw->lineleft = (strchr((char *)n,'L') ? 1 : 0); nw->linetop = (strchr((char *)n,'T') ? 1 : 0); nw->lineright = (strchr((char *)n,'R') ? 1 : 0); nw->linebottom = (strchr((char *)n,'B') ? 1 : 0); printf("outline (L%d,T%d,R%d,B%d) ",nw->lineleft,nw->linetop, nw->lineright,nw->linebottom); xmlFree(n); } // Position n = xmlGetProp(cur_node, (const xmlChar *)"pos"); if (n != 0) { int cs; float *coord = ExtractArray((char *)n, &cs); if (cs >= 4) { nw->left = (int) round(elem->bx + XCvtf(xscale*coord[0])); nw->top = (int) round(elem->by + YCvtf(yscale*coord[1])); nw->right = (int) round(elem->bx + XCvtf(xscale*coord[2])); nw->bottom = (int) round(elem->by + YCvtf(yscale*coord[3])); printf("dim (%d,%d)-(%d,%d) ",nw->left,nw->top, nw->right,nw->bottom); delete[] coord; } xmlFree(n); } // Link in the new geometry if (elem->geo == 0) elem->geo = nw; else { FloLayoutElementGeometry *cur = elem->geo; while (cur->next != 0) cur = cur->next; cur->next = nw; } printf("\n"); } } }; void FloConfig::ConfigureLayout(xmlDocPtr doc, xmlNode *layn, FloLayout *lay, float xscale, float yscale) { xmlNode *cur_node; for (cur_node = layn->children; cur_node != NULL; cur_node = cur_node->next) { // Check for a help node CheckForHelp(cur_node); if ((!xmlStrcmp(cur_node->name, (const xmlChar *)"element"))) { // Element declaration FloLayoutElement *nw = new FloLayoutElement(); printf(" Element: "); xmlChar *n = xmlGetProp(cur_node, (const xmlChar *)"id"); if (n != 0) { nw->id = atoi((char *)n); printf("#%d ",nw->id); xmlFree(n); } n = xmlGetProp(cur_node, (const xmlChar *)"name"); if (n != 0) { nw->name = new char[xmlStrlen(n)+1]; strcpy(nw->name,(char*)n); printf("'%s' ",nw->name); xmlFree(n); } // Base n = xmlGetProp(cur_node, (const xmlChar *)"base"); if (n != 0) { int cs; float *coord = ExtractArray((char *)n, &cs); if (cs) { nw->bx = lay->xpos + XCvtf(xscale*coord[0]); nw->by = lay->ypos + YCvtf(yscale*coord[1]); printf("@ (%d,%d) ",(int) nw->bx,(int) nw->by); delete[] coord; } xmlFree(n); } // Name position n = xmlGetProp(cur_node, (const xmlChar *)"namepos"); if (n != 0) { int cs; float *coord = ExtractArray((char *)n, &cs); if (cs) { nw->nxpos = (int) round(nw->bx + XCvtf(xscale*coord[0])); nw->nypos = (int) round(nw->by + YCvtf(yscale*coord[1])); printf("Name@ (%d,%d) ",nw->nxpos,nw->nypos); delete[] coord; } xmlFree(n); } // Loop position n = xmlGetProp(cur_node, (const xmlChar *)"looppos"); if (n != 0) { int cs; float *coord = ExtractArray((char *)n, &cs); if (cs) { nw->loopx = (int) round(nw->bx + XCvtf(xscale*coord[0])); nw->loopy = (int) round(nw->by + YCvtf(yscale*coord[1])); printf("looppos (%d,%d) ",nw->loopx,nw->loopy); delete[] coord; } xmlFree(n); } n = xmlGetProp(cur_node, (const xmlChar *)"loopsize"); if (n != 0) { nw->loopsize = MIN(XCvt(MIN(xscale,yscale)*atof((char *)n)), YCvt(MIN(xscale,yscale)*atof((char *)n))); printf("loopsize %d ",nw->loopsize); xmlFree(n); } // Link in the new element if (lay->elems == 0) lay->elems = nw; else { FloLayoutElement *cur = lay->elems; while (cur->next != 0) cur = cur->next; cur->next = nw; } printf("\n"); // Now populate the element with geometries.. ConfigureElement(doc,cur_node,nw,xscale,yscale); } } }; void FloConfig::ConfigurePatchBanks(xmlNode *pb, PatchBrowser *br) { // The patch browser can contain a number of patchbanks. // Configure them. for (xmlNode *cur_node = pb->children; cur_node != NULL; cur_node = cur_node->next) { if ((!xmlStrcmp(cur_node->name, (const xmlChar *)"patchbank"))) { // Get patchbank-wide bypass settings char pb_bypasscc = 0; float pb_bypasstime1 = 0.0, pb_bypasstime2 = 10.0; xmlChar *n = 0; if ((n = xmlGetProp(cur_node, (const xmlChar *)"bypasscc")) != 0) { pb_bypasscc = atoi((char *) n); xmlFree(n); } if ((n = xmlGetProp(cur_node, (const xmlChar *)"bypasstime1")) != 0) { pb_bypasstime1 = atof((char *) n); xmlFree(n); } if ((n = xmlGetProp(cur_node, (const xmlChar *)"bypasstime2")) != 0) { pb_bypasstime2 = atof((char *) n); xmlFree(n); } // Get MIDI port int pb_mport = 0; if ((n = xmlGetProp(cur_node, (const xmlChar *)"midiport")) != 0) { pb_mport = atoi((char *) n); xmlFree(n); } // Patchbank tag // Get MIDI port int pb_tag = -1; if ((n = xmlGetProp(cur_node, (const xmlChar *)"tag")) != 0) { pb_tag = atoi((char *) n); xmlFree(n); } // Separate channels into distinct patchbanks? char sepchan = 0; if ((n = xmlGetProp(cur_node, (const xmlChar *)"separatechannels")) != 0) { sepchan = atoi((char *) n); xmlFree(n); } // Suppress bank/program changes when changing patches? // (ie only change channel) char suppresschg = 0; if ((n = xmlGetProp(cur_node, (const xmlChar *)"suppressprogramchanges")) != 0) { suppresschg = atoi((char *) n); xmlFree(n); } xmlChar *pb_patches = xmlGetProp(cur_node, (const xmlChar *)"patches"); if (pb_patches != 0) { // PatchBank file defined xmlDocPtr pb_doc; // Try both ~/.fweelin and fweelin data dir char *buf = PrepareLoadConfigFile((char *) pb_patches,0); // Load and parse pb_doc = (buf == 0 ? 0 : xmlParseFile(buf)); if (pb_doc == 0) printf(FWEELIN_ERROR_COLOR_ON "\n*** INIT: ERROR: Problem parsing patches file '%s'.\n" FWEELIN_ERROR_COLOR_OFF, pb_patches); else { xmlNode *pb_root = xmlDocGetRootElement(pb_doc); if (!pb_root || !pb_root->name || xmlStrcmp(pb_root->name,(const xmlChar *) "patchlist")) printf(FWEELIN_ERROR_COLOR_ON "\n*** INIT: ERROR: Patches file '%s' invalid format.\n" FWEELIN_ERROR_COLOR_OFF, pb_patches); else { int p_curchan = -1, pcnt = 0; for (xmlNode *pb_curpatch = pb_root->children; pb_curpatch != NULL; pb_curpatch = pb_curpatch->next) { if ((!xmlStrcmp(pb_curpatch->name, (const xmlChar *)"combi"))) { // Combi (multi-zone multi-channel) // First, count zones int numzones = 0; for (xmlNode *curzone = pb_curpatch->children; curzone != NULL; curzone = curzone->next) if ((!xmlStrcmp(curzone->name, (const xmlChar *)"zone"))) numzones++; printf("\nCOMBI: Numzones: %d\n",numzones); // Setup combi xmlChar *cname = 0; cname = xmlGetProp(pb_curpatch,(const xmlChar *)"name"); if (pcnt == 0) { // First patch // Create new PatchBank br->PB_Add(new PatchBank(pb_mport,pb_tag,suppresschg)); } PatchItem *pi = new PatchItem(pcnt++,-1,-1,-1,(char *) cname); pi->SetupZones(numzones); br->AddItem(pi); if (pcnt % PatchBrowser::DIV_SPACING == 0) br->AddItem(new BrowserDivision()); if (cname != 0) xmlFree(cname); // For each zone int curzone_idx = 0; for (xmlNode *curzone = pb_curpatch->children; curzone != NULL; curzone = curzone->next) { if ((!xmlStrcmp(curzone->name, (const xmlChar *)"zone"))) { int kr_lo = 0, kr_hi = 0; if ((n = xmlGetProp(curzone, (const xmlChar *)"keyrange")) != 0) { int krs; float *kr = ExtractArray((char *)n, &krs, '>'); if (krs == 2) { kr_lo = (int) kr[0]; kr_hi = (int) kr[1]; } delete[] kr; xmlFree(n); } char mport_r = 0; int mport = pb_mport; xmlChar *n = 0; if ((n = xmlGetProp(curzone, (const xmlChar *)"midiport")) != 0) { mport_r = 1; mport = atoi((char *) n); xmlFree(n); } int bank = -1; if ((n = xmlGetProp(curzone, (const xmlChar *)"bank")) != 0) { bank = atoi((char *) n); xmlFree(n); } int prog = -1; if ((n = xmlGetProp(curzone, (const xmlChar *)"program")) != 0) { prog = atoi((char *) n); xmlFree(n); } int chan = 0; if ((n = xmlGetProp(curzone, (const xmlChar *)"channel")) != 0) { chan = atoi((char *) n); xmlFree(n); } // Bypass settings char bypasscc = pb_bypasscc; int bypasschannel = -1; float bypasstime1 = pb_bypasstime1, bypasstime2 = pb_bypasstime2; if ((n = xmlGetProp(curzone, (const xmlChar *)"bypasscc")) != 0) { bypasscc = atoi((char *) n); xmlFree(n); } if ((n = xmlGetProp(curzone, (const xmlChar *)"bypasschannel")) != 0) { bypasschannel = atoi((char *) n); xmlFree(n); } if ((n = xmlGetProp(curzone, (const xmlChar *)"bypasstime1")) != 0) { bypasstime1 = atof((char *) n); xmlFree(n); } if ((n = xmlGetProp(curzone, (const xmlChar *)"bypasstime2")) != 0) { bypasstime2 = atof((char *) n); xmlFree(n); } printf(" ZONE [%d>%d]: midiport[%s]:%d " "bank: %d prog: %d chan: %d\n", kr_lo,kr_hi, (mport_r ? "REDIRECT" : "DEFAULT"),mport, bank,prog,chan); pi->GetZone(curzone_idx)->SetupZone(kr_lo,kr_hi, mport_r,mport, bank,prog,chan, bypasscc,bypasschannel,bypasstime1,bypasstime2); curzone_idx++; } } } else if ((!xmlStrcmp(pb_curpatch->name, (const xmlChar *)"patch"))) { // Single channel patch int chan = 0; if ((n = xmlGetProp(pb_curpatch, (const xmlChar *)"channel")) != 0) { chan = atoi((char *) n); xmlFree(n); } int bank = 0; if ((n = xmlGetProp(pb_curpatch, (const xmlChar *)"bank")) != 0) { bank = atoi((char *) n); xmlFree(n); } int prog = 0; if ((n = xmlGetProp(pb_curpatch, (const xmlChar *)"program")) != 0) { prog = atoi((char *) n); xmlFree(n); } // Bypass settings char bypasscc = pb_bypasscc; int bypasschannel = -1; float bypasstime1 = pb_bypasstime1, bypasstime2 = pb_bypasstime2; if ((n = xmlGetProp(pb_curpatch, (const xmlChar *)"bypasscc")) != 0) { bypasscc = atoi((char *) n); xmlFree(n); } if ((n = xmlGetProp(pb_curpatch, (const xmlChar *)"bypasschannel")) != 0) { bypasschannel = atoi((char *) n); xmlFree(n); } if ((n = xmlGetProp(pb_curpatch, (const xmlChar *)"bypasstime1")) != 0) { bypasstime1 = atof((char *) n); xmlFree(n); } if ((n = xmlGetProp(pb_curpatch, (const xmlChar *)"bypasstime2")) != 0) { bypasstime2 = atof((char *) n); xmlFree(n); } xmlChar *pname = 0; if ((pname = xmlGetProp(pb_curpatch, (const xmlChar *)"name")) != 0) { if ((sepchan && chan != p_curchan) || (!sepchan && pcnt == 0)) { // Separate channels (patchbank for each channel)-- // or first patch // Create new PatchBank br->PB_Add(new PatchBank(pb_mport,pb_tag,suppresschg)); p_curchan = chan; pcnt = 0; //printf("new patchbank: mport: %d chan: %d\n", // pb_mport,chan); } br->AddItem(new PatchItem(pcnt++,bank,prog,chan, (char *) pname,bypasscc,bypasschannel,bypasstime1,bypasstime2)); //printf("bank: %d prog: %d patch: '%s'\n",bank,prog, // (char *) pname); //printf("patch: '%s' bypasscc: %d bypasstime1: %f bypasstime2: %f\n", // (char *) pname, bypasscc, bypasstime1, bypasstime2); if (pcnt % PatchBrowser::DIV_SPACING == 0) br->AddItem(new BrowserDivision()); xmlFree(pname); } } } } xmlFreeDoc(pb_doc); } xmlFree(pb_patches); } } } }; void FloConfig::SetupParamSetBank(xmlDocPtr /*doc*/, xmlNode *banknode, ParamSetBank *bank) { // Bank name char *name = 0; xmlChar *nn = xmlGetProp(banknode, (const xmlChar *)"name"); if (nn != 0) { name = new char[xmlStrlen(nn)+1]; strcpy(name,(char *) nn); xmlFree(nn); } // Max value of any param in this bank float maxvalue = 1.0; nn = xmlGetProp(banknode, (const xmlChar *)"maxvalue"); if (nn != 0) { maxvalue = atof((char *) nn); xmlFree(nn); } // Count number of params int numparams = 0; xmlNode *cur_node; for (cur_node = banknode->children; cur_node != NULL; cur_node = cur_node->next) { if ((!xmlStrcmp(cur_node->name, (const xmlChar *)"param"))) numparams++; } bank->Setup(name,numparams,maxvalue); if (name != 0) delete[] name; // Setup each parameter int curparam = 0; for (cur_node = banknode->children; cur_node != NULL; cur_node = cur_node->next) { if ((!xmlStrcmp(cur_node->name, (const xmlChar *)"param"))) { nn = xmlGetProp(cur_node, (const xmlChar *)"name"); if (nn != 0) { bank->params[curparam].SetName((char *) nn); xmlFree(nn); } nn = xmlGetProp(cur_node, (const xmlChar *)"init"); if (nn != 0) { bank->params[curparam].value = atof((char *) nn); xmlFree(nn); } curparam++; } } }; FloDisplay *FloConfig::SetupParamSet(xmlDocPtr doc, xmlNode *paramset, int interfaceid) { printf("(parameter set) "); // Param set name char *name = "NONAME"; char ps_named = 0; xmlChar *nn = xmlGetProp(paramset, (const xmlChar *)"name"); if (nn != 0) { ps_named = 1; name = new char[xmlStrlen(nn)+1]; strcpy(name,(char *) nn); xmlFree(nn); } // Parameter set display size int sx = 100, sy = 100; nn = xmlGetProp(paramset, (const xmlChar *)"size"); if (nn != 0) { int cs; float *coord = ExtractArray((char *)nn, &cs); if (cs) { sx = XCvt(coord[0]); sy = XCvt(coord[1]); printf("size (%d,%d) ",sx,sy); } delete[] coord; xmlFree(nn); } int numactiveparams = 8; nn = xmlGetProp(paramset, (const xmlChar *)"numactiveparams"); if (nn != 0) { numactiveparams = atoi((char *) nn); xmlFree(nn); } // Count banks int numbanks=0; xmlNode *cur_node; for (cur_node = paramset->children; cur_node != NULL; cur_node = cur_node->next) { if ((!xmlStrcmp(cur_node->name, (const xmlChar *)"bank"))) numbanks++; } // Create param set FloDisplayParamSet *nw = new FloDisplayParamSet(GetInputMatrix()->app,name,interfaceid,numactiveparams,numbanks,sx,sy); if (ps_named) delete[] name; nw->margin = XCvt(0.005); // Create and populate banks int cur_bank = 0; for (cur_node = paramset->children; cur_node != NULL; cur_node = cur_node->next) { if ((!xmlStrcmp(cur_node->name, (const xmlChar *)"bank"))) { SetupParamSetBank(doc,cur_node,&nw->banks[cur_bank]); cur_bank++; } } return nw; }; // Common config options for every display void FloConfig::ConfigureDisplay_Common(xmlNode *disp, FloDisplay *nw, FloDisplayPanel *parent) { if (parent != 0) { // Link this child display into parent int idx = 0; for (; parent->child_displays[idx] != 0; idx++); // printf("IDX : %d",idx); parent->child_displays[idx] = nw; } // Title xmlChar *n = xmlGetProp(disp, (const xmlChar *)"title"); if (n != 0) { nw->title = new char[xmlStrlen(n)+1]; strcpy(nw->title,(char*)n); printf("'%s' ",nw->title); xmlFree(n); } // Position n = xmlGetProp(disp, (const xmlChar *)"pos"); if (n != 0) { int cs; float *coord = ExtractArray((char *)n, &cs); if (cs) { nw->xpos = XCvt(coord[0]); nw->ypos = YCvt(coord[1]); if (parent != 0) { // If we're in a panel, offset our draw coordinates nw->xpos += parent->xpos + parent->margin; nw->ypos += parent->ypos + parent->margin; } printf("@ (%d,%d) ",nw->xpos,nw->ypos); delete[] coord; } xmlFree(n); } // Show? if (parent == 0) { n = xmlGetProp(disp, (const xmlChar *)"show"); if (n != 0) { nw->show = atoi((char *)n); if (nw->show) printf("(show) "); xmlFree(n); } } else { // If we're in a panel, inherit our parent's show status nw->show = parent->show; } // Font for display n = xmlGetProp(disp, (const xmlChar *)"font"); if (n != 0) { nw->font = GetFont((char *) n); if (nw->font != 0) printf("(font: %s) ",nw->font->name); else printf("(ERR: no font named '%s'!) ",n); xmlFree(n); } // ID n = xmlGetProp(disp, (const xmlChar *)"id"); if (n != 0) { ParsedExpression *tmp = im.ParseExpression((char *) n, 0); nw->id = (int) tmp->Evaluate(0); printf("(id: %d) ",nw->id); delete tmp; xmlFree(n); } // Expression to display n = xmlGetProp(disp, (const xmlChar *)"var"); if (n != 0) { printf("\n expression: "); nw->exp = im.ParseExpression((char *) n, 0); nw->exp->Print(); xmlFree(n); } // Link in the new display if (displays == 0) displays = nw; else { FloDisplay *cur = displays; while (cur->next != 0) cur = cur->next; cur->next = nw; } printf("\n"); } void FloConfig::ConfigureDisplay(xmlDocPtr doc, xmlNode *disp, int interfaceid, FloDisplayPanel *parent) { // Onscreen display declaration FloDisplay *nw = 0; printf("CONFIG: New onscreen display: "); char to_link = 1; int iid = interfaceid; xmlChar *n = xmlGetProp(disp, (const xmlChar *)"interfaceid"); if (n != 0) { iid = atoi((char *) n); printf("(interface ID: %d) ",iid); xmlFree(n); } // Type of display? n = xmlGetProp(disp, (const xmlChar *)"type"); if (n != 0) { if (!xmlStrcmp(n, (const xmlChar *)"text")) { printf("(text) "); nw = new FloDisplayText(iid); } else if (!xmlStrcmp(n, (const xmlChar *)"browser")) { printf("(browser) "); // Browser type BrowserItemType btype = (BrowserItemType) 0; xmlChar *nn = xmlGetProp(disp, (const xmlChar *)"browsetype"); if (nn != 0) { ParsedExpression *tmp = im.ParseExpression((char *) nn, 0); btype = (BrowserItemType) (int) tmp->Evaluate(0); printf("type: %s ",Browser::GetTypeName(btype)); delete tmp; xmlFree(nn); } // Expanded browser view char xpand = 0; int xpand_x1 = 0, xpand_x2 = 0, xpand_y1 = 0, xpand_y2 = 0; float xpand_delay = 1.0; nn = xmlGetProp(disp, (const xmlChar *)"xpand"); if (nn != 0) { xpand = atoi((char *) nn); printf("xpand: %d ",xpand); xmlFree(nn); } nn = xmlGetProp(disp, (const xmlChar *)"xdelay"); if (nn != 0) { xpand_delay = atof((char *) nn); printf("xdelay: %f ",xpand_delay); xmlFree(nn); } nn = xmlGetProp(disp, (const xmlChar *)"xbox"); if (nn != 0) { int cs; float *coord = ExtractArray((char *)nn, &cs); if (cs >= 4) { xpand_x1 = (int) round(XCvtf(coord[0])); xpand_y1 = (int) round(YCvtf(coord[1])); xpand_x2 = (int) round(XCvtf(coord[2])); xpand_y2 = (int) round(YCvtf(coord[3])); printf("xpand_box: (%d,%d)-(%d,%d) ",xpand_x1,xpand_y1, xpand_x2,xpand_y2); delete[] coord; } xmlFree(nn); } // Check for another browser with the same type-- not allowed FloDisplay *checkd = displays; char dupe = 0; while (!dupe && checkd != 0) { if (checkd->GetFloDisplayType() == FD_Browser && ((Browser *) checkd)->GetType() == btype) dupe = 1; checkd = checkd->next; } if (!dupe) { switch (btype) { case B_Loop_Tray : { int loopsize = 0; nn = xmlGetProp(disp, (const xmlChar *)"loopsize"); if (nn != 0) { loopsize = (int) round(XCvtf(atof((char *) nn))); xmlFree(nn); } nw = new LoopTray(iid, btype,xpand,xpand_x1,xpand_y1, xpand_x2,xpand_y2,loopsize); } break; case B_Scene_Tray : { } break; case B_Patch : { nw = new PatchBrowser(iid, btype,xpand,xpand_x1,xpand_y1, xpand_x2,xpand_y2,xpand_delay); ConfigurePatchBanks(disp,(PatchBrowser *) nw); } break; default : { // All other kinds of browsers nw = new Browser(iid, btype,xpand,xpand_x1,xpand_y1, xpand_x2,xpand_y2,xpand_delay); } break; } } else { printf(FWEELIN_ERROR_COLOR_ON "\n*** INIT: WARNING: Duplicate browser of type: '%s'\n" FWEELIN_ERROR_COLOR_OFF, Browser::GetTypeName(btype)); nw = 0; } } else if (!xmlStrcmp(n, (const xmlChar *)"panel")) { if (parent == 0) { printf("(panel) "); FloDisplayPanel *nwp = new FloDisplayPanel(iid); nw = nwp; // Snapshots display size xmlChar *nn = xmlGetProp(disp, (const xmlChar *)"size"); if (nn != 0) { int cs; float *coord = ExtractArray((char *)nn, &cs); if (cs) { nwp->sx = XCvt(coord[0]); nwp->sy = XCvt(coord[1]); printf("size (%d,%d) ",nwp->sx,nwp->sy); } delete[] coord; xmlFree(nn); } nwp->margin = XCvt(0.005); // Get position and link it in early to_link = 0; ConfigureDisplay_Common(disp,nw,parent); // Count number of child displays xmlNode *cur_node; for (cur_node = disp->children; cur_node != NULL; cur_node = cur_node->next) { if ((!xmlStrcmp(cur_node->name, (const xmlChar *)"display"))) nwp->num_children++; } nwp->child_displays = new FloDisplay *[nwp->num_children]; memset(nwp->child_displays,0,sizeof(FloDisplay *) * nwp->num_children); // Configure child displays for (cur_node = disp->children; cur_node != NULL; cur_node = cur_node->next) { // Check for a help node CheckForHelp(cur_node); if ((!xmlStrcmp(cur_node->name, (const xmlChar *)"display"))) { // Recursively add this display ConfigureDisplay(doc, cur_node, interfaceid, nwp); } } } else // Already inside a panel printf(FWEELIN_ERROR_COLOR_ON "*** CONFIG: ERROR: Can't nest panels.\n" FWEELIN_ERROR_COLOR_OFF); } else if (!xmlStrcmp(n, (const xmlChar *)"switch")) { printf("(switch) "); nw = new FloDisplaySwitch(iid); } else if (!xmlStrcmp(n, (const xmlChar *)"circle-switch")) { printf("(circle-switch) "); nw = new FloDisplayCircleSwitch(iid); // Circle radii xmlChar *nn = xmlGetProp(disp, (const xmlChar *)"size1"); if (nn != 0) { float sz = atof((char *)nn); ((FloDisplayCircleSwitch *) nw)->rad1 = XCvt(sz); printf("size1 %d ",((FloDisplayCircleSwitch *) nw)->rad1); xmlFree(nn); } nn = xmlGetProp(disp, (const xmlChar *)"size0"); if (nn != 0) { float sz = atof((char *)nn); ((FloDisplayCircleSwitch *) nw)->rad0 = XCvt(sz); printf("size0 %d ",((FloDisplayCircleSwitch *) nw)->rad0); xmlFree(nn); } // Flashing? nn = xmlGetProp(disp, (const xmlChar *)"flash"); if (nn != 0) { ((FloDisplayCircleSwitch *) nw)->flash = atoi((char *)nn); if (((FloDisplayCircleSwitch *) nw)->flash) printf("(flashing) "); xmlFree(nn); } } else if (!xmlStrcmp(n, (const xmlChar *)"text-switch")) { printf("(text-switch) "); nw = new FloDisplayTextSwitch(iid); // Text lines xmlChar *nn = xmlGetProp(disp, (const xmlChar *)"text1"); if (nn != 0) { char *text1 = new char[xmlStrlen(nn)+1]; strcpy(text1,(char*)nn); ((FloDisplayTextSwitch *) nw)->text1 = text1; printf("'%s' ",text1); xmlFree(nn); } nn = xmlGetProp(disp, (const xmlChar *)"text0"); if (nn != 0) { char *text0 = new char[xmlStrlen(nn)+1]; strcpy(text0,(char*)nn); ((FloDisplayTextSwitch *) nw)->text0 = text0; printf("'%s' ",text0); xmlFree(nn); } } else if (!xmlStrcmp(n, (const xmlChar *)"snapshots")) { printf("(snapshots) "); nw = new FloDisplaySnapshots(GetInputMatrix()->app,iid); FloDisplaySnapshots *nws = (FloDisplaySnapshots *) nw; nws->margin = XCvt(0.005); // Snapshots display size xmlChar *nn = xmlGetProp(disp, (const xmlChar *)"size"); if (nn != 0) { int cs; float *coord = ExtractArray((char *)nn, &cs); if (cs) { nws->sx = XCvt(coord[0]); nws->sy = XCvt(coord[1]); printf("size (%d,%d) ",nws->sx,nws->sy); } delete[] coord; xmlFree(nn); } } else if (!xmlStrcmp(n, (const xmlChar *)"paramset")) { nw = SetupParamSet(doc,disp,iid); } else if (!xmlStrcmp(n, (const xmlChar *)"bar") || !xmlStrcmp(n, (const xmlChar *)"bar-switch")) { // Bar or bar-switch? char sw = 0; FloDisplayBar *nwb; if (!xmlStrcmp(n, (const xmlChar *)"bar-switch")) { sw = 1; printf("(bar-switch) "); nwb = new FloDisplayBarSwitch(iid); } else { printf("(bar) "); nwb = new FloDisplayBar(iid); } nw = nwb; // Bar orientation xmlChar *nn = xmlGetProp(disp, (const xmlChar *)"orientation"); if (nn != 0) { if (!xmlStrcmp(nn,(const xmlChar *)"horizontal")) { nwb->orient = O_Horizontal; printf("(horizontal) "); } else if (!xmlStrcmp(nn,(const xmlChar *)"vertical")) { nwb->orient = O_Vertical; printf("(vertical) "); } else printf("(invalid bar orient: '%s') ",nn); xmlFree(nn); } // Bar scale nn = xmlGetProp(disp, (const xmlChar *)"barscale"); if (nn != 0) { nwb->barscale = atof((char *)nn); xmlFree(nn); } nwb->barscale = (nwb->orient == O_Horizontal ? XCvtf(nwb->barscale) : YCvtf(nwb->barscale)); printf("barscale %.2f ",nwb->barscale); // Bar thickness nn = xmlGetProp(disp, (const xmlChar *)"thickness"); if (nn != 0) { float bt = atof((char *)nn); nwb->thickness = (nwb->orient == O_Horizontal ? YCvt(bt) : XCvt(bt)); printf("thickness %d ",nwb->thickness); xmlFree(nn); } // dB scale? nn = xmlGetProp(disp, (const xmlChar *)"dbscale"); if (nn != 0) { nwb->dbscale = atoi((char *)nn); printf("(%s) ",(nwb->dbscale ? "dB scale" : "linear scale")); xmlFree(nn); } // calibration marks? nn = xmlGetProp(disp, (const xmlChar *)"marks"); if (nn != 0) { nwb->marks = atoi((char *)nn); printf("%s",(nwb->marks ? "(marks) " : "")); xmlFree(nn); } if (nwb->dbscale) nwb->maxdb = fadermaxdb; if (sw) { // Color nn = xmlGetProp(disp, (const xmlChar *)"color"); if (nn != 0) { ((FloDisplayBarSwitch *) nwb)->color = atoi((char *) nn); printf(" color %d ",((FloDisplayBarSwitch *) nwb)->color); xmlFree(nn); } // Calibration mark nn = xmlGetProp(disp, (const xmlChar *)"calibrate"); if (nn != 0) { ((FloDisplayBarSwitch *) nwb)->calibrate = 1; ((FloDisplayBarSwitch *) nwb)->cval = atof((char *) nn); printf(" calibrate %.2f ",((FloDisplayBarSwitch *) nwb)->cval); xmlFree(nn); } // Expression to display nn = xmlGetProp(disp, (const xmlChar *)"switchvar"); if (nn != 0) { printf(" switch-expression: "); ((FloDisplayBarSwitch *) nwb)->switchexp = im.ParseExpression((char *) nn, 0); ((FloDisplayBarSwitch *) nwb)->switchexp->Print(); printf(" "); xmlFree(nn); } } } else { printf(FWEELIN_ERROR_COLOR_ON "(invalid display type: '%s')\n" FWEELIN_ERROR_COLOR_OFF,n); } xmlFree(n); } if (nw != 0) { if (to_link) ConfigureDisplay_Common(disp,nw,parent); } } void FloConfig::ConfigureGraphics(xmlDocPtr doc, xmlNode *vid, int interfaceid) { xmlNode *cur_node; for (cur_node = vid->children; cur_node != NULL; cur_node = cur_node->next) { // Check for a help node CheckForHelp(cur_node); if ((!xmlStrcmp(cur_node->name, (const xmlChar *)"var"))) { // System variable setting // Check xmlChar *n = 0; if ((n = xmlGetProp(cur_node, (const xmlChar *)"resolution")) != 0) { // Video resolution int cs; float *coord = ExtractArray((char *)n, &cs); if (cs) { vsize[0] = (int)coord[0]; vsize[1] = (int)coord[1]; scope_sample_len = vsize[0]; // Scope goes across screen delete[] coord; } printf("CONFIG: Starting with (%d,%d) resolution.\n",vsize[0], vsize[1]); xmlFree(n); } n = xmlGetProp(cur_node, (const xmlChar *)"videodelay"); if (n != 0) { vdelay = atoi((char *)n); printf("CONFIG: Video delay: %d ms\n",vdelay); vdelay *= 1000; // usecs xmlFree(n); } } else if ((!xmlStrcmp(cur_node->name, (const xmlChar *)"font"))) { // Font loading FloFont *nw = new FloFont(); printf("CONFIG: New onscreen font: "); xmlChar *n = xmlGetProp(cur_node, (const xmlChar *)"name"); if (n != 0) { nw->name = new char[xmlStrlen(n)+1]; strcpy(nw->name,(char*)n); printf("%s: ",nw->name); xmlFree(n); } n = xmlGetProp(cur_node, (const xmlChar *)"file"); if (n != 0) { nw->filename = new char[xmlStrlen(n)+1]; strcpy(nw->filename,(char*)n); printf("%s",nw->filename); xmlFree(n); } n = xmlGetProp(cur_node, (const xmlChar *)"size"); if (n != 0) { nw->size = atoi((char *)n); printf(" (%d pt)",nw->size); xmlFree(n); } // Link in the new font if (fonts == 0) fonts = nw; else { FloFont *cur = fonts; while (cur->next != 0) cur = cur->next; cur->next = nw; } printf("\n"); } else if ((!xmlStrcmp(cur_node->name, (const xmlChar *)"display"))) { ConfigureDisplay(doc, cur_node, interfaceid); } else if ((!xmlStrcmp(cur_node->name, (const xmlChar *)"layout"))) { // Layout declaration FloLayout *nw = new FloLayout(); printf("CONFIG: New onscreen loop layout: "); // Set interface ID based on // what interface the layout is declared in nw->iid = interfaceid; xmlChar *n = xmlGetProp(cur_node, (const xmlChar *)"id"); if (n != 0) { nw->id = atoi((char *)n); printf("#%d ",nw->id); xmlFree(n); } n = xmlGetProp(cur_node, (const xmlChar *)"show"); if (n != 0) { nw->show = atoi((char *)n); if (nw->show) printf("(show) "); xmlFree(n); } n = xmlGetProp(cur_node, (const xmlChar *)"label"); if (n != 0) { nw->showlabel = atoi((char *)n); if (nw->showlabel) printf("(label) "); xmlFree(n); } n = xmlGetProp(cur_node, (const xmlChar *)"elabel"); if (n != 0) { nw->showelabel = atoi((char *)n); if (nw->showelabel) printf("(label elements) "); xmlFree(n); } n = xmlGetProp(cur_node, (const xmlChar *)"name"); if (n != 0) { nw->name = new char[xmlStrlen(n)+1]; strcpy(nw->name,(char*)n);; printf("'%s' ",nw->name); xmlFree(n); } float xscale = 1.0, yscale = 1.0; n = xmlGetProp(cur_node, (const xmlChar *)"scale"); if (n != 0) { int cs; float *coord = ExtractArray((char *)n, &cs); if (cs) { xscale = coord[0]; yscale = coord[1]; printf("scale (%.2f,%.2f) ",xscale,yscale); delete[] coord; } xmlFree(n); } // Position n = xmlGetProp(cur_node, (const xmlChar *)"pos"); if (n != 0) { int cs; float *coord = ExtractArray((char *)n, &cs); if (cs) { nw->xpos = XCvt(coord[0]); nw->ypos = YCvt(coord[1]); printf("@ (%d,%d) ",nw->xpos,nw->ypos); delete[] coord; } xmlFree(n); } // Name position n = xmlGetProp(cur_node, (const xmlChar *)"namepos"); if (n != 0) { int cs; float *coord = ExtractArray((char *)n, &cs); if (cs) { nw->nxpos = nw->xpos + XCvt(coord[0]); nw->nypos = nw->ypos + YCvt(coord[1]); printf("Name@ (%d,%d) ",nw->nxpos,nw->nypos); delete[] coord; } xmlFree(n); } // Link in the new layout if (layouts == 0) layouts = nw; else { FloLayout *cur = layouts; while (cur->next != 0) cur = cur->next; cur->next = nw; } printf("\n"); // Now populate the layout with elements.. ConfigureLayout(doc,cur_node,nw,xscale,yscale); } } }; // Is node 'n' a comment with help information? If so, add to our // internal help list void FloConfig::CheckForHelp(xmlNode *n) { if (n->type == XML_COMMENT_NODE) { char *str = (char *) n->content; while (*str == ' ') str++; // Advance past beginning whitespace if (!strncmp(str,FWEELIN_CONFIG_HELP_TOKEN, strlen(FWEELIN_CONFIG_HELP_TOKEN))) { // This token is a comment with help prefix-- store str += strlen(FWEELIN_CONFIG_HELP_TOKEN); char *s = new char[strlen(str)+1]; strcpy(s,str); // Replace divider with null to split string into two parts (columns) // This allows keys to be listed in separate help columns from their // functions char *div = strchr(s,':'); if (div != 0) { *div = '\0'; div++; } FloStringList *nw = new FloStringList(s,div); printf(" add user help: %s:%s\n",s,div); // Link in the new string if (help == 0) help = nw; else { FloStringList *cur = help; while (cur->next != 0) cur = cur->next; cur->next = nw; } } } }; // Creates an empty variable based on the given name. The config file // can then refer to the variable UserVariable *FloConfig::AddEmptyVariable(char *name) { UserVariable *nw = new UserVariable(); if (name != 0) { nw->name = new char[strlen(name)+1]; strcpy(nw->name,name); } // Insert into variable list nw->next = im.vars; im.vars = nw; return nw; }; // Makes the given variable into a system variable by linking it to // the pointer void FloConfig::LinkSystemVariable(char *name, CoreDataType type, char *ptr) { UserVariable *cur = im.vars; while (cur != 0) { if (cur->name != 0) { if (!strcmp(cur->name,name)) { // Variable found!- Link it with a system variable printf("CONFIG: Link system variable: %s -> %p\n",name,ptr); cur->type = type; cur->value = ptr; } } cur = cur->next; } }; // Returns a pointer to the given variable UserVariable *FloConfig::GetVariable(char *name) { UserVariable *cur = im.vars; while (cur != 0) { if (cur->name != 0) { if (!strcmp(cur->name,name)) { // Variable found! return cur; } } cur = cur->next; } return 0; }; FloConfig::~FloConfig() { // Erase displays { FloDisplay *cur = displays; while (cur != 0) { FloDisplay *tmp = cur->next; delete cur; cur = tmp; } } // Erase fonts { FloFont *cur = fonts; while (cur != 0) { FloFont *tmp = cur->next; delete cur; cur = tmp; } } // Erase layouts { FloLayout *cur = layouts; while (cur != 0) { FloLayout *tmp = cur->next; delete cur; cur = tmp; } } // Erase help { FloStringList *cur = help; while (cur != 0) { FloStringList *tmp = cur->next; delete cur; cur = tmp; } } #if USE_FLUIDSYNTH // Erase FluidSynth config { FluidSynthParam *cur = fsparam; while (cur != 0) { FluidSynthParam *tmp = cur->next; delete cur; cur = tmp; } } { FluidSynthSoundFont *cur = fsfont; while (cur != 0) { FluidSynthSoundFont *tmp = cur->next; delete cur; cur = tmp; } } #endif if (ms_inputs != 0) delete[] ms_inputs; if (monitor_inputs != 0) delete [] monitor_inputs; if (stream_inputs != 0) delete [] stream_inputs; if (librarypath != 0) delete librarypath; }; FloConfig::FloConfig(Fweelin *app) : im(app), ev_hook(0), librarypath(0), midiouts(1), msnumouts(0), msouts(0), ms_inputs(0), monitor_inputs(0), extaudioins(0), maxplayvol(0.0), maxlimitergain(1.0), limiterthreshhold(0.9), limiterreleaserate(0.000020), loopoutformat(VORBIS), streamoutformat(VORBIS), vorbis_encode_quality(0.5), num_triggers(1024), vdelay(50000), showdebug(0), layouts(0), fonts(0), displays(0), help(0), #if USE_FLUIDSYNTH fsinterp(4), fschannel(0), fsstereo(1), fstuning(0.0), fsparam(0), fsfont(0), #endif transpose(0), loop_peaksavgs_chunksize(500), status_report(0), numinterfaces(0), numnsinterfaces(0), max_snapshots(20) { vsize[0] = 640; vsize[1] = 480; scope_sample_len = vsize[0]; // Scope goes across screen }; void FloConfig::ConfigureInterfaces (xmlDocPtr /*doc*/, xmlNode *ifs, char firstpass) { int cur_iid = 1, // First interface has ID 1 (0 is main config) // First non-switchable interface has this ID cur_nsiid = NS_INTERFACE_START_ID; for (xmlNode *cur_node = ifs->children; cur_node != NULL; cur_node = cur_node->next) { if (!xmlStrcmp(cur_node->name, (const xmlChar *)"interface")) { char switchable = 1; xmlChar *n = xmlGetProp(cur_node, (const xmlChar *)"switchable"); if (n != 0) { switchable = atoi((char *) n); xmlFree(n); } n = xmlGetProp(cur_node, (const xmlChar *)"setup"); if (n != 0) { printf("INIT: Load interface '%s' [%s]\n",(char *) n, (firstpass ? "first pass" : "second pass")); char *buf = PrepareLoadConfigFile((char *) n,0); xmlSubstituteEntitiesDefault(1); xmlDocPtr doc = (buf == 0 ? 0 : xmlParseFile(buf)); if (doc == 0) printf(FWEELIN_ERROR_COLOR_ON "INIT: Error parsing config file '%s'.\n" FWEELIN_ERROR_COLOR_OFF,(char *) n); else { xmlNode *root = xmlDocGetRootElement(doc); if (!root || !root->name || xmlStrcmp(root->name,(const xmlChar *) "interface") ) printf(FWEELIN_ERROR_COLOR_ON "INIT: Interface config file '%s' format invalid-- " "should start with 'interface' tag\n" FWEELIN_ERROR_COLOR_OFF,(char *) n); else { if (switchable) ConfigureRoot(doc,root,cur_iid++,firstpass); else ConfigureRoot(doc,root,cur_nsiid++,firstpass); } xmlFreeDoc(doc); } xmlFree(n); } } } numinterfaces = cur_iid-1; numnsinterfaces = cur_nsiid-NS_INTERFACE_START_ID; printf("CONFIG: # of interfaces: %d switchable / %d non-switchable\n", numinterfaces,numnsinterfaces); }; void FloConfig::ConfigureRoot (xmlDocPtr doc, xmlNode *root, int interfaceid, char firstpass) { for (xmlNode *cur_node = root->children; cur_node != NULL; cur_node = cur_node->next) { if (!firstpass && interfaceid == 0 && !xmlStrcmp(cur_node->name, (const xmlChar *)"basics")) { // Basics cfg ConfigureBasics(doc,cur_node); } else if (!firstpass && !xmlStrcmp(cur_node->name, (const xmlChar *)"graphics")) { // Video cfg ConfigureGraphics(doc,cur_node,interfaceid); } else if (/* interfaceid != 0 && */ !xmlStrcmp(cur_node->name, (const xmlChar *)"bindings")) { // Events if (interfaceid == 0) { // All at once in main config ConfigureEventBindings(doc,cur_node,interfaceid,1); ConfigureEventBindings(doc,cur_node,interfaceid,0); } else ConfigureEventBindings(doc,cur_node,interfaceid,firstpass); } else if (!firstpass && interfaceid == 0 && !xmlStrcmp(cur_node->name, (const xmlChar *)"interfaces")) { // Interfaces- 2 passes- first load variables, then rest ConfigureInterfaces(doc,cur_node,1); ConfigureInterfaces(doc,cur_node,0); } } }; // Parse configuration file, setup config void FloConfig::Parse() { #ifdef __MACOSX__ // On Mac OS X, Set FWEELIN_DATADIR to bundle resource folder CFURLRef url = CFBundleCopyResourcesDirectoryURL(CFBundleGetMainBundle()); CFURLGetFileSystemRepresentation(url, true, (UInt8 *)FWEELIN_DATADIR, MAXPATHLEN); CFRelease(url); #endif // Setup event type table Event::SetupEventTypeTable(im.app->getMMG()); // Look for config file char *buf = PrepareLoadConfigFile(FWEELIN_CONFIG_FILE,1); xmlSubstituteEntitiesDefault(1); xmlDocPtr doc = (buf == 0 ? 0 : xmlParseFile(buf)); if (doc == 0) { printf("INIT: Error parsing config file '%s'.\n",FWEELIN_CONFIG_FILE); exit(1); } else { xmlNode *root = NULL; /*Get the root element node */ root = xmlDocGetRootElement(doc); if (!root || !root->name || xmlStrcmp(root->name,(const xmlChar *) "freewheeling") ) printf("INIT: Config file format invalid-- should start with 'freewheeling' tag\n"); else { // Get config file version and make sure it matches our version xmlChar *ver = xmlGetProp(root, (const xmlChar *)"version"); if (ver == 0 || strcmp((char *) ver,VERSION)) { printf("INIT: ERROR: Config file version \"%s\" does not match " "FreeWheeling version \"%s\"!\n\n",ver,VERSION); // Copy over new config files from shared CopyConfigFile(FWEELIN_CONFIG_FILE,1); // Free and restart printf("CONFIG: Reading new config...\n"); xmlFreeDoc(doc); buf = PrepareLoadConfigFile(FWEELIN_CONFIG_FILE,1); doc = xmlParseFile(buf); /*Get the root element node */ root = xmlDocGetRootElement(doc); xmlChar *ver = xmlGetProp(root, (const xmlChar *)"version"); if (ver == 0 || strcmp((char *) ver,VERSION)) { printf("INIT: ERROR: Config in install dir is not up to date!\n" "Did you run 'make install'?\n"); exit(1); } } else xmlFree(ver); ConfigureRoot(doc,root); } /*free the document */ xmlFreeDoc(doc); /* *Free the global variables that may *have been allocated by the parser. */ xmlCleanupParser(); } }; void FloConfig::StartInterfaces () { for (int iid = NS_INTERFACE_START_ID; iid < NS_INTERFACE_START_ID+numnsinterfaces; iid++) { Event *proto = Event::GetEventByType(T_EV_StartInterface,1); if (proto == 0) { printf("GO: Can't get start interface event prototype!\n"); } else { StartInterfaceEvent *cpy = (StartInterfaceEvent *) proto->RTNewWithWait(); if (cpy == 0) printf("CONFIG: WARNING: Can't send event- RTNew() failed\n"); else { printf("CONFIG: Start non-switchable interface %d\n",iid); cpy->interfaceid = iid; im.app->getEMG()->BroadcastEventNow(cpy, &im); } } } for (int iid = 1; iid <= numinterfaces; iid++) { Event *proto = Event::GetEventByType(T_EV_StartInterface,1); if (proto == 0) { printf("GO: Can't get start interface event prototype!\n"); } else { StartInterfaceEvent *cpy = (StartInterfaceEvent *) proto->RTNewWithWait(); if (cpy == 0) printf("CONFIG: WARNING: Can't send event- RTNew() failed\n"); else { printf("CONFIG: Start switchable interface %d\n",iid); cpy->interfaceid = iid; im.app->getEMG()->BroadcastEventNow(cpy, &im); } } } }; freewheeling-0.6.6/src/fweelin_config.h000066400000000000000000001002041370736313100201060ustar00rootroot00000000000000#ifndef __FWEELIN_CONFIG_H #define __FWEELIN_CONFIG_H /* Copyright 2004-2011 Jan Pekau This file is part of Freewheeling. Freewheeling is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. Freewheeling 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 Freewheeling. If not, see . */ #include #include #include #include #include "fweelin_block.h" // Number of beats per bar // (used only to compute sync, since FW does not use the concept of bars/beats internally) #define SYNC_BEATS_PER_BAR 4 // Maximum number of time pulses #define MAX_PULSES 10 // How many different sets of loop selections to remember? #define NUM_LOOP_SELECTION_SETS 10 // Keep track of the last n indexes we recorded to #define LAST_REC_COUNT 8 // Divisions are added in browsers wherever files are greater than // FWEELIN_FILE_BROWSER_DIVISION_TIME seconds apart #define FWEELIN_FILE_BROWSER_DIVISION_TIME 3600 #define FWEELIN_CONFIG_DIR ".fweelin" #define FWEELIN_CONFIG_FILE "fweelin.xml" #define FWEELIN_CONFIG_EXT ".xml" #define FWEELIN_CONFIG_HELP_TOKEN "HELP:" #define FWEELIN_OUTPUT_STREAM_NAME "live" #define FWEELIN_OUTPUT_TIMING_EXT ".wav.usx" #define FWEELIN_OUTPUT_LOOP_NAME "loop" #define FWEELIN_OUTPUT_SCENE_NAME "scene" #define FWEELIN_OUTPUT_SNAPSHOT_NAME "snapshot" #define FWEELIN_OUTPUT_LOOPSNAPSHOT_NAME "loopsnap" #define FWEELIN_OUTPUT_DATA_EXT ".xml" // Console sequence for error color #define FWEELIN_ERROR_COLOR_ON "\033[31;1m" #define FWEELIN_ERROR_COLOR_OFF "\033[0m" // Interface ID assigned to first non-switchable interface #define NS_INTERFACE_START_ID 1000 #ifdef __MACOSX__ // On Linux, FWEELIN_DATADIR refers to /usr/local/share/fweelin as set by autoconf // On Mac, we store our data in the Resource directory of the fweelin.app bundle. // This string stores the location of the Resource directory, and is set in the Obj-C stub // for the code. extern char *FWEELIN_DATADIR; // On Linux, VERSION is defined within configure.ac // For Mac OS, we set it here: #define VERSION "0.6" #endif #include "fweelin_datatypes.h" #include "fweelin_audioio.h" #include "fweelin_event.h" #include "fweelin_videoio.h" // TTF_Font decl class Event; class SDLIO; class MidiIO; class CircularMap; class PatchBrowser; class ParamSetBank; // ****************** CONFIG CLASSES enum CfgTokenType { T_CFG_None, T_CFG_UserVariable, T_CFG_EventParameter, T_CFG_Static }; // Config tokens can reference user variables (UserVariable) // or input EventParameters (EventParameter) // or static values class CfgToken { public: CfgToken() : cvt(T_CFG_None), var(0) {}; CfgTokenType cvt; // Dump CfgToken to stdout void Print(); // Evaluate the current value of this token to dst // Using event ev as a reference for event parameter // If overwritetype is nonzero, sets dst to be of the appropriate data type // Otherwise, converts to existing type of dst void Evaluate(UserVariable *dst, Event *ev, char overwritetype); // Reference a user defined variable UserVariable *var; // Reference an event parameter EventParameter evparam; // Or reference a static value UserVariable val; }; // Simple algebra is possible in config file // it allows, for example, a midi fader level to be divided into an appropriate // amplitude. // This is one math operation as part of an expression class CfgMathOperation { public: CfgMathOperation() : next(0) {}; // Symbols for different math operators (div, mul, add, sub, etc..) const static char operators[]; // Number of different math operators const static int numops; char otype; // One of the above operator types CfgToken operand; CfgMathOperation *next; }; // A complete expression of config tokens modified by math operations class ParsedExpression { public: ParsedExpression() : ops(0) {}; ~ParsedExpression() { // Erase math ops CfgMathOperation *cur = ops; while (cur != 0) { CfgMathOperation *tmp = cur->next; delete cur; cur = tmp; } }; // Evaluate this expression UserVariable Evaluate(Event *input); // Returns nonzero if this expression contains only static tokens // and no user variables and no input parameters char IsStatic(); // Dump expression to stdout void Print(); CfgToken start; // Starting token of expression CfgMathOperation *ops; // Optional sequence of math ops to perform on 'val' }; // DynamicToken is an expression and a config token, // used in a few places: // // 1) To evaluate an expression and assign the result to an output event // parameter (wrapped in CfgToken) // 2) To evaluate an expression and compare the result to an input event // parameter (wrapped in CfgToken) // 2) To evaluate an expression and compare the result to a user variable // (wrapped in CfgToken) class DynamicToken { public: DynamicToken() : exp(0), next(0) {}; ~DynamicToken() { if (exp != 0) delete exp; }; CfgToken token; // Variable/parameter to compare or assign to ParsedExpression *exp; // Expression to evaluate DynamicToken *next; }; // Binding between a freewheeling event and some input action // controls basic user interface class EventBinding { public: EventBinding() : boundproto(0), echo(0), tokenconds(0), paramsets(0), continued(0), next(0) {}; virtual ~EventBinding(); Event *boundproto; // Prototype instance of the output event // Nonzero if input events should be rebroadcast even // if they are consumed in this binding char echo; // ** Conditions // List of dynamic token conditions // (for example, MIDI channel on input must match given expression) DynamicToken *tokenconds; // ** Parameter mappings // List of dynamic parameter assignments for output events // (for example, when triggering from MIDI keyboard: loop # = notenum + 12) DynamicToken *paramsets; // Continued is nonzero if the next binding should always be triggered // when this binding is triggered- so the next binding is a // continuation of this binding char continued; EventBinding *next; }; class InputMatrix : public EventProducer, public EventListener { public: InputMatrix(Fweelin *app); virtual ~InputMatrix(); // Sets the given variable to the given value- string is interpreted // based on variable type void SetVariable (UserVariable *var, char *value); // Called during configuration to create user defined variables void CreateVariable (xmlNode *declare); // Called during configuration to bind input controllers to events void CreateBinding (int interfaceid, xmlNode *binding); // Are the conditions in the EventBinding bind matched by the // given input event and user variables? char CheckConditions(Event *input, EventBinding *bind); // Receive input events void ReceiveEvent(Event *ev, EventProducer *from); // Start function, called shortly before Fweelin begins running void Start(); // *********** User defined variables UserVariable *vars; Fweelin *app; // Parses a given expression string, extracting tokens // for example: 'VAR_curnote+12' references variable VAR_curnote and // creates 1 math operation +12 // The expression may also reference parameters in event 'ref' // and these references will be extracted ParsedExpression *ParseExpression(char *str, Event *ref, char enable_keynames = 0); private: // Removes leading and trailing spaces from string str // Modifies the end of string str and returns a pointer to the new // beginning after spaces char *RemoveSpaces (char *str); // Adds one key to the given list based on the keysym name // Returns the new first pointer SDLKeyList *AddOneKey (SDLKeyList *first, char *str); // Extracts named keys from the given string and returns a list // of the keysyms (named keys are separated by ,) SDLKeyList *ExtractKeys (char *str); // Parses the given token (no math ops!) into dst // Correctly identifies when variables or event parameters are referenced void ParseToken(char *str, CfgToken *dst, Event *ref, char enable_keynames = 0); // Stores in ptr the value val given that ptr is of type dtype void StoreParameter(char *ptr, CoreDataType dtype, UserVariable *val); // Using the eventbinding's parametersets as a template, dynamically // sets parameters in the output event void SetDynamicParameters(Event *input, Event *output, EventBinding *bind); // Scans in the given binding for settings for output event parameters // and sets us up to handle those void CreateParameterSets (int interfaceid, EventBinding *bind, xmlNode *binding, Event *input, unsigned char contnum); // Scans in the given binding for conditions on input event parameters // or user variables, and sets us up to handle those // Returns the hash index for this binding, based on an indexed parameter, // or 0 if this binding is not indexed int CreateConditions (int interfaceid, EventBinding *bind, xmlNode *binding, Event *input, int paramidx); // Traverses through the list of event bindings beginning at 'start' // looking for a binding that matches current user variables and input // event 'ev' EventBinding *MatchBinding(Event *ev, EventBinding *start); // *********** Event Bindings // Bindings that trigger on input events- for each input event type, // a hashtable of bindings along an indexed parameter EventBinding ***input_bind; }; class FloLayoutElementGeometry { public: FloLayoutElementGeometry() : next(0) {}; virtual ~FloLayoutElementGeometry() {}; // Draw this element to the given screen- // implementation given in videoio.cc virtual void Draw(SDL_Surface *screen, SDL_Color clr) = 0; // Inside returns nonzero if the given coordinates fall inside this // element geometry virtual char Inside(int x, int y) = 0; // Next geo FloLayoutElementGeometry *next; }; class FloLayoutBox : public FloLayoutElementGeometry { public: // Draw this element to the given screen- // implementation given in videoio.cc virtual void Draw(SDL_Surface *screen, SDL_Color clr); // Inside returns nonzero if the given coordinates fall inside this // element geometry virtual char Inside(int x, int y) { if (x >= left && x <= right && y >= top && y <= bottom) return 1; else return 0; }; // Outlines along borders? char lineleft, linetop, lineright, linebottom; // Coordinates of box int left, top, right, bottom; }; class FloLayoutElement { public: FloLayoutElement() : id(0), name(0), nxpos(0), nypos(0), bx(0.0), by(0.0), loopmap(0), loopx(0), loopy(0), loopsize(0), geo(0), next(0) {}; virtual ~FloLayoutElement() { if (name != 0) delete[] name; // Erase geometries FloLayoutElementGeometry *cur = geo; while (cur != 0) { FloLayoutElementGeometry *tmp = cur->next; delete cur; cur = tmp; } }; // Inside returns nonzero if the given coordinates fall inside this // element- we check all geometries char Inside(int x, int y) { FloLayoutElementGeometry *cur = geo; while (cur != 0) { if (cur->Inside(x,y)) return 1; // Inside this geo, so inside this element cur = cur->next; } return 0; // Not inside any geo, so not inside this element }; int id; // Id of element char *name; // Name of element int nxpos, nypos; // Location to print name label float bx, by; // Base position for element // Generated map that will take a flat scope and project it onto the right // size circle-- see videoio CircularMap *loopmap; int loopx, loopy, // Position of loop graphic for the element loopsize; // Size of loop graphic (diameter) // Geo describes how to draw this element FloLayoutElementGeometry *geo; // Next element FloLayoutElement *next; }; // The user can define the onscreen layout for loops-- see config file! class FloLayout { public: FloLayout() : id(0), iid(0), xpos(0), ypos(0), loopids(0,0), name(0), nxpos(0), nypos(0), elems(0), show(1), showlabel(1), showelabel(1), next(0) {}; ~FloLayout() { if (name != 0) delete[] name; // Erase elements FloLayoutElement *cur = elems; while (cur != 0) { FloLayoutElement *tmp = cur->next; delete cur; cur = tmp; } }; int id, // User refers to a layout by layout ID iid, // Interface id. Interface id + layout id uniquely identify // a layout xpos, ypos; // Base location on screen for this layout Range loopids; // Range of loopids that map to interface elements char *name; // ex PC Keyboard, MIDI Footpedal int nxpos, nypos; // Location to print name label FloLayoutElement *elems; // Elements that make up this layout char show, // Layout shown onscreen? showlabel, // Name of layout shown onscreen? showelabel; // Element names in layout shown onscreen? // Next layout FloLayout *next; }; // List of strings- optional two strings per listitem // Second string is assumed to be substring of first string // Only first string is deleted at destructor class FloStringList { public: FloStringList(char *str, char *str2 = 0) : str(str), str2(str2), next(0) {}; ~FloStringList() { if (str != 0) delete[] str; }; char *str, *str2; FloStringList *next; }; // List of fonts used in video- video handles the loading and unloading, // but config sets up these structures to know which fonts and sizes to load class FloFont { public: FloFont() : name(0), filename(0), font(0), size(0), next(0) {}; ~FloFont() { if (filename != 0) delete[] filename; if (name != 0) delete[] name; }; char *name, *filename; TTF_Font *font; int size; FloFont *next; }; enum FloDisplayType { FD_Unknown, FD_Browser, FD_Snapshots, FD_ParamSet, }; // List of variable displays used in video // There are different types of displays, this is a base class class FloDisplay { public: FloDisplay (int iid) : iid(iid), id(-1), exp(0), font(0), title(0), xpos(0), ypos(0), show(1), forceshow(0), next(0) {}; virtual ~FloDisplay() { if (title != 0) delete[] title; if (exp != 0) delete exp; }; // Draw this display to the given screen- // implementation given in videoio.cc virtual void Draw(SDL_Surface *screen) = 0; virtual FloDisplayType GetFloDisplayType() { return FD_Unknown; }; // Set whether this display is showing virtual void SetShow(char show) { this->show = show; }; int iid, // Interface id. Interface id + display id uniquely identify // a display id; // Display ID ParsedExpression *exp; // Expression which evaluates to a value to display FloFont *font; // Font for text char *title; // Title to be displayed int xpos, ypos; // Onscreen location for display char show, // Show (nonzero) or hide (zero) display forceshow; // Force display to show? FloDisplay *next; }; // Panel is a 'container' that holds several child displays and surrounds it with a frame // Allows easy showing and hiding of a number of displays together class FloDisplayPanel : public FloDisplay { public: FloDisplayPanel (int iid) : FloDisplay(iid), sx(100), sy(100), num_children(0), child_displays(0) {}; ~FloDisplayPanel () { if (child_displays != 0) delete[] child_displays; }; virtual void Draw(SDL_Surface *screen); // Set whether this display is showing virtual void SetShow(char show) { this->show = show; // Show/hide child displays for (int i = 0; i < num_children; i++) child_displays[i]->SetShow(show); }; int sx, sy; // Size of panel int margin; // Margin for displays inside panel // Array of pointers to all child displays. Child displays are still stored in the master list of // displays, and drawn independently of the panel. int num_children; FloDisplay **child_displays; }; // Text display shows the value of expression 'exp' as onscreen text class FloDisplayText : public FloDisplay { public: FloDisplayText (int iid) : FloDisplay(iid) {}; virtual void Draw(SDL_Surface *screen); }; // Switch display shows the title in different color depending on the value of // expression 'exp' class FloDisplaySwitch : public FloDisplay { public: FloDisplaySwitch (int iid) : FloDisplay(iid) {}; virtual void Draw(SDL_Surface *screen); }; // Circle switch display shows a circle which changes color and optionally // flashes depending on the value of expression 'exp' class FloDisplayCircleSwitch : public FloDisplay { public: FloDisplayCircleSwitch (int iid) : FloDisplay(iid), rad1(0), rad0(0), flash(0), prevnonz(0), nonztime(0.) {}; virtual void Draw(SDL_Surface *screen); int rad1, rad0; // Radii of circle when switch is on or off // For flashing char flash, // Flash or solid colors? prevnonz; // Previous character value of expression (for nonzero test) double nonztime; // System time at which the expression last became nonzero }; // Text switch display shows one string of text when a value is nonzero, // and another string of text when a value is zero. class FloDisplayTextSwitch : public FloDisplay { public: FloDisplayTextSwitch (int iid) : FloDisplay(iid), text1(0), text0(0) {}; virtual void Draw(SDL_Surface *screen); char *text1, // Text for nonzero value *text0; // Text for zero value }; enum CfgOrientation { O_Horizontal, O_Vertical }; // Bar display shows the value of expression 'exp' as a bar class FloDisplayBar : public FloDisplay { public: FloDisplayBar (int iid) : FloDisplay(iid), orient(O_Vertical), barscale(1.0), thickness(10), dbscale(0), marks(0), maxdb(0) {}; virtual void Draw(SDL_Surface *screen); CfgOrientation orient; // Orientation of bar float barscale; // Scaling factor for size of bar int thickness; // Thickness of bar char dbscale, // If nonzero, this bar maps a linear amplitude variable to a logarithmic scale bar // If zero, there is a linear mapping to the bar marks; // If nonzero, calibration marks are shown (dB scale only) float maxdb; // (dbscale) Maximum dB level shown }; // Bar-switch display shows the value of expression 'exp' as a bar and changes the color of the bar // depending on the value of expression 'switchexp' class FloDisplayBarSwitch : public FloDisplayBar { public: FloDisplayBarSwitch (int iid) : FloDisplayBar(iid), switchexp(0), color(1), calibrate(0), cval(0.0) {}; virtual ~FloDisplayBarSwitch() { if (switchexp != 0) delete switchexp; }; virtual void Draw(SDL_Surface *screen); ParsedExpression *switchexp; // Expression which evaluates to a value. Nonzero values cause the bar // to appear bright, zero values cause a dim, faded bar int color; // Color of bar-switch (index of hardcoded color) char calibrate; // Nonzero shows calibration value on barswitch & changes color when level exceeds calibration value float cval; // Calibration value (linear) }; class FloDisplaySquares : public FloDisplay { public: FloDisplaySquares (int iid) : FloDisplay(iid), orient(O_Horizontal) {}; virtual void Draw(SDL_Surface *screen); CfgOrientation orient; // Orientation of bar float v1, v2, // Value corresponding to first and last square sinterval; // 1 square for every 'sinterval' change in value int sx, sy; // Square size }; // FluidSynth config #include "fweelin_fluidsynth.h" #if USE_FLUIDSYNTH class FluidSynthParam { public: FluidSynthParam(char *name) : next(0) { this->name = new char[strlen(name)+1]; strcpy(this->name,name); }; virtual ~FluidSynthParam() { delete[] name; }; // Send this parameter into the given settings virtual void Send(fluid_settings_t *settings) = 0; char *name; FluidSynthParam *next; }; class FluidSynthParam_Num : public FluidSynthParam { public: FluidSynthParam_Num(char *name, double val) : FluidSynthParam(name), val(val) {}; virtual void Send(fluid_settings_t *settings); double val; }; class FluidSynthParam_Int : public FluidSynthParam { public: FluidSynthParam_Int(char *name, int val) : FluidSynthParam(name), val(val) {}; virtual void Send(fluid_settings_t *settings); int val; }; class FluidSynthParam_Str : public FluidSynthParam { public: FluidSynthParam_Str(char *name, char *val) : FluidSynthParam(name) { this->val = new char[strlen(val)+1]; strcpy(this->val,val); }; virtual ~FluidSynthParam_Str() { delete[] val; }; virtual void Send(fluid_settings_t *settings); char *val; }; class FluidSynthSoundFont { public: FluidSynthSoundFont(char *name) : next(0) { if (strchr(name,'/') != 0) { // Path specified this->name = new char[strlen(name)+1]; strcpy(this->name,name); } else { // Path not specified, use default this->name = new char[strlen(FWEELIN_DATADIR)+1+strlen(name)+1]; sprintf(this->name,"%s/%s",FWEELIN_DATADIR,name); } }; ~FluidSynthSoundFont() { delete[] name; }; char *name; FluidSynthSoundFont *next; }; #endif // Fweelin configuration class FloConfig { public: FloConfig(Fweelin *app); ~FloConfig(); // Parse configuration file, setup config void Parse(); // Start function, called shortly before Fweelin begins running void Start() { im.Start(); }; // Send start-interface event to all interfaces void StartInterfaces (); // Copy config file from shared folder // Optionally copy all config files void CopyConfigFile (char *cfgname, char copyall); // Prepare to load configuration file 'cfgname' // Finds the file in one of several places, and copies it to // the config folder. Returns the path name if found, or null if not found char *PrepareLoadConfigFile (char *cfgname, char basecfg); // Configure bindings between events and their triggers void ConfigureEventBindings(xmlDocPtr /*doc*/, xmlNode *events, int interfaceid = 0, char firstpass = 0); // Configuring displays void SetupParamSetBank(xmlDocPtr /*doc*/, xmlNode *banknode, ParamSetBank *bank); FloDisplay *SetupParamSet(xmlDocPtr doc, xmlNode *paramset, int interfaceid); // Configuration sections void ConfigureElement(xmlDocPtr /*doc*/, xmlNode *elemn, FloLayoutElement *elem, float xscale, float yscale); void ConfigureLayout(xmlDocPtr doc, xmlNode *layn, FloLayout *lay, float xscale, float yscale); void ConfigureDisplay_Common(xmlNode *disp, FloDisplay *nw, FloDisplayPanel *parent); void ConfigureDisplay(xmlDocPtr doc, xmlNode *disp, int interfaceid, FloDisplayPanel *parent = 0); void ConfigurePatchBanks(xmlNode *pb, PatchBrowser *br); void ConfigureGraphics(xmlDocPtr doc, xmlNode *vid, int interfaceid = 0); void ConfigureBasics(xmlDocPtr /*doc*/, xmlNode *gen); void ConfigureInterfaces (xmlDocPtr /*doc*/, xmlNode *ifs, char firstpass); void ConfigureRoot (xmlDocPtr doc, xmlNode *root, int interfaceid = 0, char firstpass = 0); // Is node 'n' a comment with help information? If so, add to our // internal help list void CheckForHelp(xmlNode *n); // Creates an empty variable based on the given name. The config file // can then refer to the variable UserVariable *AddEmptyVariable(char *name); // Returns a pointer to the given variable UserVariable *GetVariable(char *name); // Makes the given variable into a system variable by linking it to // the pointer void LinkSystemVariable(char *name, CoreDataType type, char *ptr); // Input matrix- stores and handles all bindings between inputs and events inline InputMatrix *GetInputMatrix() { return &im; }; InputMatrix im; // Add an event hook, if none already exists // An event hook gets first dibs on incoming events // We use this to override the usual functions of, say, the keyboard, // and redirect them elsewhere, like typing text. // // Returns zero on success and nonzero if another hook exists already inline char AddEventHook (EventHook *hook) { if (ev_hook == 0) { ev_hook = hook; return 0; } else return 1; }; // Remove an event hook // Returns zero on success inline char RemoveEventHook (EventHook *hook) { if (ev_hook == hook) { ev_hook = 0; return 0; } else return 1; }; // Event hook- right now, we only support one at a time EventHook *ev_hook; // Extracts an array of floats (delimited by character delim_char) // from the given string- returns size of array in 'size' float *ExtractArray(char *n, int *size, char delim_char = ','); // Same, with ints int *ExtractArrayInt(char *n, int *size, char delim_char = ','); // Library path inline char *GetLibraryPath() { if (librarypath != 0) return librarypath; else { printf("CORE: ERROR: Library path not set in configuration!\n"); exit(1); } }; char *librarypath; // Number of MIDI out ports inline int GetNumMIDIOuts() { return midiouts; }; int midiouts; // List of MIDI ports to transmit sync info to inline int GetNumMIDISyncOuts() { return msnumouts; }; inline int *GetMIDISyncOuts() { return msouts; }; int msnumouts, *msouts; // Is input/output #n stereo? inline char IsStereoInput(int out_n) { return ms_inputs[out_n]; }; inline char IsStereoOutput(int /*out_n*/) { return IsStereoMaster(); }; inline char IsInputMonitoring(int out_n) { return monitor_inputs[out_n]; }; char *ms_inputs, // Zero or nonzero for each input- is this input stereo? *monitor_inputs; // Nonzero if monitoring is enabled for this input // Is FreeWheeling running in stereo or completely in mono? char IsStereoMaster(); // Stream settings inline char IsStreamFinal() { return stream_final; }; inline char IsStreamLoops() { return stream_loops; }; inline char IsStreamInputs(int n) { return stream_inputs[n]; }; char stream_final, stream_loops, *stream_inputs; // Number of external audio inputs into FreeWheeling (specified in config file) // AudioIO may add its own inputs internal to FreeWheeling // (for example, softsynth) inline int GetExtAudioIns() { return extaudioins; }; int extaudioins; // Maximum play volume inline float GetMaxPlayVol() { return maxplayvol; }; float maxplayvol; // Maximum limiter gain inline float GetMaxLimiterGain() { return maxlimitergain; }; float maxlimitergain; // Limiter threshhold inline float GetLimiterThreshhold() { return limiterthreshhold; }; float limiterthreshhold; // Limiter release rate inline float GetLimiterReleaseRate() { return limiterreleaserate; }; float limiterreleaserate; // Logarithmic fader settings inline float GetFaderMaxDB() { return fadermaxdb; }; float fadermaxdb; // File format to save loops to inline codec GetLoopOutFormat() { return loopoutformat; }; codec loopoutformat; // File format to save streams to inline codec GetStreamOutFormat() { return streamoutformat; }; codec streamoutformat; inline char *GetCodecName (codec i) { switch (i) { case VORBIS: return "ogg"; case WAV: return "wav"; case FLAC: return "flac"; case AU: return "au"; default: return "UNKNOWN"; } }; inline codec GetCodecFromName (const char *n) { for (codec i = FIRST_FORMAT; i < END_OF_FORMATS; i = (codec) (i+1)) if (!strcasecmp(n,GetCodecName(i))) return i; return UNKNOWN; }; inline char *GetAudioFileExt (codec i) { switch (i) { case VORBIS: return ".ogg"; case WAV: return ".wav"; case FLAC: return ".flac"; case AU: return ".au"; default: return ".ogg"; }; }; // Quality for encoding OGG files inline float GetVorbisEncodeQuality() { return vorbis_encode_quality; }; float vorbis_encode_quality; // Number of triggers (loop ids) inline int GetNumTriggers() { return num_triggers; }; int num_triggers; // Video config inline int *GetVSize() { return vsize; }; inline float XCvtf(float x) { return (x*vsize[0]); }; inline float YCvtf(float y) { return (y*vsize[1]); }; inline int XCvt(float x) { return (int) (x*vsize[0]); }; inline int YCvt(float y) { return (int) (y*vsize[1]); }; int vsize[2]; inline int GetVDelay() { return vdelay; }; int vdelay; // # of samples in visual oscilloscope buffer nframes_t scope_sample_len; inline nframes_t GetScopeSampleLen() { return scope_sample_len; }; // Macro to check whether debug info is on #define CRITTERS (app->getCFG()->IsDebugInfo()) // Return nonzero if debug info to be shown char IsDebugInfo() { return showdebug; }; // Show debugging info? char showdebug; // Graphical layouts FloLayout *GetLayouts() { return layouts; }; FloLayout *layouts; // Graphical fonts // Returns the named font from our list of fonts FloFont *GetFont (char *name) { FloFont *cur = fonts; while (cur != 0 && strcmp(cur->name,name)) cur = cur->next; return cur; }; FloFont *GetFonts() { return fonts; }; FloFont *fonts; // Graphical displays inline FloDisplay *GetDisplays() { return displays; }; inline FloDisplay *GetDisplayById (int iid, int id) { FloDisplay *cur = displays; while (cur != 0) { if (cur->iid == iid && cur->id == id) return cur; cur = cur->next; } return 0; }; inline FloDisplay *GetDisplayByType (FloDisplayType typ) { FloDisplay *cur = displays; while (cur != 0) { if (cur->GetFloDisplayType() == typ) return cur; cur = cur->next; } return 0; }; FloDisplay *displays; // Help text int GetNumHelpLines() { FloStringList *cur = help; int cnt = 0; while (cur != 0) { cnt++; cur = cur->next; } return cnt; }; char *GetHelpLine(int idx, int col) { FloStringList *cur = help; int cnt = 0; while (cur != 0 && cnt != idx) { cnt++; cur = cur->next; } if (cur == 0) return 0; else return (col == 0 ? cur->str : cur->str2); }; FloStringList *help; #if USE_FLUIDSYNTH // FluidSynth config int fsinterp; int GetFluidInterpolation() { return fsinterp; }; int fschannel; int GetFluidChannel() { return fschannel; }; char fsstereo; char GetFluidStereo() { return fsstereo; }; float fstuning; float GetFluidTuning() { return fstuning; }; FluidSynthParam *fsparam; FluidSynthParam *GetFluidParam() { return fsparam; }; void AddFluidParam(FluidSynthParam *nw) { if (fsparam == 0) fsparam = nw; else { FluidSynthParam *cur = fsparam; while (cur->next != 0) cur = cur->next; cur->next = nw; } }; FluidSynthSoundFont *fsfont; void AddFluidFont(FluidSynthSoundFont *nw) { if (fsfont == 0) fsfont = nw; else { FluidSynthSoundFont *cur = fsfont; while (cur->next != 0) cur = cur->next; cur->next = nw; } }; FluidSynthSoundFont *GetFluidFont() { return fsfont; }; #endif // Pitch transpose on outgoing MIDI events signed int transpose; // Chunksize for peaks & avgs display of loops // (bigger # means shorter displays) nframes_t loop_peaksavgs_chunksize; int status_report; #define FS_REPORT_BLOCKMANAGER 1 // Total number of interfaces defined in config int numinterfaces, // Switchable interfaces // (range 1<=i<=numinterfaces) numnsinterfaces; // Nonswitchable interfaces // Maximum number of snapshots user can create inline int GetMaxSnapshots() { return max_snapshots; }; int max_snapshots; // Seconds of fixed audio history const static float AUDIO_MEMORY_LEN; // # of audio blocks to preallocate const static int NUM_PREALLOCATED_AUDIO_BLOCKS; // # of time markers to preallocate const static int NUM_PREALLOCATED_TIME_MARKERS; // Maximum path length for config files const static int CFG_PATH_MAX; }; #endif freewheeling-0.6.6/src/fweelin_core.cc000066400000000000000000003577571370736313100177620ustar00rootroot00000000000000/* Truth has a power like electricity When we dance in Truth, it is infectious, unmistakable. */ /* Copyright 2004-2011 Jan Pekau This file is part of Freewheeling. Freewheelisng is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. Freewheeling 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 Freewheeling. If not, see . */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "fweelin_core.h" #include "fweelin_fluidsynth.h" #include "fweelin_paramset.h" #include "fweelin_looplibrary.h" const float Loop::MIN_VOL = 0.01; PreallocatedType *Loop::loop_pretype = 0; // *********** CORE Snapshot *Fweelin::getSNAP (int idx) { if (idx >= 0 && idx < cfg->GetMaxSnapshots()) return &snaps[idx]; else return 0; } void Snapshot::CreateSnapshot (char *_name, LoopManager *lm, TriggerMap *tmap) { if (this->exists && this->name != 0 && _name == 0) { // Preserve name of snapshot DeleteSnapshot(0); } else DeleteSnapshot(); this->exists = 1; if (this->name == 0 && _name != 0) { this->name = new char[strlen(_name)+1]; strcpy(this->name,_name); } if (lm != 0) { // Count all loops this->numls = tmap->CountLoops(); if (this->numls > 0) { this->ls = new LoopSnapshot[this->numls]; int idx = 0; for (int i = 0; i < tmap->GetMapSize(); i++) { if (tmap->GetMap(i) != 0) { Loop *loop = tmap->GetMap(i); if (idx >= this->numls) { printf("CORE: ERROR: Loop count mismatch creating snapshot!\n"); return; } this->ls[idx++] = LoopSnapshot(i,lm->GetStatus(i), loop->vol,lm->GetTriggerVol(i)); } } } } }; // Trigger snapshot #idx - return nonzero on failure char Fweelin::TriggerSnapshot (int idx) { Snapshot *s = getSNAP(idx); if (s != 0 && s->exists) { for (int i = 0; i < s->numls; i++) { LoopSnapshot *ls = &(s->ls[i]); loopmgr->SetLoopVolume(ls->l_idx,ls->l_vol); if (ls->status == T_LS_Off && loopmgr->IsActive(ls->l_idx)) { loopmgr->Deactivate(ls->l_idx); } else if (ls->status == T_LS_Playing || ls->status == T_LS_Overdubbing) { if (loopmgr->GetStatus(ls->l_idx) != T_LS_Playing) { // Loop not yet playing if (loopmgr->IsActive(ls->l_idx)) loopmgr->Deactivate(ls->l_idx); loopmgr->Activate(ls->l_idx, 0, ls->t_vol); } else { // Loop already playing- adjust volume loopmgr->SetTriggerVol(ls->l_idx, ls->t_vol); } } } return 0; } else return 1; }; // Splits a saveable filename in the format 'basename-hash-objectname' // into its base name, hash and object name components // // Returns zero on success char Saveable::SplitFilename(const char *filename, int baselen, char *basename, char *hash, char *objname, int maxlen) { // Loop exists, use combination of time and hash as name const char *slashptr = filename + baselen; if (slashptr < filename+strlen(filename)) { const char *slashptr2 = strchr(slashptr+1,'-'), *extptr = strrchr(filename,'.'); if (extptr == 0) extptr = filename+strlen(filename); // No extension // Extract base name int len = 0; if (basename != 0) { len = MIN(baselen,maxlen-1); memcpy(basename,filename,sizeof(char)*len); basename[len] = '\0'; } // Extract hash const char *breaker = (slashptr2 != 0 ? slashptr2 : extptr); if (strlen(slashptr+1) - strlen(breaker) == SAVEABLE_HASH_LENGTH*2) { if (hash != 0) { len = MIN(SAVEABLE_HASH_LENGTH*2,maxlen-1); memcpy(hash,slashptr+1,sizeof(char)*len); hash[len] = '\0'; } } else { printf("SAVEABLE: Invalid hash within filename: '%s'\n", filename); return 1; } // Now check if the filename also contains an object name- // this would be placed after the hash if (objname != 0) { if (slashptr2 != 0) { // Name len = strlen(slashptr2+1) - strlen(extptr); len = MIN(len,maxlen-1); memcpy(objname,slashptr2+1,sizeof(char)*len); objname[len] = '\0'; } else strcpy(objname,""); } } else { printf("SAVEABLE: Invalid filename for extracting hash/name: '%s'\n", filename); return 1; } return 0; }; void Saveable::RenameSaveable(char **filename_ptr, int baselen, char *newname, const char **exts, int num_exts) { // Parse filename to extract hash part char fn_base[FWEELIN_OUTNAME_LEN], fn_hash[FWEELIN_OUTNAME_LEN], fn_name[FWEELIN_OUTNAME_LEN]; if (Saveable::SplitFilename(*filename_ptr,baselen,fn_base,fn_hash,fn_name, FWEELIN_OUTNAME_LEN)) printf("SAVEABLE: Can't rename '%s'- poorly formatted filename.\n", *filename_ptr); else { char tmp[FWEELIN_OUTNAME_LEN]; strncpy(tmp,*filename_ptr,FWEELIN_OUTNAME_LEN); tmp[FWEELIN_OUTNAME_LEN-1] = '\0'; delete[] *filename_ptr; *filename_ptr = new char[strlen(fn_base)+1+ strlen(fn_hash)+1+ strlen(newname)+1]; if (strlen(newname) > 0) sprintf(*filename_ptr,"%s-%s-%s", fn_base,fn_hash,newname); else sprintf(*filename_ptr,"%s-%s", fn_base,fn_hash); unsigned int tmp_a_size = FWEELIN_OUTNAME_LEN + 10; unsigned int tmp_b_size = FWEELIN_OUTNAME_LEN; char tmp_a[tmp_a_size], tmp_b[tmp_b_size]; for (int i = 0; i < num_exts; i++) { // Add each type of extension provided and rename the file snprintf(tmp_a,tmp_a_size,"%s%s",tmp,exts[i]); snprintf(tmp_b,tmp_b_size,"%s%s",*filename_ptr,exts[i]); if (!rename(tmp_a,tmp_b)) printf("SAVEABLE: Rename file '%s' -> '%s'\n",tmp_a,tmp_b); //else //printf("SAVEABLE: File '%s' not found for rename\n",tmp_a); } } }; // This is for renaming an item in memory, so that the disk corresponds // with the new name void Saveable::RenameSaveable(char *librarypath, char *basename, char *old_objname, char *nw_objname, const char **exts, int num_exts, char **old_filename, char **new_filename) { if (savestatus == SAVE_DONE) { // OK, we have to rename on disk // Get filename to rename GET_SAVEABLE_HASH_TEXT(GetSaveHash()); *old_filename = new char[FWEELIN_OUTNAME_LEN]; *new_filename = new char[FWEELIN_OUTNAME_LEN]; for (int i = 0; i < num_exts; i++) { // Add each type of extension provided and rename the file if (old_objname == 0 || strlen(old_objname) == 0) snprintf(*old_filename,FWEELIN_OUTNAME_LEN,"%s/%s-%s%s", librarypath,basename,hashtext,exts[i]); else snprintf(*old_filename,FWEELIN_OUTNAME_LEN,"%s/%s-%s-%s%s", librarypath,basename,hashtext,old_objname,exts[i]); if (nw_objname == 0 || strlen(nw_objname) == 0) snprintf(*new_filename,FWEELIN_OUTNAME_LEN,"%s/%s-%s%s", librarypath,basename,hashtext,exts[i]); else snprintf(*new_filename,FWEELIN_OUTNAME_LEN,"%s/%s-%s-%s%s", librarypath,basename,hashtext,nw_objname,exts[i]); printf("SAVEABLE: Rename file '%s' -> '%s'\n", *old_filename,*new_filename); rename(*old_filename,*new_filename); } // Get names without extensions if (old_objname == 0) snprintf(*old_filename,FWEELIN_OUTNAME_LEN,"%s/%s-%s", librarypath,basename,hashtext); else snprintf(*old_filename,FWEELIN_OUTNAME_LEN,"%s/%s-%s-%s", librarypath,basename,hashtext,old_objname); if (nw_objname == 0) snprintf(*new_filename,FWEELIN_OUTNAME_LEN,"%s/%s-%s", librarypath,basename,hashtext); else snprintf(*new_filename,FWEELIN_OUTNAME_LEN,"%s/%s-%s-%s", librarypath,basename,hashtext,nw_objname); } }; // Save loop void Loop::Save(Fweelin *app) { // Queue save app->getLOOPMGR()->AddLoopToSaveQueue(this); }; void LoopManager::AddToSaveQueue(Event *ev) { numsave++; EventManager::QueueEvent(&savequeue,ev); }; void LoopManager::AddLoopToSaveQueue(Loop *l) { if (!autosave && l->GetSaveStatus() == NO_SAVE) { numsave++; LoopListEvent *ll = (LoopListEvent *) Event::GetEventByType(T_EV_LoopList,1); ll->l = l; EventManager::QueueEvent(&savequeue,ll); } }; void LoopManager::AddLoopToLoadQueue(char *filename, int index, float vol) { numload++; LoopListEvent *ll = (LoopListEvent *) Event::GetEventByType(T_EV_LoopList,1); strcpy(ll->l_filename,filename); ll->l_idx = index; ll->l_vol = vol; EventManager::QueueEvent(&loadqueue,ll); }; // Adds the loop with given filename to the loop browser br void LoopManager::AddLoopToBrowser(Browser *br, char *filename) { char tmp[FWEELIN_OUTNAME_LEN]; struct stat st; if (stat(filename,&st) == 0) { char default_name = br->GetDisplayName(filename,&st.st_mtime,tmp,FWEELIN_OUTNAME_LEN); br->AddItem(new LoopBrowserItem(st.st_mtime,tmp,default_name,filename),1); } }; // Populate the loop browser with any loops on disk void LoopManager::SetupLoopBrowser() { Browser *br = app->getBROWSER(B_Loop); if (br != 0) { // Clear br->ClearAllItems(); // Look for loops on disk glob_t globbuf; char tmp[FWEELIN_OUTNAME_LEN]; for (codec lformat = FIRST_FORMAT; lformat < END_OF_FORMATS; lformat = (codec) (lformat+1)) { snprintf(tmp,FWEELIN_OUTNAME_LEN,"%s/%s*%s", app->getCFG()->GetLibraryPath(),FWEELIN_OUTPUT_LOOP_NAME, app->getCFG()->GetAudioFileExt(lformat)); printf("BROWSER: (Loop) Scanning for loops in library: %s\n",tmp); if (glob(tmp, 0, NULL, &globbuf) == 0) { for (size_t i = 0; i < globbuf.gl_pathc; i++) { //printf("BROWSER: (Loop) Loop: %s\n",globbuf.gl_pathv[i]); AddLoopToBrowser(br,globbuf.gl_pathv[i]); } br->AddDivisions(FWEELIN_FILE_BROWSER_DIVISION_TIME); br->MoveToBeginning(); globfree(&globbuf); } } } }; // Adds the scene with given filename to the scene browser br SceneBrowserItem *LoopManager::AddSceneToBrowser(Browser *br, char *filename) { char tmp[FWEELIN_OUTNAME_LEN]; SceneBrowserItem *ret = 0; struct stat st; if (stat(filename,&st) == 0) { char default_name = br->GetDisplayName(filename,&st.st_mtime,tmp,FWEELIN_OUTNAME_LEN); br->AddItem(ret = new SceneBrowserItem(st.st_mtime,tmp,default_name,filename),1); } return ret; }; // Populate the scene browser with any scenes on disk void LoopManager::SetupSceneBrowser() { Browser *br = app->getBROWSER(B_Scene); if (br != 0) { // Clear br->ClearAllItems(); // Look for scenes on disk glob_t globbuf; char tmp[FWEELIN_OUTNAME_LEN]; snprintf(tmp,FWEELIN_OUTNAME_LEN,"%s/%s*%s", app->getCFG()->GetLibraryPath(),FWEELIN_OUTPUT_SCENE_NAME, FWEELIN_OUTPUT_DATA_EXT); printf("BROWSER: (Scene) Scanning for scenes in library: %s\n",tmp); if (glob(tmp, 0, NULL, &globbuf) == 0) { for (size_t i = 0; i < globbuf.gl_pathc; i++) { // printf("BROWSER: (Scene) Scene: %s\n",globbuf.gl_pathv[i]); AddSceneToBrowser(br,globbuf.gl_pathv[i]); } br->AddDivisions(FWEELIN_FILE_BROWSER_DIVISION_TIME); br->MoveToBeginning(); globfree(&globbuf); } } }; void LoopManager::ItemBrowsed(BrowserItem */*item*/) {}; void LoopManager::ItemSelected(BrowserItem *item) { // Loop manager handles selected browser callback for scenes and loops switch (item->GetType()) { case B_Loop: printf("DISK: Load '%s'\n",((LoopBrowserItem *) item)->filename); LoadLoop(((LoopBrowserItem *) item)->filename,loadloopid, newloopvol / GetOutputVolume()); break; case B_Scene: printf("DISK: Load '%s'\n",((SceneBrowserItem *) item)->filename); LoadScene((SceneBrowserItem *) item); break; default: break; } }; void LoopManager::ItemRenamed(BrowserItem *item) { switch (item->GetType()) { case B_Loop_Tray: // Change name inside the loop { LoopTrayItem *curl = (LoopTrayItem *) item; char *old_filename = 0, *new_filename = 0; // Rename on disk const static char *exts[] = {app->getCFG()->GetAudioFileExt(curl->l->format), FWEELIN_OUTPUT_DATA_EXT}; curl->l->RenameSaveable(app->getCFG()->GetLibraryPath(), FWEELIN_OUTPUT_LOOP_NAME, curl->l->name, curl->name, exts, 2, &old_filename, &new_filename); // We also need to rename in the loop browser if (app->getBROWSER(B_Loop) != 0) app->getBROWSER(B_Loop)-> ItemRenamedOnDisk(old_filename,new_filename,curl->name); if (old_filename != 0) delete[] old_filename; if (new_filename != 0) delete[] new_filename; // And in memory.. RenameLoop(curl->l,curl->name); } break; case B_Loop: { // Name change on disk int baselen = strlen(app->getCFG()->GetLibraryPath()) + 1 + strlen(FWEELIN_OUTPUT_LOOP_NAME); // Add all audio format names + XML to extension list int numexts = END_OF_FORMATS + 1; char *exts[numexts]; for (codec c = FIRST_FORMAT; c < END_OF_FORMATS; c = (codec) (c+1)) exts[c] = app->getCFG()->GetAudioFileExt(c); exts[END_OF_FORMATS] = FWEELIN_OUTPUT_DATA_EXT; // Rename all possible audio files + XML metadata to new name printf("DISK: Rename '%s'\n",((LoopBrowserItem *) item)->filename); Saveable::RenameSaveable(&((LoopBrowserItem *) item)->filename,baselen, item->name,(const char **) exts,numexts); // Is this loop loaded? If so, rename it // Find loop in memory (by hash, extracted from filename) char fn_hash[FWEELIN_OUTNAME_LEN]; if (!Saveable::SplitFilename(((LoopBrowserItem *) item)->filename, baselen,0,fn_hash,0,FWEELIN_OUTNAME_LEN)) { // Convert text 'fn_hash' to binary hash and scan for it Saveable tmp; if (!(tmp.SetSaveableHashFromText(fn_hash))) { int foundidx; if ((foundidx = app->getTMAP()->ScanForHash(tmp.GetSaveHash())) != -1) { // This loop -is- loaded, rename in map and in loop tray // printf("loop renamed is also in memory: %d\n",foundidx); Loop *foundloop = GetSlot(foundidx); // Rename in memory RenameLoop(foundloop,item->name); // We have to notify the LoopTray of the new name given LoopTray *tray = (LoopTray *) app->getBROWSER(B_Loop_Tray); if (tray != 0) tray->ItemRenamedFromOutside(foundloop,item->name); } } } } break; case B_Scene: { int baselen = strlen(app->getCFG()->GetLibraryPath()) + 1 + strlen(FWEELIN_OUTPUT_SCENE_NAME); const static char *exts[] = {FWEELIN_OUTPUT_DATA_EXT}; printf("DISK: Rename '%s'\n",((SceneBrowserItem *) item)->filename); Saveable::RenameSaveable(&((SceneBrowserItem *) item)->filename,baselen, item->name,exts,1); } break; default: break; } }; LoopManager::LoopManager (Fweelin *app) : renamer(0), rename_loop(0), savequeue(0), loadqueue(0), cursave(0), curload(0), numsave(0), numload(0), loadloopid(0), needs_saving_stamp(0), default_looprange(Range(0,app->getCFG()->GetNumTriggers())), autosave(0), app(app), newloopvol(1.0), subdivide(1), curpulseindex(-1) { pthread_mutex_init (&loops_lock,0); int mapsz = app->getTMAP()->GetMapSize(); Loop::SetupLoopPreallocation(app->getMMG()); plist = new Processor *[mapsz]; status = new LoopStatus[mapsz]; waitactivate = new int[mapsz]; waitactivate_shot = new char[mapsz]; waitactivate_vol = new float[mapsz]; waitactivate_od = new char[mapsz]; waitactivate_od_fb = new float *[mapsz]; numloops = 0; numrecordingloops = 0; lastrecidx = new int[LAST_REC_COUNT]; memset(lastrecidx, 0, sizeof(int) * LAST_REC_COUNT); memset(plist, 0, sizeof(Processor *) * mapsz); int lst = T_LS_Off; memset(status, lst, sizeof(LoopStatus) * mapsz); memset(waitactivate, 0, sizeof(int) * mapsz); memset(waitactivate_shot, 0, sizeof(char) * mapsz); memset(waitactivate_vol, 0, sizeof(float) * mapsz); memset(waitactivate_od, 0, sizeof(char) * mapsz); memset(waitactivate_od_fb, 0, sizeof(float) * mapsz); memset(pulses, 0, sizeof(Pulse *) * MAX_PULSES); // Turn on block read/write managers for loading & saving loops bread = ::new BlockReadManager(0,this,app->getBMG(), app->getCFG()->loop_peaksavgs_chunksize); bwrite = ::new BlockWriteManager(0,this,app->getBMG()); app->getBMG()->AddManager(bread); app->getBMG()->AddManager(bwrite); // Listen for important events app->getEMG()->ListenEvent(this,0,T_EV_EndRecord); app->getEMG()->ListenEvent(this,0,T_EV_ToggleDiskOutput); app->getEMG()->ListenEvent(this,0,T_EV_ToggleSelectLoop); app->getEMG()->ListenEvent(this,0,T_EV_SelectOnlyPlayingLoops); app->getEMG()->ListenEvent(this,0,T_EV_SelectAllLoops); app->getEMG()->ListenEvent(this,0,T_EV_InvertSelection); app->getEMG()->ListenEvent(this,0,T_EV_CreateSnapshot); app->getEMG()->ListenEvent(this,0,T_EV_RenameSnapshot); app->getEMG()->ListenEvent(this,0,T_EV_TriggerSnapshot); app->getEMG()->ListenEvent(this,0,T_EV_SwapSnapshots); app->getEMG()->ListenEvent(this,0,T_EV_SetAutoLoopSaving); app->getEMG()->ListenEvent(this,0,T_EV_SaveLoop); app->getEMG()->ListenEvent(this,0,T_EV_SaveNewScene); app->getEMG()->ListenEvent(this,0,T_EV_SaveCurrentScene); app->getEMG()->ListenEvent(this,0,T_EV_SetLoadLoopId); app->getEMG()->ListenEvent(this,0,T_EV_SetDefaultLoopPlacement); app->getEMG()->ListenEvent(this,0,T_EV_SlideMasterInVolume); app->getEMG()->ListenEvent(this,0,T_EV_SlideMasterOutVolume); app->getEMG()->ListenEvent(this,0,T_EV_SlideInVolume); app->getEMG()->ListenEvent(this,0,T_EV_SetMasterInVolume); app->getEMG()->ListenEvent(this,0,T_EV_SetMasterOutVolume); app->getEMG()->ListenEvent(this,0,T_EV_SetInVolume); app->getEMG()->ListenEvent(this,0,T_EV_ToggleInputRecord); app->getEMG()->ListenEvent(this,0,T_EV_DeletePulse); app->getEMG()->ListenEvent(this,0,T_EV_SelectPulse); app->getEMG()->ListenEvent(this,0,T_EV_TapPulse); app->getEMG()->ListenEvent(this,0,T_EV_SwitchMetronome); app->getEMG()->ListenEvent(this,0,T_EV_SetSyncType); app->getEMG()->ListenEvent(this,0,T_EV_SetSyncSpeed); app->getEMG()->ListenEvent(this,0,T_EV_SetMidiSync); app->getEMG()->ListenEvent(this,0,T_EV_SetTriggerVolume); app->getEMG()->ListenEvent(this,0,T_EV_SlideLoopAmp); app->getEMG()->ListenEvent(this,0,T_EV_SetLoopAmp); app->getEMG()->ListenEvent(this,0,T_EV_AdjustLoopAmp); app->getEMG()->ListenEvent(this,0,T_EV_TriggerLoop); app->getEMG()->ListenEvent(this,0,T_EV_TriggerSelectedLoops); app->getEMG()->ListenEvent(this,0,T_EV_SetSelectedLoopsTriggerVolume); app->getEMG()->ListenEvent(this,0,T_EV_AdjustSelectedLoopsAmp); app->getEMG()->ListenEvent(this,0,T_EV_MoveLoop); app->getEMG()->ListenEvent(this,0,T_EV_RenameLoop); app->getEMG()->ListenEvent(this,0,T_EV_EraseLoop); app->getEMG()->ListenEvent(this,0,T_EV_EraseAllLoops); app->getEMG()->ListenEvent(this,0,T_EV_EraseSelectedLoops); app->getEMG()->ListenEvent(this,0,T_EV_SlideLoopAmpStopAll); app->getEMG()->ListenEvent(this,0,T_EV_ALSAMixerControlSet); }; LoopManager::~LoopManager() { // Stop block read/write managers bread->End(0); bwrite->End(); app->getBMG()->DelManager(bread); app->getBMG()->DelManager(bwrite); Loop::TakedownLoopPreallocation(); // Stop listening app->getEMG()->UnlistenEvent(this,0,T_EV_EndRecord); app->getEMG()->UnlistenEvent(this,0,T_EV_ToggleDiskOutput); app->getEMG()->UnlistenEvent(this,0,T_EV_ToggleSelectLoop); app->getEMG()->UnlistenEvent(this,0,T_EV_SelectOnlyPlayingLoops); app->getEMG()->UnlistenEvent(this,0,T_EV_SelectAllLoops); app->getEMG()->UnlistenEvent(this,0,T_EV_InvertSelection); app->getEMG()->UnlistenEvent(this,0,T_EV_CreateSnapshot); app->getEMG()->UnlistenEvent(this,0,T_EV_RenameSnapshot); app->getEMG()->UnlistenEvent(this,0,T_EV_TriggerSnapshot); app->getEMG()->UnlistenEvent(this,0,T_EV_SwapSnapshots); app->getEMG()->UnlistenEvent(this,0,T_EV_SetAutoLoopSaving); app->getEMG()->UnlistenEvent(this,0,T_EV_SaveLoop); app->getEMG()->UnlistenEvent(this,0,T_EV_SaveNewScene); app->getEMG()->UnlistenEvent(this,0,T_EV_SaveCurrentScene); app->getEMG()->UnlistenEvent(this,0,T_EV_SetLoadLoopId); app->getEMG()->UnlistenEvent(this,0,T_EV_SetDefaultLoopPlacement); app->getEMG()->UnlistenEvent(this,0,T_EV_SlideMasterInVolume); app->getEMG()->UnlistenEvent(this,0,T_EV_SlideMasterOutVolume); app->getEMG()->UnlistenEvent(this,0,T_EV_SlideInVolume); app->getEMG()->UnlistenEvent(this,0,T_EV_SetMasterInVolume); app->getEMG()->UnlistenEvent(this,0,T_EV_SetMasterOutVolume); app->getEMG()->UnlistenEvent(this,0,T_EV_SetInVolume); app->getEMG()->UnlistenEvent(this,0,T_EV_ToggleInputRecord); app->getEMG()->UnlistenEvent(this,0,T_EV_DeletePulse); app->getEMG()->UnlistenEvent(this,0,T_EV_SelectPulse); app->getEMG()->UnlistenEvent(this,0,T_EV_TapPulse); app->getEMG()->UnlistenEvent(this,0,T_EV_SwitchMetronome); app->getEMG()->UnlistenEvent(this,0,T_EV_SetSyncType); app->getEMG()->UnlistenEvent(this,0,T_EV_SetSyncSpeed); app->getEMG()->UnlistenEvent(this,0,T_EV_SetMidiSync); app->getEMG()->UnlistenEvent(this,0,T_EV_SetTriggerVolume); app->getEMG()->UnlistenEvent(this,0,T_EV_SlideLoopAmp); app->getEMG()->UnlistenEvent(this,0,T_EV_SetLoopAmp); app->getEMG()->UnlistenEvent(this,0,T_EV_AdjustLoopAmp); app->getEMG()->UnlistenEvent(this,0,T_EV_TriggerLoop); app->getEMG()->UnlistenEvent(this,0,T_EV_TriggerSelectedLoops); app->getEMG()->UnlistenEvent(this,0,T_EV_SetSelectedLoopsTriggerVolume); app->getEMG()->UnlistenEvent(this,0,T_EV_AdjustSelectedLoopsAmp); app->getEMG()->UnlistenEvent(this,0,T_EV_MoveLoop); app->getEMG()->UnlistenEvent(this,0,T_EV_RenameLoop); app->getEMG()->UnlistenEvent(this,0,T_EV_EraseLoop); app->getEMG()->UnlistenEvent(this,0,T_EV_EraseAllLoops); app->getEMG()->UnlistenEvent(this,0,T_EV_EraseSelectedLoops); app->getEMG()->UnlistenEvent(this,0,T_EV_SlideLoopAmpStopAll); app->getEMG()->UnlistenEvent(this,0,T_EV_ALSAMixerControlSet); EventManager::DeleteQueue(savequeue); EventManager::DeleteQueue(loadqueue); // Let BMG know that we are ending app->getBMG()->RefDeleted((AutoWriteControl *) this); delete[] lastrecidx; delete[] plist; delete[] status; delete[] waitactivate; delete[] waitactivate_shot; delete[] waitactivate_vol; delete[] waitactivate_od; delete[] waitactivate_od_fb; pthread_mutex_destroy (&loops_lock); }; // Get length returns the length of any loop on the specified index nframes_t LoopManager::GetLength(int index) { if (status[index] == T_LS_Recording) { // Ooh, we are recording on this index. Get the current length return ((RecordProcessor *) plist[index])->GetRecordedLength(); } else { Loop *cur = app->getTMAP()->GetMap(index); if (cur != 0) return cur->blocks->GetTotalLen(); } return 0; } // Get length returns the length of any loop on the specified index // Rounded to its currently quantized length // Or 0 if the loop has no pulse nframes_t LoopManager::GetRoundedLength(int index) { if (status[index] == T_LS_Recording) { // Return 0 when recording return 0; // Ooh, we are recording on this index. Get the current length // return ((RecordProcessor *) plist[index])->GetRecordedLength(); } else { Loop *cur = app->getTMAP()->GetMap(index); if (cur != 0) { if (cur->pulse != 0) return cur->pulse->QuantizeLength(cur->blocks->GetTotalLen()); else return 0; // cur->blocks->GetTotalLen(); } } return 0; } float LoopManager::GetPos(int index) { if (status[index] == T_LS_Recording) return 0.0; else { Loop *cur = app->getTMAP()->GetMap(index); if (cur != 0 && plist[index] != 0) { nframes_t playedlen = 0; if (status[index] == T_LS_Playing) playedlen = ((PlayProcessor *) plist[index])->GetPlayedLength(); else if (status[index] == T_LS_Overdubbing) playedlen = ((RecordProcessor *) plist[index])->GetRecordedLength(); if (cur->pulse == 0) return (float) playedlen / cur->blocks->GetTotalLen(); else { if (cur->pulse->QuantizeLength(cur->blocks->GetTotalLen()) == 0) { printf("LoopManager: ERROR: Problem with quantize GetPos\n"); exit(1); } return (float) playedlen / cur->pulse->QuantizeLength(cur->blocks->GetTotalLen()); } } } return 0.0; } // Get current # of samples into block chain with given index nframes_t LoopManager::GetCurCnt(int index) { if (status[index] == T_LS_Recording) return 0; else { Loop *cur = app->getTMAP()->GetMap(index); if (cur != 0 && plist[index] != 0) { if (status[index] == T_LS_Playing) return ((PlayProcessor *) plist[index])->GetPlayedLength(); else if (status[index] == T_LS_Overdubbing) return ((RecordProcessor *) plist[index])->GetRecordedLength(); } } return 0; } // Sets triggered volume on specified index // If index is not playing, activates the index void LoopManager::SetTriggerVol(int index, float vol) { if (status[index] == T_LS_Playing) ((PlayProcessor *) plist[index])->SetPlayVol(vol); else if (status[index] == T_LS_Overdubbing) ((RecordProcessor *) plist[index])->SetODPlayVol(vol); } // Gets trigger volume on specified index // If index is not playing, returns 0 float LoopManager::GetTriggerVol(int index) { if (status[index] == T_LS_Playing) return ((PlayProcessor *) plist[index])->GetPlayVol(); else if (status[index] == T_LS_Overdubbing) return ((RecordProcessor *) plist[index])->GetODPlayVol(); else return 0.0; } // Returns a loop with the specified index, if one exists Loop *LoopManager::GetSlot(int index) { return app->getTMAP()->GetMap(index); } void LoopManager::AdjustOutputVolume(float adjust) { app->getRP()->AdjustOutputVolume(adjust); } void LoopManager::SetOutputVolume(float set, float logset) { if (set >= 0.) app->getRP()->SetOutputVolume(set); else if (logset >= 0.) app->getRP()->SetOutputVolume(DB2LIN(AudioLevel::fader_to_dB(logset, app->getCFG()->GetFaderMaxDB()))); } float LoopManager::GetOutputVolume() { return app->getRP()->GetOutputVolume(); } void LoopManager::AdjustInputVolume(float adjust) { app->getRP()->AdjustInputVolume(adjust); } void LoopManager::SetInputVolume(float set, float logset) { if (set >= 0.) app->getRP()->SetInputVolume(set); else if (logset >= 0.) app->getRP()->SetInputVolume(DB2LIN(AudioLevel::fader_to_dB(logset, app->getCFG()->GetFaderMaxDB()))); } float LoopManager::GetInputVolume() { return app->getRP()->GetInputVolume(); } void LoopManager::SetLoopVolume(int index, float val) { Loop *lp = app->getTMAP()->GetMap(index); if (lp != 0) { // First, preprocess for smoothing Processor *p = GetProcessor(index); if (p != 0) p->dopreprocess(); if (val >= 0.0) lp->vol = val; else lp->vol = 0.0; } } float LoopManager::GetLoopVolume(int index) { Loop *lp = app->getTMAP()->GetMap(index); if (lp != 0) return lp->vol; else return 1.0; } void LoopManager::AdjustLoopVolume(int index, float adjust) { Loop *lp = app->getTMAP()->GetMap(index); if (lp != 0) { lp->dvol += adjust*app->getAUDIO()->GetTimeScale(); if (lp->dvol < 0.0) lp->dvol = 0.0; } } void LoopManager::SetLoopdVolume(int index, float val) { Loop *lp = app->getTMAP()->GetMap(index); if (lp != 0) lp->dvol = val; } float LoopManager::GetLoopdVolume(int index) { Loop *lp = app->getTMAP()->GetMap(index); if (lp != 0) return lp->dvol; else return 1.0; } void LoopManager::SelectPulse (int pulseindex) { if (pulseindex == -1) { if (GetCurPulse() != 0) GetCurPulse()->SetMIDIClock(0); // Stop MIDI clock //printf("**Select: No pulse\n"); curpulseindex = -1; } else if (pulseindex < 0 || pulseindex >= MAX_PULSES) { printf("CORE: Invalid pulse #%d, ignoring.\n",pulseindex); return; } else if (pulses[pulseindex] == 0) { //printf("New pulse[%d]: %d SUB: %d\n", pulseindex, lastindex, subdivide); CreatePulse(lastindex, pulseindex, subdivide); } else { //printf("Select pulse[%d]\n", pulseindex); curpulseindex = pulseindex; StripePulseOn(pulses[pulseindex]); // Select pulse, send MIDI start GetCurPulse()->SetMIDIClock(1); } } // Save a whole scene, with an optional filename- // if none is given, saves a new scene void TriggerMap::Save(Fweelin *app, char *filename) { if (GetSaveStatus() == NO_SAVE) { // Scene hash is generated from hash of all loops in the triggermap-- // so start by saving all loops app->getLOOPMGR()->SetAutoLoopSaving(0); for (int i = 0; i < app->getCFG()->GetNumTriggers(); i++) app->getLOOPMGR()->SaveLoop(i); // Now, we have to wait until all that saving is done. // Queue a scene marker event in the save queue SceneMarkerEvent *sEvt = (SceneMarkerEvent *) Event::GetEventByType(T_EV_SceneMarker,1); if (filename != 0) strncpy(sEvt->s_filename,filename,FWEELIN_OUTNAME_LEN); app->getLOOPMGR()->AddToSaveQueue(sEvt); } }; void TriggerMap::SetMap (int index, Loop *smp) { if (index < 0 || index >= mapsize) { printf("SetMap: Invalid loop index!\n"); } else { map[index] = smp; TouchMap(); // Fire off a TriggerSet event TriggerSetEvent *tevt = (TriggerSetEvent *) Event::GetEventByType(T_EV_TriggerSet,1); tevt->idx = index; tevt->nw = smp; app->getEMG()->BroadcastEventNow(tevt, this); } }; void TriggerMap::GoSave(char *filename) { // All loops in the scene are now hashed and saved char newScene = (filename[0] == '\0'); // New scene or overwrite existing? if (newScene) { // Begin our save by generating a scene hash from the loop hashes // This will give us an appropriate scene filename md5_ctx md5gen; md5_init(&md5gen); for (int i = 0; i < this->mapsize; i++) if (this->map[i] != 0) { if (this->map[i]->GetSaveStatus() == SAVE_DONE) { // Update scene hash with hash from this loop const uint8_t* data = (uint8_t*)this->map[i]->GetSaveHash(); md5_update(&md5gen,SAVEABLE_HASH_LENGTH,data); } else printf("DISK: WARNING: Loop %d not saved yet but scene about to be " "saved!\n",i); } // Done- compute our final hash md5_digest(&md5gen,SAVEABLE_HASH_LENGTH,GetSaveHash()); } SetSaveStatus(SAVE_DONE); // Compose filenames & start writing char tmp[FWEELIN_OUTNAME_LEN]; if (newScene) { GET_SAVEABLE_HASH_TEXT(GetSaveHash()); snprintf(tmp,FWEELIN_OUTNAME_LEN,"%s/%s-%s%s", app->getCFG()->GetLibraryPath(),FWEELIN_OUTPUT_SCENE_NAME, hashtext,FWEELIN_OUTPUT_DATA_EXT); } else snprintf(tmp,FWEELIN_OUTNAME_LEN,"%s%s", filename,FWEELIN_OUTPUT_DATA_EXT); if (!newScene) { // Back up existing scene data struct stat st; if (stat(tmp,&st) == 0) { // First available backup filename unsigned int tmp2_size = FWEELIN_OUTNAME_LEN + 20; char tmp2[tmp2_size]; unsigned char bCnt = 1; char go = 1; do { snprintf(tmp2,tmp2_size,"%s.backup.%d",tmp,bCnt); if (stat(tmp2,&st) != 0) go = 0; // Free backup filename else bCnt++; } while (go && bCnt % 256) ; unsigned int buf_size = (FWEELIN_OUTNAME_LEN * 2) + 20; char buf[buf_size]; printf("INIT: Backup existing scene.\n"); snprintf(buf,buf_size,"mv \"%s\" \"%s\"",tmp,tmp2); printf("INIT: Executing: %s\n",buf); system(buf); } } struct stat st; printf("DISK: Opening %s '%s' for saving.\n", (newScene ? "new scene" : "existing scene"), tmp); if (newScene && stat(tmp,&st) == 0) { printf("DISK: ERROR: MD5 collision while saving scene- file exists!\n"); } else { // Save scene XML data xmlDocPtr ldat = xmlNewDoc((xmlChar *) "1.0"); if (ldat != 0) { const static int XT_LEN = 11; char xmltmp[XT_LEN]; // Scene ldat->children = xmlNewDocNode(ldat,0, (xmlChar *) FWEELIN_OUTPUT_SCENE_NAME,0); // Loops for (int i = 0; i < this->mapsize; i++) if (this->map[i] != 0 && this->map[i]->GetSaveStatus() == SAVE_DONE) { xmlNodePtr lp = xmlNewChild(ldat->children, 0, (xmlChar *) FWEELIN_OUTPUT_LOOP_NAME, 0); // Loop index snprintf(xmltmp,XT_LEN,"%d",i); xmlSetProp(lp,(xmlChar *) "loopid",(xmlChar *) xmltmp); // Loop hash (used to find the loop on disk) unsigned char *sh = this->map[i]->GetSaveHash(); GET_SAVEABLE_HASH_TEXT(sh); xmlSetProp(lp,(xmlChar *) "hash",(xmlChar *) hashtext); // Loop volume snprintf(xmltmp,XT_LEN,"%.5f",this->map[i]->vol); xmlSetProp(lp,(xmlChar *) "volume",(xmlChar *) xmltmp); } // Snapshots Snapshot *snaps = app->getSNAPS(); for (int i = 0; i < app->getCFG()->GetMaxSnapshots(); i++) { if (snaps[i].exists) { Snapshot *s = &snaps[i]; xmlNodePtr sp = xmlNewChild(ldat->children, 0, (xmlChar *) FWEELIN_OUTPUT_SNAPSHOT_NAME, 0); // Snapshot index snprintf(xmltmp,XT_LEN,"%d",i); xmlSetProp(sp,(xmlChar *) "snapid",(xmlChar *) xmltmp); // Name if (s->name != 0) xmlSetProp(sp,(xmlChar *) "name",(xmlChar *) s->name); for (int j = 0; j < s->numls; j++) { LoopSnapshot *ls = &(s->ls[j]); xmlNodePtr slp = xmlNewChild(sp, 0, (xmlChar *) FWEELIN_OUTPUT_LOOPSNAPSHOT_NAME, 0); // Loop index snprintf(xmltmp,XT_LEN,"%d",ls->l_idx); xmlSetProp(slp,(xmlChar *) "loopid",(xmlChar *) xmltmp); // Loop status snprintf(xmltmp,XT_LEN,"%d",ls->status); xmlSetProp(slp,(xmlChar *) "status",(xmlChar *) xmltmp); // Loop volume snprintf(xmltmp,XT_LEN,"%.5f",ls->l_vol); xmlSetProp(slp,(xmlChar *) "loopvol",(xmlChar *) xmltmp); // Trigger volume snprintf(xmltmp,XT_LEN,"%.5f",ls->t_vol); xmlSetProp(slp,(xmlChar *) "triggervol",(xmlChar *) xmltmp); } } } xmlSaveFormatFile(tmp,ldat,1); xmlFreeDoc(ldat); if (newScene) { // Add scene to browser so we can load it Browser *br = app->getBROWSER(B_Scene); if (br != 0) { app->setCURSCENE(app->getLOOPMGR()->AddSceneToBrowser(br,tmp)); br->AddDivisions(FWEELIN_FILE_BROWSER_DIVISION_TIME); } } printf("DISK: Close output.\n"); } } }; // If we are autosaving, we have to maintain a list of new loops to be saved void LoopManager::CheckSaveMap() { if (needs_saving_stamp != app->getTMAP()->GetLastUpdate()) { //printf("Rebuild save map.\n"); // No, rebuild! numsave = 0; savequeue = EventManager::DeleteQueue(savequeue); // Scan for loops that haven't yet been saved, add them to our list TriggerMap *tmap = app->getTMAP(); int mapsz = tmap->GetMapSize(); for (int i = 0; i < mapsz; i++) { Loop *l = tmap->GetMap(i); if (l != 0 && l->GetSaveStatus() == NO_SAVE) { // Loop exists but not saved-- add to our map LoopListEvent *ll = (LoopListEvent *) Event::GetEventByType(T_EV_LoopList,1); ll->l = l; numsave++; EventManager::QueueEvent(&savequeue,ll); } } // Now we've updated map needs_saving_stamp = tmap->GetLastUpdate(); } else { //printf("Stamp match: %lf\n",needs_saving_stamp); } } // Saves loop XML data & prepares to save loop audio void LoopManager::SetupSaveLoop(Loop *l, int /*l_idx*/, FILE **out, AudioBlock **b, AudioBlockIterator **i, nframes_t *len) { const static nframes_t LOOP_HASH_CHUNKSIZE = 10000; if (l->GetSaveStatus() == NO_SAVE) { // Now return blocks from this loop to save *b = l->blocks; #if 0 if (l->pulse != 0) // Loop is syncronized to a pulse- quantize length *len = l->pulse->QuantizeLength(l->blocks->GetTotalLen()); else #endif // Take length from blocks *len = l->blocks->GetTotalLen(); *i = 0; // Generate hash from audio data double hashtime = mygettime(); // *** Hopefully this won't take so long- or we may have to split it up // as we split up the write phase AudioBlockIterator *hashi = new AudioBlockIterator(l->blocks, LOOP_HASH_CHUNKSIZE); md5_ctx md5gen; md5_init(&md5gen); char go = 1; char stereo = l->blocks->IsStereo(); do { nframes_t pos = hashi->GetTotalLength2Cur(), remaining = *len-pos; nframes_t num = MIN(LOOP_HASH_CHUNKSIZE,remaining); sample_t *ibuf[2]; if (stereo) { // Stereo hashi->GetFragment(&ibuf[0],&ibuf[1]); const uint8_t data0 = (uint8_t)(*ibuf[0] * (sample_t)256.0); const uint8_t data1 = (uint8_t)(*ibuf[1] * (sample_t)256.0); md5_update(&md5gen,sizeof(uint8_t) * num,&data0); md5_update(&md5gen,sizeof(uint8_t) * num,&data1); } else { // Mono hashi->GetFragment(&ibuf[0],0); const uint8_t data = (uint8_t)(*ibuf[0] * (sample_t)256.0); md5_update(&md5gen,sizeof(uint8_t) * num,&data); } if (remaining <= LOOP_HASH_CHUNKSIZE) { // Finished encoding go = 0; } else hashi->NextFragment(); } while (go); // Done- compute final hash md5_digest(&md5gen,SAVEABLE_HASH_LENGTH,l->GetSaveHash()); l->SetSaveStatus(SAVE_DONE); delete hashi; double dhashtime = mygettime()-hashtime; printf("HASH TIME: %f ms\n",dhashtime * 1000); // Compose filenames & start writing char tmp[FWEELIN_OUTNAME_LEN]; GET_SAVEABLE_HASH_TEXT(l->GetSaveHash()); if (l->name == 0 || strlen(l->name) == 0) snprintf(tmp,FWEELIN_OUTNAME_LEN,"%s/%s-%s%s", app->getCFG()->GetLibraryPath(),FWEELIN_OUTPUT_LOOP_NAME, hashtext, app->getCFG()->GetAudioFileExt(app->getCFG()->GetLoopOutFormat())); else snprintf(tmp,FWEELIN_OUTNAME_LEN,"%s/%s-%s-%s%s", app->getCFG()->GetLibraryPath(),FWEELIN_OUTPUT_LOOP_NAME, hashtext,l->name, app->getCFG()->GetAudioFileExt(app->getCFG()->GetLoopOutFormat())); struct stat st; printf("DISK: Opening '%s' for saving.\n",tmp); if (stat(tmp,&st) == 0) { printf("DISK: ERROR: MD5 collision while saving loop- file exists!\n"); *b = 0; *len = 0; *i = 0; if (*out != 0) { fclose(*out); *out = 0; } } else { // Go save! *out = fopen(tmp,"wb"); if (*out == 0) { printf("DISK: ERROR: Couldn't open file! Does the folder exist and " "do you have write permission?\n"); *b = 0; *len = 0; *i = 0; if (*out != 0) { fclose(*out); *out = 0; } } else { // Add loop to browser so we can load it Browser *br = app->getBROWSER(B_Loop); if (br != 0) { AddLoopToBrowser(br,tmp); br->AddDivisions(FWEELIN_FILE_BROWSER_DIVISION_TIME); } // Main file open, now save loop XML data if (l->name == 0 || strlen(l->name) == 0) snprintf(tmp,FWEELIN_OUTNAME_LEN,"%s/%s-%s%s", app->getCFG()->GetLibraryPath(),FWEELIN_OUTPUT_LOOP_NAME, hashtext,FWEELIN_OUTPUT_DATA_EXT); else snprintf(tmp,FWEELIN_OUTNAME_LEN,"%s/%s-%s-%s%s", app->getCFG()->GetLibraryPath(),FWEELIN_OUTPUT_LOOP_NAME, hashtext,l->name,FWEELIN_OUTPUT_DATA_EXT); xmlDocPtr ldat = xmlNewDoc((xmlChar *) "1.0"); if (ldat != 0) { const static int XT_LEN = 10; char xmltmp[XT_LEN]; ldat->children = xmlNewDocNode(ldat,0, (xmlChar *) FWEELIN_OUTPUT_LOOP_NAME,0); // version snprintf(xmltmp,XT_LEN,"%d",LOOP_SAVE_FORMAT_VERSION); xmlSetProp(ldat->children,(xmlChar *) "version",(xmlChar *) xmltmp); // # beats snprintf(xmltmp,XT_LEN,"%ld",l->nbeats); xmlSetProp(ldat->children,(xmlChar *) "nbeats",(xmlChar *) xmltmp); // pulse length if (l->pulse == 0) xmlSetProp(ldat->children,(xmlChar *) "pulselen",(xmlChar *) "0"); else { snprintf(xmltmp,XT_LEN,"%d",l->pulse->GetLength()); xmlSetProp(ldat->children,(xmlChar *) "pulselen", (xmlChar *) xmltmp); } xmlSaveFormatFile(tmp,ldat,1); xmlFreeDoc(ldat); } } } } else { printf("DISK: WARNING: Loop marked already saved.\n"); *b = 0; *len = 0; *i = 0; if (*out != 0) { fclose(*out); *out = 0; } } }; // Loads loop XML data & prepares to load loop audio int LoopManager::SetupLoadLoop(FILE **in, char *smooth_end, Loop **new_loop, int /*l_idx*/, float l_vol, char *l_filename) { // Open up right file and begin loading LibraryFileInfo f = LibraryHelper::GetLoopFilenameFromStub(app,l_filename); if (f.c != UNKNOWN) { printf("DISK: Open loop '%s'\n",f.name.c_str()); *in = fopen(f.name.c_str(),"rb"); bread->SetLoopType(f.c); } else { if (*in == 0) { printf("DISK: ERROR: Couldn't open loop '%s'!\n",l_filename); return 1; } } LibraryFileInfo data = LibraryHelper::GetDataFilenameFromStub(app,l_filename); // Create loop data *new_loop = Loop::GetNewLoop(); (*new_loop)->InitLoop(0,0,1.0,l_vol,0,f.c); if (!data.exists) { printf("DISK: WARNING: Loop data '%s' missing!\n" "I will load just the raw audio.\n",l_filename); } else { xmlDocPtr ldat = xmlParseFile(data.name.c_str()); if (ldat == 0) printf("DISK: WARNING: Loop data '%s' invalid!\n" "I will load just the raw audio.\n",data.name.c_str()); else { xmlNode *root = xmlDocGetRootElement(ldat); // Extract hash from filename char fn_hash[FWEELIN_OUTNAME_LEN], loopname[FWEELIN_OUTNAME_LEN]; int baselen = strlen(app->getCFG()->GetLibraryPath()) + 1 + strlen(FWEELIN_OUTPUT_LOOP_NAME); if (!Saveable::SplitFilename(data.name.c_str(),baselen,0,fn_hash,loopname, FWEELIN_OUTNAME_LEN)) { // Set hash from filename (*new_loop)->SetSaveableHashFromText(fn_hash); // GET_SAVEABLE_HASH_TEXT((*new_loop)->GetSaveHash()); // printf("md5: %s\n",hashtext); // First, check if this loop has already been loaded // by scanning for another loop with the same hash int dupidx; if ((dupidx = app->getTMAP()->ScanForHash((*new_loop)->GetSaveHash())) != -1) { printf("DISK: (DUPLICATE) Loop to load is already loaded at " "ID #%d.\n",dupidx); (*new_loop)->RTDelete(); *new_loop = 0; fclose(*in); *in = 0; return 1; } // Set loop name from filename (*new_loop)->name = new char[strlen(loopname)+1]; strcpy((*new_loop)->name,loopname); } else printf("DISK: Loop filename '%s' missing hash!\n",l_filename); // version xmlChar *n = xmlGetProp(root, (const xmlChar *) "version"); if (n != 0) { if (atoi((char *) n) >= 1) // New format of loop save, so smooth end *smooth_end = 1; else *smooth_end = 0; xmlFree(n); } else { *smooth_end = 0; printf("DISK: Old format loop '%s'- loading with length fix.\n", l_filename); } // # beats n = xmlGetProp(root, (const xmlChar *) "nbeats"); if (n != 0) { (*new_loop)->nbeats = atoi((char *) n); xmlFree(n); } // pulse length if ((n = xmlGetProp(root, (const xmlChar *) "pulselen")) != 0) { int plen = atoi((char *) n); if (plen != 0) { // Loop should be syncronized to a pulse of given length- (*new_loop)->pulse = CreatePulse(plen); } xmlFree(n); } xmlFreeDoc(ldat); // Don't call cleanup because another thread may have xml open // xmlCleanupParser(); } } return 0; }; // Starts an interactive rename for a loop in memory void LoopManager::RenameLoop(int loopid) { if (renamer == 0) { Loop *l = GetSlot(loopid); if (l != 0) { if (CRITTERS) printf("RENAME: Loop: %p\n",l); rename_loop = l; renamer = new ItemRenamer(app,this,l->name); if (!renamer->IsRenaming()) { delete renamer; renamer = 0; rename_loop = 0; } } } }; void LoopManager::ItemRenamed(char *nw) { if (nw != 0) { // Rename on disk const static char *exts[] = {app->getCFG()->GetAudioFileExt(rename_loop->format), FWEELIN_OUTPUT_DATA_EXT}; char *old_filename = 0, *new_filename = 0; rename_loop->RenameSaveable(app->getCFG()->GetLibraryPath(), FWEELIN_OUTPUT_LOOP_NAME, rename_loop->name, nw, exts, 2, &old_filename, &new_filename); // We also need to rename in the loop browser if (app->getBROWSER(B_Loop) != 0) app->getBROWSER(B_Loop)-> ItemRenamedOnDisk(old_filename,new_filename,nw); if (old_filename != 0) delete[] old_filename; if (new_filename != 0) delete[] new_filename; // Rename in memory RenameLoop(rename_loop,nw); // We have to notify the LoopTray of the new name given LoopTray *tray = (LoopTray *) app->getBROWSER(B_Loop_Tray); if (tray != 0) tray->ItemRenamedFromOutside(rename_loop,nw); delete renamer; renamer = 0; rename_loop = 0; } else { // Rename was aborted delete renamer; renamer = 0; rename_loop = 0; } }; void LoopManager::GetWriteBlock(FILE **out, AudioBlock **b, AudioBlockIterator **i, nframes_t *len) { // If we are autosaving, check that our list is up to date if (autosave) CheckSaveMap(); // Do we have a loop to save? Event *cur = savequeue, *prev = 0; if (cursave >= numsave) { numsave = 0; cursave = 0; } int l_idx = 0; char go = 1, advance = 1; while (cur != 0 && go) { if (cur->GetType() == T_EV_LoopList) { // Loop in save queue- does it exist and is it ready to save? if ((l_idx = app->getTMAP()->SearchMap(((LoopListEvent *) cur)->l)) == -1 || GetStatus(l_idx) == T_LS_Overdubbing || GetStatus(l_idx) == T_LS_Recording) { if (l_idx == -1) { printf("DEBUG: Loop no longer exists- abort save!\n"); EventManager::RemoveEvent(&savequeue,prev,&cur); advance = 0; } // If we are overdubbing or recording, just ignore this loop // we will come back to it } else { go = 0; // Found a suitable loop to save- stop! advance = 0; } } else { if (cur->GetType() == T_EV_SceneMarker) { // Scene marker in queue indicates we need to save a scene- if (cur == savequeue) { // No loops are waiting to be saved.. go app->getTMAP()->GoSave(((SceneMarkerEvent *) cur)->s_filename); EventManager::RemoveEvent(&savequeue,prev,&cur); cursave++; advance = 0; } } } // Move to next item if (advance) { prev = cur; cur = cur->next; } else advance = 1; } if (cur != 0) { if (cur->GetType() != T_EV_LoopList) { printf("DISK: ERROR: LoopList event type mismatch!\n"); EventManager::RemoveEvent(&savequeue,prev,&cur); } else { // Remove from list Loop *curl = ((LoopListEvent *) cur)->l; EventManager::RemoveEvent(&savequeue,prev,&cur); // Open up right files, save data & setup for audio save SetupSaveLoop(curl,l_idx,out,b,i,len); cursave++; } } else { // No loops to save right now *b = 0; *len = 0; *i = 0; if (*out != 0) { fclose(*out); *out = 0; } } } // We receive calls periodically for loading of loops- void LoopManager::GetReadBlock(FILE **in, char *smooth_end) { if (curload >= numload) { numload = 0; curload = 0; } // Do we have a loop to load? Event *cur = loadqueue; if (cur != 0) { if (cur->GetType() == T_EV_LoopList) { // Open up right files, load data & setup for audio load LoopListEvent *ll = (LoopListEvent *) cur; if (SetupLoadLoop(in,smooth_end, &ll->l,ll->l_idx,ll->l_vol,ll->l_filename)) { // Not a loop or there was an error in loading EventManager::RemoveEvent(&loadqueue,0,&cur); curload++; } } else { // Not a loop- remove EventManager::RemoveEvent(&loadqueue,0,&cur); curload++; } } else { // Nothing to load right now if (*in != 0) { printf("DISK: (Load) Nothing to load- close input!\n"); fclose(*in); *in = 0; } } } void LoopManager::ReadComplete(AudioBlock *b) { curload++; // Add loop to triggermap and remove from load queue Event *cur = loadqueue; if (cur == 0 || cur->GetType() != T_EV_LoopList) printf("DISK: ERROR: Load list mismatch!\n"); else { if (b == 0) printf("DISK: ERROR: .. during load!\n"); else { LoopListEvent *ll = (LoopListEvent *) cur; // Put blocks into loop ll->l->blocks = b; if (app->getTMAP()->GetMap(ll->l_idx) != 0) { // Loop ID is full. Choose another int newidx = app->getTMAP()->GetFirstFree(default_looprange.lo, default_looprange.hi); if (newidx != -1) { printf("LOOP MANAGER: LoopID #%d full, got new ID: #%d!\n", ll->l_idx,newidx); ll->l_idx = newidx; } else { printf("LOOP MANAGER: No free loopids in default placement range.\n" "I will erase the loop at id #%d.\n",ll->l_idx); DeleteLoop(ll->l_idx); } } // Add loop to our map app->getTMAP()->SetMap(ll->l_idx,ll->l); lastindex = ll->l_idx; // Set this so we can make a pulse from this loop } // And remove from load list EventManager::RemoveEvent(&loadqueue,0,&cur); } } void LoopManager::StripePulseOn(Pulse *pulse) { app->getBMG()->StripeBlockOn(pulse,app->getAMPEAKS(), app->getAMPEAKSI()); app->getBMG()->StripeBlockOn(pulse,app->getAUDIOMEM(), app->getAUDIOMEMI()); } void LoopManager::StripePulseOff(Pulse *pulse) { app->getBMG()->StripeBlockOff(pulse,app->getAMPEAKS()); app->getBMG()->StripeBlockOff(pulse,app->getAUDIOMEM()); } // Creates a pulse of the given length in the first available slot, // if none already exists of the right length Pulse *LoopManager::CreatePulse(nframes_t len) { // First, check to see if we have a pulse of the right length- int i; for (i = 0; i < MAX_PULSES && (pulses[i] == 0 || pulses[i]->GetLength() != len); i++); if (i < MAX_PULSES) // Found it, use this pulse return pulses[i]; else { // No pulse found of right length-- create a new one for (i = 0; i < MAX_PULSES && pulses[i] != 0; i++); if (i < MAX_PULSES) { app->getRP()->AddChild(pulses[i] = new Pulse(app,len,0), ProcessorItem::TYPE_HIPRIORITY); StripePulseOn(pulses[i]); curpulseindex = i; // Send MIDI start for pulse GetCurPulse()->SetMIDIClock(1); return pulses[i]; } else // No space for a new pulse! return 0; } }; // Create a time pulse around the specified index // The length of the loop on the specified index becomes // a time constant around which other loops center themselves // subdivide the length of the loop by subdivide to get the core pulse void LoopManager::CreatePulse(int index, int pulseindex, int sub) { Loop *cur = app->getTMAP()->GetMap(index); if (cur != 0 && (status[index] == T_LS_Off || status[index] == T_LS_Playing || status[index] == T_LS_Overdubbing)) { // Set pulse length based on loop length nframes_t len = GetLength(index); if (len != 0) { // Create iterator len /= sub; // Length subdivide nframes_t startpos = 0; // So set the starting pulse position based on where loop is playing if (status[index] == T_LS_Playing) startpos = ((PlayProcessor *) plist[index])->GetPlayedLength() % len; else if (status[index] == T_LS_Overdubbing) startpos = ((RecordProcessor *) plist[index])-> GetRecordedLength() % len; app->getRP()->AddChild(cur->pulse = pulses[pulseindex] = new Pulse(app,len,startpos), ProcessorItem::TYPE_HIPRIORITY); StripePulseOn(cur->pulse); curpulseindex = pulseindex; cur->nbeats = sub; // Set # of beats in the loop // Send MIDI start for pulse GetCurPulse()->SetMIDIClock(1); // Now reconfigure processor on this index to be synced to the new pulse if (status[index] == T_LS_Playing) ((PlayProcessor *) plist[index])->SyncUp(); else if (status[index] == T_LS_Overdubbing) ((RecordProcessor *) plist[index])->SyncUp(); } } } // Taps a pulse- starting at the downbeat- if newlen is nonzero, the pulse's // length is adjusted to reflect the length between taps- and a new pulse // is created if none exists void LoopManager::TapPulse(int pulseindex, char newlen) { // If more than TIMEOUT_RATIO * the current pulse length // frames have passed since the last tap, a new length is not defined const static float TAP_NEWLEN_TIMEOUT_RATIO = 5.0, //2.0, // Higher graduation makes tempo more stable against changes TAP_NEWLEN_GRADUATION = 0.0, //0.5, // Tolerance for rejecting tap tempo changes- as fraction of current length TAP_NEWLEN_REJECT_TOLERANCE = 1.0; //0.3; if (pulseindex >= 0 || pulseindex < MAX_PULSES) { Pulse *cur = pulses[pulseindex]; if (cur == 0) { if (newlen) { // New pulse- tap now!- set zero length for now cur = pulses[pulseindex] = new Pulse(app,0,0); cur->stopped = 1; cur->prevtap = app->getRP()->GetSampleCnt(); //cur->SwitchMetronome(1); app->getRP()->AddChild(cur,ProcessorItem::TYPE_HIPRIORITY); StripePulseOn(cur); curpulseindex = pulseindex; } } else { // Refresh sync SelectPulse(-1); SelectPulse(pulseindex); // Test position of axis char nextdownbeat = 0; if (cur->GetPct() >= 0.5) nextdownbeat = 1; // Old pulse- tap now! if (newlen) { // Redefine length from tap nframes_t oldlen = cur->GetLength(), newtap = app->getRP()->GetSampleCnt(), newlen = newtap - cur->prevtap; // .. only if the new length isn't outrageous if (oldlen < 64) cur->SetLength(newlen); else if (newlen < oldlen * TAP_NEWLEN_TIMEOUT_RATIO) { // 2nd outrageous length check float ratio = (float) MIN(newlen,oldlen)/MAX(newlen,oldlen); if (ratio > 1.0-TAP_NEWLEN_REJECT_TOLERANCE) cur->SetLength((nframes_t) (oldlen*TAP_NEWLEN_GRADUATION + newlen*(1-TAP_NEWLEN_GRADUATION))); } cur->prevtap = newtap; //cur->SwitchMetronome(1); cur->stopped = 0; } if (nextdownbeat) // Tap to beginning- with wrap cur->Wrap(); else // Tap to beginning- no wrap cur->SetPos(0); // Notify external transport that we have moved app->getAUDIO()->RelocateTransport(0); } } else printf("CORE: Invalid pulse #%d, ignoring.\n",pulseindex); } void LoopManager::SwitchMetronome(int pulseindex, char active) { if (pulseindex >= 0 || pulseindex < MAX_PULSES) { Pulse *cur = pulses[pulseindex]; if (cur != 0) cur->SwitchMetronome(active); else printf("CORE: No pulse at #%d, ignoring.\n",pulseindex); } else printf("CORE: Invalid pulse #%d, ignoring.\n",pulseindex); } void LoopManager::DeletePulse(int pulseindex) { if (pulseindex < 0 || pulseindex >= MAX_PULSES) { printf("CORE: Invalid pulse #%d, ignoring.\n",pulseindex); return; } if (pulses[pulseindex] != 0) { // Stop striping beats from this pulse StripePulseOff(pulses[pulseindex]); // Erase all loops which are attached to this pulse-- or we'll have // references pointing to the deleted pulse int nt = app->getCFG()->GetNumTriggers(); for (int i = 0; i < nt; i++) if (GetPulse(i) == pulses[pulseindex]) DeleteLoop(i); // Erase this pulse Processor *p = pulses[pulseindex]; pulses[pulseindex] = 0; app->getRP()->DelChild(p); } } Pulse *LoopManager::GetPulse(int index) { Loop *lp = GetSlot(index); if (lp != 0) return lp->pulse; else return 0; } // Move the loop at specified index to another index // only works if target index is empty // returns 1 if success int LoopManager::MoveLoop (int src, int tgt) { Loop *srloop = app->getTMAP()->GetMap(src); if (srloop != 0) { Loop *tgtloop = app->getTMAP()->GetMap(tgt); if (tgtloop == 0) { app->getTMAP()->SetMap(tgt,srloop); app->getTMAP()->SetMap(src,0); plist[tgt] = plist[src]; plist[src] = 0; status[tgt] = status[src]; status[src] = T_LS_Off; waitactivate[tgt] = waitactivate[src]; waitactivate[src] = 0; waitactivate_shot[tgt] = waitactivate_shot[src]; waitactivate_shot[src] = 0; waitactivate_vol[tgt] = waitactivate_vol[src]; waitactivate_vol[src] = 0.; waitactivate_od[tgt] = waitactivate_od[src]; waitactivate_od[src] = 0; waitactivate_od_fb[tgt] = waitactivate_od_fb[src]; waitactivate_od_fb[src] = 0; for (int i = 0; i < LAST_REC_COUNT; i++) if (lastrecidx[i] == src) lastrecidx[i] = tgt; if (lastindex == src) lastindex = tgt; UpdateLoopLists_ItemMoved(src,tgt); } else return 0; } else return 0; return 1; } // Delete the loop at the specified index.. // Not RT safe! // Threadsafe void LoopManager::DeleteLoop (int index) { LockLoops(); Loop *lp = app->getTMAP()->GetMap(index); if (lp != 0) { // First, zero the map at the given index // To prevent anybody from attaching to the loop as we delete it app->getTMAP()->SetMap(index, 0); } if (plist[index] != 0) { // We have a processor on this loop! Stop it! if (status[index] == T_LS_Recording) { RecordProcessor *recp = (RecordProcessor *) plist[index]; recp->AbortRecording(); AudioBlock *recblk = recp->GetFirstRecordedBlock(); if (recblk != 0) { app->getBMG()->RefDeleted(recblk); recblk->DeleteChain(); // *** Not RT Safe if (lp != 0) lp->blocks = 0; } numrecordingloops--; } else if (status[index] == T_LS_Overdubbing) numrecordingloops--; // Remove the record/play processor Processor *p = plist[index]; plist[index] = 0; app->getRP()->DelChild(p); status[index] = T_LS_Off; waitactivate[index] = 0; waitactivate_shot[index] = 0; waitactivate_vol[index] = 0.; waitactivate_od[index] = 0; waitactivate_od_fb[index] = 0; } if (lp != 0) { if (lp->blocks != 0) { // Notify any blockmanagers working on this loop's audio to end! app->getBMG()->RefDeleted(lp->blocks); lp->blocks->DeleteChain(); // *** Not RT Safe } lp->RTDelete(); numloops--; // Update looplists/scenes to ensure that loop is removed from them UpdateLoopLists_ItemRemoved(index); } UnlockLoops(); } void LoopManager::UpdateLoopLists_ItemAdded (int l_idx) { // Update... // Snapshots Snapshot *snaps = app->getSNAPS(); for (int i = 0; i < app->getCFG()->GetMaxSnapshots(); i++) { if (snaps[i].exists) { Snapshot *s = &snaps[i]; char go = 1; for (int j = 0; go && j < s->numls; j++) if (s->ls[j].l_idx == l_idx) go = 0; if (go) { // Loop index not present in snapshot- add, defaulting to loop off LoopSnapshot *newls = 0; newls = new LoopSnapshot[s->numls+1]; memcpy(newls,s->ls,sizeof(LoopSnapshot) * s->numls); LoopSnapshot *n = &newls[s->numls]; n->l_idx = l_idx; n->status = T_LS_Off; n->l_vol = GetLoopVolume(l_idx); n->t_vol = 0.; delete[] s->ls; s->ls = newls; s->numls = s->numls+1; } } } }; void LoopManager::UpdateLoopLists_ItemRemoved (int l_idx) { // Update... // Selection sets for (int i = 0; i < NUM_LOOP_SELECTION_SETS; i++) { LoopList **ll = app->getLOOPSEL(i); *ll = LoopList::Remove(*ll,l_idx); } // Snapshots Snapshot *snaps = app->getSNAPS(); for (int i = 0; i < app->getCFG()->GetMaxSnapshots(); i++) { if (snaps[i].exists) { Snapshot *s = &snaps[i]; char go = 1; for (int j = 0; go && j < s->numls; j++) if (s->ls[j].l_idx == l_idx) { // Remove loop from list LoopSnapshot *newls = 0; if (s->numls > 1) { newls = new LoopSnapshot[s->numls-1]; // All elements preceding j memcpy(newls,s->ls,sizeof(LoopSnapshot) * j); // & following memcpy(&newls[j],&(s->ls[j+1]), sizeof(LoopSnapshot) * (s->numls-j-1)); } delete[] s->ls; s->ls = newls; s->numls = s->numls-1; go = 0; // No more checking in this snapshot } } } }; void LoopManager::UpdateLoopLists_ItemMoved (int l_idx_old, int l_idx_new) { // Update... // Selection sets for (int i = 0; i < NUM_LOOP_SELECTION_SETS; i++) { LoopList **ll = app->getLOOPSEL(i), *prev, *found = LoopList::Scan(*ll,l_idx_old,&prev); // Update index if (found != 0) found->l_idx = l_idx_new; } // Snapshots Snapshot *snaps = app->getSNAPS(); for (int i = 0; i < app->getCFG()->GetMaxSnapshots(); i++) { if (snaps[i].exists) { Snapshot *s = &snaps[i]; for (int j = 0; j < s->numls; j++) if (s->ls[j].l_idx == l_idx_old) s->ls[j].l_idx = l_idx_new; } } }; int LoopManager::GetLongCountForAllPlayingLoops(Pulse *&p) { int lc = 1; p = 0; for (int i = 0; i < app->getCFG()->GetNumTriggers(); i++) { if (app->getLOOPMGR()->GetStatus(i) == T_LS_Playing) { Loop *l = app->getTMAP()->GetMap(i); // printf("Playing loop %d - nbeats %d - pulse %p\n",i,l->nbeats,l->pulse); if (l != 0) if (l->pulse != 0 && l->nbeats > 0) { if (p == 0) { p = l->pulse; lc = math_lcm(lc,(int) l->nbeats); // printf("First LCM: %d\n",lc); } else if (l->pulse == p) { lc = math_lcm(lc,(int) l->nbeats); // printf("LCM: %d\n",lc); } else printf("CORE: More than one pulse, can't compute long count for all playing loops.\n"); } } } return lc; } // Trigger the loop at index within the map // The exact behavior varies depending on what is already happening with // this loop and the settings passed- see configuration documentation // *** Not RT Safe void LoopManager::Activate (int index, char shot, float vol, nframes_t ofs, char overdub, float *od_feedback) { // printf("ACTIVATE plist %p status %d\n",plist[index],status[index]); if (plist[index] != 0) { // We have a problem, we already have a processor on this index. // Queue the requested activate waitactivate[index] = 1; waitactivate_shot[index] = shot; waitactivate_vol[index] = vol; waitactivate_od[index] = overdub; waitactivate_od_fb[index] = od_feedback; return; } Loop *lp = app->getTMAP()->GetMap(index); if (lp == 0) { // Record a new loop float *inputvol = app->getRP()->GetInputVolumePtr(); // Where to get input vol from app->getRP()->AddChild(plist[index] = new RecordProcessor(app,app->getISET(),inputvol, GetCurPulse(), app->getAUDIOMEM(), app->getAUDIOMEMI(), app->getCFG()-> loop_peaksavgs_chunksize)); numrecordingloops++; status[index] = T_LS_Recording; // Keep track of this index in our record of last recorded indexes for (int i = LAST_REC_COUNT-1; i > 0; i--) lastrecidx[i] = lastrecidx[i-1]; lastrecidx[0] = index; } else { // A loop exists at that index if (lp->pulse != 0) lp->pulse->ExtendLongCount(lp->nbeats,1); if (overdub) { // Overdub float *inputvol = app->getRP()->GetInputVolumePtr(); // Get input vol from main app->getRP()->AddChild(plist[index] = new RecordProcessor(app, app->getISET(),inputvol, lp,vol,ofs,od_feedback)); numrecordingloops++; status[index] = T_LS_Overdubbing; } else { // Play app->getRP()->AddChild(plist[index] = new PlayProcessor(app,lp,vol,ofs)); status[index] = T_LS_Playing; } // **DEBUG** Show long count based on all playing loops /* int lcm = 1; printf("***\n"); for (int i = 0; i < app->getTMAP()->GetMapSize(); i++) { if (status[i] == T_LS_Playing) { Loop *l = app->getTMAP()->GetMap(i); lcm = math_lcm(lcm,(int) l->nbeats); printf("Loop[%d] len: %d lcm: %d\n",i,(int) l->nbeats,lcm); } }*/ } } // *** Not RT Safe void LoopManager::Deactivate (int index) { if (plist[index] == 0) { // We have a problem, there is supposed to be a processor here! printf("Nothing happening on index %d to deactivate\n",index); return; } // If we recorded something new to this index, store it in the map if (status[index] == T_LS_Recording && app->getTMAP()->GetMap(index) == 0) { // *** Perhaps make a function in RecordProcessor called // ** 'createloop'.. which does the encapsulation from the blocks Pulse *curpulse = 0; if (curpulseindex != -1) curpulse = pulses[curpulseindex]; // Adjust newloop volume so that it will match the volume // it was heard as-- since output volume does not scale // the initial monitor but does scale loops, we need to adjust float adjustednewloopvol = newloopvol / GetOutputVolume(); //printf("newlp from plist: %p\n",plist[index]); long nbeats = ((RecordProcessor *) plist[index])->GetNBeats(); if (curpulse != 0) { if (curpulse->GetPct() >= 0.5) { nbeats++; // One more beat, since record will wait til next beat curpulse->ExtendLongCount(nbeats,1); } else { if (nbeats == 0) nbeats++; // Never set to zero beats, even if the loop is shorter than 1 pulse // End record after downbeat- don't justify to end of phrase curpulse->ExtendLongCount(nbeats,0); } } // Create a loop out of the recorded blocks Loop *newlp = Loop::GetNewLoop(); newlp->InitLoop(((RecordProcessor *) plist[index])->GetFirstRecordedBlock(), curpulse,1.0,adjustednewloopvol,nbeats, app->getCFG()->GetLoopOutFormat()); app->getTMAP()->SetMap(index, newlp); UpdateLoopLists_ItemAdded(index); numloops++; lastindex = index; // Record processor will broadcast when it is ready to end! ((RecordProcessor *) plist[index])->End(); } else if (status[index] == T_LS_Overdubbing) { // Overdubbing record processor will end immediately and broadcast // EndRecord event ((RecordProcessor *) plist[index])->End(); } else if (status[index] == T_LS_Playing) { // Stop playing/overdubbing Processor *p = plist[index]; plist[index] = 0; app->getRP()->DelChild(p); status[index] = T_LS_Off; } } void LoopManager::SaveLoop(int index) { Loop *l = app->getTMAP()->GetMap(index); if (l != 0) l->Save(app); }; // Saves a new scene void LoopManager::SaveNewScene() { TriggerMap *tm = app->getTMAP(); if (tm != 0) tm->Save(app); }; // Saves over current scene void LoopManager::SaveCurScene() { if (app->getCURSCENE() == 0) SaveNewScene(); else { TriggerMap *tm = app->getTMAP(); if (tm != 0) tm->Save(app,app->getCURSCENE()->filename); } }; // Load loop from disk into the given index void LoopManager::LoadLoop(char *filename, int index, float vol) { AddLoopToLoadQueue(filename,index,vol); }; // Load scene from disk void LoopManager::LoadScene(SceneBrowserItem *i) { char *filename = i->filename; // Load XML data for scene char tmp[FWEELIN_OUTNAME_LEN], tmp2[FWEELIN_OUTNAME_LEN]; snprintf(tmp,FWEELIN_OUTNAME_LEN,"%s%s", filename,FWEELIN_OUTPUT_DATA_EXT); xmlDocPtr dat = xmlParseFile(tmp); if (dat == 0) printf("DISK: ERROR: Scene data '%s' invalid or missing!\n",tmp); else { xmlNode *root = xmlDocGetRootElement(dat); if (!root || !root->name || xmlStrcmp(root->name,(const xmlChar *) FWEELIN_OUTPUT_SCENE_NAME)) printf("DISK: ERROR: Scene data '%s' bad format!\n",tmp); else { for (xmlNode *cur_node = root->children; cur_node != NULL; cur_node = cur_node->next) { if ((!xmlStrcmp(cur_node->name, (const xmlChar *) FWEELIN_OUTPUT_LOOP_NAME))) { // Loop within scene-- read int l_idx = loadloopid; float vol = 1.0; // Loopid xmlChar *n = xmlGetProp(cur_node, (const xmlChar *) "loopid"); if (n != 0) { l_idx = atoi((char *) n); xmlFree(n); } // Volume if ((n = xmlGetProp(cur_node, (const xmlChar *) "volume")) != 0) { vol = atof((char *) n); xmlFree(n); } // Hash if ((n = xmlGetProp(cur_node, (const xmlChar *) "hash")) != 0) { // Compose loop filename from hash snprintf(tmp2,FWEELIN_OUTNAME_LEN,"%s/%s-%s", app->getCFG()->GetLibraryPath(), FWEELIN_OUTPUT_LOOP_NAME,n); xmlFree(n); // Load the loop into the specified index printf(" (loopid %d vol %.5f filename %s)\n", l_idx,vol,tmp2); LoadLoop(tmp2,l_idx,vol); // sleep(2); } else printf("DISK: Scene definition for loop (id %d) has missing " "hash!\n",l_idx); } else if ((!xmlStrcmp(cur_node->name, (const xmlChar *) FWEELIN_OUTPUT_SNAPSHOT_NAME))) { // Snapshot within scene-- read int snapid = 0; char sgo = 1; // Snapshot index xmlChar *n = xmlGetProp(cur_node, (const xmlChar *) "snapid"); if (n != 0) { snapid = atoi((char *) n); xmlFree(n); } // Check if snapshot exists- if so, find another slot if (app->getSNAP(snapid) == 0 || app->getSNAP(snapid)->exists) { Snapshot *snaps = app->getSNAPS(); char go = 1; int i = 0; while (go && i < app->getCFG()->GetMaxSnapshots()) { if (!snaps[i].exists) go = 0; else i++; } if (go) { printf("DISK: No space to load snapshot in scene-\n" "please raise maximum # of snapshots in configuration!\n"); sgo = 0; } else snapid = i; } if (sgo) { // Name n = xmlGetProp(cur_node, (const xmlChar *) "name"); printf(" (snapshot: %s)\n",n); Snapshot *s = app->LoadSnapshot(snapid,(char *) n); if (n != 0) xmlFree(n); // Now, count loop snapshots given in snapshot if (s != 0) { int numls = 0; for (xmlNode *ls_node = cur_node->children; ls_node != NULL; ls_node = ls_node->next) { if ((!xmlStrcmp(ls_node->name, (const xmlChar *) FWEELIN_OUTPUT_LOOPSNAPSHOT_NAME))) { numls++; } } printf(" (%d loops in snapshot)\n",numls); // Setup & load loop snapshots s->numls = numls; if (numls > 0) s->ls = new LoopSnapshot[numls]; else s->ls = 0; int i = 0; for (xmlNode *ls_node = cur_node->children; ls_node != NULL; ls_node = ls_node->next) { if ((!xmlStrcmp(ls_node->name, (const xmlChar *) FWEELIN_OUTPUT_LOOPSNAPSHOT_NAME))) { LoopSnapshot *ls = &(s->ls[i]); // Loop index xmlChar *nn = xmlGetProp(ls_node, (const xmlChar *) "loopid"); if (nn != 0) { ls->l_idx = atoi((char *) nn); xmlFree(nn); } // Loop status nn = xmlGetProp(ls_node, (const xmlChar *) "status"); if (nn != 0) { ls->status = (LoopStatus) atoi((char *) nn); xmlFree(nn); } // Loop volume nn = xmlGetProp(ls_node, (const xmlChar *) "loopvol"); if (nn != 0) { ls->l_vol = atof((char *) nn); xmlFree(nn); } // Trigger volume nn = xmlGetProp(ls_node, (const xmlChar *) "triggervol"); if (nn != 0) { ls->t_vol = atof((char *) nn); xmlFree(nn); } i++; } } } } } } // Now, remember this scene is loaded app->setCURSCENE(i); } } xmlFreeDoc(dat); // Don't call cleanup because another thread may have xml open // xmlCleanupParser(); }; void LoopManager::ReceiveEvent(Event *ev, EventProducer *from) { switch (ev->GetType()) { case T_EV_EndRecord : // Recording has ended on one of the RecordProcessors- find it! for (int i = 0; i < app->getTMAP()->GetMapSize(); i++) if (plist[i] == from) { // Should we keep this recording if (!((EndRecordEvent *) ev)->keeprecord) { DeleteLoop(i); // No } else { nframes_t playofs = 0; if (status[i] == T_LS_Recording) { // Adjust number of beats in loop based on the recording // (this is now done immediately based on sync position) /* app->getTMAP()->GetMap(i)->nbeats = ((RecordProcessor *) plist[i])->GetNBeats(); */ Pulse *recsync = ((RecordProcessor *) plist[i])->GetPulse(); // Sync recording may have ended late, so start play where we // left off if (recsync != 0) playofs = recsync->GetPos(); } else if (status[i] == T_LS_Overdubbing) { // Start play at position where overdub left off playofs = ((RecordProcessor *) plist[i])->GetRecordedLength(); } // Remove recordprocessor from chain Processor *p = plist[i]; plist[i] = 0; app->getRP()->DelChild(p); numrecordingloops--; status[i] = T_LS_Off; // Check if we need to activate a playprocessor if (waitactivate[i]) { waitactivate[i] = 0; // Activate is not RT safe (new processor alloc) // So this event thread had better be nonRT! Activate(i,waitactivate_shot[i],waitactivate_vol[i], playofs, waitactivate_od[i],waitactivate_od_fb[i]); } } } break; case T_EV_ToggleDiskOutput : { // OK! if (CRITTERS) printf("CORE: Received ToggleDiskOutputEvent\n"); app->ToggleDiskOutput(); } break; case T_EV_ToggleSelectLoop : { ToggleSelectLoopEvent *sev = (ToggleSelectLoopEvent *) ev; // OK! if (CRITTERS) printf("CORE: Received ToggleSelectLoopEvent: Set %d Loop ID %d\n", sev->setid,sev->loopid); LoopList **ll = app->getLOOPSEL(sev->setid); if (ll != 0) { // Get loop with id Loop *l = app->getTMAP()->GetMap(sev->loopid); if (l != 0) { LoopList *prev; LoopList *exists = LoopList::Scan(*ll,sev->loopid,&prev); if (exists != 0) { // printf("REMOVE!\n"); *ll = LoopList::Remove(*ll,exists,prev); l->ChangeSelectedCount(-1); } else { // printf("ADD!\n"); *ll = LoopList::AddBegin(*ll,sev->loopid); l->ChangeSelectedCount(1); } } } else printf("CORE: Invalid set id #%d when selecting loop\n",sev->setid); } break; case T_EV_SelectOnlyPlayingLoops : { SelectOnlyPlayingLoopsEvent *sev = (SelectOnlyPlayingLoopsEvent *) ev; // OK! if (CRITTERS) printf("CORE: Received SelectOnlyPlayingLoopsEvent: Set %d [%s]\n", sev->setid,(sev->playing ? "PLAYING" : "IDLE")); LoopList **ll = app->getLOOPSEL(sev->setid); if (ll != 0) { // Scan all loops for playing loops for (int i = 0; i < app->getCFG()->GetNumTriggers(); i++) { Loop *l = app->getTMAP()->GetMap(i); if (GetStatus(i) == T_LS_Overdubbing || GetStatus(i) == T_LS_Playing) { if (l != 0) { // Loop exists, and it's playing! LoopList *prev; LoopList *exists = LoopList::Scan(*ll,i,&prev); if (!sev->playing && exists != 0) { // printf("REMOVE!\n"); *ll = LoopList::Remove(*ll,exists,prev); l->ChangeSelectedCount(-1); } else if (sev->playing && exists == 0) { // printf("ADD!\n"); *ll = LoopList::AddBegin(*ll,i); l->ChangeSelectedCount(1); } } } else if (app->getTMAP()->GetMap(i) != 0) { // Loop exists, but not playing/overdubbing LoopList *prev; LoopList *exists = LoopList::Scan(*ll,i,&prev); if (sev->playing && exists != 0) { // printf("REMOVE!\n"); *ll = LoopList::Remove(*ll,exists,prev); l->ChangeSelectedCount(-1); } else if (!sev->playing && exists == 0) { // printf("ADD!\n"); *ll = LoopList::AddBegin(*ll,i); l->ChangeSelectedCount(1); } } } } else printf("CORE: Invalid set id #%d when selecting loop\n",sev->setid); } break; case T_EV_SelectAllLoops : { SelectAllLoopsEvent *sev = (SelectAllLoopsEvent *) ev; // OK! if (CRITTERS) printf("CORE: Received SelectAllLoopsEvent: Set %d [%s]\n", sev->setid,(sev->select ? "SELECT" : "UNSELECT")); LoopList **ll = app->getLOOPSEL(sev->setid); if (ll != 0) { // Scan all loops for (int i = 0; i < app->getCFG()->GetNumTriggers(); i++) { Loop *l = app->getTMAP()->GetMap(i); if (l != 0) { // Loop exists in map LoopList *prev; LoopList *exists = LoopList::Scan(*ll,i,&prev); if (!sev->select && exists != 0) { // Unselect loops- remove loop from list // printf("REMOVE!\n"); *ll = LoopList::Remove(*ll,exists,prev); l->ChangeSelectedCount(-1); } else if (sev->select && exists == 0) { // Select loops- add loop to list // printf("ADD!\n"); *ll = LoopList::AddBegin(*ll,i); l->ChangeSelectedCount(1); } } } } else printf("CORE: Invalid set id #%d when selecting loop\n",sev->setid); } break; case T_EV_InvertSelection : { InvertSelectionEvent *sev = (InvertSelectionEvent *) ev; // OK! if (CRITTERS) printf("CORE: Received InvertSelectionEvent: Set %d\n",sev->setid); LoopList **ll = app->getLOOPSEL(sev->setid); if (ll != 0) { // Scan all loops for (int i = 0; i < app->getCFG()->GetNumTriggers(); i++) { Loop *l = app->getTMAP()->GetMap(i); if (l != 0) { // Loop exists in map LoopList *prev; LoopList *exists = LoopList::Scan(*ll,i,&prev); if (exists != 0) { // Loop exists in list- remove // printf("REMOVE!\n"); *ll = LoopList::Remove(*ll,exists,prev); l->ChangeSelectedCount(-1); } else if (exists == 0) { // Loop not in list- add // printf("ADD!\n"); *ll = LoopList::AddBegin(*ll,i); l->ChangeSelectedCount(1); } } } } else printf("CORE: Invalid set id #%d when selecting loop\n",sev->setid); } break; case T_EV_TriggerSnapshot : { TriggerSnapshotEvent *sev = (TriggerSnapshotEvent *) ev; // OK! if (CRITTERS) printf("CORE: Received TriggerSnapshotEvent: Snapshot #%d\n", sev->snapid); if (app->TriggerSnapshot(sev->snapid)) printf("CORE: Invalid snapshot #%d- can't trigger\n",sev->snapid); } break; case T_EV_CreateSnapshot : { CreateSnapshotEvent *sev = (CreateSnapshotEvent *) ev; // OK! if (CRITTERS) printf("CORE: Received CreateSnapshotEvent: Snapshot #%d\n", sev->snapid); if (app->CreateSnapshot(sev->snapid) == 0) printf("CORE: Invalid snapshot #%d- can't create\n",sev->snapid); } break; case T_EV_SwapSnapshots : { SwapSnapshotsEvent *sev = (SwapSnapshotsEvent *) ev; // OK! if (CRITTERS) printf("CORE: Received SwapSnapshotsEvent: Snapshot #%d <> #%d\n", sev->snapid1,sev->snapid2); if (app->SwapSnapshots(sev->snapid1,sev->snapid2) != 0) printf("CORE: Invalid snapshot- can't swap\n"); } break; case T_EV_RenameSnapshot : { RenameSnapshotEvent *sev = (RenameSnapshotEvent *) ev; // OK! if (CRITTERS) printf("CORE: Received RenameSnapshotEvent: Snapshot #%d\n", sev->snapid); FloDisplaySnapshots *sdisp = (FloDisplaySnapshots *) app->getCFG()->GetDisplayByType(FD_Snapshots); if (sdisp != 0) sdisp->Rename(sev->snapid); } break; case T_EV_SetSelectedLoopsTriggerVolume : { SetSelectedLoopsTriggerVolumeEvent *sev = (SetSelectedLoopsTriggerVolumeEvent *) ev; // OK! if (CRITTERS) printf("CORE: Received SetSelectedLoopsTriggerVolumeEvent: Set %d: Volume %f\n", sev->setid,sev->vol); LoopList **ll = app->getLOOPSEL(sev->setid); if (ll != 0) { LoopList *cur = *ll; while (cur != 0) { SetTriggerVol(cur->l_idx,sev->vol); cur = cur->next; } } else printf("CORE: Invalid set id #%d when selecting loop\n",sev->setid); } break; case T_EV_AdjustSelectedLoopsAmp : { AdjustSelectedLoopsAmpEvent *sev = (AdjustSelectedLoopsAmpEvent *) ev; // OK! if (CRITTERS) printf("CORE: Received AdjustSelectedLoopsAmpEvent: Set %d: " "Amp factor %f\n", sev->setid,sev->ampfactor); LoopList **ll = app->getLOOPSEL(sev->setid); if (ll != 0) { LoopList *cur = *ll; while (cur != 0) { SetLoopVolume(cur->l_idx, sev->ampfactor * GetLoopVolume(cur->l_idx)); cur = cur->next; } } else printf("CORE: Invalid set id #%d when selecting loop\n",sev->setid); } break; case T_EV_EraseSelectedLoops : { EraseSelectedLoopsEvent *sev = (EraseSelectedLoopsEvent *) ev; // OK! if (CRITTERS) printf("CORE: Received EraseSelectedLoopsEvent: Set: %d\n",sev->setid); LoopList **ll = app->getLOOPSEL(sev->setid); if (ll != 0) { LoopList *cur = *ll; while (cur != 0) { DeleteLoop(cur->l_idx); cur = cur->next; } } else printf("CORE: Invalid set id #%d when erasing selected loops\n", sev->setid); } break; case T_EV_SetAutoLoopSaving : { SetAutoLoopSavingEvent *sev = (SetAutoLoopSavingEvent *) ev; // OK! if (CRITTERS) printf("CORE: Received SetAutoLoopSavingEvent (%s)\n", (sev->save ? "on" : "off")); SetAutoLoopSaving(sev->save); } break; case T_EV_SaveLoop : { SaveLoopEvent *sev = (SaveLoopEvent *) ev; // OK! if (CRITTERS) printf("CORE: Received SaveLoopEvent (%d)\n",sev->index); SaveLoop(sev->index); } break; case T_EV_SaveNewScene : { // OK! if (CRITTERS) printf("CORE: Received SaveNewSceneEvent\n"); SaveNewScene(); } break; case T_EV_SaveCurrentScene : { // OK! if (CRITTERS) printf("CORE: Received SaveCurrentSceneEvent\n"); SaveCurScene(); } break; case T_EV_SetLoadLoopId : { SetLoadLoopIdEvent *sev = (SetLoadLoopIdEvent *) ev; // OK! if (CRITTERS) printf("CORE: Received SetLoadLoopIdEvent (%d)\n",sev->index); loadloopid = sev->index; } break; case T_EV_SetDefaultLoopPlacement : { SetDefaultLoopPlacementEvent *sev = (SetDefaultLoopPlacementEvent *) ev; // OK! if (CRITTERS) printf("CORE: Received SetDefaultLoopPlacementEvent (%d>%d)\n", sev->looprange.lo,sev->looprange.hi); default_looprange = sev->looprange; } break; case T_EV_SlideMasterInVolume : { SlideMasterInVolumeEvent *vev = (SlideMasterInVolumeEvent *) ev; // OK! if (CRITTERS) printf("CORE: Received SlideMasterInVolumeEvent(%f)\n", vev->slide); AdjustInputVolume(vev->slide); } break; case T_EV_SlideMasterOutVolume : { SlideMasterOutVolumeEvent *vev = (SlideMasterOutVolumeEvent *) ev; // OK! if (CRITTERS) printf("CORE: Received SlideMasterOutVolumeEvent(%f)\n", vev->slide); AdjustOutputVolume(vev->slide); } break; case T_EV_SlideInVolume : { SlideInVolumeEvent *vev = (SlideInVolumeEvent *) ev; // OK! if (CRITTERS) printf("CORE: Received SlideInVolumeEvent(%d: %f)\n", vev->input, vev->slide); app->getISET()->AdjustInputVol(vev->input-1, vev->slide); } break; case T_EV_SetMasterInVolume : { SetMasterInVolumeEvent *vev = (SetMasterInVolumeEvent *) ev; // OK! if (CRITTERS) printf("CORE: Received SetMasterInVolumeEvent(%f, %f)\n", vev->vol, vev->fadervol); SetInputVolume(vev->vol,vev->fadervol); } break; case T_EV_SetMasterOutVolume : { SetMasterOutVolumeEvent *vev = (SetMasterOutVolumeEvent *) ev; // OK! if (CRITTERS) printf("CORE: Received SetMasterOutVolumeEvent(%f, %f)\n", vev->vol, vev->fadervol); SetOutputVolume(vev->vol,vev->fadervol); } break; case T_EV_SetInVolume : { SetInVolumeEvent *vev = (SetInVolumeEvent *) ev; // OK! if (CRITTERS) printf("CORE: Received SetInVolumeEvent(%d: %f, %f)\n", vev->input, vev->vol, vev->fadervol); app->getISET()->SetInputVol(vev->input-1, vev->vol, vev->fadervol); } break; case T_EV_ToggleInputRecord : { ToggleInputRecordEvent *vev = (ToggleInputRecordEvent *) ev; // OK! if (CRITTERS) printf("CORE: Received ToggleInputRecordEvent(%d)\n", vev->input); app->getISET()->SelectInput(vev->input-1,(app->getISET()->InputSelected(vev->input-1) == 0 ? 1 : 0)); } break; case T_EV_DeletePulse : { DeletePulseEvent *dev = (DeletePulseEvent *) ev; // OK! if (CRITTERS) printf("CORE: Received DeletePulse(%d)\n", dev->pulse); DeletePulse(dev->pulse); } break; case T_EV_SelectPulse : { SelectPulseEvent *sev = (SelectPulseEvent *) ev; // OK! if (CRITTERS) printf("CORE: Received SelectPulse(%d)\n", sev->pulse); SelectPulse(sev->pulse); } break; case T_EV_TapPulse : { TapPulseEvent *tev = (TapPulseEvent *) ev; // OK! if (CRITTERS) printf("CORE: Received TapPulse(%d) %s\n", tev->pulse, (tev->newlen ? "[new length]" : "")); TapPulse(tev->pulse,tev->newlen); } break; case T_EV_SwitchMetronome : { SwitchMetronomeEvent *swev = (SwitchMetronomeEvent *) ev; // OK! if (CRITTERS) printf("CORE: Received SwitchMetronome(%d) %s\n", swev->pulse, (swev->metronome ? "[on]" : "[off]")); SwitchMetronome(swev->pulse,swev->metronome); } break; case T_EV_SetSyncType : { SetSyncTypeEvent *sev = (SetSyncTypeEvent *) ev; // OK! if (CRITTERS) printf("CORE: Received SetSyncType(%d)\n", sev->stype); app->SetSyncType(sev->stype); } break; case T_EV_SetSyncSpeed : { SetSyncSpeedEvent *sev = (SetSyncSpeedEvent *) ev; // OK! if (CRITTERS) printf("CORE: Received SetSyncSpeed(%d)\n", sev->sspd); app->SetSyncSpeed(sev->sspd); } break; case T_EV_SetMidiSync : { SetMidiSyncEvent *sev = (SetMidiSyncEvent *) ev; // OK! if (CRITTERS) printf("CORE: Received SetMidiSync(%d)\n", sev->midisync); app->getMIDI()->SetMIDISyncTransmit(sev->midisync); app->RefreshPulseSync(); } break; case T_EV_SetTriggerVolume : { SetTriggerVolumeEvent *laev = (SetTriggerVolumeEvent *) ev; // OK! if (CRITTERS) printf("CORE: Received SetTriggerVolume(%d,%f)\n", laev->index, laev->vol); SetTriggerVol(laev->index,laev->vol); } break; case T_EV_SlideLoopAmp : { SlideLoopAmpEvent *laev = (SlideLoopAmpEvent *) ev; // OK! if (CRITTERS) printf("CORE: Received SlideLoopAmp(%d,%f)\n", laev->index, laev->slide); AdjustLoopVolume(laev->index,laev->slide); } break; case T_EV_SetLoopAmp : { SetLoopAmpEvent *laev = (SetLoopAmpEvent *) ev; // OK! if (CRITTERS) printf("CORE: Received SetLoopAmp(%d,%f)\n", laev->index, laev->amp); SetLoopVolume(laev->index,laev->amp); } break; case T_EV_AdjustLoopAmp : { AdjustLoopAmpEvent *laev = (AdjustLoopAmpEvent *) ev; // OK! if (CRITTERS) printf("CORE: Received AdjustLoopAmp(%d,%f)\n", laev->index, laev->ampfactor); SetLoopVolume(laev->index, laev->ampfactor * GetLoopVolume(laev->index)); } break; case T_EV_TriggerLoop : { TriggerLoopEvent *tev = (TriggerLoopEvent *) ev; int index = tev->index, engage = tev->engage; float vol = tev->vol; char od = tev->od, shot = tev->shot; UserVariable *od_fb = tev->od_fb; float *od_fb_ptr = 0; if (od_fb != 0) { if (od_fb->GetType() == T_float) od_fb_ptr = (float *) od_fb->GetValue(); else printf("CORE: ERROR: Overdub feedback assigned to variable '%s'- but that variable is not a 'float'!\n",od_fb->GetName()); } // OK! if (CRITTERS) { printf("CORE: Received TriggerLoop(%d,%.2f)", index, vol); if (od) { printf(" [overdub]"); if (od_fb != 0) { printf(" (feedback "); od_fb->Print(); printf(")\n"); } else printf("\n"); } if (shot) printf(" (shot)"); if (engage != -1) printf(" (%s)\n",(engage ? "force on" : "force off")); else printf("\n"); } if ((engage == -1 || engage == 1) && (GetStatus(index) == T_LS_Recording || GetStatus(index) == T_LS_Overdubbing || (GetStatus(index) == T_LS_Playing && od == 1))) { // Stop-start case nframes_t ofs = 0; if (GetStatus(index) == T_LS_Overdubbing && od == 1) { // Don't allow retrigger from overdub to overdub-- override to play od = 0; } else if (GetStatus(index) == T_LS_Playing) { // Play->overdub case- start overdub where play left off ofs = ((PlayProcessor *) plist[index])->GetPlayedLength(); } Deactivate(index); // Stop Activate(index,shot,vol,ofs,od,od_fb_ptr); // Start } else if ((engage == -1 || engage == 0) && IsActive(index)) { // Stop case (play and no overdub) Deactivate(index); } else if (engage == -1 || engage == 1) { // Start case (record) Activate(index,shot,vol,0,od,od_fb_ptr); } } break; case T_EV_TriggerSelectedLoops : { TriggerSelectedLoopsEvent *tev = (TriggerSelectedLoopsEvent *) ev; if (CRITTERS) printf("CORE: Received TriggerSelectedLoops(set #%d,%.2f)\n", tev->setid,tev->vol); LoopList **ll = app->getLOOPSEL(tev->setid); if (ll != 0) { // Get all loops from this set LoopList *cur = *ll; while (cur != 0) { if (IsActive(cur->l_idx)) { // Overdub/play on this loop if (tev->toggleloops) Deactivate(cur->l_idx); } else { // Loop idle-- start play // No overdub/shot/etc, just straight play Activate(cur->l_idx,0,tev->vol,0,0,0); } cur = cur->next; } } else printf("CORE: Invalid set id #%d when triggering selected loops\n", tev->setid); } break; case T_EV_MoveLoop : { MoveLoopEvent *mev = (MoveLoopEvent *) ev; // OK! if (CRITTERS) printf("CORE: Received MoveLoop(%d->%d)\n", mev->oldloopid, mev->newloopid); MoveLoop(mev->oldloopid,mev->newloopid); } break; case T_EV_RenameLoop : { RenameLoopEvent *rev = (RenameLoopEvent *) ev; if (rev->in == 1) { RenameLoop(rev->loopid); if (CRITTERS) printf("LOOPMGR: Received RenameLoop(loopid: %d)\n",rev->loopid); } } break; case T_EV_EraseLoop : { EraseLoopEvent *eev = (EraseLoopEvent *) ev; // OK! if (CRITTERS) printf("CORE: Received EraseLoop(%d)\n", eev->index); DeleteLoop(eev->index); } break; case T_EV_EraseAllLoops : { // OK! if (CRITTERS) printf("CORE: Received EraseAllLoops\n"); // Erase scene settings app->setCURSCENE(0); // Erase all loops! // printf("DEBUG: ERASE LOOPS!\n"); for (int i = 0; i < app->getCFG()->GetNumTriggers(); i++) DeleteLoop(i); // And all pulses! // printf("DEBUG: ERASE PULSES!\n"); for (int i = 0; i < MAX_PULSES; i++) DeletePulse(i); // printf("DEBUG: DONE!\n\n"); // And all snapshots! Snapshot *s = app->getSNAPS(); for (int i = 0; i < app->getCFG()->GetMaxSnapshots(); i++) s[i].DeleteSnapshot(); } break; case T_EV_SlideLoopAmpStopAll : { // OK! if (CRITTERS) printf("CORE: Received SlideLoopAmpStopAll\n"); for (int i = 0; i < app->getCFG()->GetNumTriggers(); i++) SetLoopdVolume(i,1.0); } break; case T_EV_ALSAMixerControlSet : { ALSAMixerControlSetEvent *aev = (ALSAMixerControlSetEvent *) ev; // OK! if (CRITTERS) printf("CORE: Received AlsaMixerControlSet (hw:%d numid=%d %d,%d,%d,%d)\n", aev->hwid,aev->numid,aev->val1,aev->val2,aev->val3,aev->val4); #ifdef __MACOSX__ printf("CORE: Not implemented on Mac.\n"); #else app->getHMIX()->ALSAMixerControlSet(aev->hwid,aev->numid, aev->val1,aev->val2,aev->val3,aev->val4); #endif } break; default: break; } } int Fweelin::go() { running = 1; // Final setup // Broadcast start session event! Event *proto = Event::GetEventByType(T_EV_StartSession); if (proto == 0) { printf("GO: Can't get start event prototype!\n"); } else { Event *cpy = (Event *) proto->RTNew(); if (cpy == 0) printf("CORE: WARNING: Can't send event- RTNew() failed\n"); else emg->BroadcastEventNow(cpy, this); } // Broadcast events for starting all interfaces! cfg->StartInterfaces(); // Encourage the user! printf("\n-- ** OKIE DOKIE, KIDDO! ** --\n"); // *** SDL IO is now done in main thread- Mac OS X SDL requires it, and on Linux it's one less thread SDLIO::run_sdl_thread(sdlio); // Old method #if 0 // Now just wait.. the threads will take care of everything while (sdlio->IsActive()) { usleep(100000); }; #endif // Cleanup if (vid != 0) vid->close(); sdlio->close(); midi->close(); audio->close(); if (vid != 0) delete vid; delete sdlio; delete midi; delete hmix; delete audio; delete iset; delete abufs; delete[] snaps; delete[] fs_inputs; #ifndef __MACOSX__ delete osc; #endif #if USE_FLUIDSYNTH delete fluidp; #endif delete[] browsers; printf("MAIN: end stage 1\n"); //sleep(1); // Manually reset audio memory to its original state- // not preallocated! getAMPEAKS()->SetupPreallocated(0,Preallocated::PREALLOC_BASE_INSTANCE); getAMAVGS()->SetupPreallocated(0,Preallocated::PREALLOC_BASE_INSTANCE); audiomem->SetupPreallocated(0,Preallocated::PREALLOC_BASE_INSTANCE); // And main classes.. delete tmap; printf(" 1\n"); delete loopmgr; printf(" 2\n"); delete rp; printf(" 3\n"); delete bmg; printf(" 4\n"); printf("MAIN: end stage 2\n"); //::delete audiomem; delete[] scope; printf("MAIN: end stage 3\n"); // Delete preallocated type managers delete pre_audioblock; delete pre_extrachannel; delete pre_timemarker; printf("MAIN: end stage 4\n"); //sleep(2); delete cfg; printf(" 1\n"); //sleep(2); delete emg; //sleep(2); printf(" 2\n"); delete mmg; SDL_Quit(); RT_RWThreads::CloseAll(); printf("MAIN: end\n"); return 0; } BED_MarkerPoints *Fweelin::getAMPEAKSPULSE() { AudioBlock *peaks = getAMPEAKS(); if (peaks != 0) return dynamic_cast (getAMPEAKS()->GetExtendedData(T_BED_MarkerPoints)); else return 0; }; AudioBlock *Fweelin::getAMPEAKS() { return dynamic_cast(bmg->GetBlockManager(audiomem, T_MC_PeaksAvgs))-> GetPeaks(); }; AudioBlock *Fweelin::getAMAVGS() { return dynamic_cast(bmg->GetBlockManager(audiomem, T_MC_PeaksAvgs))-> GetAvgs(); }; AudioBlockIterator *Fweelin::getAMPEAKSI() { return dynamic_cast(bmg->GetBlockManager(audiomem, T_MC_PeaksAvgs))-> GetPeaksI(); }; AudioBlockIterator *Fweelin::getAMAVGSI() { return dynamic_cast(bmg->GetBlockManager(audiomem, T_MC_PeaksAvgs))-> GetAvgsI(); }; AudioBlockIterator *Fweelin::getAUDIOMEMI() { return amrec->GetIterator(); }; Browser *Fweelin::GetBrowserFromConfig(BrowserItemType b) { FloDisplay *cur = cfg->displays; while (cur != 0) { if (cur->GetFloDisplayType() == FD_Browser && ((Browser *) cur)->GetType() == b) return (Browser *) cur; cur = cur->next; } return 0; }; // Returns non-zero if all streamers have status 'status', else zero char Fweelin::CheckStreamStatus(char status) { char check = 1; if (fs_finalout != 0) check &= fs_finalout->GetStatus() == status; if (fs_loopout != 0) check &= fs_loopout->GetStatus() == status; for (int i = 0; i < iset->GetNumInputs(); i++) if (fs_inputs[i] != 0) check &= fs_inputs[i]->GetStatus() == status; return check; }; void Fweelin::ToggleDiskOutput() { if (CheckStreamStatus(FileStreamer::STATUS_STOPPED)) { // Create appropriate base filename for output streamoutname = LibraryHelper::GetNextAvailableStreamOutFilename(this,writenum,streamoutname_display); // Now start all streamers char write_timing = 1; // Only write timing file once if (fs_finalout != 0) { fs_finalout->StartWriting(streamoutname,"-final",write_timing,getCFG()->GetStreamOutFormat()); write_timing = 0; } if (fs_loopout != 0) { fs_loopout->StartWriting(streamoutname,"-loops",write_timing,getCFG()->GetStreamOutFormat()); write_timing = 0; } for (int i = 0; i < iset->GetNumInputs(); i++) if (fs_inputs[i] != 0) { std::ostringstream tmp; tmp << "-input" << i+1; fs_inputs[i]->StartWriting(streamoutname,tmp.str().c_str(),write_timing,getCFG()->GetStreamOutFormat()); write_timing = 0; } } else { // Stop disk output if (fs_finalout != 0) fs_finalout->StopWriting(); if (fs_loopout != 0) fs_loopout->StopWriting(); for (int i = 0; i < iset->GetNumInputs(); i++) if (fs_inputs[i] != 0) fs_inputs[i]->StopWriting(); streamoutname = ""; streamoutname_display = ""; // Advance to next logical filename writenum++; } }; long int Fweelin::getSTREAMSIZE(FileStreamer *fs, char &frames) { const char *streamname = fs->GetOutputName().c_str(); struct stat st; if (stat(streamname,&st) == 0) { frames = 0; return st.st_size; } else { frames = 1; return fs->GetOutputSize(); } } float Fweelin::getSTREAMSTATS(char *&stream_type, int &num_streams) { stream_type = cfg->GetAudioFileExt(cfg->GetStreamOutFormat()); num_streams = 0; char frames; long int totalsize = 0; if (fs_finalout != 0) { long int tmp = getSTREAMSIZE(fs_finalout,frames); if (!frames) totalsize += tmp; num_streams++; } if (fs_loopout != 0) { long int tmp = getSTREAMSIZE(fs_loopout,frames); if (!frames) totalsize += tmp; num_streams++; } for (int i = 0; i < iset->GetNumInputs(); i++) if (fs_inputs[i] != 0) { long int tmp = getSTREAMSIZE(fs_inputs[i],frames); if (!frames) totalsize += tmp; num_streams++; } return totalsize / (1024.*1024); }; long int Fweelin::getSTREAMER_TotalOutputSize(int &numstreams) { long int totalsize = 0; numstreams = 0; if (fs_finalout != 0) { totalsize += fs_finalout->GetOutputSize(); numstreams++; } if (fs_loopout != 0) { totalsize += fs_loopout->GetOutputSize(); numstreams++; } for (int i = 0; i < iset->GetNumInputs(); i++) if (fs_inputs[i] != 0) { totalsize += fs_inputs[i]->GetOutputSize(); numstreams++; } return totalsize; }; int Fweelin::setup() { char tmp[255]; // Keep all memory inline mlockall(MCL_CURRENT | MCL_FUTURE); // Init and Register main thread as a writer RT_RWThreads::InitAll(); RT_RWThreads::RegisterReaderOrWriter(); // Initialize vars for (int i = 0; i < NUM_LOOP_SELECTION_SETS; i++) loopsel[i] = 0; #ifndef __MACOSX__ if (!XInitThreads()) { printf("MAIN: ERROR: FreeWheeling requires threaded Xlib support\n"); return 0; } #else FweelinMac::LinkFweelin(this); #endif /* Initialize SDL- this happens here because it is common to video, keys & config */ // SDL_INIT_NOPARACHUTE /* (SDL_INIT_JOYSTICK | SDL_INIT_EVENTTHREAD) < 0) { */ if ( SDL_Init(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK) < 0 ) { printf("MAIN: ERROR: Can't initialize SDL: %s\n",SDL_GetError()); return 0; } atexit(SDL_Quit); // Memory manager mmg = new MemoryManager(); // Load configuration from .rc file cfg = new FloConfig(this); // Create system variables so that config will have them first! UserVariable *tmpv; tmpv = cfg->AddEmptyVariable("BROWSE_loop"); tmpv->type = T_int; *tmpv = (int) B_Loop; tmpv = cfg->AddEmptyVariable("BROWSE_scene"); tmpv->type = T_int; *tmpv = (int) B_Scene; tmpv = cfg->AddEmptyVariable("BROWSE_loop_tray"); tmpv->type = T_int; *tmpv = (int) B_Loop_Tray; tmpv = cfg->AddEmptyVariable("BROWSE_scene_tray"); tmpv->type = T_int; *tmpv = (int) B_Scene_Tray; tmpv = cfg->AddEmptyVariable("BROWSE_patch"); tmpv->type = T_int; *tmpv = (int) B_Patch; cfg->AddEmptyVariable("SYSTEM_num_midi_outs"); cfg->AddEmptyVariable("SYSTEM_midi_transpose"); cfg->AddEmptyVariable("SYSTEM_master_in_volume"); cfg->AddEmptyVariable("SYSTEM_master_out_volume"); cfg->AddEmptyVariable("SYSTEM_cur_pitchbend"); cfg->AddEmptyVariable("SYSTEM_bender_tune"); cfg->AddEmptyVariable("SYSTEM_cur_limiter_gain"); cfg->AddEmptyVariable("SYSTEM_audio_cpu_load"); cfg->AddEmptyVariable("SYSTEM_sync_active"); cfg->AddEmptyVariable("SYSTEM_sync_transmit"); cfg->AddEmptyVariable("SYSTEM_midisync_transmit"); #if USE_FLUIDSYNTH cfg->AddEmptyVariable("SYSTEM_fluidsynth_enabled"); #endif cfg->AddEmptyVariable("SYSTEM_num_help_pages"); cfg->AddEmptyVariable("SYSTEM_num_loops_in_map"); cfg->AddEmptyVariable("SYSTEM_num_recording_loops_in_map"); cfg->AddEmptyVariable("SYSTEM_num_patchbanks"); cfg->AddEmptyVariable("SYSTEM_cur_patchbank_tag"); cfg->AddEmptyVariable("SYSTEM_num_switchable_interfaces"); cfg->AddEmptyVariable("SYSTEM_cur_switchable_interface"); cfg->AddEmptyVariable("SYSTEM_snapshot_page_firstidx"); for (int i = 0; i < LAST_REC_COUNT; i++) { sprintf(tmp,"SYSTEM_loopid_lastrecord_%d",i); cfg->AddEmptyVariable(tmp); } // Now parse and setup config cfg->Parse(); // Event manager emg = new EventManager(); vid = new VideoIO(this); if (vid->activate()) { printf("MAIN: ERROR: Can't start video handler!\n"); return 1; } while (!vid->IsActive()) usleep(100000); abufs = new AudioBuffers(this); iset = new InputSettings(this,abufs->numins); audio = new AudioIO(this); if (audio->open()) { printf("MAIN: ERROR: Can't start system level audio!\n"); return 1; } fragmentsize = audio->getbufsz(); printf("MAIN: Core block size: %d\n",fragmentsize); // Linkup to browsers browsers = new Browser *[(int) B_Last]; memset(browsers,0,sizeof(Browser *) * (int) B_Last); // Setup patch browser, if defined in config { Browser *br = GetBrowserFromConfig(B_Patch); if (br != 0) { browsers[B_Patch] = br; br->Setup(this,this); // We handle callbacks ourselves for patch browser } } // Setup parameter sets to listen for events { FloDisplay *cur = cfg->displays; while (cur != 0) { if (cur->GetFloDisplayType() == FD_ParamSet) ((FloDisplayParamSet *) cur)->ListenEvents(); cur = cur->next; } } // FluidSynth #if USE_FLUIDSYNTH // Create synth printf("MAIN: Creating integrated FluidSynth.\n"); fluidp = new FluidSynthProcessor(this,cfg->GetFluidStereo()); // Setup patch names fluidp->SetupPatches(); #endif // Setup sample buffer for visual scope scope = new sample_t[fragmentsize]; scope_len = fragmentsize; // Block manager bmg = new BlockManager(this); // Preallocated type managers pre_audioblock = new PreallocatedType(mmg, ::new AudioBlock(), sizeof(AudioBlock), FloConfig:: NUM_PREALLOCATED_AUDIO_BLOCKS); if (cfg->IsStereoMaster()) // Only preallocate for stereo blocks if we are running in stereo pre_extrachannel = new PreallocatedType(mmg, ::new BED_ExtraChannel(), sizeof(BED_ExtraChannel), FloConfig:: NUM_PREALLOCATED_AUDIO_BLOCKS); else pre_extrachannel = 0; pre_timemarker = new PreallocatedType(mmg,::new TimeMarker(), sizeof(TimeMarker), FloConfig:: NUM_PREALLOCATED_TIME_MARKERS); rp = new RootProcessor(this,iset); writenum = 1; streamoutname = ""; streamoutname_display = ""; curscene = 0; #if 0 strcpy(scenedispname,""); strcpy(scenefilename,""); #endif // Fixed audio memory nframes_t memlen = (nframes_t) (audio->get_srate() * cfg->AUDIO_MEMORY_LEN), scopelen = cfg->GetScopeSampleLen(), chunksize = memlen/scopelen; // Note here we bypass using Preallocated RTNew because we want // a single block of our own size, not many preallocated blocks // chained together.. audiomem = ::new AudioBlock(memlen); if (audiomem == 0) { printf("CORE: ERROR: Can't create audio memory!\n"); exit(1); } audiomem->Zero(); // If we are running in stereo, create a custom right channel to match // our left channel audio memory if (cfg->IsStereoMaster()) { BED_ExtraChannel *audiomem_r = ::new BED_ExtraChannel(memlen); if (audiomem_r == 0) { printf("CORE: ERROR: Can't create audio memory (right channel)!\n"); exit(1); } audiomem->AddExtendedData(audiomem_r); } // So we have to set a pointer manually to the manager.. // Because some functions depend on using audiomem as a basis // to access RTNew audiomem->SetupPreallocated(pre_audioblock, Preallocated::PREALLOC_BASE_INSTANCE); // Compute running peaks and averages from audio mem (for scope) AudioBlock *peaks = ::new AudioBlock(scopelen), *avgs = ::new AudioBlock(scopelen); if (peaks == 0 || avgs == 0) { printf("CORE: ERROR: Can't create peaks/averages memory!\n"); exit(1); } peaks->Zero(); avgs->Zero(); // **BUG-- small leak-- the above two are never deleted peaks->SetupPreallocated(pre_audioblock, Preallocated::PREALLOC_BASE_INSTANCE); avgs->SetupPreallocated(pre_audioblock, Preallocated::PREALLOC_BASE_INSTANCE); audiomem->AddExtendedData(new BED_PeaksAvgs(peaks,avgs,chunksize)); int nt = cfg->GetNumTriggers(); tmap = new TriggerMap(this,nt); loopmgr = new LoopManager(this); // Setup loop & scene browsers & trays, if defined in config { Browser *br = GetBrowserFromConfig(B_Loop); if (br != 0) { browsers[B_Loop] = br; br->Setup(this,loopmgr); } loopmgr->SetupLoopBrowser(); br = GetBrowserFromConfig(B_Scene); if (br != 0) { browsers[B_Scene] = br; br->Setup(this,loopmgr); } loopmgr->SetupSceneBrowser(); br = GetBrowserFromConfig(B_Loop_Tray); if (br != 0) { browsers[B_Loop_Tray] = br; br->Setup(this,loopmgr); } } // Create snapshots snaps = new Snapshot[cfg->GetMaxSnapshots()]; // Input methods sdlio = new SDLIO(this); midi = new MidiIO(this); if (sdlio->activate()) { printf("(start) cant start keyboard handler\n"); return 1; } if (midi->activate()) { printf("(start) cant start midi\n"); return 1; } // Create Hardware Mixer interface hmix = new HardwareMixerInterface(this); #ifndef __MACOSX__ osc = new OSCClient(this); #endif // Linkup system variables cfg->LinkSystemVariable("SYSTEM_num_midi_outs",T_int, (char *) &(cfg->midiouts)); cfg->LinkSystemVariable("SYSTEM_midi_transpose",T_int, (char *) &(cfg->transpose)); cfg->LinkSystemVariable("SYSTEM_master_in_volume",T_float, (char *) rp->GetInputVolumePtr()); cfg->LinkSystemVariable("SYSTEM_master_out_volume",T_float, (char *) &(rp->outputvol)); cfg->LinkSystemVariable("SYSTEM_cur_pitchbend",T_int, (char *) &(midi->curbender)); cfg->LinkSystemVariable("SYSTEM_bender_tune",T_int, (char *) &(midi->bendertune)); cfg->LinkSystemVariable("SYSTEM_audio_cpu_load",T_float, (char *) &(audio->cpuload)); cfg->LinkSystemVariable("SYSTEM_sync_active",T_char, (char *) &(audio->sync_active)); cfg->LinkSystemVariable("SYSTEM_sync_transmit",T_char, (char *) &(audio->timebase_master)); cfg->LinkSystemVariable("SYSTEM_midisync_transmit",T_char, (char *) &(midi->midisyncxmit)); #if USE_FLUIDSYNTH cfg->LinkSystemVariable("SYSTEM_fluidsynth_enabled",T_char, (char *) &(fluidp->enable)); #endif cfg->LinkSystemVariable("SYSTEM_num_help_pages",T_int, (char *) &(vid->numhelppages)); cfg->LinkSystemVariable("SYSTEM_num_loops_in_map",T_int, (char *) &(loopmgr->numloops)); cfg->LinkSystemVariable("SYSTEM_num_recording_loops_in_map",T_int, (char *) &(loopmgr->numrecordingloops)); cfg->LinkSystemVariable("SYSTEM_num_recording_loops_in_map",T_int, (char *) &(loopmgr->numrecordingloops)); if (browsers[B_Patch] != 0) { cfg->LinkSystemVariable("SYSTEM_num_patchbanks",T_int, (char *) &(((PatchBrowser *) browsers[B_Patch])-> num_pb)); cfg->LinkSystemVariable("SYSTEM_cur_patchbank_tag",T_int, (char *) &(((PatchBrowser *) browsers[B_Patch])-> pb_cur_tag)); } cfg->LinkSystemVariable("SYSTEM_num_switchable_interfaces",T_int, (char *) &(cfg->numinterfaces)); cfg->LinkSystemVariable("SYSTEM_cur_switchable_interface",T_int, (char *) &(vid->cur_iid)); for (int i = 0; i < LAST_REC_COUNT; i++) { sprintf(tmp,"SYSTEM_loopid_lastrecord_%d",i); cfg->LinkSystemVariable(tmp,T_int, (char *) &(loopmgr->lastrecidx[i])); } for (int i = 0; i < iset->numins; i++) { snprintf(tmp,255,"SYSTEM_in_%d_volume",i+1); cfg->LinkSystemVariable(tmp,T_float, (char *) &(iset->invols[i])); snprintf(tmp,255,"SYSTEM_in_%d_peak",i+1); cfg->LinkSystemVariable(tmp,T_float, (char *) &(iset->inpeak[i])); snprintf(tmp,255,"SYSTEM_in_%d_record",i+1); cfg->LinkSystemVariable(tmp,T_char, (char *) &(iset->selins[i])); } { FloDisplaySnapshots *sn = (FloDisplaySnapshots *) cfg->GetDisplayByType(FD_Snapshots); if (sn != 0) cfg->LinkSystemVariable("SYSTEM_snapshot_page_firstidx",T_int, (char *) &(sn->firstidx)); } // Finally, final Config start cfg->Start(); // Now start signal processing if (audio->activate(rp)) { printf("MAIN: Error with signal processing start!\n"); return 1; } // Add disk output threads if (cfg->IsStreamFinal()) fs_finalout = new FileStreamer(this,0,cfg->IsStereoMaster()); else fs_finalout = 0; if (cfg->IsStreamLoops()) fs_loopout = new FileStreamer(this,0,cfg->IsStereoMaster()); else fs_loopout = 0; printf("CORE: Creating disk streamers for %d inputs\n",iset->GetNumInputs()); fs_inputs = new FileStreamer *[iset->GetNumInputs()]; for (int i = 0; i < iset->GetNumInputs(); i++) if (cfg->IsStreamInputs(i)) fs_inputs[i] = new FileStreamer(this,i,cfg->IsStereoInput(i)); else fs_inputs[i] = 0; // *** ALL THREADS THAT WRITE TO SRMWRingBuffers MUST BE CREATED BEFORE THIS POINT *** // Now that all threads are present, initialize ring buffers emg->FinalPrep(); rp->FinalPrep(); // Add core audio processing elements (requires event queue, initialized above) // Add 'individual inputs' disk streams for (int i = 0; i < iset->GetNumInputs(); i++) if (fs_inputs[i] != 0) rp->AddChild(fs_inputs[i],ProcessorItem::TYPE_GLOBAL,1); // Silent- no output from file streamer // Add 'loop output' disk stream // In series following a limiter just for loop outputs if (fs_loopout != 0) { rp->AddChild(new AutoLimitProcessor(this),ProcessorItem::TYPE_GLOBAL_SECOND_CHAIN); rp->AddChild(fs_loopout,ProcessorItem::TYPE_GLOBAL_SECOND_CHAIN,1); // Streamer is silent } // Add monitor mix float *inputvol = rp->GetInputVolumePtr(); // Where to get input vol from rp->AddChild(new PassthroughProcessor(this,iset,inputvol), ProcessorItem::TYPE_GLOBAL); // Monitor mix is global- it is summed in after the gain stage for all loops // Now do master output autolimit masterlimit = new AutoLimitProcessor(this); rp->AddChild(masterlimit,ProcessorItem::TYPE_FINAL); cfg->LinkSystemVariable("SYSTEM_cur_limiter_gain",T_float, (char *) &(masterlimit->curlimitvol)); // Add 'final output' disk stream if (fs_finalout != 0) rp->AddChild(fs_finalout,ProcessorItem::TYPE_FINAL,1); // Begin recording into audio memory (use mono/stereo memory as appropriate) amrec = new RecordProcessor(this,iset,inputvol,audiomem, cfg->IsStereoMaster()); if (amrec == 0) { printf("CORE: ERROR: Can't create core RecordProcessor!\n"); exit(1); } bmg->PeakAvgOn(audiomem,amrec->GetIterator()); rp->AddChild(amrec,ProcessorItem::TYPE_HIPRIORITY); return 0; } void Fweelin::ItemSelected (BrowserItem *item) { // Main app handles selected callback for patch browser if (item->GetType() != B_Patch) printf("CORE: ERROR- Patch Browser contains items of invalid type!\n"); else { PatchBrowser *br = (PatchBrowser *) getBROWSER(B_Patch); if (br != 0) { // Update MIDI with newly selected patch br->SetMIDIForPatch(); PatchBank *pb = br->GetCurPatchBank(); if (pb->port == 0) { // We are selecting in a Fluidsynth bank-- send patch change #if USE_FLUIDSYNTH getFLUIDP()->SendPatchChange((PatchItem *) item); #else printf("CORE: ERROR: Can't change FluidSynth patches- no FluidSynth " "support!\n"); #endif } else { // Check if change messages to be sent? if (!pb->suppresschg) { // Tell MIDI to send out bank/program change(s) for new patch getMIDI()->SendBankProgramChange((PatchItem *) item); } } } } }; freewheeling-0.6.6/src/fweelin_core.h000066400000000000000000001041361370736313100176010ustar00rootroot00000000000000#ifndef __FWEELIN_CORE_H #define __FWEELIN_CORE_H /* ******** Art is what's going on right under our noses. An artist is one who listens to it. ******** */ /* Copyright 2004-2011 Jan Pekau This file is part of Freewheeling. Freewheeling is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. Freewheeling 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 Freewheeling. If not, see . */ #include #include "fweelin_amixer.h" #include "fweelin_midiio.h" #include "fweelin_videoio.h" #include "fweelin_sdlio.h" #include "fweelin_audioio.h" #include "fweelin_rcu.h" #include "fweelin_core_dsp.h" #include "fweelin_block.h" #include "fweelin_event.h" #include "fweelin_config.h" #include "fweelin_browser.h" #include "fweelin_fluidsynth.h" #include "fweelin_osc.h" class SDLIO; class EventManager; class BlockManager; class AutoLimitProcessor; class RootProcessor; class RecordProcessor; class TriggerMap; class AudioBlock; class AudioBlockIterator; class Loop; class Pulse; class BED_MarkerPoints; class FileStreamer; class PreallocatedType; class AudioBuffers; class InputSettings; class Browser; class HardwareMixerInterface; #ifndef __MACOSX__ class OSCClient; #endif #if USE_FLUIDSYNTH class FluidSynthProcessor; #endif // ****************** CORE CLASSES // Status types for loops enum LoopStatus { T_LS_Off = 0, T_LS_Recording = 1, T_LS_Overdubbing = 2, T_LS_Playing = 3 }; // Base class for all saveable types of objects #define SAVEABLE_HASH_LENGTH 16 //MD5_DIGEST_LENGTH #define GET_SAVEABLE_HASH_TEXT(s) \ char hashtext[SAVEABLE_HASH_LENGTH*2+1]; \ { \ char *ptr = hashtext; \ for (int i = 0; i < SAVEABLE_HASH_LENGTH; i++, ptr += 2) \ sprintf(ptr,"%02X",s[i]); \ *ptr = '\0'; \ } enum SaveStatus { NO_SAVE, SAVE_DONE }; class Saveable { public: Saveable() : savestatus(NO_SAVE) {}; virtual void Save(Fweelin */*app*/) {}; // Save the object inline unsigned char *GetSaveHash() { return savehash; }; inline int CompareHash(unsigned char *hash2) { return memcmp(savehash,hash2,sizeof(unsigned char) * SAVEABLE_HASH_LENGTH); }; inline SaveStatus GetSaveStatus() { return savestatus; }; inline void SetSaveStatus(SaveStatus s) { savestatus = s; }; inline void ClearSaveHash() { memset(savehash,0,sizeof(unsigned char) * SAVEABLE_HASH_LENGTH); }; inline int SetSaveableHashFromText(char *stext) { int slen = strlen(stext); if (slen != SAVEABLE_HASH_LENGTH*2) { printf("DISK: Invalid MD5 hash '%s'\n",stext); return 1; } else { char htmp[3]; htmp[2] = '\0'; for (int i = 0, j = 0; i < slen; i += 2, j++) { htmp[0] = stext[i]; htmp[1] = stext[i+1]; int sh_tmp; sscanf(htmp,"%X",&sh_tmp); savehash[j] = (unsigned char) sh_tmp; } SetSaveStatus(SAVE_DONE); return 0; } }; // Splits a saveable filename in the format 'basename-hash-objectname' // into its base name, hash and object name components // // Returns zero on success static char SplitFilename(const char *filename, int baselen, char *basename, char *hash, char *objname, int maxlen); // Rename the file with name *filename_ptr to a new name // use the format 'basename-hash-objectname' // Here, we specify a new objectname 'newname', but the basename and hash // are retained in the filename // Exts is a list of filename extensions to try for renaming // num_exts is the size of the list // // This is for renaming an item on disk static void RenameSaveable(char **filename_ptr, int baselen, char *newname, const char **exts, int num_exts); // Renames -this- saveable object on disk to correspond with the new name // given. Any files having an MD5 corresponding to this saveable are // renamed. // // This is for renaming an item in memory, so that the disk corresponds // with the new name // // *Old_filename and *new_filename are set to point to the old and new // filename-- you must delete[] the memory that is allocated for these void RenameSaveable(char *librarypath, char *basename, char *old_objname, char *nw_objname, const char **exts, int num_exts, char **old_filename, char **new_filename); // Gets the first two characters of the hash in the given filename, // given the base length-- store in *c1 and *c2-- only if the // filename contains a valid hash inline static void GetHashFirst(char *filename, int baselen, char *c1, char *c2) { char *c = filename + baselen + 1; if (c < filename+strlen(filename)) { *c1 = *c++; *c2 = *c; #if 0 char *slashptr = strchr(c,'-'); if (slashptr == 0) // If name is not in filename slashptr = strrchr(filename,'.'); // Use extension to get hash printf("c1 - %d vs %d\n",slashptr-c,SAVEABLE_HASH_LENGTH*2); if (slashptr != 0 && slashptr-c == SAVEABLE_HASH_LENGTH*2) { printf("set\n"); *c1 = *c++; *c2 = *c; } #endif } } protected: // When we save an object, we first compute the MD5 hash for that object // and put that in the filename for the object. Other objects can refer to // the object by hash. SaveStatus savestatus; unsigned char savehash[SAVEABLE_HASH_LENGTH+1]; }; // An audio loop // -Wraps around a list of audio blocks // -Stores basic parameters for a loop, such as volumes class Loop : public Preallocated, public Saveable { friend class LoopManager; public: const static float MIN_VOL; Loop () : name(0) { Recycle(); } // Initialize a loop data structure void InitLoop (AudioBlock *blocks, Pulse *pulse, float quant, float vol, long nbeats, codec format) { this->format = format; this->blocks = blocks; this->pulse = pulse; this->quant = quant; this->vol = vol; this->dvol = 1.0; this->nbeats = nbeats; this->selcnt = 0; } // Save loop virtual void Save(Fweelin *app); // RT update volume inline void UpdateVolume() { if (dvol != 1.0) { // Apply delta if (dvol > 1.0 && vol < MIN_VOL) vol = MIN_VOL; vol *= dvol; } }; inline void ChangeSelectedCount (int delta) { selcnt += delta; if (selcnt < 0) selcnt = 0; }; // ** LOOP PREALLOCATION ** // Loops are preallocated in blocks for quick creation and destruction FWMEM_DEFINE_DELBLOCK; virtual Preallocated *NewInstance() { return ::new Loop[GetMgr()->GetBlockSize()]; }; // Re-use an old instance in a block virtual void Recycle() { SetSaveStatus(NO_SAVE); ClearSaveHash(); if (name != 0) { delete[] name; name = 0; } blocks = 0; pulse = 0; }; #define NUM_LOOP_PREALLOCATED 100 // How many loops to preallocate in a block (more blocks will be created as needed) static void SetupLoopPreallocation(MemoryManager *mmgr) { loop_pretype = new PreallocatedType(mmgr,::new Loop[NUM_LOOP_PREALLOCATED],sizeof(Loop),NUM_LOOP_PREALLOCATED,1); }; static void TakedownLoopPreallocation() { delete loop_pretype; }; // Get a new loop. Uses the RTNewWithWait method, so it shouldn't be called from RT. static Loop *GetNewLoop() { return (Loop *) loop_pretype->RTNewWithWait(); }; static PreallocatedType *loop_pretype; // Preallocated type for loops // ** // Perhaps store the length of the loop... // Because right now GetTotalLength is a calculation // in AudioBlock char *name; // Name of loop, or null codec format; // File format on disk AudioBlock *blocks; // Chain of blocks that form this loop Pulse *pulse; // Time pulse to which this loop is quantized float quant; // Quantization factor float vol, // Volume multiplier dvol; // Rate of volume change long nbeats; // Number of beats in this loop int selcnt; // Number of times this loop is currently selected // (see toggle-select-loop). A loop can be selected // in several sets }; // Snapshot of information for a loop class LoopSnapshot { public: LoopSnapshot (int l_idx = -1, LoopStatus status = T_LS_Off, float l_vol = 0.0, float t_vol = 0.0) : l_idx(l_idx), status(status), l_vol(l_vol), t_vol(t_vol) {}; int l_idx; // Loop index LoopStatus status; // Is it playing? float l_vol, // Loop volume (persistent) t_vol; // Trigger volume (not persistent) }; // A snapshot remembers all settings related to which loops are playing & // at what levels class Snapshot { public: Snapshot() : name(0), exists(0), ls(0) {}; ~Snapshot () { DeleteSnapshot(); }; void DeleteSnapshot (char erasename = 1) { if (erasename && name != 0) { delete[] name; name = 0; } if (ls != 0) { delete[] ls; ls = 0; } exists = 0; }; // Create a snapshot from loops right now void CreateSnapshot (char *name, LoopManager *lm, TriggerMap *tmap); char *name; // Name of snapshot char exists; // This snapshot exists (nonzero), or empty slot (zero)? // Array of info for each loop within the snapshot LoopSnapshot *ls; int numls; }; // A set of loops class LoopList { public: LoopList (int l_idx = -1) : l_idx(l_idx), next(0) {}; // Scans through the list beginning with 'first' for the loop 'l_idx'- // returns the LoopList containing 'item', and sets 'prev' to the previous // LoopList. If not found, returns 0. static LoopList *Scan (LoopList *first, int l_idx, LoopList **prev) { LoopList *cur = first, *tprev = 0; while (cur != 0 && cur->l_idx != l_idx) { tprev = cur; cur = cur->next; } *prev = tprev; return cur; }; // Add to the beginning of a list of loops- return the new first pointer static LoopList *AddBegin (LoopList *first, int l_idx) { if (first == 0) return new LoopList(l_idx); else { LoopList *nwl = new LoopList(l_idx); nwl->next = first; return nwl; } }; // Remove the given looplist 'll' from the list of loops- // you must also pass the element previous to ll // We return the new first pointer static LoopList *Remove (LoopList *first, LoopList *ll, LoopList *prev) { if (ll != 0) { if (ll == first) { LoopList *nwfirst = ll->next; delete ll; return nwfirst; } else { if (prev != 0) prev->next = ll->next; delete ll; return first; } } return first; }; // Remove the given loop from the list of loops- return the new first pointer static LoopList *Remove (LoopList *first, int l_idx) { LoopList *prev, *ll = Scan(first,l_idx,&prev); return Remove(first,ll,prev); }; // Erase a list of loops, given the first static void Delete (LoopList *first) { LoopList *cur = first; while (cur != 0) { LoopList *tmp = cur->next; delete cur; cur = tmp; } }; int l_idx; LoopList *next; }; // This class manages sets of loops, allowing them to be triggered.. // like a keymap class TriggerMap : public Saveable, public EventProducer { public: TriggerMap (Fweelin *app, int mapsize) : app(app), mapsize(mapsize), lastupdate(0) { // Map is an array of pointers to different loops map = new Loop *[mapsize]; memset(map,0,mapsize * sizeof(Loop *)); }; virtual ~TriggerMap () { delete[] map; } // Save a whole scene, with an optional filename- // if none is given, saves a new scene virtual void Save(Fweelin *app, char *filename = 0); // Go save- when all loops are saved, this part saves the XML data // for the scene void GoSave(char *filename); inline void SetMap (int index, Loop *smp); inline Loop *GetMap (int index) { if (index < 0 || index >= mapsize) { printf("GetMap: Invalid loop index!\n"); return 0; } else return map[index]; } inline int SearchMap (Loop *l) { for (int i = 0; i < mapsize; i++) if (map[i] == l) return i; return -1; }; // Return the first free loopid within the range of indexes 'lo -> hi' // or -1 if no free IDs found inline int GetFirstFree (int lo, int hi) { int i_start = lo, i_end = hi; if (i_start < 0) i_start = 0; if (i_start >= mapsize) i_start = mapsize-1; if (i_end < 0) i_end = 0; if (i_end >= mapsize) i_start = mapsize-1; for (int i = i_start; i <= i_end; i++) if (map[i] == 0) return i; return -1; }; // Returns the loop ID for the first loop whose 'savehash' matches the given // hash, or -1 if none found inline int ScanForHash (unsigned char *hash) { for (int i = 0; i < mapsize; i++) if (map[i] != 0 && map[i]->GetSaveStatus() == SAVE_DONE && !map[i]->CompareHash(hash)) return i; return -1; }; inline int GetMapSize() { return mapsize; } inline double GetLastUpdate() { return lastupdate; } inline void TouchMap() { lastupdate = mygettime(); SetSaveStatus(NO_SAVE); }; // Return the number of loops in the map inline int CountLoops() { int cnt = 0; for (int i = 0; i < mapsize; i++) if (map[i] != 0) cnt++; return cnt; }; private: Fweelin *app; int mapsize; Loop **map; // Time of last update of the map- used for rebuilding tables & such double lastupdate; }; // LoopTrayItem is for loaded loops class LoopTrayItem : public BrowserItem { public: LoopTrayItem(Loop *l, int loopid, char *name, char default_name, char *placename) : BrowserItem(name,default_name), l(l), loopid(loopid), xpos(-1), ypos(-1), placename(placename) {}; virtual int Compare(BrowserItem *second) { if (second->GetType() == B_Loop_Tray) return ((LoopTrayItem *) second)->loopid-loopid; else return 0; }; virtual int MatchItem(int itemmatch) { if (loopid == itemmatch) return 0; else return 1; }; virtual BrowserItemType GetType() { return B_Loop_Tray; }; Loop *l; // Loop that this item refers to int loopid, // Loop ID for it xpos, // Position in tray window ypos; char *placename; // Place name for where the loop is mapped }; // LoopBrowserItem is for loops in the library on disk class LoopBrowserItem : public BrowserItem { public: LoopBrowserItem(time_t time, char *name, char default_name, char *fn) : BrowserItem(name,default_name), time(time) { if (fn == 0) filename = 0; else { // Copy filename filename = new char[strlen(fn)+1]; strcpy(filename,fn); // Remove extension char *ext_ptr = strrchr(filename,'.'); if (ext_ptr != 0) *ext_ptr = '\0'; } }; virtual ~LoopBrowserItem() { if (filename != 0) delete[] filename; }; virtual int Compare(BrowserItem *second) { if (second->GetType() == B_Loop) return ((LoopBrowserItem *) second)->time-(signed int) time; else return 0; }; virtual BrowserItemType GetType() { return B_Loop; }; time_t time; char *filename; }; class SceneBrowserItem : public BrowserItem { public: SceneBrowserItem(time_t time, char *name, char default_name, char *fn) : BrowserItem(name, default_name), time(time) { if (fn == 0) filename = 0; else { // Copy filename filename = new char[strlen(fn)+1]; strcpy(filename,fn); // Remove extension char *ext_ptr = strrchr(filename,'.'); if (ext_ptr != 0) *ext_ptr = '\0'; } }; virtual ~SceneBrowserItem() { if (filename != 0) delete[] filename; }; virtual int Compare(BrowserItem *second) { if (second->GetType() == B_Scene) return ((SceneBrowserItem *) second)->time - (signed int) time; else return 0; }; virtual BrowserItemType GetType() { return B_Scene; }; time_t time; char *filename; }; // LoopManager contains all loops, and wraps up recording, playing, and // other RT & non-RT processing on loops class LoopManager : public EventListener, public AutoWriteControl, public AutoReadControl, public BrowserCallback, public RenameCallback { friend class Loop; public: // Version tracking for saving of loop data const static int LOOP_SAVE_FORMAT_VERSION = 1; LoopManager (Fweelin *app); virtual ~LoopManager(); virtual void ReceiveEvent(Event *ev, EventProducer *from); virtual void ItemBrowsed(BrowserItem *i); virtual void ItemSelected(BrowserItem *i); virtual void ItemRenamed(BrowserItem *i); // Populate the loop/scene browser with any loops/scenes on disk void SetupLoopBrowser(); void SetupSceneBrowser(); // Get long count (number of beats for whole pattern) for all playing loops // Assumes only one pulse for all playing loops. // // Returns the first pulse detected in the playing loops (in p) and the long count (return) int GetLongCountForAllPlayingLoops(Pulse *&p); // Get length returns the length of any loop on the specified index // (including the tail for cross-fading) nframes_t GetLength(int index); // Get length returns the length of any loop on the specified index // Rounded to its currently quantized length (ie the actual repeated part) // Or 0 if the loop has no pulse nframes_t GetRoundedLength(int index); // Returns from 0.0-1.0 how far through a block chain with specified index // we are float GetPos(int index); // Get current # of samples into block chain with given index nframes_t GetCurCnt(int index); // Returns nonzero if there is a processor at the specified mapindex int IsActive(int index) { return (plist[index] != 0); } // Sets trigger volume on specified index // If index is not playing, activates the index void SetTriggerVol(int index, float vol); // Gets triggered volume on specified index // If index is not playing, returns 0 float GetTriggerVol(int index); // Returns the status at the specified index inline LoopStatus GetStatus(int index) { return status[index]; }; inline Processor *GetProcessor(int index) { return plist[index]; }; // Returns a loop with the specified index, if one exists Loop *GetSlot(int index); void AdjustNewLoopVolume(float adjust) { newloopvol += adjust; if (newloopvol < 0.0) newloopvol = 0.0; } float GetNewLoopVolume() { return newloopvol; } void AdjustOutputVolume(float adjust); void SetOutputVolume(float set, float logset); float GetOutputVolume(); void AdjustInputVolume(float adjust); void SetInputVolume(float set, float logset); float GetInputVolume(); void SetLoopVolume(int index, float val); float GetLoopVolume(int index); void AdjustLoopVolume(int index, float adjust); void SetLoopdVolume(int index, float val); float GetLoopdVolume(int index); void SelectPulse(int pulseindex); // Create a time pulse around the specified index // The length of the loop on the specified index becomes // a time constant around which other loops center themselves // subdivide the length of the loop by subdivide to get the core pulse void CreatePulse(int index, int pulseindex, int sub); // Creates a pulse of the given length in the first available slot, // if none already exists of the right length Pulse *CreatePulse(nframes_t len); // Taps a pulse- starting at the downbeat- if newlen is nonzero, the pulse's // length is adjusted to reflect the length between taps- and a new pulse // is created if none exists void TapPulse(int pulseindex, char newlen); void SwitchMetronome(int pulseindex, char active); inline Pulse *GetCurPulse() { if (curpulseindex >= 0) return pulses[curpulseindex]; else return 0; }; inline int GetCurPulseIndex() { return curpulseindex; }; inline Pulse *GetPulseByIndex(int pulseindex) { return pulses[pulseindex]; }; // Deletes the specified pulse, stopping striping void DeletePulse(int pulseindex); // Gets the pulse to which the loop on index is attached Pulse *GetPulse(int index); inline void SetSubdivide(int sub) { //printf("Set subdivide: %d\n", sub); subdivide = sub; } inline int GetSubdivide() { return subdivide; }; // Move the loop at specified index to another index // only works if target index is empty // returns 1 if success int MoveLoop (int src, int tgt); // Prompts the user for a new name for the given loop // We can only rename one loop at a time void RenameLoop(int loopid); virtual void ItemRenamed(char *nw); ItemRenamer *renamer; // Renamer instance, or null if we are not renaming Loop *rename_loop; // Loop being renamed inline ItemRenamer *GetRenamer() { return renamer; }; inline Loop *GetRenameLoop() { return rename_loop; }; // Delete the loop at the specified index.. void DeleteLoop (int index); // Add the given loop index to all snapshots (off) void UpdateLoopLists_ItemAdded (int l_idx); // Remove the given loop index from all loop lists void UpdateLoopLists_ItemRemoved (int l_idx); // Update all loop lists to reflect that a loop has moved in the TriggerMap void UpdateLoopLists_ItemMoved (int l_idx_old, int l_idx_new); // Trigger the loop at index within the map // The exact behavior varies depending on what is already happening with // this loop and the settings passed- see ~/.fweelin/.fweelin.rc void Activate (int index, char shot = 0, float vol = 1.0, nframes_t ofs = 0, char overdub = 0, float *od_feedback = 0); void Deactivate (int index); // Saves the loop with given index void SaveLoop (int index); // Load loop from disk into the given index void LoadLoop(char *filename, int index, float vol = 1.0); // Saves a new scene of all loops void SaveNewScene(); // Saves over the current scene void SaveCurScene(); // Load scene from disk void LoadScene(SceneBrowserItem *i); // We receive calls periodically for saving of loops- // here, we return blocks to save from loops which need saving virtual void GetWriteBlock(FILE **out, AudioBlock **b, AudioBlockIterator **i, nframes_t *len); // We receive calls periodically for loading of loops- virtual void GetReadBlock(FILE **in, char *smooth_end); virtual void ReadComplete(AudioBlock *b); // Check if the needs_saving map is up to date, rebuild if needed. void CheckSaveMap(); // Adds the loop/scene with given filename to the browser br void AddLoopToBrowser(Browser *br, char *filename); SceneBrowserItem *AddSceneToBrowser(Browser *br, char *filename); inline void SetAutoLoopSaving(char save) { autosave = save; }; void AddToSaveQueue(Event *ev); inline int GetNumSave() { return numsave; }; inline int GetCurSave() { return cursave; }; inline int GetNumLoad() { return numload; }; inline int GetCurLoad() { return curload; }; Event *savequeue, // Loop/scene save queue *loadqueue; // Loop/scene load queue int cursave, curload, // # of loops/scenes saved/loaded numsave, numload; // Total # of loops/scenes to save/load int loadloopid; // Index where to load new loops from disk double needs_saving_stamp; // Timestamp from trigger map from which // needs_saving was built Range default_looprange; // Default placement for loops int *lastrecidx; // List of last indexes recorded to int numloops, // Total number of loops in map numrecordingloops; // Number of loops currently recording in map inline void LockLoops() { pthread_mutex_lock (&loops_lock); }; inline void UnlockLoops() { pthread_mutex_unlock (&loops_lock); }; protected: // Rename a loop in memory (threadsafe) inline void RenameLoop(Loop *l, char *nw) { LockLoops(); if (l->name != 0) // Erase loop stored name delete[] l->name; if (nw != 0) { l->name = new char[strlen(nw)+1]; strcpy(l->name,nw); } else l->name = 0; UnlockLoops(); }; // Adds the given loop to the list of loops to save void AddLoopToSaveQueue(Loop *l); // Adds the given loop to the list of loops to load void AddLoopToLoadQueue(char *filename, int index, float vol); // Saves loop XML data & prepares to save loop audio void SetupSaveLoop(Loop *l, int /*l_idx*/, FILE **out, AudioBlock **b, AudioBlockIterator **i, nframes_t *len); // Loads loop XML data & prepares to load loop audio- // returns nonzero on error int SetupLoadLoop(FILE **in, char *smooth_end, Loop **new_loop, int /*l_idx*/, float l_vol, char *l_filename); // Setup time marker striping on audio memory when a new // pulse is selected void StripePulseOn(Pulse *pulse); // Deactivate time marker striping on audio memory for the // given pulse void StripePulseOff(Pulse *pulse); // Turn on/off auto loop saving char autosave; // Autosave loops? // Core Fweelin app on which this player is working on Fweelin *app; // We also need to keep track of record/playprocessors attached to each // index Processor **plist; // Pointer to a processor for each index // *** Replace this with well designed event queue system int *waitactivate; // For each index, are we waiting to activate? float *waitactivate_vol; char *waitactivate_od, *waitactivate_shot; float **waitactivate_od_fb; LoopStatus *status; // For each index, what's the status? // Block managers that load/save loops BlockReadManager *bread; BlockWriteManager *bwrite; // Initial volume of new loops float newloopvol; // Subdivision for creating new pulses int subdivide; // Index of last deactivated trigger index.. used when creating new pulses int lastindex; // Current pulse (index) for new loops.. will be quantized to this pulse int curpulseindex; // List of possible pulses Pulse *pulses[MAX_PULSES]; pthread_mutex_t loops_lock; // A way to lock up loops so two threads // don't race on one loop }; // This is Fweelin class Fweelin : public EventProducer, public BrowserCallback { public: Fweelin() : #if USE_FLUIDSYNTH fluidp(0), #endif mmg(0), bmg(0), emg(0), rp(0), tmap(0), loopmgr(0), browsers(0), abufs(0), iset(0), audio(0), midi(0), sdlio(0), vid(0), scope(0), scope_len(0), audiomem(0), amrec(0), sync_type(0), sync_speed(1), running(0) {}; ~Fweelin() {}; char IsRunning() { return running; }; // Setup int setup(); // Start int go(); void ToggleDiskOutput(); void FlushStreamOutName() { streamoutname = ""; }; inline nframes_t getBUFSZ() { return fragmentsize; }; inline sample_t *getSCOPE() { return scope; }; inline nframes_t getSCOPELEN() { return scope_len; }; #if USE_FLUIDSYNTH inline FluidSynthProcessor *getFLUIDP() { return fluidp; }; FluidSynthProcessor *fluidp; #endif inline AudioBlock *getAUDIOMEM() { return audiomem; }; AudioBlockIterator *getAUDIOMEMI(); inline RecordProcessor *getAMREC() { return amrec; }; AudioBlock *getAMPEAKS(); AudioBlock *getAMAVGS(); AudioBlockIterator *getAMPEAKSI(); AudioBlockIterator *getAMAVGSI(); BED_MarkerPoints *getAMPEAKSPULSE(); inline MemoryManager *getMMG() { return mmg; }; inline BlockManager *getBMG() { return bmg; }; inline EventManager *getEMG() { return emg; }; inline RootProcessor *getRP() { return rp; }; inline FileStreamer *getSTREAMER_INPUT(int n) { return fs_inputs[n]; }; inline FileStreamer *getSTREAMER_LOOPMIX() { return fs_loopout; }; inline FileStreamer *getSTREAMER_FINALMIX() { return fs_finalout; }; char CheckStreamStatus(char status); // Returns the total number of bytes written from all disk streamer instances. // Also returns the number of streams being written. long int getSTREAMER_TotalOutputSize(int &numstreams); inline TriggerMap *getTMAP() { return tmap; }; inline LoopManager *getLOOPMGR() { return loopmgr; }; inline AudioIO *getAUDIO() { return audio; }; inline MidiIO *getMIDI() { return midi; }; inline VideoIO *getVIDEO() { return vid; }; inline SDLIO *getSDLIO() { return sdlio; }; inline HardwareMixerInterface *getHMIX() { return hmix; }; inline FloConfig *getCFG() { return cfg; }; inline const std::string &getSTREAMOUTNAME() { return streamoutname; }; inline const std::string &getSTREAMOUTNAME_DISPLAY() { return streamoutname_display; }; // FIXME move to filestream manager // Returns the stream size in frames or bytes written. // Returns nonzero in frames if frames are being returned. // Returns zero in frames if bytes are being returned. inline long int getSTREAMSIZE(FileStreamer *fs, char &frames); // Returns stats about output streams- // The type (file extension .ogg, etc), The number of output streams open, the total number of megabytes written (Return value). float getSTREAMSTATS(char *&stream_type, int &num_streams); inline SceneBrowserItem *getCURSCENE() { return curscene; }; inline void setCURSCENE(SceneBrowserItem *nw) { curscene = nw; }; inline PreallocatedType *getPRE_EXTRACHANNEL() { return pre_extrachannel; }; inline PreallocatedType *getPRE_AUDIOBLOCK() { return pre_audioblock; }; inline PreallocatedType *getPRE_TIMEMARKER() { return pre_timemarker; }; inline AudioBuffers *getABUFS() { return abufs; }; inline InputSettings *getISET() { return iset; }; inline AutoLimitProcessor *getMASTERLIMITER() { return masterlimit; }; inline Browser *getBROWSER(BrowserItemType b) { if (b >= 0 && b < B_Last) return browsers[b]; else return 0; } // Selections inline LoopList **getLOOPSEL(int idx) { if (idx >= 0 && idx < NUM_LOOP_SELECTION_SETS) return &loopsel[idx]; else return 0; }; // Snapshots Snapshot *getSNAP(int idx); inline Snapshot *getSNAPS() { return snaps; }; // Trigger snapshot #idx - return nonzero on failure char TriggerSnapshot (int idx); // Create snapshot from current state of all loops void CreateSnapshot (char *_name, LoopManager *lm, TriggerMap *tmap); Snapshot *CreateSnapshot (int idx) { Snapshot *s = getSNAP(idx); if (s != 0) { tmap->TouchMap(); s->CreateSnapshot(0,loopmgr,tmap); } return s; }; // Swaps snapshots with given indices int SwapSnapshots (int i1, int i2) { Snapshot *s1 = getSNAP(i1), *s2 = getSNAP(i2); if (s1 != 0 && s2 != 0 && s1 != s2) { char tmp[sizeof(Snapshot)]; tmap->TouchMap(); memcpy(tmp,s1,sizeof(Snapshot)); memcpy((unsigned char*)s1,s2,sizeof(Snapshot)); memcpy((unsigned char*)s2,tmp,sizeof(Snapshot)); return 0; } else return -1; }; // Load snapshot from disk - just create space & name Snapshot *LoadSnapshot (int idx, char *name) { Snapshot *s = getSNAP(idx); if (s != 0) { tmap->TouchMap(); s->CreateSnapshot(name,0,0); s->numls = 0; } return s; }; // Sync parameters inline int GetSyncSpeed() { return sync_speed; }; inline char GetSyncType() { return sync_type; }; inline void SetSyncSpeed(int sspd) { if (sspd < 1) sync_speed = 1; else sync_speed = sspd; RefreshPulseSync(); }; inline void SetSyncType(char stype) { sync_type = stype; RefreshPulseSync(); }; // Resets MIDI sync / beat/bar metronome generation to restart on the next pulse wraparound inline void RefreshPulseSync() { int curpulse = getLOOPMGR()->GetCurPulseIndex(); getLOOPMGR()->SelectPulse(-1); getLOOPMGR()->SelectPulse(curpulse); }; // Patch browser callbacks virtual void ItemBrowsed(BrowserItem */*item*/) { // Auto-select (disabled) // ItemSelected(i); }; virtual void ItemSelected(BrowserItem *item); // Patches can not yet be renamed virtual void ItemRenamed(BrowserItem */*item*/) { return; }; private: OSCClient *osc; MemoryManager *mmg; BlockManager *bmg; EventManager *emg; RootProcessor *rp; TriggerMap *tmap; LoopManager *loopmgr; Browser **browsers; Browser *GetBrowserFromConfig(BrowserItemType b); // ****************** PREALLOCATED TYPE MANAGERS PreallocatedType *pre_audioblock, *pre_extrachannel, *pre_timemarker; // ****************** DISK STREAMERS FileStreamer *fs_finalout, // Final output disk stream *fs_loopout, // Loop output disk stream **fs_inputs; // Array of pointers to disk streams for audio inputs int writenum; // Number of audio output file currently being written std::string streamoutname, // Full path and base name of output stream (for example, fw-lib/live52) streamoutname_display; // Base name of output stream, excluding path (for example, live52) // ****************** MASTER LIMITER AutoLimitProcessor *masterlimit; // ****************** LOOP SELECTIONS LoopList *loopsel[NUM_LOOP_SELECTION_SETS]; // ****************** ARRAY OF SNAPSHOTS Snapshot *snaps; // ****************** SCENE INFO SceneBrowserItem *curscene; // ****************** SYSTEM LEVEL AUDIO // Audio buffers AudioBuffers *abufs; // Input settings InputSettings *iset; // Audio interface AudioIO *audio; // ****************** MIDI MidiIO *midi; // ****************** SDL INPUT (KEYBOARD / MOUSE / JOYSTICK) SDLIO *sdlio; // ****************** VIDEO VideoIO *vid; // Audio buffer size nframes_t fragmentsize; // Buffers for visual sample scope sample_t *scope; nframes_t scope_len; // Audio memory & the processor which records to it AudioBlock *audiomem; RecordProcessor *amrec; // Control settings FloConfig *cfg; // Hardware Mixer settings HardwareMixerInterface *hmix; // Variables for sync char sync_type; // Nonzero for beat-sync and zero for bar-sync int sync_speed; // Number of beats or bars (external) per pulse (FW) char running; // Nonzero if FW is fully started }; #endif freewheeling-0.6.6/src/fweelin_core_dsp.cc000066400000000000000000002363251370736313100206130ustar00rootroot00000000000000/* Music holds us together "it becomes a movement" */ /* Copyright 2004-2011 Jan Pekau This file is part of Freewheeling. Freewheeling is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. Freewheeling 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 Freewheeling. If not, see . */ #include #include #include #include #include #include #include #include #include #include #include "fweelin_config.h" #include "fweelin_core_dsp.h" const float Processor::MIN_VOL = 0.01; const nframes_t Processor:: DEFAULT_SMOOTH_LENGTH = 64; // Length of metronome strike sound in samples const nframes_t Pulse::METRONOME_HIT_LEN = 800; // Length of metronome tone sound in samples const nframes_t Pulse::METRONOME_TONE_LEN = 4400; // Initial metronome volume const float Pulse::METRONOME_INIT_VOL = 0.1; // AutoLimitProcessor const float AutoLimitProcessor::LIMITER_ATTACK_LENGTH = 1024, AutoLimitProcessor::LIMITER_START_AMP = 1.0; const nframes_t AutoLimitProcessor::LIMITER_ADJUST_PERIOD = 64; // const float RecordProcessor::OVERDUB_DEFAULT_FEEDBACK = 0.5; const static float MAX_VOL = 5.0; const static float MAX_DVOL = 1.5; // DB FADER CODE #define DB_FLOOR -1000.f #define FADER_MIN_DB -70.f int math_gcd (int a, int b) { return (b == 0 ? a : math_gcd(b, a % b)); }; int math_lcm (int a, int b) { return a*b/math_gcd(a,b); }; // IEC 60-268-18 fader levels. Thanks to Steve Harris. // Thanks to Chris Cannam & Sonic Visualiser code float iec_dB_to_fader (float db) { float def = 0.0f; // Meter deflection %age if (db < -70.0f) { def = 0.0f; } else if (db < -60.0f) { def = (db + 70.0f) * 0.25f; } else if (db < -50.0f) { def = (db + 60.0f) * 0.5f + 2.5f; // used to be +5.0f, but this caused a discontinuity in low dB deflections } else if (db < -40.0f) { def = (db + 50.0f) * 0.75f + 7.5f; } else if (db < -30.0f) { def = (db + 40.0f) * 1.5f + 15.0f; } else if (db < -20.0f) { def = (db + 30.0f) * 2.0f + 30.0f; } else { def = (db + 20.0f) * 2.5f + 50.0f; } return def; } static float iec_fader_to_dB(float def) // Meter deflection %age { float db = 0.0f; if (def >= 50.0f) { db = (def - 50.0f) / 2.5f - 20.0f; } else if (def >= 30.0f) { db = (def - 30.0f) / 2.0f - 30.0f; } else if (def >= 15.0f) { db = (def - 15.0f) / 1.5f - 40.0f; } else if (def >= 7.5f) { db = (def - 7.5f) / 0.75f - 50.0f; } else if (def >= 2.5f) { // used to be 0.5, ... db = (def - 2.5f) / 0.5f - 60.0f; // used to be (def - 5.0f), but this caused a discontinuity in low dB deflections } else { db = (def / 0.25f) - 70.0f; } return db; } float AudioLevel::fader_to_dB (float level, float maxDb) { if (level == 0.) return DB_FLOOR; float maxPercent = iec_dB_to_fader(maxDb); float percent = level * maxPercent; float dB = iec_fader_to_dB(percent); return dB; } float AudioLevel::dB_to_fader (float dB, float maxDb) { if (dB == DB_FLOOR) return 0.; // The IEC scale gives a "percentage travel" for a given dB // level, but it reaches 100% at 0dB. So we want to treat the // result not as a percentage, but as a scale between 0 and // whatever the "percentage" for our (possibly >0dB) max dB is. float maxPercent = iec_dB_to_fader(maxDb); float percent = iec_dB_to_fader(dB); float faderLevel = percent / maxPercent; if (faderLevel < 0.) faderLevel = 0.; if (faderLevel > 1.0) faderLevel = 1.0; return faderLevel; } // // *********** CORE SIGNAL PROCESSING AudioBuffers::AudioBuffers(Fweelin *app) : app(app) { numins_ext = app->getCFG()->GetExtAudioIns(); numins = numins_ext + GetIntAudioIns(); numouts = GetAudioOuts(); ins[0] = new sample_t *[numins]; ins[1] = new sample_t *[numins]; outs[0] = new sample_t *[numouts]; outs[1] = new sample_t *[numouts]; memset(ins[0],0,sizeof(sample_t *) * numins); memset(ins[1],0,sizeof(sample_t *) * numins); memset(outs[0],0,sizeof(sample_t *) * numouts); memset(outs[1],0,sizeof(sample_t *) * numouts); }; AudioBuffers::~AudioBuffers() { delete[] ins[0]; delete[] ins[1]; delete[] outs[0]; delete[] outs[1]; }; char AudioBuffers::IsStereoInput(int n) { return app->getCFG()->IsStereoInput(n); }; char AudioBuffers::IsStereoOutput(int n) { return app->getCFG()->IsStereoOutput(n); }; char AudioBuffers::IsStereoMaster() { return app->getCFG()->IsStereoMaster(); }; // Mixes the selected inputs (nonzero) to dest // Dest is an array of 2 pointers to left & right buffers // If dest[1] is null, mix is done in mono // Also, we do compensation for DC offset of inputs // // *** Glitch/inefficiency: MixInputs is called for each RecordProcessor // And for PassthroughProcessor- DC offsets are recomputed, etc void AudioBuffers::MixInputs (nframes_t len, sample_t **dest, InputSettings *iset, float inputvol, char compute_stats) { const static int DCOFS_MINIMUM_SAMPLE_COUNT = 10000; const static float DCOFS_LOWPASS_COEFF = 0.99, DCOFS_ONEMINUS_LOWPASS_COEFF = 1.0-DCOFS_LOWPASS_COEFF; const static nframes_t PEAK_HOLD_LENGTH = 1; // Mix together selected inputs.. int stereomix = (dest[1] != 0 ? 1 : 0); memset(dest[0],0,sizeof(sample_t) * len); if (stereomix) memset(dest[1],0,sizeof(sample_t) * len); nframes_t phold = 0; if (compute_stats) phold = app->getAUDIO()->get_srate() * PEAK_HOLD_LENGTH; for (int i = 0; i < numins; i++) { if (iset->selins[i]) { // If input is selected! for (int j = 0; j <= stereomix; j++) { // Left & right channels sample_t *in = ins[j][i]; float vol = iset->invols[i] * inputvol; // DC offset compute sample_t sum = 0, peak = 0, dcofs = iset->insavg[j][i]; nframes_t peaktime = 0; int cnt = 0; if (compute_stats) { cnt = iset->inscnt[i]; sum = iset->insums[j][i]; peaktime = iset->inpeaktime[i]; if (cnt-peaktime > phold) // Old peak- fall to zero peak = 0; else // Retain peak peak = iset->inpeak[i]; } if (j == 0) { // Left if (compute_stats) { // Stats for (nframes_t idx = 0; idx < len; idx++) { sample_t s = in[idx], sabs = fabs(s); sum += s; if (sabs > peak) { peak = sabs; peaktime = cnt; } cnt++; dest[0][idx] += (s-dcofs) * vol; } iset->inscnt[i] = cnt; } else { // No stats for (nframes_t idx = 0; idx < len; idx++) dest[0][idx] += (in[idx]-dcofs) * vol; } } else { // If input is mono, take signal from left channel and // use it for the right output if (in == 0) in = ins[0][i]; if (compute_stats) { // Stats for (nframes_t idx = 0; idx < len; idx++) { sample_t s = in[idx], sabs = fabs(s); sum += s; if (sabs > peak) { peak = sabs; peaktime = cnt; } dest[j][idx] += (s-dcofs) * vol; } } else { // No stats for (nframes_t idx = 0; idx < len; idx++) dest[j][idx] += (in[idx]-dcofs) * vol; } } // DC offset adjust if (compute_stats) { iset->insums[j][i] = sum; iset->inpeak[i] = peak; iset->inpeaktime[i] = peaktime; if (cnt > DCOFS_MINIMUM_SAMPLE_COUNT) iset->insavg[j][i] = (DCOFS_LOWPASS_COEFF*iset->insavg[j][i]) + (DCOFS_ONEMINUS_LOWPASS_COEFF*sum/cnt); } } } } } char InputSettings::IsSelectedStereo() { for (int i = 0; i < numins; i++) if (selins[i] && app->getCFG()->IsStereoInput(i)) return 1; // Nope! return 0; }; void InputSettings::AdjustInputVol(int n, float adjust) { if (n >= 0 || n < numins) { if (dinvols[n] < MAX_DVOL) dinvols[n] += adjust*app->getAUDIO()->GetTimeScale(); if (dinvols[n] < 0.0) dinvols[n] = 0.0; } else { printf("CORE: InputSettings- input number %d not in range.\n",n); } } Processor::Processor(Fweelin *app) : app(app), prelen(DEFAULT_SMOOTH_LENGTH), prewritten(0), prewriting(0) { // Create preprocess audio buffers (for smoothing) preab = new AudioBuffers(app); for (int i = 0; i < preab->numouts; i++) { preab->outs[0][i] = new sample_t[prelen]; preab->outs[1][i] = (preab->IsStereoMaster() ? new sample_t[prelen] : 0); } }; Processor::~Processor() { // Delete preprocess audio buffers for (int i = 0; i < preab->numouts; i++) { delete[] preab->outs[0][i]; if (preab->outs[1][i] != 0) delete[] preab->outs[1][i]; } delete preab; }; void Processor::dopreprocess() { if (prewriting) { printf("Caught ourselves writing PREPROCESS!\n"); return; } if (!prewritten && !prewriting) { // Do a preprocess to smooth abrupt changes in flow prewriting = 1; process(1,prelen,preab); // Process but write to preprocess buffers prewriting = 0; prewritten = 1; } } // Fade together current with preprocessed to create a smoothed output during // control changes void Processor::fadepreandcurrent(AudioBuffers *ab) { if (prewriting) { // This does happen } if (prewritten) { float dr = 1.0/prelen; // For each output for (int i = 0; i < ab->numouts; i++) { int stereo = (ab->outs[1][i] != 0 ? 1 : 0); for (int j = 0; j <= stereo; j++) { // Fade between preprocessed and current output sample_t *out = ab->outs[j][i]; if (out != 0) { // Do the pre-buffers match the outputs in channels? sample_t *pre = preab->outs[j][i]; if (pre == 0) { printf("DSP: ERROR: Pre buffers are null for active output.\n"); } else { float ramp = 0.0; for (nframes_t l = 0; l < prelen; l++, ramp += dr) out[l] = (out[l]*ramp) + (pre[l]*(1.0-ramp)); } } } } prewritten = 0; } } Pulse::Pulse(Fweelin *app, nframes_t len, nframes_t startpos) : Processor(app), len(len), curpos(startpos), lc_len(1), lc_cur(0), wrapped(0), stopped(0), prev_sync_bb(0), sync_cnt(0), prev_sync_speed(-1), prev_sync_type(0), prevbpm(0.0), prevtap(0), metroofs(metrolen), metrohiofs(metrolen), metroloofs(metrolen), metrolen(METRONOME_HIT_LEN), metrotonelen(METRONOME_TONE_LEN), metroactive(0), metrovol(METRONOME_INIT_VOL), numsyncpos(0), clockrun(SS_NONE) { #define METRO_HI_FREQ 880 #define METRO_HI_AMP 1.5 #define METRO_LO_FREQ 440 #define METRO_LO_AMP 1.0 // Generate metronome data metro = new sample_t[metrolen]; metrohitone = new sample_t[metrotonelen]; metrolotone = new sample_t[metrotonelen]; for (nframes_t i = 0; i < metrolen; i++ ) metro[i] = ((sample_t)rand()/RAND_MAX - 0.5) * (1.0 - (float)i/metrolen); for (nframes_t i = 0; i < metrotonelen; i++ ) { metrohitone[i] = METRO_HI_AMP * sin(METRO_HI_FREQ*i*2*M_PI/app->getAUDIO()->get_srate()) * (1.0 - (float)i/metrotonelen); metrolotone[i] = METRO_LO_AMP * sin(METRO_LO_FREQ*i*2*M_PI/app->getAUDIO()->get_srate()) * (1.0 - (float)i/metrotonelen); } }; Pulse::~Pulse() { // Notify BlockManager we are dying in case any mgrs depend on us app->getBMG()->RefDeleted(this); delete [] metro; delete [] metrohitone; delete [] metrolotone; }; // Quantizes src length to fit to this pulse length nframes_t Pulse::QuantizeLength(nframes_t src) { float frac = (float) src/len; if (frac < 0.5) frac = 1.0; // Don't allow 0 length loops return (nframes_t) (round(frac) * len); } void Pulse::SetMIDIClock (char start) { if (app->getMIDI()->GetMIDISyncTransmit()) { if (start) clockrun = SS_START; else { clockrun = SS_NONE; // Send MIDI stop for pulse MIDIStartStopInputEvent *ssevt = (MIDIStartStopInputEvent *) Event::GetEventByType(T_EV_Input_MIDIStartStop); ssevt->start = 0; app->getEMG()->BroadcastEventNow(ssevt, this); } } }; int Pulse::ExtendLongCount (long nbeats, char endjustify) { if (nbeats > 0) { int lc_new_len = math_lcm(lc_len,(int) nbeats); // Justify position relative to end of phrase (when expanding) if (endjustify && lc_new_len > lc_len) { int lc_end_delta = lc_len - lc_cur; // printf("CUR %d LEN %d\n",lc_cur,lc_len); lc_cur = lc_new_len - lc_end_delta; // Distance from end of phrase is preserved // printf("EDELTA %d NEWCUR %d NEWLEN %d\n",lc_end_delta,lc_cur,lc_new_len); } lc_len = lc_new_len; } return lc_len; }; // TODO // // Please note that all sync is done with a granularity of the audio period // size. A potential bug exists when loops recorded with one period size // are played on a system with another period size... the syncronization // may not line up, causing a click in the audio. // // Not sure how this might be resolved // For loops whose syncronized length is not a multiple of the period size, // those loops may need to be resized so that the loop point falls on a // period boundary // void Pulse::process(char pre, nframes_t l, AudioBuffers *ab) { static int midi_clock_count = 0, midi_beat_count = 0; // If we're using Jack transport (audio) sync, and we're slave to another app, // adjust pulse to stay in-sync if (app->getAUDIO()->IsTransportRolling() && !app->getAUDIO()->IsTimebaseMaster()) { char sync_type = app->GetSyncType(); int sync_speed = app->GetSyncSpeed(); if (sync_type != prev_sync_type || sync_speed != prev_sync_speed) { // Make sure we recalculate length / wrap if sync params changed prevbpm = 0; prev_sync_bb = -1; prev_sync_type = sync_type; prev_sync_speed = sync_speed; } double bpm = app->getAUDIO()->GetTransport_BPM(); if (bpm != prevbpm) { // Adjust pulse length from BPM float mult = (sync_type ? sync_speed : app->getAUDIO()->GetTransport_BPB()* sync_speed); len = (nframes_t) ((double) 60.*app->getAUDIO()->get_srate()*mult/bpm); // printf("slave to bpm: %lf, len: %d\n",bpm,len); prevbpm = bpm; } int sync_bb = (sync_type ? app->getAUDIO()->GetTransport_Beat() : app->getAUDIO()->GetTransport_Bar()); if (sync_bb != prev_sync_bb) { sync_cnt++; if (sync_cnt >= sync_speed) { // Wrap pulse- enough bars or beats has passed sync_cnt = 0; Wrap(); } // printf("slave to sync: %d\n",sync_bb); prev_sync_bb = sync_bb; } } nframes_t fragmentsize = app->getBUFSZ(); if (l > fragmentsize) l = fragmentsize; // Process on left channel of first output sample_t *out = ab->outs[0][0]; nframes_t ofs = 0; if (!pre && !stopped) { nframes_t remaining = len-curpos; // Move forward pulse position wrapped = 0; nframes_t oldpos = curpos; curpos += MIN(l,remaining); // If we are transmitting MIDI sync, do so now if (clockrun != SS_NONE && app->getMIDI()->GetMIDISyncTransmit()) { char sync_type = app->GetSyncType(); int sync_speed = app->GetSyncSpeed(); // 1 pulse = how many MIDI clock messages to send? // In sync-beat mode, each pulse is SyncSpeed beats, so MIDI_CLOCK_FREQUENCY*SyncSpeed clocks to send // In sync-bar mode, each pulse is one bar, so MIDI_CLOCK_FREQUENCY*BeatsPerBar*SyncSpeed clocks to send int clocksperpulse = MIDI_CLOCK_FREQUENCY*sync_speed; if (!sync_type) clocksperpulse *= SYNC_BEATS_PER_BAR; // Check timing of pulse float framesperclock = (float) len/clocksperpulse; int oldclock = (int) ((float) oldpos/framesperclock), newclock = (int) ((float) curpos/framesperclock); if ((clockrun == SS_BEAT && newclock != oldclock) || curpos >= len) { // printf("CLOCKY-OO %d!\n",newclock); if (clockrun == SS_START) { // Send MIDI start for pulse metrohiofs = 0; // Sound metronome high tone midi_clock_count = 0; midi_beat_count = 0; MIDIStartStopInputEvent *ssevt = (MIDIStartStopInputEvent *) Event::GetEventByType(T_EV_Input_MIDIStartStop); ssevt->start = 1; app->getEMG()->BroadcastEventNow(ssevt, this); // If this is the first downbeat, start the clock proper clockrun = SS_BEAT; } else { midi_clock_count++; if (midi_clock_count >= MIDI_CLOCK_FREQUENCY) { // Quarter not has passed, sound metronome low tone midi_clock_count = 0; // printf("PULSE: quarter clock\n"); midi_beat_count++; if (midi_beat_count >= clocksperpulse/MIDI_CLOCK_FREQUENCY) { midi_beat_count = 0; metrohiofs = 0; // Sound metronome high tone } else metroloofs = 0; // Sound metronome low tone } // Time for another clock message MIDIClockInputEvent *clkevt = (MIDIClockInputEvent *) Event::GetEventByType(T_EV_Input_MIDIClock); // *** Broadcast immediately-- this will yield lowest MIDI sync latency, // but may cause problems if MIDI transmit code blocks/conflicts with RT audio thread // (which it very well might) // _experimental_ app->getEMG()->BroadcastEventNow(clkevt, this); } } } // Check pulse wrap if (curpos >= len) { // Downbeat!! wrapped = 1; curpos = 0; // Long count lc_cur++; if (lc_cur >= lc_len) lc_cur = 0; // Send out a pulse sync event PulseSyncEvent *pevt = (PulseSyncEvent *) Event::GetEventByType(T_EV_PulseSync); app->getEMG()->BroadcastEventNow(pevt, this); // Trigger management of any RT work on blocks // (currently PulseSync event handles loop points, but // BMG handles striping through StripeBlockManager) // *** To be consolidated into EMG? app->getBMG()->HiPriTrigger(this); // Metronome sound on metroofs = 0; l -= remaining; memset(out,0,sizeof(sample_t) * remaining); ofs += remaining; } // Send out user-define pulse syncs for (int i = 0; i < numsyncpos; i++) { if (syncpos[i].cb != 0 && ((oldpos < syncpos[i].syncpos && curpos >= syncpos[i].syncpos) || (wrapped && syncpos[i].syncpos <= curpos))) { // Call sync callback syncpos[i].cb->PulseSync(i,curpos); } } } // Producing metronome signals if (metroofs < metrolen) { if (metroactive && metrovol > 0.0) { nframes_t i = 0; for (; i < l && metroofs+i 0.0) { nframes_t i = 0; for (; i < l && metrohiofs+i 0.0) { nframes_t i = 0; for (; i < l && metroloofs+iouts[1][0] != 0) memcpy(ab->outs[1][0],ab->outs[0][0],sizeof(sample_t) * l); } AutoLimitProcessor::AutoLimitProcessor(Fweelin *app) : Processor(app) { ResetLimiter(); }; AutoLimitProcessor::~AutoLimitProcessor() { }; void AutoLimitProcessor::ResetLimiter() { dlimitvol = app->getCFG()->GetLimiterReleaseRate(); limitvol = LIMITER_START_AMP; curlimitvol = LIMITER_START_AMP; maxvol = app->getCFG()->GetLimiterThreshhold(); limiterfreeze = 0; } void AutoLimitProcessor::process(char /*pre*/, nframes_t len, AudioBuffers *ab) { // Autolimit treats stereo channels as linked float localmaxvol = 0.0, maxamp = app->getCFG()->GetMaxLimiterGain(), limitthresh = app->getCFG()->GetLimiterThreshhold(), limitrr = app->getCFG()->GetLimiterReleaseRate(); int clipcnt = 0; sample_t *s_left = ab->outs[0][0], // Process in place on the output *s_right = ab->outs[1][0]; int stereo = (s_right != 0 ? 1 : 0); if (stereo) { // Stereo limit for (nframes_t l = 0; l < len; l++, s_left++, s_right++) { float abssamp_l = fabs(*s_left), abssamp_r = fabs(*s_right); // Volume scale *s_left *= curlimitvol; *s_right *= curlimitvol; float abssamp2_l = fabs(*s_left), abssamp2_r = fabs(*s_right); if (!limiterfreeze) { // Find local maxima if (abssamp_l > localmaxvol) localmaxvol = abssamp_l; if (abssamp_r > localmaxvol) localmaxvol = abssamp_r; // Find clipping after limit if (abssamp2_l > limitthresh) clipcnt++; // Force limit if (abssamp2_r > limitthresh) clipcnt++; // Force limit // Adjust volume scale curlimitvol += dlimitvol; } // Clipping kludge-- // Some output formats clip near 1.0.. brickwall limit to 1.0 if (abssamp2_l > 0.99) { // Absolute clip! Truncate if (*s_left > 0.0) *s_left = 0.99; else *s_left = -0.99; } if (abssamp2_r > 0.99) { // Absolute clip! Truncate if (*s_right > 0.0) *s_right = 0.99; else *s_right = -0.99; } if (l+1 == len || l % LIMITER_ADJUST_PERIOD == 0) { // Time to check & adjust limit parameters if (clipcnt > 0 || localmaxvol > maxvol) { // We got more clipping! clipcnt = 0; float newlimitvol = limitthresh/localmaxvol; // Compute volume reduction necessary to bring in peak limitvol = newlimitvol; // Compute delta (speed) to get to that reduction (attack time) dlimitvol = (limitvol-curlimitvol)/LIMITER_ATTACK_LENGTH; // Store new max maxvol = localmaxvol; } if (dlimitvol < 0.0 && curlimitvol <= limitvol) { // We are done the attack phase- switch to release! dlimitvol = limitrr; } if (dlimitvol > 0.0 && curlimitvol > maxamp) { // Too much amp! dlimitvol = 0.0; } } } } else { // Mono limit for (nframes_t l = 0; l < len; l++, s_left++) { float abssamp_l = fabs(*s_left); // Volume scale *s_left *= curlimitvol; float abssamp2_l = fabs(*s_left); if (!limiterfreeze) { // Find local maxima if (abssamp_l > localmaxvol) localmaxvol = abssamp_l; // Find clipping after limit if (abssamp2_l > limitthresh) clipcnt++; // Force limit // Adjust volume scale curlimitvol += dlimitvol; } // Vorbis clipping kludge-- // Vorbis clips near 1.0.. 1st step is brickwall at 1.0 // then scale down.. (scaling happens in FileStreamer) if (abssamp2_l > 0.99) { // Absolute clip! Truncate if (*s_left > 0.0) *s_left = 0.99; else *s_left = -0.99; } if (l+1 == len || l % LIMITER_ADJUST_PERIOD == 0) { // Time to check & adjust limit parameters if (clipcnt > 0 || localmaxvol > maxvol) { // We got more clipping! clipcnt = 0; float newlimitvol = limitthresh/localmaxvol; // Compute volume reduction necessary to bring in peak limitvol = newlimitvol; // Compute delta (speed) to get to that reduction (attack time) dlimitvol = (limitvol-curlimitvol)/LIMITER_ATTACK_LENGTH; // Store new max maxvol = localmaxvol; } if (dlimitvol < 0.0 && curlimitvol <= limitvol) { // We are done the attack phase- switch to release! dlimitvol = limitrr; } if (dlimitvol > 0.0 && curlimitvol > maxamp) { // Too much amp! dlimitvol = 0.0; } } } } } RootProcessor::RootProcessor(Fweelin *app, InputSettings *iset) : Processor(app), eq(0), protect_plist(0), iset(iset), outputvol(1.0), doutputvol(1.0), inputvol(1.0), dinputvol(1.0), firstchild(0), samplecnt(0) { // Temporary buffers and routing abtmp = new AudioBuffers(app); // abtmp2 = new AudioBuffers(app); // Second chain temp // Pre needs a separate set because preprocess runs in a different thread preabtmp = new AudioBuffers(app); buf[0] = new sample_t[app->getBUFSZ()]; // buf2[0] = new sample_t[app->getBUFSZ()]; prebuf[0] = new sample_t[prelen]; if (abtmp->IsStereoMaster()) { buf[1] = new sample_t[app->getBUFSZ()]; // buf2[1] = new sample_t[app->getBUFSZ()]; prebuf[1] = new sample_t[prelen]; } else { buf[1] = 0; // buf2[1] = 0; prebuf[1] = 0; } //printf (" :: Processor: RootProcessor begin (block size: %d)\n", // app->getBUFSZ()); app->getEMG()->ListenEvent(this,0,T_EV_CleanupProcessor); }; RootProcessor::~RootProcessor() { // printf(" :: Processor: RootProcessor cleanup...\n"); // RootProcessor closing.. // All child processors must end! ProcessorItem *cur = firstchild; while (cur != 0) { ProcessorItem *tmp = cur->next; // Stop child and delete processor! delete cur->p; delete cur; cur = tmp; } delete[] buf[0]; // delete[] buf2[0]; delete[] prebuf[0]; if (buf[1] != 0) delete[] buf[1]; //if (buf2[1] != 0) // delete[] buf2[1]; if (prebuf[1] != 0) delete[] prebuf[1]; delete abtmp; // delete abtmp2; delete preabtmp; if (eq != 0) delete eq; // printf(" :: Processor: RootProcessor end\n"); app->getEMG()->UnlistenEvent(this,0,T_EV_CleanupProcessor); } void RootProcessor::FinalPrep () { printf("RP: Create ringbuffers and begin.\n"); eq = new SRMWRingBuffer(RP_QUEUE_SIZE); } void RootProcessor::AdjustOutputVolume(float adjust) { if (doutputvol < MAX_DVOL) doutputvol += adjust*app->getAUDIO()->GetTimeScale(); if (doutputvol < 0.0) doutputvol = 0.0; } void RootProcessor::AdjustInputVolume(float adjust) { if (dinputvol < MAX_DVOL) dinputvol += adjust*app->getAUDIO()->GetTimeScale(); if (dinputvol < 0.0) dinputvol = 0.0; } // Adds a child processor.. the processor begins processing immediately // Not realtime safe // // If the processor should not produce any output, pass nonzero in silent void RootProcessor::AddChild (Processor *o, int type, char silent) { // Do a preprocess for fadein dopreprocess(); // Prepare an event for RT process to add a new processor to its list AddProcessorEvent *addevt = (AddProcessorEvent *) Event::GetEventByType(T_EV_AddProcessor); addevt->new_processor = new ProcessorItem(o,type,silent); // Add event to queue eq->WriteElement(addevt); // This way, no modifications to the processor list are done, except by the RT thread. } // Removes a child processor from receiving processing time.. // also, deletes the child processor // Realtime safe! Should also be threadsafe. void RootProcessor::DelChild (Processor *o) { ProcessorItem *cur = firstchild; protect_plist++; // Tell the RT thread - DON'T modify the processor list during this critical section // ** Just do this search in RT instead!!! FIXME // Search for processor 'o' in our list while (cur != 0 && cur->p != o) { cur = cur->next; } protect_plist--; // OK now if (cur != 0) { // Found it! // Do a preprocess for fadeout dopreprocess(); // Tell processor, Halt! o->Halt(); // Then set it to be deleted (call RT once first to finish up any RT tasks) cur->status = ProcessorItem::STATUS_LIVE_PENDING_DELETE; } } void RootProcessor::processchain(char pre, nframes_t len, AudioBuffers *ab, AudioBuffers *abchild, const int ptype, const char mixintoout) { int stereo = (ab->outs[1][0] != 0 && abchild->outs[1][0] != 0 ? 1 : 0); // Go through all children of type 'ptype' and mix ProcessorItem *cur = firstchild; while (cur != 0) { if (cur->status != ProcessorItem::STATUS_PENDING_DELETE && cur->type == ptype) { // Run audio processing... cur->p->process(pre, len, abchild); if (!pre && cur->status == ProcessorItem::STATUS_LIVE_PENDING_DELETE) { cur->status = ProcessorItem::STATUS_PENDING_DELETE; // Last run finished, now delete // Flag this processor for removal from our list, the next time through RT DelProcessorEvent *delevt = (DelProcessorEvent *) Event::GetEventByType(T_EV_DelProcessor); delevt->processor = cur; // Add event to queue eq->WriteElement(delevt); } if (mixintoout && !cur->silent) { // Sum from temporary output (abchild) into main output (ab) for (int chan = 0; chan <= stereo; chan++) { sample_t *sumout = ab->outs[chan][0], *out = abchild->outs[chan][0]; for (nframes_t j = 0; j < len; j++) sumout[j] += out[j]; } } } cur = cur->next; } } void RootProcessor::ReceiveEvent(Event *ev, EventProducer */*from*/) { switch (ev->GetType()) { case T_EV_CleanupProcessor : { CleanupProcessorEvent *cleanevt = (CleanupProcessorEvent *) ev; delete cleanevt->processor->p; delete cleanevt->processor; // printf("CORE: Freed mem\n"); } break; default: break; } }; // Update the list of processors void RootProcessor::UpdateProcessors() { if (protect_plist == 0) { // Only mess with processor list when no thread is in a critical section // First, process any events coming from non-RT threads Event *curev = eq->ReadElement(); while (curev != 0) { switch (curev->GetType()) { case T_EV_AddProcessor : { AddProcessorEvent *addevt = (AddProcessorEvent *) curev; // Add processor to the end of the list ProcessorItem *cur = firstchild; if (cur == 0) firstchild = addevt->new_processor; else { while (cur->next != 0) cur = cur->next; cur->next = addevt->new_processor; } } break; case T_EV_DelProcessor : { // Traverse the list of children and look for a processor pending delete ProcessorItem *cur = firstchild, *prev = 0; while (cur != 0) { // Search for any processor pending delete in our list while (cur != 0 && cur->status != ProcessorItem::STATUS_PENDING_DELETE) { prev = cur; cur = cur->next; } if (cur != 0) { // Got one to delete, unlink! if (prev != 0) prev->next = cur->next; else firstchild = cur->next; ProcessorItem *tmp = cur->next; // Queue for memory free via EventManager CleanupProcessorEvent *cleanevt = (CleanupProcessorEvent *) Event::GetEventByType(T_EV_CleanupProcessor); cleanevt->processor = cur; app->getEMG()->BroadcastEvent(cleanevt,this); cur = tmp; } } } break; default: printf("RP: ERROR: Unknown event in my queue (%d)!\n",curev->GetType()); } curev->RTDelete(); curev = eq->ReadElement(); } } }; void RootProcessor::process(char pre, nframes_t len, AudioBuffers *ab) { nframes_t fragmentsize = app->getBUFSZ(); if (len > fragmentsize) len = fragmentsize; if (pre) // Do not allow processor list modification by RT thread when non-RT preprocess is engaged protect_plist++; if (!pre) { // RT pass. if (eq == 0) { // printf("*** RET FROM RT PASS\n"); return; // Event queue not up yet - abort } if (protect_plist < 0) { printf("RP: ERROR: Corrupt protect_plist (%d)\n",protect_plist); protect_plist = 0; } // Only update the processor list from this one thread UpdateProcessors(); // Run FluidSynth first, because its out feeds an input // Later support may come for true multiple signal chains #if USE_FLUIDSYNTH FluidSynthProcessor *fluidp = app->getFLUIDP(); fluidp->process(0, len, ab); #endif // Adjust global in/out volumes if (doutputvol != 1.0 || dinputvol != 1.0) { // Smoothing isn't necessary if the deltas are small! // dopreprocess(); // Apply delta if (doutputvol > 1.0 && outputvol < MIN_VOL) outputvol = MIN_VOL; if (outputvol < MAX_VOL) outputvol *= doutputvol; if (dinputvol > 1.0 && inputvol < MIN_VOL) inputvol = MIN_VOL; if (inputvol < MAX_VOL) inputvol *= dinputvol; } // Adjust individual input volumes for (int i = 0; i < iset->numins; i++) { if (iset->dinvols[i] > 1.0 && iset->invols[i] < MIN_VOL) iset->invols[i] = MIN_VOL; iset->invols[i] *= iset->dinvols[i]; } } // Zero the main output buffers- we'll be summing into them sample_t *out[2] = {ab->outs[0][0], ab->outs[1][0]}; int stereo = (out[1] != 0 ? 1 : 0); memset(out[0],0,sizeof(sample_t)*len); if (stereo) memset(out[1],0,sizeof(sample_t)*len); if (!pre) { // Setup our own audio route, routing output to our internal buffer // Then, child processors will use this buffer memcpy(abtmp->ins[0],ab->ins[0],sizeof(sample_t *) * ab->numins); memcpy(abtmp->ins[1],ab->ins[1],sizeof(sample_t *) * ab->numins); memset(abtmp->outs[0],0,sizeof(sample_t *) * ab->numouts); memset(abtmp->outs[1],0,sizeof(sample_t *) * ab->numouts); abtmp->outs[0][0] = buf[0]; abtmp->outs[1][0] = buf[1]; // Go through 1st all hipri, then all default children and mix processchain(pre,len,ab,abtmp,ProcessorItem::TYPE_HIPRIORITY,1); processchain(pre,len,ab,abtmp,ProcessorItem::TYPE_DEFAULT,1); } else { // Preprocess-- // Notice I use a different set of structs for AudioBuffer ptrs // This is so that a concurrently running preprocess and RT process // do not collide memset(preabtmp->ins[0],0,sizeof(sample_t *) * ab->numins); memset(preabtmp->ins[1],0,sizeof(sample_t *) * ab->numins); memset(preabtmp->outs[0],0,sizeof(sample_t *) * ab->numouts); memset(preabtmp->outs[1],0,sizeof(sample_t *) * ab->numouts); preabtmp->outs[0][0] = prebuf[0]; preabtmp->outs[1][0] = prebuf[1]; // Go through 1st all hipri, then all default children and mix back into main out (out) processchain(pre,len,ab,preabtmp,ProcessorItem::TYPE_HIPRIORITY,1); processchain(pre,len,ab,preabtmp,ProcessorItem::TYPE_DEFAULT,1); } // Output volume transform - main outputs for (int chan = 0; chan <= stereo; chan++) { sample_t *o = out[chan]; for (nframes_t l = 0; l < len; l++) o[l] *= outputvol; } if (!pre) { // Fade together current with preprocessed to create smoothed fadepreandcurrent(ab); // Route the output through a second chain of global children - each of these processors is connected in serial // with the output from one feeding the input of the next // The final output of this chain is not used- it is actually only used for the intermediary steps, such as // limiting the loop mix prior to streaming it /* memset(abtmp2->ins[0],0,sizeof(sample_t *) * ab->numins); memset(abtmp2->ins[1],0,sizeof(sample_t *) * ab->numins); memset(abtmp2->outs[0],0,sizeof(sample_t *) * ab->numouts); memset(abtmp2->outs[1],0,sizeof(sample_t *) * ab->numouts); abtmp2->ins[0][0] = buf2[0]; abtmp2->ins[1][0] = buf2[1]; abtmp2->outs[0][0] = buf2[0]; abtmp2->outs[1][0] = buf2[1]; */ // Second global chain works in place on the current output, like a side-chain memcpy(buf[0],out[0],sizeof(sample_t)*len); if (out[1] != 0) memcpy(buf[1],out[1],sizeof(sample_t)*len); abtmp->ins[0][0] = buf[0]; abtmp->ins[1][0] = buf[1]; abtmp->outs[0][0] = buf[0]; abtmp->outs[1][0] = buf[1]; processchain(pre,len,abtmp,abtmp,ProcessorItem::TYPE_GLOBAL_SECOND_CHAIN,0); // No mixing back in // Restore inputs to come from system inputs, and go through all global children after volume xform and mix. memcpy(abtmp->ins[0],ab->ins[0],sizeof(sample_t *) * ab->numins); memcpy(abtmp->ins[1],ab->ins[1],sizeof(sample_t *) * ab->numins); processchain(pre,len,ab,abtmp,ProcessorItem::TYPE_GLOBAL,1); // Make a copy for the visual scope // Output scope is disabled // memcpy(app->getSCOPE(), out, sizeof(sample_t) * len); // Now go through all FINAL children-- // They work on the end resulting signal, so we need to change the routing // so that our output becomes their input abtmp->ins[0][0] = out[0]; abtmp->ins[1][0] = out[1]; abtmp->outs[0][0] = out[0]; abtmp->outs[1][0] = out[1]; processchain(pre,len,ab,abtmp,ProcessorItem::TYPE_FINAL,0); // No mixing // Advance global sample count samplecnt += len; } // Now copy single hardcoded output to all other outputs // This is a hack until more developed multioutput support is implemented for (int i = 1; i < ab->numouts; i++) { for (int chan = 0; chan <= stereo; chan++) { if (ab->outs[chan][i] != 0) memcpy(ab->outs[chan][i],ab->outs[chan][0],sizeof(sample_t) * len); } } if (pre) protect_plist--; // Allow processor list update in RT audio } // Overdubbing version of record into existing loop RecordProcessor::RecordProcessor(Fweelin *app, InputSettings *iset, float *inputvol, Loop *od_loop, float od_playvol, nframes_t od_startofs, float *od_feedback) : Processor(app), sync_state(SS_NONE), iset(iset), inputvol(inputvol), nbeats(0), endsyncidx(-2), endsyncwait(0), sync_idx(-1), sync_add_pos(0), sync_add(0), stopped(0), pa_mgr(0), od_loop(od_loop), od_playvol(od_playvol), od_feedback(od_feedback), od_curbeat(0), od_fadein(1), od_fadeout(0), od_stop(0), od_prefadeout(0), od_lastofs(0) { // Store initial value for overdub feedback if (od_feedback != 0) od_feedback_lastval = *od_feedback; // Use the block supplied-- fixed length growchain = 0; compute_stats = 0; recblk = od_loop->blocks; // Clear the hash for the loop, since overdubbing will change it od_loop->SetSaveStatus(NO_SAVE); mbuf[0] = new sample_t[app->getBUFSZ()]; od_last_mbuf[0] = new sample_t[app->getBUFSZ()]; od_last_lpbuf[0] = new sample_t[app->getBUFSZ()]; // Is the loop we are overdubbing into a stereo loop? If so, run in stereo if (recblk->IsStereo()) { stereo = 1; mbuf[1] = new sample_t[app->getBUFSZ()]; od_last_mbuf[1] = new sample_t[app->getBUFSZ()]; od_last_lpbuf[1] = new sample_t[app->getBUFSZ()]; } else { stereo = 0; mbuf[1] = 0; od_last_mbuf[1] = 0; od_last_lpbuf[1] = 0; } // Create an audioblock iterator to move through that memory i = new AudioBlockIterator(recblk,app->getBUFSZ(), app->getPRE_EXTRACHANNEL()); // And a temporary iterator for overdub jumps tmpi = new AudioBlockIterator(recblk,app->getBUFSZ(), app->getPRE_EXTRACHANNEL()); // Check for quantize to pulse sync = od_loop->pulse; if (sync != 0) { // Behavior is that in overdub we always start immediately // .. at the right place in the loop if (od_startofs == 0) i->Jump(sync->GetPos()); else { // Calculate correct current beat based on startofs od_curbeat = od_startofs/sync->GetLength(); } // Notify Pulse to call us every beat sync_state = SS_BEAT; sync_add_pos = 0; sync_add = 1; } if (od_startofs != 0) { // Start at specified position i->Jump(od_startofs); } // And update peaks&avgs for displays (no grow!) pa_mgr = app->getBMG()->PeakAvgOn(recblk,i); }; // Recording into preexisting fixed size block // We can optionally specify whether we want the block to be stereo // Don't try to switch from stereo->mono->stereo for a block, though // If we don't specify stereo/mono, RecordProcessor decides automatically // based on the existing 'dest' RecordProcessor::RecordProcessor(Fweelin *app, InputSettings *iset, float *inputvol, AudioBlock *dest, int suggest_stereo) : Processor(app), sync_state(SS_NONE), iset(iset), inputvol(inputvol), sync(0), tmpi(0), nbeats(0), sync_idx(-1), sync_add_pos(0), sync_add(0), stopped(0), pa_mgr(0), od_loop(0), od_feedback(0), od_fadeout(0), od_stop(0), od_prefadeout(0) { // Use the block supplied-- fixed length growchain = 0; compute_stats = 1; recblk = dest; // Stereo or mono? mbuf[0] = new sample_t[app->getBUFSZ()]; stereo = (suggest_stereo == -1 ? recblk->IsStereo() : suggest_stereo); if (stereo) mbuf[1] = new sample_t[app->getBUFSZ()]; else mbuf[1] = 0; // Create an audioblock iterator to move through that memory i = new AudioBlockIterator(recblk,app->getBUFSZ(), app->getPRE_EXTRACHANNEL()); }; // ISSUES- // // Loop is straddled right now // between RecordProcessor & LoopManager-- icky // make separation more clear // // Tricky stuff with those block managers // // Recording new blocks, growing size as necessary RecordProcessor::RecordProcessor(Fweelin *app, InputSettings *iset, float *inputvol, Pulse *sync, AudioBlock *audiomem, AudioBlockIterator *audiomemi, nframes_t peaksavgs_chunksize) : Processor(app), sync_state(SS_NONE), iset(iset), inputvol(inputvol), sync(sync), tmpi(0), nbeats(0), endsyncidx(-2), endsyncwait(0), sync_idx(-1), sync_add_pos(0), sync_add(0), stopped(0), pa_mgr(0), od_loop(0), od_feedback(0), od_fadeout(0), od_stop(0), od_prefadeout(0) { // Grow the length of record as necessary growchain = 1; compute_stats = 0; // Get the next available block so we can begin recording now! recblk = (AudioBlock *) app->getPRE_AUDIOBLOCK()->RTNew(); if (recblk == 0) { printf("RecordProcessor: ERROR: No free blocks for record\n"); stopped = 1; i = 0; return; } // Stereo or mono? mbuf[0] = new sample_t[app->getBUFSZ()]; if (iset->IsSelectedStereo()) { stereo = 1; mbuf[1] = new sample_t[app->getBUFSZ()]; } else { stereo = 0; mbuf[1] = 0; } // printf("REC: New loop: %s\n",(stereo ? "stereo" : "mono")); // Create an audioblock iterator to move through that memory i = new AudioBlockIterator(recblk,app->getBUFSZ(), app->getPRE_EXTRACHANNEL()); // Check for sync to an pulse if (sync != 0) { if (sync->GetPct() >= 0.5) { // Close to next downbeat- so delay record start til then stopped = 1; sync_state = SS_START; sync_add_pos = 0; sync_add = 1; } else { // Close to previous downbeat- start record now & grab missed // chunk from previous downbeat til now // Use BED_MarkerPoints in audiomem to get chunk BED_MarkerPoints *mp = (BED_MarkerPoints *) (audiomem->GetExtendedData(T_BED_MarkerPoints)); if (mp == 0) { // No marker block printf("Err (SYNCREC): No markers striped in Audio Mem!\n"); exit(1); } else { // Get a sub block from the previous downbeat nframes_t curofs = audiomemi->GetTotalLength2Cur(), prevofs; TimeMarker *prevm = mp->GetMarkerNBeforeCur(1,curofs); if (prevm != 0) { prevofs = prevm->markofs; AudioBlock *beginblk = audiomem->GenerateSubChain(prevofs,curofs,stereo); if (beginblk == 0) { printf("Err: Problem generating subchain from audiomemory.\n"); exit(1); } // Now reorganize the block chain to put beginblk first recblk = recblk->InsertFirst(beginblk); // Recalculate iterator constants-- iterator should // start recording at end of block ripped from audiomemory i->GenConstants(); } else { // Bad markers (not fatal!)- just don't copy from audiomem printf("SYNCREC: Previous markers in Audio Mem unknown!\n"); } } // Notify Pulse to call us every beat sync_state = SS_BEAT; sync_add_pos = 0; sync_add = 1; } } // Concurrently compute peaks & averages during recording if (peaksavgs_chunksize != 0) { AudioBlock *peaks = (AudioBlock *) recblk->RTNew(), *avgs = (AudioBlock *) recblk->RTNew(); if (peaks == 0 || avgs == 0) { printf("RecordProcessor: ERROR: No free blocks for peaks/avgs\n"); stopped = 1; return; } recblk->AddExtendedData(new BED_PeaksAvgs(peaks,avgs, peaksavgs_chunksize)); pa_mgr = app->getBMG()->PeakAvgOn(recblk,i,1); } // Tell the block manager to auto-grow this block chain for recording app->getBMG()->GrowChainOn(recblk,i); }; RecordProcessor::~RecordProcessor() { if (!stopped) { // This shouldn't be a problem, it happens in overdub and direct record AbortRecording(); } // Notify BlockManager we are dying in case any mgrs depend on us app->getBMG()->RefDeleted(this); app->getBMG()->RefDeleted(i); // Redundant check- stop pulse sync callback if (sync != 0 && sync_idx != -1) { printf("CORE: Stray PulseSync Callback!\n"); sync->DelPulseSync(sync_idx); } if (i != 0) delete i; if (tmpi != 0) delete tmpi; delete[] mbuf[0]; if (mbuf[1] != 0) delete[] mbuf[1]; if (od_loop != 0) { delete[] od_last_mbuf[0]; if (od_last_mbuf[1] != 0) delete[] od_last_mbuf[1]; delete[] od_last_lpbuf[0]; if (od_last_lpbuf[1] != 0) delete[] od_last_lpbuf[1]; } }; void RecordProcessor::SyncUp() { // Sync loop to pulse if (od_loop != 0) { sync_state = SS_START; sync = od_loop->pulse; sync_add_pos = 0; sync_add = 1; } } nframes_t RecordProcessor::GetRecordedLength() { return i->GetTotalLength2Cur(); } void RecordProcessor::EndNow() { // End record now if (od_loop == 0) stopped = 1; // For straight record, stop all processing else od_stop = 1; // For overdub, keep playing going EndRecordEvent *endrec = (EndRecordEvent *) Event::GetEventByType(T_EV_EndRecord); if (endrec == 0) { printf("RecordProcessor: ERROR: No free event memory\n"); exit(1); } if (od_loop == 0 && i->GetTotalLength2Cur() == 0) { // Zero length record! Forget it! endrec->keeprecord = 0; AbortRecording(); } else { endrec->keeprecord = 1; // Not overdubbing.. if (od_loop == 0) { // Chop recorded block to current position (end record) i->EndChain(); if (growchain) { // Stop expanding this recording app->getBMG()->GrowChainOff(recblk); } // For new non syncronized loops-- // Bend our strip of audio into a loop // Smooth beginning into end, shorten loop- if (sync == 0) recblk->Smooth(); /* else printf("reclen: %d, synclen: %d\n",recblk->GetTotalLen(), sync->GetLength()); */ } // End peaks avgs compute now if (pa_mgr != 0) { pa_mgr->End(); app->getBMG()->PeakAvgOff(recblk); pa_mgr = 0; } } // Broadcast a message that recording has finished // Broadcast nonRT, because EndRecord does non-RT safe operations app->getEMG()->BroadcastEvent(endrec, this); } // May be called during EndNow() (RT) // RT safe void RecordProcessor::AbortRecording() { // Stop iterator- this stops GrowChain as well as other // managers attached to iterator i->Stop(); // Stop pulse sync if (sync != 0) { // AbortRecording is RT safe, so reset sync_state to stop further // sync processing sync_state = SS_ENDED; } // No more process(), just in case race condition // causes process() while we are still cleaning up stopped = 1; // End peaks avgs compute now if (pa_mgr != 0) { pa_mgr->End(); app->getBMG()->PeakAvgOff(recblk); pa_mgr = 0; } // Blocks are deleted nonRT in DeleteLoop if (growchain) // Stop expanding this recording app->getBMG()->GrowChainOff(recblk); } void RecordProcessor::PulseSync (int syncidx, nframes_t /*actualpos*/) { // printf("RecSync: %d ESIdx: %d Sync_Idx: %d ActualPos: %d\n",syncidx,endsyncidx,sync_idx,actualpos); if (syncidx == endsyncidx && endsyncwait) { // End record msg // printf("PulseSync CB: %d %d\n",syncidx,actualpos); // End record now EndNow(); // Remove user-defined sync point endsyncwait = 0; sync->DelPulseSync(endsyncidx); // Stop calling use! sync_state = SS_ENDED; } else if (syncidx == sync_idx) { // Regular pulse msg switch (sync_state) { case SS_START: if (od_loop != 0) { // Overdub record, fade to start since we are syncing with pulse Jump(od_loop->pulse->GetPos()); } else { // Start record now stopped = 0; } sync_state = SS_BEAT; break; case SS_END: nbeats++; endsyncwait = 1; break; case SS_BEAT: if (od_loop != 0) { // Overdub record od_curbeat++; if (od_curbeat >= od_loop->nbeats) { // Quantize loop by restarting Jump(od_loop->pulse->GetPos()); od_curbeat = 0; } } else { // Regular grow record nbeats++; } // Call us on further beats sync_state = SS_BEAT; break; case SS_ENDED: break; default: break; } } }; void RecordProcessor::End() { if (od_loop != 0) { // Overdub ends after short smooth fadeout (see process()) od_fadeout = 1; } else { if (sync != 0) { // Sync, so check timing if (sync->GetPct() >= 0.5 || sync->GetPos() < REC_TAIL_LEN) { // Delay record til slightly after downbeat-- we // want to capture an extra 'tail' for crossfading. if (sync->GetPos() < REC_TAIL_LEN) endsyncwait = 1; // Past the downbeat // printf("CORE: Add EndSync\n"); endsyncidx = sync->AddPulseSync(this,REC_TAIL_LEN); sync_state = SS_END; } else { // Close to previous downbeat- end record now & crop extra chunk EndNow(); // Now hack off end of recording to downbeat // *** To be tested *** /*if (recblk->HackTotalLengthBy(sync->GetPos())) printf("Err (SYNCREC): Problem cutting length of record\n");*/ } } else { // No sync, stop recording now! EndNow(); } } } // Fades input samples out of mix- writing to 'dest' void RecordProcessor::FadeOut_Input(nframes_t len, sample_t *input_l, sample_t *input_r, sample_t *loop_l, sample_t *loop_r, float old_fb, float /*new_fb*/, float fb_delta, sample_t *dest_l, sample_t *dest_r) { // Fade out input samples // (feedback to 1.0) // Left float ramp = 0.0, negramp = 1.0, dr = 1.0/prelen; nframes_t l = 0; float cur_fb = old_fb; if (fb_delta == 0.0) { for (; l < prelen; l++, ramp += dr, negramp -= dr) { dest_l[l] = (input_l[l]*negramp) + (loop_l[l]*(ramp+negramp*cur_fb)); } } else { for (; l < prelen; l++, ramp += dr, negramp -= dr, cur_fb += fb_delta) { dest_l[l] = (input_l[l]*negramp) + (loop_l[l]*(ramp+negramp*cur_fb)); } } // Copy remainder of fragment directly from loop if (len-l > 0) memcpy(&(dest_l[l]),&(loop_l[l]),sizeof(sample_t) * (len-l)); if (dest_r != 0) { // Right ramp = 0.0; negramp = 1.0; cur_fb = old_fb; if (fb_delta == 0.0) { for (l = 0; l < prelen; l++, ramp += dr, negramp -= dr) { dest_r[l] = (input_r[l]*negramp) + (loop_r[l]*(ramp+negramp*cur_fb)); } } else { for (l = 0; l < prelen; l++, ramp += dr, negramp -= dr, cur_fb += fb_delta) { dest_r[l] = (input_r[l]*negramp) + (loop_r[l]*(ramp+negramp*cur_fb)); } } // Copy remainder of fragment directly from loop if (len-l > 0) memcpy(&(dest_r[l]),&(loop_r[l]),sizeof(sample_t) * (len-l)); } }; // Fades input samples into mix- writing to 'dest' void RecordProcessor::FadeIn_Input(nframes_t len, sample_t *input_l, sample_t *input_r, sample_t *loop_l, sample_t *loop_r, float old_fb, float /*new_fb*/, float fb_delta, sample_t *dest_l, sample_t *dest_r) { // Left // Fade in input samples float ramp = 0.0, negramp = 1.0, dr = 1.0/prelen; nframes_t l = 0; float cur_fb = old_fb; if (fb_delta == 0.0) { for (; l < prelen; l++, ramp += dr, negramp -= dr) { dest_l[l] = (input_l[l]*ramp) + (loop_l[l]*(negramp+ramp*cur_fb)); } // Proceed as regular mix for (; l < len; l++) dest_l[l] = input_l[l] + loop_l[l] * cur_fb; } else { for (; l < prelen; l++, ramp += dr, negramp -= dr, cur_fb += fb_delta) { dest_l[l] = (input_l[l]*ramp) + (loop_l[l]*(negramp+ramp*cur_fb)); } // Proceed as regular mix for (; l < len; l++, cur_fb += fb_delta) dest_l[l] = input_l[l] + loop_l[l] * cur_fb; } if (dest_r != 0) { // Right // Fade in input samples ramp = 0.0; negramp = 1.0; cur_fb = old_fb; if (fb_delta == 0.0) { for (l = 0; l < prelen; l++, ramp += dr, negramp -= dr) { dest_r[l] = (input_r[l]*ramp) + (loop_r[l]*(negramp+ramp*cur_fb)); } // Proceed as regular mix for (; l < len; l++) dest_r[l] = input_r[l] + loop_r[l] * cur_fb; } else { for (l = 0; l < prelen; l++, ramp += dr, negramp -= dr, cur_fb += fb_delta) { dest_r[l] = (input_r[l]*ramp) + (loop_r[l]*(negramp+ramp*cur_fb)); } // Proceed as regular mix for (; l < len; l++, cur_fb += fb_delta) dest_r[l] = input_r[l] + loop_r[l] * cur_fb; } } }; // Jumps to a position within an overdubbing loop- fade of input & output void RecordProcessor::Jump(nframes_t ofs) { //dopreprocess(); //i->Jump(ofs); nframes_t curofs = i->GetTotalLength2Cur(); if (curofs != ofs) { if (od_loop != 0) { #if 0 printf("Overdub jump: %d -> %d\n",curofs,ofs); printf("looplen: %d pulselen: %d\n",od_loop->blocks->GetTotalLen(), od_loop->pulse->GetLength()); // Since we are jumping in overdub, we need to fade out/in input // We need to fadeout input on preprocess // and fadein input on new position // So go back to the last processed fragment and fade out input samples FadeOut_Input(app->getBUFSZ(), od_last_mbuf[0], od_last_mbuf[1], od_last_lpbuf[0], od_last_lpbuf[1], od_feedback, od_last_mbuf[0], od_last_mbuf[1]); // Store in last processed fragment tmpi->Jump(od_lastofs); tmpi->PutFragment(od_last_mbuf[0],od_last_mbuf[1]); od_fadein = 1; #endif od_lastofs = curofs; od_prefadeout = 1; od_fadein = 1; } dopreprocess(); i->Jump(ofs); } }; void RecordProcessor::process(char pre, nframes_t len, AudioBuffers *ab) { nframes_t fragmentsize = app->getBUFSZ(); if (len > fragmentsize) len = fragmentsize; if (!pre && sync != 0 && sync_add) { // RT thread- add pulse sync callback sync_idx = sync->AddPulseSync(this,sync_add_pos); sync_add = 0; // rintf("CORE: Record AddSync: %d @ idx %d\n",sync_add_pos,sync_idx); } // If we have sync points defined with a pulse, // and if sync_state is SS_ENDED, this is the last run through process() // so remove the pulse sync(s) if (!pre && sync_state == SS_ENDED && sync_idx != -1) { sync->DelPulseSync(sync_idx); sync_idx = -1; } if (!pre && sync_state == SS_ENDED && endsyncwait) { endsyncwait = 0; sync->DelPulseSync(endsyncidx); } // Some key behavior: // stopped means no processing occurs // od_fadein means fade in input samples // od_fadeout means fade out input samples (it is the end of overdub) // od_stop means overdub has ended but playing from loop is retained sample_t *out[2] = {ab->outs[0][0], ab->outs[1][0]}; if (!stopped) { sample_t *lpbuf[2] = {0,0}; // Loop buffer // Compute feedback delta float new_fb, old_fb, fb_delta = 0.0; if (od_feedback != 0) { new_fb = *od_feedback; old_fb = od_feedback_lastval; fb_delta = (new_fb-old_fb)/len; } else new_fb = old_fb = OVERDUB_DEFAULT_FEEDBACK; if (!pre) od_feedback_lastval = new_fb; /* if (od_feedback != 0) printf("OLD FB: %f NEW FB: %f DELTA: %f\n",old_fb,new_fb,fb_delta); */ // ** Play part if (od_loop != 0) { // Overdub- playing & recording // Adjust volume if (!pre) od_loop->UpdateVolume(); // Check if we need to fade-out at a previous position if (!pre && od_prefadeout) { // We jumped to a new position in overdub.. fadeout at // old position tmpi->Jump(od_lastofs); // Get audio from the block if (stereo) tmpi->GetFragment(&lpbuf[0],&lpbuf[1]); else tmpi->GetFragment(&lpbuf[0],0); // Mix selected inputs ab->MixInputs(len,mbuf,iset,*inputvol,compute_stats); FadeOut_Input(len, mbuf[0], mbuf[1], lpbuf[0], lpbuf[1], old_fb, new_fb, fb_delta, mbuf[0], mbuf[1]); if (stereo) tmpi->PutFragment(mbuf[0],mbuf[1]); else tmpi->PutFragment(mbuf[0],0); od_prefadeout = 0; } // Get audio from the block if (stereo) i->GetFragment(&lpbuf[0],&lpbuf[1]); else i->GetFragment(&lpbuf[0],0); // Scale volume float vol = od_loop->vol * od_playvol; // Protect our ears! float maxvol = app->getCFG()->GetMaxPlayVol(); if (maxvol > 0.0 && vol > maxvol) vol = maxvol; if (vol < 0) vol = 0; // Play to output if (stereo) { sample_t *o_l = out[0], *o_r = out[1], *lpb_l = lpbuf[0], *lpb_r = lpbuf[1]; for (nframes_t l = 0; l < len; l++, o_l++, o_r++, lpb_l++, lpb_r++) { *o_l = *lpb_l * vol; *o_r = *lpb_r * vol; } } else { sample_t *o_l = out[0], *lpb_l = lpbuf[0]; for (nframes_t l = 0; l < len; l++, o_l++, lpb_l++) *o_l = *lpb_l * vol; if (out[1] != 0) // Mono loop into stereo outs- duplicate memcpy(out[1],out[0],sizeof(sample_t) * len); } if (!pre) { // Fade together current with preprocessed to create smoothed fadepreandcurrent(ab); } } else { // No overdub- not playing- zero outputs memset(out[0],0,sizeof(sample_t) * len); if (out[1] != 0) memset(out[1],0,sizeof(sample_t) * len); } // ** Record part if (!pre && !od_stop) { // Mix selected inputs to record loop ab->MixInputs(len,mbuf,iset,*inputvol,compute_stats); if (od_loop != 0) { // Overdub- mix new input with loop // First, make copies of buffers incase we have an overdub jump memcpy(od_last_lpbuf[0],lpbuf[0],sizeof(sample_t) * len); memcpy(od_last_mbuf[0],mbuf[0],sizeof(sample_t) * len); if (stereo) { memcpy(od_last_lpbuf[1],lpbuf[1],sizeof(sample_t) * len); memcpy(od_last_mbuf[1],mbuf[1],sizeof(sample_t) * len); } // od_lastofs = i->GetTotalLength2Cur(); if (!od_fadeout && !od_fadein) { // Regular case mix if (stereo) { sample_t *m_l = mbuf[0], *m_r = mbuf[1], *lpb_l = lpbuf[0], *lpb_r = lpbuf[1]; if (fb_delta == 0.0) { for (nframes_t l = 0; l < len; l++, m_l++, m_r++, lpb_l++, lpb_r++) { *m_l += *lpb_l * old_fb; *m_r += *lpb_r * old_fb; } } else { for (nframes_t l = 0; l < len; l++, m_l++, m_r++, lpb_l++, lpb_r++, old_fb += fb_delta) { *m_l += *lpb_l * old_fb; *m_r += *lpb_r * old_fb; } } } else { sample_t *m_l = mbuf[0], *lpb_l = lpbuf[0]; if (fb_delta == 0.0) { for (nframes_t l = 0; l < len; l++, m_l++, lpb_l++) *m_l += *lpb_l * old_fb; } else { for (nframes_t l = 0; l < len; l++, m_l++, lpb_l++, old_fb += fb_delta) *m_l += *lpb_l * old_fb; } } } else if (od_fadein) { // Fade in input samples FadeIn_Input(len, mbuf[0], mbuf[1], lpbuf[0], lpbuf[1], old_fb, new_fb, fb_delta, mbuf[0], mbuf[1]); // Proceed as regular overdub od_fadein = 0; } else if (od_fadeout) { // Fade out input samples FadeOut_Input(len, mbuf[0], mbuf[1], lpbuf[0], lpbuf[1], old_fb, new_fb, fb_delta, mbuf[0], mbuf[1]); } } // Record if (stereo) i->PutFragment(mbuf[0],mbuf[1]); else i->PutFragment(mbuf[0],0); if (!pre) { if (od_fadeout) { // Now end! EndNow(); } // Move along i->NextFragment(); } } else if (!pre && od_stop) { // Ended, no record but just advance i->NextFragment(); } } else { memset(out[0],0,sizeof(sample_t) * len); if (out[1] != 0) memset(out[1],0,sizeof(sample_t) * len); } } PlayProcessor::PlayProcessor(Fweelin *app, Loop *playloop, float playvol, nframes_t startofs) : Processor(app), sync_state(SS_NONE), sync_idx(-1), sync_add_pos(0), sync_add(0), stopped(0), playloop(playloop), playvol(playvol), curbeat(0) { // Stereo? stereo = playloop->blocks->IsStereo(); // Setup iterator to move through loop i = new AudioBlockIterator(playloop->blocks,app->getBUFSZ()); // Check for quantize to pulse sync = playloop->pulse; if (sync != 0) { // Compute start position based on long count of pulse if (playloop->nbeats == 0) { printf("CORE: Zero beats in loop- adjusting\n"); playloop->nbeats++; } int startcnt = sync->GetLongCount_Cur() % playloop->nbeats; nframes_t startofs_lc = startcnt * sync->GetLength() + sync->GetPos(); // Start using long count curbeat = startcnt; i->Jump(startofs_lc); // Notify Pulse to call us every beat sync_state = SS_BEAT; sync_add_pos = 0; sync_add = 1; } #ifdef FWEELIN_EXPERIMENTAL_NOTIFY_PULSE // OK, we are synced to a pulse, so notify on every beat of that pulse if (startofs == 0 && sync->GetPct() >= 0.5) { // Close to next downbeat- so delay play start til then stopped = 1; sync_state = SS_START; sync_add_pos = 0; sync_add = 1; } else { // Either we are close to a previous downbeat, // or we've been set to start at a specific place. // Start play now at the right place if (startofs == 0) i->Jump(sync->GetPos()); else { // Calculate correct current beat based on startofs curbeat = startofs/sync->GetLength(); } // Notify Pulse to call us every beat sync_state = SS_BEAT; sync_add_pos = 0; sync_add = 1; } } if (startofs != 0) { // Start at specified position i->Jump(startofs); } #else // FWEELIN_EXPERIMENTAL_NOTIFY_PULSE if (startofs) {} #endif // FWEELIN_EXPERIMENTAL_NOTIFY_PULSE }; PlayProcessor::~PlayProcessor() { // Notify BlockManager we are dying in case any mgrs depend on us app->getBMG()->RefDeleted(this); app->getBMG()->RefDeleted(i); // Redundant check- stop pulse sync callback if (sync != 0 && sync_idx != -1) { printf("CORE: Stray PulseSync Callback!\n"); sync->DelPulseSync(sync_idx); } delete i; } void PlayProcessor::SyncUp() { // Sync loop to pulse sync_state = SS_START; sync = playloop->pulse; sync_add_pos = 0; sync_add = 1; } nframes_t PlayProcessor::GetPlayedLength() { return i->GetTotalLength2Cur(); } void PlayProcessor::PulseSync (int /*syncidx*/, nframes_t /*actualpos*/) { switch (sync_state) { case SS_START: // Start play now dopreprocess(); // Fade to start i->Jump(sync->GetPos()); stopped = 0; // Call us every beat sync_state = SS_BEAT; break; case SS_BEAT: curbeat++; if (curbeat >= playloop->nbeats) { // Quantize loop by restarting dopreprocess(); // Fade to loop point i->Jump(sync->GetPos()); curbeat = 0; } // Call us on further beats sync_state = SS_BEAT; break; case SS_ENDED: break; default: break; } }; void PlayProcessor::process(char pre, nframes_t len, AudioBuffers *ab) { nframes_t fragmentsize = app->getBUFSZ(); if (len > fragmentsize) len = fragmentsize; if (!pre && sync != 0 && sync_add) { // RT thread- add pulse sync callback sync_idx = sync->AddPulseSync(this,sync_add_pos); sync_add = 0; } if (!pre && sync_state == SS_ENDED && sync_idx != -1) { sync->DelPulseSync(sync_idx); sync_idx = -1; } sample_t *out[2] = {ab->outs[0][0], ab->outs[1][0]}; if (!stopped) { if (!pre) playloop->UpdateVolume(); // Get audio from the block and put it in out sample_t *buf[2]; if (stereo) i->GetFragment(&buf[0],&buf[1]); else i->GetFragment(&buf[0],0); // Scale volume float vol = playloop->vol * playvol; // Protect our ears! float maxvol = app->getCFG()->GetMaxPlayVol(); if (maxvol > 0.0 && vol > maxvol) vol = maxvol; if (vol < 0) vol = 0; // Play if (stereo) { sample_t *o_l = out[0], *o_r = out[1], *b_l = buf[0], *b_r = buf[1]; for (nframes_t l = 0; l < len; l++, o_l++, o_r++, b_l++, b_r++) { *o_l = *b_l * vol; *o_r = *b_r * vol; } } else { sample_t *o_l = out[0], *b_l = buf[0]; for (nframes_t l = 0; l < len; l++, o_l++, b_l++) *o_l = *b_l * vol; if (out[1] != 0) // Mono loop into stereo outs- duplicate memcpy(out[1],out[0],sizeof(sample_t) * len); } if (!pre) { // Fade together current with preprocessed to create smoothed fadepreandcurrent(ab); // Advance to next fragment! i->NextFragment(); } } else { memset(out[0],0,sizeof(sample_t) * len); if (out[1] != 0) memset(out[1],0,sizeof(sample_t) * len); } } FileStreamer::FileStreamer(Fweelin *app, int input_idx, char stereo, nframes_t outbuflen) : Processor(app), writerstatus(STATUS_STOPPED), input_idx(input_idx), stereo(stereo), outname(""), timingname(""), write_timing(0), nbeats(0), outbuflen(outbuflen), threadgo(1) { const static size_t STACKSIZE = 1024*128; pthread_attr_t attr; pthread_attr_init(&attr); pthread_attr_setstacksize(&attr,STACKSIZE); printf("FILESTREAMER: Stacksize: %zd.\n",STACKSIZE); // Start encoding thread int ret = pthread_create(&encode_thread, &attr, run_encode_thread, static_cast(this)); if (ret != 0) { printf("(FILESTREAMER) pthread_create failed, exiting\n"); exit(1); } RT_RWThreads::RegisterReaderOrWriter(encode_thread); // Allocate space for time markers marks = ::new TimeMarker[MARKERBUFLEN]; } FileStreamer::~FileStreamer() { // Stop any writing if (writerstatus != STATUS_STOPPED) writerstatus = STATUS_STOP_PENDING; // Terminate the management thread threadgo = 0; pthread_join(encode_thread,0); // Erase space for time markers ::delete[] marks; // printf(" :: Processor: VorbisStreamer end\n"); }; void FileStreamer::InitStreamer() { // Allocate output buffer outbuf[0] = new sample_t[outbuflen]; if (stereo) outbuf[1] = new sample_t[outbuflen]; else outbuf[1] = 0; // Setup encoder switch (filetype) { case VORBIS: // OGG VORBIS enc = new VorbisEncoder(app,stereo); break; case WAV: //WAV enc = new SndFileEncoder(app, outbuflen, stereo, WAV); break; case FLAC: //FLAC enc = new SndFileEncoder(app, outbuflen, stereo, FLAC); break; case AU: //AU enc = new SndFileEncoder(app, outbuflen, stereo, AU); break; default: enc = new VorbisEncoder(app,stereo); break; } }; void FileStreamer::EndStreamer() { // Free output buffer delete[] outbuf[0]; if (outbuf[1] != 0) delete[] outbuf[1]; // Cleanup encoder delete enc; }; int FileStreamer::StartWriting(const std::string &filename_stub, const char *stream_type_name, char write_timing, codec type) { if (writerstatus != STATUS_STOPPED) return -1; // Already writing! outname = filename_stub + stream_type_name + app->getCFG()->GetAudioFileExt(type); printf("DISK: Open %s for writing\n",outname.c_str()); outputsize = 0; filetype = type; this->write_timing = write_timing; if (write_timing) this->timingname = filename_stub + FWEELIN_OUTPUT_TIMING_EXT; else this->timingname = ""; writerstatus = STATUS_START_PENDING; return 0; }; void FileStreamer::process(char pre, nframes_t len, AudioBuffers *ab) { // Stream a given input to disk sample_t *in[2] = {ab->ins[0][input_idx], ab->ins[1][input_idx]}; // sample_t *out = ab->outs[0]; if (!pre && writerstatus == STATUS_RUNNING) { // Streamer is active-- dump the realtime data into our buffer // for later encoding // Vorbis clips near 1.0 sample_t *b_l = in[0], *b_r = in[1]; if (stereo && b_r != 0) { // Stereo enc->Preprocess(b_l,b_r,len); if (outpos < encodepos && outpos + len > encodepos) // Encode thread is not keeping up. We are about to wrap around the ring buffer printf("DISK: FileStreamer encoder thread is behind. CPU use too high / too many streams.\n"); if (outpos + len < outbuflen) { memcpy(&outbuf[0][outpos],in[0],sizeof(sample_t) * len); memcpy(&outbuf[1][outpos],in[1],sizeof(sample_t) * len); outpos += len; } else { // Wrap case- byte-by-byte nframes_t n; sample_t *o_l = outbuf[0], *o_r = outbuf[1]; for (n = 0; outpos < outbuflen; outpos++, n++) { o_l[outpos] = b_l[n]; o_r[outpos] = b_r[n]; } outpos = 0; wrap = 1; for (; n < len; outpos++, n++) { o_l[outpos] = b_l[n]; o_r[outpos] = b_r[n]; } } } else { // Mono enc->Preprocess(b_l,0,len); if (outpos + len < outbuflen) { memcpy(&outbuf[0][outpos],in[0],sizeof(sample_t) * len); outpos += len; } else { // Wrap case- byte-by-byte nframes_t n; sample_t *o_l = outbuf[0]; for (n = 0; outpos < outbuflen; outpos++, n++) o_l[outpos] = b_l[n]; outpos = 0; wrap = 1; for (; n < len; outpos++, n++) o_l[outpos] = b_l[n]; } } } }; void FileStreamer::ReceiveEvent(Event *ev, EventProducer */*from*/) { switch (ev->GetType()) { case T_EV_PulseSync : // Called because of downbeat // Record the beat if (timingfd != 0) { nbeats++; marks[mkwriteidx].markofs = app->getRP()->GetSampleCnt()-startcnt; marks[mkwriteidx].data = nbeats; mkwriteidx++; if (mkwriteidx >= MARKERBUFLEN) mkwriteidx = 0; } break; default: break; } }; void *FileStreamer::run_encode_thread (void *ptr) { FileStreamer *inst = static_cast(ptr); nframes_t curpos; // *** Could FileStreamer be rewritten as a BlockManager, using the // BMG manage thread? It could still be a core DSP processor, no? while (inst->threadgo || inst->writerstatus != STATUS_STOPPED) { switch (inst->writerstatus) { case STATUS_RUNNING: // We're running, so feed data to the chosen audio encoder. // Make a local copy of outpos-- because it is liable to change // during this loop!-- RT thread curpos = inst->outpos; if (curpos != inst->encodepos) { nframes_t num; if (inst->wrap) { // Wrap case- so take from the end & beginning of circular buffer nframes_t numend = inst->outbuflen - inst->encodepos; num = curpos + numend; if (numend > 0) { inst->outputsize += inst->enc->WriteSamplesToDisk (inst->outbuf, inst->encodepos, numend); } if (curpos > 0) { inst->outputsize += inst->enc->WriteSamplesToDisk (inst->outbuf, 0, curpos); } inst->wrap = 0; } else { if (curpos > inst->encodepos) { num = curpos - inst->encodepos; inst->outputsize += inst->enc->WriteSamplesToDisk (inst->outbuf, inst->encodepos, num); } else { // Wrap not set but buffer seems wrapped- this could be caused // by extreme processor load and this thread not keeping up with // RT- print warning printf("DISK: WARNING: FileStreamer Buffer wrap possible?\n"); } } inst->encodepos = curpos; } // Now dump markers to gnusound USX for later edit points while (inst->mkreadidx != inst->mkwriteidx) { if (inst->timingfd != 0) fprintf(inst->timingfd,"%ld=4 0 0.000000 lb%d\n", (long int) inst->marks[inst->mkreadidx].markofs, (int) inst->marks[inst->mkreadidx].data); inst->mkreadidx++; if (inst->mkreadidx >= MARKERBUFLEN) inst->mkreadidx = 0; } break; case STATUS_START_PENDING: // Open output file // printf("DISK: Open output file.\n"); inst->outfd = fopen(inst->outname.c_str(),"wb"); if (inst->write_timing) inst->timingfd = fopen(inst->timingname.c_str(),"wb"); else inst->timingfd = 0; if (inst->outfd != 0) { // Setup vorbis lib printf("DISK: Initialize streamer.\n"); inst->InitStreamer(); if (inst->timingfd) { // Write header block for GNUSound fprintf(inst->timingfd, "[Mixer]\n" "0=1.000000\n" "1=1.000000\n" "Source Is Mute=0\n" "Source Is Solo=0\n\n" "[Markers for track 0]\n"); } // Setup beat counting inst->nbeats = 0; inst->mkwriteidx = 0; inst->mkreadidx = 0; // Notify us on ALL pulse beats... we will stripe them all! inst->app->getEMG()->ListenEvent(inst,0,T_EV_PulseSync); // Set encoder to dump to file we have opened inst->enc->SetupFileForWriting(inst->outfd); inst->outputsize = 0; inst->outpos = 0; inst->encodepos = 0; inst->wrap = 0; inst->startcnt = inst->app->getRP()->GetSampleCnt(); inst->writerstatus = STATUS_RUNNING; // printf("DISK: Streamer encoding.\n"); } else { printf("DISK: Error writing output file.\n"); if (inst->outfd != 0) fclose(inst->outfd); if (inst->timingfd != 0) fclose(inst->timingfd); inst->writerstatus = STATUS_STOPPED; inst->timingfd = 0; inst->outname = ""; inst->timingname = ""; inst->app->FlushStreamOutName(); } break; case STATUS_STOP_PENDING: printf("DISK: Closing streamer.\n"); // Tell encoder we are stopping inst->enc->PrepareFileForClosing(); // Now end inst->EndStreamer(); // Stop notify on ALL pulse beats. inst->app->getEMG()->UnlistenEvent(inst,0,T_EV_PulseSync); fclose(inst->outfd); if (inst->timingfd != 0) { fclose(inst->timingfd); inst->timingfd = 0; } printf("DISK: ..done\n"); inst->writerstatus = STATUS_STOPPED; inst->outname = ""; inst->timingname = ""; break; } // 100 ms delay between encoding cycles- give other processes a go! usleep(100000); } return 0; }; PassthroughProcessor::PassthroughProcessor(Fweelin *app, InputSettings *iset, float *inputvol) : Processor(app), iset(iset), inputvol(inputvol) { // Create input settings for all inputs set alliset = new InputSettings(app,app->getABUFS()->numins); }; PassthroughProcessor::~PassthroughProcessor() { delete alliset; // printf(" :: Processor: PassthroughProcessor end\n"); }; void PassthroughProcessor::process(char pre, nframes_t len, AudioBuffers *ab) { nframes_t fragmentsize = app->getBUFSZ(); if (len > fragmentsize) len = fragmentsize; // Single output hack sample_t *out[2] = {ab->outs[0][0], ab->outs[1][0]}; if (!pre) { // *** // This part could be optimized out of RT // Copy current input settings *alliset = *iset; // And only mix inputs that are set to monitor for (int i = 0; i < alliset->numins; i++) alliset->selins[i] = app->getCFG()->IsInputMonitoring(i); // *** // Mix all inputs together into single output- this is a monitor mix ab->MixInputs(len,out,alliset,*inputvol,0); } else { memset(out[0],0,sizeof(sample_t) * len); if (out[1] != 0) memset(out[1],0,sizeof(sample_t) * len); } } void InputSettings::SetInputVol(int n, float vol, float logvol) { if (n >= 0 || n < numins) { if (vol >= 0.) invols[n] = vol; else if (logvol >= 0.) invols[n] = DB2LIN(AudioLevel::fader_to_dB(logvol, app->getCFG()->GetFaderMaxDB())); dinvols[n] = 1.0; } else { printf("CORE: InputSettings- input number %d not in range.\n",n); } } freewheeling-0.6.6/src/fweelin_core_dsp.h000066400000000000000000000716141370736313100204530ustar00rootroot00000000000000#ifndef __FWEELIN_CORE_DSP_H #define __FWEELIN_CORE_DSP_H /* Copyright 2004-2011 Jan Pekau This file is part of Freewheeling. Freewheeling is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. Freewheeling 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 Freewheeling. If not, see . */ #include #include #include "fweelin_core.h" #include "fweelin_event.h" #include "fweelin_block.h" #ifndef MIN #define MIN(a,b) ((a) < (b) ? (a) : (b)) #endif #ifndef MAX #define MAX(a,b) ((a) > (b) ? (a) : (b)) #endif extern int math_gcd (int a, int b); extern int math_lcm (int a, int b); // Macros for converting between linear amplitude and dB #define DB2LIN(db) (powf(10.0f, (db) * 0.05f)) #define LIN2DB(amp) (20.0f * log10f(amp)) class Fweelin; class Loop; class AudioBlock; class AudioBlockIterator; class PeaksAvgsManager; class TimeMarker; class InputSettings; class AudioLevel; // Class for converting between dB and vertical fader levels class AudioLevel { public: static float fader_to_dB (float level, float maxDb); static float dB_to_fader (float dB, float maxDb); }; // Audio buffers encapsulates all buffers going into & out of // a processor-- allowing for multiple ins and outs to be passed class AudioBuffers { public: AudioBuffers(Fweelin *app); ~AudioBuffers(); // Get input #n, left/mono (0) or right (1) channel inline sample_t *GetInput(int n, short channel) { return ins[channel][n]; }; // Get output #n, left/mono (0) or right (1) channel inline sample_t *GetOutput(int n, short channel) { return outs[channel][n]; }; // Get # of inputs/ouputs inline int GetNumInputs() { return numins; }; inline int GetNumOutputs() { return numouts; }; // Is input/output #n stereo? char IsStereoInput(int n); char IsStereoOutput(int n); // Is FreeWheeling running in stereo or completely in mono? char IsStereoMaster(); // Mixes the selected inputs to dest (array of 2 channels) void MixInputs (nframes_t len, sample_t **dest, InputSettings *iset, float inputvol, char compute_stats); // Get number of internal audio inputs into FreeWheeling static inline int GetIntAudioIns() { #if USE_FLUIDSYNTH return 1; #else return 0; #endif } // Number of audio outs static inline int GetAudioOuts() { return 1; }; Fweelin *app; // Main app int numins, // Total number of inputs (including internal Fluidsynth) numins_ext, // Number of external inputs (not including internal Fluidsynth) numouts; // & outs sample_t **ins[2], // 2 lists of input sample buffers (mono/left and right) **outs[2]; // & 2 lists of output sample buffers (mono/left and right) }; // Settings for each input coming into FreeWheeling // Now we can have multiple sets of settings & pass settings to recordprocessor. // This allows differen recordprocessors to record from different inputs. class InputSettings { public: InputSettings(Fweelin *app, int numins) : app(app), numins(numins) { selins = new char[numins]; invols = new float[numins]; dinvols = new float[numins]; insums[0] = new sample_t[numins]; insums[1] = new sample_t[numins]; insavg[0] = new sample_t[numins]; insavg[1] = new sample_t[numins]; inpeak = new sample_t[numins]; inpeaktime = new nframes_t[numins]; inscnt = new int[numins]; // Start with all inputs selected, and default volumes! for (int i = 0; i < numins; i++) { selins[i] = 1; invols[i] = 1.0; dinvols[i] = 1.0; insums[0][i] = 0.0; insums[1][i] = 0.0; insavg[0][i] = 0.0; insavg[1][i] = 0.0; inpeak[i] = 0.0; inpeaktime[i] = 0; inscnt[i] = 0; } }; ~InputSettings() { delete[] selins; delete[] invols; delete[] dinvols; delete[] insums[0]; delete[] insums[1]; delete[] insavg[0]; delete[] insavg[1]; delete[] inpeak; delete[] inpeaktime; delete[] inscnt; }; // (de)Select input inline void SelectInput(int n, char selected) { if (n >= 0 || n < numins) { selins[n] = selected; } else { printf("CORE: InputSettings- input number %d not in range.\n",n); } }; // Is input n selected? inline char InputSelected(int n) { if (n >= 0 || n < numins) { return selins[n]; } else { printf("CORE: InputSettings- input number %d not in range.\n",n); return 0; } }; // Are any of the selected inputs stereo? char IsSelectedStereo(); // Set input volume for input n void AdjustInputVol(int n, float adjust); void SetInputVol(int n, float vol, float logvol); inline float GetInputVol(int n) { if (n >= 0 || n < numins) { return invols[n]; } else { printf("CORE: InputSettings- input number %d not in range.\n",n); return 0; } }; inline float *GetInputVols() { return invols; }; inline int GetNumInputs() { return numins; }; // Copy contents of settings from source object- don't fuss with pointers inline void operator = (InputSettings &src) { if (numins != src.numins) printf("CORE: InputSettings- number of inputs mismatch!\n"); else { memcpy(selins,src.selins,sizeof(char)*numins); memcpy(invols,src.invols,sizeof(float)*numins); memcpy(dinvols,src.dinvols,sizeof(float)*numins); memcpy(insums[0],src.insums[0],sizeof(sample_t)*numins); memcpy(insums[1],src.insums[1],sizeof(sample_t)*numins); memcpy(insavg[0],src.insavg[0],sizeof(sample_t)*numins); memcpy(insavg[1],src.insavg[1],sizeof(sample_t)*numins); memcpy(inpeak,src.inpeak,sizeof(sample_t)*numins); memcpy(inpeaktime,src.inpeaktime,sizeof(sample_t)*numins); memcpy(inscnt,src.inscnt,sizeof(int)*numins); } }; Fweelin *app; // Main app- we get a few variables from it int numins; // Number of inputs char *selins; // For each input, is it selected? float *invols, // For each input, what's the volume? *dinvols; // And the rate of volume change sample_t *insums[2], *insavg[2], *inpeak; nframes_t *inpeaktime; int *inscnt; }; enum SyncStateType { SS_NONE, SS_START, SS_BEAT, SS_END, SS_ENDED }; // Handles realtime DSP from a signal chain // *** Consider making this an RT allocated type-- // because right now, triggering loops actually allocates memory class Processor : public EventProducer { public: const static float MIN_VOL; const static nframes_t DEFAULT_SMOOTH_LENGTH; Processor(Fweelin *app); virtual ~Processor(); // Realtime process one fragment of audio-- process len samples- // { if pre is nonzero, preprocess len bytes ahead- // used for smoothing sudden changes-- don't actually // advance pointers } virtual void process(char /*pre*/, nframes_t len, AudioBuffers *ab) = 0; Fweelin *getAPP() { return app; }; // This is called by RootProcessor when a processor is flagged- // pending delete and should no longer perform any processing virtual void Halt() {}; void dopreprocess(); protected: // Fade together current with preprocessed to create a smoothed buffer void fadepreandcurrent(AudioBuffers *ab); // Parent Flo-Monkey app Fweelin *app; // Preprocessing audio buffers- store preprocessed output for // smoothing on control changes AudioBuffers *preab; nframes_t prelen; char prewritten, // Nonzero if a // preprocess has been written to buffers prewriting; // Nonzero if a // preprocess is being written to buffers }; // One processor in a linked list of processors class ProcessorItem { public: // Processor is running, or ready to be deleted const static int STATUS_GO = 0, // Running STATUS_LIVE_PENDING_DELETE = 1, // Call RT thread, then delete STATUS_PENDING_DELETE = 2; // Delete at next non-RT opportunity // Processor type- // // Global processors get their input from the external audio inputs. // They are executed near the end of the signal chain (after output volume transformation) // // Hipriority: these processors will process before all other processors // // Final processors will process after all other processors-- // after TYPE_GLOBAL // They will be fed the end signal chain of all other processors as input const static int TYPE_DEFAULT = 0, TYPE_GLOBAL = 1, TYPE_GLOBAL_SECOND_CHAIN = 2, TYPE_HIPRIORITY = 3, TYPE_FINAL = 4; ProcessorItem(Processor *p, int type = TYPE_DEFAULT, char silent = 0) : p(p), next(0), status(STATUS_GO), type(type), silent(silent) {}; Processor *p; ProcessorItem *next; int status, type; char silent; // Nonzero if this processor should always be silent (no output) }; class PulseSyncCallback { public: virtual void PulseSync (int syncidx, nframes_t actualpos) = 0; }; class PulseSync { public: PulseSync (PulseSyncCallback *cb = 0, nframes_t syncpos = 0) : cb(cb), syncpos(syncpos) {}; PulseSyncCallback *cb; // Callback instance nframes_t syncpos; // Position where to call back }; // Pulse defines a heartbeat for a piece // It keeps track of a constant period for tempo, as well as // the timing of the downbeat (current position in pulse) class Pulse : public Processor { public: // Length of metronome strike sound in samples const static nframes_t METRONOME_HIT_LEN; // Length of metronome tone sound in samples const static nframes_t METRONOME_TONE_LEN; // Initial metronome volume const static float METRONOME_INIT_VOL; // Maximum number of user-defined pulse sync callbacks const static int MAX_SYNC_POS = 1000; Pulse(Fweelin *app, nframes_t len, nframes_t startpos); ~Pulse(); inline float round(float num) { if (num-(long)num < 0.5) return floor(num); else return ceil(num); } virtual void process(char pre, nframes_t l, AudioBuffers *ab); inline char IsMetronomeActive() { return metroactive; }; inline void SwitchMetronome(char active) { metroactive = active; }; // Start/stop sending MIDI clock for this pulse void SetMIDIClock (char start); // Quantizes src length to fit to this pulse length nframes_t QuantizeLength(nframes_t src); // These methods add and remove sync positions. // A pulse sends out an RT PulseSync event whenever any of these // positions is reached. (RT Safe, but can only be called from one thread- RT audio thread) inline int AddPulseSync(PulseSyncCallback *cb, nframes_t pos) { // Returns sync index of new position // Check position if (pos >= len) { printf("PULSE: Sync position adjusted for really short loop " "(pos %d, len %d)\n",pos,len); pos = len-1; } // First, search for unfilled positions in our array int i = 0; while (i < numsyncpos && syncpos[i].cb != 0) i++; if (i < numsyncpos) { // Position found, use this index syncpos[i] = PulseSync(cb,pos); return i; } else { // No holes found, add to end of array if (numsyncpos >= MAX_SYNC_POS) { printf("PULSE: Too many sync positions.\n"); return -1; } else { int ret = numsyncpos; syncpos[numsyncpos++] = PulseSync(cb,pos); return ret; } } }; // Removes sync position at index syncidx (RT Safe, but can only be called from one thread- RT audio thread) inline void DelPulseSync (int syncidx) { if (syncidx < 0 || syncidx >= numsyncpos) printf("PULSE: Invalid sync position %d (0->%d).\n",syncidx,numsyncpos); else { if (syncidx+1 == numsyncpos) { // Position exists on the end of array- shrink syncpos[syncidx] = PulseSync(); numsyncpos--; } else // Position exists in the middle of the array- create a hole syncpos[syncidx] = PulseSync(); } }; // Returns nonzero if the wrapped bit is set-- which indicates // that the Meter has wrapped around to the beginning (downbeat) // in the last process frame inline char Wrapped() { if (wrapped) { wrapped = 0; return 1; } else return 0; } // Get current position in pulse in frames inline nframes_t GetPos() { return curpos; }; // Set current position of pulse in frames inline void SetPos(nframes_t pos) { curpos = pos; }; // Cause this pulse to wrap to its beginning, firing off any triggers // and producing a metronome pulse-- SetPos(0) does not do this inline void Wrap() { curpos = len; }; // Set length of pulse in frames inline void SetLength(nframes_t newlen) { len = newlen; }; // Get current position in % inline float GetPct() { return (float)curpos/len; }; // Returns length of pulse in frames inline nframes_t GetLength() { return len; }; inline int GetLongCount_Len() { return lc_len; }; inline int GetLongCount_Cur() { return lc_cur; }; inline float GetLongCount_CurPct() { return (float) lc_cur + GetPct(); }; int ExtendLongCount (long nbeats, char endjustify); void ResetLongCount() { lc_len = 1; }; nframes_t len, // Length of one revolution of this pulse in samples curpos; // Current position in samples into this pulse int lc_len, // Length of long count lc_cur; // Current position in long count char wrapped, // Wrapped? stopped; // Stopped? int prev_sync_bb, // Previous beat/bar from transport (used for slave sync) sync_cnt, // Number of external beats/bars that have elapsed since // this pulse has wrapped around prev_sync_speed; char prev_sync_type; double prevbpm; // Previous BPM from transport // Tap nframes_t prevtap; // samplecnt @ previous tap // Metronome sample_t *metro, // Sample data for metronome strike *metrohitone, // Metronome hi tone *metrolotone; // Metronome lo tone nframes_t metroofs, // Current position into metronome strike sample metrohiofs, // Current position into high metronome tone metroloofs, // Current position into low metronome tone metrolen, // Length of metronome strike sample metrotonelen; // Length of metronome hi/lo tone samples char metroactive; // Nonzero if metronome sound is active float metrovol; // Volume of metronome PulseSync syncpos[MAX_SYNC_POS]; // Sync positions int numsyncpos; // Current number of sync positions SyncStateType clockrun; // Status of MIDI clock }; // This class implements a quick auto limiter. // This design does not add latency to the output. It is not a brickwall or look-ahead design. // It cannot guarantee that no samples are clipped. // It is essentially a compressor with fast attack time. // // It is intended to prevent hard overdriving of the signal chain and potential damage to audio components. // It does produce some distortion when peaking. It is fairly musical and low on CPU usage. class AutoLimitProcessor : public Processor { friend class Fweelin; public: AutoLimitProcessor(Fweelin *app); virtual ~AutoLimitProcessor(); float GetLimiterVolume() { return curlimitvol; }; char GetLimiterFreeze() { return limiterfreeze; }; void SetLimiterFreeze(char set) { limiterfreeze = set; }; void ResetLimiter(); // This process function processes in place on the output. It does not read the input at all. virtual void process(char pre, nframes_t len, AudioBuffers *ab); private: const static float LIMITER_ATTACK_LENGTH, LIMITER_START_AMP; const static nframes_t LIMITER_ADJUST_PERIOD; float dlimitvol, // Limiter volume delta- how fast vol is being changed limitvol, // Target volume- amplitude needed to stop clipping curlimitvol, // Current volume- volume is moving towards limitvol maxvol; // Maximum volume found in audio coming into limiter char limiterfreeze; // Nonzero if limiter is frozen- no changes in amp }; // This is the base of signal processing tree- it connects to system level audio // and calls child processors which do signal processing // Child processes execute in parallel and their signals are summed class RootProcessor : public Processor, public EventListener { #define RP_QUEUE_SIZE 200 // Number of events that can be queued up here. Things like 'starting loops playing'. friend class Fweelin; public: RootProcessor(Fweelin *app, InputSettings *iset); virtual ~RootProcessor(); void AdjustOutputVolume(float adjust); void SetOutputVolume(float set) { // Preprocess audio for smoothing dopreprocess(); outputvol = set; doutputvol = 1.0; }; inline float GetOutputVolume() { return outputvol; } void AdjustInputVolume(float adjust); void SetInputVolume(float set) { // Preprocess audio for smoothing dopreprocess(); inputvol = set; dinputvol = 1.0; }; inline float GetInputVolume() { return inputvol; } inline float *GetInputVolumePtr() { return &inputvol; } // Sample accurate timing is provided through samplecnt inline nframes_t GetSampleCnt() { return samplecnt; }; // Process len frames through all child processors of type 'ptype', // passing abchild audio buffers to the processors and optionally mixing // into the main output buffers ab void processchain(char pre, nframes_t len, AudioBuffers *ab, AudioBuffers *abchild, const int ptype, const char mixintoout); virtual void process(char pre, nframes_t len, AudioBuffers *ab); // Adds a child processor.. the processor begins processing immediately // Possibly realtime safe? void AddChild (Processor *o, int type = ProcessorItem::TYPE_DEFAULT, char silent = 0); // Removes a child processor from receiving processing time.. // also, deletes the child processor // Realtime safe! void DelChild (Processor *o); // Create ring buffers once all threads are present void FinalPrep (); void ReceiveEvent(Event *ev, EventProducer */*from*/); private: // Update the list of processors void UpdateProcessors(); // Event queue (read in RT). Used to handle events in the RT audio thread, that are generated from multiple // writers in other threads. SRMWRingBuffer *eq; volatile char protect_plist; // Nonzero if the processor list is being read and SHOULD NOT be modified // Volumes- we are responsible for adjusting volumes in RT InputSettings *iset; float outputvol, doutputvol, // Delta output volume-- rate of change inputvol, dinputvol; // Delta input volume-- rate of change ProcessorItem *firstchild; // Temporary buffers for summing signals AudioBuffers *abtmp, *preabtmp; sample_t *buf[2], *prebuf[2]; // Count samples processed from start of execution volatile nframes_t samplecnt; }; class RecordProcessor : public Processor, public PulseSyncCallback { public: // Extra tail on record end facilitates smooth crossfade for // sync-recorded loops const static nframes_t REC_TAIL_LEN = 1024; const static float OVERDUB_DEFAULT_FEEDBACK; // Notes: // One caveat, since hipri mgrs have granularity of only one fragment // loop points are not sample accurate but to nearest fragment // but there will be no drift since meter is sample accurate // and it is syncronizing time // .. // Should RecordProcessor create loops instead of LoopManager? // .. // Recording into preexisting fixed size block RecordProcessor(Fweelin *app, InputSettings *iset, float *inputvol, AudioBlock *dest, int suggest_stereo = -1); // Overdubbing version of record into existing loop RecordProcessor(Fweelin *app, InputSettings *iset, float *inputvol, Loop *od_loop, float od_playvol, nframes_t od_startofs, float *od_feedback); // Pointer to value for feedback (can be continuously varied) // Recording new blocks, growing size as necessary RecordProcessor(Fweelin *app, InputSettings *iset, float *inputvol, Pulse *sync = 0, AudioBlock *audiomem = 0, AudioBlockIterator *audiomemi = 0, nframes_t peaksavgs_chunksize = 0); // Destructor- executed nonRT ~RecordProcessor(); virtual void process(char pre, nframes_t len, AudioBuffers *ab); // In Halt() method we ensure that no stray Pulse_Syncs will be responded to virtual void Halt() { stopped = 1; sync_state = SS_ENDED; }; virtual void PulseSync (int syncidx, nframes_t /*actualpos*/); // Sync up overdubbing of the loop to a newly created pulse void SyncUp(); nframes_t GetRecordedLength(); AudioBlock *GetFirstRecordedBlock() { return recblk; } PeaksAvgsManager *GetPAMgr() { return pa_mgr; } // Is this an overdub record (1) or a fresh record (0)? char IsOverdub() { return (od_loop != 0); }; long GetNBeats() { return nbeats; }; // End this recording- if we are syncronized to an external pulse, // then we adjust recording end time as necessary void End(); // Stops recording now-- RT safe! void EndNow(); // Abort recording-- free memory associated with all audio blocks void AbortRecording(); // Fades input samples out of mix- writing to 'dest' void FadeOut_Input(nframes_t len, sample_t *input_l, sample_t *input_r, sample_t *loop_l, sample_t *loop_r, float old_fb, float /*new_fb*/, float fb_delta, sample_t *dest_l, sample_t *dest_r); // Fades input samples into mix- writing to 'dest' void FadeIn_Input(nframes_t len, sample_t *input_l, sample_t *input_r, sample_t *loop_l, sample_t *loop_r, float old_fb, float /*new_fb*/, float fb_delta, sample_t *dest_l, sample_t *dest_r); // Jumps to a position within an overdubbing loop- fade of input & output void Jump(nframes_t ofs); void SetODPlayVol(float newvol) { // Preprocess audio for smoothing dopreprocess(); od_playvol = newvol; } float GetODPlayVol() { return od_playvol; } AudioBlockIterator *GetIterator() { return i; }; Pulse *GetPulse() { return sync; }; SyncStateType sync_state; // Are we waiting for a downbeat, running, ended? // Recording in stereo? char stereo; // Which inputs to record from and at what volumes? InputSettings *iset; float *inputvol; // Pointer to overall input volume- can change during record sample_t *mbuf[2]; // Mixed input buffers // Pulse to syncronize (quantize) record to Pulse *sync; // Iterator with current record position, and temporary iterator AudioBlockIterator *i, *tmpi; // Block to record into AudioBlock *recblk; // (Syncrec) Number of beat triggers passed in this recording long nbeats; int endsyncidx; // Pulse sync index for delayed end-of-record char endsyncwait; // Are we waiting for a delayed end-of-record? int sync_idx; // Index of sync callback added (or -1 if none is being used) nframes_t sync_add_pos; // Position in pulse where to add sync callback char sync_add; // RT thread should call AddPulseSync to let pulse know we are waiting for a sync callback char stopped, growchain, // Nonzero if we should grow the chain of blocks-- // Zero if record is fixed length compute_stats; // Nonzero if we should compute stats like DC offset, // sums & peaks for InputSettings // Manager for peaks & averages computation alongside this record PeaksAvgsManager *pa_mgr; // Overdub settings Loop *od_loop; float od_playvol, *od_feedback, od_feedback_lastval; // Last value for feedback- used to determine delta, to remove // zipper noise long od_curbeat; // Current beat in od_loop char od_fadein, od_fadeout, od_stop, // Fade in overdub, fade out overdub, // and stop overdub flags od_prefadeout; // Overdub, preprocess fadeout nframes_t od_lastofs; // Last position of record sample_t *od_last_mbuf[2], // Copy of last mixed input buffers *od_last_lpbuf[2]; // Copy of last loop buffers }; class PlayProcessor : public Processor, public PulseSyncCallback { public: PlayProcessor(Fweelin *app, Loop *playloop, float playvol, nframes_t startofs = 0); virtual ~PlayProcessor(); // Sync up playing of the loop to a newly created pulse void SyncUp(); virtual void process(char pre, nframes_t len, AudioBuffers *ab); virtual void PulseSync (int /*syncidx*/, nframes_t /*actualpos*/); nframes_t GetPlayedLength(); void SetPlayVol(float newvol) { // Preprocess audio for smoothing dopreprocess(); playvol = newvol; } float GetPlayVol() { return playvol; } // In Halt() method we ensure that no stray Pulse_Syncs will be responded to virtual void Halt() { stopped = 1; sync_state = SS_ENDED; }; SyncStateType sync_state; // Are we waiting for a downbeat, running, ended? // Pulse to syncronize (quantize) play to Pulse *sync; int sync_idx; // Index of sync callback added (or -1 if none is being used) nframes_t sync_add_pos; // Position in pulse where to add sync callback char sync_add; // RT thread should call AddPulseSync to let pulse know we are waiting for a sync callback // Playing in stereo? char stereo; // Stop- pause for right place to start char stopped; AudioBlockIterator *i; Loop *playloop; float playvol; long curbeat; }; class FileStreamer : public Processor, public EventListener { public: const static nframes_t OUTPUTBUFLEN = 100000; const static int MARKERBUFLEN = 50; // Initialize a disk stream recording input #input_idx, with the given buffer size FileStreamer(Fweelin *app, int input_idx, char stereo, nframes_t outbuflen = OUTPUTBUFLEN); virtual ~FileStreamer(); virtual void process(char pre, nframes_t len, AudioBuffers *ab); virtual void ReceiveEvent(Event *ev, EventProducer */*from*/); // Starts writing to a new audio stream // Note all the heavy work is done in the encode thread! int StartWriting(const std::string &filename_stub, const char *stream_type_name, char write_timing, codec type); // Stop writing to a stream // Note all the heavy work is done in the encode thread! void StopWriting() { writerstatus = STATUS_STOP_PENDING; }; char GetStatus() { return writerstatus; }; const std::string &GetOutputName() { return outname; }; // Returns the number of *frames* written so far-- not bytes // The actual file size will vary depending on the codec used long int GetOutputSize() { return outputsize; }; static void *run_encode_thread (void *ptr); // Writer status flags const static char STATUS_STOPPED = 0, STATUS_RUNNING = 1, STATUS_STOP_PENDING = 2, STATUS_START_PENDING = 3; private: void InitStreamer(); void EndStreamer(); char writerstatus; // Status flag int input_idx; // Index of input to record char stereo; // Encoding in stereo? codec filetype; // Audio file type // File FILE *outfd, // Current output filedescriptor (audio) *timingfd; // Current timing output filedescriptor (data- USX) std::string outname, // Current output filename timingname; // Current timing output filename char write_timing; // Nonzero if a timing file is being written by this streamer // Time markers for storing downbeat points along with audio (ring buffer) TimeMarker *marks; volatile int mkwriteidx, mkreadidx; // Number of beat triggers passed in this recording long nbeats; // Global sample count at start of stream file nframes_t startcnt; // Output buffers sample_t *outbuf[2]; // Two channel ring buffer nframes_t outbuflen; volatile nframes_t outpos, // Current position of realtime data coming into output buffer encodepos; // Current position of encoder in buffer (lags behind outpos) char wrap; // Nonzero if outpos has wrapped but encodepos hasn't yet // Number of bytes written to output file long int outputsize; // Disk encode/disk write thread pthread_t encode_thread; int threadgo; // Encoder iFileEncoder *enc; }; // PassthroughProcessor creates a monitor mix of several given inputs into one output class PassthroughProcessor : public Processor { public: PassthroughProcessor(Fweelin *app, InputSettings *iset, float *inputvol); virtual ~PassthroughProcessor(); virtual void process(char pre, nframes_t len, AudioBuffers *ab); // Input settings with all inputs selected- to create monitor mix InputSettings *alliset, *iset; // Pointer to outside input settings from which levels will be taken float *inputvol; // Pointer to overall input volume- can change }; #endif freewheeling-0.6.6/src/fweelin_datatypes.cc000066400000000000000000000032031370736313100207760ustar00rootroot00000000000000/* To change the world, I aspire to perceive it differently. */ /* Copyright 2004-2011 Jan Pekau This file is part of Freewheeling. Freewheeling is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. Freewheeling 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 Freewheeling. If not, see . */ #include #include #include #include #include #include #include #include #include #include #include "fweelin_datatypes.h" int RT_RWThreads::num_rw_threads = 0; pthread_t RT_RWThreads::ids[MAX_RW_THREADS]; pthread_mutex_t RT_RWThreads::register_rw_lock; int RT_RWThreads::num_rt_structs = 0; RTDataStruct_Updater *RT_RWThreads::rtsructs[MAX_RT_STRUCTS]; pthread_mutex_t RT_RWThreads::register_rtstruct_lock; CoreDataType GetCoreDataType(char *name) { if (!strcmp(name, "char")) return T_char; else if (!strcmp(name, "int")) return T_int; else if (!strcmp(name, "long")) return T_long; else if (!strcmp(name, "float")) return T_float; else if (!strcmp(name, "range")) return T_range; else return T_invalid; }; freewheeling-0.6.6/src/fweelin_datatypes.h000066400000000000000000000657271370736313100206630ustar00rootroot00000000000000#ifndef __FWEELIN_DATATYPES_H #define __FWEELIN_DATATYPES_H /* Copyright 2004-2011 Jan Pekau This file is part of Freewheeling. Freewheeling is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. Freewheeling 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 Freewheeling. If not, see . */ #include #include enum CoreDataType { T_char, T_int, T_long, T_float, T_range, T_variable, T_variableref, T_invalid }; CoreDataType GetCoreDataType(char *name); class Range { public: Range(int lo, int hi) : lo(lo), hi(hi) {}; int lo, hi; }; // Flexible data type configuration variable- // Used in parsing and evaluating expressions from config file #define CFG_VAR_SIZE 16 // Number of data bytes in one variable class UserVariable { public: UserVariable() : name(0), type(T_invalid), value(data), next(0) {}; ~UserVariable() { if (name != 0) delete[] name; }; // Ensures that the precision of this variable is at least that of src // If not, reconfigures this variable to match src.. // For ex, if this is T_char and src is T_float, this becomes T_float void RaisePrecision (UserVariable &src) { switch (src.type) { case T_char : break; case T_int : if (type == T_char) { int tmp = (int) *this; type = T_int; *this = tmp; } break; case T_long : if (type == T_char || type == T_int) { long tmp = (long) *this; type = T_long; *this = tmp; } break; case T_float : if (type == T_char || type == T_int || type == T_long) { float tmp = (float) *this; type = T_float; *this = tmp; } break; default : break; } }; char operator > (UserVariable &cmp) { RaisePrecision(cmp); // Comparing ranges yields undefined results if (type == T_range || cmp.type == T_range) return 0; switch (type) { case T_char : return (*((char *) value) > (char) cmp); case T_int : return (*((int *) value) > (int) cmp); case T_long : return (*((long *) value) > (long) cmp); case T_float : return (*((float *) value) > (float) cmp); case T_variable : case T_variableref : printf(" UserVariable: WARNING: Compare T_variable or T_variableref " " not implemented!\n"); return 0; case T_range : printf(" UserVariable: WARNING: Can't compare range variable!\n"); return 0; case T_invalid : printf(" UserVariable: WARNING: Can't compare invalid variable!\n"); return 0; } return 0; }; char operator == (UserVariable &cmp) { RaisePrecision(cmp); // Special case if one variable is range and one is scalar-- then // we check if the scalar is within the range if (type == T_range && cmp.type != T_range) { int v = (int) cmp; Range r(*((int *) value),*(((int *) value)+1)); return (v >= r.lo && v <= r.hi); } if (cmp.type == T_range && type != T_range) { int v = (int) *this; Range r(*((int *) cmp.value),*(((int *) cmp.value)+1)); return (v >= r.lo && v <= r.hi); } switch (type) { case T_char : return (*((char *) value) == (char) cmp); case T_int : return (*((int *) value) == (int) cmp); case T_long : return (*((long *) value) == (long) cmp); case T_float : return (*((float *) value) == (float) cmp); case T_range : { Range r = (Range) cmp; return (*((int *) value) == r.lo && *(((int *) value)+1) == r.hi); } case T_variable : case T_variableref : printf(" UserVariable: WARNING: Compare T_variable or T_variableref " " not implemented!\n"); return 0; case T_invalid : printf(" UserVariable: WARNING: Can't compare invalid variable!\n"); return 0; } return 0; }; char operator != (UserVariable &cmp) { return !(operator == (cmp)); }; void operator += (UserVariable &src) { RaisePrecision(src); switch (type) { case T_char : *((char *) value) += (char) src; break; case T_int : *((int *) value) += (int) src; break; case T_long : *((long *) value) += (long) src; break; case T_float : *((float *) value) += (float) src; break; case T_range : { Range r = (Range) src; *((int *) value) += r.lo; *(((int *) value)+1) += r.hi; } break; case T_variable : case T_variableref : printf(" UserVariable: WARNING: Algebra on T_variable or T_variableref " " not possible!\n"); break; case T_invalid : printf(" UserVariable: WARNING: Can't operate on invalid variable!\n"); break; } }; // Return the absolute value of the difference (delta) between this variable and arg UserVariable GetDelta (UserVariable &arg) { UserVariable ret; ret.type = T_char; ret.RaisePrecision(*this); ret.RaisePrecision(arg); switch (ret.type) { case T_char : ret = (char) abs((char) arg - (char) *this); break; case T_int : ret = (int) abs((int) arg - (int) *this); break; case T_long : ret = (long) labs((long) arg - (long) *this); break; case T_float : ret = (float) fabsf((float) arg - (float) *this); break; default : printf(" UserVariable: WARNING: GetDelta() doesn't work on this type of variable!\n"); break; } return ret; }; void operator -= (UserVariable &src) { RaisePrecision(src); switch (type) { case T_char : *((char *) value) -= (char) src; break; case T_int : *((int *) value) -= (int) src; break; case T_long : *((long *) value) -= (long) src; break; case T_float : *((float *) value) -= (float) src; break; case T_range : { Range r = (Range) src; *((int *) value) -= r.lo; *(((int *) value)+1) -= r.hi; } break; case T_variable : case T_variableref : printf(" UserVariable: WARNING: Algebra on T_variable or T_variableref " " not possible!\n"); break; case T_invalid : printf(" UserVariable: WARNING: Can't operate on invalid variable!\n"); break; } }; void operator *= (UserVariable &src) { RaisePrecision(src); switch (type) { case T_char : *((char *) value) *= (char) src; break; case T_int : *((int *) value) *= (int) src; break; case T_long : *((long *) value) *= (long) src; break; case T_float : *((float *) value) *= (float) src; break; case T_range : { Range r = (Range) src; *((int *) value) *= r.lo; *(((int *) value)+1) *= r.hi; } break; case T_variable : case T_variableref : printf(" UserVariable: WARNING: Algebra on T_variable or T_variableref " " not possible!\n"); break; case T_invalid : printf(" UserVariable: WARNING: Can't operate on invalid variable!\n"); break; } }; void operator /= (UserVariable &src) { switch (type) { case T_char : case T_int : case T_long : case T_float : { // Special case- when dividing a scalar by another scalar, the // result is always evaluated to a float!! float t = (float) src; // Convert this variable to a float if (t != 0) { *((float *) value) = (float) *this / t; type = T_float; } } break; case T_range : { Range r = (Range) src; if (r.lo != 0) *((int *) value) /= r.lo; if (r.hi != 0) *(((int *) value)+1) /= r.hi; } break; case T_variable : case T_variableref : printf(" UserVariable: WARNING: Algebra on T_variable or T_variableref " " not possible!\n"); break; case T_invalid : printf(" UserVariable: WARNING: Can't operate on invalid variable!\n"); break; } }; UserVariable & operator = (char src) { *((char *) value) = src; return *this; }; UserVariable & operator = (int src) { *((int *) value) = src; return *this; }; UserVariable & operator = (long src) { *((long *) value) = src; return *this; }; UserVariable & operator = (float src) { *((float *) value) = src; return *this; }; UserVariable & operator = (Range src) { *((int *) value) = src.lo; *(((int *) value)+1) = src.hi; return *this; }; operator char () { switch (type) { case T_char : return *((char *) value); case T_int : return (char) *((int *) value); case T_long : return (char) *((long *) value); case T_float : return (char) *((float *) value); case T_range : printf(" UserVariable: WARNING: Can't convert range to scalar!\n"); return 0; case T_variable : case T_variableref : printf(" UserVariable: WARNING: Can't convert T_variable or " "T_variableref!\n"); return 0; case T_invalid : printf(" UserVariable: WARNING: Can't convert invalid variable!\n"); return 0; } return 0; }; operator int () { switch (type) { case T_char : return (int) *((char *) value); case T_int : return *((int *) value); case T_long : return (int) *((long *) value); case T_float : return (int) *((float *) value); case T_range : printf(" UserVariable: WARNING: Can't convert range to scalar!\n"); return 0; case T_variable : case T_variableref : printf(" UserVariable: WARNING: Can't convert T_variable or " "T_variableref!\n"); return 0; case T_invalid : printf(" UserVariable: WARNING: Can't convert invalid variable!\n"); return 0; } return 0; }; operator long () { switch (type) { case T_char : return (long) *((char *) value); case T_int : return (long) *((int *) value); case T_long : return *((long *) value); case T_float : return (long) *((float *) value); case T_range : printf(" UserVariable: WARNING: Can't convert range to scalar!\n"); return 0; case T_variable : case T_variableref : printf(" UserVariable: WARNING: Can't convert T_variable or " "T_variableref!\n"); return 0; case T_invalid : printf(" UserVariable: WARNING: Can't convert invalid variable!\n"); return 0; } return 0; }; operator float () { switch (type) { case T_char : return (float) *((char *) value); case T_int : return (float) *((int *) value); case T_long : return (float) *((long *) value); case T_float : return *((float *) value); case T_range : printf(" UserVariable: WARNING: Can't convert range to scalar!\n"); return 0; case T_variable : case T_variableref : printf(" UserVariable: WARNING: Can't convert T_variable or " "T_variableref!\n"); return 0; case T_invalid : printf(" UserVariable: WARNING: Can't convert invalid variable!\n"); return 0; } return 0; }; operator Range () { switch (type) { case T_char : return Range( *((char *) value), *((char *) value )); case T_int : return Range( *((int *) value), *((int *) value )); case T_long : return Range( *((long *) value), *((long *) value )); case T_float : return Range((int) *((float *) value), (int) *((float *) value )); case T_range : return Range( *((int *) value), *(((int *) value)+1)); case T_variable : case T_variableref : printf(" UserVariable: WARNING: Can't convert T_variable or " "T_variableref!\n"); return Range(0,0); case T_invalid : printf(" UserVariable: WARNING: Can't convert invalid variable!\n"); return Range(0,0); default: assert(0); } return Range(0,0); }; void operator = (UserVariable &src) { // Assignment operator does not copy name to avoid memory alloc // problems type = src.type; memcpy(data,src.data,CFG_VAR_SIZE); if (src.value == src.data) value = data; else value = src.value; // System variable, copy data ptr directly }; // Sets this UserVariable from src, converting from src type to this void SetFrom(UserVariable &src) { switch (type) { case T_char : *this = (char) src; break; case T_int : *this = (int) src; break; case T_long : *this = (long) src; break; case T_float : *this = (float) src; break; case T_range : *this = (Range) src; break; case T_variable : case T_variableref : case T_invalid : printf(" UserVariable: WARNING: Can't set from invalid variable!\n"); break; } } // Dump UserVariable to string str (maxlen is maximum length) // or stdout if str = 0 void Print(char *str = 0, int maxlen = 0); inline char IsSystemVariable() { return (value != data); }; inline char *GetValue() { return value; }; // Returns the raw data bytes for the value of this variable inline CoreDataType GetType() { return type; }; inline char *GetName() { return name; }; char *name; CoreDataType type; char data[CFG_VAR_SIZE] = {}; // System variables are a special type of variable that is created by the // core FreeWheeling system and not the user. // // A system variable is essentially a pointer to an internal data value // inside FreeWheeling. It can be read by the configuration system like // any other user variable, but it accesses directly into FreeWheeling's // internal memory and so it has a mind of its own // // If value points to the data array, this is a user variable // If value does not point to data, this is a system variable char *value; UserVariable *next; }; // Abstract class to allow updating RT data structures with a new # of reader and writer threads class RTDataStruct_Updater { friend class RT_RWThreads; protected: virtual void UpdateNumRWThreads(int new_num_writers) = 0; }; // Certain RT data structures require info about which threads read or write to them // This allows them to be lock-free while stile protecting the data from race conditions. // // This class holds data about all reader and writer threads for all RT data structures // Note that this is global. RT structures may contain extra protections for threads that // are not actually used for reading/writing to that structure. class RT_RWThreads { template friend class SRMWRingBuffer; friend class RT_RCU; public: #define MAX_RW_THREADS 50 // Hard-wired maximum number of reader and writer threads #define MAX_RT_STRUCTS 20 // System-wide total number of RT data structures allowed // Global prep methods static void InitAll() { pthread_mutex_init(®ister_rw_lock,0); pthread_mutex_init(®ister_rtstruct_lock,0); num_rw_threads = 0; num_rt_structs = 0; }; static void CloseAll() { pthread_mutex_destroy(®ister_rw_lock); pthread_mutex_destroy(®ister_rtstruct_lock); num_rw_threads = 0; num_rt_structs = 0; }; // Registration of reader/ writer threads // Register a given thread as a writer static void RegisterReaderOrWriter (pthread_t id) { pthread_mutex_lock (®ister_rw_lock); if (num_rw_threads >= MAX_RW_THREADS) { printf("CORE: ERROR: Too many writer threads for Ring Buffer!\n"); exit(1); } printf("CORE: Register ringbuffer writer thread: %lu\n",id); ids[num_rw_threads] = id; num_rw_threads++; pthread_mutex_unlock (®ister_rw_lock); // Update existing buffers with new writer thread UpdateRTStructs(); }; // Registers this thread as a writer static void RegisterReaderOrWriter () { pthread_mutex_lock (®ister_rw_lock); if (num_rw_threads >= MAX_RW_THREADS) { printf("CORE: ERROR: Too many writer threads for Ring Buffer!\n"); exit(1); } printf("CORE: Register ringbuffer writer thread: %lu\n",pthread_self()); ids[num_rw_threads] = pthread_self(); num_rw_threads++; pthread_mutex_unlock (®ister_rw_lock); // Update existing buffers with new writer thread UpdateRTStructs(); }; // RT data structures are automatically registered and unregistered here. // This allows them to be notified of additional reader or writer threads that are starting later. // This is important during initialization if RT data structures need to be created before all // threads that read or write to them are initialized. static void RegisterRTDataStruct (RTDataStruct_Updater *r) { pthread_mutex_lock (®ister_rtstruct_lock); if (num_rt_structs >= MAX_RT_STRUCTS) { printf("CORE: ERROR: Too many ring buffers!\n"); exit(1); } printf("CORE: Register ringbuffer #%d: %p\n",num_rt_structs,r); rtsructs[num_rt_structs] = r; num_rt_structs++; pthread_mutex_unlock (®ister_rtstruct_lock); }; static void UnregisterRTDataStruct (RTDataStruct_Updater *r) { pthread_mutex_lock (®ister_rtstruct_lock); char done = 0; for (int i = 0; i < num_rt_structs; i++) if (rtsructs[i] == r) { printf("CORE: Unregister ringbuffer #%d: %p\n",i,r); rtsructs[i] = 0; done = 1; } if (!done) printf("CORE: ERROR: Could not find ringbuffer %p to unregister.\n",r); pthread_mutex_unlock (®ister_rtstruct_lock); }; private: static void UpdateRTStructs() { // Notify every RT data struct of a new reader / writer thread pthread_mutex_lock (®ister_rtstruct_lock); for (int i = 0; i < num_rt_structs; i++) if (rtsructs[i] != 0) rtsructs[i]->UpdateNumRWThreads(num_rw_threads); pthread_mutex_unlock (®ister_rtstruct_lock); }; static int num_rw_threads; // Number of reader and writer threads registered static pthread_t ids[MAX_RW_THREADS]; // Thread ID for each reader / writer static pthread_mutex_t register_rw_lock; static int num_rt_structs; // Number of RT data structures in the system static RTDataStruct_Updater *rtsructs[MAX_RT_STRUCTS]; // Array of pointers to RT data structure updaters static pthread_mutex_t register_rtstruct_lock; }; // Ringbuffer implementation for a Single Reader Thread & Multiple Writer Threads // // This expands to a set of ringbuffers- one for each writer thread. The order of elements between threads is not preserved. // Elements are written and read using COPY operations. // // NOTE: Writer threads should not be added and removed once multithreaded operation has begun. // New writer threads may be registered after the ringbuffer is created, but only while that RingBuffer // is being written to by a single thread (ie during a single initialization thread). // // Class T must be able to be assigned to a null integer. // If class T is a pointer, no problem. // If class T is an instance, you must provide an initializer accepting an integer. template class SRMWRingBuffer : public RTDataStruct_Updater { friend class RT_RWThreads; public: // Create a ringbuffer with numel elements of class T SRMWRingBuffer (int numel) : numel(numel), num_writers(RT_RWThreads::num_rw_threads) { wbufs = new jack_ringbuffer_t *[MAX_RW_THREADS]; for (int i = 0; i < num_writers; i++) wbufs[i] = jack_ringbuffer_create(sizeof(T) * numel); // Register this ringbuf RT_RWThreads::RegisterRTDataStruct(this); }; virtual ~SRMWRingBuffer() { // Unregister this ringbuf RT_RWThreads::UnregisterRTDataStruct(this); for (int i = 0; i < num_writers; i++) jack_ringbuffer_free(wbufs[i]); delete[] wbufs; }; // Instance methods int WriteElement (const T &el) { if (num_writers != RT_RWThreads::num_rw_threads) { pthread_mutex_lock(&RT_RWThreads::register_rtstruct_lock); pthread_mutex_unlock(&RT_RWThreads::register_rtstruct_lock); if (num_writers != RT_RWThreads::num_rw_threads) { printf("CORE: ERROR: SRMWRingBuffer thread count mismatch.\n"); exit(1); } } // Determine which write thread we are pthread_t id = pthread_self(); for (int i = 0; i < num_writers; i++) if (pthread_equal(id,RT_RWThreads::ids[i])) { // Write to the appropriate ringbuf if (jack_ringbuffer_write(wbufs[i],(const char *) &el,sizeof(T)) < sizeof(T)) { printf("CORE: No space in RingBuffer for element\n"); return -1; } else return 0; } printf("CORE: RingBuffer write from unregistered write thread: %lu!\n",id); return -1; }; const T ReadElement () { if (num_writers != RT_RWThreads::num_rw_threads) { pthread_mutex_lock(&RT_RWThreads::register_rtstruct_lock); pthread_mutex_unlock(&RT_RWThreads::register_rtstruct_lock); if (num_writers != RT_RWThreads::num_rw_threads) { printf("CORE: ERROR: SRMWRingBuffer thread count mismatch.\n"); exit(1); } } // Check each ring buffer for (int i = 0; i < num_writers; i++) { size_t avail = jack_ringbuffer_read_space(wbufs[i]); if (avail >= sizeof(T)) { // Read element here if (jack_ringbuffer_read(wbufs[i],(char *) &tmpread,sizeof(T)) != sizeof(T)) { printf("CORE: Size mismatch during RingBuffer read\n"); exit(1); } else { // printf("CORE: Ringbuf got item\n"); return tmpread; } } } // No data available // printf("CORE: Ringbuf empty\n"); return 0; }; private: virtual void UpdateNumRWThreads(int new_num_rw_threads) { printf("CORE: RingBuffer %p: Update reader and writer threads to %d\n",this,new_num_rw_threads); if (new_num_rw_threads <= num_writers) { printf("CORE: ERROR: Can't go from %d to %d threads during initialization.\n",num_writers, new_num_rw_threads); exit(1); } else { for (; num_writers < new_num_rw_threads; num_writers++) wbufs[num_writers] = jack_ringbuffer_create(sizeof(T) * numel); } }; // Array of single-read single-write ring buffers: one for each writer thread jack_ringbuffer_t **wbufs; int numel, // Number of elements of class T in the buffer num_writers; // Local copy of RT_RWThreads::num_rw_threads T tmpread; // Holding spot for read }; // An RTStore is the concept of a store shelf stocked with cans of something (class T) // The store shelf has a number of items. Each item has a state. The state can be compared and swapped // atomically. This allows several threads to work together without locks, stocking and pulling items // from the shelf. // // RTStore does not care about the content of class T. It does not care about the cans. // It only cares about managing the state of each item on the shelf in a thread-safe, RT-safe way. // // This design pattern is used in the memory manager classes (fweelin_mem). template class RTStore { public: // 3 states of the transaction at a given index- waiting, busy and done. const static int ITEM_WAITING = 0, ITEM_BUSY = 1, ITEM_DONE = 2; private: class RTStoreItem : public T { public: RTStoreItem() : item_status(ITEM_DONE) {}; volatile int item_status; // Current status of this item (update using careful atomic ops) }; public: RTStore (int num_items) : num_items(num_items) { items = new RTStoreItem[num_items]; }; ~RTStore () { delete [] items; }; // Finds the first RTStoreItem with the given state 'find_state' and resets the state atomically to // 'replace_state'. Returns the index of the store item in the store (in idx), as well as a pointer to the // item object itself (return). // // Returns null if no item could be found with the given state. inline T *FindItemWithState (int find_state, int replace_state, int &idx) { for (int i = 0; i < num_items; i++) { // printf("RTStore Find (%p): %d: state is %d : find %d replace %d\n",this,i,items[i].item_status,find_state,replace_state); // Compare and swap, atomically. This guarantees that only one thread can modify an RTStoreItem // at a time, without locking. if (__sync_bool_compare_and_swap(&items[i].item_status,find_state,replace_state)) { // printf(" got it\n"); // Found. idx = i; return &items[i]; } } // None found return 0; }; // Change the state of store item with given index to 'new_state', if the item has the expected state. // Returns nonzero if the state matched and was changed. Returns zero if the state did not match. inline char ChangeStateAtIdx (int idx, int expect_state, int new_state) { // printf("RTStore Change (%p): %d: state is %d : expect %d replace %d\n",this,idx,items[idx].item_status,expect_state,new_state); return __sync_bool_compare_and_swap(&items[idx].item_status,expect_state,new_state); }; // Returns the item at the given index. To modify the item, change to the BUSY state first. inline T *GetItemAtIdx (int idx) { return &items[idx]; }; private: RTStoreItem *items; int num_items; // Number of items in the store }; // Base class for single linked list class SListItem { friend class SLinkList; public: SListItem() : slist_next(0) {}; private: SListItem *slist_next; // Next item pointer }; // Single linked list. RT-safe but not threadsafe. Must be locked. class SLinkList { public: SLinkList() : first(0) {}; inline void AddToHead(SListItem *i) { if (first == 0) first = i; else { i->slist_next = first; first = i; } }; // Finds and removes item i from the list. Returns i if successful, otherwise null. inline SListItem *FindAndRemove(SListItem *i) { SListItem *cur = first, *prev = 0; // Search for 'i' in our list while (cur != 0 && cur != i) { prev = cur; cur = cur->slist_next; } if (cur != 0) { // Got one to delete, unlink! if (prev != 0) prev->slist_next = cur->slist_next; else first = cur->slist_next; } return cur; }; inline SListItem *GetFirstItem() { return first; }; inline SListItem *GetNextItem(SListItem *cur) { return cur->slist_next; }; private: SListItem *first; }; class DListItem { public: DListItem() : slist_prev(0), slist_next(0) {}; SListItem *slist_prev, *slist_next; // Previous and next item pointers }; class DLinkList { DLinkList() : first(0) {}; DListItem *first; }; #endif freewheeling-0.6.6/src/fweelin_event.cc000066400000000000000000000573241370736313100201360ustar00rootroot00000000000000/* They said we don't do kirtan during seva. Because singing is not mouna. but I differ-- Rhythm is stillness in motion. And in the silence, there is music. */ /* Copyright 2004-2011 Jan Pekau This file is part of Freewheeling. Freewheeling is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. Freewheeling 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 Freewheeling. If not, see . */ #include #include #include #include #include #include #include #include #include #include #include "fweelin_event.h" #define EVENT_QUEUE_SIZE 100 // Number of events in event queue, per writer thread EventTypeTable *Event::ett = 0; // Events are allocated in blocks using the Memory Manager // These macros help populate the event type table with names and managers // They also determine which, if any, event parameters are indexed for speed // Event with normal (direct method call) delivery using block allocation with // default number of instances preallocated #define SET_ETYPE(etyp,nm,typ) \ case etyp : \ { \ Event *proto = \ ::new typ[PreallocatedType:: \ PREALLOC_DEFAULT_NUM_INSTANCES]; \ ett[i].name = nm; \ ett[i].pretype = \ new PreallocatedType(mmgr,proto,sizeof(typ), \ PreallocatedType:: \ PREALLOC_DEFAULT_NUM_INSTANCES, \ 1); \ ett[i].slowdelivery = 0; \ int paramidx = -1, j = 0; \ for (; j < proto->GetNumParams() && \ proto->GetParam(j).max_index == -1; j++); \ if (j < proto->GetNumParams()) \ paramidx = j; \ ett[i].paramidx = paramidx; \ } \ break; // Event with slow (guaranteed non-RT) delivery using block allocation // with default number of instances preallocated #define SET_ETYPE_SLOW(etyp,nm,typ) \ case etyp : \ { \ Event *proto = \ ::new typ[PreallocatedType:: \ PREALLOC_DEFAULT_NUM_INSTANCES]; \ ett[i].name = nm; \ ett[i].pretype = \ new PreallocatedType(mmgr,proto,sizeof(typ), \ PreallocatedType:: \ PREALLOC_DEFAULT_NUM_INSTANCES, \ 1); \ ett[i].slowdelivery = 1; \ int paramidx = -1, j = 0; \ for (; j < proto->GetNumParams() && \ proto->GetParam(j).max_index == -1; j++); \ if (j < proto->GetNumParams()) \ paramidx = j; \ ett[i].paramidx = paramidx; \ } \ break; // Event with normal (direct method call) delivery using SINGLE INSTANCE allocation with // default number of instances preallocated #define SET_ETYPE_NO_BLOCK(etyp,nm,typ) \ case etyp : \ { \ Event *proto = \ ::new typ[PreallocatedType:: \ PREALLOC_DEFAULT_NUM_INSTANCES]; \ ett[i].name = nm; \ ett[i].pretype = \ new PreallocatedType(mmgr,proto,sizeof(typ), \ PreallocatedType:: \ PREALLOC_DEFAULT_NUM_INSTANCES, \ 0); \ int paramidx = -1, j = 0; \ for (; j < proto->GetNumParams() && \ proto->GetParam(j).max_index == -1; j++); \ if (j < proto->GetNumParams()) \ paramidx = j; \ ett[i].paramidx = paramidx; \ } \ break; // Event with normal (direct method call) delivery using block allocation with // a SET number of instances preallocated #define SET_ETYPE_NUMPREALLOC(etyp,nm,typ,numpre) \ case etyp : \ { \ Event *proto = ::new typ[numpre]; \ ett[i].name = nm; \ ett[i].pretype = new PreallocatedType(mmgr,proto,sizeof(typ),numpre,1); \ int paramidx = -1, j = 0; \ for (; j < proto->GetNumParams() && \ proto->GetParam(j).max_index == -1; j++); \ if (j < proto->GetNumParams()) \ paramidx = j; \ ett[i].paramidx = paramidx; \ } \ break; void Event::SetupEventTypeTable(MemoryManager *mmgr) { int evnum = (int) EventType(T_EV_Last); ett = new EventTypeTable[evnum]; for (int i = 0; i < evnum; i++) { switch (EventType(i)) { // *** Notice some events are marked SET_ETYPE_SLOW // This is critical because some code sections are not able to run in RT // Any event marked SET_ETYPE should be able to be run in RT, // because if it is bound to a MIDI trigger, that will happen. // // Events marked SET_ETYPE_SLOW will always run from the nonRT event // thread. This means they will be delivered after SET_ETYPE events if // a sequence of events is sent. #define MIDI_EVENT_PREALLOCATION 50 // How many MIDI events to preallocate. SET_ETYPE_NUMPREALLOC(T_EV_Input_Key,"key",KeyInputEvent,MIDI_EVENT_PREALLOCATION); SET_ETYPE_NUMPREALLOC(T_EV_Input_JoystickButton,"joybutton", JoystickButtonInputEvent,MIDI_EVENT_PREALLOCATION); SET_ETYPE_NUMPREALLOC(T_EV_Input_MIDIKey,"midikey",MIDIKeyInputEvent,MIDI_EVENT_PREALLOCATION); SET_ETYPE_NUMPREALLOC(T_EV_Input_MIDIController,"midicontroller", MIDIControllerInputEvent,MIDI_EVENT_PREALLOCATION); SET_ETYPE_NUMPREALLOC(T_EV_Input_MIDIProgramChange, "midiprogramchange", MIDIProgramChangeInputEvent,MIDI_EVENT_PREALLOCATION); SET_ETYPE_NUMPREALLOC(T_EV_Input_MIDIChannelPressure, "midichannelpressure", MIDIChannelPressureInputEvent,MIDI_EVENT_PREALLOCATION); SET_ETYPE_NUMPREALLOC(T_EV_Input_MIDIPitchBend,"midipitchbend", MIDIPitchBendInputEvent,MIDI_EVENT_PREALLOCATION); SET_ETYPE_NUMPREALLOC(T_EV_Input_MIDIClock,"midiclock",MIDIClockInputEvent,MIDI_EVENT_PREALLOCATION); SET_ETYPE_NUMPREALLOC(T_EV_Input_MIDIStartStop,"midistartstop",MIDIStartStopInputEvent,MIDI_EVENT_PREALLOCATION); SET_ETYPE_SLOW(T_EV_ALSAMixerControlSet,"alsa-mixer-control-set",ALSAMixerControlSetEvent); SET_ETYPE(T_EV_LoopClicked,"loop-clicked",LoopClickedEvent); SET_ETYPE(T_EV_GoSub,"go-sub",GoSubEvent); SET_ETYPE(T_EV_StartSession,"start-freewheeling",StartSessionEvent); SET_ETYPE(T_EV_StartInterface,"start-interface",StartInterfaceEvent); SET_ETYPE_SLOW(T_EV_ExitSession,"exit-freewheeling",ExitSessionEvent); SET_ETYPE(T_EV_SlideMasterInVolume,"slide-master-in-volume", SlideMasterInVolumeEvent); SET_ETYPE(T_EV_SlideMasterOutVolume,"slide-master-out-volume", SlideMasterOutVolumeEvent); SET_ETYPE(T_EV_SlideInVolume,"slide-in-volume", SlideInVolumeEvent); SET_ETYPE(T_EV_SetMasterInVolume,"set-master-in-volume", SetMasterInVolumeEvent); SET_ETYPE(T_EV_SetMasterOutVolume,"set-master-out-volume", SetMasterOutVolumeEvent); SET_ETYPE(T_EV_SetInVolume,"set-in-volume", SetInVolumeEvent); SET_ETYPE(T_EV_ToggleInputRecord,"toggle-input-record", ToggleInputRecordEvent); SET_ETYPE(T_EV_SetMidiEchoPort,"set-midi-echo-port", SetMidiEchoPortEvent); SET_ETYPE(T_EV_SetMidiEchoChannel,"set-midi-echo-channel", SetMidiEchoChannelEvent); SET_ETYPE(T_EV_AdjustMidiTranspose,"adjust-midi-transpose", AdjustMidiTransposeEvent); SET_ETYPE(T_EV_FluidSynthEnable,"fluidsynth-enable", FluidSynthEnableEvent); SET_ETYPE(T_EV_SetMidiTuning,"set-midi-tuning", SetMidiTuningEvent); SET_ETYPE(T_EV_SetTriggerVolume,"set-trigger-volume", SetTriggerVolumeEvent); SET_ETYPE(T_EV_SlideLoopAmp,"slide-loop-amplifier",SlideLoopAmpEvent); SET_ETYPE(T_EV_SetLoopAmp,"set-loop-amplifier",SetLoopAmpEvent); SET_ETYPE(T_EV_AdjustLoopAmp,"adjust-loop-amplifier",AdjustLoopAmpEvent); SET_ETYPE(T_EV_TriggerLoop,"trigger-loop",TriggerLoopEvent); SET_ETYPE_SLOW(T_EV_MoveLoop,"move-loop",MoveLoopEvent); SET_ETYPE_SLOW(T_EV_RenameLoop,"rename-loop",RenameLoopEvent); SET_ETYPE_SLOW(T_EV_EraseLoop,"erase-loop",EraseLoopEvent); SET_ETYPE_SLOW(T_EV_EraseAllLoops,"erase-all-loops",EraseAllLoopsEvent); SET_ETYPE_SLOW(T_EV_EraseSelectedLoops,"erase-selected-loops", EraseSelectedLoopsEvent); SET_ETYPE(T_EV_SlideLoopAmpStopAll,"slide-loop-amplifier-stop-all", SlideLoopAmpStopAllEvent); SET_ETYPE_SLOW(T_EV_DeletePulse,"delete-pulse",DeletePulseEvent); SET_ETYPE_SLOW(T_EV_SelectPulse,"select-pulse",SelectPulseEvent); SET_ETYPE(T_EV_TapPulse,"tap-pulse",TapPulseEvent); SET_ETYPE(T_EV_SwitchMetronome,"switch-metronome",SwitchMetronomeEvent); SET_ETYPE(T_EV_SetSyncType,"set-sync-type",SetSyncTypeEvent); SET_ETYPE(T_EV_SetSyncSpeed,"set-sync-speed",SetSyncSpeedEvent); SET_ETYPE(T_EV_SetMidiSync,"set-midi-sync",SetMidiSyncEvent); SET_ETYPE(T_EV_SetVariable,"set-variable",SetVariableEvent); SET_ETYPE(T_EV_ToggleVariable,"toggle-variable",ToggleVariableEvent); SET_ETYPE(T_EV_SplitVariableMSBLSB, "split-variable-msb-lsb",SplitVariableMSBLSBEvent); SET_ETYPE(T_EV_ParamSetGetAbsoluteParamIdx,"paramset-get-absolute-param-index", ParamSetGetAbsoluteParamIdxEvent); SET_ETYPE(T_EV_ParamSetGetParam,"paramset-get-param", ParamSetGetParamEvent); SET_ETYPE(T_EV_ParamSetSetParam,"paramset-set-param", ParamSetSetParamEvent); SET_ETYPE(T_EV_LogFaderVolToLinear,"log-fader-to-linear",LogFaderVolToLinearEvent); SET_ETYPE(T_EV_VideoShowParamSetBank,"video-show-paramset-bank", VideoShowParamSetBankEvent); SET_ETYPE(T_EV_VideoShowParamSetPage,"video-show-paramset-page", VideoShowParamSetPageEvent); SET_ETYPE_SLOW(T_EV_VideoShowSnapshotPage,"video-show-snapshot-page", VideoShowSnapshotPageEvent); SET_ETYPE_SLOW(T_EV_VideoShowLoop,"video-show-loop",VideoShowLoopEvent); SET_ETYPE_SLOW(T_EV_VideoShowLayout,"video-show-layout", VideoShowLayoutEvent); SET_ETYPE_SLOW(T_EV_VideoSwitchInterface,"video-switch-interface", VideoSwitchInterfaceEvent); SET_ETYPE_SLOW(T_EV_VideoShowDisplay,"video-show-display", VideoShowDisplayEvent); SET_ETYPE_SLOW(T_EV_VideoShowHelp,"video-show-help", VideoShowHelpEvent); SET_ETYPE_SLOW(T_EV_VideoFullScreen,"video-full-screen", VideoFullScreenEvent); SET_ETYPE_SLOW(T_EV_ShowDebugInfo,"show-debug-info", ShowDebugInfoEvent); SET_ETYPE_SLOW(T_EV_ToggleDiskOutput,"toggle-disk-output", ToggleDiskOutputEvent); SET_ETYPE(T_EV_SetAutoLoopSaving,"set-auto-loop-saving", SetAutoLoopSavingEvent); SET_ETYPE_SLOW(T_EV_SaveLoop,"save-loop",SaveLoopEvent); SET_ETYPE_SLOW(T_EV_SaveNewScene,"save-new-scene",SaveNewSceneEvent); SET_ETYPE_SLOW(T_EV_SaveCurrentScene,"save-current-scene", SaveCurrentSceneEvent); SET_ETYPE(T_EV_SetLoadLoopId,"set-load-loop-id",SetLoadLoopIdEvent); SET_ETYPE(T_EV_SetDefaultLoopPlacement,"set-default-loop-placement", SetDefaultLoopPlacementEvent); SET_ETYPE_SLOW(T_EV_ToggleSelectLoop,"toggle-select-loop", ToggleSelectLoopEvent); SET_ETYPE_SLOW(T_EV_SelectOnlyPlayingLoops,"select-only-playing-loops", SelectOnlyPlayingLoopsEvent); SET_ETYPE_SLOW(T_EV_SelectAllLoops,"select-all-loops", SelectAllLoopsEvent); SET_ETYPE_SLOW(T_EV_TriggerSelectedLoops,"trigger-selected-loops", TriggerSelectedLoopsEvent); SET_ETYPE(T_EV_SetSelectedLoopsTriggerVolume, "set-selected-loops-trigger-volume", SetSelectedLoopsTriggerVolumeEvent); SET_ETYPE(T_EV_AdjustSelectedLoopsAmp, "adjust-selected-loops-amp", AdjustSelectedLoopsAmpEvent); SET_ETYPE_SLOW(T_EV_InvertSelection,"invert-selection", InvertSelectionEvent); SET_ETYPE_SLOW(T_EV_CreateSnapshot,"create-snapshot", CreateSnapshotEvent); SET_ETYPE_SLOW(T_EV_RenameSnapshot,"rename-snapshot", RenameSnapshotEvent); SET_ETYPE_SLOW(T_EV_TriggerSnapshot,"trigger-snapshot", TriggerSnapshotEvent); SET_ETYPE_SLOW(T_EV_SwapSnapshots,"swap-snapshots", SwapSnapshotsEvent); SET_ETYPE_SLOW(T_EV_BrowserMoveToItem,"browser-move-to-item", BrowserMoveToItemEvent); SET_ETYPE_SLOW(T_EV_BrowserMoveToItemAbsolute, "browser-move-to-item-absolute", BrowserMoveToItemAbsoluteEvent); SET_ETYPE_SLOW(T_EV_BrowserSelectItem,"browser-select-item", BrowserSelectItemEvent); SET_ETYPE_SLOW(T_EV_BrowserRenameItem,"browser-rename-item", BrowserRenameItemEvent); SET_ETYPE(T_EV_BrowserItemBrowsed,"browser-item-browsed", BrowserItemBrowsedEvent); SET_ETYPE_SLOW(T_EV_PatchBrowserMoveToBank,"patchbrowser-move-to-bank", PatchBrowserMoveToBankEvent); SET_ETYPE_SLOW(T_EV_PatchBrowserMoveToBankByIndex, "patchbrowser-move-to-bank-by-index", PatchBrowserMoveToBankByIndexEvent); SET_ETYPE_SLOW(T_EV_TransmitPlayingLoopsToDAW, "transmit-playing-loops-to-daw", TransmitPlayingLoopsToDAWEvent); // Internal events-- don't try to bind to these SET_ETYPE(T_EV_EndRecord,"__internal__endrecord",EndRecordEvent); SET_ETYPE(T_EV_LoopList,"__internal__looplist",LoopListEvent); SET_ETYPE(T_EV_SceneMarker,"__internal__scenemarker",SceneMarkerEvent); SET_ETYPE(T_EV_PulseSync,"__internal__pulsesync",PulseSyncEvent); SET_ETYPE_NUMPREALLOC(T_EV_TriggerSet,"__internal__triggerset",TriggerSetEvent,100); SET_ETYPE_NUMPREALLOC(T_EV_AddProcessor,"__internal__addprocessor",AddProcessorEvent,100); SET_ETYPE_NUMPREALLOC(T_EV_DelProcessor,"__internal__delprocessor",DelProcessorEvent,100); SET_ETYPE_NUMPREALLOC(T_EV_CleanupProcessor,"__internal__cleanupprocessor",CleanupProcessorEvent,100); SET_ETYPE(T_EV_Input_MouseButton,"__internal__mousebutton",MouseButtonInputEvent); SET_ETYPE_NUMPREALLOC(T_EV_Input_MouseMotion,"__internal__mousemotion",MouseMotionInputEvent,100); default: break; } } }; void Event::TakedownEventTypeTable() { int evnum = (int) EventType(T_EV_Last); for (int i = 0; i < evnum; i++) { // Deleting the manager will delete all instances // allocated thru it-- if (ett[i].pretype != 0) { // printf("Deleting manager for event: %s\n",ett[i].name); delete ett[i].pretype; } // so the prototype base instance is already deleted ett[i].proto = 0; } delete[] ett; }; Event *Event::GetEventByType(EventType typ, char wait) { if (ett == 0) { printf("EVENT: ERROR- no event type table!\n"); exit(1); } int i = (int) typ; if (ett[i].pretype != 0) { Event *ret = (Event *) ett[i].pretype->RTNew(); if (ret != 0) return ret; else { // No instance available if (wait) { // Wait printf("EVENT: Waiting for memory allocation of event '%s'.\n",ett[i].name); do { usleep(10000); ret = (Event *) ett[i].pretype->RTNew(); } while (ret == 0); return ret; } else { printf("EVENT: ERROR: No wait condition and no instances available for event '%s'\n",ett[i].name); return 0; // Don't wait } } } else if (ett[i].proto != 0) { Event *ret = (Event *) ett[i].proto->RTNew(); if (ret != 0) return ret; else { // No instance available if (wait) { // Wait printf("EVENT: Waiting for memory allocation of event '%s'.\n",ett[i].name); do { usleep(10000); ret = (Event *) ett[i].proto->RTNew(); } while (ret == 0); return ret; } else { printf("EVENT: ERROR: No wait condition and no instances available for event '%s'\n",ett[i].name); return 0; // Don't wait } } } else { printf("ERROR: no prototype or mgr for event type: '%s'\n", ett[i].name); return 0; } }; Event *Event::GetEventByName(char *evtname, char wait) { if (ett == 0) { printf("EVENT: Error- no event type table!\n"); exit(1); } int evnum = (int) EventType(T_EV_Last); for (int i = 0; i < evnum; i++) { if (ett[i].name != 0) if (!strcmp(evtname, ett[i].name)) return GetEventByType((EventType) i,wait); } return 0; }; EventManager::EventManager () : eq(0), needs_wakeup(0), threadgo(1) { printf("Start event manager.\n"); // Create listener structure.. int evnum = (int) EventType(T_EV_Last); listeners = new EventListenerItem *[evnum]; for (int i = 0; i < evnum; i++) listeners[i] = 0; pthread_mutex_init(&dispatch_thread_lock,0); pthread_mutex_init(&listener_list_lock,0); pthread_cond_init(&dispatch_ready,0); const static size_t STACKSIZE = 1024*128; pthread_attr_t attr; pthread_attr_init(&attr); pthread_attr_setstacksize(&attr,STACKSIZE); printf("EVENT: Stacksize: %zd.\n",STACKSIZE); // Hold dispatch thread until ready pthread_mutex_lock(&dispatch_thread_lock); // Start an event dispatch thread int ret = pthread_create(&dispatch_thread, &attr, run_dispatch_thread, static_cast(this)); if (ret != 0) { printf("(eventmanager) pthread_create failed, exiting"); exit(1); } RT_RWThreads::RegisterReaderOrWriter(dispatch_thread); struct sched_param schp; memset(&schp, 0, sizeof(schp)); // Event dispatch thread is NOT RT schp.sched_priority = sched_get_priority_max(SCHED_OTHER); if (pthread_setschedparam(dispatch_thread, SCHED_OTHER, &schp) != 0) { printf("EVENT: Can't set hi priority thread, will use regular!\n"); } }; EventManager::~EventManager() { //printf("Event Manager: cleanup... this: %p\n",this); // Terminate the dispatch thread threadgo = 0; pthread_mutex_lock (&dispatch_thread_lock); pthread_cond_signal (&dispatch_ready); pthread_mutex_unlock (&dispatch_thread_lock); pthread_join(dispatch_thread,0); pthread_cond_destroy (&dispatch_ready); pthread_mutex_destroy (&dispatch_thread_lock); pthread_mutex_destroy (&listener_list_lock); int evnum = (int) EventType(T_EV_Last); for (int i = 0; i < evnum; i++) { // Erase listeners EventListenerItem *cur = listeners[i]; while (cur != 0) { EventListenerItem *tmp = cur->next; delete cur; cur = tmp; } } delete[] listeners; if (eq != 0) delete eq; // Takedown event type table // printf(" .. ETT takedown (this: %p)\n",this); Event::TakedownEventTypeTable(); // printf(" .. ETT takedown done (this: %p)\n",this); printf("EVENT: manager end.\n"); }; // Create ring buffers after ALL writer threads are created void EventManager::FinalPrep() { printf("EVENT: Create ringbuffers and begin.\n"); eq = new SRMWRingBuffer(EVENT_QUEUE_SIZE); // Start processing pthread_mutex_unlock(&dispatch_thread_lock); }; // Event queue functions ** NOT THREADSAFE ** Event *EventManager::DeleteQueue(Event *first) { Event *cur = first; while (cur != 0) { Event *tmp = cur->next; cur->RTDelete(); cur = tmp; } return 0; } void EventManager::QueueEvent(Event **first, Event *nw) { Event *cur = *first; if (cur == 0) *first = nw; else { while (cur->next != 0) cur = cur->next; cur->next = nw; } }; void EventManager::RemoveEvent(Event **first, Event *prev, Event **cur) { Event *tmp = (*cur)->next; if (prev != 0) prev->next = tmp; else *first = tmp; (*cur)->RTDelete(); *cur = tmp; }; // ** End event queue functions // Broadcast through dispatch thread! // RT and threadsafe, so long as you allocate your event with RTNew() void EventManager::BroadcastEvent(Event *ev, EventProducer *source) { // printf("*** THREAD (BROADCAST): %li\n",pthread_self()); ev->from = source; //ev->time = mygettime(); // Write to queue if (eq->WriteElement(ev) != 0) { printf("EVENT: BroadcastEvent failed!\n"); return; } // Wakeup dispatch thread WakeupIfNeeded(1); // printf("EVENT: SENT: %s!\n",Event::ett[(int) ev->GetType()].name); }; void *EventManager::run_dispatch_thread (void *ptr) { EventManager *inst = static_cast(ptr); pthread_mutex_lock(&inst->dispatch_thread_lock); while (inst->threadgo) { // printf("EVENT: start process queue\n"); // Scan through all events Event *cur = inst->eq->ReadElement(); while (cur != 0) { //printf("broadcast thread\n"); // Print time elapsed since broadcast //double dt = (mygettime()-cur->time) * 1000; //printf("Evt dispatch- dt: %2.2f ms\n",dt); if (cur->GetMgr() == 0) printf("EVENT: WARNING: Broadcast from RT nonRT event!!\n"); // printf("EVENT: DISPATCH: %s!\n",Event::ett[(int) cur->GetType()].name); inst->BroadcastEventNow(cur,cur->from,0,0); // Force delivery now, // don't erase til we // advance cur->RTDelete(); cur = inst->eq->ReadElement(); } // No more events in queue // printf("EVENT: end process queue\n"); // Wait for wakeup pthread_cond_wait (&inst->dispatch_ready, &inst->dispatch_thread_lock); // printf("EVENT: WAKEUP!\n"); inst->needs_wakeup = 0; // Woken! } printf("Event Manager: end dispatch thread\n"); pthread_mutex_unlock(&inst->dispatch_thread_lock); return 0; }; // Not RT safe, but threadsafe! // Listen for the given event (optionally from the given producer) and callme // when it occurs-- optionally, block calls from myself void EventManager::ListenEvent(EventListener *callme, EventProducer *from, EventType type, char block_self_calls) { EventListenerItem *nw = new EventListenerItem(callme,from,type, block_self_calls); pthread_mutex_lock(&listener_list_lock); // Add to the listeners list int evnum = (int) type; EventListenerItem *cur = listeners[evnum]; if (cur == 0) listeners[evnum] = nw; // That was easy, now we have 1 item else { while (cur->next != 0) cur = cur->next; cur->next = nw; // Link up the last item to new1 } pthread_mutex_unlock(&listener_list_lock); }; // Not RT safe! void EventManager::UnlistenEvent(EventListener *callme, EventProducer *from, EventType type) { pthread_mutex_lock(&listener_list_lock); // Remove from the listeners list int evnum = (int) type; EventListenerItem *cur = listeners[evnum], *prev = 0; // Search for those listening to 'from' & 'type' while (cur != 0 && (cur->callwhom != callme || cur->eventsfrom != from)) { prev = cur; cur = cur->next; } if (cur != 0) { // Got it, unlink! if (prev != 0) prev->next = cur->next; else listeners[evnum] = cur->next; delete cur; } pthread_mutex_unlock(&listener_list_lock); }; freewheeling-0.6.6/src/fweelin_event.h000066400000000000000000002440131370736313100177710ustar00rootroot00000000000000#ifndef __FWEELIN_EVENT_H #define __FWEELIN_EVENT_H /* Copyright 2004-2011 Jan Pekau This file is part of Freewheeling. Freewheeling is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. Freewheeling 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 Freewheeling. If not, see . */ #include #include #include extern "C" { #include } // Event parameter name for interface ID #define INTERFACEID "interfaceid" class Loop; class Event; class ProcessorItem; class EventProducer { }; class EventListener { public: virtual void ReceiveEvent(Event *ev, EventProducer *from) = 0; }; // An event hook gets first dibs on incoming events // We use this to override the usual functions of, say, the keyboard, // and redirect them elsewhere, like typing text. class EventHook { public: // HookEvent works just like EventListener::ReceiveEvent, // except it returns nonzero if it has swallowed the event // and zero if it has disregarded the event. // // If HookEvent disregards the event, it is processed as defined // through the configuration system virtual char HookEvent(Event *ev, EventProducer *from) = 0; }; double mygettime(void); // Max filename length #define FWEELIN_OUTNAME_LEN PATH_MAX #define MAX_MIDI_CHANNELS 16 #define MAX_MIDI_CONTROLLERS 127 #define MAX_MIDI_NOTES 127 #define MAX_MIDI_PORTS 4 #define MIDI_CC_SUSTAIN 64 // Sustain pedal cc // Get a new block of events of the given type #define EVT_NEW_BLOCK(typ,etyp) ::new typ[Event::GetMemMgrByType(etyp)-> \ GetBlockSize()] // Basic defines for within an Event #define EVT_DEFINE(typ,etyp) \ typ() { Recycle(); }; \ \ virtual Preallocated *NewInstance() { \ return EVT_NEW_BLOCK(typ,etyp); \ }; \ virtual EventType GetType() { return etyp; }; \ FWMEM_DEFINE_DELBLOCK #define EVT_DEFINE_NO_CONSTR(typ,etyp) \ virtual Preallocated *NewInstance() { \ return EVT_NEW_BLOCK(typ,etyp); \ }; \ virtual EventType GetType() { return etyp; }; \ FWMEM_DEFINE_DELBLOCK #define EVT_DEFINE_NO_BLOCK(typ,etyp) \ typ() { Recycle(); }; \ \ virtual Preallocated *NewInstance() { \ return ::new typ(); \ }; \ virtual EventType GetType() { return etyp; }; // List of all types of events enum EventType { T_EV_None, T_EV_Input_Key, T_EV_Input_JoystickButton, T_EV_Input_MIDIKey, T_EV_Input_MIDIController, T_EV_Input_MIDIProgramChange, T_EV_Input_MIDIChannelPressure, T_EV_Input_MIDIPitchBend, T_EV_StartSession, T_EV_StartInterface, T_EV_GoSub, T_EV_LoopClicked, T_EV_BrowserItemBrowsed, // End of bindable events- // Events after this can not trigger config bindings T_EV_Last_Bindable, T_EV_Input_MIDIClock, T_EV_Input_MIDIStartStop, T_EV_Input_MouseButton, T_EV_Input_MouseMotion, T_EV_ALSAMixerControlSet, T_EV_EndRecord, T_EV_LoopList, T_EV_SceneMarker, T_EV_PulseSync, T_EV_TriggerSet, T_EV_AddProcessor, T_EV_DelProcessor, T_EV_CleanupProcessor, T_EV_SetVariable, T_EV_ToggleVariable, T_EV_SplitVariableMSBLSB, T_EV_ParamSetGetAbsoluteParamIdx, T_EV_ParamSetGetParam, T_EV_ParamSetSetParam, T_EV_LogFaderVolToLinear, T_EV_VideoShowParamSetBank, T_EV_VideoShowParamSetPage, T_EV_VideoShowSnapshotPage, T_EV_VideoShowLoop, T_EV_VideoShowLayout, T_EV_VideoSwitchInterface, T_EV_VideoShowDisplay, T_EV_VideoShowHelp, T_EV_VideoFullScreen, T_EV_ShowDebugInfo, T_EV_ExitSession, T_EV_SlideMasterInVolume, T_EV_SlideMasterOutVolume, T_EV_SlideInVolume, T_EV_SetMasterInVolume, T_EV_SetMasterOutVolume, T_EV_SetInVolume, T_EV_ToggleInputRecord, T_EV_SetMidiEchoPort, T_EV_SetMidiEchoChannel, T_EV_AdjustMidiTranspose, T_EV_FluidSynthEnable, T_EV_SetMidiTuning, T_EV_DeletePulse, T_EV_SelectPulse, T_EV_TapPulse, T_EV_SwitchMetronome, T_EV_SetSyncType, T_EV_SetSyncSpeed, T_EV_SetMidiSync, T_EV_ToggleSelectLoop, T_EV_SelectOnlyPlayingLoops, T_EV_SelectAllLoops, T_EV_TriggerSelectedLoops, T_EV_SetSelectedLoopsTriggerVolume, T_EV_AdjustSelectedLoopsAmp, T_EV_InvertSelection, T_EV_CreateSnapshot, T_EV_RenameSnapshot, T_EV_TriggerSnapshot, T_EV_SwapSnapshots, T_EV_SetTriggerVolume, T_EV_SlideLoopAmp, T_EV_SetLoopAmp, T_EV_AdjustLoopAmp, T_EV_TriggerLoop, T_EV_MoveLoop, T_EV_RenameLoop, T_EV_EraseLoop, T_EV_EraseAllLoops, T_EV_EraseSelectedLoops, T_EV_SlideLoopAmpStopAll, T_EV_ToggleDiskOutput, T_EV_SetAutoLoopSaving, T_EV_SaveLoop, T_EV_SaveNewScene, T_EV_SaveCurrentScene, T_EV_SetLoadLoopId, T_EV_SetDefaultLoopPlacement, T_EV_BrowserMoveToItem, T_EV_BrowserMoveToItemAbsolute, T_EV_BrowserSelectItem, T_EV_BrowserRenameItem, T_EV_PatchBrowserMoveToBank, T_EV_PatchBrowserMoveToBankByIndex, T_EV_TransmitPlayingLoopsToDAW, T_EV_Last }; #include "fweelin_datatypes.h" #include "fweelin_block.h" // Gets the offset of given variable into the current class #define FWEELIN_GETOFS(a) ((long)&a - (long)this) class SDLKeyList; class PreallocatedType; class Event; // EventParameters are parameters in events that can be controlled // from inputs such as MIDI and Keyboard (see InputMatrix) class EventParameter { public: // Specify an event parameter with given name, offset into event, // size of data type, and max index (-1 by default if parameter // is not indexed) EventParameter (char *name = 0, long ofs = 0, CoreDataType dtype = T_char, int max_index = -1) : name(name), ofs(ofs), dtype(dtype), max_index(max_index) {}; char *name; // Name of event parameter long ofs; // Offset into event class of data CoreDataType dtype; // Type of data int max_index; // Config stores a hashtable for input events for // quick triggering-- this is the # of hash indexes // for an indexed parameter, or -1 for an unindexed param }; // Table of all event types and memory managers for them class EventTypeTable { public: EventTypeTable (char *name = 0, PreallocatedType *mgr = 0, Event *proto = 0, int paramidx = -1, char slowdelivery = 0) : name(name), pretype(mgr), proto(proto), paramidx(paramidx), slowdelivery(slowdelivery) {}; char *name; PreallocatedType *pretype; Event *proto; int paramidx; // Index of event parameter that is used for hash index // For example, in the keyboard input event, the keysym // is indexed for quick triggering of keyboard events by key char slowdelivery; // Nonzero if this event should be delivered slow, in // a nonRT thread. This is useful for events that cause // nonRT-safe operations to be executed. }; // Events can be allocated in realtime using class Preallocated class Event : public Preallocated { public: Event() { Recycle(); }; virtual ~Event() {}; virtual void Recycle() { from = 0; to = 0; next = 0; time.tv_sec = 0; time.tv_nsec = 0; echo = 0; }; virtual void operator = (const Event &/*evt*/) {}; virtual EventType GetType() { return T_EV_None; }; // Returns the number of parameters this event has virtual int GetNumParams() { return 0; }; // Returns the nth parameter virtual EventParameter GetParam(int /*param_n*/) { return EventParameter(); }; // Get the memory manager for the given type static inline PreallocatedType *GetMemMgrByType(EventType typ) { return ett[(int) typ].pretype; }; // Returns an instance of the event named 'evtname' // If wait is nonzero and there are no free instances through RTNew, // we wait until one becomes available static Event *GetEventByName(char *evtname, char wait = 0); // Returns an instance of the event with given type static Event *GetEventByType(EventType typ, char wait = 0); // Returns the index of the indexed parameter for the event with given // type static int GetParamIdxByType(EventType typ) { return ett[typ].paramidx; }; // Returns the string name of the given event type static char *GetEventName(EventType typ) { return ett[typ].name; }; static EventTypeTable *ett; static void SetupEventTypeTable(MemoryManager *mmgr); static void TakedownEventTypeTable(); // In an event queue, stores who this event is from EventProducer *from; // In an event queue, stores who this event is to EventListener *to; // In an event queue, this stores pointer to next event Event *next; // Time to send event struct timespec time; // Event is being echoed to MIDI outputs? // If echo is nonzero, the event is sent through the patch routing // for the currently selected patch- affecting the port(s) and channel(s) // where the event is sent. If echo is 0, the event is sent out as described // in the event (ie via outport and midichannel parameters). char echo; }; // GoSub is really an event that encapsulates other events // It allows us to fire off a subroutine of events by triggering one GoSubEvent // The events that are fired off are defined by creating a binding to // input event "go-sub" class GoSubEvent : public Event { // Size of hashtable for indexing based on subs parameter const static int SUBS_HASH = 127; public: EVT_DEFINE(GoSubEvent,T_EV_GoSub); virtual void operator = (const Event &src) { GoSubEvent &s = (GoSubEvent &) src; sub = s.sub; param1 = s.param1; param2 = s.param2; param3 = s.param3; }; virtual int GetNumParams() { return 4; }; virtual EventParameter GetParam(int n) { switch (n) { case 0: return EventParameter("sub",FWEELIN_GETOFS(sub),T_int,SUBS_HASH); case 1: return EventParameter("param1",FWEELIN_GETOFS(param1),T_float); case 2: return EventParameter("param2",FWEELIN_GETOFS(param2),T_float); case 3: return EventParameter("param3",FWEELIN_GETOFS(param3),T_float); } return EventParameter(); }; int sub; // Subroutine # float param1, // Parameter 1 param2, // Parameter 2 param3; // Parameter 3 }; class KeyInputEvent : public Event { public: EVT_DEFINE(KeyInputEvent,T_EV_Input_Key); virtual void operator = (const Event &src) { KeyInputEvent &s = (KeyInputEvent &) src; down = s.down; keysym = s.keysym; unicode = s.unicode; }; virtual int GetNumParams() { return 3; }; virtual EventParameter GetParam(int n) { switch (n) { case 0: return EventParameter("keydown",FWEELIN_GETOFS(down),T_char); case 1: return EventParameter("key",FWEELIN_GETOFS(keysym),T_int,SDLK_LAST); case 2: return EventParameter("unicode",FWEELIN_GETOFS(unicode),T_int); } return EventParameter(); }; char down; // Nonzero if key is pressed, zero if key is released int keysym, // Keysym of key pressed unicode; // Unicode translation (if enabled) int presslen; }; class LoopClickedEvent : public Event { public: EVT_DEFINE(LoopClickedEvent,T_EV_LoopClicked); virtual void operator = (const Event &src) { LoopClickedEvent &s = (LoopClickedEvent &) src; down = s.down; button = s.button; loopid = s.loopid; in = s.in; }; virtual int GetNumParams() { return 4; }; virtual EventParameter GetParam(int n) { switch (n) { case 0: return EventParameter("down",FWEELIN_GETOFS(down),T_char); case 1: return EventParameter("button",FWEELIN_GETOFS(button),T_int); case 2: return EventParameter("loopid",FWEELIN_GETOFS(loopid),T_int); case 3: return EventParameter("in",FWEELIN_GETOFS(in),T_char); } return EventParameter(); }; char down, // Nonzero if button is pressed, zero if button is released in; // Zero if clicked in looptray, one if clicked in layout int button; // Button # pressed/released int loopid; // LoopID of loop that was clicked int presslen; }; class JoystickButtonInputEvent : public Event { public: EVT_DEFINE(JoystickButtonInputEvent,T_EV_Input_JoystickButton); virtual void operator = (const Event &src) { JoystickButtonInputEvent &s = (JoystickButtonInputEvent &) src; down = s.down; joystick = s.joystick; button = s.button; }; virtual int GetNumParams() { return 3; }; virtual EventParameter GetParam(int n) { switch (n) { case 0: return EventParameter("down",FWEELIN_GETOFS(down),T_char); case 1: return EventParameter("button",FWEELIN_GETOFS(button),T_int); case 2: return EventParameter("joystick",FWEELIN_GETOFS(joystick),T_int); } return EventParameter(); }; char down; // Nonzero if button is pressed, zero if button is released int button; // Button # pressed/released int joystick; // Index of joystick int presslen; }; class MouseButtonInputEvent : public Event { public: EVT_DEFINE(MouseButtonInputEvent,T_EV_Input_MouseButton); virtual void operator = (const Event &src) { MouseButtonInputEvent &s = (MouseButtonInputEvent &) src; down = s.down; button = s.button; x = s.x; y = s.y; }; virtual int GetNumParams() { return 4; }; virtual EventParameter GetParam(int n) { switch (n) { case 0: return EventParameter("down",FWEELIN_GETOFS(down),T_char); case 1: return EventParameter("button",FWEELIN_GETOFS(button),T_int); case 2: return EventParameter("x",FWEELIN_GETOFS(x),T_int); case 3: return EventParameter("y",FWEELIN_GETOFS(y),T_int); } return EventParameter(); }; char down; // Nonzero if button is pressed, zero if button is released int button; // Button # pressed/released int x, y; // Coordinates of press (on screen) int presslen; }; class MouseMotionInputEvent : public Event { public: EVT_DEFINE(MouseMotionInputEvent,T_EV_Input_MouseMotion); virtual void operator = (const Event &src) { MouseMotionInputEvent &s = (MouseMotionInputEvent &) src; x = s.x; y = s.y; }; virtual int GetNumParams() { return 2; }; virtual EventParameter GetParam(int n) { switch (n) { case 0: return EventParameter("x",FWEELIN_GETOFS(x),T_int); case 1: return EventParameter("y",FWEELIN_GETOFS(y),T_int); } return EventParameter(); }; int x, y; // Coordinates of mouse motion (on screen) }; class MIDIControllerInputEvent : public Event { public: EVT_DEFINE(MIDIControllerInputEvent,T_EV_Input_MIDIController); virtual void Recycle() { outport = 1; Event::Recycle(); }; virtual void operator = (const Event &src) { MIDIControllerInputEvent &s = (MIDIControllerInputEvent &) src; outport = s.outport; channel = s.channel; ctrl = s.ctrl; val = s.val; echo = s.echo; }; virtual int GetNumParams() { return 5; }; virtual EventParameter GetParam(int n) { switch (n) { case 0: return EventParameter("outport",FWEELIN_GETOFS(outport),T_int); case 1: return EventParameter("midichannel",FWEELIN_GETOFS(channel),T_int); case 2: return EventParameter("controlnum",FWEELIN_GETOFS(ctrl),T_int, MAX_MIDI_CONTROLLERS); case 3: return EventParameter("controlval",FWEELIN_GETOFS(val),T_int); case 4: return EventParameter("routethroughpatch",FWEELIN_GETOFS(echo),T_char); } return EventParameter(); }; int outport, // # of MIDI output to send event to channel, // MIDI channel ctrl, // controller # val; // value }; class MIDIChannelPressureInputEvent : public Event { public: EVT_DEFINE(MIDIChannelPressureInputEvent, T_EV_Input_MIDIChannelPressure); virtual void Recycle() { outport = 1; Event::Recycle(); }; virtual void operator = (const Event &src) { MIDIChannelPressureInputEvent &s = (MIDIChannelPressureInputEvent &) src; outport = s.outport; channel = s.channel; val = s.val; echo = s.echo; }; virtual int GetNumParams() { return 4; }; virtual EventParameter GetParam(int n) { switch (n) { case 0: return EventParameter("outport",FWEELIN_GETOFS(outport),T_int); case 1: return EventParameter("midichannel",FWEELIN_GETOFS(channel),T_int, MAX_MIDI_CHANNELS); case 2: return EventParameter("pressureval",FWEELIN_GETOFS(val),T_int); case 3: return EventParameter("routethroughpatch",FWEELIN_GETOFS(echo),T_char); } return EventParameter(); }; int outport, // # of MIDI output to send event to channel, // MIDI channel val; // Channel pressure value }; class MIDIProgramChangeInputEvent : public Event { public: EVT_DEFINE(MIDIProgramChangeInputEvent, T_EV_Input_MIDIProgramChange); virtual void Recycle() { outport = 1; Event::Recycle(); }; virtual void operator = (const Event &src) { MIDIProgramChangeInputEvent &s = (MIDIProgramChangeInputEvent &) src; outport = s.outport; channel = s.channel; val = s.val; echo = s.echo; }; virtual int GetNumParams() { return 4; }; virtual EventParameter GetParam(int n) { switch (n) { case 0: return EventParameter("outport",FWEELIN_GETOFS(outport),T_int); case 1: return EventParameter("midichannel",FWEELIN_GETOFS(channel),T_int, MAX_MIDI_CHANNELS); case 2: return EventParameter("programval",FWEELIN_GETOFS(val),T_int); case 3: return EventParameter("routethroughpatch",FWEELIN_GETOFS(echo),T_char); } return EventParameter(); }; int outport, // # of MIDI output to send event to channel, // MIDI channel val; // program change value }; class MIDIPitchBendInputEvent : public Event { public: EVT_DEFINE(MIDIPitchBendInputEvent,T_EV_Input_MIDIPitchBend); virtual void Recycle() { outport = 1; Event::Recycle(); }; virtual void operator = (const Event &src) { MIDIPitchBendInputEvent &s = (MIDIPitchBendInputEvent &) src; outport = s.outport; channel = s.channel; val = s.val; echo = s.echo; }; virtual int GetNumParams() { return 4; }; virtual EventParameter GetParam(int n) { switch (n) { case 0: return EventParameter("outport",FWEELIN_GETOFS(outport),T_int); case 1: return EventParameter("midichannel",FWEELIN_GETOFS(channel),T_int, MAX_MIDI_CHANNELS); case 2: return EventParameter("pitchval",FWEELIN_GETOFS(val),T_int); case 3: return EventParameter("routethroughpatch",FWEELIN_GETOFS(echo),T_char); } return EventParameter(); }; int outport, // # of MIDI output to send event to channel, // MIDI channel val; // pitch bend value }; class MIDIKeyInputEvent : public Event { public: EVT_DEFINE(MIDIKeyInputEvent,T_EV_Input_MIDIKey); virtual void Recycle() { outport = 1; Event::Recycle(); }; virtual void operator = (const Event &src) { MIDIKeyInputEvent &s = (MIDIKeyInputEvent &) src; outport = s.outport; down = s.down; channel = s.channel; notenum = s.notenum; vel = s.vel; echo = s.echo; }; virtual int GetNumParams() { return 6; }; virtual EventParameter GetParam(int n) { switch (n) { case 0: return EventParameter("outport",FWEELIN_GETOFS(outport),T_int); case 1: return EventParameter("keydown",FWEELIN_GETOFS(down),T_char); case 2: return EventParameter("midichannel",FWEELIN_GETOFS(channel),T_int, MAX_MIDI_CHANNELS); case 3: return EventParameter("notenum",FWEELIN_GETOFS(notenum),T_int); case 4: return EventParameter("velocity",FWEELIN_GETOFS(vel),T_int); case 5: return EventParameter("routethroughpatch",FWEELIN_GETOFS(echo),T_char); } return EventParameter(); }; char down; // Nonzero if key is pressed, zero if key is released int outport, // # of MIDI output to send event to channel, // MIDI channel notenum, // note number vel; // velocity }; class MIDIClockInputEvent : public Event { public: EVT_DEFINE(MIDIClockInputEvent,T_EV_Input_MIDIClock); virtual void Recycle() { outport = 1; Event::Recycle(); }; virtual void operator = (const Event &src) { MIDIClockInputEvent &s = (MIDIClockInputEvent &) src; outport = s.outport; }; virtual int GetNumParams() { return 1; }; virtual EventParameter GetParam(int n) { switch (n) { case 0: return EventParameter("outport",FWEELIN_GETOFS(outport),T_int); } return EventParameter(); }; int outport; // # of MIDI output to send event to }; class MIDIStartStopInputEvent : public Event { public: EVT_DEFINE(MIDIStartStopInputEvent,T_EV_Input_MIDIStartStop); virtual void Recycle() { outport = 1; start = 0; Event::Recycle(); }; virtual void operator = (const Event &src) { MIDIStartStopInputEvent &s = (MIDIStartStopInputEvent &) src; outport = s.outport; start = s.start; }; virtual int GetNumParams() { return 2; }; virtual EventParameter GetParam(int n) { switch (n) { case 0: return EventParameter("outport",FWEELIN_GETOFS(outport),T_int); case 1: return EventParameter("start",FWEELIN_GETOFS(start),T_char); } return EventParameter(); }; int outport; // # of MIDI output to send event to char start; // 1- MIDI Start, 0- MIDI Stop }; class SetVariableEvent : public Event { public: EVT_DEFINE(SetVariableEvent,T_EV_SetVariable); virtual void Recycle() { maxjumpcheck = 0; Event::Recycle(); }; virtual void operator = (const Event &src) { SetVariableEvent &s = (SetVariableEvent &) src; var = s.var; value.type = s.value.type; value = s.value; maxjumpcheck = s.maxjumpcheck; maxjump.type = s.maxjump.type; maxjump = s.maxjump; }; virtual int GetNumParams() { return 4; }; virtual EventParameter GetParam(int n) { switch (n) { case 0: return EventParameter("var",FWEELIN_GETOFS(var),T_variableref); case 1: return EventParameter("value",FWEELIN_GETOFS(value),T_variable); case 2: return EventParameter("maxjumpcheck",FWEELIN_GETOFS(maxjumpcheck),T_char); case 3: return EventParameter("maxjump",FWEELIN_GETOFS(maxjump),T_variable); } return EventParameter(); }; UserVariable *var; // Variable to set UserVariable value, // Value to set it to maxjump; // Maximum jump in variable between current value and new value // Jumps beyond maxjump cause the variable not to be set char maxjumpcheck; // Nonzero if we should check variable change against maxjump- // If maxjumpcheck is zero, the variable is always set }; class ToggleVariableEvent : public Event { public: EVT_DEFINE(ToggleVariableEvent,T_EV_ToggleVariable); virtual void Recycle() { maxvalue = 1; minvalue = 0; Event::Recycle(); }; virtual void operator = (const Event &src) { ToggleVariableEvent &s = (ToggleVariableEvent &) src; var = s.var; maxvalue = s.maxvalue; minvalue = s.minvalue; }; virtual int GetNumParams() { return 3; }; virtual EventParameter GetParam(int n) { switch (n) { case 0: return EventParameter("var",FWEELIN_GETOFS(var),T_variableref); case 1: return EventParameter("maxvalue",FWEELIN_GETOFS(maxvalue),T_int); case 2: return EventParameter("minvalue",FWEELIN_GETOFS(minvalue),T_int); } return EventParameter(); }; UserVariable *var; // Variable to increment (toggle) int maxvalue, // Maximum value of variable before wraparound minvalue; // Value to wrap to }; class SplitVariableMSBLSBEvent : public Event { public: EVT_DEFINE(SplitVariableMSBLSBEvent,T_EV_SplitVariableMSBLSB); virtual void Recycle() { Event::Recycle(); }; virtual void operator = (const Event &src) { SplitVariableMSBLSBEvent &s = (SplitVariableMSBLSBEvent &) src; var = s.var; msb = s.msb; lsb = s.lsb; }; virtual int GetNumParams() { return 3; }; virtual EventParameter GetParam(int n) { switch (n) { case 0: return EventParameter("var",FWEELIN_GETOFS(var),T_variable); case 1: return EventParameter("msb",FWEELIN_GETOFS(msb),T_variableref); case 2: return EventParameter("lsb",FWEELIN_GETOFS(lsb),T_variableref); } return EventParameter(); }; UserVariable var; // Variable to split UserVariable *msb, // MSB of var will be stored here *lsb; // LSB of var will be stored here. var is unchanged }; class ParamSetGetAbsoluteParamIdxEvent : public Event { public: EVT_DEFINE_NO_CONSTR(ParamSetGetAbsoluteParamIdxEvent,T_EV_ParamSetGetAbsoluteParamIdx); ParamSetGetAbsoluteParamIdxEvent() { Recycle(); }; virtual void Recycle() { interfaceid = -1; displayid = 0; paramidx = 0; Event::Recycle(); }; virtual void operator = (const Event &src) { ParamSetGetAbsoluteParamIdxEvent &s = (ParamSetGetAbsoluteParamIdxEvent &) src; interfaceid = s.interfaceid; displayid = s.displayid; paramidx = s.paramidx; absidx = s.absidx; }; virtual int GetNumParams() { return 4; }; virtual EventParameter GetParam(int n) { switch (n) { case 0: return EventParameter(INTERFACEID,FWEELIN_GETOFS(interfaceid),T_int); case 1: return EventParameter("displayid",FWEELIN_GETOFS(displayid),T_int); case 2: return EventParameter("paramidx",FWEELIN_GETOFS(paramidx),T_int); case 3: return EventParameter("absidx",FWEELIN_GETOFS(absidx),T_variableref); } return EventParameter(); }; int interfaceid, // Interface in which parameter set display is defined displayid, // Display ID of parameter set display paramidx; // Relative index of parameter UserVariable *absidx; // Absolute index of parameter will be stored in absidx }; class ParamSetGetParamEvent : public Event { public: EVT_DEFINE_NO_CONSTR(ParamSetGetParamEvent,T_EV_ParamSetGetParam); ParamSetGetParamEvent() { Recycle(); }; virtual void Recycle() { interfaceid = -1; displayid = 0; paramidx = 0; Event::Recycle(); }; virtual void operator = (const Event &src) { ParamSetGetParamEvent &s = (ParamSetGetParamEvent &) src; interfaceid = s.interfaceid; displayid = s.displayid; paramidx = s.paramidx; var = s.var; }; virtual int GetNumParams() { return 4; }; virtual EventParameter GetParam(int n) { switch (n) { case 0: return EventParameter(INTERFACEID,FWEELIN_GETOFS(interfaceid),T_int); case 1: return EventParameter("displayid",FWEELIN_GETOFS(displayid),T_int); case 2: return EventParameter("paramidx",FWEELIN_GETOFS(paramidx),T_int); case 3: return EventParameter("var",FWEELIN_GETOFS(var),T_variableref); } return EventParameter(); }; int interfaceid, // Interface in which parameter set display is defined displayid, // Display ID of parameter set display paramidx; // Index of parameter to get (relative to the first parameter of the active page in the active bank) UserVariable *var; // Variable to use to store value of parameter }; class ParamSetSetParamEvent : public Event { public: EVT_DEFINE_NO_CONSTR(ParamSetSetParamEvent,T_EV_ParamSetSetParam); ParamSetSetParamEvent() { Recycle(); }; virtual void Recycle() { interfaceid = -1; displayid = 0; paramidx = 0; Event::Recycle(); }; virtual void operator = (const Event &src) { ParamSetSetParamEvent &s = (ParamSetSetParamEvent &) src; interfaceid = s.interfaceid; displayid = s.displayid; paramidx = s.paramidx; value = s.value; }; virtual int GetNumParams() { return 4; }; virtual EventParameter GetParam(int n) { switch (n) { case 0: return EventParameter(INTERFACEID,FWEELIN_GETOFS(interfaceid),T_int); case 1: return EventParameter("displayid",FWEELIN_GETOFS(displayid),T_int); case 2: return EventParameter("paramidx",FWEELIN_GETOFS(paramidx),T_int); case 3: return EventParameter("value",FWEELIN_GETOFS(value),T_float); } return EventParameter(); }; int interfaceid, // Interface in which parameter set display is defined displayid, // Display ID of parameter set display paramidx; // Index of parameter to set (relative to the first parameter of the active page in the active bank) float value; // Value to store in parameter }; class LogFaderVolToLinearEvent : public Event { public: EVT_DEFINE(LogFaderVolToLinearEvent,T_EV_LogFaderVolToLinear); virtual void Recycle() { Event::Recycle(); }; virtual void operator = (const Event &src) { LogFaderVolToLinearEvent &s = (LogFaderVolToLinearEvent &) src; var = s.var; fadervol.type = s.fadervol.type; fadervol = s.fadervol; scale = s.scale; }; virtual int GetNumParams() { return 3; }; virtual EventParameter GetParam(int n) { switch (n) { case 0: return EventParameter("var",FWEELIN_GETOFS(var),T_variableref); case 1: return EventParameter("fadervol",FWEELIN_GETOFS(fadervol),T_variable); case 2: return EventParameter("scale",FWEELIN_GETOFS(scale),T_float); } return EventParameter(); }; UserVariable *var; // Variable to store converted fadervol UserVariable fadervol; // Fader volume to convert to linear float scale; // Scaling factor for linear output - ie 0.0dB on the // fader becomes 'scale'. For example, if scale is 16384, // 0.0dB on the fader is 16384 and 6.0dB on the fader is // roughly 32768. Note that fadervol is not actually // a dB value, but a 'fadervol', which is a value between // 0 and 1 which corresponds to the throw of a // log volume fader. Please see AudioLevel class. }; class ALSAMixerControlSetEvent : public Event { public: EVT_DEFINE(ALSAMixerControlSetEvent,T_EV_ALSAMixerControlSet); virtual void Recycle() { hwid = 0; numid = -1; val1 = -1; val2 = -1; val3 = -1; val4 = -1; Event::Recycle(); }; virtual void operator = (const Event &src) { ALSAMixerControlSetEvent &s = (ALSAMixerControlSetEvent &) src; hwid = s.hwid; numid = s.numid; val1 = s.val1; val2 = s.val2; val3 = s.val3; val4 = s.val4; }; virtual int GetNumParams() { return 6; }; virtual EventParameter GetParam(int n) { switch (n) { case 0: return EventParameter("hwid",FWEELIN_GETOFS(hwid),T_int); case 1: return EventParameter("numid",FWEELIN_GETOFS(numid),T_int); case 2: return EventParameter("val1",FWEELIN_GETOFS(val1),T_int); case 3: return EventParameter("val2",FWEELIN_GETOFS(val2),T_int); case 4: return EventParameter("val3",FWEELIN_GETOFS(val3),T_int); case 5: return EventParameter("val4",FWEELIN_GETOFS(val4),T_int); } return EventParameter(); }; int hwid, // Hardware interface ID for alsa (ie hwid=0 is hw:0) numid; // ALSA mixer control numid (ie 'amixer cset numid=5') int val1, val2, val3, val4; // Values to set (up to 4, leave blank for fewer) }; class VideoShowLoopEvent : public Event { public: EVT_DEFINE_NO_CONSTR(VideoShowLoopEvent,T_EV_VideoShowLoop); VideoShowLoopEvent() : loopid(0,0) { Recycle(); }; virtual void Recycle() { interfaceid = -1; layoutid = 0; loopid = Range(0,0); Event::Recycle(); }; virtual void operator = (const Event &src) { VideoShowLoopEvent &s = (VideoShowLoopEvent &) src; interfaceid = s.interfaceid; layoutid = s.layoutid; loopid = s.loopid; }; virtual int GetNumParams() { return 3; }; virtual EventParameter GetParam(int n) { switch (n) { case 0: return EventParameter(INTERFACEID,FWEELIN_GETOFS(interfaceid),T_int); case 1: return EventParameter("layoutid",FWEELIN_GETOFS(layoutid),T_int); case 2: return EventParameter("loopid",FWEELIN_GETOFS(loopid),T_range); } return EventParameter(); }; int interfaceid, // Interface in which layout is defined layoutid; // Layout in which to show loops Range loopid; // Range of loop IDs that will be set to correspond to // elements in layout }; class VideoShowSnapshotPageEvent : public Event { public: EVT_DEFINE_NO_CONSTR(VideoShowSnapshotPageEvent,T_EV_VideoShowSnapshotPage); VideoShowSnapshotPageEvent() { Recycle(); }; virtual void Recycle() { interfaceid = -1; displayid = 0; page = 0; Event::Recycle(); }; virtual void operator = (const Event &src) { VideoShowSnapshotPageEvent &s = (VideoShowSnapshotPageEvent &) src; interfaceid = s.interfaceid; displayid = s.displayid; page = s.page; }; virtual int GetNumParams() { return 3; }; virtual EventParameter GetParam(int n) { switch (n) { case 0: return EventParameter(INTERFACEID,FWEELIN_GETOFS(interfaceid),T_int); case 1: return EventParameter("displayid",FWEELIN_GETOFS(displayid),T_int); case 2: return EventParameter("page",FWEELIN_GETOFS(page),T_int); } return EventParameter(); }; int interfaceid, // Interface in which snapshot display is defined displayid, // Display ID of snapshot display page; // +1 (next page) or -1 (previous page) }; class VideoShowParamSetBankEvent : public Event { public: EVT_DEFINE_NO_CONSTR(VideoShowParamSetBankEvent,T_EV_VideoShowParamSetBank); VideoShowParamSetBankEvent() { Recycle(); }; virtual void Recycle() { interfaceid = -1; displayid = 0; bank = 0; Event::Recycle(); }; virtual void operator = (const Event &src) { VideoShowParamSetBankEvent &s = (VideoShowParamSetBankEvent &) src; interfaceid = s.interfaceid; displayid = s.displayid; bank = s.bank; }; virtual int GetNumParams() { return 3; }; virtual EventParameter GetParam(int n) { switch (n) { case 0: return EventParameter(INTERFACEID,FWEELIN_GETOFS(interfaceid),T_int); case 1: return EventParameter("displayid",FWEELIN_GETOFS(displayid),T_int); case 2: return EventParameter("bank",FWEELIN_GETOFS(bank),T_int); } return EventParameter(); }; int interfaceid, // Interface in which parameter set display is defined displayid, // Display ID of parameter set display bank; // +1 (next bank of parameters) or -1 (previous bank) }; class VideoShowParamSetPageEvent : public Event { public: EVT_DEFINE_NO_CONSTR(VideoShowParamSetPageEvent,T_EV_VideoShowParamSetPage); VideoShowParamSetPageEvent() { Recycle(); }; virtual void Recycle() { interfaceid = -1; displayid = 0; page = 0; Event::Recycle(); }; virtual void operator = (const Event &src) { VideoShowParamSetPageEvent &s = (VideoShowParamSetPageEvent &) src; interfaceid = s.interfaceid; displayid = s.displayid; page = s.page; }; virtual int GetNumParams() { return 3; }; virtual EventParameter GetParam(int n) { switch (n) { case 0: return EventParameter(INTERFACEID,FWEELIN_GETOFS(interfaceid),T_int); case 1: return EventParameter("displayid",FWEELIN_GETOFS(displayid),T_int); case 2: return EventParameter("page",FWEELIN_GETOFS(page),T_int); } return EventParameter(); }; int interfaceid, // Interface in which parameter set display is defined displayid, // Display ID of parameter set display page; // +1 (next page of parameters) or -1 (previous page) }; class VideoShowLayoutEvent : public Event { public: EVT_DEFINE(VideoShowLayoutEvent,T_EV_VideoShowLayout); virtual void Recycle() { interfaceid = -1; layoutid = 0; show = 0; hideothers = 0; Event::Recycle(); }; virtual void operator = (const Event &src) { VideoShowLayoutEvent &s = (VideoShowLayoutEvent &) src; interfaceid = s.interfaceid; layoutid = s.layoutid; show = s.show; hideothers = s.hideothers; }; virtual int GetNumParams() { return 4; }; virtual EventParameter GetParam(int n) { switch (n) { case 0: return EventParameter(INTERFACEID,FWEELIN_GETOFS(interfaceid),T_int); case 1: return EventParameter("layoutid",FWEELIN_GETOFS(layoutid),T_int); case 2: return EventParameter("show",FWEELIN_GETOFS(show),T_char); case 3: return EventParameter("hideothers",FWEELIN_GETOFS(hideothers),T_char); } return EventParameter(); }; int interfaceid, // Interface in which layout is defined layoutid; // Layout to show char show, // Show it or hide it? hideothers; // Hide other layouts? }; class VideoSwitchInterfaceEvent : public Event { public: EVT_DEFINE(VideoSwitchInterfaceEvent,T_EV_VideoSwitchInterface); virtual void Recycle() { interfaceid = -1; Event::Recycle(); }; virtual void operator = (const Event &src) { VideoSwitchInterfaceEvent &s = (VideoSwitchInterfaceEvent &) src; interfaceid = s.interfaceid; }; virtual int GetNumParams() { return 1; }; virtual EventParameter GetParam(int n) { switch (n) { case 0: return EventParameter(INTERFACEID,FWEELIN_GETOFS(interfaceid),T_int); } return EventParameter(); }; int interfaceid; // Interface to switch to }; class VideoShowDisplayEvent : public Event { public: EVT_DEFINE(VideoShowDisplayEvent,T_EV_VideoShowDisplay); virtual void Recycle() { interfaceid = -1; displayid = 0; show = 0; Event::Recycle(); }; virtual void operator = (const Event &src) { VideoShowDisplayEvent &s = (VideoShowDisplayEvent &) src; interfaceid = s.interfaceid; displayid = s.displayid; show = s.show; }; virtual int GetNumParams() { return 3; }; virtual EventParameter GetParam(int n) { switch (n) { case 0: return EventParameter(INTERFACEID,FWEELIN_GETOFS(interfaceid),T_int); case 1: return EventParameter("displayid",FWEELIN_GETOFS(displayid),T_int); case 2: return EventParameter("show",FWEELIN_GETOFS(show),T_char); } return EventParameter(); }; int interfaceid, // Interface in which display is defined displayid; // Display to show char show; // Show it or hide it? }; class ShowDebugInfoEvent : public Event { public: EVT_DEFINE(ShowDebugInfoEvent,T_EV_ShowDebugInfo); virtual void Recycle() { show = 0; Event::Recycle(); }; virtual void operator = (const Event &src) { ShowDebugInfoEvent &s = (ShowDebugInfoEvent &) src; show = s.show; }; virtual int GetNumParams() { return 1; }; virtual EventParameter GetParam(int n) { switch (n) { case 0: return EventParameter("show",FWEELIN_GETOFS(show),T_char); } return EventParameter(); }; char show; // Show debugging info onscreen? }; class VideoShowHelpEvent : public Event { public: EVT_DEFINE(VideoShowHelpEvent,T_EV_VideoShowHelp); virtual void Recycle() { page = 0; Event::Recycle(); }; virtual void operator = (const Event &src) { VideoShowHelpEvent &s = (VideoShowHelpEvent &) src; page = s.page; }; virtual int GetNumParams() { return 1; }; virtual EventParameter GetParam(int n) { switch (n) { case 0: return EventParameter("page",FWEELIN_GETOFS(page),T_int); } return EventParameter(); }; int page; // Help page to show or 0 for no help }; class VideoFullScreenEvent : public Event { public: EVT_DEFINE(VideoFullScreenEvent,T_EV_VideoFullScreen); virtual void Recycle() { fullscreen = 0; Event::Recycle(); }; virtual void operator = (const Event &src) { VideoFullScreenEvent &s = (VideoFullScreenEvent &) src; fullscreen = s.fullscreen; }; virtual int GetNumParams() { return 1; }; virtual EventParameter GetParam(int n) { switch (n) { case 0: return EventParameter("fullscreen",FWEELIN_GETOFS(fullscreen), T_char); } return EventParameter(); }; char fullscreen; // Freewheeling is full screen or in a window? }; class StartSessionEvent : public Event { public: EVT_DEFINE(StartSessionEvent,T_EV_StartSession); }; class StartInterfaceEvent : public Event { public: EVT_DEFINE(StartInterfaceEvent,T_EV_StartInterface); virtual void Recycle() { interfaceid = -1; Event::Recycle(); }; virtual void operator = (const Event &src) { StartInterfaceEvent &s = (StartInterfaceEvent &) src; interfaceid = s.interfaceid; }; virtual int GetNumParams() { return 1; }; virtual EventParameter GetParam(int n) { switch (n) { case 0: return EventParameter(INTERFACEID,FWEELIN_GETOFS(interfaceid),T_int); } return EventParameter(); }; int interfaceid; // Interface to start }; class ExitSessionEvent : public Event { public: EVT_DEFINE(ExitSessionEvent,T_EV_ExitSession); }; class SlideMasterInVolumeEvent : public Event { public: EVT_DEFINE(SlideMasterInVolumeEvent,T_EV_SlideMasterInVolume); virtual void operator = (const Event &src) { SlideMasterInVolumeEvent &s = (SlideMasterInVolumeEvent &) src; slide = s.slide; }; virtual int GetNumParams() { return 1; }; virtual EventParameter GetParam(int n) { switch (n) { case 0: return EventParameter("slide",FWEELIN_GETOFS(slide),T_float); } return EventParameter(); }; float slide; // Change in speed of amplitude slide }; class SlideMasterOutVolumeEvent : public Event { public: EVT_DEFINE(SlideMasterOutVolumeEvent,T_EV_SlideMasterOutVolume); virtual void operator = (const Event &src) { SlideMasterOutVolumeEvent &s = (SlideMasterOutVolumeEvent &) src; slide = s.slide; }; virtual int GetNumParams() { return 1; }; virtual EventParameter GetParam(int n) { switch (n) { case 0: return EventParameter("slide",FWEELIN_GETOFS(slide),T_float); } return EventParameter(); }; float slide; // Change in speed of amplitude slide }; class SlideInVolumeEvent : public Event { public: EVT_DEFINE(SlideInVolumeEvent,T_EV_SlideInVolume); virtual void operator = (const Event &src) { SlideInVolumeEvent &s = (SlideInVolumeEvent &) src; input = s.input; slide = s.slide; }; virtual int GetNumParams() { return 2; }; virtual EventParameter GetParam(int n) { switch (n) { case 0: return EventParameter("input",FWEELIN_GETOFS(input),T_int); case 1: return EventParameter("slide",FWEELIN_GETOFS(slide),T_float); } return EventParameter(); }; int input; // Number of input to change volume for float slide; // Change in speed of amplitude slide }; class SetMasterInVolumeEvent : public Event { public: EVT_DEFINE(SetMasterInVolumeEvent,T_EV_SetMasterInVolume); virtual void Recycle() { vol = -1.; fadervol = -1.; Event::Recycle(); }; virtual void operator = (const Event &src) { SetMasterInVolumeEvent &s = (SetMasterInVolumeEvent &) src; vol = s.vol; fadervol = s.fadervol; }; virtual int GetNumParams() { return 2; }; virtual EventParameter GetParam(int n) { switch (n) { case 0: return EventParameter("vol",FWEELIN_GETOFS(vol),T_float); case 1: return EventParameter("fadervol",FWEELIN_GETOFS(fadervol),T_float); } return EventParameter(); }; float vol, // Linear volume to set fadervol; // Logarithmic volume to set (by fader throw) }; class SetMasterOutVolumeEvent : public Event { public: EVT_DEFINE(SetMasterOutVolumeEvent,T_EV_SetMasterOutVolume); virtual void Recycle() { vol = -1.; fadervol = -1.; Event::Recycle(); }; virtual void operator = (const Event &src) { SetMasterOutVolumeEvent &s = (SetMasterOutVolumeEvent &) src; vol = s.vol; fadervol = s.fadervol; }; virtual int GetNumParams() { return 2; }; virtual EventParameter GetParam(int n) { switch (n) { case 0: return EventParameter("vol",FWEELIN_GETOFS(vol),T_float); case 1: return EventParameter("fadervol",FWEELIN_GETOFS(fadervol),T_float); } return EventParameter(); }; float vol, // Linear volume to set fadervol; // Logarithmic volume to set (by fader throw) }; class SetInVolumeEvent : public Event { public: EVT_DEFINE(SetInVolumeEvent,T_EV_SetInVolume); virtual void Recycle() { input = 1; vol = -1.; fadervol = -1.; Event::Recycle(); }; virtual void operator = (const Event &src) { SetInVolumeEvent &s = (SetInVolumeEvent &) src; input = s.input; vol = s.vol; fadervol = s.fadervol; }; virtual int GetNumParams() { return 3; }; virtual EventParameter GetParam(int n) { switch (n) { case 0: return EventParameter("input",FWEELIN_GETOFS(input),T_int); case 1: return EventParameter("vol",FWEELIN_GETOFS(vol),T_float); case 2: return EventParameter("fadervol",FWEELIN_GETOFS(fadervol),T_float); } return EventParameter(); }; int input; // Number of input to change volume for float vol, // Linear volume to set fadervol; // Logarithmic volume to set (by fader throw) }; class ToggleInputRecordEvent : public Event { public: EVT_DEFINE(ToggleInputRecordEvent,T_EV_ToggleInputRecord); virtual void operator = (const Event &src) { ToggleInputRecordEvent &s = (ToggleInputRecordEvent &) src; input = s.input; }; virtual int GetNumParams() { return 1; }; virtual EventParameter GetParam(int n) { switch (n) { case 0: return EventParameter("input",FWEELIN_GETOFS(input),T_int); } return EventParameter(); }; int input; // Number of input to toggle for recording }; class SetMidiEchoPortEvent : public Event { public: EVT_DEFINE(SetMidiEchoPortEvent,T_EV_SetMidiEchoPort); virtual void operator = (const Event &src) { SetMidiEchoPortEvent &s = (SetMidiEchoPortEvent &) src; echoport = s.echoport; }; virtual int GetNumParams() { return 1; }; virtual EventParameter GetParam(int n) { switch (n) { case 0: return EventParameter("echoport",FWEELIN_GETOFS(echoport),T_int); } return EventParameter(); }; int echoport; // Port # to echo MIDI events to or 0 for disable echo }; class SetMidiEchoChannelEvent : public Event { public: EVT_DEFINE(SetMidiEchoChannelEvent,T_EV_SetMidiEchoChannel); virtual void operator = (const Event &src) { SetMidiEchoChannelEvent &s = (SetMidiEchoChannelEvent &) src; echochannel = s.echochannel; }; virtual int GetNumParams() { return 1; }; virtual EventParameter GetParam(int n) { switch (n) { case 0: return EventParameter("echochannel",FWEELIN_GETOFS(echochannel),T_int); } return EventParameter(); }; int echochannel; // Override MIDI channel for MIDI event echo // (-1 to leave as is) }; class AdjustMidiTransposeEvent : public Event { public: EVT_DEFINE(AdjustMidiTransposeEvent,T_EV_AdjustMidiTranspose); virtual void operator = (const Event &src) { AdjustMidiTransposeEvent &s = (AdjustMidiTransposeEvent &) src; adjust = s.adjust; }; virtual int GetNumParams() { return 1; }; virtual EventParameter GetParam(int n) { switch (n) { case 0: return EventParameter("adjust",FWEELIN_GETOFS(adjust),T_int); } return EventParameter(); }; int adjust; // Number of semitones to add to MIDI transpose }; class FluidSynthEnableEvent : public Event { public: EVT_DEFINE(FluidSynthEnableEvent,T_EV_FluidSynthEnable); virtual void operator = (const Event &src) { FluidSynthEnableEvent &s = (FluidSynthEnableEvent &) src; enable = s.enable; }; virtual int GetNumParams() { return 1; }; virtual EventParameter GetParam(int n) { switch (n) { case 0: return EventParameter("enable",FWEELIN_GETOFS(enable),T_char); } return EventParameter(); }; char enable; // FluidSynth enabled? }; class SetMidiTuningEvent : public Event { public: EVT_DEFINE(SetMidiTuningEvent,T_EV_SetMidiTuning); virtual void Recycle() { tuning = 0; Event::Recycle(); }; virtual void operator = (const Event &src) { SetMidiTuningEvent &s = (SetMidiTuningEvent &) src; tuning = s.tuning; }; virtual int GetNumParams() { return 1; }; virtual EventParameter GetParam(int n) { switch (n) { case 0: return EventParameter("tuning",FWEELIN_GETOFS(tuning),T_int); } return EventParameter(); }; int tuning; // New offset of 0 position for pitch bender- // shifts whole pitch bend by this value }; class SetTriggerVolumeEvent : public Event { public: EVT_DEFINE(SetTriggerVolumeEvent,T_EV_SetTriggerVolume); virtual void operator = (const Event &src) { SetTriggerVolumeEvent &s = (SetTriggerVolumeEvent &) src; index = s.index; vol = s.vol; }; virtual int GetNumParams() { return 2; }; virtual EventParameter GetParam(int n) { switch (n) { case 0: return EventParameter("loopid",FWEELIN_GETOFS(index),T_int); case 1: return EventParameter("vol",FWEELIN_GETOFS(vol),T_float); } return EventParameter(); }; int index; // Index of loop to set trigger volume for float vol; // New trigger volume }; class SlideLoopAmpEvent : public Event { public: EVT_DEFINE(SlideLoopAmpEvent,T_EV_SlideLoopAmp); virtual void operator = (const Event &src) { SlideLoopAmpEvent &s = (SlideLoopAmpEvent &) src; index = s.index; slide = s.slide; }; virtual int GetNumParams() { return 2; }; virtual EventParameter GetParam(int n) { switch (n) { case 0: return EventParameter("loopid",FWEELIN_GETOFS(index),T_int); case 1: return EventParameter("slide",FWEELIN_GETOFS(slide),T_float); } return EventParameter(); }; int index; // Index of loop to slide amplitude for float slide; // Change in speed of slide }; class SetLoopAmpEvent : public Event { public: EVT_DEFINE(SetLoopAmpEvent,T_EV_SetLoopAmp); virtual void operator = (const Event &src) { SetLoopAmpEvent &s = (SetLoopAmpEvent &) src; index = s.index; amp = s.amp; }; virtual int GetNumParams() { return 2; }; virtual EventParameter GetParam(int n) { switch (n) { case 0: return EventParameter("loopid",FWEELIN_GETOFS(index),T_int); case 1: return EventParameter("amp",FWEELIN_GETOFS(amp),T_float); } return EventParameter(); }; int index; // Index of loop to set amplitude for float amp; // Amplitude to set loop at }; class AdjustLoopAmpEvent : public Event { public: EVT_DEFINE(AdjustLoopAmpEvent,T_EV_AdjustLoopAmp); virtual void operator = (const Event &src) { AdjustLoopAmpEvent &s = (AdjustLoopAmpEvent &) src; index = s.index; ampfactor = s.ampfactor; }; virtual int GetNumParams() { return 2; }; virtual EventParameter GetParam(int n) { switch (n) { case 0: return EventParameter("loopid",FWEELIN_GETOFS(index),T_int); case 1: return EventParameter("ampfactor",FWEELIN_GETOFS(ampfactor),T_float); } return EventParameter(); }; int index; // Index of loop to adjust amplitude for float ampfactor; // Factor to multiply loop amplitudesby }; class TriggerLoopEvent : public Event { public: EVT_DEFINE(TriggerLoopEvent,T_EV_TriggerLoop); virtual void Recycle() { index = 0; vol = 1.0; engage = -1; shot = 0; od = 0; od_fb = 0; Event::Recycle(); }; virtual void operator = (const Event &src) { TriggerLoopEvent &s = (TriggerLoopEvent &) src; index = s.index; vol = s.vol; engage = s.engage; shot = s.shot; od = s.od; od_fb = s.od_fb; }; virtual int GetNumParams() { return 6; }; virtual EventParameter GetParam(int n) { switch (n) { case 0: return EventParameter("loopid",FWEELIN_GETOFS(index),T_int); case 1: return EventParameter("engage",FWEELIN_GETOFS(engage),T_int); case 2: return EventParameter("shot",FWEELIN_GETOFS(shot),T_char); case 3: return EventParameter("vol",FWEELIN_GETOFS(vol),T_float); case 4: return EventParameter("overdub",FWEELIN_GETOFS(od),T_char); case 5: return EventParameter("overdubfeedback",FWEELIN_GETOFS(od_fb),T_variableref); } return EventParameter(); }; int index; // Index of loop int engage; // -1 is the default behavior, where each trigger-loop // event toggles between rec/play and off // 0 forces the loop to off // 1 forces the loop to on char shot; // Nonzero if we should only play thru once- no loop float vol; // Volume of trigger char od; // Nonzero if we should trigger an overdub UserVariable *od_fb; // Variable which holds overdub feedback- can be continuously varied }; class MoveLoopEvent : public Event { public: EVT_DEFINE(MoveLoopEvent,T_EV_MoveLoop); virtual void operator = (const Event &src) { MoveLoopEvent &s = (MoveLoopEvent &) src; oldloopid = s.oldloopid; newloopid = s.newloopid; }; virtual int GetNumParams() { return 2; }; virtual EventParameter GetParam(int n) { switch (n) { case 0: return EventParameter("oldloopid",FWEELIN_GETOFS(oldloopid),T_int); case 1: return EventParameter("newloopid",FWEELIN_GETOFS(newloopid),T_int); } return EventParameter(); }; int oldloopid, // Old index of loop newloopid; // New index of loop }; class EraseLoopEvent : public Event { public: EVT_DEFINE(EraseLoopEvent,T_EV_EraseLoop); virtual void operator = (const Event &src) { EraseLoopEvent &s = (EraseLoopEvent &) src; index = s.index; }; virtual int GetNumParams() { return 1; }; virtual EventParameter GetParam(int n) { switch (n) { case 0: return EventParameter("loopid",FWEELIN_GETOFS(index),T_int); } return EventParameter(); }; int index; // Index of loop }; class EraseAllLoopsEvent : public Event { public: EVT_DEFINE(EraseAllLoopsEvent,T_EV_EraseAllLoops); }; class EraseSelectedLoopsEvent : public Event { public: EVT_DEFINE(EraseSelectedLoopsEvent,T_EV_EraseSelectedLoops); virtual void Recycle() { setid = 0; Event::Recycle(); }; virtual void operator = (const Event &src) { EraseSelectedLoopsEvent &s = (EraseSelectedLoopsEvent &) src; setid = s.setid; }; virtual int GetNumParams() { return 1; }; virtual EventParameter GetParam(int n) { switch (n) { case 0: return EventParameter("setid",FWEELIN_GETOFS(setid),T_int); } return EventParameter(); }; int setid; // ID # of the selection set to work on }; class SlideLoopAmpStopAllEvent : public Event { public: EVT_DEFINE(SlideLoopAmpStopAllEvent,T_EV_SlideLoopAmpStopAll); }; class ToggleDiskOutputEvent : public Event { public: EVT_DEFINE(ToggleDiskOutputEvent,T_EV_ToggleDiskOutput); }; class SetAutoLoopSavingEvent : public Event { public: EVT_DEFINE(SetAutoLoopSavingEvent,T_EV_SetAutoLoopSaving); virtual void operator = (const Event &src) { SetAutoLoopSavingEvent &s = (SetAutoLoopSavingEvent &) src; save = s.save; }; virtual int GetNumParams() { return 1; }; virtual EventParameter GetParam(int n) { switch (n) { case 0: return EventParameter("save",FWEELIN_GETOFS(save),T_char); } return EventParameter(); }; char save; // Are we autosaving loops? }; class SaveLoopEvent : public Event { public: EVT_DEFINE(SaveLoopEvent,T_EV_SaveLoop); virtual void operator = (const Event &src) { SaveLoopEvent &s = (SaveLoopEvent &) src; index = s.index; }; virtual int GetNumParams() { return 1; }; virtual EventParameter GetParam(int n) { switch (n) { case 0: return EventParameter("loopid",FWEELIN_GETOFS(index),T_int); } return EventParameter(); }; int index; // Index of loop to save }; class SaveNewSceneEvent : public Event { public: EVT_DEFINE(SaveNewSceneEvent,T_EV_SaveNewScene); }; class SaveCurrentSceneEvent : public Event { public: EVT_DEFINE(SaveCurrentSceneEvent,T_EV_SaveCurrentScene); }; class SetLoadLoopIdEvent : public Event { public: EVT_DEFINE(SetLoadLoopIdEvent,T_EV_SetLoadLoopId); virtual void operator = (const Event &src) { SetLoadLoopIdEvent &s = (SetLoadLoopIdEvent &) src; index = s.index; }; virtual int GetNumParams() { return 1; }; virtual EventParameter GetParam(int n) { switch (n) { case 0: return EventParameter("loopid",FWEELIN_GETOFS(index),T_int); } return EventParameter(); }; int index; // Index to load loops into }; class SetDefaultLoopPlacementEvent : public Event { public: EVT_DEFINE_NO_CONSTR(SetDefaultLoopPlacementEvent, T_EV_SetDefaultLoopPlacement); SetDefaultLoopPlacementEvent() : looprange(0,0) { Recycle(); }; virtual void Recycle() { looprange = Range(0,0); Event::Recycle(); }; virtual void operator = (const Event &src) { SetDefaultLoopPlacementEvent &s = (SetDefaultLoopPlacementEvent &) src; looprange = s.looprange; }; virtual int GetNumParams() { return 1; }; virtual EventParameter GetParam(int n) { switch (n) { case 0: return EventParameter("looprange",FWEELIN_GETOFS(looprange),T_range); } return EventParameter(); }; Range looprange; // Range of loop IDs to be used when others are full }; class BrowserMoveToItemEvent : public Event { public: EVT_DEFINE(BrowserMoveToItemEvent,T_EV_BrowserMoveToItem); virtual void Recycle() { browserid = -1; adjust = 0; jumpadjust = 0; Event::Recycle(); }; virtual void operator = (const Event &src) { BrowserMoveToItemEvent &s = (BrowserMoveToItemEvent &) src; browserid = s.browserid; adjust = s.adjust; jumpadjust = s.jumpadjust; }; virtual int GetNumParams() { return 3; }; virtual EventParameter GetParam(int n) { switch (n) { case 0: return EventParameter("browserid",FWEELIN_GETOFS(browserid),T_int); case 1: return EventParameter("adjust",FWEELIN_GETOFS(adjust),T_int); case 2: return EventParameter("jumpadjust",FWEELIN_GETOFS(jumpadjust),T_int); } return EventParameter(); }; int browserid; // Display ID of browser int adjust; // Move fwd/back by adjust items int jumpadjust; // Jump fwd/back by jumpadjust divisions }; class BrowserMoveToItemAbsoluteEvent : public Event { public: EVT_DEFINE(BrowserMoveToItemAbsoluteEvent,T_EV_BrowserMoveToItemAbsolute); virtual void Recycle() { browserid = -1; idx = 0; Event::Recycle(); }; virtual void operator = (const Event &src) { BrowserMoveToItemAbsoluteEvent &s = (BrowserMoveToItemAbsoluteEvent &) src; browserid = s.browserid; idx = s.idx; }; virtual int GetNumParams() { return 2; }; virtual EventParameter GetParam(int n) { switch (n) { case 0: return EventParameter("browserid",FWEELIN_GETOFS(browserid),T_int); case 1: return EventParameter("idx",FWEELIN_GETOFS(idx),T_int); } return EventParameter(); }; int browserid; // Display ID of browser int idx; // Index to move to (absolute from beginning of list) }; class BrowserSelectItemEvent : public Event { public: EVT_DEFINE(BrowserSelectItemEvent,T_EV_BrowserSelectItem); virtual void Recycle() { browserid = -1; Event::Recycle(); }; virtual void operator = (const Event &src) { BrowserSelectItemEvent &s = (BrowserSelectItemEvent &) src; browserid = s.browserid; }; virtual int GetNumParams() { return 1; }; virtual EventParameter GetParam(int n) { switch (n) { case 0: return EventParameter("browserid",FWEELIN_GETOFS(browserid),T_int); } return EventParameter(); }; int browserid; // Display ID of browser }; class BrowserRenameItemEvent : public Event { public: EVT_DEFINE(BrowserRenameItemEvent,T_EV_BrowserRenameItem); virtual void Recycle() { browserid = -1; Event::Recycle(); }; virtual void operator = (const Event &src) { BrowserRenameItemEvent &s = (BrowserRenameItemEvent &) src; browserid = s.browserid; }; virtual int GetNumParams() { return 1; }; virtual EventParameter GetParam(int n) { switch (n) { case 0: return EventParameter("browserid",FWEELIN_GETOFS(browserid),T_int); } return EventParameter(); }; int browserid; // Display ID of browser }; class BrowserItemBrowsedEvent : public Event { public: EVT_DEFINE(BrowserItemBrowsedEvent,T_EV_BrowserItemBrowsed); virtual void Recycle() { browserid = -1; Event::Recycle(); }; virtual void operator = (const Event &src) { BrowserItemBrowsedEvent &s = (BrowserItemBrowsedEvent &) src; browserid = s.browserid; }; virtual int GetNumParams() { return 1; }; virtual EventParameter GetParam(int n) { switch (n) { case 0: return EventParameter("browserid",FWEELIN_GETOFS(browserid),T_int); } return EventParameter(); }; int browserid; // Display ID of browser }; class PatchBrowserMoveToBankEvent : public Event { public: EVT_DEFINE(PatchBrowserMoveToBankEvent,T_EV_PatchBrowserMoveToBank); virtual void Recycle() { direction = 1; Event::Recycle(); }; virtual void operator = (const Event &src) { PatchBrowserMoveToBankEvent &s = (PatchBrowserMoveToBankEvent &) src; direction = s.direction; }; virtual int GetNumParams() { return 1; }; virtual EventParameter GetParam(int n) { switch (n) { case 0: return EventParameter("direction",FWEELIN_GETOFS(direction),T_int); } return EventParameter(); }; int direction; // Direction to move (+1/-1 next/previous) }; class PatchBrowserMoveToBankByIndexEvent : public Event { public: EVT_DEFINE(PatchBrowserMoveToBankByIndexEvent, T_EV_PatchBrowserMoveToBankByIndex); virtual void Recycle() { index = 0; Event::Recycle(); }; virtual void operator = (const Event &src) { PatchBrowserMoveToBankByIndexEvent &s = (PatchBrowserMoveToBankByIndexEvent &) src; index = s.index; }; virtual int GetNumParams() { return 1; }; virtual EventParameter GetParam(int n) { switch (n) { case 0: return EventParameter("index",FWEELIN_GETOFS(index),T_int); } return EventParameter(); }; int index; // Index of patchbank to choose }; class RenameLoopEvent : public Event { public: EVT_DEFINE(RenameLoopEvent,T_EV_RenameLoop); virtual void Recycle() { loopid = 0; in = 0; Event::Recycle(); }; virtual void operator = (const Event &src) { RenameLoopEvent &s = (RenameLoopEvent &) src; loopid = s.loopid; in = s.in; }; virtual int GetNumParams() { return 2; }; virtual EventParameter GetParam(int n) { switch (n) { case 0: return EventParameter("loopid",FWEELIN_GETOFS(loopid),T_int); case 1: return EventParameter("in",FWEELIN_GETOFS(in),T_char); } return EventParameter(); }; int loopid; // Loop ID to rename char in; // Rename in loop tray (0) or layout (1) }; class SelectPulseEvent : public Event { public: EVT_DEFINE(SelectPulseEvent,T_EV_SelectPulse); virtual void operator = (const Event &src) { SelectPulseEvent &s = (SelectPulseEvent &) src; pulse = s.pulse; }; virtual int GetNumParams() { return 1; }; virtual EventParameter GetParam(int n) { switch (n) { case 0: return EventParameter("pulse",FWEELIN_GETOFS(pulse),T_int); } return EventParameter(); }; int pulse; // Index of pulse }; class DeletePulseEvent : public Event { public: EVT_DEFINE(DeletePulseEvent,T_EV_DeletePulse); virtual void operator = (const Event &src) { DeletePulseEvent &s = (DeletePulseEvent &) src; pulse = s.pulse; }; virtual int GetNumParams() { return 1; }; virtual EventParameter GetParam(int n) { switch (n) { case 0: return EventParameter("pulse",FWEELIN_GETOFS(pulse),T_int); } return EventParameter(); }; int pulse; // Index of pulse }; class TapPulseEvent : public Event { public: EVT_DEFINE(TapPulseEvent,T_EV_TapPulse); virtual void operator = (const Event &src) { TapPulseEvent &s = (TapPulseEvent &) src; pulse = s.pulse; newlen = s.newlen; }; virtual int GetNumParams() { return 2; }; virtual EventParameter GetParam(int n) { switch (n) { case 0: return EventParameter("pulse",FWEELIN_GETOFS(pulse),T_int); case 1: return EventParameter("newlen",FWEELIN_GETOFS(newlen),T_char); } return EventParameter(); }; int pulse; // Index of pulse char newlen; // Nonzero to redefine pulse length or create new pulse }; class SwitchMetronomeEvent : public Event { public: EVT_DEFINE(SwitchMetronomeEvent,T_EV_SwitchMetronome); virtual void operator = (const Event &src) { SwitchMetronomeEvent &s = (SwitchMetronomeEvent &) src; pulse = s.pulse; metronome = s.metronome; }; virtual int GetNumParams() { return 2; }; virtual EventParameter GetParam(int n) { switch (n) { case 0: return EventParameter("pulse",FWEELIN_GETOFS(pulse),T_int); case 1: return EventParameter("metronome",FWEELIN_GETOFS(metronome),T_char); } return EventParameter(); }; int pulse; // Index of pulse char metronome; // Metronome active? }; class SetSyncTypeEvent : public Event { public: EVT_DEFINE(SetSyncTypeEvent,T_EV_SetSyncType); virtual void operator = (const Event &src) { SetSyncTypeEvent &s = (SetSyncTypeEvent &) src; stype = s.stype; }; virtual int GetNumParams() { return 1; }; virtual EventParameter GetParam(int n) { switch (n) { case 0: return EventParameter("type",FWEELIN_GETOFS(stype),T_char); } return EventParameter(); }; char stype; // Nonzero for beat sync, zero for bar sync }; class SetSyncSpeedEvent : public Event { public: EVT_DEFINE(SetSyncSpeedEvent,T_EV_SetSyncSpeed); virtual void operator = (const Event &src) { SetSyncSpeedEvent &s = (SetSyncSpeedEvent &) src; sspd = s.sspd; }; virtual int GetNumParams() { return 1; }; virtual EventParameter GetParam(int n) { switch (n) { case 0: return EventParameter("speed",FWEELIN_GETOFS(sspd),T_int); } return EventParameter(); }; int sspd; // Number of external transport beats/bars per internal pulse }; class SetMidiSyncEvent : public Event { public: EVT_DEFINE(SetMidiSyncEvent,T_EV_SetMidiSync); virtual void operator = (const Event &src) { SetMidiSyncEvent &s = (SetMidiSyncEvent &) src; midisync = s.midisync; }; virtual int GetNumParams() { return 1; }; virtual EventParameter GetParam(int n) { switch (n) { case 0: return EventParameter("midisync",FWEELIN_GETOFS(midisync),T_int); } return EventParameter(); }; int midisync; // Nonzero to transmit MIDI sync, zero for no MIDI sync }; class ToggleSelectLoopEvent : public Event { public: EVT_DEFINE(ToggleSelectLoopEvent,T_EV_ToggleSelectLoop); virtual void operator = (const Event &src) { ToggleSelectLoopEvent &s = (ToggleSelectLoopEvent &) src; setid = s.setid; loopid = s.loopid; }; virtual int GetNumParams() { return 2; }; virtual EventParameter GetParam(int n) { switch (n) { case 0: return EventParameter("setid",FWEELIN_GETOFS(setid),T_int); case 1: return EventParameter("loopid",FWEELIN_GETOFS(loopid),T_int); } return EventParameter(); }; int setid, // ID # of the selection set in which to toggle the loop loopid; // ID # of loop to toggle }; class SelectOnlyPlayingLoopsEvent : public Event { public: EVT_DEFINE(SelectOnlyPlayingLoopsEvent,T_EV_SelectOnlyPlayingLoops); virtual void operator = (const Event &src) { SelectOnlyPlayingLoopsEvent &s = (SelectOnlyPlayingLoopsEvent &) src; setid = s.setid; playing = s.playing; }; virtual int GetNumParams() { return 2; }; virtual EventParameter GetParam(int n) { switch (n) { case 0: return EventParameter("setid",FWEELIN_GETOFS(setid),T_int); case 1: return EventParameter("playing",FWEELIN_GETOFS(playing),T_char); } return EventParameter(); }; int setid; // ID # of the selection set to work on char playing; // Nonzero if we should select only those loops currently // playing-- zero if we should select only those loops // currently idle }; class SelectAllLoopsEvent : public Event { public: EVT_DEFINE(SelectAllLoopsEvent,T_EV_SelectAllLoops); virtual void operator = (const Event &src) { SelectAllLoopsEvent &s = (SelectAllLoopsEvent &) src; setid = s.setid; select = s.select; }; virtual int GetNumParams() { return 2; }; virtual EventParameter GetParam(int n) { switch (n) { case 0: return EventParameter("setid",FWEELIN_GETOFS(setid),T_int); case 1: return EventParameter("select",FWEELIN_GETOFS(select),T_char); } return EventParameter(); }; int setid; // ID # of the selection set to work on char select; // Nonzero to select/zero to unselect all loops }; class InvertSelectionEvent : public Event { public: EVT_DEFINE(InvertSelectionEvent,T_EV_InvertSelection); virtual void operator = (const Event &src) { InvertSelectionEvent &s = (InvertSelectionEvent &) src; setid = s.setid; }; virtual int GetNumParams() { return 1; }; virtual EventParameter GetParam(int n) { switch (n) { case 0: return EventParameter("setid",FWEELIN_GETOFS(setid),T_int); } return EventParameter(); }; int setid; // ID # of the selection set to invert (select all other loops) }; class CreateSnapshotEvent : public Event { public: EVT_DEFINE(CreateSnapshotEvent,T_EV_CreateSnapshot); virtual void Recycle() { snapid = 0; Event::Recycle(); }; virtual void operator = (const Event &src) { CreateSnapshotEvent &s = (CreateSnapshotEvent &) src; snapid = s.snapid; }; virtual int GetNumParams() { return 1; }; virtual EventParameter GetParam(int n) { switch (n) { case 0: return EventParameter("snapid",FWEELIN_GETOFS(snapid),T_int); } return EventParameter(); }; int snapid; // Create and store snapshot #snapid }; class SwapSnapshotsEvent : public Event { public: EVT_DEFINE(SwapSnapshotsEvent,T_EV_SwapSnapshots); virtual void Recycle() { snapid1 = 0; snapid2 = 0; Event::Recycle(); }; virtual void operator = (const Event &src) { SwapSnapshotsEvent &s = (SwapSnapshotsEvent &) src; snapid1 = s.snapid1; snapid2 = s.snapid2; }; virtual int GetNumParams() { return 2; }; virtual EventParameter GetParam(int n) { switch (n) { case 0: return EventParameter("snapid1",FWEELIN_GETOFS(snapid1),T_int); case 1: return EventParameter("snapid2",FWEELIN_GETOFS(snapid2),T_int); } return EventParameter(); }; int snapid1, snapid2; // Swap these two snapshots }; class RenameSnapshotEvent : public Event { public: EVT_DEFINE(RenameSnapshotEvent,T_EV_RenameSnapshot); virtual void Recycle() { snapid = 0; Event::Recycle(); }; virtual void operator = (const Event &src) { RenameSnapshotEvent &s = (RenameSnapshotEvent &) src; snapid = s.snapid; }; virtual int GetNumParams() { return 1; }; virtual EventParameter GetParam(int n) { switch (n) { case 0: return EventParameter("snapid",FWEELIN_GETOFS(snapid),T_int); } return EventParameter(); }; int snapid; // Rename snapshot #snapid }; class TriggerSnapshotEvent : public Event { public: EVT_DEFINE(TriggerSnapshotEvent,T_EV_TriggerSnapshot); virtual void Recycle() { snapid = 0; Event::Recycle(); }; virtual void operator = (const Event &src) { TriggerSnapshotEvent &s = (TriggerSnapshotEvent &) src; snapid = s.snapid; }; virtual int GetNumParams() { return 1; }; virtual EventParameter GetParam(int n) { switch (n) { case 0: return EventParameter("snapid",FWEELIN_GETOFS(snapid),T_int); } return EventParameter(); }; int snapid; // Trigger snapshot #snapid }; class TriggerSelectedLoopsEvent : public Event { public: EVT_DEFINE(TriggerSelectedLoopsEvent,T_EV_TriggerSelectedLoops); virtual void Recycle() { setid = 0; vol = 1.0; toggleloops = 0; Event::Recycle(); }; virtual void operator = (const Event &src) { TriggerSelectedLoopsEvent &s = (TriggerSelectedLoopsEvent &) src; setid = s.setid; vol = s.vol; toggleloops = s.toggleloops; }; virtual int GetNumParams() { return 3; }; virtual EventParameter GetParam(int n) { switch (n) { case 0: return EventParameter("setid",FWEELIN_GETOFS(setid),T_int); case 1: return EventParameter("vol",FWEELIN_GETOFS(vol),T_float); case 2: return EventParameter("toggleloops",FWEELIN_GETOFS(toggleloops),T_char); } return EventParameter(); }; int setid; // ID # of the selection set to work on float vol; // Volume at which to trigger selected loops char toggleloops; // Nonzero to toggle loops, zero to force active }; class SetSelectedLoopsTriggerVolumeEvent : public Event { public: EVT_DEFINE(SetSelectedLoopsTriggerVolumeEvent, T_EV_SetSelectedLoopsTriggerVolume); virtual void Recycle() { setid = 0; vol = 1.0; Event::Recycle(); }; virtual void operator = (const Event &src) { SetSelectedLoopsTriggerVolumeEvent &s = (SetSelectedLoopsTriggerVolumeEvent &) src; setid = s.setid; vol = s.vol; }; virtual int GetNumParams() { return 2; }; virtual EventParameter GetParam(int n) { switch (n) { case 0: return EventParameter("setid",FWEELIN_GETOFS(setid),T_int); case 1: return EventParameter("vol",FWEELIN_GETOFS(vol),T_float); } return EventParameter(); }; int setid; // ID # of the selection set to work on float vol; // Trigger volume to set for loops }; class AdjustSelectedLoopsAmpEvent : public Event { public: EVT_DEFINE(AdjustSelectedLoopsAmpEvent, T_EV_AdjustSelectedLoopsAmp); virtual void Recycle() { setid = 0; ampfactor = 1.0; Event::Recycle(); }; virtual void operator = (const Event &src) { AdjustSelectedLoopsAmpEvent &s = (AdjustSelectedLoopsAmpEvent &) src; setid = s.setid; ampfactor = s.ampfactor; }; virtual int GetNumParams() { return 2; }; virtual EventParameter GetParam(int n) { switch (n) { case 0: return EventParameter("setid",FWEELIN_GETOFS(setid),T_int); case 1: return EventParameter("ampfactor",FWEELIN_GETOFS(ampfactor),T_float); } return EventParameter(); }; int setid; // ID # of the selection set to work on float ampfactor; // Factor to multiply all loop amplitudes by }; class EndRecordEvent : public Event { public: EVT_DEFINE(EndRecordEvent,T_EV_EndRecord); // Nonzero if recording should be kept char keeprecord; }; // List refers to loops in memory or on disk- used by background save/load class LoopListEvent : public Event { public: EVT_DEFINE(LoopListEvent,T_EV_LoopList); virtual void Recycle() { l = 0; strcpy(l_filename,""); l_idx = 0; l_vol = 1.0; Event::Recycle(); }; Loop *l; // Loop // Filename of loop on disk // (note we have to copy the string) char l_filename[FWEELIN_OUTNAME_LEN]; int l_idx; // Index of loop in map float l_vol; // Volume to set loop to when loading }; class SceneMarkerEvent : public Event { public: EVT_DEFINE(SceneMarkerEvent,T_EV_SceneMarker); virtual void Recycle() { strcpy(s_filename,""); Event::Recycle(); }; char s_filename[FWEELIN_OUTNAME_LEN]; // Filename of scene on disk }; // This event is broadcast once on the downbeat of each pulse class PulseSyncEvent : public Event { public: EVT_DEFINE(PulseSyncEvent,T_EV_PulseSync); }; // TriggerSet is fired by TriggerMap whenever a change is made to the map // The LoopTray and potentially others listen for changes to the TriggerMap class TriggerSetEvent : public Event { public: EVT_DEFINE(TriggerSetEvent,T_EV_TriggerSet); int idx; // On index 'idx' Loop *nw; // ..we now have 'nw' }; // This event is added internally to RootProcessor's RT queue whenever a child processor should be // added to RootProcessor (ie recording/playing a loop) class AddProcessorEvent : public Event { public: EVT_DEFINE(AddProcessorEvent,T_EV_AddProcessor); ProcessorItem *new_processor; // Pointer to new processor item instance }; // This event is added internally to RootProcessor's RT queue whenever a child processor should be // deleted from RootProcessor (ie stop play/record/overdub) class DelProcessorEvent : public Event { public: EVT_DEFINE(DelProcessorEvent,T_EV_DelProcessor); ProcessorItem *processor; // ProcessorItem which holds processor to remove }; // This event is called when a Processor's memory should be freed class CleanupProcessorEvent : public Event { public: EVT_DEFINE(CleanupProcessorEvent,T_EV_CleanupProcessor); ProcessorItem *processor; // ProcessorItem which holds processor to cleanup }; // TransmitPlayingLoopsToDAW can be used to send all playing // loops to a connected DAW via OSC // Only saved loops will be sent class TransmitPlayingLoopsToDAWEvent : public Event { public: EVT_DEFINE(TransmitPlayingLoopsToDAWEvent,T_EV_TransmitPlayingLoopsToDAW); }; // Consider making EventListenerItem a Preallocated type to improve performance // when adding/removing listeners-- this will happen more often now that // PulseSyncEvent and other BMG type tasks are being merged into EMG class EventListenerItem { public: EventListenerItem(EventListener *callwhom, EventProducer *eventsfrom, EventType oftype, char block_self_calls) : callwhom(callwhom), eventsfrom(eventsfrom), oftype(oftype), block_self_calls(block_self_calls), next(0) {}; // Call this listener.. EventListener *callwhom; // When events from this event producer.. EventProducer *eventsfrom; // And this type.. are produced EventType oftype; // If nonzero, this flag stops a producer's events from calling itself // if that producer is also a listener char block_self_calls; // Pointer to next list item EventListenerItem *next; }; // EventManager manages generic event types // Allows for sending & receiving of events between different // parts of the application-- which is useful because those // parts can then be loosely coupled through extensible modular event // types // // Events can be sent immediately in the same thread they are broadcast // Or they can be sent through a dispatch thread // // Events can be sent through RT safe methods.. the dispatch is // optimized by event type, to eliminate lengthy searches for // eventlisteners class EventManager { public: EventManager(); ~EventManager(); // Create ring buffers after ALL writer threads are created void FinalPrep(); // Event queue functions ** NO THREAD PROTECTION PROVIDED ** // These are good for single threaded queue/dequeue operations static Event *DeleteQueue(Event *first); static void QueueEvent(Event **first, Event *nw); static void RemoveEvent(Event **first, Event *prev, Event **cur); // Broadcast immediately (RT safe only if listeners' receive methods are RT safe - depends on event)! inline void BroadcastEventNow(Event *ev, EventProducer *source, char allowslowdelivery = 1, char deleteonsend = 1) { int evnum = (int) ev->GetType(); // Check if this event is slow-delivery only if (allowslowdelivery && Event::ett[evnum].slowdelivery) BroadcastEvent(ev,source); else { // Scan through the listeners to see who to call EventListenerItem *cur = listeners[evnum]; while (cur != 0) { if ((cur->eventsfrom == 0 && (!cur->block_self_calls || source != (void *) cur->callwhom)) || source == 0 || cur->eventsfrom == source) cur->callwhom->ReceiveEvent(ev,source); cur = cur->next; } // This event has been broadcast.. erase it!.. use RTDelete() if (deleteonsend) ev->RTDelete(); } }; // Broadcast through dispatch thread! // RT safe! -- so long as you allocate your event with RTNew() void BroadcastEvent(Event *ev, EventProducer *source); // Not RT safe, but threadsafe! // Listen for the given event (optionally from the given producer) and callme // when it occurs-- optionally, block calls from myself void ListenEvent(EventListener *callme, EventProducer *from, EventType type, char block_self_calls = 0); // Not RT safe, but threadsafe! void UnlistenEvent(EventListener *callme, EventProducer *from, EventType type); // Wakeup the event dispatch thread. Non blocking, RT safe. inline void WakeupIfNeeded(char always_wakeup = 0) { if (always_wakeup || needs_wakeup) { /* if (!always_wakeup) printf("EVENT: Woken because of priority inversion\n"); */ // Wake up the dispatch thread if (pthread_mutex_trylock (&dispatch_thread_lock) == 0) { pthread_cond_signal (&dispatch_ready); pthread_mutex_unlock (&dispatch_thread_lock); } else { // Priority inversion - we are interrupting the event dispatch thread while it's processing eq // This is not an issue, because eq uses SRMWRingBuffer. However, we the event dispatch thread // may go to sleep, missing the new messages until it's woken again. So, set a flag and the RT audio // thread will wake it up next process cycle. if (always_wakeup) { // printf("EVENT: WARNING: Priority inversion during event broadcast!\n"); // ,Event::ett[(int) ev->GetType()].name); needs_wakeup = 1; } } } }; private: static void *run_dispatch_thread (void *ptr); // For each event type, we store a list of listeners.. EventListenerItem **listeners; // Event queue- for calling listeners in lowpriority SRMWRingBuffer *eq; volatile char needs_wakeup; // Event dispatch thread needs wakeup? (priority inversion) pthread_t dispatch_thread; pthread_mutex_t dispatch_thread_lock, listener_list_lock; pthread_cond_t dispatch_ready; int threadgo; jack_ringbuffer_data_t asd; }; #endif freewheeling-0.6.6/src/fweelin_fluidsynth.cc000066400000000000000000000202661370736313100212010ustar00rootroot00000000000000/* Copyright 2004-2011 Jan Pekau This file is part of Freewheeling. Freewheeling is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. Freewheeling 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 Freewheeling. If not, see . */ #if USE_FLUIDSYNTH #include #include #include #include #include #include #include #include #include #include #include "fweelin_fluidsynth.h" void FluidSynthParam_Int::Send(fluid_settings_t *settings) { printf("FLUID: Setting parameter '%s' = '%d'\n",name,val); fluid_settings_setint(settings, name, val); }; void FluidSynthParam_Num::Send(fluid_settings_t *settings) { printf("FLUID: Setting parameter '%s' = '%f'\n",name,val); fluid_settings_setnum(settings, name, val); }; void FluidSynthParam_Str::Send(fluid_settings_t *settings) { printf("FLUID: Setting parameter '%s' = '%s'\n",name,val); fluid_settings_setstr(settings, name, val); }; FluidSynthProcessor::FluidSynthProcessor(Fweelin *app, char stereo) : Processor(app), stereo(stereo), enable(1) { nframes_t bufsz = app->getBUFSZ(); leftbuf = new sample_t[bufsz]; rightbuf = new sample_t[bufsz]; // Setup FluidSynth settings = new_fluid_settings(); { FluidSynthParam *cur = app->getCFG()->GetFluidParam(); while (cur != 0) { cur->Send(settings); cur = cur->next; } } // Set sampling rate fluid_settings_setnum(settings, "synth.sample-rate", app->getAUDIO()->get_srate()); // Create synth synth = new_fluid_synth(settings); // Set interpolation quality printf("FLUID: Setting interpolation quality: %d\n", app->getCFG()->GetFluidInterpolation()); fluid_synth_set_interp_method(synth,-1, app->getCFG()->GetFluidInterpolation()); // User-specified global fluidsynth tuning float tuning = app->getCFG()->GetFluidTuning(); if (tuning != 0.0) { printf("FLUID: Setting pitch tuning: %.2f cents\n", tuning); // Create tuning for each key in octave double pitches[12]; for (int i = 0; i < 12; i++) pitches[i] = tuning; fluid_synth_activate_octave_tuning(synth, 0, 0, "DETUNE", pitches, false); // Select tuning for (int i = 0; i < MAX_MIDI_CHANNELS; i++) fluid_synth_activate_tuning(synth, i, 0, 0, false); } else printf("FLUID: Using default tuning\n"); // Load soundfonts { FluidSynthSoundFont *cur = app->getCFG()->GetFluidFont(); while (cur != 0) { printf("FLUID: Loading SoundFont '%s'\n",cur->name); fluid_synth_sfload(synth,cur->name,1); cur = cur->next; } } app->getEMG()->ListenEvent(this,0,T_EV_FluidSynthEnable); }; FluidSynthProcessor::~FluidSynthProcessor() { app->getEMG()->UnlistenEvent(this,0,T_EV_FluidSynthEnable); delete_fluid_synth(synth); delete_fluid_settings(settings); delete[] leftbuf; delete[] rightbuf; }; void FluidSynthProcessor::process(char pre, nframes_t len, AudioBuffers *ab) { if (!pre) { // Map our output to the end of the external inputs ab->ins[0][ab->numins_ext] = leftbuf; if (stereo) ab->ins[1][ab->numins_ext] = rightbuf; else ab->ins[1][ab->numins_ext] = 0; if (enable) { // Run synth DSP fluid_synth_write_float(synth, len, leftbuf, 0, 1, rightbuf, 0, 1); if (!stereo) { // Mono, so fold the right channel into the left like pudding for (nframes_t l = 0; l < len; l++) leftbuf[l] = (leftbuf[l] + rightbuf[l]) / 2; } } else { // Silence, not enabled memset(leftbuf,0,sizeof(sample_t) * len); if (stereo) memset(rightbuf,0,sizeof(sample_t) * len); } } }; // Read new current patch from 'patches' and send patch change to synth void FluidSynthProcessor::SendPatchChange(PatchItem *p) { fluid_synth_program_select(synth, p->channel, p->id, p->bank, p->prog); }; // Sets up our internal patch list based on loaded soundfonts void FluidSynthProcessor::SetupPatches() { PatchBrowser *br = (PatchBrowser *) app->getBROWSER(B_Patch); #if FLUIDSYNTH_VERSION_MAJOR == 1 // NOTE: fluidsynth v2 implements these #define fluid_sfont_iteration_start(_sf) (*(_sf)->iteration_start)(_sf) #define fluid_sfont_iteration_next(_sf,_pr) (*(_sf)->iteration_next)(_sf,_pr) #define fluid_preset_get_name(_preset) (*(_preset)->get_name)(_preset) #define fluid_preset_get_banknum(_preset) (*(_preset)->get_banknum)(_preset) #define fluid_preset_get_num(_preset) (*(_preset)->get_num)(_preset) fluid_preset_t preset; #elif FLUIDSYNTH_VERSION_MAJOR == 2 fluid_preset_t* preset; #endif // FLUIDSYNTH_VERSION_MAJOR if (br != 0) { // Add FluidSynth patch bank int fluidchan = app->getCFG()->GetFluidChannel(); br->PB_AddBegin(new PatchBank(0,-1,0)); // Use port 0 for FluidSynth // Store patches int sfcnt = fluid_synth_sfcount(synth); for (int i = 0; i < sfcnt; i++) { fluid_sfont_t *curfont = fluid_synth_get_sfont(synth,i); fluid_sfont_iteration_start(curfont); #if FLUIDSYNTH_VERSION_MAJOR == 1 while (fluid_sfont_iteration_next(curfont, &preset)) br->AddItem(new PatchItem(fluid_sfont_get_id(curfont), fluid_preset_get_banknum(&preset), fluid_preset_get_num(&preset), fluidchan, fluid_preset_get_name(&preset))); #elif FLUIDSYNTH_VERSION_MAJOR == 2 while ((preset = fluid_sfont_iteration_next(curfont)) != NULL) br->AddItem(new PatchItem(fluid_sfont_get_id(curfont), fluid_preset_get_banknum(preset), fluid_preset_get_num(preset), fluidchan, fluid_preset_get_name(preset))); #endif // FLUIDSYNTH_VERSION_MAJOR if (i+1 < sfcnt) { // End of soundfont- put in a divider br->AddItem(new BrowserDivision()); } } } }; void FluidSynthProcessor::ReceiveMIDIEvent(Event *ev) { FloConfig *fs = app->getCFG(); switch (ev->GetType()) { case T_EV_Input_MIDIController : if (enable) { MIDIControllerInputEvent *mcev = (MIDIControllerInputEvent *) ev; fluid_synth_cc(synth,app->getCFG()->GetFluidChannel(), mcev->ctrl,mcev->val); } break; case T_EV_Input_MIDIPitchBend : if (enable) { MIDIPitchBendInputEvent *mpev = (MIDIPitchBendInputEvent *) ev; fluid_synth_pitch_bend(synth,app->getCFG()->GetFluidChannel(), mpev->val + FLUIDSYNTH_PITCHBEND_CENTER); } break; case T_EV_Input_MIDIKey : if (enable) { MIDIKeyInputEvent *mkev = (MIDIKeyInputEvent *) ev; if (mkev->down) fluid_synth_noteon(synth, app->getCFG()->GetFluidChannel(), mkev->notenum+fs->transpose, mkev->vel); else fluid_synth_noteoff(synth, app->getCFG()->GetFluidChannel(), mkev->notenum+fs->transpose); } break; default: break; } }; void FluidSynthProcessor::ReceiveEvent(Event *ev, EventProducer */*from*/) { switch (ev->GetType()) { case T_EV_FluidSynthEnable : { FluidSynthEnableEvent *fev = (FluidSynthEnableEvent *) ev; // OK! if (CRITTERS) printf("FLUID: Received FluidSynthEnable (%s)\n", (fev->enable ? "on" : "off")); SetEnable(fev->enable); } break; default: break; } } #endif freewheeling-0.6.6/src/fweelin_fluidsynth.h000066400000000000000000000041571370736313100210440ustar00rootroot00000000000000#ifndef __FWEELIN_FLUIDSYNTH_H #define __FWEELIN_FLUIDSYNTH_H /* Copyright 2004-2011 Jan Pekau This file is part of Freewheeling. Freewheeling is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. Freewheeling 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 Freewheeling. If not, see . */ #if USE_FLUIDSYNTH #include #include "fweelin_core_dsp.h" #include "fweelin_browser.h" // Whacky FluidSynth center of pitchbend is 0x2000 not 0 #define FLUIDSYNTH_PITCHBEND_CENTER 0x2000 // Integrated soft-synth based on libfluidsynth class FluidSynthProcessor : public Processor, public EventListener { friend class Fweelin; public: FluidSynthProcessor(Fweelin *app, char stereo); virtual ~FluidSynthProcessor(); virtual void process(char pre, nframes_t len, AudioBuffers *ab); virtual void ReceiveEvent(Event *ev, EventProducer */*from*/); // Send a new patch to synth void SendPatchChange(PatchItem *p); // Receive MIDI events for synth void ReceiveMIDIEvent(Event *ev); // Enable/disable FluidSynth- if disabled, bypasses // processor stage to reduce CPU usage, but leaves memory allocated inline void SetEnable(char en) { // Preprocess audio for smoothing //dopreprocess(); this->enable = en; }; char GetEnable() { return enable; }; // Sets up browser patches based on loaded soundfonts void SetupPatches(); private: // Run FluidSynth in stereo? char stereo; // Left and right output buffers sample_t *leftbuf, *rightbuf; // And fluidsynth variables.. fluid_settings_t *settings; fluid_synth_t *synth; // Currently processing? char enable; }; #endif #endif freewheeling-0.6.6/src/fweelin_logo.h000066400000000000000000002750131370736313100176140ustar00rootroot00000000000000/* GIMP RGBA C-Source image dump (fweelin-logo.c) */ /* Copyright 2004-2011 Jan Pekau This file is part of Freewheeling. Freewheeling is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. Freewheeling 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 Freewheeling. If not, see . */ static const struct { unsigned int width; unsigned int height; unsigned int bytes_per_pixel; /* 3:RGB, 4:RGBA */ unsigned char pixel_data[223 * 42 * 4 + 1]; } fweelin_logo = { 223, 42, 4, "\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1" "\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1" "\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1" "\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1" "\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1" "\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1" "\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1" "\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\2\0\0\0\2" "\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1" "\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1" "\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\1\0\0\0\1" "\0\0\0\1\0\0\0\1\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\2" "\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1" "\0\0\0\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1\0\0\0\1" "\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\2\0\0\0\2" "\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\1" "\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1" "\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1" "\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1" "\0\0\0\1\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\1\0\0\0\1\0\0\0\1" "\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1" "\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\2\0\0\0\2\0\0\0\2" "\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\3\0\0\0\3\0\0\0\3\0\0\0\3" "\0\0\0\3\0\0\0\3\0\0\0\3\0\0\0\2\0\0\0\2\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1" "\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1" "\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\2\0\0\0\2" "\0\0\0\3\0\0\0\3\0\0\0\3\0\0\0\3\0\0\0\3\0\0\0\3\0\0\0\3\0\0\0\2\0\0\0\3" "\0\0\0\3\0\0\0\3\0\0\0\3\0\0\0\4\0\0\0\4\0\0\0\4\0\0\0\3\0\0\0\3\0\0\0\2" "\0\0\0\2\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1" "\0\0\0\1\0\0\0\1\0\0\0\2\0\0\0\3\0\0\0\3\0\0\0\3\0\0\0\4\0\0\0\4\0\0\0\4" "\0\0\0\4\0\0\0\4\0\0\0\4\0\0\0\4\0\0\0\4\0\0\0\4\0\0\0\4\0\0\0\4\0\0\0\4" "\0\0\0\3\0\0\0\3\0\0\0\2\0\0\0\2\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1" "\0\0\0\1\0\0\0\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1\0\0\0\1\0\0\0\1" "\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\2\0\0\0\2\0\0\0\3\0\0\0\3" "\0\0\0\4\0\0\0\4\0\0\0\3\0\0\0\3\0\0\0\3\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\2" "\0\0\0\3\0\0\0\3\0\0\0\3\0\0\0\3\0\0\0\3\0\0\0\3\0\0\0\3\0\0\0\3\0\0\0\3" "\0\0\0\2\0\0\0\3\0\0\0\3\0\0\0\3\0\0\0\3\0\0\0\4\0\0\0\4\0\0\0\4\0\0\0\4" "\0\0\0\5\0\0\0\5\0\0\0\5\0\0\0\6\0\0\0\7\0\0\0\7\0\0\0\7\0\0\0\7\0\0\0\6" "\0\0\0\5\0\0\0\4\0\0\0\3\0\0\0\2\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1" "\0\0\0\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1" "\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\2\0\0\0\3\0\0\0\4\0\0\0\5\0\0\0\6\0\0\0\6" "\0\0\0\7\0\0\0\7\0\0\0\7\0\0\0\6\0\0\0\6\0\0\0\5\0\0\0\6\0\0\0\6\0\0\0\7" "\0\0\0\10\0\0\0\10\0\0\0\10\0\0\0\10\0\0\0\7\0\0\0\6\0\0\0\5\0\0\0\4\0\0" "\0\2\0\0\0\2\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\2\0\0" "\0\3\0\0\0\4\0\0\0\5\0\0\0\6\0\0\0\7\0\0\0\10\0\0\0\10\0\0\0\11\0\0\0\11" "\0\0\0\11\0\0\0\10\0\0\0\10\0\0\0\10\0\0\0\10\0\0\0\7\0\0\0\7\0\0\0\7\0\0" "\0\6\0\0\0\5\0\0\0\4\0\0\0\3\0\0\0\2\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0" "\0\1\0\0\0\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1\0\0\0\1\0\0\0\1\0\0" "\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\2\0\0\0\3\0\0\0\4\0\0\0\5\0\0\0\6\0\0" "\0\7\0\0\0\7\0\0\0\7\0\0\0\6\0\0\0\5\0\0\0\4\0\0\0\4\0\0\0\4\0\0\0\4\0\0" "\0\5\0\0\0\6\0\0\0\6\0\0\0\6\0\0\0\6\0\0\0\6\0\0\0\6\0\0\0\5\0\0\0\5\0\0" "\0\4\0\0\0\5\0\0\0\5\0\0\0\6\0\0\0\7\0\0\0\7\0\0\0\10\0\0\0\10\0\0\0\10\0" "\0\0\11\0\0\0\12\0\0\0\13\0\0\0\14\0\0\0\16\0\0\0\16\0\0\0\17\0\0\0\16\0" "\0\0\15\0\0\0\12\0\0\0\10\0\0\0\6\0\0\0\4\0\0\0\2\0\0\0\2\0\0\0\1\0\0\0\1" "\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1\0\0\0\1\0\0\0\1" "\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\2\0\0\0\3\0\0\0\5\0\0\0\7\0\0\0\12\0\0\0\14" "\0\0\0\15\0\0\0\16\0\0\0\16\0\0\0\15\0\0\0\14\0\0\0\13\0\0\0\13\0\0\0\14" "\0\0\0\15\0\0\0\16\0\0\0\17\0\0\0\20\0\0\0\20\0\0\0\17\0\0\0\16\0\0\0\14" "\0\0\0\12\0\0\0\7\0\0\0\4\0\0\0\3\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1\0\0\0\1\0\0\0\2" "\0\0\0\2\0\0\0\4\0\0\0\6\0\0\0\10\0\0\0\12\0\0\0\14\0\0\0\16\0\0\0\20\0\0" "\0\21\0\0\0\22\0\0\0\23\0\0\0\22\0\0\0\22\0\0\0\21\0\0\0\20\0\0\0\20\0\0" "\0\20\0\0\0\17\0\0\0\16\0\0\0\15\0\0\0\13\0\0\0\10\0\0\0\6\0\0\0\4\0\0\0" "\2\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\0\0\0\0\1\0\0\0" "\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0" "\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0" "\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\2\0\0\0\3\0\0\0\4\0\0\0" "\7\0\0\0\11\0\0\0\13\0\0\0\15\0\0\0\16\0\0\0\16\0\0\0\16\0\0\0\14\0\0\0\13" "\0\0\0\11\0\0\0\11\0\0\0\11\0\0\0\12\0\0\0\13\0\0\0\14\0\0\0\15\0\0\0\16" "\0\0\0\16\0\0\0\15\0\0\0\14\0\0\0\13\0\0\0\12\0\0\0\11\0\0\0\12\0\0\0\13" "\0\0\0\14\0\0\0\16\0\0\0\17\0\0\0\20\0\0\0\21\0\0\0\21\0\0\0\23\0\0\0\24" "\0\0\0\27\0\0\0\31\0\0\0\33\0\0\0\35\0\0\0\35\0\0\0\34\0\0\0\31\0\0\0\25" "\0\0\0\20\0\0\0\14\0\0\0\10\0\0\0\5\0\0\0\3\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0" "\1\0\0\0\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0" "\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0" "\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0" "\1\0\0\0\2\0\0\0\4\0\0\0\6\0\0\0\12\0\0\0\16\0\0\0\23\0\0\0\27\0\0\0\32\0" "\0\0\34\0\0\0\34\0\0\0\32\0\0\0\31\0\0\0\27\0\0\0\27\0\0\0\30\0\0\0\31\0" "\0\0\34\0\0\0\36\0\0\0\37\0\0\0\40\0\0\0\36\0\0\0\33\0\0\0\27\0\0\0\22\0" "\0\0\15\0\0\0\10\0\0\0\5\0\0\0\3\0\0\0\2\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1" "\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1" "\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1" "\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1" "\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\3\0\0\0\4" "\0\0\0\7\0\0\0\13\0\0\0\17\0\0\0\23\0\0\0\27\0\0\0\33\0\0\0\36\0\0\0\40\0" "\0\0\"\0\0\0\"\0\0\0\"\0\0\0!\0\0\0\40\0\0\0\37\0\0\0\37\0\0\0\36\0\0\0\35" "\0\0\0\34\0\0\0\30\0\0\0\24\0\0\0\20\0\0\0\13\0\0\0\7\0\0\0\5\0\0\0\3\0\0" "\0\2\0\0\0\2\0\0\0\2\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0" "\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0" "\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0" "\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0" "\0\1\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\4\0\0\0\6\0\0\0\11\0\0\0\15\0\0\0\21\0" "\0\0\26\0\0\0\31\0\0\0\33\0\0\0\33\0\0\0\32\0\0\0\30\0\0\0\25\0\0\0\23\0" "\0\0\21\0\0\0\21\0\0\0\23\0\0\0\25\0\0\0\30\0\0\0\31\0\0\0\32\0\0\0\32\0" "\0\0\31\0\0\0\27\0\0\0\25\0\0\0\23\0\0\0\22\0\0\0\22\0\0\0\25\0\0\0\27\0" "\0\0\32\0\0\0\35\0\0\0\37\0\0\0\40\0\0\0!\0\0\0#\0\0\0%\0\0\0(\0\0\0,\0\0" "\0/\0\0\0""2\0\0\0""2\0\0\0""0\0\0\0+\0\0\0%\0\0\0\35\0\0\0\25\0\0\0\16\0" "\0\0\10\0\0\0\5\0\0\0\3\0\0\0\2\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0" "\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0" "\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0" "\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0" "\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\2\0\0\0\2\0\0\0\4\0\0\0\7\0\0\0\14\0" "\0\0\22\0\0\0\32\0\0\0\"\0\0\0(\0\0\0-\0\0\0""0\0\0\0""0\0\0\0.\0\0\0,\0" "\0\0*\0\0\0)\0\0\0*\0\0\0-\0\0\0""0\0\0\0""3\0\0\0""5\0\0\0""5\0\0\0""3\0" "\0\0.\0\0\0'\0\0\0\36\0\0\0\26\0\0\0\16\0\0\0\11\0\0\0\5\0\0\0\3\0\0\0\2" "\0\0\0\2\0\0\0\2\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1" "\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1" "\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1" "\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1" "\0\0\0\2\0\0\0\4\0\0\0\10\0\0\0\15\0\0\0\23\0\0\0\33\0\0\0#\0\0\0*\0\0\0" """0\0\0\0""5\0\0\0""8\0\0\0:\0\0\0;\0\0\0;\0\0\0""9\0\0\0""8\0\0\0""7\0\0" "\0""6\0\0\0""6\0\0\0""4\0\0\0""0\0\0\0+\0\0\0$\0\0\0\33\0\0\0\24\0\0\0\15" "\0\0\0\10\0\0\0\5\0\0\0\3\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\1\0\0\0\1\0\0\0\1" "\0\0\0\1\0\0\0\1\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\2" "\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1" "\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\2\0\0\0\2\0\0\0\2" "\0\0\0\2\0\0\0\2\0\0\0\3\0\0\0\3\0\0\0\3\0\0\0\4\0\0\0\7\0\0\0\13\0\0\0\20" "\0\0\0\27\0\0\0\37\0\0\0&\0\0\0,\0\0\0""0\0\0\0""0\0\0\0.\0\0\0+\0\0\0&\0" "\0\0\"\0\0\0\40\0\0\0\40\0\0\0#\0\0\0'\0\0\0+\0\0\0.\0\0\0/\0\0\0/\0\0\0" "-\0\0\0*\0\0\0&\0\0\0\"\0\0\0!\0\0\0!\0\0\0%\0\0\0)\0\0\0/\0\0\0""3\0\0\0" """5\0\0\0""8\0\0\0""9\0\0\0<\0\0\0?\0\0\0D\0\0\0H\0\0\0M\0\0\0P\0\0\0P\0" "\0\0L\0\0\0E\0\0\0:\0\0\0.\0\0\0\"\0\0\0\26\0\0\0\16\0\0\0\10\0\0\0\5\0\0" "\0\3\0\0\0\2\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0" "\0\1\0\0\0\1\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\2\0\0" "\0\2\0\0\0\2\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0" "\0\1\0\0\0\1\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\2\0\0" "\0\2\0\0\0\2\0\0\0\4\0\0\0\7\0\0\0\14\0\0\0\24\0\0\0\36\0\0\0*\0\0\0""7\0" "\0\0A\0\0\0I\0\0\0M\0\0\0M\0\0\0K\0\0\0G\0\0\0D\0\0\0C\0\0\0E\0\0\0H\0\0" "\0M\0\0\0Q\0\0\0T\0\0\0S\0\0\0O\0\0\0G\0\0\0<\0\0\0.\0\0\0!\0\0\0\26\0\0" "\0\15\0\0\0\7\0\0\0\4\0\0\0\3\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\2\0\0" "\0\2\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0" "\0\1\0\0\0\1\0\0\0\1\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\2\0\0" "\0\2\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\1\0\0" "\0\1\0\0\0\1\0\0\0\1\0\0\0\2\0\0\0\4\0\0\0\7\0\0\0\15\0\0\0\25\0\0\0\37\0" "\0\0,\0\0\0""7\0\0\0B\0\0\0K\0\0\0R\0\0\0W\0\0\0Z\0\0\0[\0\0\0Z\0\0\0Y\0" "\0\0W\0\0\0V\0\0\0U\0\0\0T\0\0\0Q\0\0\0L\0\0\0C\0\0\0""9\0\0\0,\0\0\0\40" "\0\0\0\25\0\0\0\16\0\0\0\11\0\0\0\6\0\0\0\4\0\0\0\4\0\0\0\3\0\0\0\3\0\0\0" "\3\0\0\0\3\0\0\0\3\0\0\0\3\0\0\0\3\0\0\0\3\0\0\0\4\0\0\0\4\0\0\0\4\0\0\0" "\4\0\0\0\4\0\0\0\4\0\0\0\4\0\0\0\4\0\0\0\3\0\0\0\3\0\0\0\2\0\0\0\2\0\0\0" "\2\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\3\0\0\0\3\0\0\0" "\4\0\0\0\4\0\0\0\4\0\0\0\4\0\0\0\5\0\0\0\5\0\0\0\6\0\0\0\10\0\0\0\14\0\0" "\0\22\0\0\0\33\0\0\0&\0\0\0""1\0\0\0=\0\0\0F\0\0\0K\0\0\0L\0\0\0J\0\0\0D" "\0\0\0=\0\0\0""8\0\0\0""4\0\0\0""5\0\0\0""9\0\0\0?\0\0\0E\0\0\0I\0\0\0K\0" "\0\0K\0\0\0H\0\0\0C\0\0\0<\0\0\0""7\0\0\0""4\0\0\0""6\0\0\0;\0\0\0B\0\0\0" "I\0\0\0O\0\0\0S\0\0\0V\0\0\0Y\0\0\0\\\0\0\0`\0\0\0e\27\27\27j\\\\\\ossss" "\300\300\300rtttm]]]c<<\0\0\0" "P;;;^\301\301\301ivvvnRRRoXXXm\4\4\4i\0\0\0e\0\0\0c\0\0\0e\14\14\14iyyyo" "\250\250\250t\241\241\241w\203\203\203uYYYo\213\213\213c\303\303\303TTTT" "A\0\0\0/\0\0\0\37\0\0\0\23\0\0\0\13\0\0\0\7\0\0\0\5\0\0\0\4\0\0\0\4\0\0\0" "\4\0\0\0\4\0\0\0\4\0\0\0\4\0\0\0\4\0\0\0\4\0\0\0\3\0\0\0\3\0\0\0\2\0\0\0" "\2\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\2\0\0\0\2\0\0\0\3\0\0\0\4\0\0\0\4\0\0\0" "\4\0\0\0\4\0\0\0\4\0\0\0\4\0\0\0\4\0\0\0\4\0\0\0\4\0\0\0\4\0\0\0\4\0\0\0" "\4\0\0\0\3\0\0\0\3\0\0\0\2\0\0\0\2\0\0\0\1\0\0\0\3\0\0\0\5\0\0\0\12\0\0\0" "\23\0\0\0\37\0\0\0.\0\0\0@\33\33\33Q###`\"\"\"l###v\223\223\223|\316\316" "\316\177\320\320\320\200\255\255\255\200ZZZ~###|###{666z\213\213\213x\213" "\213\213t\\\\\\m\211\211\211a[[[S\0\0\0A\0\0\0""0\0\0\0!\0\0\0\26\0\0\0\17" "\0\0\0\13\0\0\0\11\0\0\0\10\0\0\0\7\0\0\0\7\0\0\0\7\0\0\0\6\0\0\0\6\0\0\0" "\6\0\0\0\6\0\0\0\6\0\0\0\7\0\0\0\10\0\0\0\11\0\0\0\12\0\0\0\12\0\0\0\11\0" "\0\0\11\0\0\0\10\0\0\0\7\0\0\0\6\0\0\0\4\0\0\0\4\0\0\0\3\0\0\0\3\0\0\0\2" "\0\0\0\3\0\0\0\3\0\0\0\4\0\0\0\5\0\0\0\6\0\0\0\7\0\0\0\10\0\0\0\11\0\0\0" "\11\0\0\0\11\0\0\0\12\0\0\0\12\0\0\0\14\0\0\0\16\0\0\0\24\0\0\0\34\0\0\0" ")\0\0\0""8\0\0\0I\25\25\25Y###e\243\243\243l\331\331\331n!!!k\"\"\"d\11\11" "\11[\0\0\0T\0\0\0P\0\0\0Q\0\0\0V\11\11\11^\200\200\200fOOOk\"\"\"n!!!m\37" "\37\37iyyyaaaaY\0\0\0R\0\0\0N\0\0\0P\0\0\0W\16\16\16`\252\252\252j\324\324" "\324q!!!w\31\31\31{\210\210\210~\177\177\177\201\211\211\211\205LLL\212\314" "\314\314\220\266\266\266\225\316\316\316\230\235\235\235\226\262\262\262" "\220\324\324\324\203\341\341\341q\203\203\203[\0\0\0E\0\0\0""0\0\0\0\37\0" "\0\0\24\0\0\0\15\0\0\0\10\0\0\0\6\0\0\0\4\0\0\0\3\0\0\0\3\0\0\0\2\0\0\0\2" "\0\0\0\3\0\0\0\3\0\0\0\4\0\0\0\5\0\0\0\6\0\0\0\7\0\0\0\10\0\0\0\11\0\0\0" "\11\0\0\0\11\0\0\0\10\0\0\0\7\0\0\0\6\0\0\0\5\0\0\0\4\0\0\0\3\0\0\0\3\0\0" "\0\3\0\0\0\3\0\0\0\4\0\0\0\4\0\0\0\5\0\0\0\7\0\0\0\7\0\0\0\10\0\0\0\10\0" "\0\0\10\0\0\0\7\0\0\0\7\0\0\0\7\0\0\0\10\0\0\0\13\0\0\0\21\0\0\0\34\0\0\0" "+\0\0\0?:::U\232\232\232l\341\341\341~\323\323\323\213\355\355\355\223\354" "\354\354\224\357\357\357\222\346\346\346\215\330\330\330\211\12\12\12\207" "888\211\236\236\236\216\343\343\343\223\240\240\240\231\223\223\223\233\257" "\257\257\230\312\312\312\220\305\305\305\201\275\275\275mvvvU\0\0\0>\0\0" "\0*\0\0\0\33\0\0\0\21\0\0\0\14\0\0\0\11\0\0\0\11\0\0\0\10\0\0\0\11\0\0\0" "\11\0\0\0\11\0\0\0\11\0\0\0\11\0\0\0\10\0\0\0\7\0\0\0\6\0\0\0\4\0\0\0\3\0" "\0\0\3\0\0\0\3\0\0\0\3\0\0\0\4\0\0\0\5\0\0\0\6\0\0\0\7\0\0\0\10\0\0\0\11" "\0\0\0\11\0\0\0\11\0\0\0\10\0\0\0\10\0\0\0\10\0\0\0\10\0\0\0\10\0\0\0\10" "\0\0\0\7\0\0\0\7\0\0\0\6\0\0\0\5\0\0\0\3\0\0\0\2\0\0\0\3\0\0\0\6\0\0\0\16" "\0\0\0\31\0\0\0*\1\1\1>\260\260\260V\352\352\352l\271\271\271\200\361\361" "\361\216\316\316\316\231\311\311\311\240XXX\244AAA\245UUU\245\340\340\340" "\243\317\317\317\241\331\331\331\240\273\273\273\237\253\253\253\235\254" "\254\254\230\272\272\272\217\275\275\275\200\354\354\354n\0\0\0X\0\0\0C\0" "\0\0""0\0\0\0#\0\0\0\31\0\0\0\24\0\0\0\21\0\0\0\20\0\0\0\17\0\0\0\16\0\0" "\0\16\0\0\0\15\0\0\0\14\0\0\0\14\0\0\0\15\0\0\0\16\0\0\0\17\0\0\0\21\0\0" "\0\23\0\0\0\24\0\0\0\24\0\0\0\23\0\0\0\22\0\0\0\20\0\0\0\16\0\0\0\14\0\0" "\0\11\0\0\0\7\0\0\0\6\0\0\0\5\0\0\0\5\0\0\0\5\0\0\0\6\0\0\0\10\0\0\0\12\0" "\0\0\14\0\0\0\16\0\0\0\20\0\0\0\22\0\0\0\23\0\0\0\23\0\0\0\24\0\0\0\25\0" "\0\0\26\0\0\0\31\0\0\0\37\0\0\0*\0\0\0""9111M\273\273\273b\340\340\340v\323" "\323\323\205\367\367\367\217\367\367\367\221\354\354\354\215\352\352\352" "\205\311\311\311{VVVs\0\0\0o\0\0\0pzzzv\303\303\303\177\346\346\346\211\361" "\361\361\217\357\357\357\222\360\360\360\221\360\360\360\213\311\311\311" "\202\345\345\345wZZZn\0\0\0j\0\0\0ltttu\320\320\320\200\317\317\317\214\352" "\352\352\225\361\361\361\233\334\334\334\237\277\277\277\242\304\304\304" "\246\335\335\335\251\332\332\332\256uuu\263\24\24\24\267\0\0\0\271\0\0\0" "\267\0\0\0\257\"\"\"\241666\214\331\331\331s\0\0\0Y\0\0\0A\0\0\0-\0\0\0\37" "\0\0\0\25\0\0\0\17\0\0\0\14\0\0\0\11\0\0\0\7\0\0\0\5\0\0\0\4\0\0\0\4\0\0" "\0\5\0\0\0\6\0\0\0\10\0\0\0\12\0\0\0\14\0\0\0\16\0\0\0\20\0\0\0\21\0\0\0" "\22\0\0\0\22\0\0\0\21\0\0\0\17\0\0\0\15\0\0\0\13\0\0\0\10\0\0\0\6\0\0\0\5" "\0\0\0\5\0\0\0\6\0\0\0\7\0\0\0\11\0\0\0\13\0\0\0\15\0\0\0\17\0\0\0\20\0\0" "\0\20\0\0\0\20\0\0\0\17\0\0\0\16\0\0\0\16\0\0\0\17\0\0\0\22\0\0\0\31\0\0" "\0%\0\0\0""8\0\0\0Q\301\301\301k\210\210\210\206'''\233\6\6\6\252ggg\263" "\250\250\250\265\177\177\177\264\265\265\265\260\357\357\357\254&&&\252\341" "\341\341\254mmm\260555\265\36\36\36\271\0\0\0\272\0\0\0\267\0\0\0\255,,," "\233\333\333\333\204\"\"\"i\0\0\0N\0\0\0""7\0\0\0&\0\0\0\32\0\0\0\24\0\0" "\0\22\0\0\0\21\0\0\0\21\0\0\0\22\0\0\0\23\0\0\0\23\0\0\0\23\0\0\0\22\0\0" "\0\20\0\0\0\16\0\0\0\13\0\0\0\11\0\0\0\7\0\0\0\6\0\0\0\6\0\0\0\7\0\0\0\10" "\0\0\0\12\0\0\0\15\0\0\0\17\0\0\0\21\0\0\0\21\0\0\0\22\0\0\0\21\0\0\0\21" "\0\0\0\20\0\0\0\20\0\0\0\20\0\0\0\20\0\0\0\20\0\0\0\17\0\0\0\16\0\0\0\13" "\0\0\0\11\0\0\0\6\0\0\0\4\0\0\0\4\0\0\0\10\0\0\0\21\0\0\0\37\0\0\0""5\2\2" "\2N\362\362\362k\332\332\332\205\20\20\20\234JJJ\255\36\36\36\271\12\12\12" "\300\0\0\0\304\0\0\0\306\0\0\0\305\20\20\20\304\12\12\12\303999\301;;;\300" "kkk\275GGG\270FFF\256UUU\236\343\343\343\212\236\236\236r\0\0\0Z\0\0\0E\0" "\0\0""5\0\0\0*\0\0\0$\0\0\0\40\0\0\0\36\0\0\0\35\0\0\0\34\0\0\0\33\0\0\0" "\32\0\0\0\30\0\0\0\30\0\0\0\31\0\0\0\33\0\0\0\35\0\0\0\40\0\0\0#\0\0\0%\0" "\0\0%\0\0\0%\0\0\0\"\0\0\0\37\0\0\0\33\0\0\0\27\0\0\0\23\0\0\0\17\0\0\0\14" "\0\0\0\12\0\0\0\11\0\0\0\12\0\0\0\15\0\0\0\20\0\0\0\24\0\0\0\30\0\0\0\34" "\0\0\0\37\0\0\0\"\0\0\0$\0\0\0%\0\0\0&\0\0\0&\0\0\0'\0\0\0)\0\0\0""0\0\0" "\0;\0\0\0Lwwwc\324\324\324{KKK\222```\243$$$\256iii\261bbb\256\220\220\220" "\246\357\357\357\233\350\350\350\223\6\6\6\216GGG\220\330\330\330\227yyy" "\241\213\213\213\252[[[\261VVV\264GGG\262;;;\253\207\207\207\241\365\365" "\365\225QQQ\213\0\0\0\207'''\212\347\347\347\223\245\245\245\237AAA\2538" "88\265???\274(((\300eee\303>>>\306\367\367\367\310\236\236\236\314\6\6\6" "\320\0\0\0\323\0\0\0\324\0\0\0\321\0\0\0\311\0\0\0\272\0\0\0\245\314\314" "\314\213\0\0\0o\0\0\0U\0\0\0?\0\0\0/\0\0\0$\0\0\0\34\0\0\0\26\0\0\0\21\0" "\0\0\16\0\0\0\13\0\0\0\11\0\0\0\11\0\0\0\12\0\0\0\14\0\0\0\20\0\0\0\24\0" "\0\0\30\0\0\0\34\0\0\0\37\0\0\0!\0\0\0\"\0\0\0\"\0\0\0\40\0\0\0\35\0\0\0" "\31\0\0\0\24\0\0\0\20\0\0\0\14\0\0\0\12\0\0\0\12\0\0\0\13\0\0\0\16\0\0\0" "\22\0\0\0\26\0\0\0\32\0\0\0\35\0\0\0\37\0\0\0\37\0\0\0\37\0\0\0\36\0\0\0" "\34\0\0\0\33\0\0\0\33\0\0\0\35\0\0\0$\0\0\0""2\0\0\0F\200\200\200a\370\370" "\370~XXX\233\0\0\0\262\0\0\0\304\0\0\0\315\0\0\0\320\4\4\4\320\16\16\16\315" "\276\276\276\311\262\262\262\310\251\251\251\311\1\1\1\314\0\0\0\320\0\0" "\0\324\0\0\0\324\0\0\0\317\0\0\0\304xxx\261\270\270\270\231ggg|\0\0\0`\0" "\0\0G\0\0\0""6\0\0\0*\0\0\0$\0\0\0!\0\0\0!\0\0\0!\0\0\0#\0\0\0$\0\0\0$\0" "\0\0$\0\0\0\"\0\0\0\37\0\0\0\33\0\0\0\26\0\0\0\22\0\0\0\16\0\0\0\14\0\0\0" "\14\0\0\0\15\0\0\0\20\0\0\0\24\0\0\0\31\0\0\0\34\0\0\0\40\0\0\0!\0\0\0\"" "\0\0\0\"\0\0\0!\0\0\0\40\0\0\0\37\0\0\0\37\0\0\0\37\0\0\0\37\0\0\0\35\0\0" "\0\32\0\0\0\26\0\0\0\21\0\0\0\14\0\0\0\10\0\0\0\4\0\0\0\12\0\0\0\24\0\0\0" "%\0\0\0=\2\2\2Z\361\361\361|***\231\0\0\0\263\0\0\0\305\0\0\0\322\0\0\0\331" "\0\0\0\335\0\0\0\336\0\0\0\336\0\0\0\335\0\0\0\334\0\0\0\333\0\0\0\332\0" "\0\0\327\0\0\0\322\0\0\0\310\0\0\0\270\311\311\311\244\221\221\221\213\0" "\0\0t\0\0\0]\0\0\0M\0\0\0B\0\0\0;\0\0\0""7\0\0\0""5\0\0\0""3\0\0\0""2\0\0" "\0""0\0\0\0.\0\0\0,\0\0\0+\0\0\0,\0\0\0/\0\0\0""3\0\0\0""8\0\0\0<\0\0\0>" "\0\0\0?\0\0\0>\0\0\0:\0\0\0""6\0\0\0/\0\0\0)\0\0\0\"\0\0\0\34\0\0\0\27\0" "\0\0\23\0\0\0\22\0\0\0\24\0\0\0\27\0\0\0\35\0\0\0$\0\0\0*\0\0\0""1\0\0\0" """6\0\0\0:\0\0\0<\0\0\0>\0\0\0?\0\0\0?\0\0\0?\0\0\0A\0\0\0F\0\0\0P\0\0\0" "a\260\260\260xPPP\221\0\0\0\252\0\0\0\274\0\0\0\307\0\0\0\313\0\0\0\310\35" "\35\35\301\303\303\303\270WWW\257===\253\363\363\363\255bbb\264\7\7\7\275" "\0\0\0\307\0\0\0\315\13\13\13\317&&&\314\0\0\0\306OOO\273\364\364\364\257" "\200\200\200\246\0\0\0\241\331\331\331\244\213\213\213\256\0\0\0\272\0\0" "\0\306\0\0\0\320\14\14\14\326\25\25\25\332\0\0\0\334'''\336\371\371\371\340" "\231\231\231\343\0\0\0\345\0\0\0\347\0\0\0\347\0\0\0\344\0\0\0\334\0\0\0" "\316ooo\272\337\337\337\241\25\25\25\206\0\0\0m\0\0\0W\0\0\0F\0\0\0""9\0" "\0\0/\0\0\0'\0\0\0\40\0\0\0\31\0\0\0\24\0\0\0\22\0\0\0\21\0\0\0\23\0\0\0" "\27\0\0\0\35\0\0\0$\0\0\0+\0\0\0""1\0\0\0""6\0\0\0""9\0\0\0;\0\0\0:\0\0\0" """7\0\0\0""2\0\0\0,\0\0\0$\0\0\0\35\0\0\0\27\0\0\0\24\0\0\0\23\0\0\0\26\0" "\0\0\32\0\0\0\40\0\0\0'\0\0\0-\0\0\0""2\0\0\0""5\0\0\0""7\0\0\0""6\0\0\0" """4\0\0\0""2\0\0\0""0\0\0\0.\0\0\0/\0\0\0""4\0\0\0@\0\0\0T\217\217\217p\356" "\356\356\216\13\13\13\253\0\0\0\304\0\0\0\326\0\0\0\337\0\0\0\344\0\0\0\344" "\0\0\0\342\230\230\230\340\375\375\375\337\245\245\245\340\3\3\3\342\0\0" "\0\345\0\0\0\347\0\0\0\346\0\0\0\340\0\0\0\325{{{\303\366\366\366\253qqq" "\217\0\0\0t\0\0\0\\\0\0\0K\0\0\0@\0\0\0;\0\0\0""8\0\0\0""8\0\0\0:\0\0\0;" "\0\0\0=\0\0\0=\0\0\0<\0\0\0:\0\0\0""5\0\0\0/\0\0\0'\0\0\0\40\0\0\0\32\0\0" "\0\26\0\0\0\26\0\0\0\31\0\0\0\36\0\0\0$\0\0\0+\0\0\0""1\0\0\0""6\0\0\0""9" "\0\0\0:\0\0\0:\0\0\0""8\0\0\0""7\0\0\0""7\0\0\0""7\0\0\0""6\0\0\0""5\0\0" "\0""2\0\0\0-\0\0\0&\0\0\0\36\0\0\0\25\0\0\0\16\0\0\0\5\0\0\0\13\0\0\0\27" "\0\0\0)\0\0\0D\2\2\2c\362\362\362\210)))\247\0\0\0\304\0\0\0\326\0\0\0\343" "\0\0\0\351\0\0\0\355\0\0\0\357\0\0\0\357\0\0\0\356\0\0\0\355\0\0\0\355\0" "\0\0\354\0\0\0\351\0\0\0\344\0\0\0\333\0\0\0\315\264\264\264\273\334\334" "\334\244&&&\216\0\0\0z\0\0\0k\0\0\0`\0\0\0Z\0\0\0V\0\0\0S\0\0\0R\0\0\0P\0" "\0\0M\0\0\0K\0\0\0H\0\0\0G\0\0\0H\0\0\0K\0\0\0Q\0\0\0V\0\0\0\\\22\22\22_" "\20\20\20`\0\0\0^\0\0\0Z\0\0\0S\0\0\0K\0\0\0B\0\0\0""9\0\0\0""0\0\0\0(\0" "\0\0#\0\0\0!\0\0\0#\0\0\0)\0\0\0""1\0\0\0;\0\0\0D\0\0\0M\0\0\0T\0\0\0Y\0" "\0\0]\0\0\0_\1\1\1`\24\24\24`\3\3\3_\0\0\0^\0\0\0a\0\0\0i\0\0\0xuuu\215\201" "\201\201\245\0\0\0\274\0\0\0\316\0\0\0\332\0\0\0\336\0\0\0\334\0\0\0\326" "\242\242\242\316\320\320\320\307\6\6\6\304\316\316\316\306nnn\314\0\0\0\324" "\0\0\0\334\0\0\0\341\0\0\0\343\0\0\0\340\0\0\0\332\20\20\20\320\340\340\340" "\305\201\201\201\274\0\0\0\270\247\247\247\273MMM\304\0\0\0\317\0\0\0\332" "\0\0\0\343\0\0\0\350\0\0\0\353\0\0\0\355hhh\356\374\374\374\360\333\333\333" "\361\5\5\5\363\0\0\0\363\0\0\0\363\0\0\0\360\0\0\0\351\0\0\0\335PPP\314\303" "\303\303\266OOO\237\0\0\0\210\0\0\0t\0\0\0c\0\0\0V\0\0\0J\0\0\0?\0\0\0""5" "\0\0\0+\0\0\0$\0\0\0\40\0\0\0\37\0\0\0\"\0\0\0)\0\0\0""1\0\0\0;\0\0\0D\0" "\0\0M\0\0\0S\0\0\0X\0\0\0Z\12\12\12Z\15\15\15V\0\0\0O\0\0\0F\0\0\0<\0\0\0" """1\0\0\0)\0\0\0#\0\0\0\"\0\0\0&\0\0\0,\0\0\0""6\0\0\0?\0\0\0H\0\0\0O\0\0" "\0T\0\0\0U\0\0\0U\0\0\0S\0\0\0P\0\0\0L\0\0\0H\0\0\0F\0\0\0I\0\0\0R\0\0\0" "d\177\177\177~\360\360\360\232]]]\267\0\0\0\317\0\0\0\341\0\0\0\353\0\0\0" "\360\0\0\0\361\21\21\21\360\247\247\247\357\261\261\261\356\335\335\335\357" "<<<\360\0\0\0\362\0\0\0\363\0\0\0\361\0\0\0\353\0\0\0\341\210\210\210\321" "\313\313\313\274\275\275\275\243\0\0\0\213\0\0\0v\0\0\0g\0\0\0]\0\0\0Y\0" "\0\0W\0\0\0X\0\0\0Z\0\0\0\\\0\0\0]\0\0\0^\0\0\0]\16\16\16Y\20\20\20R\0\0" "\0I\0\0\0>\0\0\0""4\0\0\0,\0\0\0'\0\0\0'\0\0\0+\0\0\0""2\0\0\0;\0\0\0E\0" "\0\0M\15\15\15T\27\27\27X\0\0\0Z\0\0\0Y\0\0\0X\0\0\0W\0\0\0U\0\0\0U\0\0\0" "U\0\0\0S\25\25\25N\4\4\4G\0\0\0<\0\0\0""0\0\0\0\"\0\0\0\27\0\0\0\5\0\0\0" "\14\0\0\0\31\0\0\0,\0\0\0I\2\2\2j\324\324\324\221\14\14\14\261\0\0\0\316" "\0\0\0\340\0\0\0\355\0\0\0\363\0\0\0\367\0\0\0\370\0\0\0\370\0\0\0\370\0" "\0\0\370\0\0\0\367\0\0\0\366\0\0\0\364\0\0\0\360\0\0\0\351\0\0\0\335\313" "\313\313\316\241\241\241\274%%%\252\\\\\\\231\240\240\240\214MMM\203GGG~" "NNN{NNNxNNNwKKKtNNNqNNNn\27\27\27j\0\0\0i\0\0\0j\0\0\0nAAAt\262\262\262{" "\246\246\246\201\347\347\347\204\341\341\341\205\265\265\265\203\265\265" "\265~\252\252\252w\30\30\30n\0\0\0c\0\0\0W\0\0\0K\0\0\0A\0\0\0:\0\0\0""7" "\0\0\0:\0\0\0A\0\0\0K\0\0\0X\11\11\11d\255\255\255o\247\247\247x<<<~\261" "\261\261\202\265\265\265\205\270\270\270\206\355\355\355\205\252\252\252" "\203\263\263\263\200xxx\200\23\23\23\205\0\0\0\220GGG\241\204\204\204\266" "\0\0\0\312\0\0\0\333\0\0\0\346\0\0\0\353\0\0\0\352\0\0\0\345\245\245\245" "\337\355\355\355\332CCC\330\272\272\272\331\263\263\263\336\0\0\0\345\0\0" "\0\353\0\0\0\357\0\0\0\360\0\0\0\356\0\0\0\350\0\0\0\337GGG\326\234\234\234" "\317\0\0\0\314\224\224\224\317OOO\326\0\0\0\337\0\0\0\350\0\0\0\357\0\0\0" "\363\0\0\0\366\0\0\0\367\313\313\313\370\340\340\340\371\326\326\326\371" "DDD\372\0\0\0\372\0\0\0\371\0\0\0\367\0\0\0\362\0\0\0\350,,,\333\353\353" "\353\312\300\300\300\267}}}\245\247\247\247\223\241\241\241\205MMMw\40\40" "\40k\0\0\0]\0\0\0P\0\0\0D\0\0\0:\0\0\0""5\0\0\0""4\0\0\0""9\0\0\0B\0\0\0" "M\0\0\0Y///e\253\253\253o\207\207\207wXXX}\257\257\257\177\322\322\322~\325" "\325\325zRRRqGGGf\5\5\5Y\0\0\0L\0\0\0A\0\0\0:\0\0\0""9\0\0\0=\0\0\0F\0\0" "\0R&&&^OOOj\237\237\237s\254\254\254x\240\240\240zNNNzNNNxNNNsGGGn\20\20" "\20i\0\0\0d\0\0\0d\0\0\0i\0\0\0v\0\0\0\214]]]\246ooo\300\0\0\0\327\0\0\0" "\347\0\0\0\361\0\0\0\366\0\0\0\370%%%\370\374\374\374\370\252\252\252\370" "\177\177\177\370\330\330\330\370\13\13\13\371\6\6\6\371...\367%%%\362\34" "\34\34\352QQQ\334\363\363\363\314hhh\267III\245HHH\224LLL\210MMM\201JJJ}" "NNN|NNN}QQQ\177\253\253\253\201\265\265\265\203\265\265\265\203\233\233\233" "\201\275\275\275}\326\326\326u$$$j\0\0\0\\\0\0\0P\0\0\0D\0\0\0?\0\0\0>\0" "\0\0C\0\0\0M\0\0\0Y(((fNNNp\261\261\261x\363\363\363}\262\262\262\177___" "~NNN}AAA|))){NNNzCCCynnnv\363\363\363pqqqe\34\34\34U\0\0\0D\0\0\0""1\0\0" "\0!\0\0\0\6\0\0\0\15\0\0\0\32\0\0\0/\0\0\0M\2\2\2o\332\332\332\226\21\21" "\21\267\0\0\0\324\0\0\0\346\0\0\0\362\0\0\0\370\0\0\0\373\0\0\0\374&&&\374" "!!!\374\15\15\15\374\2\2\2\374\0\0\0\373\0\0\0\372\0\0\0\367\0\0\0\362\6" "\6\6\351ooo\336\352\352\352\320\337\337\337\303\341\341\341\266\326\326\326" "\255\314\314\314\246\345\345\345\242\317\317\317\237\256\256\256\235\303" "\303\303\233\324\324\324\231\302\302\302\226\247\247\247\222\342\342\342" "\217NNN\215\31\31\31\216\305\305\305\222\351\351\351\230\206\206\206\237" "\246\246\246\245\275\275\275\250\273\273\273\251kkk\250EEE\243\221\221\221" "\233\331\331\331\221\327\327\327\206XXXx\11\11\11k\0\0\0_\0\0\0W\0\0\0S\0" "\0\0V\0\0\0^\6\6\6k\263\263\263y\332\332\332\207\351\351\351\223\273\273" "\273\234\340\340\340\242\345\345\345\246\240\240\240\251\234\234\234\251" "\254\254\254\250\214\214\214\245\266\266\266\242\346\346\346\237XXX\241\0" "\0\0\247===\264\324\324\324\304\0\0\0\325\0\0\0\344\0\0\0\355\0\0\0\362\0" "\0\0\362\0\0\0\360TTT\353\300\300\300\350\340\340\340\346\344\344\344\347" "PPP\353\0\0\0\357\0\0\0\364\0\0\0\366\0\0\0\367\0\0\0\365\0\0\0\361\0\0\0" "\352!!!\343\340\340\340\336\207\207\207\333\351\351\351\336555\343\0\0\0" "\352\0\0\0\361\0\0\0\366\0\0\0\371\0\0\0\373\0\0\0\374\232\232\232\374\356" "\356\356\374\202\202\202\375\11\11\11\375\0\0\0\375\0\0\0\375\0\0\0\373\0" "\0\0\370\0\0\0\361\"\"\"\347\317\317\317\333\303\303\303\315\273\273\273" "\300\352\352\352\262\304\304\304\246\334\334\334\232\346\346\346\215\323" "\323\323~ttto\13\13\13a\0\0\0U\0\0\0O\0\0\0O\0\0\0U\0\0\0`$$$m~~~{\237\237" "\237\210\362\362\362\223\273\273\273\234\241\241\241\241nnn\243%%%\242\216" "\216\216\235\342\342\342\225\361\361\361\210rrrz\12\12\12k\0\0\0^\0\0\0V" "\0\0\0U\0\0\0Z\0\0\0e\14\14\14r\327\327\327\200\324\324\324\215\251\251\251" "\226\240\240\240\234\236\236\236\237\312\312\312\237\307\307\307\234\321" "\321\321\230\272\272\272\222\335\335\335\214\331\331\331\205ddd\201\1\1\1" "\203\0\0\0\214\20\20\20\235\306\306\306\262hhh\311\0\0\0\335\0\0\0\354\0" "\0\0\365\0\0\0\372\0\0\0\374\4\4\4\374!!!\374\353\353\353\374\336\336\336" "\374\333\333\333\375???\375&&&\375///\373\7\7\7\367xxx\361\277\277\277\347" "\372\372\372\332\221\221\221\313^^^\276\342\342\342\261\236\236\236\251\226" "\226\226\244\347\347\347\241\271\271\271\241\237\237\237\242\364\364\364" "\244\276\276\276\246BBB\247bbb\250\302\302\302\245\324\324\324\241\327\327" "\327\230\346\346\346\214\241\241\241}FFFo\0\0\0b\0\0\0[\0\0\0[\0\0\0awww" "m\200\200\200z\310\310\310\210\333\333\333\223\213\213\213\234[[[\241zzz" "\243\323\323\323\243\350\350\350\242\330\330\330\241\342\342\342\240\267" "\267\267\237\346\346\346\235\224\224\224\231vvv\220\245\245\245\203\322\322" "\322owwwY\0\0\0@\0\0\0+\0\0\0\7\0\0\0\16\0\0\0\35\0\0\0""2\0\0\0Q\2\2\2t" "\350\350\350\233\36\36\36\273\0\0\0\330\0\0\0\352\0\0\0\365\0\0\0\373\0\0" "\0\376\0\0\0\377222\377\223\223\223\377\364\364\364\377\232\232\232\377\243" "\243\243\376PPP\375666\373$$$\370zzz\362]]]\353222\341\34\34\34\331\0\0\0" "\320\24\24\24\312\21\21\21\305\3\3\3\302\202\202\202\300\210\210\210\277" "FFF\275111\273SSS\271DDD\266ccc\262\322\322\322\261\254\254\254\262\330\330" "\330\265LLL\272\30\30\30\300\13\13\13\305\14\14\14\310ttt\311\23\23\23\310" "\26\26\26\304\0\0\0\275\0\0\0\264jjj\251\365\365\365\234\324\324\324\216" "\247\247\247\202ZZZy\0\0\0u\0\0\0xbbb\201\252\252\252\215\364\364\364\234" ">>>\251444\265\201\201\201\275\227\227\227\303YYY\307\21\21\21\311\0\0\0" "\311\0\0\0\310\0\0\0\305\14\14\14\300nnn\275\337\337\337\274\251\251\251" "\277222\307\324\324\324\323///\337\0\0\0\353\0\0\0\363\0\0\0\367\0\0\0\370" "\0\0\0\366\0\0\0\364mmm\361\332\332\332\360\206\206\206\361\0\0\0\364\0\0" "\0\367\0\0\0\372\0\0\0\373\0\0\0\373\0\0\0\372\0\0\0\367\0\0\0\363\0\0\0" "\356\217\217\217\352\355\355\355\350\307\307\307\352\0\0\0\355\0\0\0\362" "\0\0\0\366\0\0\0\372\0\0\0\374\0\0\0\375\0\0\0\375\326\326\326\376\342\342" "\342\376\213\213\213\376\13\13\13\377\0\0\0\377\0\0\0\376\0\0\0\375\0\0\0" "\373\0\0\0\367\0\0\0\361eee\351jjj\340KKK\327@@@\316fff\305999\272===\256" "kkk\240\277\277\277\220\255\255\255\201\0\0\0u\0\0\0o\0\0\0o333v\246\246" "\246\202\311\311\311\220\236\236\236\236RRR\253NNN\265$$$\275\0\0\0\302\0" "\0\0\304\0\0\0\303\0\0\0\276\36\36\36\266\210\210\210\252\313\313\313\234" "\325\325\325\215\14\14\14\200\0\0\0x\10\10\10w@@@|xxx\207\336\336\336\224" "\273\273\273\243999\257\3\3\3\270\0\0\0\276\27\27\27\301---\301(((\277bb" "b\273www\265RRR\256\215\215\215\247\347\347\347\241\220\220\220\237\0\0\0" "\244&&&\260\364\364\364\300jjj\323\0\0\0\343\0\0\0\360\0\0\0\370\0\0\0\374" "\0\0\0\376\0\0\0\376JJJ\377\367\367\367\377\377\377\377\377\262\262\262\377" "\35\35\35\377\24\24\24\376\0\0\0\375\0\0\0\372***\366\240\240\240\357\360" "\360\360\347\364\364\364\335\322\322\322\324KKK\315HHH\307\32\32\32\304Z" "ZZ\302\26\26\26\303\0\0\0\303rrr\305\20\20\20\307\0\0\0\310\0\0\0\310%%%" "\306AAA\301uuu\271\231\231\231\255\311\311\311\236\327\327\327\220888\204" "\0\0\0}\0\0\0}\27\27\27\203\362\362\362\217\262\262\262\235\227\227\227\252" "BBB\265\1\1\1\276<<<\302AAA\304\202\202\202\304\247\247\247\303\346\346\346" "\302bbb\301\0\0\0\300\0\0\0\275\0\0\0\270\0\0\0\255\0\0\0\235\234\234\234" "\205\344\344\344jEEEM\0\0\0""4\0\0\0\7\0\0\0\20\0\0\0\37\0\0\0""5\0\0\0V" "UUUy\334\334\334\240)))\300\0\0\0\332\0\0\0\354\0\0\0\367\0\0\0\374\0\0\0" "\376\0\0\0\377999\377\311\311\311\377\371\371\371\377\314\314\314\377\363" "\363\363\377\270\270\270\377\262\262\262\375|||\373\325\325\325\370HHH\363" "\0\0\0\356\0\0\0\351\0\0\0\343\0\0\0\337\0\0\0\334\0\0\0\332\15\15\15\330" "\13\13\13\327\0\0\0\326\0\0\0\325\4\4\4\323\3\3\3\321\7\7\7\317\313\313\313" "\316\356\356\356\316\301\301\301\321;;;\325\14\14\14\331\0\0\0\335\0\0\0" "\337\0\0\0\340\0\0\0\337\0\0\0\334\0\0\0\327\0\0\0\317\15\15\15\306+++\272" "ddd\257\237\237\237\243\222\222\222\233\0\0\0\227\22\22\22\231\321\321\321" "\241\301\301\301\255bbb\272\4\4\4\306$$$\320\21\21\21\326\26\26\26\334\14" "\14\14\337\0\0\0\340\0\0\0\340\0\0\0\337\0\0\0\334\0\0\0\330\2\2\2\324TT" "T\322\301\301\301\323\244\244\244\330\323\323\323\337(((\350\0\0\0\360\0" "\0\0\366\0\0\0\372\0\0\0\373\0\0\0\373\0\0\0\371ggg\370\362\362\362\367P" "PP\370\0\0\0\371\0\0\0\373\0\0\0\375\0\0\0\376\0\0\0\376\0\0\0\375\0\0\0" "\372\0\0\0\370\0\0\0\365FFF\363\342\342\342\362nnn\362\0\0\0\365\0\0\0\367" "\0\0\0\371\0\0\0\373\0\0\0\374\0\0\0\374\2\2\2\375\335\335\335\375\345\345" "\345\376sss\376\30\30\30\377\0\0\0\377\0\0\0\377\0\0\0\376\0\0\0\375\0\0" "\0\373\0\0\0\367\16\16\16\363333\356\2\2\2\350\0\0\0\342\0\0\0\333\0\0\0" "\323\0\0\0\311\0\0\0\274\30\30\30\255\346\346\346\237\264\264\264\224\3\3" "\3\216fff\220\244\244\244\227\350\350\350\242bbb\257\16\16\16\274\0\0\0\307" "\0\0\0\320\0\0\0\327\0\0\0\333\0\0\0\334\0\0\0\334\0\0\0\327\0\0\0\320\0" "\0\0\306CCC\271\321\321\321\254\333\333\333\241666\231\34\34\34\230\232\232" "\232\235\327\327\327\247\240\240\240\263\16\16\16\300\0\0\0\313\0\0\0\323" "\0\0\0\330\0\0\0\332\0\0\0\332\0\0\0\331\0\0\0\325\0\0\0\321\6\6\6\313''" "'\303}}}\275\341\341\341\271\204\204\204\273)))\302\364\364\364\316===\334" "\0\0\0\351\0\0\0\363\0\0\0\371\0\0\0\375\0\0\0\376\0\0\0\377\262\262\262" "\377\366\366\366\377\277\277\277\377333\377\0\0\0\377\0\0\0\377\0\0\0\376" "\0\0\0\374\0\0\0\372KKK\365\337\337\337\361\353\353\353\353HHH\345\1\1\1" "\341\0\0\0\336\0\0\0\334\0\0\0\333\0\0\0\333\0\0\0\334\0\0\0\335\0\0\0\337" "\0\0\0\337\0\0\0\337\0\0\0\336\0\0\0\332\0\0\0\322\0\0\0\310TTT\274xxx\257" "\315\315\315\243\0\0\0\235---\236\341\341\341\244\304\304\304\257???\273" "\1\1\1\307\0\0\0\320\0\0\0\327\0\0\0\333\0\0\0\335\0\0\0\335666\334CCC\333" "\0\0\0\332\0\0\0\331\0\0\0\325\0\0\0\317\0\0\0\301\0\0\0\256\0\0\0\223ii" "iusssT\0\0\0""9\0\0\0\11\0\0\0\22\0\0\0#\0\0\0;\0\0\0\\###\177\355\355\355" "\245III\304\0\0\0\336\0\0\0\356\0\0\0\367\0\0\0\374\0\0\0\376\0\0\0\377\12" "\12\12\377***\377JJJ\377```\377\232\232\232\377KKK\377\0\0\0\376EEE\375\300" "\300\300\373\40\40\40\371\0\0\0\366\0\0\0\363\0\0\0\360\0\0\0\356\0\0\0\353" "\0\0\0\351\0\0\0\347\0\0\0\346\0\0\0\346\0\0\0\346\0\0\0\345\0\0\0\345\10" "\10\10\344\205\205\205\344sss\344\32\32\32\346\0\0\0\351\0\0\0\353\0\0\0" "\356\0\0\0\360\0\0\0\360\0\0\0\357\0\0\0\355\0\0\0\352\0\0\0\344\0\0\0\335" "\0\0\0\324\0\0\0\313***\302\343\343\343\273JJJ\270\345\345\345\271\361\361" "\361\300\254\254\254\311\21\21\21\324\0\0\0\335\0\0\0\344\0\0\0\352\0\0\0" "\355\0\0\0\357\0\0\0\360\0\0\0\360\0\0\0\357\0\0\0\355\0\0\0\352\0\0\0\347" "\24\24\24\344ZZZ\344\343\343\343\345\340\340\340\352\20\20\20\360\0\0\0\365" "\0\0\0\371\0\0\0\374\0\0\0\375\0\0\0\375\0\0\0\375\15\15\15\374\264\264\264" "\374:::\374\0\0\0\374\0\0\0\375\0\0\0\376\0\0\0\377\0\0\0\377\0\0\0\376\0" "\0\0\375\0\0\0\373\0\0\0\372uuu\371\242\242\242\370AAA\370\0\0\0\371\0\0" "\0\372\0\0\0\372\0\0\0\372\0\0\0\371\10\10\10\371uuu\371\366\366\366\372" "\361\361\361\373\200\200\200\375\0\0\0\376\0\0\0\377\0\0\0\377\0\0\0\377" "\0\0\0\376\0\0\0\375\0\0\0\374\0\0\0\371\0\0\0\367\0\0\0\364\0\0\0\360\0" "\0\0\354\0\0\0\346\0\0\0\336\0\0\0\324\0\0\0\310\263\263\263\273XXX\262K" "KK\256\340\340\340\260vvv\267\203\203\203\300&&&\313\0\0\0\326\0\0\0\337" "\0\0\0\345\0\0\0\352\0\0\0\355\0\0\0\356\0\0\0\355\0\0\0\352\0\0\0\345\0" "\0\0\335\0\0\0\323888\311\307\307\307\277\261\261\261\271ttt\271\273\273" "\273\275\333\333\333\305===\317\0\0\0\331\0\0\0\341\0\0\0\347\0\0\0\353\0" "\0\0\354\0\0\0\355\0\0\0\353\0\0\0\351\0\0\0\346\0\0\0\341\0\0\0\333\0\0" "\0\325///\321\335\335\335\321ooo\325\274\274\274\335\4\4\4\346\0\0\0\357" "\0\0\0\366\0\0\0\373\0\0\0\376\0\0\0\377\26\26\26\377\331\331\331\377\361" "\361\361\377\202\202\202\377...\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\376" "\0\0\0\374\242\242\242\372\265\265\265\367\362\362\362\365___\362\21\21\21" "\360\0\0\0\357\0\0\0\356\0\0\0\355\0\0\0\356\0\0\0\356\0\0\0\357\0\0\0\357" "\0\0\0\360\0\0\0\360\0\0\0\356\0\0\0\353\0\0\0\346\0\0\0\336\0\0\0\324\0" "\0\0\312\345\345\345\301```\275\356\356\356\275\274\274\274\302\25\25\25" "\313\0\0\0\324\0\0\0\336\0\0\0\345\0\0\0\352\0\0\0\355\0\0\0\356\0\0\0\356" "\0\0\0\356\0\0\0\355\0\0\0\354\0\0\0\352\0\0\0\345\0\0\0\335\0\0\0\315\0" "\0\0\270EEE\231\277\277\277ynnnV\0\0\0:\0\0\0\13\0\0\0\26\0\0\0)\0\0\0B\0" "\0\0dXXX\207\274\274\274\254\0\0\0\312\0\0\0\341\0\0\0\357\0\0\0\370\0\0" "\0\374\0\0\0\375\0\0\0\376\0\0\0\375\0\0\0\375\0\0\0\375\0\0\0\376;;;\376" "000\376***\376\0\0\0\376\0\0\0\375\0\0\0\374\0\0\0\373\0\0\0\371\0\0\0\366" "\0\0\0\364\0\0\0\360\0\0\0\356\0\0\0\353\0\0\0\352\0\0\0\353\0\0\0\354\0" "\0\0\356\0\0\0\357KKK\360fff\361%%%\361\0\0\0\362\0\0\0\364\0\0\0\366\0\0" "\0\367\0\0\0\370\0\0\0\371\0\0\0\370\0\0\0\367\0\0\0\365\0\0\0\361\0\0\0" "\355\0\0\0\347\0\0\0\340\0\0\0\331\244\244\244\324\365\365\365\321\305\305" "\305\323'''\327\24\24\24\336\0\0\0\346\0\0\0\354\0\0\0\361\0\0\0\365\0\0" "\0\367\0\0\0\370\1\1\1\371\0\0\0\371\0\0\0\370\0\0\0\366\0\0\0\364\0\0\0" "\362\0\0\0\360\17\17\17\357\330\330\330\360\341\341\341\362LLL\365\0\0\0" "\371\0\0\0\373\0\0\0\375\0\0\0\376\0\0\0\376\0\0\0\376\0\0\0\376\20\20\20" "\376\14\14\14\376\0\0\0\376\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0" "\377\0\0\0\376\0\0\0\376\0\0\0\375666\374,,,\373\3\3\3\373\0\0\0\373\0\0" "\0\372\0\0\0\370\0\0\0\366\0\0\0\364\16\16\16\363\334\334\334\364\276\276" "\276\366\334\334\334\370RRR\373\0\0\0\375\0\0\0\376\0\0\0\377\0\0\0\377\0" "\0\0\377\0\0\0\377\0\0\0\376\0\0\0\375\0\0\0\374\0\0\0\372\0\0\0\370\0\0" "\0\366\0\0\0\362\0\0\0\354\0\0\0\344\2\2\2\332\265\265\265\321HHH\312\276" "\276\276\307\321\321\321\311\7\7\7\317\17\17\17\327\7\7\7\340\0\0\0\347\0" "\0\0\355\0\0\0\362\1\1\1\365\3\3\3\367\1\1\1\367\0\0\0\367\0\0\0\365\0\0" "\0\361\0\0\0\354\0\0\0\345\0\0\0\336uuu\327\346\346\346\322\331\331\331\322" "\323\323\323\325MMM\333\0\0\0\342\0\0\0\351\0\0\0\357\0\0\0\363\27\27\27" "\365666\367+++\367\5\5\5\366\0\0\0\365\0\0\0\362\0\0\0\357\0\0\0\353\0\0" "\0\346\23\23\23\343\337\337\337\342\344\344\344\344JJJ\351\0\0\0\357\0\0" "\0\365\0\0\0\371\0\0\0\374\0\0\0\376\0\0\0\377'''\377\322\322\322\377\343" "\343\343\377\40\40\40\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377" "\0\0\0\376\340\340\340\375\323\323\323\374\202\202\202\372RRR\371!!!\370" "\0\0\0\367\0\0\0\367\0\0\0\367\0\0\0\367\0\0\0\370\0\0\0\370\2\2\2\370\0" "\0\0\370\0\0\0\370\0\0\0\367\0\0\0\365\0\0\0\362\0\0\0\355\0\0\0\345\0\0" "\0\336sss\330\350\350\350\325\326\326\326\325>>>\331\0\0\0\337\0\0\0\346" "\0\0\0\355\0\0\0\361\0\0\0\365\0\0\0\367\0\0\0\367\0\0\0\367\0\0\0\367\0" "\0\0\367\0\0\0\366\0\0\0\363\0\0\0\355\0\0\0\343\0\0\0\321\2\2\2\271\350" "\350\350\230hhhw\21\21\21S\0\0\0""7\0\0\0\15\0\0\0\32\0\0\0/\0\0\0J\0\0\0" "n\307\307\307\221ZZZ\265\0\0\0\320\0\0\0\345\0\0\0\362\0\0\0\370\0\0\0\373" "\0\0\0\373\0\0\0\372\0\0\0\371\0\0\0\371\0\0\0\371\0\0\0\372\0\0\0\373\0" "\0\0\374\0\0\0\375\0\0\0\376\0\0\0\376\0\0\0\375\0\0\0\374\0\0\0\373\0\0" "\0\370\0\0\0\364\0\0\0\357\0\0\0\352\0\0\0\346\0\0\0\345\0\0\0\346\0\0\0" "\352\0\0\0\357\0\0\0\362\15\15\15\365\36\36\36\367\0\0\0\371\0\0\0\372\0" "\0\0\373\0\0\0\374\0\0\0\374\1\1\1\375UUU\375QQQ\375\0\0\0\374\0\0\0\373" "\0\0\0\371\0\0\0\367\0\0\0\363\0\0\0\357\10\10\10\352\230\230\230\347\207" "\207\207\345,,,\346\0\0\0\351\0\0\0\355\0\0\0\362\0\0\0\366\0\0\0\371\0\0" "\0\373\0\0\0\374\22\22\22\375qqq\375,,,\375\0\0\0\374\0\0\0\374\0\0\0\372" "\0\0\0\371\0\0\0\367\0\0\0\367|||\367\351\351\351\370UUU\372\0\0\0\373\0" "\0\0\375\0\0\0\376\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0" "\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0" "\377\0\0\0\377\0\0\0\376\0\0\0\376\0\0\0\375\0\0\0\374\0\0\0\373\0\0\0\370" "\0\0\0\364\0\0\0\360\0\0\0\354FFF\353\321\321\321\354CCC\357\365\365\365" "\363\31\31\31\370\0\0\0\373\0\0\0\375\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0" "\377\0\0\0\377\0\0\0\377\0\0\0\376\0\0\0\376\0\0\0\375\0\0\0\373\0\0\0\371" "\0\0\0\365\0\0\0\357sss\351\372\372\372\343\256\256\256\336\210\210\210\335" "\7\7\7\336\0\0\0\343\0\0\0\351\0\0\0\356\0\0\0\363\0\0\0\367\17\17\17\371" "OOO\373\214\214\214\374555\374\4\4\4\374\0\0\0\373\0\0\0\371\0\0\0\366\0" "\0\0\362\0\0\0\355\33\33\33\351\272\272\272\346\333\333\333\346\255\255\255" "\350\11\11\11\353\0\0\0\360\0\0\0\364\0\0\0\367\13\13\13\372rrr\373hhh\374" "\223\223\223\374LLL\374\0\0\0\373\0\0\0\372\0\0\0\370\0\0\0\365\0\0\0\362" "\6\6\6\360\274\274\274\357\340\340\340\360\\\\\\\362\0\0\0\366\0\0\0\371" "\0\0\0\374\0\0\0\376\0\0\0\377\0\0\0\377qqq\377\344\344\344\377\314\314\314" "\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377nnn\377\334" "\334\334\376\326\326\326\376\12\12\12\376\0\0\0\375\0\0\0\375\0\0\0\375\0" "\0\0\375\0\0\0\375\0\0\0\375***\375|||\375\244\244\244\375@@@\375\0\0\0\375" "\0\0\0\374\0\0\0\373\0\0\0\371\0\0\0\366\0\0\0\362\21\21\21\355\330\330\330" "\351\360\360\360\347ggg\350\0\0\0\352\0\0\0\356\0\0\0\362\0\0\0\366\0\0\0" "\371\0\0\0\373\0\0\0\374\0\0\0\375\0\0\0\375\0\0\0\375\0\0\0\374\0\0\0\372" "\0\0\0\367\0\0\0\360\0\0\0\344\0\0\0\320\221\221\221\265\263\263\263\222" "\0\0\0p\0\0\0L\0\0\0""1\0\0\0\20\0\0\0\36\0\0\0""5\0\0\0R\177\177\177w\355" "\355\355\233000\275\0\0\0\326\0\0\0\351\0\0\0\363\0\0\0\370\0\0\0\371\0\0" "\0\367\0\0\0\365\0\0\0\363\0\0\0\362\0\0\0\362\0\0\0\363\0\0\0\365\0\0\0" "\367\0\0\0\372\0\0\0\373\0\0\0\375\0\0\0\375\0\0\0\374\0\0\0\372\0\0\0\366" "\0\0\0\360\0\0\0\350\30\30\30\340yyy\333\205\205\205\331YYY\333\16\16\16" "\341\0\0\0\351\0\0\0\360\0\0\0\366\0\0\0\371\0\0\0\374\0\0\0\375\0\0\0\376" "\0\0\0\376\0\0\0\377\33\33\33\377\307\307\307\377\337\337\337\377\0\0\0\377" "\0\0\0\376\0\0\0\375\0\0\0\374\0\0\0\371\0\0\0\367\200\200\200\365\222\222" "\222\362---\362\0\0\0\362\0\0\0\364\0\0\0\366\0\0\0\371\0\0\0\373\0\0\0\375" "\0\0\0\376QQQ\377iii\377\204\204\204\377\17\17\17\377\0\0\0\377\0\0\0\376" "\0\0\0\375\0\0\0\374\0\0\0\373\0\0\0\372\252\252\252\372\344\344\344\372" "---\373\0\0\0\375\0\0\0\376\0\0\0\376\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0" "\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\20\20\20\377777\377\0\0\0\377" "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\376\0\0\0\374\0" "\0\0\371\0\0\0\365\0\0\0\356\0\0\0\350444\343\347\347\347\341\224\224\224" "\342\322\322\322\350\327\327\327\356\25\25\25\364\0\0\0\371\0\0\0\375\0\0" "\0\376\0\0\0\377\0\0\0\377OOO\377\252\252\252\377\257\257\257\377aaa\377" "fff\377\0\0\0\377\0\0\0\376\0\0\0\374\0\0\0\371\0\0\0\366NNN\362\365\365" "\365\356\302\302\302\353&&&\353\0\0\0\354\0\0\0\357\0\0\0\363\0\0\0\367\0" "\0\0\372\0\0\0\374NNN\375ttt\376UUU\377\"\"\"\377\0\0\0\376\0\0\0\376\0\0" "\0\375\0\0\0\373\0\0\0\371\0\0\0\366\5\5\5\364)))\362\36\36\36\362\36\36" "\36\363\2\2\2\365\0\0\0\370\0\0\0\372\0\0\0\374\3\3\3\375FFF\376}}}\376z" "zz\377\23\23\23\376\0\0\0\376\0\0\0\375\0\0\0\374\0\0\0\373\0\0\0\371###" "\367\365\365\365\367\240\240\240\367\21\21\21\370\0\0\0\372\0\0\0\374\0\0" "\0\376\0\0\0\376\0\0\0\377DDD\377\305\305\305\377\340\340\340\377QQQ\377" "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377222\377\322\322\322\377" "\237\237\237\377\350\350\350\377\11\11\11\377\0\0\0\377\0\0\0\377\0\0\0\377" "\0\0\0\377\0\0\0\377\14\14\14\377\241\241\241\377\361\361\361\377\364\364" "\364\377```\377\0\0\0\377\0\0\0\377\0\0\0\376\0\0\0\375\0\0\0\373\0\0\0\371" "]]]\366\316\316\316\364\307\307\307\363\22\22\22\363\0\0\0\364\0\0\0\366" "\0\0\0\371\0\0\0\373\0\0\0\375\37\37\37\376ooo\377\313\313\313\377LLL\377" "\0\0\0\377\0\0\0\376\0\0\0\374\0\0\0\371\0\0\0\361\0\0\0\343\37\37\37\315" "\312\312\312\260ddd\214\0\0\0i\0\0\0F\0\0\0,\0\0\0\23\0\0\0#\0\0\0<\1\1\1" "[\323\323\323\201+++\244\0\0\0\305\0\0\0\334\0\0\0\354\0\0\0\364\0\0\0\366" "\0\0\0\364\0\0\0\360\13\13\13\353\31\31\31\346\20\20\20\344\0\0\0\344\0\0" "\0\346\0\0\0\352\0\0\0\356\0\0\0\363\0\0\0\367\0\0\0\372\0\0\0\373\0\0\0" "\373\0\0\0\370\0\0\0\362\2\2\2\350}}}\335\336\336\336\321\357\357\357\311" "\327\327\327\306\344\344\344\312\345\345\345\323000\337\0\0\0\352\0\0\0\363" "\0\0\0\371\0\0\0\374\0\0\0\376\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0" "\0\0\377\26\26\26\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\376\0\0\0\375\0" "\0\0\374yyy\373hhh\372\0\0\0\372\0\0\0\372\0\0\0\373\0\0\0\374\0\0\0\375" "\0\0\0\376\0\0\0\377\0\0\0\377999\377***\377\0\0\0\377\0\0\0\377\0\0\0\377" "\0\0\0\377\0\0\0\376\0\0\0\375\0\0\0\374qqq\373\342\342\342\372\336\336\336" "\373\0\0\0\373\0\0\0\374\0\0\0\376\0\0\0\376\0\0\0\377\0\0\0\377\0\0\0\377" "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377444\377\242\242\242\377" "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\376\0" "\0\0\373\0\0\0\366\0\0\0\360\0\0\0\347\204\204\204\335\360\360\360\327\343" "\343\343\324&&&\327\334\334\334\337999\350\5\5\5\361\0\0\0\367\0\0\0\373" "\0\0\0\376\0\0\0\377\37\37\37\377\334\334\334\377\265\265\265\377\357\357" "\357\377\265\265\265\377555\377\0\0\0\377\0\0\0\377\0\0\0\376\0\0\0\375\0" "\0\0\373]]]\370\345\345\345\366\216\216\216\365\0\0\0\364\0\0\0\365\0\0\0" "\370\0\0\0\372\0\0\0\374\0\0\0\375QQQ\376999\377)))\377\0\0\0\377\0\0\0\377" "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\376\0\0\0\375\0\0\0\373aaa\372QQQ\372" "\0\0\0\372\0\0\0\372\0\0\0\373\0\0\0\374\0\0\0\375\0\0\0\376\0\0\0\377\0" "\0\0\377\36\36\36\377\17\17\17\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\376" "\0\0\0\376\0\0\0\375000\374\353\353\353\374DDD\374\0\0\0\374\0\0\0\375\0" "\0\0\376\0\0\0\376\0\0\0\377\0\0\0\377\276\276\276\377\366\366\366\377\330" "\330\330\377\10\10\10\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377" "\230\230\230\377\300\300\300\377\302\302\302\377\237\237\237\377\0\0\0\377" "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\234\234\234\377\334\334" "\334\377xxx\377\342\342\342\377MMM\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0" "\0\377\0\0\0\376\0\0\0\375~~~\373\247\247\247\372\0\0\0\372\0\0\0\372\0\0" "\0\373\0\0\0\374\0\0\0\375\0\0\0\376DDD\377\237\237\237\377\345\345\345\377" "\331\331\331\377\311\311\311\377\1\1\1\377\0\0\0\377\0\0\0\375\0\0\0\370" "\0\0\0\357\0\0\0\341\177\177\177\310\320\320\320\252iii\204\0\0\0a\0\0\0" "?\0\0\0&\0\0\0\26\0\0\0'\0\0\0C\1\1\1c\316\316\316\212\10\10\10\254\0\0\0" "\313\0\0\0\341\0\0\0\356\0\0\0\364\0\0\0\363\27\27\27\357\216\216\216\346" "\222\222\222\336\240\240\240\326\307\307\307\322\23\23\23\321\23\23\23\324" "\0\0\0\333EEE\342\36\36\36\352\0\0\0\361\0\0\0\366\0\0\0\371\0\0\0\371\0" "\0\0\365\0\0\0\354\4\4\4\340\337\337\337\320\241\241\241\301777\266\10\10" "\10\263\33\33\33\270\255\255\255\304\241\241\241\324\0\0\0\343\0\0\0\357" "\0\0\0\367\0\0\0\374\0\0\0\376\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0" "\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0" "\0\376\0\0\0\375\0\0\0\375\0\0\0\375\0\0\0\375\0\0\0\375\0\0\0\376\0\0\0" "\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377" "\0\0\0\377\0\0\0\376\0\0\0\376\0\0\0\374\0\0\0\372BBB\371\327\327\327\370" "\337\337\337\370\0\0\0\371\0\0\0\373\0\0\0\375\0\0\0\376\0\0\0\377\0\0\0" "\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\376\5\5\5\376FFF\376)" "))\376\0\0\0\376\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0" "\375\0\0\0\371\0\0\0\363\0\0\0\352\0\0\0\337\324\324\324\323RRR\313///\311" "lll\315\275\275\275\327\0\0\0\343\0\0\0\356\0\0\0\366\0\0\0\373\0\0\0\375" "\0\0\0\376\237\237\237\377\332\332\332\377\0\0\0\377\325\325\325\377\177" "\177\177\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\376\0\0\0\374" "\11\11\11\373\214\214\214\372\36\36\36\371\0\0\0\372\0\0\0\372\0\0\0\373" "\0\0\0\375\0\0\0\376\0\0\0\377\26\26\26\377\2\2\2\377\0\0\0\377\0\0\0\377" "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\376\0\0\0\376\20" "\20\20\375\10\10\10\375\0\0\0\375\0\0\0\375\0\0\0\376\0\0\0\376\0\0\0\377" "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0" "\0\0\377\0\0\0\377\0\0\0\377\0\0\0\376\207\207\207\376\377\377\377\376tt" "t\376\0\0\0\376\0\0\0\376\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\276\276" "\276\377\240\240\240\377\241\241\241\377\0\0\0\377\0\0\0\377\0\0\0\377\0" "\0\0\377\0\0\0\377'''\377\303\303\303\377\236\236\236\377\353\353\353\377" "III\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377@@@\377\327\327" "\327\377\36\36\36\377***\377\342\342\342\377&&&\377\0\0\0\377\0\0\0\377\0" "\0\0\377\0\0\0\377\0\0\0\377\40\40\40\376\314\314\314\376\\\\\\\375\0\0\0" "\375\0\0\0\375\0\0\0\375\0\0\0\376\0\0\0\377\0\0\0\377\271\271\271\377\356" "\356\356\377AAA\377\264\264\264\377\246\246\246\377\1\1\1\377\0\0\0\377\0" "\0\0\374\0\0\0\370\0\0\0\356\0\0\0\336iii\305\365\365\365\245:::\177\0\0" "\0[\0\0\0:\0\0\0#\0\0\0\30\0\0\0+\0\0\0I\1\1\1j\305\305\305\221\0\0\0\263" "\0\0\0\321\0\0\0\344\0\0\0\360\0\0\0\362\0\0\0\357\27\27\27\347\222\222\222" "\332\304\304\304\314\316\316\316\300\352\352\352\271\356\356\356\267\327" "\327\327\273\213\213\213\305\261\261\261\321\346\346\346\336~~~\351\0\0\0" "\361\0\0\0\366\0\0\0\366\0\0\0\362\0\0\0\347\6\6\6\330\352\352\352\304$$" "$\261\0\0\0\242\0\0\0\235\0\0\0\244\316\316\316\262yyy\307\0\0\0\332\0\0" "\0\352\0\0\0\364\0\0\0\372\0\0\0\376\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0" "\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377" "\0\0\0\376\0\0\0\376\0\0\0\376\0\0\0\376\0\0\0\376\0\0\0\376\0\0\0\377\0" "\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0" "\0\377\0\0\0\377\0\0\0\376\0\0\0\374\0\0\0\372\0\0\0\367mmm\364\331\331\331" "\363\267\267\267\363\31\31\31\365\0\0\0\367\0\0\0\372\0\0\0\374\0\0\0\376" "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\376\0\0\0\375\0\0\0\375\203\203\203" "\374\330\330\330\374ccc\374\0\0\0\375\0\0\0\376\0\0\0\376\0\0\0\377\0\0\0" "\377\0\0\0\376\0\0\0\374\0\0\0\370\0\0\0\360\0\0\0\345\12\12\12\326\320\320" "\320\311\0\0\0\277\0\0\0\276\252\252\252\304\214\214\214\320\0\0\0\337\0" "\0\0\353\0\0\0\364\0\0\0\372\0\0\0\374\5\5\5\375\201\201\201\375\244\244" "\244\375\0\0\0\375\330\330\330\375\243\243\243\376\0\0\0\376\0\0\0\377\0" "\0\0\377\0\0\0\376\0\0\0\376\0\0\0\375\330\330\330\374\361\361\361\373\27" "\27\27\373\0\0\0\373\0\0\0\374\0\0\0\375\0\0\0\376\0\0\0\377\0\0\0\377\0" "\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0" "\0\377\0\0\0\377\0\0\0\377\0\0\0\376\0\0\0\376\0\0\0\376\0\0\0\376\0\0\0" "\376\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377" "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\37733" "3\377\235\235\235\377ddd\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0" "\0\377###\377\344\344\344\377000\377\245\245\245\377\0\0\0\377\0\0\0\377" "\0\0\0\377\0\0\0\377\0\0\0\377\1\1\1\377eee\377\260\260\260\377\241\241\241" "\377nnn\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377!!!\377\335" "\335\335\377\227\227\227\377+++\377\362\362\362\377OOO\377\0\0\0\377\0\0" "\0\377\0\0\0\377\0\0\0\377\0\0\0\377777\377\375\375\375\377iii\377\0\0\0" "\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377$$$\377\321\321\321" "\377666\377\357\357\357\377\320\320\320\377XXX\377\0\0\0\377\0\0\0\374\0" "\0\0\367\0\0\0\355\0\0\0\334\22\22\22\302\321\321\321\241gggz\0\0\0W\0\0" "\0""6\0\0\0\40\0\0\0\33\0\0\0/\0\0\0N\1\1\1p\350\350\350\227\40\40\40\271" "\0\0\0\325\0\0\0\347\0\0\0\360\0\0\0\361\0\0\0\352\0\0\0\336xxx\314\223\223" "\223\272\0\0\0\251...\236888\233\323\323\323\241\361\361\361\256\353\353" "\353\276\355\355\355\320\204\204\204\340\0\0\0\354\0\0\0\362\0\0\0\364\0" "\0\0\357\0\0\0\343\6\6\6\321\354\354\354\271kkk\243\0\0\0\222\0\0\0\214\0" "\0\0\222\317\317\317\243mmm\273\0\0\0\321\0\0\0\344\0\0\0\361\0\0\0\371\0" "\0\0\374\0\0\0\377\0\0\0\377\22\22\22\377MMM\377\0\0\0\377\0\0\0\377\0\0" "\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\376\25\25\25\375\211\211\211\375" "ccc\375\0\0\0\375\0\0\0\375\0\0\0\376\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0" "\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\33\33\33\376nnn\374" "888\372---\366222\362uuu\356\366\366\366\353\342\342\342\354$$$\357\0\0\0" "\363\0\0\0\367\0\0\0\373\0\0\0\375\0\0\0\376\0\0\0\376\0\0\0\376\0\0\0\374" "\0\0\0\373\0\0\0\371\322\322\322\370\351\351\351\370\303\303\303\371\0\0" "\0\372\0\0\0\374\0\0\0\375\0\0\0\376\0\0\0\377\0\0\0\376\0\0\0\373\0\0\0" "\365\0\0\0\355\0\0\0\337===\317\341\341\341\301\0\0\0\267\0\0\0\266\254\254" "\254\276\277\277\277\314\0\0\0\334\0\0\0\352\0\0\0\364\0\0\0\371\0\0\0\373" "\0\0\0\373qqq\373\236\236\236\372\0\0\0\372\332\332\332\373<<<\374\0\0\0" "\375\0\0\0\376\0\0\0\376\0\0\0\376\0\0\0\374\0\0\0\373\333\333\333\372\347" "\347\347\371\27\27\27\372\0\0\0\372\0\0\0\374\0\0\0\375\0\0\0\376\0\0\0\377" "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\15\15\15\377" "nnn\377\35\35\35\377\0\0\0\377\0\0\0\376111\376\40\40\40\376\0\0\0\376\0" "\0\0\376\0\0\0\376\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377+++\377777\377" "\0\0\0\377%%%\377\3\3\3\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0" "\377\0\0\0\377\224\224\224\377\234\234\234\377\0\0\0\377\0\0\0\377\0\0\0" "\377\0\0\0\377\0\0\0\377$$$\377\346\346\346\377uuu\377\245\245\245\377\0" "\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\376DDD\376\367\367" "\367\376\354\354\354\376^^^\376\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0" "\0\0\377\0\0\0\376\321\321\321\376\224\224\224\376\31\31\31\376\342\342\342" "\377\7\7\7\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377bbb\377\371" "\371\371\377___\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0" "\0\377\24\24\24\377\356\356\356\377}}}\377\361\361\361\377\235\235\235\377" "\24\24\24\377\0\0\0\376\0\0\0\374\0\0\0\366\0\0\0\353\0\0\0\332\12\12\12" "\276\316\316\316\236AAAw\0\0\0T\0\0\0""3\0\0\0\36\0\0\0\35\0\0\0""3\0\0\0" "S999u\350\350\350\235###\276\0\0\0\330\0\0\0\350\0\0\0\360\0\0\0\356\0\0" "\0\344\0\0\0\324\216\216\216\275\222\222\222\246\0\0\0\220\0\0\0\202\0\0" "\0~\10\10\10\205\12\12\12\226\11\11\11\253ttt\302\350\350\350\326\0\0\0\346" "\0\0\0\357\0\0\0\361\0\0\0\353\0\0\0\336\5\5\5\311\370\370\370\257\215\215" "\215\226\0\0\0\202\0\0\0{\0\0\0\202hhh\224\274\274\274\256\0\0\0\306\0\0" "\0\335\0\0\0\354\0\0\0\366\0\0\0\373\0\0\0\376\2\2\2\377FFF\377\231\231\231" "\377kkk\377'''\377'''\377\35\35\35\377\30\30\30\376\40\40\40\375\0\0\0\374" "\245\245\245\372\365\365\365\372\335\335\335\371\0\0\0\372\0\0\0\373\0\0" "\0\374\0\0\0\375\0\0\0\376\0\0\0\377\0\0\0\377\17\17\17\377\"\"\"\377NNN" "\377\305\305\305\377\260\260\260\376\206\206\206\375\325\325\325\372KKK\366" "444\360\234\234\234\352\343\343\343\344\245\245\245\341\237\237\237\342T" "TT\347\0\0\0\355\0\0\0\364\0\0\0\371\0\0\0\374\0\0\0\375\0\0\0\374\0\0\0" "\373\0\0\0\371\0\0\0\366\0\0\0\363sss\362\361\361\361\362\342\342\342\363" "\0\0\0\366\0\0\0\371\0\0\0\373\0\0\0\375\0\0\0\375\0\0\0\374\0\0\0\371\0" "\0\0\362\0\0\0\350\0\0\0\331$$$\310\331\331\331\270\0\0\0\257\0\0\0\260x" "xx\271\334\334\334\311\35\35\35\333\0\0\0\351\0\0\0\363\0\0\0\367\0\0\0\370" "\0\0\0\367@@@\366\344\344\344\366...\366\347\347\347\367VVV\371\0\0\0\374" "\0\0\0\375\0\0\0\374\0\0\0\373\0\0\0\371\0\0\0\367~~~\365\364\364\364\364" "kkk\365\0\0\0\366\0\0\0\370\0\0\0\373\0\0\0\375\0\0\0\376\0\0\0\377\22\22" "\22\377~~~\377\233\233\233\377~~~\377\212\212\212\377aaa\377ddd\376\235\235" "\235\376\0\0\0\375\14\14\14\374\260\260\260\373\256\256\256\373\0\0\0\373" "\0\0\0\374\0\0\0\375\0\0\0\376\0\0\0\376\0\0\0\377\0\0\0\377\232\232\232" "\377\310\310\310\377\257\257\257\377\365\365\365\377\242\242\242\377\201" "\201\201\377\21\21\21\377\22\22\22\377\23\23\23\377\26\26\26\377\234\234" "\234\377\354\354\354\377\270\270\270\377\0\0\0\377\0\0\0\377\0\0\0\377\0" "\0\0\377\0\0\0\377\1\1\1\377\255\255\255\377\237\237\237\377\357\357\357" "\377\13\13\13\377\0\0\0\377\0\0\0\377\0\0\0\376\0\0\0\375\0\0\0\374\213\213" "\213\374\362\362\362\373\362\362\362\374\216\216\216\375\0\0\0\376\0\0\0" "\376\0\0\0\376\0\0\0\376\0\0\0\375\0\0\0\374\260\260\260\373\235\235\235" "\373$$$\374\365\365\365\374888\375\0\0\0\376\0\0\0\377\0\0\0\377\0\0\0\377" "\0\0\0\377\11\11\11\377,,,\377qqq\377\33\33\33\377\0\0\0\377\0\0\0\377\0" "\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377KKK\377\320\320\320\377\322\322\322" "\377\214\214\214\377\0\0\0\377\0\0\0\376\0\0\0\373\0\0\0\365\0\0\0\351\0" "\0\0\327\6\6\6\273\305\305\305\232fffr\0\0\0P\0\0\0""1\0\0\0\34\0\0\0\40" "\0\0\0""6\0\0\0Wnnnz\265\265\265\241\0\0\0\301\0\0\0\333\0\0\0\351\0\0\0" "\357\0\0\0\353\0\0\0\336\0\0\0\312\223\223\223\257rrr\224\0\0\0z\0\0\0k\0" "\0\0f\0\0\0n\0\0\0\202\3\3\3\233\335\335\335\267YYY\316\0\0\0\341\0\0\0\353" "\0\0\0\355\0\0\0\347\0\0\0\327\3\3\3\301\262\262\262\245\321\321\321\212" "\0\0\0u\0\0\0l\0\0\0sqqq\205\260\260\260\240\0\0\0\273\0\0\0\324\0\0\0\345" "\0\0\0\361\0\0\0\370\0\0\0\374\25\25\25\376444\376\355\355\355\377\317\317" "\317\377\311\311\311\377\256\256\256\376\224\224\224\375\254\254\254\374" "\260\260\260\372\0\0\0\370222\365\372\372\372\363\242\242\242\362\0\0\0\363" "\0\0\0\365\0\0\0\370\0\0\0\372\0\0\0\374\0\0\0\376\0\0\0\377bbb\377\332\332" "\332\377\316\316\316\377\370\370\370\376\245\245\245\375\240\240\240\372" "iii\366\14\14\14\361\2\2\2\351~~~\340\336\336\336\331\22\22\22\325rrr\327" "\231\231\231\336\0\0\0\346\0\0\0\357\0\0\0\365\0\0\0\371\0\0\0\372\0\0\0" "\371\0\0\0\366\0\0\0\362\0\0\0\356\0\0\0\352\207\207\207\350\316\316\316" "\350\331\331\331\353\0\0\0\360\0\0\0\365\0\0\0\371\0\0\0\373\0\0\0\373\0" "\0\0\372\0\0\0\366\0\0\0\355\0\0\0\341\13\13\13\321\236\236\236\277\342\342" "\342\260\0\0\0\250%%%\252\276\276\276\266\323\323\323\307;;;\331\0\0\0\350" "\0\0\0\360\0\0\0\364\0\0\0\363\0\0\0\361\202\202\202\357\367\367\367\356" "\252\252\252\357\350\350\350\362\221\221\221\366\0\0\0\371\0\0\0\372\0\0" "\0\372\0\0\0\370\0\0\0\364\0\0\0\360~~~\354\365\365\365\353HHH\353\0\0\0" "\356\0\0\0\363\0\0\0\367\0\0\0\372\0\0\0\375\34\34\34\376www\377\374\374" "\374\377\371\371\371\377\335\335\335\376\361\361\361\376\306\306\306\375" "<<<\374222\372\0\0\0\371KKK\367\226\226\226\366\241\241\241\365666\366\0" "\0\0\367\0\0\0\371\0\0\0\373\0\0\0\375\0\0\0\376\0\0\0\376bbb\377\360\360" "\360\377\367\367\367\377\323\323\323\377\353\353\353\377\351\351\351\377" "\221\221\221\377vvv\377GGG\376\33\33\33\376\302\302\302\376\372\372\372\376" "NNN\376\0\0\0\376\0\0\0\376\0\0\0\375\0\0\0\375\0\0\0\375\0\0\0\375aaa\375" "\357\357\357\375\327\327\327\376\7\7\7\376\0\0\0\375\0\0\0\374\0\0\0\373" "\0\0\0\371\0\0\0\370\200\200\200\367\372\372\372\367\321\321\321\370RRR\372" "\0\0\0\374\0\0\0\375\0\0\0\375\0\0\0\373\0\0\0\372\0\0\0\370\221\221\221" "\367\216\216\216\366)))\367\363\363\363\370ccc\372\0\0\0\374\0\0\0\375\0" "\0\0\376\0\0\0\376\0\0\0\377+++\377\364\364\364\377\260\260\260\377rrr\377" "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\227\227\227" "\377\320\320\320\377\322\322\322\377999\377\0\0\0\377\0\0\0\376\0\0\0\372" "\0\0\0\364\0\0\0\346\0\0\0\323'''\265\367\367\367\224DDDm\0\0\0K\0\0\0-\0" "\0\0\32\0\0\0\"\0\0\0""9\0\0\0[{{{~\273\273\273\245%%%\303\0\0\0\333\0\0" "\0\350\0\0\0\353\0\0\0\345\0\0\0\325\0\0\0\276\232\232\232\240\217\217\217" "\202\0\0\0g\0\0\0W\0\0\0S\0\0\0\\\0\0\0rddd\216\315\315\315\256000\310\0" "\0\0\334\0\0\0\346\0\0\0\347\0\0\0\340\0\0\0\316\1\1\1\267\230\230\230\231" "\330\330\330}\0\0\0g\0\0\0^\0\0\0c[[[u\353\353\353\220\"\"\"\254\0\0\0\307" "\0\0\0\333\0\0\0\352\0\0\0\363\0\0\0\370\0\0\0\372\3\3\3\374\16\16\16\374" "GGG\374GGG\374nnn\374,,,\372zzz\370111\364\0\0\0\357\12\12\12\353\341\341" "\341\350\310\310\310\346NNN\350\0\0\0\353\0\0\0\360\0\0\0\364\0\0\0\370\0" "\0\0\373\0\0\0\374\6\6\6\375TTT\375\304\304\304\374\231\231\231\373{{{\371" "\32\32\32\365\0\0\0\360\0\0\0\347\0\0\0\335---\322\344\344\344\312JJJ\307" "EEE\312\270\270\270\322\0\0\0\335\0\0\0\350\0\0\0\360\0\0\0\364\0\0\0\365" "\0\0\0\362\0\0\0\356\0\0\0\350\0\0\0\341\7\7\7\334\307\307\307\331YYY\333" "\320\320\320\340\11\11\11\347\0\0\0\356\0\0\0\364\0\0\0\367\0\0\0\367\0\0" "\0\364\0\0\0\357\0\0\0\345\0\0\0\327\25\25\25\305\314\314\314\263\351\351" "\351\245\0\0\0\237YYY\243\317\317\317\262\306\306\306\304333\327\0\0\0\344" "\0\0\0\354\0\0\0\356\0\0\0\354\3\3\3\350\207\207\207\345\271\271\271\344" "\263\263\263\346\340\340\340\352888\357\0\0\0\364\0\0\0\366\0\0\0\365\0\0" "\0\361\0\0\0\353\0\0\0\344\213\213\213\336\352\352\352\334\213\213\213\335" "\10\10\10\341\0\0\0\350\0\0\0\357\0\0\0\365\0\0\0\371***\373>>>\374\37\37" "\37\375\250\250\250\374\254\254\254\373...\372\13\13\13\371\2\2\2\367\0\0" "\0\364\0\0\0\361\5\5\5\356\30\30\30\354\332\332\332\353\217\217\217\354\0" "\0\0\357\0\0\0\363\0\0\0\366\0\0\0\371\0\0\0\372\0\0\0\373\5\5\5\374SSS\374" "\272\272\272\374\274\274\274\374\242\242\242\374www\374uuu\374(((\374\4\4" "\4\373\0\0\0\373\224\224\224\373\334\334\334\373\224\224\224\372\16\16\16" "\372\0\0\0\372\0\0\0\372\0\0\0\371\0\0\0\371\0\0\0\371MMM\371\362\362\362" "\371\356\356\356\372BBB\372\0\0\0\371\0\0\0\367\0\0\0\365\0\0\0\363\0\0\0" "\360\\\\\\\357\363\363\363\360\364\364\364\362777\364\0\0\0\367\0\0\0\371" "\0\0\0\371\0\0\0\367\0\0\0\364***\361\250\250\250\356\370\370\370\355\210" "\210\210\357\330\330\330\361ZZZ\364\0\0\0\367\0\0\0\371\0\0\0\373\0\0\0\374" "\0\0\0\374)))\375\366\366\366\375\356\356\356\376\216\216\216\377\0\0\0\377" "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\12\12\12\377!!!\377nn" "n\377\16\16\16\377\0\0\0\377\0\0\0\375\0\0\0\371\0\0\0\360\0\0\0\342\0\0" "\0\315\7\7\7\256\316\316\316\214\1\1\1f\0\0\0E\0\0\0)\0\0\0\27\0\0\0#\0\0" "\0;\0\0\0]\303\303\303\201\277\277\277\246\12\12\12\303\0\0\0\331\0\0\0\344" "\0\0\0\345\0\0\0\335\0\0\0\312\2\2\2\261\353\353\353\221fffs\0\0\0W\0\0\0" "G\0\0\0D\0\0\0O\0\0\0g\263\263\263\205\266\266\266\246```\301\0\0\0\325\0" "\0\0\337\0\0\0\336\0\0\0\325\0\0\0\301\217\217\217\250\341\341\341\211\37" "\37\37n\0\0\0X\0\0\0N\0\0\0S\0\0\0d\243\243\243\177\301\301\301\233777\267" "\0\0\0\316\0\0\0\336\0\0\0\351\0\0\0\360\0\0\0\364\0\0\0\366\0\0\0\367\0" "\0\0\370\5\5\5\370]]]\367\37\37\37\364\0\0\0\357\0\0\0\351\0\0\0\342\12\12" "\12\334\363\363\363\327\257\257\257\325\257\257\257\327&&&\334\0\0\0\343" "\0\0\0\353\0\0\0\361\0\0\0\365\0\0\0\370\0\0\0\371\0\0\0\371\27\27\27\370" "\14\14\14\365\0\0\0\362\0\0\0\354\0\0\0\344\0\0\0\332\0\0\0\316\242\242\242" "\301\334\334\334\270QQQ\266NNN\272\341\341\341\305\25\25\25\323\0\0\0\337" "\0\0\0\350\0\0\0\354\0\0\0\353\0\0\0\347\0\0\0\340\0\0\0\330\5\5\5\317xx" "x\311\307\307\307\306\22\22\22\312\323\323\323\321MMM\333\0\0\0\345\0\0\0" "\354\0\0\0\357\0\0\0\357\0\0\0\353\0\0\0\343\0\0\0\330\0\0\0\310OOO\265\344" "\344\344\243\231\231\231\226\0\0\0\223\20\20\20\232\341\341\341\253\30\30" "\30\277\0\0\0\321\0\0\0\336\0\0\0\345\0\0\0\344\0\0\0\340>>>\332\370\370" "\370\326yyy\326eee\331\327\327\327\340...\347\0\0\0\355\0\0\0\357\0\0\0\356" "\0\0\0\350\0\0\0\337\0\0\0\324\330\330\330\314___\310\323\323\323\311\204" "\204\204\320\0\0\0\332\0\0\0\344\0\0\0\355\0\0\0\363\0\0\0\366\0\0\0\370" "\0\0\0\370\0\0\0\367\0\0\0\366\0\0\0\363\0\0\0\361\0\0\0\355\0\0\0\350\0" "\0\0\343\0\0\0\337\245\245\245\334\365\365\365\333\302\302\302\336\14\14" "\14\342\0\0\0\350\0\0\0\355\0\0\0\361\0\0\0\364\0\0\0\365\0\0\0\366\0\0\0" "\367\0\0\0\370\0\0\0\370\0\0\0\370\0\0\0\370\40\40\40\367\0\0\0\366\0\0\0" "\365\0\0\0\364\327\327\327\363\333\333\333\363%%%\363\0\0\0\362\0\0\0\362" "\0\0\0\362\0\0\0\361\0\0\0\360\30\30\30\360\307\307\307\361\365\365\365\362" "\337\337\337\362uuu\362\0\0\0\362\0\0\0\357\0\0\0\354\0\0\0\350\0\0\0\345" "\244\244\244\343\313\313\313\344\367\367\367\350HHH\354\0\0\0\360\0\0\0\362" "\0\0\0\362\0\0\0\357\0\0\0\352OOO\345\325\325\325\341\261\261\261\337\254" "\254\254\341\222\222\222\345???\352\0\0\0\357\0\0\0\363\0\0\0\365\0\0\0\367" "\0\0\0\370\12\12\12\371\312\312\312\373\357\357\357\374\334\334\334\375\3" "\3\3\376\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0" "\0\377\0\0\0\377\0\0\0\377\0\0\0\376\0\0\0\373\0\0\0\366\0\0\0\354\0\0\0" "\333\0\0\0\304EEE\244\331\331\331\202\1\1\1]\0\0\0>\0\0\0$\0\0\0\24\0\0\0" "%\0\0\0<\0\0\0^\313\313\313\200]]]\244\0\0\0\277\0\0\0\323\0\0\0\334\0\0" "\0\332\0\0\0\320\0\0\0\273555\241\316\316\316\200\0\0\0c\0\0\0I\0\0\0:\0" "\0\0""9\0\0\0E\0\0\0^\322\322\322|ccc\235AAA\270\0\0\0\313\0\0\0\322\0\0" "\0\320\0\0\0\304\0\0\0\257\311\311\311\226\20\20\20w\0\0\0\\\0\0\0H\0\0\0" ">\0\0\0B\0\0\0Q\15\15\15j\306\306\306\206\201\201\201\242\0\0\0\272\0\0\0" "\315\0\0\0\331\0\0\0\342\0\0\0\347\0\0\0\353\0\0\0\355\0\0\0\357\0\0\0\357" "\0\0\0\355\0\0\0\351\0\0\0\342\0\0\0\331\0\0\0\317\23\23\23\305\354\354\354" "\276333\274\364\364\364\277\207\207\207\307\0\0\0\321\0\0\0\333\0\0\0\344" "\0\0\0\353\0\0\0\357\0\0\0\361\0\0\0\361\0\0\0\357\0\0\0\353\0\0\0\345\0" "\0\0\335\1\1\1\323\17\17\17\306\11\11\11\270\241\241\241\253\210\210\210" "\242\6\6\6\241>>>\250\324\324\324\265\15\15\15\304\0\0\0\322\0\0\0\333\0" "\0\0\336\0\0\0\333\0\0\0\325\0\0\0\314\35\35\35\301\177\177\177\267\331\331" "\331\260<<<\257BBB\264\343\343\343\277\210\210\210\314\0\0\0\327\0\0\0\337" "\0\0\0\342\0\0\0\341\0\0\0\333\0\0\0\321\0\0\0\304\6\6\6\262\321\321\321" "\237\253\253\253\216\0\0\0\204\0\0\0\204\31\31\31\216\326\326\326\240\15" "\15\15\265\0\0\0\307\0\0\0\323\0\0\0\327\0\0\0\325\0\0\0\316III\307\267\267" "\267\303BBB\303\310\310\310\310\262\262\262\321GGG\332\0\0\0\342\0\0\0\344" "\0\0\0\341\0\0\0\331\0\0\0\315\234\234\234\300\306\306\306\264\0\0\0\256" "mmm\260\313\313\313\271\17\17\17\306\0\0\0\324\0\0\0\337\0\0\0\350\0\0\0" "\355\0\0\0\357\0\0\0\357\0\0\0\356\0\0\0\353\0\0\0\347\0\0\0\342\0\0\0\334" "\0\0\0\326\0\0\0\317\0\0\0\311\206\206\206\305\201\201\201\305\276\276\276" "\310===\317\0\0\0\327\0\0\0\337\0\0\0\344\0\0\0\350\0\0\0\352\0\0\0\354\0" "\0\0\355\0\0\0\356\0\0\0\357\0\0\0\357\0\0\0\356\0\0\0\355\0\0\0\353\0\0" "\0\351III\347\364\364\364\346YYY\345\1\1\1\345\0\0\0\345\0\0\0\344\0\0\0" "\343\0\0\0\342\0\0\0\341NNN\341\327\327\327\342\343\343\343\343XXX\345DD" "D\345\0\0\0\344\0\0\0\340\0\0\0\333\0\0\0\326MMM\322\323\323\323\321uuu\323" "\311\311\311\330)))\337\2\2\2\345\0\0\0\350\0\0\0\347\0\0\0\343\0\0\0\333" "PPP\324\323\323\323\316\\\\\\\313\333\333\333\315GGG\323\2\2\2\332\0\0\0" "\341\0\0\0\346\0\0\0\352\0\0\0\355\0\0\0\357TTT\362\350\350\350\365\335\335" "\335\370\366\366\366\373;;;\375\0\0\0\376\0\0\0\377\0\0\0\377\0\0\0\377\0" "\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\375\0\0\0\371\0\0" "\0\362\0\0\0\346\0\0\0\322\11\11\11\271\233\233\233\227hhhu\0\0\0R\0\0\0" """6\0\0\0\37\0\0\0\20\0\0\0$\0\0\0;\0\0\0[\257\257\257{ZZZ\235\0\0\0\266" "\0\0\0\307\0\0\0\315\0\0\0\312\0\0\0\275\34\34\34\247\320\320\320\215```" "n\0\0\0R\0\0\0;\0\0\0""0\0\0\0""0\0\0\0=\0\0\0U\260\260\260rYYY\221\0\0\0" "\251\0\0\0\272\0\0\0\300\0\0\0\274\32\32\32\256EEE\231\325\325\325\177\0" "\0\0c\0\0\0K\0\0\0""8\0\0\0/\0\0\0""2\0\0\0?\0\0\0U%%%o\342\342\342\212\241" "\241\241\241III\265\0\0\0\303\0\0\0\315\0\0\0\323\0\0\0\331\0\0\0\334\0\0" "\0\337\0\0\0\337\0\0\0\334\0\0\0\327\0\0\0\316\0\0\0\302\16\16\16\265\264" "\264\264\251\230\230\230\241\14\14\14\236\371\371\371\242\325\325\325\253" "\212\212\212\270\30\30\30\305\0\0\0\321\0\0\0\332\0\0\0\340\0\0\0\342\0\0" "\0\342\0\0\0\337\0\0\0\332\0\0\0\322\0\0\0\307:::\272\302\302\302\254\313" "\313\313\235\343\343\343\220111\211\0\0\0\212RRR\222\265\265\265\241\0\0" "\0\262\0\0\0\277\0\0\0\307\0\0\0\311\0\0\0\305\0\0\0\274666\261\243\243\243" "\245\331\331\331\232PPP\223\0\0\0\223ooo\233\332\332\332\250\233\233\233" "\267\0\0\0\304\0\0\0\314\0\0\0\317\0\0\0\314\0\0\0\305\0\0\0\271<<<\252\230" "\230\230\230\307\307\307\205444v\0\0\0o\0\0\0q\27\27\27~\362\362\362\221" "\27\27\27\246\0\0\0\267\0\0\0\301\0\0\0\303\4\4\4\277\14\14\14\267\221\221" "\221\257ggg\252QQQ\254\307\307\307\263ppp\276\0\0\0\311\0\0\0\321\0\0\0\324" "\0\0\0\320\0\0\0\306\20\20\20\267\336\336\336\247\27\27\27\231\0\0\0\222" "\10\10\10\224\312\312\312\236{{{\255\21\21\21\275\0\0\0\314\0\0\0\327\0\0" "\0\335\0\0\0\340\0\0\0\337\0\0\0\335\0\0\0\331\0\0\0\323\6\6\6\314CCC\305" "mmm\274qqq\264\254\254\254\255\344\344\344\250,,,\250kkk\256\265\265\265" "\266\0\0\0\300\0\0\0\311\0\0\0\320\0\0\0\324\0\0\0\327\0\0\0\331\0\0\0\333" "\0\0\0\335\0\0\0\336\0\0\0\336\0\0\0\336\0\0\0\333\0\0\0\330\11\11\11\326" "\205\205\205\323\367\367\367\322\266\266\266\320\3\3\3\317\0\0\0\317\0\0" "\0\316\0\0\0\314\0\0\0\313\0\0\0\312\225\225\225\312\340\340\340\313\362" "\362\362\315aaa\317\4\4\4\320\0\0\0\316\0\0\0\312\0\0\0\305%%%\276\254\254" "\254\272kkk\271[[[\274\316\316\316\304\14\14\14\314\0\0\0\323\0\0\0\327\0" "\0\0\326\0\0\0\320\6\6\6\307\241\241\241\274\253\253\253\264===\261\330\330" "\330\263JJJ\272555\303\12\12\12\313\0\0\0\322\0\0\0\330\0\0\0\334\0\0\0\340" "\224\224\224\346QQQ\353&&&\361\231\231\231\366\343\343\343\372\242\242\242" "\375\201\201\201\376???\377///\377\11\11\11\377\0\0\0\377\0\0\0\377\0\0\0" "\377\0\0\0\376\0\0\0\373\0\0\0\366\0\0\0\354\0\0\0\336\0\0\0\307ooo\253\355" "\355\355\211'''g\0\0\0F\0\0\0-\0\0\0\31\0\0\0\15\0\0\0!\0\0\0""6222S\353" "\353\353qXXX\217\2\2\2\245\5\5\5\263\0\0\0\267\0\0\0\262\37\37\37\244\343" "\343\343\216\263\263\263v\0\0\0Y\0\0\0A\0\0\0.\0\0\0%\0\0\0'\0\0\0""3\0\0" "\0Jtttdggg\200\20\20\20\225\22\22\22\243\14\14\14\247111\241\312\312\312" "\223\336\336\336~\256\256\256g\0\0\0N\0\0\0""9\0\0\0)\0\0\0\"\0\0\0$\0\0" "\0.\0\0\0A\1\1\1V\257\257\257o\352\352\352\204\326\326\326\227\320\320\320" "\245\261\261\261\260!!!\270\6\6\6\276\0\0\0\303\3\3\3\307\15\15\15\307\15" "\15\15\304\15\15\15\275\21\21\21\262\260\260\260\245\331\331\331\226\253" "\253\253\211\10\10\10\200\1\1\1}\33\33\33\201%%%\213\350\350\350\232\205" "\205\205\251\26\26\26\267\0\0\0\302\0\0\0\311\0\0\0\314\3\3\3\314\17\17\17" "\310666\301SSS\267\306\306\306\252\345\345\345\234\256\256\256\214rrr~\\" "\\\\s\0\0\0m\0\0\0p\22\22\22z\267\267\267\211\0\0\0\231\10\10\10\246\10\10" "\10\255AAA\255\246\246\246\247\277\277\277\235\340\340\340\221\302\302\302" "\204BBBy\0\0\0t\0\0\0v555\177\340\340\340\216\242\242\242\236\6\6\6\253\0" "\0\0\263;;;\264\220\220\220\260\204\204\204\247\212\212\212\232\352\352\352" "\212\204\204\204y\30\30\30h\0\0\0\\\0\0\0X\0\0\0\\\32\32\32j\354\354\354" "}444\221\15\15\15\240///\250%%%\250___\242\333\333\333\231\341\341\341\221" "@@@\215\0\0\0\220\265\265\265\231***\245\4\4\4\261\15\15\15\272\4\4\4\274" "\32\32\32\270%%%\254\315\315\315\234\254\254\254\213\2\2\2|\0\0\0t\0\0\0" "vZZZ\200\306\306\306\221\206\206\206\242000\262\0\0\0\276\0\0\0\305\0\0\0" "\311\6\6\6\310\"\"\"\304KKK\276aaa\267\264\264\264\257\353\353\353\246\350" "\350\350\234\330\330\330\222yyy\213\202\202\202\207\11\11\11\210\10\10\10" "\216\333\333\333\230qqq\243\223\223\223\256\262\262\262\265;;;\272nnn\275" "OOO\277%%%\302\10\10\10\304---\306###\306rrr\305\5\5\5\302\4\4\4\276~~~\272" "\374\374\374\267\367\367\367\264\360\360\360\263\331\331\331\262\330\330" "\330\261\226\226\226\260\310\310\310\256\305\305\305\254\335\335\335\253" "\342\342\342\254\212\212\212\255\343\343\343\260(((\262;;;\263KKK\261iii" "\255???\246\216\216\216\240\311\311\311\233\16\16\16\233\\\\\\\240\354\354" "\354\251888\263\7\7\7\273\3\3\3\300\0\0\0\276\5\5\5\267|||\254\352\352\352" "\240\20\20\20\226\0\0\0\222|||\224\344\344\344\233\226\226\226\245hhh\257" "\24\24\24\267888\276\17\17\17\304ZZZ\313\301\301\301\324\340\340\340\335" "\327\327\327\347\342\342\342\360\333\333\333\366\263\263\263\373\227\227" "\227\375\253\253\253\377\274\274\274\377www\377FFF\377555\377\26\26\26\377" "\0\0\0\375\0\0\0\371\0\0\0\362\0\0\0\346\0\0\0\324---\271\345\345\345\233" "gggx\0\0\0X\0\0\0:\0\0\0$\0\0\0\23\0\0\0\12\0\0\0\35\0\0\0/(((H\351\351\351" "b\231\231\231{\244\244\244\215\255\255\255\230|||\232<<<\224\253\253\253" "\207\246\246\246r\0\0\0]\0\0\0E\0\0\0""1\0\0\0\"\0\0\0\34\0\0\0\36\0\0\0" ")\0\0\0=OOOS\363\363\363j\335\335\335{\344\344\344\206\324\324\324\210\350" "\350\350\201\275\275\275t\0\0\0a\0\0\0M\0\0\0""9\0\0\0(\0\0\0\34\0\0\0\27" "\0\0\0\30\0\0\0\40\0\0\0.\0\0\0?555STTTe\275\275\275v\317\317\317\203\276" "\276\276\216\363\363\363\226\302\302\302\235\251\251\251\243\217\217\217" "\247\261\261\261\250[[[\245\303\303\303\235\351\351\351\222\271\271\271\204" "\26\26\26t\0\0\0g\0\0\0^\0\0\0\\\0\0\0`\0\0\0j\204\204\204y\351\351\351\211" "\270\270\270\230\214\214\214\243iii\253&&&\257kkk\256\310\310\310\252\357" "\357\357\241\361\361\361\226\336\336\336\210aaaz\32\32\32k\0\0\0^\0\0\0U" "\0\0\0Q\0\0\0U\22\22\22_\336\336\336nxxx|\304\304\304\207\303\303\303\214" "\351\351\351\213\263\263\263\204sssz)))n\0\0\0b\0\0\0Y\0\0\0V\0\0\0Y\0\0" "\0c[[[r\333\333\333\201\216\216\216\215qqq\224\342\342\342\224\235\235\235" "\216\360\360\360\205tttxJJJi\0\0\0Z\0\0\0L\0\0\0C\0\0\0A\0\0\0G\31\31\31" "U\363\363\363f\324\324\324w\275\275\275\203\357\357\357\210\363\363\363\207" "\327\327\327\201RRRx\0\0\0q\0\0\0n\0\0\0r\261\261\261{\323\323\323\207\220" "\220\220\224\320\320\320\234\223\223\223\236\222\222\222\231\227\227\227" "\216\364\364\364~KKKm\0\0\0_\0\0\0X\0\0\0Y\0\0\0c\203\203\203r\370\370\370" "\203\335\335\335\223\214\214\214\240^^^\247SSS\252\300\300\300\251\271\271" "\271\244\303\303\303\235\277\277\277\225\303\303\303\214555\202vvvxxxxo\0" "\0\0h\0\0\0e\0\0\0g\0\0\0n\226\226\226x\351\351\351\203\276\276\276\215\356" "\356\356\224\342\342\342\230\341\341\341\233\274\274\274\236\344\344\344" "\241\275\275\275\244\241\241\241\246\226\226\226\246\332\332\332\245\245" "\245\245\241\271\271\271\234\340\340\340\230\206\206\206\224\367\367\367" "\221\313\313\313\217\231\231\231\216\271\271\271\215\332\332\332\214\324" "\324\324\212\331\331\331\210JJJ\207!!!\210VVV\211\361\361\361\215\272\272" "\272\217\324\324\324\220\364\364\364\216\322\322\322\212\276\276\276\203" "\273\273\273}GGGz\0\0\0{ZZZ\200\363\363\363\212\322\322\322\224\261\261\261" "\235\211\211\211\242\220\220\220\240\250\250\250\231\347\347\347\215qqq\201" "\0\0\0v\0\0\0q\0\0\0s\237\237\237y\354\354\354\203\350\350\350\215\360\360" "\360\226\317\317\317\236\331\331\331\246\331\331\331\260\266\266\266\275" "\352\352\352\313[[[\332666\346\223\223\223\360\220\220\220\367\264\264\264" "\373\252\252\252\375\273\273\273\376\235\235\235\376MMM\376\0\0\0\376\25" "\25\25\375\0\0\0\373\0\0\0\366\0\0\0\355\0\0\0\335\20\20\20\310\237\237\237" "\252\177\177\177\212\0\0\0g\0\0\0I\0\0\0.\0\0\0\33\0\0\0\16\0\0\0\7\0\0\0" "\27\0\0\0&\0\0\0:nnnN\304\304\304b\372\372\372p\206\206\206y\256\256\256" "y\347\347\347s\227\227\227g\14\14\14V\0\0\0D\0\0\0""1\0\0\0\"\0\0\0\30\0" "\0\0\23\0\0\0\26\0\0\0\37\0\0\0.\2\2\2@wwwR\326\326\326_\272\272\272g\"\"" "\"f\"\"\"`\5\5\5U\0\0\0F\0\0\0""6\0\0\0'\0\0\0\33\0\0\0\22\0\0\0\16\0\0\0" "\17\0\0\0\25\0\0\0\37\0\0\0+\0\0\0:\0\0\0H\24\24\24U\20\20\20`\24\24\24j" "\"\"\"q###xNNN~\340\340\340\202\345\345\345\204\345\345\345\201\274\274\274" "z>>>o\5\5\5b\0\0\0T\0\0\0H\0\0\0A\0\0\0>\0\0\0B\0\0\0L\7\7\7YLLLg|||u\324" "\324\324\200\347\347\347\210\337\337\337\214\373\373\373\213\314\314\314" "\206fff~\36\36\36s\27\27\27e\0\0\0Y\0\0\0L\0\0\0A\0\0\0:\0\0\0""8\0\0\0=" "\2\2\2FeeeR\217\217\217^\201\201\201g\205\205\205jbbbh\0\0\0a\0\0\0X\0\0" "\0M\0\0\0D\0\0\0=\0\0\0;\0\0\0>\0\0\0H\13\13\13U\251\251\251b\347\347\347" "m\317\317\317rMMMq\10\10\10k\34\34\34b\0\0\0V\0\0\0J\0\0\0>\0\0\0""4\0\0" "\0-\0\0\0-\0\0\0""3\3\3\3?!!!M\314\314\314[\246\246\246dNNNg!!!e\17\17\17" "_\0\0\0W\0\0\0Q\0\0\0P\0\0\0T\27\27\27]SSSh\333\333\333s\357\357\357{\211" "\211\211}\266\266\266x\347\347\347nZZZ`\11\11\11Q\0\0\0E\0\0\0>\0\0\0?\0" "\0\0G\20\20\20T\"\"\"cxxxr\334\334\334}\345\345\345\204\343\343\343\206k" "kk\205\336\336\336\200\200\200\200y###q\17\17\17h\0\0\0^\0\0\0U\0\0\0N\0" "\0\0H\0\0\0F\0\0\0H\0\0\0OjjjX\317\317\317b\20\20\20j999p\206\206\206t**" "*v\0\0\0y\27\27\27|\322\322\322\177\334\334\334\201\345\345\345\202\305\305" "\305\200yyy|###w\33\33\33r\12\12\12o\"\"\"l\10\10\10j\0\0\0h\30\30\30h##" "#g\21\21\21e\31\31\31d\0\0\0c\0\0\0c\12\12\12e111h\214\214\214jLLLk###i\16" "\16\16f\0\0\0`\0\0\0[\0\0\0Y\0\0\0Z\13\13\13`BBBi\353\353\353s\334\334\334" "|\301\301\301\200\313\313\313~\365\365\365w|||l\0\0\0`\0\0\0W\0\0\0R\0\0" "\0S\13\13\13X###a\"\"\"i111r\212\212\212{\177\177\177\205$$$\222\0\0\0\243" "\305\305\305\265\\\\\\\311\0\0\0\332\3\3\3\350\20\20\20\360\24\24\24\366" "\4\4\4\371\24\24\24\372\\\\\\\373333\373\0\0\0\373\0\0\0\372\0\0\0\367\0" "\0\0\357\0\0\0\344\0\0\0\321WWW\271\363\363\363\231333y\0\0\0W\0\0\0;\0\0" "\0#\0\0\0\24\0\0\0\12\0\0\0\5\0\0\0\21\0\0\0\34\0\0\0*\0\0\0""9\21\21\21" "HNNNR\0\0\0W\0\0\0W\0\0\0R\0\0\0H\0\0\0;\0\0\0.\0\0\0!\0\0\0\26\0\0\0\17" "\0\0\0\15\0\0\0\17\0\0\0\26\0\0\0!\0\0\0-\0\0\0:\0\0\0B\0\0\0G\0\0\0G\0\0" "\0A\0\0\0""9\0\0\0.\0\0\0#\0\0\0\30\0\0\0\21\0\0\0\13\0\0\0\10\0\0\0\11\0" "\0\0\14\0\0\0\23\0\0\0\33\0\0\0%\0\0\0.\0\0\0""8\0\0\0@\0\0\0H\0\0\0N\0\0" "\0T\0\0\0Y\0\0\0^\36\36\36_OOO]\13\13\13W\0\0\0N\0\0\0C\0\0\0""8\0\0\0.\0" "\0\0(\0\0\0'\0\0\0*\0\0\0""2\0\0\0<\0\0\0H\0\0\0S\0\0\0]\0\0\0d\12\12\12" "g\275\275\275fdddb\0\0\0Z\0\0\0P\0\0\0E\0\0\0;\0\0\0""1\0\0\0)\0\0\0$\0\0" "\0$\0\0\0(\0\0\0/\0\0\0""9\0\0\0A\0\0\0G\0\0\0I\0\0\0F\0\0\0A\0\0\0""9\0" "\0\0""2\0\0\0*\0\0\0&\0\0\0%\0\0\0)\0\0\0""1\0\0\0;\27\27\27E\\\\\\M\30\30" "\30P\0\0\0O\0\0\0I\0\0\0B\0\0\0""9\0\0\0/\0\0\0'\0\0\0\40\0\0\0\34\0\0\0" "\35\0\0\0\"\0\0\0+\0\0\0""6\0\0\0?\0\0\0F\0\0\0G\0\0\0E\0\0\0@\0\0\0:\0\0" "\0""6\0\0\0""5\0\0\0""9\0\0\0@\0\0\0J===RNNNX\0\0\0Z\0\0\0V\0\0\0N\0\0\0" "C\0\0\0""7\0\0\0.\0\0\0)\0\0\0)\0\0\0/\0\0\0""9\0\0\0E\0\0\0Q===ZLLL_\0\0" "\0a\0\0\0_\0\0\0[\0\0\0U\0\0\0N\0\0\0F\0\0\0?\0\0\0""7\0\0\0""2\0\0\0-\0" "\0\0,\0\0\0/\0\0\0""4\0\0\0;\0\0\0C\0\0\0I\0\0\0M\0\0\0P\0\0\0R\0\0\0U\0" "\0\0W\0\0\0Z\0\0\0\\\0\0\0\\\0\0\0[\0\0\0W\0\0\0S\0\0\0O\0\0\0K\0\0\0H\0" "\0\0G\0\0\0F\0\0\0E\0\0\0D\0\0\0C\0\0\0B\0\0\0A\0\0\0B\0\0\0C\0\0\0F\0\0" "\0H\0\0\0H\0\0\0G\0\0\0D\0\0\0@\0\0\0<\0\0\0;\0\0\0=\0\0\0B\0\0\0J\0\0\0" "R\0\0\0Y\0\0\0\\///[___V###L\0\0\0C\0\0\0:\0\0\0""6\0\0\0""6\0\0\0:\0\0\0" "A\0\0\0H\0\0\0P\0\0\0X\0\0\0d\0\0\0s\0\0\0\207\307\307\307\235ZZZ\265\0\0" "\0\312\0\0\0\333\0\0\0\346\0\0\0\355\0\0\0\361\0\0\0\363\0\0\0\365\0\0\0" "\365\0\0\0\365\0\0\0\363\0\0\0\357\0\0\0\346\0\0\0\331\0\0\0\303VVV\251\314" "\314\314\207\0\0\0g\0\0\0G\0\0\0.\0\0\0\33\0\0\0\17\0\0\0\7\0\0\0\4\0\0\0" "\14\0\0\0\23\0\0\0\35\0\0\0&\0\0\0""0\0\0\0""7\0\0\0:\0\0\0:\0\0\0""6\0\0" "\0/\0\0\0&\0\0\0\35\0\0\0\24\0\0\0\16\0\0\0\11\0\0\0\10\0\0\0\11\0\0\0\16" "\0\0\0\25\0\0\0\35\0\0\0%\0\0\0+\0\0\0.\0\0\0-\0\0\0)\0\0\0#\0\0\0\33\0\0" "\0\25\0\0\0\16\0\0\0\12\0\0\0\6\0\0\0\5\0\0\0\5\0\0\0\7\0\0\0\13\0\0\0\20" "\0\0\0\26\0\0\0\34\0\0\0\"\0\0\0'\0\0\0,\0\0\0""1\0\0\0""6\0\0\0:\0\0\0>" "\0\0\0?\0\0\0=\0\0\0""9\0\0\0""2\0\0\0*\0\0\0\"\0\0\0\33\0\0\0\27\0\0\0\26" "\0\0\0\31\0\0\0\36\0\0\0%\0\0\0.\0\0\0""6\0\0\0>\0\0\0C\0\0\0E\0\0\0E\0\0" "\0B\0\0\0<\0\0\0""4\0\0\0,\0\0\0$\0\0\0\35\0\0\0\30\0\0\0\25\0\0\0\25\0\0" "\0\30\0\0\0\35\0\0\0$\0\0\0)\0\0\0-\0\0\0.\0\0\0,\0\0\0(\0\0\0#\0\0\0\35" "\0\0\0\31\0\0\0\26\0\0\0\26\0\0\0\30\0\0\0\37\0\0\0&\0\0\0-\0\0\0""2\0\0" "\0""4\0\0\0""3\0\0\0.\0\0\0)\0\0\0\"\0\0\0\34\0\0\0\26\0\0\0\22\0\0\0\21" "\0\0\0\21\0\0\0\25\0\0\0\33\0\0\0\"\0\0\0)\0\0\0-\0\0\0-\0\0\0+\0\0\0'\0" "\0\0#\0\0\0!\0\0\0!\0\0\0$\0\0\0)\0\0\0""0\0\0\0""6\0\0\0:\0\0\0<\0\0\0""9" "\0\0\0""3\0\0\0,\0\0\0#\0\0\0\35\0\0\0\31\0\0\0\31\0\0\0\35\0\0\0$\0\0\0" "-\0\0\0""5\0\0\0;\0\0\0?\0\0\0A\0\0\0?\0\0\0<\0\0\0""7\0\0\0""1\0\0\0,\0" "\0\0&\0\0\0!\0\0\0\35\0\0\0\32\0\0\0\32\0\0\0\34\0\0\0\40\0\0\0%\0\0\0*\0" "\0\0.\0\0\0""1\0\0\0""3\0\0\0""5\0\0\0""6\0\0\0""8\0\0\0;\0\0\0<\0\0\0=\0" "\0\0;\0\0\0""8\0\0\0""5\0\0\0""2\0\0\0/\0\0\0-\0\0\0+\0\0\0+\0\0\0*\0\0\0" "*\0\0\0)\0\0\0(\0\0\0(\0\0\0(\0\0\0)\0\0\0+\0\0\0,\0\0\0-\0\0\0,\0\0\0*\0" "\0\0'\0\0\0%\0\0\0$\0\0\0&\0\0\0*\0\0\0""0\0\0\0""6\0\0\0;\0\0\0>\0\0\0=" "\0\0\0""9\0\0\0""2\0\0\0+\0\0\0%\0\0\0!\0\0\0!\0\0\0$\0\0\0(\0\0\0.\0\0\0" """4\0\0\0<\0\0\0G\0\0\0W\0\0\0m\300\300\300\205aaa\237\0\0\0\266\0\0\0\311" "\0\0\0\326\0\0\0\336\0\0\0\343\0\0\0\346\0\0\0\350\0\0\0\352\0\0\0\352\0" "\0\0\350\0\0\0\343\0\0\0\330\0\0\0\311FFF\261\335\335\335\226\223\223\223" "u\0\0\0V\0\0\0""9\0\0\0$\0\0\0\24\0\0\0\12\0\0\0\5\0\0\0\2\0\0\0\7\0\0\0" "\14\0\0\0\21\0\0\0\27\0\0\0\35\0\0\0!\0\0\0\"\0\0\0\"\0\0\0\37\0\0\0\33\0" "\0\0\26\0\0\0\20\0\0\0\13\0\0\0\7\0\0\0\5\0\0\0\4\0\0\0\6\0\0\0\10\0\0\0" "\14\0\0\0\21\0\0\0\25\0\0\0\30\0\0\0\32\0\0\0\31\0\0\0\27\0\0\0\23\0\0\0" "\17\0\0\0\13\0\0\0\10\0\0\0\5\0\0\0\3\0\0\0\2\0\0\0\3\0\0\0\4\0\0\0\5\0\0" "\0\10\0\0\0\13\0\0\0\17\0\0\0\22\0\0\0\25\0\0\0\31\0\0\0\34\0\0\0\37\0\0" "\0\"\0\0\0$\0\0\0%\0\0\0$\0\0\0!\0\0\0\35\0\0\0\30\0\0\0\23\0\0\0\17\0\0" "\0\14\0\0\0\14\0\0\0\15\0\0\0\21\0\0\0\25\0\0\0\32\0\0\0\40\0\0\0%\0\0\0" "(\0\0\0*\0\0\0*\0\0\0(\0\0\0#\0\0\0\36\0\0\0\31\0\0\0\24\0\0\0\17\0\0\0\15" "\0\0\0\13\0\0\0\13\0\0\0\15\0\0\0\20\0\0\0\24\0\0\0\27\0\0\0\31\0\0\0\32" "\0\0\0\30\0\0\0\26\0\0\0\22\0\0\0\17\0\0\0\15\0\0\0\13\0\0\0\14\0\0\0\16" "\0\0\0\21\0\0\0\26\0\0\0\32\0\0\0\35\0\0\0\37\0\0\0\35\0\0\0\32\0\0\0\27" "\0\0\0\22\0\0\0\17\0\0\0\14\0\0\0\11\0\0\0\11\0\0\0\11\0\0\0\14\0\0\0\17" "\0\0\0\24\0\0\0\27\0\0\0\31\0\0\0\32\0\0\0\30\0\0\0\25\0\0\0\23\0\0\0\22" "\0\0\0\22\0\0\0\24\0\0\0\30\0\0\0\34\0\0\0\40\0\0\0#\0\0\0#\0\0\0!\0\0\0" "\36\0\0\0\31\0\0\0\24\0\0\0\20\0\0\0\16\0\0\0\16\0\0\0\20\0\0\0\25\0\0\0" "\32\0\0\0\37\0\0\0#\0\0\0&\0\0\0&\0\0\0%\0\0\0#\0\0\0\40\0\0\0\34\0\0\0\30" "\0\0\0\25\0\0\0\21\0\0\0\17\0\0\0\16\0\0\0\16\0\0\0\17\0\0\0\22\0\0\0\25" "\0\0\0\30\0\0\0\32\0\0\0\34\0\0\0\35\0\0\0\36\0\0\0\37\0\0\0!\0\0\0\"\0\0" "\0#\0\0\0#\0\0\0\"\0\0\0\40\0\0\0\36\0\0\0\34\0\0\0\32\0\0\0\30\0\0\0\27" "\0\0\0\27\0\0\0\27\0\0\0\26\0\0\0\26\0\0\0\25\0\0\0\25\0\0\0\26\0\0\0\26" "\0\0\0\30\0\0\0\31\0\0\0\31\0\0\0\30\0\0\0\27\0\0\0\25\0\0\0\24\0\0\0\24" "\0\0\0\25\0\0\0\30\0\0\0\34\0\0\0\40\0\0\0#\0\0\0%\0\0\0$\0\0\0\"\0\0\0\36" "\0\0\0\31\0\0\0\25\0\0\0\23\0\0\0\22\0\0\0\24\0\0\0\26\0\0\0\32\0\0\0\37" "\0\0\0%\0\0\0""0\0\0\0?\0\0\0TIIIk\335\335\335\206\35\35\35\235\0\0\0\261" "\0\0\0\276\27\27\27\307\32\32\32\315\0\0\0\321\0\0\0\324\0\0\0\326\0\0\0" "\326\0\0\0\325\0\0\0\317\0\0\0\304...\263\333\333\333\233\224\224\224\200" "\0\0\0`\0\0\0E\0\0\0,\0\0\0\33\0\0\0\16\0\0\0\7\0\0\0\3\0\0\0\2\0\0\0\4\0" "\0\0\6\0\0\0\12\0\0\0\15\0\0\0\20\0\0\0\22\0\0\0\23\0\0\0\22\0\0\0\21\0\0" "\0\17\0\0\0\13\0\0\0\10\0\0\0\6\0\0\0\4\0\0\0\3\0\0\0\2\0\0\0\3\0\0\0\4\0" "\0\0\6\0\0\0\11\0\0\0\13\0\0\0\15\0\0\0\16\0\0\0\15\0\0\0\14\0\0\0\12\0\0" "\0\10\0\0\0\6\0\0\0\4\0\0\0\3\0\0\0\2\0\0\0\1\0\0\0\2\0\0\0\2\0\0\0\3\0\0" "\0\4\0\0\0\6\0\0\0\7\0\0\0\11\0\0\0\13\0\0\0\15\0\0\0\16\0\0\0\20\0\0\0\22" "\0\0\0\24\0\0\0\24\0\0\0\24\0\0\0\22\0\0\0\20\0\0\0\15\0\0\0\12\0\0\0\10" "\0\0\0\6\0\0\0\6\0\0\0\7\0\0\0\11\0\0\0\13\0\0\0\16\0\0\0\21\0\0\0\24\0\0" "\0\26\0\0\0\30\0\0\0\27\0\0\0\26\0\0\0\23\0\0\0\21\0\0\0\15\0\0\0\12\0\0" "\0\10\0\0\0\6\0\0\0\6\0\0\0\6\0\0\0\7\0\0\0\11\0\0\0\13\0\0\0\14\0\0\0\15" "\0\0\0\15\0\0\0\14\0\0\0\13\0\0\0\11\0\0\0\10\0\0\0\6\0\0\0\6\0\0\0\6\0\0" "\0\7\0\0\0\11\0\0\0\14\0\0\0\16\0\0\0\20\0\0\0\20\0\0\0\20\0\0\0\16\0\0\0" "\14\0\0\0\11\0\0\0\10\0\0\0\6\0\0\0\5\0\0\0\5\0\0\0\5\0\0\0\6\0\0\0\10\0" "\0\0\12\0\0\0\14\0\0\0\15\0\0\0\15\0\0\0\14\0\0\0\13\0\0\0\12\0\0\0\11\0" "\0\0\11\0\0\0\13\0\0\0\15\0\0\0\17\0\0\0\22\0\0\0\23\0\0\0\23\0\0\0\22\0" "\0\0\20\0\0\0\16\0\0\0\13\0\0\0\11\0\0\0\7\0\0\0\7\0\0\0\11\0\0\0\13\0\0" "\0\16\0\0\0\21\0\0\0\23\0\0\0\25\0\0\0\25\0\0\0\24\0\0\0\23\0\0\0\21\0\0" "\0\17\0\0\0\14\0\0\0\12\0\0\0\11\0\0\0\10\0\0\0\7\0\0\0\7\0\0\0\10\0\0\0" "\11\0\0\0\13\0\0\0\15\0\0\0\16\0\0\0\17\0\0\0\17\0\0\0\20\0\0\0\20\0\0\0" "\21\0\0\0\22\0\0\0\23\0\0\0\23\0\0\0\22\0\0\0\21\0\0\0\20\0\0\0\16\0\0\0" "\15\0\0\0\14\0\0\0\14\0\0\0\13\0\0\0\13\0\0\0\13\0\0\0\13\0\0\0\13\0\0\0" "\13\0\0\0\13\0\0\0\13\0\0\0\14\0\0\0\14\0\0\0\15\0\0\0\14\0\0\0\13\0\0\0" "\13\0\0\0\12\0\0\0\12\0\0\0\13\0\0\0\15\0\0\0\17\0\0\0\21\0\0\0\23\0\0\0" "\24\0\0\0\24\0\0\0\23\0\0\0\20\0\0\0\16\0\0\0\13\0\0\0\12\0\0\0\11\0\0\0" "\12\0\0\0\14\0\0\0\16\0\0\0\21\0\0\0\26\0\0\0\37\0\0\0,\0\0\0>\0\0\0T\236" "\236\236l\313\313\313\201nnn\223\255\255\255\240\302\302\302\252\226\226" "\226\260hhh\265III\270\4\4\4\273\10\10\10\274\3\3\3\272\6\6\6\265\27\27\27" "\251\254\254\254\231\351\351\351\202BBBi\0\0\0M\0\0\0""6\0\0\0!\0\0\0\23" "\0\0\0\12\0\0\0\5\0\0\0\2\0\0\0\1\0\0\0\2\0\0\0\3\0\0\0\5\0\0\0\6\0\0\0\10" "\0\0\0\11\0\0\0\11\0\0\0\11\0\0\0\10\0\0\0\7\0\0\0\6\0\0\0\4\0\0\0\3\0\0" "\0\2\0\0\0\2\0\0\0\1\0\0\0\2\0\0\0\2\0\0\0\3\0\0\0\4\0\0\0\5\0\0\0\6\0\0" "\0\6\0\0\0\6\0\0\0\6\0\0\0\5\0\0\0\4\0\0\0\3\0\0\0\2\0\0\0\1\0\0\0\1\0\0" "\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\2\0\0\0\3\0\0\0\3\0\0\0\4\0\0\0\5\0\0" "\0\6\0\0\0\7\0\0\0\10\0\0\0\11\0\0\0\12\0\0\0\12\0\0\0\12\0\0\0\11\0\0\0" "\10\0\0\0\6\0\0\0\5\0\0\0\4\0\0\0\3\0\0\0\3\0\0\0\3\0\0\0\4\0\0\0\5\0\0\0" "\7\0\0\0\10\0\0\0\12\0\0\0\13\0\0\0\14\0\0\0\14\0\0\0\13\0\0\0\12\0\0\0\10" "\0\0\0\6\0\0\0\5\0\0\0\4\0\0\0\3\0\0\0\3\0\0\0\3\0\0\0\3\0\0\0\4\0\0\0\5" "\0\0\0\6\0\0\0\6\0\0\0\6\0\0\0\6\0\0\0\5\0\0\0\4\0\0\0\4\0\0\0\3\0\0\0\3" "\0\0\0\3\0\0\0\4\0\0\0\5\0\0\0\6\0\0\0\7\0\0\0\10\0\0\0\10\0\0\0\7\0\0\0" "\7\0\0\0\6\0\0\0\5\0\0\0\4\0\0\0\3\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\3\0\0\0" "\4\0\0\0\5\0\0\0\6\0\0\0\6\0\0\0\6\0\0\0\6\0\0\0\5\0\0\0\5\0\0\0\4\0\0\0" "\4\0\0\0\5\0\0\0\6\0\0\0\7\0\0\0\11\0\0\0\11\0\0\0\11\0\0\0\11\0\0\0\10\0" "\0\0\7\0\0\0\5\0\0\0\4\0\0\0\3\0\0\0\3\0\0\0\4\0\0\0\5\0\0\0\7\0\0\0\10\0" "\0\0\11\0\0\0\12\0\0\0\12\0\0\0\12\0\0\0\11\0\0\0\10\0\0\0\7\0\0\0\6\0\0" "\0\5\0\0\0\4\0\0\0\4\0\0\0\3\0\0\0\3\0\0\0\4\0\0\0\4\0\0\0\5\0\0\0\6\0\0" "\0\7\0\0\0\7\0\0\0\7\0\0\0\7\0\0\0\10\0\0\0\10\0\0\0\11\0\0\0\11\0\0\0\11" "\0\0\0\11\0\0\0\10\0\0\0\10\0\0\0\7\0\0\0\6\0\0\0\6\0\0\0\5\0\0\0\5\0\0\0" "\5\0\0\0\5\0\0\0\5\0\0\0\5\0\0\0\5\0\0\0\5\0\0\0\5\0\0\0\5\0\0\0\6\0\0\0" "\6\0\0\0\5\0\0\0\5\0\0\0\5\0\0\0\5\0\0\0\5\0\0\0\5\0\0\0\6\0\0\0\7\0\0\0" "\10\0\0\0\11\0\0\0\12\0\0\0\12\0\0\0\11\0\0\0\10\0\0\0\7\0\0\0\5\0\0\0\5" "\0\0\0\4\0\0\0\5\0\0\0\6\0\0\0\7\0\0\0\11\0\0\0\15\0\0\0\23\0\0\0\35\0\0" "\0,\0\0\0=\16\16\16Pzzzb\302\302\302r\302\302\302}\304\304\304\206\235\235" "\235\213\311\311\311\220\347\347\347\224\300\300\300\230\364\364\364\231" "\267\267\267\230\332\332\332\223\245\245\245\211\341\341\341zVVVe\20\20\20" "P\0\0\0""9\0\0\0'\0\0\0\27\0\0\0\15\0\0\0\7\0\0\0\3\0\0\0\2\0\0\0\1\0\0\0" "\1\0\0\0\2\0\0\0\2\0\0\0\3\0\0\0\4\0\0\0\4\0\0\0\5\0\0\0\5\0\0\0\4\0\0\0" "\4\0\0\0\3\0\0\0\2\0\0\0\2\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0" "\2\0\0\0\2\0\0\0\3\0\0\0\3\0\0\0\3\0\0\0\3\0\0\0\3\0\0\0\2\0\0\0\2\0\0\0" "\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0" "\1\0\0\0\2\0\0\0\2\0\0\0\3\0\0\0\3\0\0\0\4\0\0\0\4\0\0\0\4\0\0\0\5\0\0\0" "\5\0\0\0\5\0\0\0\4\0\0\0\4\0\0\0\3\0\0\0\3\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0" "\2\0\0\0\2\0\0\0\3\0\0\0\4\0\0\0\4\0\0\0\5\0\0\0\5\0\0\0\6\0\0\0\6\0\0\0" "\5\0\0\0\5\0\0\0\4\0\0\0\3\0\0\0\3\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0" "\2\0\0\0\2\0\0\0\3\0\0\0\3\0\0\0\3\0\0\0\3\0\0\0\3\0\0\0\3\0\0\0\2\0\0\0" "\2\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\3\0\0\0\4\0\0\0\4\0\0\0" "\4\0\0\0\4\0\0\0\3\0\0\0\3\0\0\0\2\0\0\0\2\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0" "\1\0\0\0\2\0\0\0\2\0\0\0\3\0\0\0\3\0\0\0\3\0\0\0\3\0\0\0\3\0\0\0\3\0\0\0" "\2\0\0\0\2\0\0\0\2\0\0\0\3\0\0\0\3\0\0\0\4\0\0\0\4\0\0\0\5\0\0\0\5\0\0\0" "\4\0\0\0\4\0\0\0\3\0\0\0\3\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\3\0\0\0" "\4\0\0\0\4\0\0\0\5\0\0\0\5\0\0\0\5\0\0\0\5\0\0\0\5\0\0\0\4\0\0\0\4\0\0\0" "\3\0\0\0\3\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\3\0\0\0" "\3\0\0\0\3\0\0\0\4\0\0\0\4\0\0\0\4\0\0\0\4\0\0\0\4\0\0\0\4\0\0\0\4\0\0\0" "\5\0\0\0\4\0\0\0\4\0\0\0\4\0\0\0\4\0\0\0\3\0\0\0\3\0\0\0\3\0\0\0\3\0\0\0" "\3\0\0\0\3\0\0\0\3\0\0\0\3\0\0\0\3\0\0\0\3\0\0\0\3\0\0\0\3\0\0\0\3\0\0\0" "\3\0\0\0\3\0\0\0\3\0\0\0\3\0\0\0\3\0\0\0\3\0\0\0\3\0\0\0\3\0\0\0\4\0\0\0" "\4\0\0\0\5\0\0\0\5\0\0\0\5\0\0\0\4\0\0\0\4\0\0\0\3\0\0\0\3\0\0\0\3\0\0\0" "\3\0\0\0\3\0\0\0\3\0\0\0\4\0\0\0\5\0\0\0\7\0\0\0\14\0\0\0\23\0\0\0\35\0\0" "\0*\0\0\0""8\0\0\0F\0\0\0R\0\0\0[\0\0\0b\0\0\0g\10\10\10l222p444sRRRu\232" "\232\232tFFFp\220\220\220gYYY[\0\0\0K\0\0\0:\0\0\0)\0\0\0\33\0\0\0\20\0\0" "\0\11\0\0\0\4\0\0\0\2\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\2\0\0" "\0\2\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\1\0\0\0\1\0\0\0\1\0\0" "\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0" "\0\2\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0" "\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0" "\0\2\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\2\0\0" "\0\2\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\2\0\0" "\0\2\0\0\0\2\0\0\0\2\0\0\0\3\0\0\0\3\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\2\0\0" "\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0" "\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0" "\0\1\0\0\0\1\0\0\0\1\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\2\0\0" "\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0" "\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0" "\0\2\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\1\0\0" "\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\2\0\0" "\0\2\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\1\0\0\0\1\0\0\0\1\0\0" "\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\2\0\0" "\0\2\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\2\0\0" "\0\2\0\0\0\2\0\0\0\2\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0" "\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0" "\0\1\0\0\0\1\0\0\0\1\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\2\0\0\0\2\0\0" "\0\2\0\0\0\2\0\0\0\2\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\2\0\0" "\0\3\0\0\0\4\0\0\0\7\0\0\0\13\0\0\0\22\0\0\0\32\0\0\0#\0\0\0,\0\0\0""5\0" "\0\0;\0\0\0@\0\0\0D\0\0\0H\0\0\0K\0\0\0N\0\0\0P\0\0\0P\0\0\0M\0\0\0F\0\0" "\0=\0\0\0""2\0\0\0&\0\0\0\32\0\0\0\21\0\0\0\12\0\0\0\5\0\0\0\3\0\0\0\1\0" "\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0" "\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0" "\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0" "\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0" "\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0" "\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0" "\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\2\0" "\0\0\2\0\0\0\2\0\0\0\2\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0" "\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0" "\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0" "\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0" "\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0" "\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0" "\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0" "\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0" "\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0" "\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0" "\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0" "\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0" "\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0" "\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0" "\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\2\0\0\0\3\0\0\0\4\0" "\0\0\6\0\0\0\12\0\0\0\17\0\0\0\25\0\0\0\32\0\0\0\40\0\0\0$\0\0\0'\0\0\0*" "\0\0\0-\0\0\0/\0\0\0""2\0\0\0""3\0\0\0""3\0\0\0""1\0\0\0-\0\0\0'\0\0\0\37" "\0\0\0\30\0\0\0\20\0\0\0\12\0\0\0\6\0\0\0\3\0\0\0\2\0\0\0\1\0\0\0\1\0\0\0" "\1", }; freewheeling-0.6.6/src/fweelin_looplibrary.h000066400000000000000000000123141370736313100212030ustar00rootroot00000000000000#ifndef __FWEELIN_LOOPLIBRARY_H #define __FWEELIN_LOOPLIBRARY_H /* Copyright 2004-2011 Jan Pekau This file is part of Freewheeling. Freewheeling is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. Freewheeling 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 Freewheeling. If not, see . */ #include #include #include #include #include #include "fweelin_core.h" class LibraryFileInfo { public: LibraryFileInfo () : exists(0), c(UNKNOWN), name("") {}; char exists; // File exists? codec c; // Codec (extension of file) for audio files std::string name; // Name of file }; class LibraryHelper { public: // Returns the stub (base of filename) for a given loop in memory static const std::string GetStubnameFromLoop (Fweelin *app, Loop *l) { std::ostringstream tmp; GET_SAVEABLE_HASH_TEXT(l->GetSaveHash()); tmp << app->getCFG()->GetLibraryPath() << "/" << FWEELIN_OUTPUT_LOOP_NAME << "-" << hashtext; return tmp.str(); }; // Returns, for example, fw-lib/live24. Does not return the file extension. static const std::string GetNextAvailableStreamOutFilename (Fweelin *app, int &stream_num, std::string &display_name) { // Create appropriate filename for output char go = 1; do { // Scan for already existing output streams, using the timing file as a check std::ostringstream tmp; tmp << app->getCFG()->GetLibraryPath() << "/" << FWEELIN_OUTPUT_STREAM_NAME << stream_num << FWEELIN_OUTPUT_TIMING_EXT; const std::string s = tmp.str(); struct stat st; printf("DISK: Test '%s' for streaming.\n",s.c_str()); fflush(stdout); if (stat(s.c_str(),&st) == 0) { printf("DISK: File exists, trying another.\n"); stream_num++; } else { // No file with this name. Name is free. // Prepare base name with and without path go = 0; std::ostringstream tmp2; tmp2 << app->getCFG()->GetLibraryPath() << "/" << FWEELIN_OUTPUT_STREAM_NAME << stream_num; const std::string s2 = tmp2.str(); std::ostringstream display_tmp; display_tmp << FWEELIN_OUTPUT_STREAM_NAME << stream_num; display_name = display_tmp.str(); return s2; } } while (go); return ""; }; // Finds the loop with given stubname in the loop library. Returns information about it. static LibraryFileInfo GetLoopFilenameFromStub (Fweelin *app, const char *stubname) { struct stat st; LibraryFileInfo ret; // Try exact filename with all format types for (codec i = FIRST_FORMAT; i < END_OF_FORMATS; i = (codec) (i+1)) { std::ostringstream tmp; tmp << stubname << app->getCFG()->GetAudioFileExt(i); const std::string s = tmp.str(); if (stat(s.c_str(),&st) == 0) { // Found it ret.exists = 1; ret.c = i; ret.name = s; return ret; } } // No go, try wildcard search with all format types for (codec i = FIRST_FORMAT; i < END_OF_FORMATS; i = (codec) (i+1)) { std::ostringstream tmp; tmp << stubname << "*" << app->getCFG()->GetAudioFileExt(i); const std::string s = tmp.str(); glob_t globbuf; if (glob(s.c_str(), 0, NULL, &globbuf) == 0) { for (size_t j = 0; j < globbuf.gl_pathc; j++) { if (stat(globbuf.gl_pathv[j],&st) == 0) { // Found it ret.exists = 1; ret.c = i; ret.name = globbuf.gl_pathv[j]; globfree(&globbuf); return ret; } } globfree(&globbuf); } } return ret; }; // Finds the data (XML) file with given stubname in the loop library. Returns information about it. static LibraryFileInfo GetDataFilenameFromStub (Fweelin */*app*/, const char *stubname) { struct stat st; LibraryFileInfo ret; // Try exact filename { std::ostringstream tmp; tmp << stubname << FWEELIN_OUTPUT_DATA_EXT; const std::string s = tmp.str(); if (stat(s.c_str(),&st) == 0) { // Found it ret.exists = 1; ret.name = s; return ret; } } // No go, try wildcard search { std::ostringstream tmp; tmp << stubname << "*" << FWEELIN_OUTPUT_DATA_EXT; const std::string s = tmp.str(); glob_t globbuf; if (glob(s.c_str(), 0, NULL, &globbuf) == 0) { for (size_t j = 0; j < globbuf.gl_pathc; j++) { if (stat(globbuf.gl_pathv[j],&st) == 0) { // Found it ret.exists = 1; ret.name = globbuf.gl_pathv[j]; globfree(&globbuf); return ret; } } globfree(&globbuf); } } return ret; }; }; #endif freewheeling-0.6.6/src/fweelin_mem.cc000066400000000000000000000370101370736313100175610ustar00rootroot00000000000000/* I surrender, and God comes singing. */ /* Copyright 2004-2011 Jan Pekau This file is part of Freewheeling. Freewheeling is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. Freewheeling 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 Freewheeling. If not, see . */ #include #include #include #include #include #include #include #include #include #include #include "fweelin_mem.h" #include "fweelin_datatypes.h" // Room for this many instances created / deleted between manager thread passes #define MEMMGR_UPDATE_QUEUE_SIZE 1000 MemoryManager::MemoryManager() : update_queue(0) { // Init mutex/conditions pthread_mutex_init(&mgr_thread_lock,0); pthread_cond_init(&mgr_go,0); // Create update queue update_queue = new SRMWRingBuffer(MEMMGR_UPDATE_QUEUE_SIZE); const static size_t STACKSIZE = 1024*128; pthread_attr_t attr; pthread_attr_init(&attr); pthread_attr_setstacksize(&attr,STACKSIZE); printf("MEMMGR: Stacksize: %zd.\n",STACKSIZE); // Setup manager thread threadgo = 1; int ret = pthread_create(&mgr_thread, &attr, run_mgr_thread, static_cast(this)); if (ret != 0) { printf("MEM: (memorymanager) pthread_create failed, exiting"); exit(1); } RT_RWThreads::RegisterReaderOrWriter(mgr_thread); // Setup high priority threads struct sched_param schp; memset(&schp, 0, sizeof(schp)); schp.sched_priority = sched_get_priority_max(SCHED_OTHER); printf("MEM: Memory manager thread (p%d)\n",schp.sched_priority); if (pthread_setschedparam(mgr_thread, SCHED_OTHER, &schp) != 0) { printf("MEM: Can't set thread priority, will use regular!\n"); } }; MemoryManager::~MemoryManager() { // Terminate the manager thread threadgo = 0; pthread_mutex_lock (&mgr_thread_lock); pthread_cond_signal (&mgr_go); pthread_mutex_unlock (&mgr_thread_lock); pthread_join(mgr_thread,0); pthread_cond_destroy (&mgr_go); pthread_mutex_destroy (&mgr_thread_lock); delete update_queue; printf("MEM: End manager thread.\n"); }; void MemoryManager::WakeUp(MemoryManagerUpdate &upd) { if (update_queue->WriteElement(upd) != 0) { printf("MEM: ERROR: No space in memory manager update queue!\nMust increase MEMMGR_UPDATE_QUEUE_SIZE.\n"); exit(1); } // Wake up the manager thread WakeupIfNeeded(1); }; void MemoryManager::AddType(PreallocatedType *t) { pthread_mutex_lock (&mgr_thread_lock); pts.AddToHead(t); pthread_mutex_unlock (&mgr_thread_lock); }; void MemoryManager::DelType(PreallocatedType *t) { pthread_mutex_lock (&mgr_thread_lock); if (pts.FindAndRemove(t) != 0) t->Cleanup(); pthread_mutex_unlock (&mgr_thread_lock); }; // Look through update queue and perform all updates needed void MemoryManager::ProcessQueue() { // printf("MEM: start process queue\n"); MemoryManagerUpdate mmu = 0; do { // printf("MEM: ...Processing queue...\n"); mmu = update_queue->ReadElement(); if (mmu.IsValid()) { // printf("MEM: Valid item: updatetype: %d typeptr: %p restockidx: %d freeptr: %p\n",mmu.update_type,mmu.which_pt,mmu.updatedat.update_idx,mmu.updatedat.tofree); if (mmu.update_type == T_MU_FreeInstance) { // Free item in free list *take out trash* mmu.which_pt->GoPostdelete(mmu.updatedat.tofree); } else if (mmu.update_type == T_MU_RestockInstance) { // Allocate new item for ready list *restock* mmu.which_pt->GoPreallocate(mmu.updatedat.update_idx); } else { printf("MEM: ERROR: Invalid update type\n"); exit(1); } } //else // printf("MEM: No more items received from queue.\n"); } while (mmu.IsValid()); // printf("MEM: end process queue\n"); }; void *MemoryManager::run_mgr_thread (void *ptr) { MemoryManager *inst = static_cast(ptr); // printf("*** THREAD: %p\n",pthread_self()); pthread_mutex_lock(&inst->mgr_thread_lock); while (inst->threadgo) { inst->ProcessQueue(); // Wait for wakeup pthread_cond_wait (&inst->mgr_go, &inst->mgr_thread_lock); inst->needs_wakeup = 0; // Woken! } printf("MEM: Begin cleanup.\n"); inst->ProcessQueue(); PreallocatedType *cur = (PreallocatedType *) inst->pts.GetFirstItem(); while (cur != 0) { cur->Cleanup(); cur = (PreallocatedType *) inst->pts.GetNextItem(cur); } printf("MEM: End cleanup.\n"); pthread_mutex_unlock(&inst->mgr_thread_lock); return 0; } PreallocatedType::PreallocatedType(MemoryManager *mmgr, Preallocated *prealloc_base, int instance_size, int prealloc_num_instances, char block_mode) : prealloc_base(prealloc_base), instance_size(instance_size), prealloc_num_instances(prealloc_num_instances), block_mode(block_mode), blocks_list(0), mmgr(mmgr) { // Set up ready and free lists ready_list = new RTStore(prealloc_num_instances); // Setup base instance prealloc_base-> SetupPreallocated(this,Preallocated::PREALLOC_BASE_INSTANCE); if (block_mode) { // Setup one base block of instances if (prealloc_num_instances < 3) { printf("MEM: ERROR- Types using block mode must have at least 3 instances."); exit(1); } // Mark first instance in block as base Preallocated *cur = prealloc_base; // Store the first block of instances blocks_list = prealloc_base; /* printf("MEM: NEW BLOCK (STARTUP): %p, size: %d\n",cur, instance_size); */ // The rest are going right into the 'ready list'.. mark them and set them up cur = (Preallocated *) (((char *) cur) + instance_size); for (int i = 1; i < prealloc_num_instances; i++, cur = (Preallocated *) (((char *) cur) + instance_size)) { cur->SetupPreallocated(this,Preallocated::PREALLOC_IN_USE); if (i == 1) // Second instance contains # of free instances cur->predata.prealloc_num_free = 0; // None are free. We have the base instance and then the // rest go straight to the ready list. // Add to ready list... PreallocatedInstance *inst = 0; int inst_idx; // Index in ready list if ((inst = ready_list->FindItemWithState(RTStore::ITEM_DONE, RTStore::ITEM_BUSY,inst_idx)) == 0) { printf("MEM: ERROR: Ready_list size mismatch.\n"); exit(1); } else inst->ptr = cur; if (!ready_list->ChangeStateAtIdx(inst_idx,RTStore::ITEM_BUSY, RTStore::ITEM_WAITING)) { printf("MEM: ERROR: State mismatch in ready_list\n"); exit(1); } } } else { // Instance mode // Create full ready list PreallocatedInstance *i = 0; do { int idx; if ((i = ready_list->FindItemWithState(RTStore::ITEM_DONE, RTStore::ITEM_BUSY,idx)) != 0) { // Prepare an instance and store in the list i->ptr = prealloc_base->NewInstance(); i->ptr->SetupPreallocated(this,Preallocated::PREALLOC_IN_USE); // Update state to waiting (for consumption) if (!ready_list->ChangeStateAtIdx(idx,RTStore::ITEM_BUSY, RTStore::ITEM_WAITING)) { printf("MEM: ERROR: State mismatch in ready_list\n"); exit(1); } } } while (i != 0); } // Add ourselves to list of managed types mmgr->AddType(this); }; PreallocatedType::~PreallocatedType() { // Remove ourselves from list of managed types mmgr->DelType(this); delete ready_list; }; // Realtime and thread-safe function to get a new instance of this class Preallocated *PreallocatedType::RTNew() { // Simply scan through the ready list and get an item marked 'waiting' (for consumption) int idx; PreallocatedInstance *i = ready_list->FindItemWithState(RTStore::ITEM_WAITING, RTStore::ITEM_BUSY,idx); if (i != 0) { // Now, grab the pointer Preallocated *ptr = i->ptr; // And mark it as 'done' (in use) if (!ready_list->ChangeStateAtIdx(idx,RTStore::ITEM_BUSY, RTStore::ITEM_DONE)) { printf("MEM: ERROR: State mismatch in ready_list\n"); exit(1); } // Wake up manager thread to replace the consumed instance MemoryManagerUpdate mmu(this,T_MU_RestockInstance,idx,0); mmgr->WakeUp(mmu); return ptr; } else { // No instances ready for consumption printf("\nMEM: RTNew- No instances available.\n"); // mmgr->WakeupIfNeeded(1); return 0; } }; Preallocated *PreallocatedType::RTNewWithWait() { Preallocated *ret = 0; do { ret = RTNew(); if (ret == 0) { printf("MEM: Waiting for memory to be allocated.\n"); usleep(10000); } } while (ret == 0); return ret; }; // Realtime and thread-safe function to delete this instance of this class void PreallocatedType::RTDelete(Preallocated *inst) { // Wake up manager thread to free the instance MemoryManagerUpdate mmu(this,T_MU_FreeInstance,0,inst); mmgr->WakeUp(mmu); }; void PreallocatedType::GoPostdelete(Preallocated *tofree) { // *** NOTE: Currently no support for deleting additional blocks // of instances- so if we are bursting to many instances // the memory overhead will remain *** // // This should not use significant memory because, in Freewheeling, the large data structures // such as AudioBlock are allocated in instance mode, not block mode. if (block_mode) { // Recycle the instance (instead of deleting) tofree->Recycle(); // Mark as free tofree->prealloc_status = Preallocated::PREALLOC_FREE; // Check pointer range to see which block this instance is in Preallocated *cur = blocks_list; int blocksize = instance_size*prealloc_num_instances; while (cur != 0 && (tofree < cur || (char *) tofree >= ((char *) cur) + blocksize)) cur = cur->predata.prealloc_next; if (cur == 0) { printf("MEM: ERROR: Postdelete: Instance not found in any blocks\n"); exit(1); } else { // Add to free count Preallocated *second = (Preallocated *) (((char *) cur) + instance_size); second->predata.prealloc_num_free++; } } else { // Single instance, simply delete it - no internal data structures to modify ::delete tofree; } }; void PreallocatedType::GoPreallocate(int ready_list_idx) { Preallocated *nw = 0; if (block_mode) { // In block mode, we get a new index from our blocks list. // Find a block with a free instance. Preallocated *curblk = blocks_list; char found = 0; while (!found && curblk != 0) { // Second instance in block contains # of free instances Preallocated *second = (Preallocated *) (((char *) curblk) + instance_size); if (second->predata.prealloc_num_free > 0) { // This block has a free instance. Use it. found = 1; } else curblk = curblk->predata.prealloc_next; } if (found) { // Find a free instance in this block Preallocated *curinst = curblk; int i = 0; for (; i < prealloc_num_instances && curinst->prealloc_status != Preallocated::PREALLOC_FREE; i++, curinst = (Preallocated *) (((char *) curinst) + instance_size)); if (i >= prealloc_num_instances) { // Failed, even though this block says it has free instances printf("MEM: ERROR: Block marked with free instances but has none.\n"); exit(1); } else { // Use this instance nw = curinst; nw->prealloc_status = Preallocated::PREALLOC_IN_USE; // Reduce free count Preallocated *second = (Preallocated *) (((char *) curblk) + instance_size); second->predata.prealloc_num_free--; } } else { // No blocks found with free instances. We need a new block // printf("MEM: New block allocated\n"); nw = prealloc_base->NewInstance(); // Setup new block Preallocated *cur = nw; for (int i = 0; i < prealloc_num_instances; i++, cur = (Preallocated *) (((char *) cur) + instance_size)) { if (i == 0) cur->SetupPreallocated(this,Preallocated::PREALLOC_IN_USE); // Use first instance else cur->SetupPreallocated(this,Preallocated::PREALLOC_FREE); if (i == 1) // Second instance contains # of free instances // All but 1 (which we'll use) will be free cur->predata.prealloc_num_free = prealloc_num_instances-1; } // Link it in nw->predata.prealloc_next = blocks_list; blocks_list = nw; } } else { // Single instance mode. Easy. Since one instance was consumed, we must allocate one more and // put it in the ready list. nw = prealloc_base->NewInstance(); nw->SetupPreallocated(this,Preallocated::PREALLOC_IN_USE); } // Now place this instance in the ready list if (nw != 0) { if (!ready_list->ChangeStateAtIdx(ready_list_idx,RTStore::ITEM_DONE, RTStore::ITEM_BUSY)) { printf("MEM: ERROR: State mismatch in ready_list\n"); exit(1); } ready_list->GetItemAtIdx(ready_list_idx)->ptr = nw; // Mark as waiting-for-consumption if (!ready_list->ChangeStateAtIdx(ready_list_idx,RTStore::ITEM_BUSY, RTStore::ITEM_WAITING)) { printf("MEM: ERROR: State mismatch in ready_list\n"); exit(1); } } else { printf("MEM: ERROR: Can't allocate more instances.\n"); exit(1); } }; void PreallocatedType::Cleanup() { // Ok, we've been told to stop // So we have to delete all preallocated instances/blocks! if (block_mode) { // Delete all blocks from blocks list Preallocated *curblk = blocks_list; while (curblk != 0) { Preallocated *curinst = curblk; int numfree = 0, numfree_verify = 0; for (int i = 0; i < prealloc_num_instances; i++, curinst = (Preallocated *) (((char *) curinst) + instance_size)) { if (i == 1) numfree = curinst->predata.prealloc_num_free; // The check below does not work because instances marked 'in use' could still be in the ready list // if (curinst->prealloc_status == Preallocated::PREALLOC_IN_USE) // printf("MEM: WARNING: Freeing block with instance #%d marked in use.\n",i); if (curinst->prealloc_status == Preallocated::PREALLOC_FREE) numfree_verify++; } if (numfree != numfree_verify) printf("MEM: WARNING: Number of free blocks listed and actual number of free blocks don't match.\n"); Preallocated *tmp = curblk->predata.prealloc_next; curblk->DelBlock(); curblk = tmp; } blocks_list = 0; } else { // No internal data structures to free } }; freewheeling-0.6.6/src/fweelin_mem.h000066400000000000000000000277201370736313100174320ustar00rootroot00000000000000#ifndef __FWEELIN_MEM_H #define __FWEELIN_MEM_H /* Copyright 2004-2011 Jan Pekau This file is part of Freewheeling. Freewheeling is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. Freewheeling 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 Freewheeling. If not, see . */ class MemoryManager; class Preallocated; #include "fweelin_datatypes.h" /* * This source implements memory manager classes that offer very fast, lightweight, realtime and * thread-safe allocation and deallocation of arbitrary class instances. Using this approach, instances * are preallocated and postdeleted and stored in lock-free real-time data structures. * * This allows real-time and time critical threads to get new instances on demand, and to free them without * pausing. The actual memory allocation and deletion are managed in a manager thread. */ // RTStore uses classes, so here's a single preallocated instance: class PreallocatedInstance { public: PreallocatedInstance() : ptr(0) {}; Preallocated *ptr; }; class PreallocatedType : public SListItem { friend class MemoryManager; public: // Default number of instances to keep preallocated const static int PREALLOC_DEFAULT_NUM_INSTANCES = 10; // Tells memory manager to start preallocating blocks of this type // Note for each type of preallocated data we can specify // a different number of instances to keep ready for RT consumption // // We must provide one instance of the Preallocated class as a reference // This is prealloc_base // // If block_mode is 1, a continuous array of instances is used, and unused instances // are recycled instead of new ones constructed. Pass an initial BLOCK of prealloc_num_instances // instances as 'prealloc_base'. PreallocatedType(MemoryManager *mmgr, Preallocated *prealloc_base, int instance_size, int prealloc_num_instances = PREALLOC_DEFAULT_NUM_INSTANCES, char block_mode = 0); // Stops preallocating this type ~PreallocatedType(); // Realtime-safe function to get a new instance of this class Preallocated *RTNew(); // RTNewWithWait() returns a new instance-- whereas RTNew returns 0 // if none is available, RTNewWithWait -waits- until one becomes available // -- not realtime safe -- Preallocated *RTNewWithWait(); // Realtime-safe function to delete this instance of this class void RTDelete(Preallocated *inst); // Perform any preallocations and pending deletes that are needed! // Called by memory manager void GoPreallocate(int ready_list_idx); // Allocate/assign an instance into the ready-to-consume list void GoPostdelete(Preallocated *tofree); // Free/unassign an instance // Cleanup- delete all preallocated instances of this type- called // on program exit void Cleanup(); inline int GetBlockSize() { return prealloc_num_instances; }; private: Preallocated *prealloc_base; // Base instance from which others are spawned RTStore *ready_list; // List of all instances ready (preallocated) // Actual size of one instance (we can't get it with RTTI, so you have to // pass it!) int instance_size; // Number of instances to keep preallocated int prealloc_num_instances; // *** BLOCK MODE *** // Block mode or single instance mode? char block_mode; // List of blocks (block mode only) Preallocated *blocks_list; // Last block index scanned for free instances int block_last_idx; // *** MemoryManager *mmgr; // Memory manager }; // This class is a base for classes that want to be preallocated // and postdeleted-- classes in which new instances are needed // in realtime-- the memory allocation is done in a nonrealtime thread // // One such allocate&delete thread exists for all preallocated types // MemoryManager handles that thread. // // Using this class as a base adds some bytes of size to each instance // which might be a concern if you are allocating many instances! class Preallocated { friend class PreallocatedType; public: // Default constructor calls recycle to init this instance Preallocated() : prealloc_mgr(0) {}; virtual ~Preallocated() {}; void *operator new(size_t) { printf("ERROR: Preallocated type can not be allocated directly\n"); exit(1); }; void operator delete(void*) { // cannot pass to RTDelete as this would end with two delete executed // and destructor called twice printf("ERROR: Preallocated type can not be deleted directly\n"); exit(1); } // Realtime-safe function to get a new instance of this class Preallocated *RTNew() { if (prealloc_mgr == 0) { // No mgr, so allocate nonRT way! //printf("WARNING: nonRT Prealloc in RTNew\n"); return NewInstance(); } else return prealloc_mgr->RTNew(); }; Preallocated *RTNewWithWait() { if (prealloc_mgr == 0) { // No mgr, so allocate nonRT way! //printf("WARNING: nonRT Prealloc in RTNew\n"); return NewInstance(); } else return prealloc_mgr->RTNewWithWait(); }; // Realtime-safe function to delete this instance of this class void RTDelete() { if (prealloc_mgr == 0) { // No mgr, nonRT delete! // printf("WARNING: nonRT delete in RTDelete: %p\n",this); ::delete this; } else prealloc_mgr->RTDelete(this); }; // Returns the PreallocatedType manager associated with this type inline PreallocatedType *GetMgr() { return prealloc_mgr; }; // Values for status of preallocated instances const static char PREALLOC_BASE_INSTANCE = 0, // Base instance, never deleted PREALLOC_IN_USE = 1, // In use means 'in the ready list, or already consumed // for use' PREALLOC_FREE = 2; // Free is only applicable for block mode, and means // 'ready to be added to the ready list- not available for // consumption yet' // This setup function is called from PreallocatedType // after a new instance of Preallocated is created. // It sets up the internal variables in this instance. void SetupPreallocated(PreallocatedType *mgr, char status) { prealloc_mgr = mgr; prealloc_status = status; predata.prealloc_next = 0; }; private: // Code to destroy a block of instances- only called in block mode // This is a workaround because operator delete[] is not virtual // and can not handle our arrays of derived instances // // Any derived classes that use block mode must re-implement this method (ie use the macro below). #define FWMEM_DEFINE_DELBLOCK virtual void DelBlock() { ::delete[] this; }; FWMEM_DEFINE_DELBLOCK; // Code to call new operator for the derived class (nonRT) // All allocation and lengthy initialization can be done here // If this type is allocated in block mode, NewInstance must allocate // not one instance, but an array of instances with prealloc_num_instances // size virtual Preallocated *NewInstance() = 0; // For managed types in block mode only: // // This method should recycle an old instance to be used again. // It is used instead of the constructor/destructor. // // In block mode, the default constructor is called by NewInstance (which you implement) // ONCE when allocating a block of instances. When an instance is freed, it is not destructed // but simply Recycled. // // Initialization code can go here. // // This method is called from the memory manager thread, so it needn't be RT safe. virtual void Recycle() {}; // Status of this instance char prealloc_status; // PreallocatedType that manages the allocation of new instances // ** With a table, this could be optimized out of each instance ** PreallocatedType *prealloc_mgr; union { // In block mode, // Each instance is part of an array. And each array is part of a linked // list. So we have a list of blocks of instances. // The 1st instance in a block points to the next block. // The 2nd instance in a block holds the # of free instances in that block: int prealloc_num_free; // Next instance- or in block mode, next block of instances Preallocated *prealloc_next; } predata; }; enum MemoryManagerUpdateType { T_MU_RestockInstance, T_MU_FreeInstance, }; /** * This class communicates a single change from RTNew() / RTDelete() to nonRT manager thread. * The manager thread must either "re-stock the shelves" in the ready list, or * "Take out the trash" by freeing an instance. */ class MemoryManagerUpdate { public: // Zero (invalid) update MemoryManagerUpdate(int zero = 0) : which_pt(0) { if (zero) { /*zero is for what now?*/ } }; // Valid update MemoryManagerUpdate(PreallocatedType *which_pt, MemoryManagerUpdateType update_type, int update_idx, Preallocated *tofree) : which_pt(which_pt), update_type(update_type) { if (update_type == T_MU_RestockInstance) updatedat.update_idx = update_idx; else if (update_type == T_MU_FreeInstance) updatedat.tofree = tofree; }; inline char IsValid() { return which_pt != 0; }; PreallocatedType *which_pt; // Which preallocated type needs updating MemoryManagerUpdateType update_type; // Is it a change to the ready list or an item to be freed union { int update_idx; // If it's an item to restock, which index to update Preallocated *tofree; // If it's an instance to be freed, pointer to the instance } updatedat; }; class MemoryManager { public: MemoryManager(); ~MemoryManager(); // Starts managing the specified type void AddType(PreallocatedType *t); // Stops managing the specified type void DelType(PreallocatedType *t); // Wake up the manager thread- // queue the update- // either we need to re-stock the shelves or take out the trash void WakeUp(MemoryManagerUpdate &upd); // Wakeup the memory manager thread. Non blocking, RT safe. inline void WakeupIfNeeded(char always_wakeup = 0) { if (always_wakeup || needs_wakeup) { /* if (!always_wakeup) printf("MEM: Woken because of priority inversion\n"); */ // Wake up the memory manager thread if (pthread_mutex_trylock (&mgr_thread_lock) == 0) { pthread_cond_signal (&mgr_go); pthread_mutex_unlock (&mgr_thread_lock); } else { // Priority inversion - we are interrupting the memory manager thread while it's processing // update_queue. This is not an issue, because update_queue uses SRMWRingBuffer. // However, the memory manager thread may go to sleep, missing the new updates // until it's woken again. So, set a flag and the RT audio // thread will wake it up next process cycle. if (always_wakeup) { // printf("MEM: WARNING: Priority inversion while filling update queue!\n"); needs_wakeup = 1; } } } }; private: // Look through update queue and perform all updates needed void ProcessQueue(); // Thread function static void *run_mgr_thread (void *ptr); // List of all PreallocatedTypes we are managing SLinkList pts; // Queue of all changes needed to ready_lists and items to be freed SRMWRingBuffer *update_queue; volatile char needs_wakeup; // Memory manager thread needs wakeup? (priority inversion) // Thread to preallocate and postdelete instances pthread_t mgr_thread; pthread_mutex_t mgr_thread_lock; pthread_cond_t mgr_go; int threadgo; }; #endif freewheeling-0.6.6/src/fweelin_midiio.cc000066400000000000000000001301541370736313100202600ustar00rootroot00000000000000/* Control is such a trick-- We can guide the ship but are we ever really in control of where we land? */ /* Copyright 2004-2011 Jan Pekau This file is part of Freewheeling. Freewheeling is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. Freewheeling 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 Freewheeling. If not, see . */ #include #if HAVE_SYS_RESOURCE_H #include #endif #include #include #include #include #include #include #include #include #include #include "fweelin_midiio.h" #include "fweelin_core.h" // ******** MIDI #define MIDI_CLIENT_NAME "FreeWheeling" #ifdef __MACOSX__ // ******** MACOSX MIDI void MidiIO::SetMIDIInput (int idx) { if (inputidx != -1) { // Deselect previous source MIDIEndpointRef src = MIDIGetSource(inputidx); if (src != 0) { //printf("DISCONNECT MIDI: %d\n",inputidx); MIDIPortDisconnectSource(in_ports[0], src); } } inputidx = idx; // Select new source MIDIEndpointRef src = MIDIGetSource(inputidx); if (src != 0) { //printf("CONNECT MIDI: %d\n",inputidx); MIDIPortConnectSource(in_ports[0], src, 0); } }; // Open MIDI engine with num_in writeable ports and num_out readable ports. // Nonzero is returned on error char MidiIO::open_midi (int num_in, int num_out) { if (MIDIClientCreate(CFSTR(MIDI_CLIENT_NAME), 0, 0, &client) != noErr) { fprintf(stderr, "MIDI: Error opening MIDI client.\n"); return -1; } int l1; char portname[64]; numins = num_in; numouts = num_out; in_ports = new MIDIPortRef[num_in]; out_ports = new MIDIPortRef[num_out]; out_sources = new MIDIEndpointRef[num_out]; for (l1 = 0; l1 < num_in; l1++) { sprintf(portname, MIDI_CLIENT_NAME " IN %d", l1+1); if (MIDIInputPortCreate(client, CFStringCreateWithCString(0,portname,kCFStringEncodingUTF8), MidiInputProc, this, &in_ports[l1]) != noErr) { fprintf(stderr, "MIDI: Error creating MIDI port.\n"); return -1; } } for (l1 = 0; l1 < num_out; l1++) { sprintf(portname, MIDI_CLIENT_NAME " OUT %d", l1+1); if (MIDIOutputPortCreate(client, CFStringCreateWithCString(0,portname,kCFStringEncodingUTF8), &out_ports[l1]) != noErr) { fprintf(stderr, "MIDI: Error creating MIDI port.\n"); return -1; } } // Make list of input sources int n = MIDIGetNumberOfSources(); printf("MIDI: Input possible from %d sources.\n", n); CFStringRef endname; char cendname[1024]; FweelinMac::ClearMIDIInputList(); for (int i = 0; i < n; ++i) { MIDIEndpointRef src = MIDIGetSource(i); MIDIObjectGetStringProperty(src, kMIDIPropertyName, &endname); CFStringGetCString(endname, cendname, 1024, kCFStringEncodingUTF8); printf(" MIDI: source name: %s\n",cendname); FweelinMac::AddMIDIInputSource(cendname); } // Connect first input SetMIDIInput(0); #ifdef FWEELIN_MIDI_SEND // We no longer use MIDISend to send to destinations-- // because many apps connect to sources, we instead create virtual sources for each output // and use MIDIReceived to send to them // Discover a place to send MIDI data n = MIDIGetNumberOfDestinations(); printf("MIDI: Output possible to %d destinations.\n",n); if (n > 0) dest = MIDIGetDestination(n-1); if (dest == 0) { printf("MIDI: WARNING: No place to send MIDI.\n"); return 0; // No place to send data } // Get name of destination we are sending to CFStringRef pName; char name[64]; MIDIObjectGetStringProperty(dest, kMIDIPropertyName, &pName); CFStringGetCString(pName, name, sizeof(name), 0); CFRelease(pName); printf("MIDI: Sending MIDI to destination: %s\n", name); // MIDI transmit using destinations #define MIDI_TRANSMIT(idx) MIDISend(out_ports[idx], dest, packetList) #else // FWEELIN_MIDI_SEND dest = 0; // Create virtual sources char sourcename[64]; for (int i = 0; i < num_out; i++) { sprintf(sourcename, MIDI_CLIENT_NAME " OUT %d", i+1); if (MIDISourceCreate(client,CFStringCreateWithCString(0,sourcename,kCFStringEncodingUTF8), &out_sources[i]) != noErr) { fprintf(stderr, "MIDI: Error creating virtual MIDI source.\n"); return -1; } } // MIDI transmit using virtual sources #define MIDI_TRANSMIT(idx) MIDIReceived(out_sources[idx], packetList) #endif // FWEELIN_MIDI_SEND return 0; } int MidiIO::activate() { FloConfig *fs = app->getCFG(); // Open up MIDI if (open_midi(1, fs->GetNumMIDIOuts())) { fprintf(stderr, "MIDI: Can't open MIDI client.\n"); exit(1); } listen_events(); // Request initial patch from patch browser PatchBrowser *br = (PatchBrowser *) app->getBROWSER(B_Patch); if (br != 0) br->SetMIDIForPatch(); // Prepare auto-bypass bp = new BypassInfo[fs->GetNumMIDIOuts()*MAX_MIDI_CHANNELS]; inst->checkfreq = inst->app->getAUDIO()->get_srate(); // How often to check auto-bypass conditions for MIDI return 0; } void MidiIO::close() { printf("MIDI: begin close...\n"); unlisten_events(); printf("MIDI: end\n"); } void MidiIO::MidiInputProc (const MIDIPacketList *pktlist, void *refCon, void *connRefCon) { MidiIO *inst = static_cast(refCon); // Check whether to unbypass used channels inst->CheckUnbypass(); MIDIPacket *packet = (MIDIPacket *) pktlist->packet; for (int j = 0; j < pktlist->numPackets; j++) { if ((packet->data[0] >= 0x80 && packet->data[0] <= 0x8F) || (packet->data[0] >= 0x90 && packet->data[0] <= 0x9F && packet->data[2] == 0)) { // Interpret NoteOn velocity 0 as note off // Note Off int base = (packet->data[0] >= 0x90 ? 0x90 : 0x80); inst->ReceiveNoteOffEvent(packet->data[0] - base, packet->data[1], packet->data[2]); } else if (packet->data[0] >= 0x90 && packet->data[0] <= 0x9F) { // Note On inst->ReceiveNoteOnEvent(packet->data[0] - 0x90, packet->data[1], packet->data[2]); } else if (packet->data[0] >= 0xB0 && packet->data[0] <= 0xBF) { // Control Change inst->ReceiveControlChangeEvent(packet->data[0] - 0xB0, packet->data[1], packet->data[2]); } else if (packet->data[0] >= 0xC0 && packet->data[0] <= 0xCF) { // Program Change inst->ReceiveProgramChangeEvent(packet->data[0] - 0xC0, packet->data[1]); } else if (packet->data[0] >= 0xD0 && packet->data[0] <= 0xDF) { // Channel Pressure inst->ReceiveChannelPressureEvent(packet->data[0] - 0xD0, packet->data[1]); } else if (packet->data[0] >= 0xE0 && packet->data[0] <= 0xEF) { // Pitch Bend int lsb = packet->data[1], msb = packet->data[2], benderval = msb << 8 + lsb; inst->ReceivePitchBendEvent(packet->data[0] - 0xE0, benderval); } // Advance packet = MIDIPacketNext(packet); } // Check whether to bypass unused channels inst->CheckBypass(); } void MidiIO::OutputController (int port, int chan, int ctrl, int val) { unsigned char msg[3]; msg[0] = 0xB0 + chan; msg[1] = (unsigned char) ctrl; if (val > 127) val = 127; else if (val < 0) val = 0; msg[2] = (unsigned char) val; curPacket = MIDIPacketListAdd(packetList,sizeof(obuf), curPacket,0 /*Now*/,3,msg); }; void MidiIO::OutputProgramChange (int port, int chan, int val) { unsigned char msg[2]; msg[0] = 0xC0 + chan; if (val > 127) val = 127; else if (val < 0) val = 0; msg[1] = (unsigned char) val; curPacket = MIDIPacketListAdd(packetList,sizeof(obuf), curPacket,0 /*Now*/,2,msg); }; void MidiIO::OutputChannelPressure (int port, int chan, int val) { unsigned char msg[2]; msg[0] = 0xD0 + chan; if (val > 127) val = 127; else if (val < 0) val = 0; msg[1] = (unsigned char) val; curPacket = MIDIPacketListAdd(packetList,sizeof(obuf), curPacket,0 /*Now*/,2,msg); }; void MidiIO::OutputPitchBend (int port, int chan, int val) { unsigned char msg[3]; msg[0] = 0xE0 + chan; msg[1] = (unsigned char) (val & 0x00FF); // LSB msg[2] = (unsigned char) (val >> 8); // MSB curPacket = MIDIPacketListAdd(packetList,sizeof(obuf), curPacket,0 /*Now*/,3,msg); }; void MidiIO::OutputNote (int port, int chan, char down, int notenum, int vel) { unsigned char msg[3]; if (down) msg[0] = 0x90 + chan; // NoteOn else msg[0] = 0x80 + chan; // NoteOff msg[1] = (unsigned char) notenum; msg[2] = (unsigned char) vel; curPacket = MIDIPacketListAdd(packetList,sizeof(obuf), curPacket,0 /*Now*/,3,msg); }; void MidiIO::OutputClock (int port) { unsigned char msg = 0xF8; curPacket = MIDIPacketListAdd(packetList,sizeof(obuf), curPacket,0 /*Now*/,1,&msg); }; void MidiIO::OutputStart (int port) { unsigned char msg = 0xFA; curPacket = MIDIPacketListAdd(packetList,sizeof(obuf), curPacket,0 /*Now*/,1,&msg); }; void MidiIO::OutputStop (int port) { unsigned char msg = 0xFC; curPacket = MIDIPacketListAdd(packetList,sizeof(obuf), curPacket,0 /*Now*/,1,&msg); }; void MidiIO::OutputStartOnPort () { // Init output packet curPacket = MIDIPacketListInit(packetList); };b void MidiIO::OutputEndOnPort (int port) { // Send MIDI packet- all messages for this port MIDI_TRANSMIT(port); }; #else // __MACOSX__ // ******** LINUX MIDI // Open MIDI engine with num_in writeable ports and num_out readable ports. // Nonzero is returned on error char MidiIO::open_midi (int num_in, int num_out) { int l1; char portname[64]; numins = num_in; numouts = num_out; in_ports = new int[num_in]; out_ports = new int[num_out]; if (snd_seq_open(&seq_handle, "default", SND_SEQ_OPEN_DUPLEX, 0) < 0) { fprintf(stderr, "MIDI: Error opening ALSA MIDI.\n"); return -1; } snd_seq_set_client_name(seq_handle, MIDI_CLIENT_NAME); for (l1 = 0; l1 < num_in; l1++) { sprintf(portname, MIDI_CLIENT_NAME " IN %d", l1+1); if ((in_ports[l1] = snd_seq_create_simple_port(seq_handle, portname, SND_SEQ_PORT_CAP_WRITE|SND_SEQ_PORT_CAP_SUBS_WRITE, SND_SEQ_PORT_TYPE_APPLICATION)) < 0) { fprintf(stderr, "MIDI: Error creating MIDI port.\n"); return -1; } } for (l1 = 0; l1 < num_out; l1++) { sprintf(portname, MIDI_CLIENT_NAME " OUT %d", l1+1); if ((out_ports[l1] = snd_seq_create_simple_port(seq_handle, portname, SND_SEQ_PORT_CAP_READ|SND_SEQ_PORT_CAP_SUBS_READ, SND_SEQ_PORT_TYPE_APPLICATION)) < 0) { fprintf(stderr, "MIDI: Error creating MIDI port.\n"); return -1; } } return 0; } int MidiIO::activate() { // Linux MIDI handling using ALSA seq on its own thread printf("MIDI: Starting MIDI thread..\n"); const static size_t STACKSIZE = 1024*64; pthread_attr_t attr; pthread_attr_init(&attr); pthread_attr_setstacksize(&attr,STACKSIZE); printf("MIDI: Stacksize: %zd.\n",STACKSIZE); midithreadgo = 1; int ret = pthread_create(&midi_thread, &attr, run_midi_thread, this); if (ret != 0) { printf("(start) pthread_create failed, exiting"); return 1; } RT_RWThreads::RegisterReaderOrWriter(midi_thread); // Setup high priority threads struct sched_param schp; memset(&schp, 0, sizeof(schp)); // MIDI thread at SCHED_FIFO- yes! High priority! //schp.sched_priority = sched_get_priority_max(SCHED_OTHER); //schp.sched_priority = sched_get_priority_min(SCHED_FIFO); schp.sched_priority = sched_get_priority_max(SCHED_FIFO); #ifdef RLIMIT_RTPRIO // Check the rtprio limit (/etc/security/limits.conf) struct rlimit user_limits; memset(&user_limits, 0, sizeof(user_limits)); if (getrlimit(RLIMIT_RTPRIO, &user_limits) == 0 && user_limits.rlim_max > 0 && schp.sched_priority > 0 && user_limits.rlim_max < static_cast(schp.sched_priority)) { schp.sched_priority = user_limits.rlim_max; } #endif printf("MIDI: HiPri Thread %d\n",schp.sched_priority); if (pthread_setschedparam(midi_thread, SCHED_FIFO /* OTHER */, &schp) != 0) { printf("MIDI: Can't set realtime thread, will use nonRT!\n"); } // Request initial patch from patch browser PatchBrowser *br = (PatchBrowser *) app->getBROWSER(B_Patch); if (br != 0) br->SetMIDIForPatch(); // Prepare auto-bypass bp = new BypassInfo[app->getCFG()->GetNumMIDIOuts()*MAX_MIDI_CHANNELS]; return 0; } void MidiIO::close() { printf("MIDI: begin close...\n"); midithreadgo = 0; pthread_join(midi_thread,0); printf("MIDI: end\n"); } void *MidiIO::run_midi_thread(void *ptr) { MidiIO *inst = static_cast(ptr); int npfd; struct pollfd *pfd; FloConfig *fs = inst->app->getCFG(); inst->checkfreq = inst->app->getAUDIO()->get_srate(); // How often to check auto-bypass conditions for MIDI printf("MIDIthread start..\n"); // printf("*** MIDI THREAD: %li\n",pthread_self()); // Open up ALSA MIDI client if (inst->open_midi(1, fs->GetNumMIDIOuts())) { fprintf(stderr, "MIDI: Can't open ALSA MIDI.\n"); exit(1); } npfd = snd_seq_poll_descriptors_count(inst->seq_handle, POLLIN); pfd = (struct pollfd *)alloca(npfd * sizeof(struct pollfd)); snd_seq_poll_descriptors(inst->seq_handle, pfd, npfd, POLLIN); inst->listen_events(); // Main MIDI loop while (inst->midithreadgo) { // Every second, come out of poll-- so we don't get locked up // if no MIDI events come in if (poll(pfd, npfd, 1000) > 0) { // There's an event here! // Check whether to unbypass used channels inst->CheckUnbypass(); // Read event(s) snd_seq_event_t *ev; // static int cnt = 0; do { snd_seq_event_input(inst->seq_handle, &ev); switch (ev->type) { #ifdef FWEELIN_LOG_UNHANDLED_MIDI_EVTS case SND_SEQ_EVENT_QFRAME: printf("MTC quarterframe\n"); break; case SND_SEQ_EVENT_CLOCK: if (cnt % 24 == 0) printf("clock: %d\n",cnt); cnt++; //printf("clock: %d\n",ev->data.time.tick); //printf("clock: %d\n",ev->data.time.time.tv_sec); //printf("clock: %d\n",ev->data.queue.param.time.time.tv_sec); break; case SND_SEQ_EVENT_TICK: printf("MIDI: 'tick' not yet implemented\n"); break; case SND_SEQ_EVENT_TEMPO: printf("MIDI: 'tempo' not yet implemented\n"); break; #endif // FWEELIN_LOG_UNHANDLED_MIDI_EVTS case SND_SEQ_EVENT_CONTROLLER: // Control Change inst->ReceiveControlChangeEvent(ev->data.control.channel, ev->data.control.param, ev->data.control.value); break; case SND_SEQ_EVENT_CHANPRESS: // Channel aftertouch inst->ReceiveChannelPressureEvent(ev->data.control.channel, ev->data.control.value); break; case SND_SEQ_EVENT_PGMCHANGE: // Program Change inst->ReceiveProgramChangeEvent(ev->data.control.channel, ev->data.control.value); break; case SND_SEQ_EVENT_PITCHBEND: // Pitch Bend inst->ReceivePitchBendEvent(ev->data.control.channel, ev->data.control.value); break; case SND_SEQ_EVENT_NOTEON: // Note On inst->ReceiveNoteOnEvent(ev->data.control.channel, ev->data.note.note, ev->data.note.velocity); break; case SND_SEQ_EVENT_NOTEOFF: // Note Off inst->ReceiveNoteOffEvent(ev->data.control.channel, ev->data.note.note, ev->data.note.velocity); break; } snd_seq_free_event(ev); } while (snd_seq_event_input_pending(inst->seq_handle, 0) > 0); } // Every MIDI msg or at max 1 s intervals, check auto-bypass conditions inst->CheckBypass(); } inst->unlisten_events(); printf("MIDI: thread done\n"); return 0; } void MidiIO::OutputController (int port, int chan, int ctrl, int val) { if (val > 127) val = 127; else if (val < 0) val = 0; snd_seq_event_t outev; snd_seq_ev_set_subs(&outev); snd_seq_ev_set_direct(&outev); snd_seq_ev_set_source(&outev,out_ports[port]); snd_seq_ev_set_controller(&outev,chan,ctrl,val); snd_seq_event_output_direct(seq_handle, &outev); }; void MidiIO::OutputProgramChange (int port, int chan, int val) { if (val > 127) val = 127; else if (val < 0) val = 0; snd_seq_event_t outev; snd_seq_ev_set_subs(&outev); snd_seq_ev_set_direct(&outev); snd_seq_ev_set_source(&outev,out_ports[port]); snd_seq_ev_set_pgmchange(&outev,chan,val); snd_seq_event_output_direct(seq_handle, &outev); }; void MidiIO::OutputChannelPressure (int port, int chan, int val) { if (val > 127) val = 127; else if (val < 0) val = 0; snd_seq_event_t outev; snd_seq_ev_set_subs(&outev); snd_seq_ev_set_direct(&outev); snd_seq_ev_set_source(&outev,out_ports[port]); snd_seq_ev_set_chanpress(&outev,chan,val); snd_seq_event_output_direct(seq_handle, &outev); }; void MidiIO::OutputPitchBend (int port, int chan, int val) { snd_seq_event_t outev; snd_seq_ev_set_subs(&outev); snd_seq_ev_set_direct(&outev); snd_seq_ev_set_source(&outev,out_ports[port]); snd_seq_ev_set_pitchbend(&outev,chan,val); snd_seq_event_output_direct(seq_handle, &outev); }; void MidiIO::OutputNote (int port, int chan, char down, int notenum, int vel) { snd_seq_event_t outev; snd_seq_ev_set_subs(&outev); snd_seq_ev_set_direct(&outev); snd_seq_ev_set_source(&outev,out_ports[port]); if (down) snd_seq_ev_set_noteon(&outev,chan,notenum,vel); else snd_seq_ev_set_noteoff(&outev,chan,notenum,vel); snd_seq_event_output_direct(seq_handle, &outev); }; void MidiIO::OutputClock (int port) { snd_seq_event_t outev; snd_seq_ev_set_subs(&outev); snd_seq_ev_set_direct(&outev); snd_seq_ev_set_source(&outev,out_ports[port]); outev.type = SND_SEQ_EVENT_CLOCK; snd_seq_ev_set_fixed(&outev); snd_seq_event_output_direct(seq_handle, &outev); }; void MidiIO::OutputStart (int port) { snd_seq_event_t outev; snd_seq_ev_set_subs(&outev); snd_seq_ev_set_direct(&outev); snd_seq_ev_set_source(&outev,out_ports[port]); outev.type = SND_SEQ_EVENT_START; snd_seq_ev_set_fixed(&outev); snd_seq_event_output_direct(seq_handle, &outev); }; void MidiIO::OutputSPP (int port) { snd_seq_event_t outev; snd_seq_ev_set_subs(&outev); snd_seq_ev_set_direct(&outev); snd_seq_ev_set_source(&outev,out_ports[port]); outev.type = SND_SEQ_EVENT_SONGPOS; outev.data.control.value = 0; // Always start at the beginning snd_seq_ev_set_fixed(&outev); snd_seq_event_output_direct(seq_handle, &outev); }; void MidiIO::OutputStop (int port) { snd_seq_event_t outev; snd_seq_ev_set_subs(&outev); snd_seq_ev_set_direct(&outev); snd_seq_ev_set_source(&outev,out_ports[port]); outev.type = SND_SEQ_EVENT_STOP; snd_seq_ev_set_fixed(&outev); snd_seq_event_output_direct(seq_handle, &outev); }; // Events are sent directly- no buffer emptying necessary void MidiIO::OutputStartOnPort () {}; void MidiIO::OutputEndOnPort (int /*port*/) {}; #endif // __MACOSX__ // ******** CROSS-PLATFORM MIDI CODE MidiIO::MidiIO (Fweelin *app) : bendertune(0), curbender(0), echoport(1), echochan(-1), curpatch(0), numins(0), numouts(0), app(app), checkfreq(40000), lastchecktime(0), #ifdef __MACOSX__ client(0), in_ports(0), out_ports(0), out_sources(0), dest(0), inputidx(-1), curPacket(0), packetList((MIDIPacketList *) obuf), #else seq_handle(0), in_ports(0), out_ports(0), midithreadgo(0), #endif bp(0), midisyncxmit(0) { note_def_port = new int[MAX_MIDI_NOTES]; note_patch = new PatchItem *[MAX_MIDI_NOTES]; memset(note_def_port,0,sizeof(int) * MAX_MIDI_NOTES); memset(note_patch,0,sizeof(PatchItem *) * MAX_MIDI_NOTES); }; void MidiIO::listen_events () { FloConfig *fs = app->getCFG(); app->getEMG()->ListenEvent(this,0,T_EV_SetMidiTuning); app->getEMG()->ListenEvent(this,0,T_EV_SetMidiEchoPort); app->getEMG()->ListenEvent(this,0,T_EV_SetMidiEchoChannel); app->getEMG()->ListenEvent(this,fs->GetInputMatrix(), T_EV_Input_MIDIKey); app->getEMG()->ListenEvent(this,fs->GetInputMatrix(), T_EV_Input_MIDIController); app->getEMG()->ListenEvent(this,fs->GetInputMatrix(), T_EV_Input_MIDIProgramChange); app->getEMG()->ListenEvent(this,fs->GetInputMatrix(), T_EV_Input_MIDIPitchBend); app->getEMG()->ListenEvent(this,0,T_EV_Input_MIDIClock); app->getEMG()->ListenEvent(this,0,T_EV_Input_MIDIStartStop); } void MidiIO::unlisten_events () { FloConfig *fs = app->getCFG(); app->getEMG()->UnlistenEvent(this,0,T_EV_SetMidiTuning); app->getEMG()->UnlistenEvent(this,0,T_EV_SetMidiEchoPort); app->getEMG()->UnlistenEvent(this,0,T_EV_SetMidiEchoChannel); app->getEMG()->UnlistenEvent(this,fs->GetInputMatrix(), T_EV_Input_MIDIKey); app->getEMG()->UnlistenEvent(this,fs->GetInputMatrix(), T_EV_Input_MIDIController); app->getEMG()->UnlistenEvent(this,fs->GetInputMatrix(), T_EV_Input_MIDIProgramChange); app->getEMG()->UnlistenEvent(this,fs->GetInputMatrix(), T_EV_Input_MIDIPitchBend); app->getEMG()->UnlistenEvent(this,0,T_EV_Input_MIDIClock); app->getEMG()->UnlistenEvent(this,0,T_EV_Input_MIDIStartStop); } void MidiIO::ReceiveNoteOffEvent (int channel, int notenum, int vel) { // Note Off MIDIKeyInputEvent *mevt = (MIDIKeyInputEvent *) Event::GetEventByType(T_EV_Input_MIDIKey); mevt->down = 0; mevt->channel = channel; mevt->notenum = notenum; if (mevt->notenum < 0 || mevt->notenum >= MAX_MIDI_NOTES) { printf("MIDI: Bad MIDI note #%d!\n",mevt->notenum); mevt->notenum = 0; } mevt->vel = vel; mevt->outport = note_def_port[mevt->notenum]; if (app->getCFG()->IsDebugInfo()) printf("MIDI: Note %d off, channel %d velocity %d\n", mevt->notenum, mevt->channel, mevt->vel); app->getEMG()->BroadcastEventNow(mevt, this); }; void MidiIO::ReceiveNoteOnEvent (int channel, int notenum, int vel) { MIDIKeyInputEvent *mevt = (MIDIKeyInputEvent *) Event::GetEventByType(T_EV_Input_MIDIKey); mevt->channel = channel; mevt->notenum = notenum; if (mevt->notenum < 0 || mevt->notenum >= MAX_MIDI_NOTES) { printf("MIDI: Bad MIDI note #%d!\n",mevt->notenum); mevt->notenum = 0; } mevt->vel = vel; if (vel > 0) { mevt->down = 1; note_def_port[mevt->notenum] = mevt->outport = echoport; note_patch[mevt->notenum] = curpatch; } else { mevt->down = 0; mevt->outport = note_def_port[mevt->notenum]; } if (app->getCFG()->IsDebugInfo()) printf("MIDI: Note %d %s, channel %d velocity %d\n", mevt->notenum, (mevt->down ? "on" : "off"), mevt->channel, mevt->vel); app->getEMG()->BroadcastEventNow(mevt, this); } void MidiIO::ReceivePitchBendEvent (int channel, int value) { // Store incoming bender value curbender = value; // Perform tune value += bendertune; MIDIPitchBendInputEvent *mevt = (MIDIPitchBendInputEvent *) Event::GetEventByType(T_EV_Input_MIDIPitchBend); mevt->outport = echoport; mevt->channel = channel; mevt->val = value; if (app->getCFG()->IsDebugInfo()) printf("MIDI: Pitchbend channel %d value %d\n", mevt->channel,mevt->val); app->getEMG()->BroadcastEventNow(mevt, this); } void MidiIO::ReceiveChannelPressureEvent (int channel, int value) { MIDIChannelPressureInputEvent *mevt = (MIDIChannelPressureInputEvent *) Event::GetEventByType(T_EV_Input_MIDIChannelPressure); mevt->outport = echoport; mevt->channel = channel; mevt->val = value; if (app->getCFG()->IsDebugInfo()) printf("MIDI: Channel pressure channel %d value %d\n", mevt->channel,mevt->val); app->getEMG()->BroadcastEventNow(mevt, this); } void MidiIO::ReceiveProgramChangeEvent (int channel, int value) { MIDIProgramChangeInputEvent *mevt = (MIDIProgramChangeInputEvent *) Event::GetEventByType(T_EV_Input_MIDIProgramChange); mevt->outport = echoport; mevt->channel = channel; mevt->val = value; if (app->getCFG()->IsDebugInfo()) printf("MIDI: Program change channel %d value %d\n", mevt->channel,mevt->val); app->getEMG()->BroadcastEventNow(mevt, this); } void MidiIO::ReceiveControlChangeEvent (int channel, int ctrl, int value) { MIDIControllerInputEvent *mevt = (MIDIControllerInputEvent *) Event::GetEventByType(T_EV_Input_MIDIController); mevt->outport = echoport; mevt->channel = channel; mevt->ctrl = ctrl; mevt->val = value; if (app->getCFG()->IsDebugInfo()) printf("MIDI: Controller %d channel %d value %d\n",mevt->ctrl, mevt->channel,mevt->val); app->getEMG()->BroadcastEventNow(mevt, this); } MidiIO::~MidiIO() { delete[] note_def_port; delete[] note_patch; if (in_ports != 0) delete[] in_ports; if (out_ports != 0) delete[] out_ports; if (bp != 0) delete[] bp; #ifdef __MACOSX__ if (out_sources != 0) delete[] out_sources; #endif // __MACOSX__ } void MidiIO::SetMIDIForPatch (int def_port, PatchItem *patch) { if (CRITTERS) printf("MIDI: Setup MIDI for Patch (Port: %d Patch: %s)\n",def_port, (patch != 0 ? patch->name : "(none)")); // Move away from another patch? if (curpatch != 0 && patch != curpatch) { if (curpatch->IsCombi()) { // Bypass settings for (int i = 0; i < curpatch->numzones; i++) { CombiZone *z = curpatch->GetZone(i); if (z->bypasscc != 0) { int z_port = (z->port_r ? z->port : echoport), c = (z->bypasschannel == -1 ? z->channel : z->bypasschannel); BypassInfo *b = getBP(z_port-1,c); if (b != 0) b->active = 1; // Activate auto-bypass as we are leaving this patch else printf("MIDI: Can't find BypassInfo struct for p/c [%d/%d]\n",z_port-1,c); } } } else { // Bypass settings if (curpatch->bypasscc != 0) { int c = (curpatch->bypasschannel == -1 ? echochan : curpatch->bypasschannel); BypassInfo *b = getBP(echoport-1,c); if (b != 0) b->active = 1; // Activate auto-bypass as we are leaving this patch else printf("MIDI: Can't find BypassInfo struct for p/c [%d/%d]\n",echoport-1,c); } } } // Save default port char outportschanged = 0, usefluid = 0; // Enable FluidSynth? if (def_port >= 0 && def_port <= numouts) { if (def_port != echoport) { echoport = def_port; outportschanged = 1; if (echoport == 0) usefluid = 1; } } else printf("MIDI: Invalid port #%d (valid range 0-%d)\n", def_port,numouts); if (patch != 0) { if (patch->IsCombi()) { // Store reference to patch, to get zones later if (patch != curpatch) { curpatch = patch; // Check if FluidSynth port is referenced- outportschanged = 1; usefluid = 0; for (int i = 0; i < patch->numzones && !usefluid; i++) { CombiZone *z = patch->GetZone(i); if ((!z->port_r && echoport == 0) || // Port 0 is FluidSynth (z->port_r && z->port == 0)) usefluid = 1; } if (CRITTERS) printf("MIDI: COMBI PATCH!\n"); // Bypass settings for (int i = 0; i < curpatch->numzones; i++) { CombiZone *z = curpatch->GetZone(i); if (z->bypasscc != 0) { int z_port = (z->port_r ? z->port : echoport), c = (z->bypasschannel == -1 ? z->channel : z->bypasschannel); BypassInfo *b = getBP(z_port-1,c); if (b != 0) { b->active = 0; // Only bypass when we switch away from another patch b->bypasscc = z->bypasscc; b->bypasslen1 = (nframes_t) (z->bypasstime1*app->getAUDIO()->get_srate()); b->bypasslen2 = (nframes_t) (z->bypasstime2*app->getAUDIO()->get_srate()); } else printf("MIDI: Can't find BypassInfo struct for p/c [%d/%d]\n",z_port-1,c); } } } } else { // Easy, single channel patch curpatch = patch; echochan = patch->channel; // Bypass settings if (patch->bypasscc != 0) { int c = (curpatch->bypasschannel == -1 ? echochan : curpatch->bypasschannel); BypassInfo *b = getBP(echoport-1,c); if (b != 0) { b->active = 0; // Only bypass when we switch away from another patch b->bypasscc = patch->bypasscc; b->bypasslen1 = (nframes_t) (patch->bypasstime1*app->getAUDIO()->get_srate()); b->bypasslen2 = (nframes_t) (patch->bypasstime2*app->getAUDIO()->get_srate()); } else printf("MIDI: Can't find BypassInfo struct for p/c [%d/%d]\n",echoport-1,c); } } } if (outportschanged) { // If ports changed // Enable/Disable FluidSynth engine FluidSynthEnableEvent *fsevt = (FluidSynthEnableEvent *) Event::GetEventByType(T_EV_FluidSynthEnable); fsevt->enable = usefluid; app->getEMG()->BroadcastEventNow(fsevt, this); } } void MidiIO::ReceiveEvent(Event *ev, EventProducer */*from*/) { // Handle special events for MIDI switch (ev->GetType()) { case T_EV_SetMidiTuning : { SetMidiTuningEvent *tev = (SetMidiTuningEvent *) ev; // OK! if (CRITTERS) printf("MIDI: Received SetMidiTuning " "(new tuning: %d)\n", tev->tuning); SetBenderTune(tev->tuning); } return; #ifdef FWEELIN_EXPERIMENTAL_MIDI_ECHO case T_EV_SetMidiEchoPort : { SetMidiEchoPortEvent *pev = (SetMidiEchoPortEvent *) ev; // OK! if (CRITTERS) printf("MIDI: Received SetMidiEchoPort " "(port #: %d)\n", pev->echoport); if (pev->echoport >= 0 && pev->echoport <= numouts) echoport = pev->echoport; else printf("MIDI: Invalid port #%d (valid range 0-%d)\n", pev->echoport,numouts); } return; case T_EV_SetMidiEchoChannel : { SetMidiEchoChannelEvent *cev = (SetMidiEchoChannelEvent *) ev; // OK! if (CRITTERS) printf("MIDI: Received SetMidiEchoChannel " "(channel #: %d)\n", cev->echochannel); echochan = cev->echochannel; } return; #endif // FWEELIN_EXPERIMENTAL_MIDI_ECHO default: break; } // Unhandled event?-- echo back to MIDI outs EchoEvent(ev); } int MidiIO::EchoEventToPortChannel (Event *ev, int port, int channel, int bypasschannel) { FloConfig *fs = app->getCFG(); static int midi_clock_count = 0; // DEBUG // printf("ECHO EVENT -> Port: %d Channel: %d\n",port,channel); int ret = -1; switch (ev->GetType()) { case T_EV_Input_MIDIClock : { // MIDIClockInputEvent *clkevt = (MIDIClockInputEvent *) ev; OutputClock(ret = port); midi_clock_count++; if (midi_clock_count >= MIDI_CLOCK_FREQUENCY) { midi_clock_count = 0; if (CRITTERS) printf("MIDI: Quarter Note Clock\n"); } } break; case T_EV_Input_MIDIStartStop : { MIDIStartStopInputEvent *ssevt = (MIDIStartStopInputEvent *) ev; if (ssevt->start) { midi_clock_count = 0; OutputSPP(ret = port); // Output song position pointer first OutputStart(port); // Then start message } else OutputStop(ret = port); } break; case T_EV_Input_MIDIController : { MIDIControllerInputEvent *mcev = (MIDIControllerInputEvent *) ev; int p = (port == -1 ? mcev->outport-1 : port), c = (channel == -1 ? mcev->channel : channel), bc = (bypasschannel == -1 ? c : bypasschannel); ret = p; OutputController(p,c, mcev->ctrl, mcev->val); if (mcev->ctrl == MIDI_CC_SUSTAIN) { BypassInfo *b = getBP(p,bc); if (b != 0) { // printf ("sustain: %d\n",mcev->val); b->sp = mcev->val; if (b->sp == 0 && b->numheld == 0) b->releasecnt = app->getRP()->GetSampleCnt(); // Register release time of notes as when sustain pedal is released } else printf("MIDI: Can't find BypassInfo struct for p/c [%d/%d]\n",p,c); } } break; case T_EV_Input_MIDIProgramChange : { MIDIProgramChangeInputEvent *mpev = (MIDIProgramChangeInputEvent *) ev; OutputProgramChange(ret = (port == -1 ? mpev->outport-1 : port), (channel == -1 ? mpev->channel : channel), mpev->val); } break; case T_EV_Input_MIDIChannelPressure : { MIDIChannelPressureInputEvent *mpev = (MIDIChannelPressureInputEvent *) ev; OutputChannelPressure(ret = (port == -1 ? mpev->outport-1 : port), (channel == -1 ? mpev->channel : channel), mpev->val); } break; case T_EV_Input_MIDIPitchBend : { MIDIPitchBendInputEvent *mpev = (MIDIPitchBendInputEvent *) ev; OutputPitchBend(ret = (port == -1 ? mpev->outport-1 : port), (channel == -1 ? mpev->channel : channel), mpev->val); } break; case T_EV_Input_MIDIKey : { MIDIKeyInputEvent *mkev = (MIDIKeyInputEvent *) ev; int p = (port == -1 ? mkev->outport-1 : port), c = (channel == -1 ? mkev->channel : channel), bc = (bypasschannel == -1 ? c : bypasschannel); ret = p; OutputNote(p,c, mkev->down, mkev->notenum + fs->transpose, mkev->vel); BypassInfo *b = getBP(p,bc); if (b != 0) { // Keep track of # of keys held down- assume no duplicates or repeated note offs if (mkev->down) { b->notepresscnt = app->getRP()->GetSampleCnt(); b->numheld++; } else { b->numheld--; if (b->numheld <= 0) { b->numheld = 0; if (b->sp == 0) // Only register release time if sustain pedal is released b->releasecnt = app->getRP()->GetSampleCnt(); } } // printf ("held: %d\n",b->numheld); } else printf("MIDI: Can't find BypassInfo struct for p/c [%d/%d]\n",p,c); #ifdef FWEELIN_EXPERIMENTAL_SOFTSYNTHS_KLUDGE // For poorly behaved softsynths, double up on Note Offs if (!mkev->down) OutputNote(ret = (port == -1 ? mkev->outport-1 : port), (channel == -1 ? mkev->channel : channel), mkev->down, mkev->notenum + fs->transpose, mkev->vel); #endif // FWEELIN_EXPERIMENTAL_SOFTSYNTHS_KLUDGE } break; default: break; } return ret; }; void MidiIO::EchoEvent (Event *ev) { // Handle MIDI event echos.. if (ev->GetType() == T_EV_Input_MIDIClock || ev->GetType() == T_EV_Input_MIDIStartStop) { // MIDI sync message- send out to all ports set to transmit MIDI sync int *xmitports = app->getCFG()->GetMIDISyncOuts(), numxmitports = app->getCFG()->GetNumMIDISyncOuts(); for (int i = 0; i < numxmitports; i++) { OutputStartOnPort(); int port = EchoEventToPortChannel(ev,xmitports[i],-1,-1); OutputEndOnPort(port); } } else if (!ev->echo) { // This event is generated from the configuration explicitly- not // an automatic echo of an unhandled MIDI event-- // So don't send it through our current patch settings. // Send to the exact port and channel specified OutputStartOnPort(); int port = EchoEventToPortChannel(ev,-1,-1,-1); OutputEndOnPort(port); } else { // Echo of unused MIDI event- use patch logic // Handle special note off case- ensure note off sent to right place(s) PatchItem *ev_patch = 0; int ev_port = 0; if (ev->GetType() == T_EV_Input_MIDIKey && !((MIDIKeyInputEvent *) ev)->down && note_patch[((MIDIKeyInputEvent *) ev)->notenum] != 0) { // Use patch which was used when note was pressed ev_patch = note_patch[((MIDIKeyInputEvent *) ev)->notenum]; ev_port = note_def_port[((MIDIKeyInputEvent *) ev)->notenum]; } else { // Use current patch for all other events ev_patch = curpatch; ev_port = echoport; } // DEBUG // printf("MIDI: Echo port: %d Patch: %p\n",ev_port,ev_patch); if (ev_patch != 0 && ev_patch->IsCombi()) { // Combi patch- keyboard split into zones, possible multichannel output int curport = -1; for (int i = 0; i < ev_patch->numzones; i++) { CombiZone *z = ev_patch->GetZone(i); int notenum = -1; MIDIKeyInputEvent *note = 0; if (ev->GetType() == T_EV_Input_MIDIKey) { note = (MIDIKeyInputEvent *) ev; notenum = note->notenum; } if (notenum == -1 || (notenum >= z->kr_lo && notenum <= z->kr_hi)) { int z_port = (z->port_r ? z->port : echoport); if (curport == -1 || z_port != curport) { // Starting with a new port if (curport > 0 && curport <= numouts) OutputEndOnPort(curport-1); if (z_port > 0 && z_port <= numouts) OutputStartOnPort(); curport = z_port; } if (curport > 0 && curport <= numouts) EchoEventToPortChannel(ev,curport-1,z->channel,z->bypasschannel); else if (curport == 0) { #if USE_FLUIDSYNTH app->getFLUIDP()->ReceiveMIDIEvent(ev); #endif } } } } else { if (ev_port > 0 && ev_port <= numouts) { // Single channel output- easy case OutputStartOnPort(); EchoEventToPortChannel(ev,ev_port-1, (echochan != -1 && ev_patch != 0 ? ev_patch->channel : echochan),ev_patch->bypasschannel); OutputEndOnPort(ev_port-1); } else if (ev_port == 0) { #if USE_FLUIDSYNTH app->getFLUIDP()->ReceiveMIDIEvent(ev); #endif } } } }; void MidiIO::SendBankProgramChangeToPortChannel (int bank, int program, int port, int channel) { if (bank != -1) { OutputController(port,channel,MIDI_BANKCHANGE_MSB,bank / 128); OutputController(port,channel,MIDI_BANKCHANGE_MSB,bank % 128); } if (program != -1) OutputProgramChange(port,channel,program); }; void MidiIO::SendBankProgramChange (PatchItem *patch) { printf("MIDI: Program Change\n"); if (patch != 0) { if (patch->IsCombi()) { // Combi, send individual zone bank/patch changes for (int i = 0; i < patch->numzones; i++) { CombiZone *z = patch->GetZone(i); int z_port = (z->port_r ? z->port : echoport); if (z_port > 0 && z_port <= numouts) SendBankProgramChangeToPortChannel(z->bank, z->prog, z_port-1, z->channel); } } else { // Single patch, send bank/patch change if (echoport > 0 && echoport <= numouts) SendBankProgramChangeToPortChannel(patch->bank, patch->prog, echoport-1, patch->channel); } } }; BypassInfo *MidiIO::getBP(int port, int channel) { // printf("MIDI: getBP: %d/%d\n",port,channel); if (port >= 0 && port < app->getCFG()->GetNumMIDIOuts() && channel >= 0 && channel < MAX_MIDI_CHANNELS) return &bp[port*MAX_MIDI_CHANNELS + channel]; else return 0; } void MidiIO::CheckBypass() { // Save scanning through bypass info array by only checking periodically (since bypassing unused channels isn't *that* time critical) nframes_t now = app->getRP()->GetSampleCnt(); if (now - lastchecktime > checkfreq) { // printf("CHECK!\n"); // Run through all ports/channels and test time BypassInfo *b = bp; for (int p = 0; p < app->getCFG()->GetNumMIDIOuts(); p++) { for (int c = 0; c < MAX_MIDI_CHANNELS; c++, b++) { if (b->active && b->bypasscc != 0 && !b->bypassed) { // Time since last note press is greater than sustain time?? Then bypass if ((b->bypasslen1 > 0 && now - b->notepresscnt >= b->bypasslen1) || // Time after last note release is greater than release time?? Then bypass (b->bypasslen2 > 0 && b->sp == 0 && b->numheld == 0 && now - b->releasecnt >= b->bypasslen2)) { // Bypass port/channel /* printf("dnotepress: %d dnoterelease: %d\n",now - b->notepresscnt, now - b->releasecnt); printf("len1: %d len2: %d\n",b->bypasslen1,b->bypasslen2); printf("bypass p/c: %d/%d\n",p,c); */ b->bypassed = 1; OutputController(p,c, b->bypasscc, 127); } } } } lastchecktime = now; } }; void MidiIO::CheckUnbypass() { // Look at current patch, make sure all used channels are unbypassed if (curpatch != 0) { if (curpatch->IsCombi()) { // Bypass settings for (int i = 0; i < curpatch->numzones; i++) { CombiZone *z = curpatch->GetZone(i); if (z->bypasscc != 0) { int z_port = (z->port_r ? z->port : echoport), c = (z->bypasschannel == -1 ? z->channel : z->bypasschannel); BypassInfo *b = getBP(z_port-1,c); if (b != 0) { if (b->bypassed) { // Unbypass // printf("unbypass p/c: %d/%d\n",echoport-1,echochan); b->bypassed = 0; OutputController(z_port-1,c, b->bypasscc, 0); } } else printf("MIDI: Can't find BypassInfo struct for p/c [%d/%d]\n",z_port-1,c); } } } else { // Bypass settings if (curpatch->bypasscc != 0) { int p = echoport-1, bc = (curpatch->bypasschannel == -1 ? echochan : curpatch->bypasschannel); BypassInfo *b = getBP(p,bc); if (b != 0) { if (b->bypassed) { // Unbypass // printf("unbypass p/c: %d/%d\n",echoport-1,echochan); b->bypassed = 0; OutputController(p,bc, b->bypasscc, 0); } } else printf("MIDI: Can't find BypassInfo struct for p/c [%d/%d]\n",echoport-1,echochan); } } } }; freewheeling-0.6.6/src/fweelin_midiio.h000066400000000000000000000173011370736313100201200ustar00rootroot00000000000000#ifndef __FWEELIN_MIDIIO_H #define __FWEELIN_MIDIIO_H /* Copyright 2004-2011 Jan Pekau This file is part of Freewheeling. Freewheeling is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. Freewheeling 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 Freewheeling. If not, see . */ #ifdef __MACOSX__ #include // Small MIDI output buffer- must be large enough to hold any one MIDI message #define OBUF_LEN 128 #else #include #endif #include "fweelin_event.h" #define MIDI_CLOCK_FREQUENCY 24 // 24 MIDI clock messages per quarter note (beat) MIDI standard class Fweelin; class PatchItem; class BypassInfo { public: BypassInfo () : notepresscnt(0), releasecnt(0), bypasslen1(0), bypasslen2(0), numheld(0), sp(0), active(0), bypassed(1), bypasscc(0) {}; nframes_t notepresscnt, // Sample count when this channel last had a note pressed releasecnt, // Sample count when all notes were last released on this channel bypasslen1, // Number of audio samples (time) of channel inactivity with notes sustained before this channel is bypassed bypasslen2; // Number of audio samples (time) of channel inactivity with notes released before this channel is bypassed int numheld; // Number of notes held down on this port/channel char sp, // Sustain pedal is down for this port/channel active, // Auto-Bypassing is enabled for this port/channel? bypassed, // Is this channel bypassed? bypasscc; // MIDI CC to send for bypass }; class MidiIO : public EventProducer, public EventListener { friend class Fweelin; public: MidiIO (Fweelin *app); virtual ~MidiIO (); void ReceiveEvent(Event *ev, EventProducer */*from*/); int activate (); void close (); void SetBenderTune(int tuning) { bendertune = tuning; }; int GetBenderTune() { return bendertune; }; void ResetBenderTune() { bendertune = 0; }; // Sets up MIDI (echo and auto-bypass). Echo is set to one or more ports and channels based on: // a default MIDI output port (def_port) // and the given patch. // // Regular patches use the default MIDI output port and one channel, given // within the patch. // // Combi patches split the keyboard into multiple zones. // Each zone can output to any channel, and can optionally override and send // to a different MIDI output port altogether. This allows one MIDI // controller to control many instruments, even on different softsynths, // at the same time. // Zones can overlap, so that one key sends to multiple channels/ports void SetMIDIForPatch (int def_port, PatchItem *patch); // Send bank and program change messages where appropriate for the given // patch void SendBankProgramChange (PatchItem *patch); #ifndef __MACOSX__ char IsActive () { return midithreadgo; }; #else // Switch MIDI inputs (which system MIDI input source feeds Fweelin?) void SetMIDIInput (int idx); #endif // MIDI Sync inline int GetMIDISyncTransmit() { return midisyncxmit; }; inline void SetMIDISyncTransmit(int midisyncxmit) { this->midisyncxmit = midisyncxmit; }; // Value to offset bender amounts by-- used to do tuning from // bender int bendertune; // Current bender value (before tuning adjustment) int curbender; // MIDI ECHO // Single channel echo- // Echo MIDI events out which MIDI port? // (0 is off, port #s ascending from 1 reference out_ports) int echoport; // Echo out which MIDI channel? // (-1 echoes without changing channel information) int echochan; PatchItem *curpatch; // Current patch- gives which channel(s) // to map to // Number of MIDI in/out ports int numins, numouts; protected: // Core app Fweelin *app; // Open MIDI engine with num_in writeable ports and num_out readable ports. // Nonzero is returned on error char open_midi (int num_in, int num_out); // Listen/unlisten to events (used in startup & shutdown) void listen_events (); void unlisten_events (); // Methods that send one MIDI message to one system MIDI out void OutputController (int port, int chan, int ctrl, int val); void OutputProgramChange (int port, int chan, int val); void OutputChannelPressure (int port, int chan, int val); void OutputPitchBend (int port, int chan, int val); void OutputNote (int port, int chan, char down, int notenum, int vel); // MIDI Sync messages void OutputClock (int port); void OutputSPP (int port); void OutputStart (int port); void OutputStop (int port); // Start/End pass messages void OutputStartOnPort (); // First message for this port in this pass void OutputEndOnPort (int /*port*/); // Last message for this port in this pass // Echo MIDI event to a single port and channel, and update bypass settings for the given channel // Return the port echoed to int EchoEventToPortChannel (Event *ev, int port, int channel, int bypasschannel); // Echo MIDI event back to MIDI outs, according to current patch settings void EchoEvent (Event *ev); // Receive incoming MIDI events from the system and broadcast FreeWheeling // MIDI events internally void ReceiveNoteOffEvent (int channel, int notenum, int vel); void ReceiveNoteOnEvent (int channel, int notenum, int vel); void ReceivePitchBendEvent (int channel, int value); void ReceiveChannelPressureEvent (int channel, int value); void ReceiveProgramChangeEvent (int channel, int value); void ReceiveControlChangeEvent (int channel, int ctrl, int value); // Send bank and program change message to port/channel void SendBankProgramChangeToPortChannel (int bank, int program, int port, int channel); void CheckBypass(); // Time to bypass any channels yet? void CheckUnbypass(); // Unbypass channels still bypassed but needing use nframes_t checkfreq, // How often (samples) to check whether to bypass unused channels lastchecktime; // Last time (samples) auto-bypass conditions checked #ifdef __MACOSX__ MIDIClientRef client; MIDIPortRef *in_ports, *out_ports; MIDIEndpointRef *out_sources; MIDIEndpointRef dest; // Deprecated int inputidx; // Index of last selected MIDI input source MIDIPacket *curPacket; MIDIPacketList *packetList; Byte obuf[OBUF_LEN]; // Small MIDI event output buffer void static MidiInputProc (const MIDIPacketList *pktlist, void *refCon, void *connRefCon); #else // Midi event handler thread static void *run_midi_thread (void *ptr); snd_seq_t *seq_handle; int *in_ports, *out_ports; pthread_t midi_thread; char midithreadgo; #endif // For each MIDI note on the scale, what default port and patch was the note // played with? This allows us to send note off(s) to the right place(s), // even when the patch is changed while notes are held // Note: this assumes only 1 keyboard int *note_def_port; PatchItem **note_patch; // Data for automatic toggling of Soft-synth Bypass based on active MIDI channels // One instance for each MIDI channel and port BypassInfo *bp; BypassInfo *getBP (int port, int channel); // MIDI Sync int midisyncxmit; // Nonzero if we should transmit MIDI sync messages }; #endif freewheeling-0.6.6/src/fweelin_osc.cc000066400000000000000000000135061370736313100175730ustar00rootroot00000000000000/* Recovery is a long process-- 1 day at a time */ /* Copyright 2004-2011 Jan Pekau This file is part of Freewheeling. Freewheeling is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. Freewheeling 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 Freewheeling. If not, see . */ #ifndef __MACOSX__ #include #include #include #include #include #include #include #include #include #include #include #include #include "fweelin_core.h" #include "fweelin_osc.h" #include "fweelin_looplibrary.h" OSCClient::OSCClient(Fweelin *app) : app(app), qtractor_addr(0) { printf("OSC: Start.\n"); // Init mutex/conditions pthread_mutex_init(&osc_client_lock,0); app->getEMG()->ListenEvent(this,0,T_EV_TransmitPlayingLoopsToDAW); }; OSCClient::~OSCClient() { printf("OSC: End.\n"); if (qtractor_addr != 0) lo_address_free(qtractor_addr); app->getEMG()->UnlistenEvent(this,0,T_EV_TransmitPlayingLoopsToDAW); pthread_mutex_destroy (&osc_client_lock); } void OSCClient::ReceiveEvent(Event *evt, EventProducer */*from*/) { switch (evt->GetType()) { case T_EV_TransmitPlayingLoopsToDAW : { // OK! if (CRITTERS) printf("OSC: Received TransmitPlayingLoopsToDAWEvent\n"); SendPlayingLoops(); } break; default: break; } } void OSCClient::SendPlayingLoops() { pthread_mutex_lock(&osc_client_lock); if (!open_qtractor_connection()) { // Get long count Pulse *p = 0; int lc = app->getLOOPMGR()->GetLongCountForAllPlayingLoops(p); nframes_t max_len = 0; // Set QTractor tempo based on pulse if (p != 0) { nframes_t bar_len; int sync_speed = (app->GetSyncSpeed() > 0 ? app->GetSyncSpeed() : 1), beats_per_bar = 4; if (!app->GetSyncType()) // Bar-sync, one pulse represents several bars bar_len = p->GetLength()/sync_speed; else { // Beat-sync, one pulse represents one bar of several beats bar_len = p->GetLength(); beats_per_bar = sync_speed; } // frames/sec * beats/bar / (frames/bar) == beats / sec float tempo = 60. * (float) app->getAUDIO()->get_srate() * beats_per_bar / bar_len; printf("OSC: Send tempo: %f, %d beats per bar - from pulse & sync settings\n",tempo,beats_per_bar); if (lo_send(qtractor_addr, "/SetGlobalTempo", "fi", tempo, beats_per_bar) == -1) { printf("OSC: Error %d: %s\n", lo_address_errno(qtractor_addr), lo_address_errstr(qtractor_addr)); } } // Scan all loops for playing loops for (int i = 0; i < app->getCFG()->GetNumTriggers(); i++) { if (app->getLOOPMGR()->GetStatus(i) == T_LS_Playing) { Loop *l = app->getTMAP()->GetMap(i); if (l != 0 && l->GetSaveStatus() == SAVE_DONE) { // Saved loop. Get filename const std::string s = LibraryHelper::GetStubnameFromLoop(app,l); LibraryFileInfo loopfile = LibraryHelper::GetLoopFilenameFromStub(app,s.c_str()); if (loopfile.exists) { char buf[PATH_MAX + 1]; char *res = realpath(loopfile.name.c_str(), buf); if (res != 0) { // Do not send overlapping regions- this seems to cause clicks in QTractor. // Region ends look like fadeout then fadein (currently). nframes_t cflen = app->getAUDIO()->getbufsz() * 2, len = app->getLOOPMGR()->GetRoundedLength(i); // + cflen; float gain = l->vol; printf("OSC: Transfer loop: %s to Qtractor (nbeats: %d, lc: %d, cflen: %d, len: %d, gain: %0.2f)\n", buf,(int) l->nbeats,lc,cflen,len,gain); // Fill pattern with reps int nbeats = (l->pulse != 0 && l->nbeats > 0 ? l->nbeats : lc); // Only 1 rep if there is no pulse nframes_t curstart = 0; for (int reps = 0; reps < lc; reps += nbeats, curstart += app->getLOOPMGR()->GetRoundedLength(i)) { printf("OSC: Send loop @ %d\n",(int) curstart); if (lo_send(qtractor_addr, "/AddAudioClipOnUniqueTrack", "iiiifs", (int) curstart, 0, len, cflen, gain, buf) == -1) { printf("OSC: Error %d: %s\n", lo_address_errno(qtractor_addr), lo_address_errstr(qtractor_addr)); } if (curstart + len > max_len) max_len = curstart + len; // Length of pattern in frames } } else printf("OSC: Can't get path for loop: %s\n",loopfile.name.c_str()); } else printf("OSC: Can't find loop: %s\n",s.c_str()); } } } // Update loop point if (lo_send(qtractor_addr, "/AdvanceLoopRange", "ii", 0, max_len) == -1) { printf("OSC: Error %d: %s\n", lo_address_errno(qtractor_addr), lo_address_errstr(qtractor_addr)); } } else { printf("OSC: Couldn't open an OSC connection to QTractor on port %d\n",QTRACTOR_OSC_PORT); } pthread_mutex_unlock(&osc_client_lock); } // Open or refresh connection to qtractor char OSCClient::open_qtractor_connection() { if (qtractor_addr != 0) lo_address_free(qtractor_addr); char portbuf[256]; snprintf(portbuf,255,"%d",QTRACTOR_OSC_PORT); qtractor_addr = lo_address_new(NULL, portbuf); return (qtractor_addr == 0); } #endif freewheeling-0.6.6/src/fweelin_osc.h000066400000000000000000000025751370736313100174410ustar00rootroot00000000000000#ifndef __FWEELIN_OSC_H #define __FWEELIN_OSC_H /* Copyright 2004-2011 Jan Pekau This file is part of Freewheeling. Freewheeling is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. Freewheeling 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 Freewheeling. If not, see . */ #ifndef __MACOSX__ #include class Fweelin; #define QTRACTOR_OSC_PORT 5000 class OSCClient : public EventListener { public: OSCClient (Fweelin *app); virtual ~OSCClient (); void ReceiveEvent(Event *ev, EventProducer */*from*/); protected: // Core app Fweelin *app; // Opens a connection to the Qtractor DAW, for transmitting // loops. // // Returns zero on success. char open_qtractor_connection (); // Send all playing loops to a DAW via OSC void SendPlayingLoops(); // Qtractor interface lo_address qtractor_addr; // pthread_mutex_t osc_client_lock; }; #endif #endif freewheeling-0.6.6/src/fweelin_paramset.cc000066400000000000000000000144351370736313100206250ustar00rootroot00000000000000/* Copyright 2004-2011 Jan Pekau This file is part of Freewheeling. Freewheeling is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. Freewheeling 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 Freewheeling. If not, see . */ #include #include #include #include #include #include #include #include #include #include #include "fweelin_core.h" #include "fweelin_paramset.h" // Link system variables for each active parameter to the actual parameter // values, based on the current bank and parameter page. #if 0 void FloDisplayParamSet::LinkActiveParams() { for (int i = 0; i < numactiveparams; i++) { activeparam[i]->type = T_float; ParamSetBank *b = &banks[curbank]; if (b->firstparamidx + i < b->numparams) activeparam[i]->value = (char *) &(b->params[b->firstparamidx].value); else activeparam[i]->value = (char *) &invalidparam; } }; #endif void FloDisplayParamSet::ReceiveEvent(Event *ev, EventProducer */*from*/) { switch (ev->GetType()) { case T_EV_ParamSetGetAbsoluteParamIdx : { ParamSetGetAbsoluteParamIdxEvent *psev = (ParamSetGetAbsoluteParamIdxEvent *) ev; if (psev->interfaceid == iid && psev->displayid == id) { // Message is for this param set display if (psev->absidx == 0 || psev->absidx->IsSystemVariable()) printf(" ParamSetGetAbsoluteParamIdxEvent: The variable provided for the 'absidx' parameter is missing or invalid\n"); else { if (psev->absidx->GetType() != T_int) printf("PARAMSET: ParamSetGetAbsoluteParamIdxEvent: 'absidx' parameter requires a variable of type int."); else { ParamSetBank *b = &banks[curbank]; int idx = b->firstparamidx + psev->paramidx; if (idx < 0) idx = 0; else if (idx >= b->numparams) idx = b->numparams-1; *psev->absidx = idx; if (CRITTERS) printf("PARAMSET: Received ParamSetGetAbsoluteParamIdx (interfaceid: %d displayid: %d) Relative index: %d Returned absolute index: %d\n", psev->interfaceid,psev->displayid,psev->paramidx,idx); } } } } break; case T_EV_ParamSetSetParam : { ParamSetSetParamEvent *psev = (ParamSetSetParamEvent *) ev; if (psev->interfaceid == iid && psev->displayid == id) { // Message is for this param set display ParamSetBank *b = &banks[curbank]; int idx = b->firstparamidx + psev->paramidx; if (idx >= 0 && idx < b->numparams) b->params[idx].value = psev->value; if (CRITTERS) { printf("PARAMSET: Received ParamSetSetParam (interfaceid: %d displayid: %d) Relative index: %d Absolute index: %d Value: %f", psev->interfaceid,psev->displayid,psev->paramidx,idx,psev->value); printf("\n"); } } } break; case T_EV_ParamSetGetParam : { ParamSetGetParamEvent *psev = (ParamSetGetParamEvent *) ev; if (psev->interfaceid == iid && psev->displayid == id) { // Message is for this param set display if (psev->var == 0 || psev->var->IsSystemVariable()) printf(" ParamSetGetParamEvent: Invalid variable!\n"); else { if (psev->var->GetType() != T_float) printf("PARAMSET: ParamSetGetParamEvent: 'var' must be of type float."); else { ParamSetBank *b = &banks[curbank]; int idx = b->firstparamidx + psev->paramidx; if (idx >= 0 && idx < b->numparams) *psev->var = b->params[idx].value; else *psev->var = (float) 0.; if (CRITTERS) { printf("PARAMSET: Received ParamSetGetParam (interfaceid: %d displayid: %d) Relative index: %d Absolute index: %d Val: ", psev->interfaceid,psev->displayid,psev->paramidx,idx); psev->var->Print(); printf("\n"); } } } } } break; case T_EV_VideoShowParamSetBank : { VideoShowParamSetBankEvent *psev = (VideoShowParamSetBankEvent *) ev; if (psev->interfaceid == iid && psev->displayid == id) { // Message is for this param set display // Adjust bank int newbank = curbank + psev->bank; if (newbank < 0) newbank = 0; if (newbank >= numbanks) newbank = numbanks-1; curbank = newbank; // LinkActiveParams(); if (CRITTERS) printf("PARAMSET: Received VideoShowParamSetBank(interfaceid: %d displayid: %d bank: %d) - Bank # is now %d\n", psev->interfaceid,psev->displayid,psev->bank,curbank); } } break; case T_EV_VideoShowParamSetPage : { VideoShowParamSetPageEvent *psev = (VideoShowParamSetPageEvent *) ev; if (psev->interfaceid == iid && psev->displayid == id) { // Message is for this param set display // Adjust page in the bank int newfirstidx = banks[curbank].firstparamidx + numactiveparams * psev->page; if (newfirstidx < 0) newfirstidx = 0; if (newfirstidx >= banks[curbank].numparams) newfirstidx = banks[curbank].firstparamidx; banks[curbank].firstparamidx = newfirstidx; // LinkActiveParams(); if (CRITTERS) printf("PARAMSET: Received VideoShowParamSetPage(interfaceid: %d displayid: %d page: %d) - First parameter index is now %d\n", psev->interfaceid,psev->displayid,psev->page,newfirstidx); } break; } default: break; } } freewheeling-0.6.6/src/fweelin_paramset.h000066400000000000000000000114511370736313100204620ustar00rootroot00000000000000#ifndef __FWEELIN_PARAMSET_H #define __FWEELIN_PARAMSET_H /* Copyright 2004-2011 Jan Pekau This file is part of Freewheeling. Freewheeling is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. Freewheeling 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 Freewheeling. If not, see . */ #include "fweelin_event.h" #include "fweelin_config.h" class ParamSetParam { public: ParamSetParam(char *name = 0, float value = 0) : name(0), value(value) { SetName(name); }; void SetName(char *name) { if (this->name != 0) delete[] this->name; if (name != 0) { printf("(param name: %s) ",name); this->name = new char[strlen(name)+1]; strcpy(this->name,name); } } char *name; // Name of parameter float value; // Value of parameter }; class ParamSetBank { public: ParamSetBank() : name(0), firstparamidx(0), maxvalue(1.0), params(0) {}; ~ParamSetBank() { if (params != 0) delete[] params; }; void Setup(char *name, int numparams, float maxvalue) { this->numparams = numparams; this->maxvalue = maxvalue; SetName(name); params = new ParamSetParam[numparams]; printf("(bank %s with %d params) ",name,numparams); }; void SetName(char *name) { if (this->name != 0) delete[] this->name; if (name != 0) { this->name = new char[strlen(name)+1]; strcpy(this->name,name); } } char *name; // Of bank int numparams, // Number of parameters in bank firstparamidx; // Index of first parameter currently shown float maxvalue; // Maximum value of any parameter in this bank // (used for scaling the visual) ParamSetParam *params; // Array of parameters }; class FloDisplayParamSet : public FloDisplay, public EventListener, public EventProducer { public: FloDisplayParamSet (Fweelin *app, char *name, int iid, int numactiveparams, int numbanks, int sx, int sy) : FloDisplay(iid), app(app), name(name), numactiveparams(numactiveparams), invalidparam(0.), sx(sx), sy(sy), numbanks(numbanks), curbank(0) { this->name = new char[strlen(name)+1]; strcpy(this->name,name); banks = new ParamSetBank[numbanks]; activeparam = new UserVariable *[numactiveparams]; // SetupSystemVariables(); }; ~FloDisplayParamSet() { app->getEMG()->UnlistenEvent(this,0,T_EV_VideoShowParamSetBank); app->getEMG()->UnlistenEvent(this,0,T_EV_VideoShowParamSetPage); app->getEMG()->UnlistenEvent(this,0,T_EV_ParamSetGetAbsoluteParamIdx); app->getEMG()->UnlistenEvent(this,0,T_EV_ParamSetSetParam); app->getEMG()->UnlistenEvent(this,0,T_EV_ParamSetGetParam); delete[] name; delete[] banks; delete[] activeparam; }; #if 0 // Link system variables for each active parameter to the actual parameter // values, based on the current bank and parameter page. void LinkActiveParams(); void SetupSystemVariables() { int slen = strlen(name) + 255; char tmp[slen+1]; for (int i = 0; i < numactiveparams; i++) { snprintf(tmp,slen,"SYSTEM_paramset_%s_activeparam%d_value",name,i); activeparam[i] = app->getCFG()->AddEmptyVariable(tmp); printf("CONFIG: Add parameter set global variable: %s\n",tmp); } LinkActiveParams(); }; #endif void ListenEvents() { app->getEMG()->ListenEvent(this,0,T_EV_VideoShowParamSetBank); app->getEMG()->ListenEvent(this,0,T_EV_VideoShowParamSetPage); app->getEMG()->ListenEvent(this,0,T_EV_ParamSetGetAbsoluteParamIdx); app->getEMG()->ListenEvent(this,0,T_EV_ParamSetGetParam); app->getEMG()->ListenEvent(this,0,T_EV_ParamSetSetParam); }; virtual FloDisplayType GetFloDisplayType() { return FD_ParamSet; }; virtual void Draw(SDL_Surface *screen); virtual void ReceiveEvent(Event *ev, EventProducer */*from*/); Fweelin *app; char *name; // Of parameter set int numactiveparams; // Number of parameters active & displayed at a time UserVariable **activeparam; // Array of pointers to active parameters, // stored as system variables float invalidparam; // Placeholder value for invalid parameter int sx, sy, // Size of parameter set display margin; // Margin for text int numbanks, // Number of banks curbank; // Currently active bank ParamSetBank *banks; // Array of all banks }; #endif freewheeling-0.6.6/src/fweelin_rcu.cc000066400000000000000000000020401370736313100175670ustar00rootroot00000000000000/* Does power come from fancy toys or does power come from the integrity of our walk? */ /* Copyright 2004-2011 Jan Pekau This file is part of Freewheeling. Freewheeling is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. Freewheeling 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 Freewheeling. If not, see . */ #include #include #include #include #include #include #include #include #include #include #include "fweelin_rcu.h" freewheeling-0.6.6/src/fweelin_rcu.h000066400000000000000000000144411370736313100174410ustar00rootroot00000000000000#ifndef __FWEELIN_RCU_H #define __FWEELIN_RCU_H /* Copyright 2004-2011 Jan Pekau This file is part of Freewheeling. Freewheeling is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. Freewheeling 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 Freewheeling. If not, see . */ #include #include "fweelin_datatypes.h" #include "fweelin_mem.h" // Realtime RCU (Read-Copy-Update) implementation // That allows light-weight read access to a data structure without locking. // And more heavy-weight write access // // RT_RCU protects one or more pointers to Preallocated objects. // (More than one pointer can be protected only if they are independent pointers (update can only happen atomically to one pointer)). class RT_RCU : public RTDataStruct_Updater { friend class RT_RWThreads; public: // Create an RCU helper class T RT_RCU () : global_time_count(1), last_update_time(0), num_readers(RT_RWThreads::num_rw_threads) { reader_lock_times = new uint32_t[MAX_RW_THREADS]; for (int i = 0; i < MAX_RW_THREADS; i++) reader_lock_times[i] = 0; // Register this RCU RT_RWThreads::RegisterRTDataStruct(this); }; ~RT_RCU() { // Unregister this RCU RT_RWThreads::UnregisterRTDataStruct(this); delete[] reader_lock_times; }; // Instance methods // Begin read-side critical section - RT and thread-safe inline int ReadLock () { if (num_readers != RT_RWThreads::num_rw_threads) { printf("CORE: ERROR: RT_RCU thread count mismatch.\n"); exit(1); } // Determine which read thread we are pthread_t id = pthread_self(); for (int i = 0; i < num_readers; i++) if (pthread_equal(id,RT_RWThreads::ids[i])) { // Increment global time count atomically, storing old value // (then, no two threads will ever lock with the same time count) uint32_t cnt = __sync_fetch_and_add(&global_time_count,1); // Store global count in reader-specific time count reader_lock_times[i] = cnt; // Must ensure that reader_locktimes[i] has actually been updated before we return, because that's all that protects the // reader from having the data freed from under their feet __sync_synchronize(); return 0; } printf("CORE: RT_RCU ReadLock from unregistered read thread: %lu!\n",id); return -1; }; // End read-side critical section - RT and thread-safe inline int ReadUnlock () { if (num_readers != RT_RWThreads::num_rw_threads) { printf("CORE: ERROR: RT_RCU thread count mismatch.\n"); exit(1); } // Determine which read thread we are pthread_t id = pthread_self(); for (int i = 0; i < num_readers; i++) if (pthread_equal(id,RT_RWThreads::ids[i])) { // Reset state of this reader thread to unlocked reader_lock_times[i] = 0; __sync_synchronize(); return 0; } printf("CORE: RT_RCU ReadUnlock from unregistered read thread: %lu!\n",id); return -1; }; // Update your reference from old_ptr to new_ptr. // *old_ptr = new_ptr; // Does this atomically, remembering the time when it was done inline void Update (volatile Preallocated **old_ptr, Preallocated *new_ptr) { // Update pointer atomically *old_ptr = new_ptr; // Ensure it has happened in memory by this point __sync_synchronize(); // Increment global time count atomically and store as the last update time // (guarantees that *old_ptr == new_ptr by last_update_time) last_update_time = __sync_fetch_and_add(&global_time_count,1); } // Synchronize() is called by the reclaiming thread. // It waits (using sleep_time microsecond granules), until all read-side critical sections that started BEFORE the last Update() have completed- // This ensures that no readers are holding a pointer to a structure. After this call returns, the old_ptr (before update) may be freed. inline void Synchronize (int sleep_time) { // A warning is issued after waiting for this many microseconds const static int WARNING_WAIT_TIME = 1000000; int wait_time = 0; char recheck; do { recheck = 0; for (int i = 0; !recheck && i < num_readers; i++) if (reader_lock_times[i] != 0 && reader_lock_times[i] < last_update_time) // Pointer was updated during grace period (read-side critical section). Therefore, we must wait til this section unlocks. recheck = 1; if (recheck) { if ((wait_time + sleep_time) % WARNING_WAIT_TIME < wait_time % WARNING_WAIT_TIME) // Warn that we are waiting too long printf("CORE: WARNING: RCU Synchronize() is still waiting (%d secs)...\n",(wait_time + sleep_time) / 1000000); // Wait wait_time += sleep_time; usleep(sleep_time); } } while (recheck); }; private: virtual void UpdateNumRWThreads(int new_num_rw_threads) { printf("CORE: RT_RCU %p: Update reader and writer threads to %d\n",this,new_num_rw_threads); if (new_num_rw_threads <= num_readers) { printf("CORE: ERROR: Can't go from %d to %d threads during initialization.\n",num_readers, new_num_rw_threads); exit(1); } else { // Fixed size structure used, no problem. } }; volatile uint32_t global_time_count, // Every time a lock, or update occurs, this count is incremented. This allows us to easily tell // whether a read-side critical section is underway before we reclaim. last_update_time; // Time when the ptr this RT_RCU protects volatile uint32_t *reader_lock_times; // Every reader thread has a value that says what was the global_time_count when it was locked, or 0 // if that reader thread is unlocked. int num_readers; // Local copy of RT_RWThreads::num_rw_threads }; #endif freewheeling-0.6.6/src/fweelin_sdlio.cc000066400000000000000000000365041370736313100201240ustar00rootroot00000000000000/* With my hands, I weave the bridge's design feeling as the sides combine, reality remade and realigned, I fell thru death, now it's my time. */ /* Copyright 2004-2011 Jan Pekau This file is part of Freewheeling. Freewheeling is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. Freewheeling 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 Freewheeling. If not, see . */ #include #include #include #include #include #include #include #include #include #include #include #include #ifdef __MACOSX__ #include #include #else #include #include #endif #include "fweelin_sdlio.h" #include "fweelin_core.h" // ******** KEYBOARD / MOUSE / JOYSTICK HANDLER static const char *SDL_names[] = { "", "", "", "", "", "", "", "", "backspace", "tab", "", "", "clear", "return", "", "", "", "", "", "pause", "", "", "", "", "", "", "", "escape", "", "", "", "", "space", "exclamation", "dblquote", "numbersign", "dollarsign", "", "ampersand", "backquote", "openparen", "closeparen", "asterisk", "plus", "comma", "minus", "period", "slash", "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "colon", "semicolon", "lessthan", "equal", "greaterthan", "questionmark", "at", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "squarebracketopen", "backslash", "squarebracketclose", "caret", "underscore", "tilde", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "", "", "", "", "delete", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "world0", "world1", "world2", "world3", "world4", "world5", "world6", "world7", "world8", "world9", "world10", "world11", "world12", "world13", "world14", "world15", "world16", "world17", "world18", "world19", "world20", "world21", "world22", "world23", "world24", "world25", "world26", "world27", "world28", "world29", "world30", "world31", "world32", "world33", "world34", "world35", "world36", "world37", "world38", "world39", "world40", "world41", "world42", "world43", "world44", "world45", "world46", "world47", "world48", "world49", "world50", "world51", "world52", "world53", "world54", "world55", "world56", "world57", "world58", "world59", "world60", "world61", "world62", "world63", "world64", "world65", "world66", "world67", "world68", "world69", "world70", "world71", "world72", "world73", "world74", "world75", "world76", "world77", "world78", "world79", "world80", "world81", "world82", "world83", "world84", "world85", "world86", "world87", "world88", "world89", "world90", "world91", "world92", "world93", "world94", "world95", "KP0", "KP1", "KP2", "KP3", "KP4", "KP5", "KP6", "KP7", "KP8", "KP9", "KPperiod", "KPslash", "KPasterisk", "KPminus", "KPplus", "enter", "equals", "up", "down", "right", "left", "insert", "home", "end", "pageup", "pagedown", "f1", "f2", "f3", "f4", "f5", "f6", "f7", "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15", "", "", "", "numlock", "capslock", "scrolllock", "rightshift", "leftshift", "rightctrl", "leftctrl", "rightalt", "leftalt", "rightmeta", "leftmeta", "leftsuper", "rightsuper", "altgr", "compose", "help", "printscreen", "sysreq", "break", "menu", "power", "euro", "undo"}; SDLKey SDLIO::GetSDLKey(char *keyname) { SDLKey ky; for (ky = SDLK_FIRST; ky < SDLK_LAST; ky = (SDLKey)(ky+1)) { /*char *nm = SDL_GetKeyName(ky); printf("\"%s\", \n",(!strcmp(nm,"unknown key") ? "" : nm));*/ /*if (SDL_names[ky][0] != '\0') printf("%03d - %s\n",ky,SDL_names[ky]);*/ if (!strcmp(SDL_names[ky],keyname)) return ky; } return SDLK_UNKNOWN; }; const char *SDLIO::GetSDLName(SDLKey sym) { return SDL_names[sym]; }; int SDLIO::activate() { sdlthreadgo = 1; #if 0 printf("SDLIO: Starting SDL input thread.\n"); const static size_t STACKSIZE = 1024*64; pthread_attr_t attr; pthread_attr_init(&attr); pthread_attr_setstacksize(&attr,STACKSIZE); printf("SDL: Stacksize: %d.\n",STACKSIZE); sdlthreadgo = 1; int ret = pthread_create(&sdl_thread, &attr, run_sdl_thread, this); if (ret != 0) { printf("SDLIO: (SDL input) pthread_create failed, exiting"); return 1; } RT_RWThreads::RegisterReaderOrWriter(sdl_thread); // Setup high priority threads struct sched_param schp; memset(&schp, 0, sizeof(schp)); schp.sched_priority = sched_get_priority_max(SCHED_OTHER); printf("SDLIO: thread priority %d\n",schp.sched_priority); if (pthread_setschedparam(sdl_thread, SCHED_OTHER, &schp) != 0) { printf("SDLIO: Can't set hi priority thread, will use regular!\n"); } #endif return 0; } void SDLIO::close() { sdlthreadgo = 0; // *** SDL IO now running on main thread // pthread_join(sdl_thread,0); printf("SDLIO: end\n"); } void SDLIO::ReceiveEvent(Event *ev, EventProducer */*from*/) { switch (ev->GetType()) { case T_EV_ExitSession : sdlthreadgo = 0; printf("\n** Event: Exit session\n"); break; default: break; } } // *********** Old hardcoded key handler // *********** Still handles a few things directly void SDLIO::handle_key(int keycode, char press) { //printf("SDLIO: %d\n",keycode); static int prevkeycode = 0, prevcnt = 0; if (press) { if (keycode == prevkeycode) prevcnt++; else prevcnt = 0; prevkeycode = keycode; #if 0 if (keycode == 51) { // Backslash freezes & resets limiter if (sets.leftshift || sets.rightshift) { // Reset limiter app->getRP()->ResetLimiter(); } else { // Toggle limiter freeze char limiterfreeze = app->getRP()->GetLimiterFreeze(); limiterfreeze = (limiterfreeze == 0 ? 1 : 0); app->getRP()->SetLimiterFreeze(limiterfreeze); } } #endif if (keycode == 108) { // greyENTER // Produce stdout status report app->getCFG()->status_report = 1; } else if (keycode == 65) { // spacebar sets.spacekey = 1; } else if (keycode == 64) { // left alt sets.leftalt = 1; } else if (keycode == 113) { // right alt sets.rightalt = 1; } else if (keycode == 50) { // left shift sets.leftshift = 1; } else if (keycode == 62) { // right shift sets.rightshift = 1; } else if (keycode == 37) { // left ctrl sets.leftctrl = 1; } else if (keycode == 109) { // right ctrl sets.rightctrl = 1; } else if (keycode == 98) { // up arrow, hold for adjusting individual loop volumes sets.upkey = 1; } else if (keycode == 104) { // down arrow, hold for adjusting individual loop volumes sets.downkey = 1; } else if (keycode == 9) { // escape key- exit! //app->getEMG()->BroadcastEvent(::new ExitSessionEvent(), this); //sdlthreadgo = 0; //printf("end\n"); } else { // This keyrange (F1-F10) is set to select pulses if ((keycode >= 67 && keycode <= 76)) { if (sets.leftshift || sets.rightshift) { // Set subdivide // Old method (F1=1, F2=2, F3=4, F4=8, F5=16..) // app->getLOOPMGR()->SetSubdivide((int) pow(2,keycode-67)); // New method- Fn is translated to subdivide directly // And amplified by repeat presses of Fn int newsub = (prevcnt+1) * (keycode-67+1); app->getLOOPMGR()->SetSubdivide(newsub); } } #if 0 if (keycode == 95) { // Toggle metronome on current pulse (F11) Pulse *a = app->getLOOPMGR()->GetCurPulse(); if (a != 0) a->SwitchMetronome((a->IsMetronomeActive() ? 0 : 1)); } #endif } } else { // Release if (keycode == 64) { // left alt sets.leftalt = 0; } else if (keycode == 113) { // right alt sets.rightalt = 0; } else if (keycode == 65) { // spacebar sets.spacekey = 0; } else if (keycode == 50) { // left shift sets.leftshift = 0; } else if (keycode == 62) { // right shift sets.rightshift = 0; } else if (keycode == 37) { // left ctrl sets.leftctrl = 0; } else if (keycode == 109) { // right ctrl sets.rightctrl = 0; } else if (keycode == 98) { // up arrow sets.upkey = 0; } else if (keycode == 104) { // down arrow sets.downkey = 0; } } } // This is the SDL input event loop void *SDLIO::run_sdl_thread(void *ptr) { SDLIO *inst = static_cast(ptr); SDL_Event event; printf("SDLIO: SDL Input thread start.\n"); #ifdef __MACOSX__ // inst->cocoa.SetupCocoaThread(); #endif // Setup joysticks inst->numjoy = SDL_NumJoysticks(); if (inst->numjoy > 0) inst->joys = new SDL_Joystick *[inst->numjoy]; printf("SDLIO: Detected %d joysticks..\n", inst->numjoy); for (int i = 0; i < inst->numjoy; i++) { printf(" Joystick #%d: %s\n",i+1,SDL_JoystickName(i)); inst->joys[i] = SDL_JoystickOpen(i); } // Listen for pertinent events if (inst->app->getEMG() == 0) { printf("INIT: Error: Event Manager not yet active!\n"); exit(1); } inst->app->getEMG()->ListenEvent(inst,0,T_EV_ExitSession); while (inst->sdlthreadgo) { if (SDL_WaitEvent(&event)) { switch (event.type) { case SDL_JOYBUTTONDOWN : case SDL_JOYBUTTONUP : { JoystickButtonInputEvent *jevt = (JoystickButtonInputEvent *) Event::GetEventByType(T_EV_Input_JoystickButton); jevt->joystick = event.jbutton.which; jevt->button = event.jbutton.button; jevt->down = (event.type == SDL_JOYBUTTONUP ? 0 : 1); inst->app->getEMG()->BroadcastEventNow(jevt, inst); if (inst->app->getCFG()->IsDebugInfo()) printf("JOYSTICK: Joystick #%d, button #%d %s\n", jevt->joystick,jevt->button, (jevt->down ? "pressed" : "released")); } break; case SDL_MOUSEMOTION : { MouseMotionInputEvent *mevt = (MouseMotionInputEvent *) Event::GetEventByType(T_EV_Input_MouseMotion); mevt->x = event.motion.x; mevt->y = event.motion.y; inst->app->getEMG()->BroadcastEventNow(mevt, inst); // No debug info for mouse motion #if 0 if (inst->app->getCFG()->IsDebugInfo()) printf("MOUSE: Motion: (%d,%d)\n", mevt->x, mevt->y); #endif } // printf("x: %d y: %d\n", // event.motion.x,event.motion.y); break; case SDL_MOUSEBUTTONDOWN : case SDL_MOUSEBUTTONUP : { MouseButtonInputEvent *mevt = (MouseButtonInputEvent *) Event::GetEventByType(T_EV_Input_MouseButton); mevt->button = event.button.button; mevt->down = (event.type == SDL_MOUSEBUTTONUP ? 0 : 1); mevt->x = event.button.x; mevt->y = event.button.y; inst->app->getEMG()->BroadcastEventNow(mevt, inst); if (inst->app->getCFG()->IsDebugInfo()) printf("MOUSE: Button #%d %s @ (%d,%d)\n", mevt->button, (mevt->down ? "pressed" : "released"), mevt->x, mevt->y); } //printf("button: %d x: %d y: %d\n", // event.button.button, // event.button.x,event.button.y); break; case SDL_KEYDOWN : { SDLKey sym = event.key.keysym.sym; if (sym >= SDLK_FIRST && sym < SDLK_LAST) { // Mark the key as held down inst->keyheld[sym] = 1; // Now generate an input event.. KeyInputEvent *kevt = (KeyInputEvent *) Event::GetEventByType(T_EV_Input_Key); kevt->down = 1; kevt->keysym = sym; kevt->unicode = event.key.keysym.unicode; inst->app->getEMG()->BroadcastEventNow(kevt, inst); if (inst->app->getCFG()->IsDebugInfo()) printf("KEYBOARD: Key pressed: %d (%s)\n", kevt->keysym, GetSDLName(sym)); inst->handle_key(event.key.keysym.scancode,1); } else { printf("KEYBOARD: Invalid key\n"); } } break; case SDL_KEYUP : { SDLKey sym = event.key.keysym.sym; if (sym >= SDLK_FIRST && sym < SDLK_LAST) { // Mark the key as unheld inst->keyheld[sym] = 0; // Now generate an input event.. KeyInputEvent *kevt = (KeyInputEvent *) Event::GetEventByType(T_EV_Input_Key); kevt->down = 0; kevt->keysym = sym; kevt->unicode = event.key.keysym.unicode; inst->app->getEMG()->BroadcastEventNow(kevt, inst); if (inst->app->getCFG()->IsDebugInfo()) printf("KEYBOARD: Key released: %d (%s)\n", kevt->keysym, GetSDLName(sym)); inst->handle_key(event.key.keysym.scancode,0); break; } else printf("KEYBOARD: Invalid key\n"); } break; } } /*else { printf("SDL Error Waiting for Event!\n"); sdlthreadgo = 0; }*/ // usleep(100); // Give up the processor briefly! } inst->app->getEMG()->UnlistenEvent(inst,0,T_EV_ExitSession); printf("Closing joysticks.\n"); for (int i = 0; i < inst->numjoy; i++) SDL_JoystickClose(inst->joys[i]); #ifdef __MACOSX__ // inst->cocoa.TakedownCocoaThread(); #endif printf("SDLIO: SDL Input thread done.\n"); return 0; } freewheeling-0.6.6/src/fweelin_sdlio.h000066400000000000000000000056311370736313100177630ustar00rootroot00000000000000#ifndef __FWEELIN_SDLIO_H #define __FWEELIN_SDLIO_H /* Copyright 2004-2011 Jan Pekau This file is part of Freewheeling. Freewheeling is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. Freewheeling 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 Freewheeling. If not, see . */ #include #include "fweelin_event.h" #ifdef __MACOSX__ #include "FweelinMac.h" #endif class Fweelin; // Deprecated! class KeySettings { public: KeySettings() : leftshift(0), rightshift(0), leftctrl(0), rightctrl(0), leftalt(0), rightalt(0), upkey(0), downkey(0), spacekey(0) {}; // Function modifier keys char leftshift, rightshift, leftctrl, rightctrl, leftalt, rightalt, upkey, downkey, spacekey; }; class SDLKeyList { public: SDLKeyList (SDLKey k) : k(k), next(0) {}; SDLKey k; SDLKeyList *next; }; // SDL Input Handler class SDLIO : public EventProducer, public EventListener { public: SDLIO (Fweelin *app) : app(app), sdlthreadgo(0) { keyheld = new char[SDLK_LAST]; for (int i = 0; i < SDLK_LAST; i++) keyheld[i] = 0; }; virtual ~SDLIO() { delete[] keyheld; }; int activate (); void close (); char IsActive () { return sdlthreadgo; }; char *GetKeysHeld () { return keyheld; }; KeySettings *getSETS() { return &sets; }; void ReceiveEvent(Event *ev, EventProducer */*from*/); // We use slightly modified keynames for the config system: // Gets the SDL keysym that corresponds to key with a given name static SDLKey GetSDLKey(char *keyname); // And the name corresponding to the keysym.. static const char *GetSDLName(SDLKey sym); inline void EnableUNICODE(int enable) { SDL_EnableUNICODE(enable); }; inline void EnableKeyRepeat(int enable) { if (enable) SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL); else SDL_EnableKeyRepeat(0,0); }; // SDL event handler thread static void *run_sdl_thread (void *ptr); protected: #ifdef __MACOSX__ FweelinMac cocoa; // Cocoa thread setup #endif // Core app Fweelin *app; // Joysticks int numjoy; // Number of joysticks SDL_Joystick **joys; // Control structure for each joystick // Keys currently held down- array for all SDLKeys, nonzero if held char *keyheld; // Deprecated KeySettings sets; void handle_key(int keycode, char press); pthread_t sdl_thread; char sdlthreadgo; }; #endif freewheeling-0.6.6/src/fweelin_videoio.cc000066400000000000000000002030671370736313100204500ustar00rootroot00000000000000/* Art is the beginning. */ /* Copyright 2004-2011 Jan Pekau This file is part of Freewheeling. Freewheeling is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. Freewheeling 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 Freewheeling. If not, see . */ #include #include #include #include #include #include #include #include #include #include #include #ifdef LCD_DISPLAY #include #include #endif #include "fweelin_videoio.h" #include "fweelin_core.h" #include "fweelin_paramset.h" #include "fweelin_logo.h" double mygettime(void) { static struct timeval mytv; gettimeofday(&mytv,NULL); return(mytv.tv_sec+mytv.tv_usec/1000000.0); } int myround(float num) { if (num-(long)num < 0.5) return (int) floor(num); else return (int) ceil(num); } CircularMap::CircularMap(SDL_Surface *in, int map_xs, int map_ys, int in_xs, int in_ys, int rinner, int rsize) : in(in), map_xs(map_xs), map_ys(map_ys), in_xs(in_xs), in_ys(in_ys), rinner(rinner), rsize(rsize), next(0) { // Allocate memory for maps map = new Uint8 *[map_xs * map_ys]; // 4 scan run lengths per scanline scanmap = new int[4 * map_ys]; // Compute constants int map_xc = map_xs/2; int map_yc = map_ys/2; int pitch = in->pitch; int bpp = in->format->BytesPerPixel; Uint8 *in_base = (Uint8 *) in->pixels; // Now generate, interating across output range for (int y = 0; y < map_ys; y++) { int runnum = 0, // Count of consecutive written/notwritten pixels // Positive is written, negative is notwritten pixelscount = 0; for (int x = 0; x < map_xs; x++) { //printf("%d %d\n", x, y); int yofs = y-map_yc, xofs = map_xc-x; float theta = atan2(yofs,xofs), in_x = in_xs*(theta+M_PI)/(2*M_PI); // Now that we know x mapping, based on calculated theta (see theta) // Let's get y mapping float in_y; if (sin(theta) == 0) { // This fixes an annoying horizontal crack in the map in_y = (xofs-rinner)*in_ys/rsize; //printf("xofs: %d yofs: %d inx: %f iny: %f\n",xofs,yofs,in_x,in_y); } else in_y = (yofs/sin(theta)-rinner)*in_ys/rsize; // Are we in range, honey? int idx = y*map_xs + x; if (in_x >= 0 && in_y >= 0 && in_x < in_xs && in_y < in_ys) { /*printf("%d %d\n", x, y); printf(" in[%d,%d]\n",(int)in_x,(int)in_y);*/ // Yup-- write the map map[idx] = in_base + myround(in_y)*pitch + myround(in_x)*bpp; // Generate scan map if (pixelscount <= 0) { // OK start of run // Write number of empty pixels from last run to here scanmap[y*4 + runnum] = -pixelscount; //printf("Y:%d r:%d cnt: %d\n",y,runnum,-pixelscount); runnum++; pixelscount = 0; } pixelscount++; } else { //printf(" none\n"); // Mapping is empty for this location map[idx] = 0; // Generate scan map if (pixelscount > 0) { // OK end of run // Write number of pixels written from beginning of run to here scanmap[y*4 + runnum] = pixelscount; //printf("Y:%d r:%d cnt: %d\n",y,runnum,pixelscount); runnum++; pixelscount = 0; } pixelscount--; } } // Now write the rest of scan map if (pixelscount > 0) { // OK end of run // Write number of pixels written from beginning of run to here scanmap[y*4 + runnum] = pixelscount; //printf("Y:%d r:%d cnt: %d\n",y,runnum,pixelscount); runnum++; } //printf("EOL- r:%d\n",runnum); //usleep(100000); for (; runnum < 4; runnum++) scanmap[y*4 + runnum] = -1; } } CircularMap::~CircularMap() { delete[] scanmap; delete[] map; }; // Map flat scope onto circle // Return nonzero on error char CircularMap::Map(SDL_Surface *out, int dstx, int dsty) { int bpp; int *tmpscan = scanmap; // Get surface format bpp = out->format->BytesPerPixel; if (bpp != in->format->BytesPerPixel) { printf("VIDEO: ERROR: Temporary buffer & video screen not " "matching depth (in: %d out: %d).\n", in->format->BytesPerPixel,bpp); return 1; } // Check for clipping if (dstx < 0 || dsty < 0 || dstx+map_xs >= out->w || dsty+map_ys >= out->h) return 1; // Don't handle clip case-- just don't draw! /* * Lock the surface */ if (SDL_MUSTLOCK(out)) { if (SDL_LockSurface(out) < 0) { return 1; } } int out_pitch = out->pitch; Uint8 **ptr = map, **ptr2, *optr = (Uint8 *) out->pixels + dsty*out_pitch + dstx*bpp, *optr2; Uint8 *op, *ip; int ofs, scanleft; for (int y = 0; y < map_ys; y++, ptr += map_xs, optr += out_pitch, tmpscan += scanleft) { scanleft = 4; ptr2 = ptr; optr2 = optr; // What's the first x location on this scanline we should look at? while ((ofs = *tmpscan) != -1 && scanleft) { tmpscan++; // Starting position on this scanline ptr2 += ofs; optr2 += ofs*bpp; //printf("wy:%d sofs:%d ",y,ofs); // And the number of bytes in the run on this scanline ofs = *(tmpscan++); //printf("len:%d\n",ofs); // Depending on the number of bytes per pixel, handle this scanline // differently-- optimized subroutines follow.. switch (bpp) { case 1: { for (int i = 0; i < ofs; i++, ptr2++, optr2 += bpp) // Copy 1 byte pixels *optr2 = **ptr2; } break; case 2: { for (int i = 0; i < ofs; i++, ptr2++, optr2 += bpp) // Copy 2 byte pixels *((Uint16 *) optr2) = *((Uint16 *) (*ptr2)); } break; case 3: { // 3 byte pixels for (int i = 0; i < ofs; i++, ptr2++, optr2 += bpp) { // Access the map to find offset into input ip = *ptr2; // And output pointer is right there op = optr2; if (SDL_BYTEORDER == SDL_BIG_ENDIAN) { ip += 2; // Copy, reversing bit order for this pixel for (int n = 0; n < bpp; n++) *(op++) = *(ip--); } else { // Copy, regular bit order for this pixel for (int n = 0; n < bpp; n++) *(op++) = *(ip++); } } } break; case 4: { for (int i = 0; i < ofs; i++, ptr2++, optr2 += bpp) // Copy 4 byte pixels *((Uint32 *) optr2) = *((Uint32 *) (*ptr2)); } break; } // Ok, 1 scan run complete, so 2 endpoints less on scanline scanleft -= 2; } } /* * Unlock surface */ if (SDL_MUSTLOCK(out)) { SDL_UnlockSurface(out); } return 0; }; // ******** VIDEO HANDLER int VideoIO::activate() { #ifdef __MACOSX__ // On Mac OS X, prime video in main thread SetVideoMode(0); #endif #if 1 printf("VIDEO: Starting handler..\n"); pthread_mutex_init (&video_thread_lock,0); const static size_t STACKSIZE = 1024*128; pthread_attr_t attr; pthread_attr_init(&attr); pthread_attr_setstacksize(&attr,STACKSIZE); printf("VIDEO: Stacksize: %zd.\n",STACKSIZE); int ret = pthread_create(&video_thread, &attr, run_video_thread, this); if (ret != 0) { printf("VIDEO: (start) pthread_create failed, exiting"); return 1; } RT_RWThreads::RegisterReaderOrWriter(video_thread); // Setup low priority thread #if 0 struct sched_param schp; memset(&schp, 0, sizeof(schp)); schp.sched_priority = sched_get_priority_min(SCHED_OTHER); printf("VIDEO: Low priority thread %d\n",schp.sched_priority); if (pthread_setschedparam(video_thread, SCHED_OTHER, &schp) != 0) printf("VIDEO: Can't set thread priority, will use regular!\n"); #endif // Listen for events if (app->getEMG() == 0) { printf("VIDEO: Error: Event Manager not yet active!\n"); exit(1); } app->getEMG()->ListenEvent(this,0,T_EV_VideoShowSnapshotPage); app->getEMG()->ListenEvent(this,0,T_EV_VideoShowLoop); app->getEMG()->ListenEvent(this,0,T_EV_VideoShowDisplay); app->getEMG()->ListenEvent(this,0,T_EV_VideoShowLayout); app->getEMG()->ListenEvent(this,0,T_EV_VideoSwitchInterface); app->getEMG()->ListenEvent(this,0,T_EV_VideoShowHelp); app->getEMG()->ListenEvent(this,0,T_EV_VideoFullScreen); app->getEMG()->ListenEvent(this,0,T_EV_Input_MouseButton); app->getEMG()->ListenEvent(this,0,T_EV_Input_MouseMotion); #endif return 0; } void VideoIO::close() { app->getEMG()->UnlistenEvent(this,0,T_EV_VideoShowSnapshotPage); app->getEMG()->UnlistenEvent(this,0,T_EV_VideoShowLoop); app->getEMG()->UnlistenEvent(this,0,T_EV_VideoShowDisplay); app->getEMG()->UnlistenEvent(this,0,T_EV_VideoShowLayout); app->getEMG()->UnlistenEvent(this,0,T_EV_VideoSwitchInterface); app->getEMG()->UnlistenEvent(this,0,T_EV_VideoShowHelp); app->getEMG()->UnlistenEvent(this,0,T_EV_VideoFullScreen); app->getEMG()->UnlistenEvent(this,0,T_EV_Input_MouseButton); app->getEMG()->UnlistenEvent(this,0,T_EV_Input_MouseMotion); videothreadgo = 0; pthread_join(video_thread,0); pthread_mutex_destroy (&video_thread_lock); printf("VIDEO: end\n"); } void VideoIO::ReceiveEvent(Event *ev, EventProducer */*from*/) { switch (ev->GetType()) { case T_EV_Input_MouseMotion : { MouseMotionInputEvent *mev = (MouseMotionInputEvent *) ev; // Notify all visible browsers of mouse move FloDisplay *curdisplay = app->getCFG()->GetDisplays(); char skip = 0; while (curdisplay != 0 && !skip) { if ((curdisplay->show || curdisplay->forceshow) && curdisplay->GetFloDisplayType() == FD_Browser) skip = ((Browser *) curdisplay)->MouseMotion(mev); curdisplay = curdisplay->next; } } break; case T_EV_Input_MouseButton : { MouseButtonInputEvent *mev = (MouseButtonInputEvent *) ev; // Notify all visible browsers of button press FloDisplay *curdisplay = app->getCFG()->GetDisplays(); char skip = 0; while (curdisplay != 0 && !skip) { if ((curdisplay->show || curdisplay->forceshow) && curdisplay->GetFloDisplayType() == FD_Browser) skip = ((Browser *) curdisplay)->MouseButton(mev); curdisplay = curdisplay->next; } if (!skip) { // Only continue if a browser hasn't eaten the event // Has the mouse button been pressed inside any of the // on-screen layout elements? FloLayout *cur = app->getCFG()->GetLayouts(); while (cur != 0) { if (cur->show) { int firstid = cur->loopids.lo, curid = firstid, maxid = cur->loopids.hi; // Check each element in this layout FloLayoutElement *curel = cur->elems; while (curel != 0 && curid <= maxid) { if (curel->Inside(mev->x,mev->y)) { // Mouse button inside element- // Issue 'loop clicked' event LoopClickedEvent *lcevt = (LoopClickedEvent *) Event::GetEventByType(T_EV_LoopClicked); lcevt->button = mev->button; lcevt->down = mev->down; lcevt->loopid = firstid + curel->id; lcevt->in = 1; // In=1 means clicked in on-screen layout app->getEMG()->BroadcastEventNow(lcevt, this); if (CRITTERS) printf("MOUSE: Button #%d %s in element: %s\n", mev->button, (mev->down ? "pressed" : "released"), curel->name); } curid++; curel = curel->next; } } cur = cur->next; } } } break; case T_EV_VideoShowSnapshotPage : { VideoShowSnapshotPageEvent *vev = (VideoShowSnapshotPageEvent *) ev; if (CRITTERS) printf("VIDEO: %s snapshot page (interface id %d, display id %d)\n", (vev->page < 0 ? "Previous" : "Next"), vev->interfaceid,vev->displayid); // Find the right display FloDisplay *cur = app->getCFG()->GetDisplayById(vev->interfaceid, vev->displayid); if (cur != 0 && cur->GetFloDisplayType() == FD_Snapshots) { FloDisplaySnapshots *sn = (FloDisplaySnapshots *) cur; if (vev->page < 0) { int newidx = sn->firstidx - sn->numdisp; if (newidx < 0) newidx = 0; sn->firstidx = newidx; } else { int newidx = sn->firstidx + sn->numdisp; if (newidx < app->getCFG()->GetMaxSnapshots()) sn->firstidx = newidx; } } else printf("VIDEO: Specified display is not a snapshot display " "(interface id %d, display id %d)\n", vev->interfaceid,vev->displayid); } break; case T_EV_VideoShowLoop : { VideoShowLoopEvent *vev = (VideoShowLoopEvent *) ev; if (CRITTERS) printf("VIDEO: Show loop (interface %d layout %d): %d>%d\n", vev->interfaceid, vev->layoutid,vev->loopid.lo,vev->loopid.hi); // Error check range if (vev->loopid.lo < 0 || vev->loopid.hi < 0 || vev->loopid.lo >= app->getCFG()->GetNumTriggers() || vev->loopid.hi >= app->getCFG()->GetNumTriggers() || vev->loopid.hi < vev->loopid.lo) { printf("VIDEO: Invalid loopid range for interface %d " "layout %d: %d>%d\n", vev->interfaceid, vev->layoutid,vev->loopid.lo,vev->loopid.hi); } else { // Find the right layout int id = vev->layoutid, iid = vev->interfaceid; FloLayout *cur = app->getCFG()->GetLayouts(); char found = 0; while (cur != 0) { if (iid == cur->iid && id == cur->id) { // Match-- change the range of displayed loops for // this layout cur->loopids = vev->loopid; found = 1; } cur = cur->next; } if (!found) printf("VIDEO: Invalid layoutid %d in interface %d.\n", vev->layoutid,vev->interfaceid); } } break; case T_EV_VideoShowDisplay : { VideoShowDisplayEvent *vev = (VideoShowDisplayEvent *) ev; if (CRITTERS) printf("VIDEO: %s display (interface id %d, display id %d)\n", (vev->show ? "show" : "hide"), vev->interfaceid,vev->displayid); // Find the right display FloDisplay *cur = app->getCFG()->GetDisplayById(vev->interfaceid, vev->displayid); if (cur != 0) cur->SetShow(vev->show); else printf("VIDEO: Invalid display (interface id %d, display id %d)\n", vev->interfaceid,vev->displayid); } break; case T_EV_VideoShowLayout : { VideoShowLayoutEvent *vev = (VideoShowLayoutEvent *) ev; if (CRITTERS) printf("VIDEO: %s layout (interface id %d, layout id %d) %s\n", (vev->show ? "show" : "hide"), vev->interfaceid,vev->layoutid, (vev->hideothers ? "(hide others)" : "")); // Find the right layout int iid = vev->interfaceid, id = vev->layoutid; FloLayout *cur = app->getCFG()->GetLayouts(); char found = 0; while (cur != 0) { if (iid == cur->iid && id == cur->id) { // Match! // Set show or hide cur->show = vev->show; found = 1; } else if (vev->hideothers) { // Hide other layouts cur->show = 0; } cur = cur->next; } if (!found) printf("VIDEO: Invalid layoutid %d in interface %d.\n", vev->layoutid,vev->interfaceid); } break; case T_EV_VideoSwitchInterface : { // Here, we show all layouts & displays that belong to the given // interface // All other layouts & displays are hidden, unless they belong to a // non-switchable interface VideoSwitchInterfaceEvent *vev = (VideoSwitchInterfaceEvent *) ev; if (CRITTERS) printf("VIDEO: Switch to interface %d\n",vev->interfaceid); // Show/hide layouts int iid = vev->interfaceid; cur_iid = iid; { FloLayout *cur = app->getCFG()->GetLayouts(); while (cur != 0) { if (cur->iid != 0 && cur->iid < NS_INTERFACE_START_ID) { // Switchable interface? if (cur->iid == iid) // Layout in matching interface- show cur->show = 1; else // Layout in unmatching interface- hide cur->show = 0; } cur = cur->next; } } { FloDisplay *cur = app->getCFG()->GetDisplays(); while (cur != 0) { if (cur->iid != 0 && cur->iid < NS_INTERFACE_START_ID) { // Switchable interface? if (cur->iid == iid) // Display in matching interface- show cur->SetShow(1); else // Display in unmatching interface- hide cur->SetShow(0); } cur = cur->next; } } } break; case T_EV_VideoShowHelp : { VideoShowHelpEvent *vev = (VideoShowHelpEvent *) ev; if (CRITTERS) printf("VIDEO: show help page - %d%s\n", vev->page,(vev->page ? "" : " - off")); if (vev->page >= 0 && vev->page <= numhelppages) showhelppage = vev->page; else printf("VIDEO: invalid help page - %d (valid range: 0-%d)\n", vev->page,numhelppages); } break; case T_EV_VideoFullScreen : { VideoFullScreenEvent *vev = (VideoFullScreenEvent *) ev; if (CRITTERS) printf("VIDEO: set full screen = %s\n", (vev->fullscreen ? "on" : "off")); SetVideoMode(vev->fullscreen); } break; default: break; } }; // This is a custom surface blitter that doesn't use large block // memory writes and thus avoids the strange video glitch of introducing // audio pops on some machines-- some loss in performance! void VideoIO::Custom_BlitSurface(SDL_Surface *in, SDL_Surface *out, SDL_Rect *dstrect) { int opitch = out->pitch, ipitch = in->pitch, bpp = out->format->BytesPerPixel; if (bpp != in->format->BytesPerPixel) { printf("VIDEO: ERROR: Buffer and screen different format!\n"); return; } /* * Lock the surface */ if (SDL_MUSTLOCK(out)) { if (SDL_LockSurface(out) < 0) { return; } } Uint8 *opixels = (Uint8 *)out->pixels + dstrect->y*opitch + dstrect->x*bpp, *ipixels = (Uint8 *)in->pixels; int xrun = (dstrect->x+dstrect->w <= out->w ? dstrect->w : out->w-dstrect->x), yrun = (dstrect->y+dstrect->h <= out->h ? dstrect->h : out->h-dstrect->y), ojump = opitch-xrun*bpp, ijump = ipitch-xrun*bpp; switch (bpp) { case 1 : { for (int i = 0; i < yrun; i++, opixels += ojump, ipixels += ijump) for (int j = 0; j < xrun; j++, opixels += bpp, ipixels += bpp) *opixels = *ipixels; } break; case 2 : { for (int i = 0; i < yrun; i++, opixels += ojump, ipixels += ijump) for (int j = 0; j < xrun; j++, opixels += bpp, ipixels += bpp) *((Uint16 *) opixels) = *((Uint16 *) ipixels); } break; case 3 : { for (int i = 0; i < yrun; i++, opixels += ojump, ipixels += ijump) for (int j = 0; j < xrun; j++, opixels += bpp, ipixels += bpp) { *(opixels++) = *(ipixels++); *(opixels++) = *(ipixels++); *(opixels++) = *(ipixels++); } } break; case 4 : { for (int i = 0; i < yrun; i++, opixels += ojump, ipixels += ijump) for (int j = 0; j < xrun; j++, opixels += bpp, ipixels += bpp) *((Uint32 *) opixels) = *((Uint32 *) ipixels); } break; } /* * Unlock surface */ if (SDL_MUSTLOCK(out)) { SDL_UnlockSurface(out); } }; void VideoIO::Squeeze_BlitSurface(SDL_Surface *in, SDL_Surface *out, SDL_Rect *dstrect) { int opitch = out->pitch, ipitch = in->pitch, bpp = out->format->BytesPerPixel; if (bpp != in->format->BytesPerPixel) { printf("VIDEO: ERROR: Buffer and screen different format!\n"); return; } if (dstrect->w == 0 || dstrect->h == 0) return; if (dstrect->h > in->h) dstrect->h = in->h; /* * Lock the surface */ if (SDL_MUSTLOCK(out)) { if (SDL_LockSurface(out) < 0) { return; } } Uint8 *opixels = (Uint8 *)out->pixels + dstrect->y*opitch + dstrect->x*bpp, *ipixels = (Uint8 *)in->pixels; float yscale = (float) in->h/dstrect->h; int xrun = (dstrect->x+dstrect->w <= out->w ? dstrect->w : out->w-dstrect->x), yh = (dstrect->y+dstrect->h <= out->h ? dstrect->h : out->h-dstrect->y), yrun = (int) (yh*yscale), ojump = opitch-xrun*bpp, ijump = ipitch-xrun*bpp, ilinejump = ipitch; /* printf("xrun: %d yrun: %d w: %d h: %d yscale: %.2f ijump: %d\n", xrun,yrun, in->w,in->h, yscale,ijump); */ switch (bpp) { case 1 : { for (float i = 0; i < yrun; opixels += ojump) { for (int j = 0; j < xrun; j++, opixels += bpp, ipixels += bpp) *opixels = *ipixels; int oldi = (int)i; i += yscale; ipixels += ijump+ilinejump*((int)i-(int)oldi-1); } } break; case 2 : { for (float i = 0; i < yrun; opixels += ojump) { for (int j = 0; j < xrun; j++, opixels += bpp, ipixels += bpp) *((Uint16 *) opixels) = *((Uint16 *) ipixels); int oldi = (int)i; i += yscale; ipixels += ijump+ilinejump*((int)i-(int)oldi-1); } } break; case 3 : { for (float i = 0; i < yrun; opixels += ojump) { for (int j = 0; j < xrun; j++, opixels += bpp, ipixels += bpp) { *(opixels++) = *(ipixels++); *(opixels++) = *(ipixels++); *(opixels++) = *(ipixels++); } int oldi = (int)i; i += yscale; ipixels += ijump+ilinejump*((int)i-(int)oldi-1); } } break; case 4 : { for (float i = 0; i < yrun; opixels += ojump) { for (int j = 0; j < xrun; j++, opixels += bpp, ipixels += bpp) *((Uint32 *) opixels) = *((Uint32 *) ipixels); int oldi = (int)i; i += yscale; ipixels += ijump+ilinejump*((int)i-(int)oldi-1); } } break; } /* * Unlock surface */ if (SDL_MUSTLOCK(out)) { SDL_UnlockSurface(out); } }; // Draws text on the given surface // Justify is 0 for default justify, 1 for center, and 2 for opposite side // Returns size of text drawn in sx and sy (optionally) int VideoIO::draw_text(SDL_Surface *out, TTF_Font *font, char *str, int x, int y, SDL_Color clr, char justifyx, char justifyy, int *sx, int *sy) { SDL_Surface *text; SDL_Rect dstrect; SDL_Color black = { 0, 0, 0, 0 }; text = TTF_RenderText_Shaded(font, str, clr, black); if ( text != NULL ) { dstrect.x = x; dstrect.y = y; dstrect.w = text->w; dstrect.h = text->h; if (sx != 0) *sx = dstrect.w; if (sy != 0) *sy = dstrect.h; if (justifyx) dstrect.x -= (justifyx == 1 ? dstrect.w/2 : dstrect.w); if (justifyy) dstrect.y -= (justifyy == 1 ? dstrect.h/2 : dstrect.h); SDL_SetColorKey(text, SDL_SRCCOLORKEY|SDL_RLEACCEL, 0); SDL_BlitSurface(text, NULL, out, &dstrect); SDL_FreeSurface(text); } else { if (sx != 0) *sx = 0; if (sy != 0) *sy = 0; return 1; } return 0; } char VideoIO::DrawLoop(LoopManager *loopmgr, int i, SDL_Surface *screen, SDL_Surface *lscopepic, SDL_Color *loopcolors, float colormag, FloConfig *fs, FloLayoutElement *curel, CircularMap *direct_map, int direct_xpos, int direct_ypos, float lvol, char drawtext) { const static SDL_Color txtclr = { 0xFF, 0x50, 0x20, 0 }, cursorclr = { 0xEF, 0x11, 0x11, 0 }, txtclr2 = { 0xEF, 0xAF, 0xFF, 0 }; // Color for selected loops static SDL_Color selcolor[4] = { { 0xF9, 0xE6, 0x13, 0 }, { 0x62, 0x62, 0x62, 0 }, { 0xFF, 0xFF, 0xFF, 0 }, { 0xE0, 0xDA, 0xD5, 0 } }; const float cpeak_mul = 2.0, // For pulsing loops - magnitude of pulse cpeak_base = 0.5; // For pulsing loops - base size of loop const int lscope_maxmag = OCY(15), lscopemag = OCY(20), looppiemag = OCX(20); BED_PeaksAvgs *pa; nframes_t plen = 0; float curpeak = 1.0, ispd; sample_t *peakbuf, *avgbuf; static int liney = -1; // How high is a line of text? // Lockup loops so that loop manager doesn't go and delete one while we // are drawing it loopmgr->LockLoops(); Loop *l = 0; if (loopmgr->GetStatus(i) == T_LS_Recording) { // Use current record length for visual size pa = (BED_PeaksAvgs *) ((RecordProcessor *) loopmgr-> GetProcessor(i))-> GetFirstRecordedBlock()->GetExtendedData(T_BED_PeaksAvgs); if (pa != 0) { PeaksAvgsManager *pa_mgr = ((RecordProcessor *) loopmgr-> GetProcessor(i))->GetPAMgr(); if (pa_mgr != 0) plen = pa_mgr->GetPeaksI()->GetTotalLength2Cur(); } } else { l = loopmgr->GetSlot(i); if (l != 0) { // Double check the loop is still there // Use loop length for visual size pa = (BED_PeaksAvgs *) l->blocks->GetExtendedData(T_BED_PeaksAvgs); } else pa = 0; if (pa != 0) plen = pa->peaks->GetTotalLen(); } if (l != 0 && l->selcnt > 0) { loopcolors = selcolor; // Color loop selected } // Draw peaks & avgs float loopvol = 1.0, // Loop volume loopdvol = 1.0; // Loop volume delta if (pa != 0) { // Background SDL_FillRect(lscopepic,NULL, SDL_MapRGB(lscopepic->format, (int) (loopcolors[0].r*colormag), (int) (loopcolors[0].g*colormag), (int) (loopcolors[0].b*colormag))); if (plen > 0) { // Access buffers peakbuf = pa->peaks->buf; avgbuf = pa->avgs->buf; loopvol = loopmgr->GetLoopVolume(i); loopdvol = loopmgr->GetLoopdVolume(i); nframes_t idx = loopmgr->GetCurCnt(i)/ fs->loop_peaksavgs_chunksize; // Compute current peak curpeakidx[i] = idx; if (curpeakidx[i] == lastpeakidx[i]) curpeak = oldpeak[i]; // No new peak data since last update! else { nframes_t j = lastpeakidx[i]; if (curpeakidx[i] < lastpeakidx[i]) j = 0; curpeak = 0; for (; j < curpeakidx[i]; j++) curpeak = MAX(curpeak,peakbuf[j]*loopvol); curpeak *= cpeak_mul; curpeak += cpeak_base; oldpeak[i] = curpeak; lastpeakidx[i] = curpeakidx[i]; } float cmag = lvol*loopvol*lscopemag*curpeak; float rv1 = loopcolors[1].r*colormag, gv1 = loopcolors[1].g*colormag, bv1 = loopcolors[1].b*colormag, rv2 = loopcolors[2].r*colormag, gv2 = loopcolors[2].g*colormag, bv2 = loopcolors[2].b*colormag; int midpt = lscopepic->h/2; // Ratio of visual size to audio scope buffer length ispd = (float) lscopepic->w / plen; // Write into the buffer on sliding position to give animated // scope effect float pos = -(float)idx*ispd; if (pos < 0.) pos += (float)lscopepic->w; for (nframes_t j = 0; j < plen; j++, pos += ispd) { float pbj = peakbuf[j]; int peakd = (int) (cmag*pbj); if (peakd > lscope_maxmag) peakd = lscope_maxmag; if (pos >= (float)lscopepic->w) pos = 0.; float peaky = avgbuf[j]/(pbj*pbj + 0.00000001)*2; if (peaky > 1.0) peaky = 1.0; float rv = rv1 * peaky + rv2 * (1.-peaky), gv = gv1 * peaky + gv2 * (1.-peaky), bv = bv1 * peaky + bv2 * (1.-peaky); //if (rv > 255) rv = 255; //if (gv > 255) gv = 255; //if (bv > 255) bv = 255; if (ispd >= 1.) { int pos1 = (int) pos, pos2 = (int) (pos+ispd); boxRGBA(lscopepic, (int) pos1, midpt-peakd, (int) pos2, midpt+peakd, (int) rv, (int) gv, (int) bv, 255); } else vlineRGBA(lscopepic, (int) pos, midpt-peakd, midpt+peakd, (int) rv, (int) gv, (int) bv, 255); } } } // loopmgr->UnlockLoops(); // Map flat scope onto circle CircularMap *loopmap; int dispx, dispy; if (curel != 0) { // Show in layout loopmap = curel->loopmap; dispx = curel->loopx; dispy = curel->loopy; } else { // Show direct on screen loopmap = direct_map; dispx = direct_xpos; dispy = direct_ypos; } int fullx = loopmap->map_xs, fully = loopmap->map_ys, halfx = fullx/2, halfy = fully/2; if (curel != 0) { // Layout specifies center of loop position.. compensate dispx -= halfx; dispy -= halfy; } // Show scope if (!loopmap->Map(screen,dispx,dispy)) { circleRGBA(screen,dispx+halfx,dispy+halfy,halfx, 0,0,0, 255); // Outline // Show portion played in semitranslucent int pieradius = MIN((int) (lvol*looppiemag*curpeak),70); FILLED_PIE(screen,dispx+halfx,dispy+halfy, pieradius,0, (int) (360*loopmgr->GetPos(i)), (int) (loopcolors[3].r*colormag), (int) (loopcolors[3].g*colormag), (int) (loopcolors[3].b*colormag),127); // Show volume float loop_volmag = fullx*0.9/2, // For loop volume bar loop_dvolmag = fullx*250; // For loop volume delta bar int magbar = (int) (loop_volmag*loopmgr->GetTriggerVol(i)); boxRGBA(screen,dispx+halfx-magbar, dispy+halfy-halfy/5, dispx+halfx+magbar, dispy+halfy+halfy/5, (int) (loopcolors[3].r*colormag),0,0, 127); // Show volume delta magbar = (int) ((loopdvol-1.0)*loop_dvolmag); boxRGBA(screen,dispx+halfx, dispy+halfy+halfy/4, dispx+halfx+magbar, dispy+halfy+halfy/2, (int) (loopcolors[3].r*colormag),0,0, 127); // Show if overdub if (loopmgr->GetStatus(i) == T_LS_Overdubbing) draw_text(screen,mainfont,"O",dispx+halfx,dispy+halfy,txtclr,1,1); if (drawtext) { // Show loop name ItemRenamer *renamer = loopmgr->GetRenamer(); if (renamer != 0 && l == loopmgr->GetRenameLoop()) { // This loop is being renamed- show current name RenameUIVars *rui = renamer->UpdateUIVars(); if (liney == -1) TTF_SizeText(smallfont,VERSION,0,&liney); // Draw text with cursor int sx, sy; int txty = dispy+fully; char *curn = renamer->GetCurName(); if (*curn != '\0') VideoIO::draw_text(screen,smallfont,curn, dispx,txty,txtclr2,0,2,&sx,&sy); else { sx = 0; sy = liney; } if (rui->rename_cursor_toggle) boxRGBA(screen, dispx+sx,txty, dispx+sx+sy/2,txty-sy, cursorclr.r,cursorclr.g,cursorclr.b,255); } else if (l != 0 && l->name != 0) // Show name draw_text(screen,smallfont,l->name, dispx,dispy+fully,txtclr2,0,2); // Show last recorded loop # int cnt = 0; for (cnt = 0; cnt < LAST_REC_COUNT && loopmgr->lastrecidx[cnt] != i; cnt++); if (cnt < LAST_REC_COUNT) { char tmp[50]; snprintf(tmp,50,"L%d",cnt+1); draw_text(screen,smallfont,tmp, dispx+fullx,dispy,txtclr2,2,0); } #if 0 // Old way to label loop in 'show-all-loops' mode if (curel == 0) { char tmp[50]; // Show direct-- so label the loop Pulse *a = loopmgr->GetPulse(i); long len; if (a != 0) len = loopmgr->GetRoundedLength(i)/a->len; else len = loopmgr->GetRoundedLength(i); if (len != 0) snprintf(tmp,50,"%03d %ld",i,len); else snprintf(tmp,50,"%03d",i); SDL_Color tmpclr = { (int) (loopcolors[3].r*colormag), (int) (loopcolors[3].g*colormag), (int) (loopcolors[3].b*colormag), 0 }; draw_text(screen,mainfont,tmp,dispx,dispy+textyofs,tmpclr); } #endif } loopmgr->UnlockLoops(); return 0; } else { loopmgr->UnlockLoops(); return 1; } }; // If no suitable map exists in list 'cmaps', creates a planar>circular map // of diameter 'sz', mapping from the given surface. CircularMap *VideoIO::CreateMap(SDL_Surface *lscopepic, int sz) { // OK, scan to see if a fitting map already exists CircularMap *nw; if (cmaps != 0) nw = cmaps->Scan(sz); else nw = 0; if (nw == 0) { // No fitting map found, generate one at the right size int lscope_crinner = (int) (sz*0.13), lscope_crsize = sz/2 - lscope_crinner; printf("VIDEO: Generating planar->circular map @ size %d\n",sz); nw = new CircularMap(lscopepic, sz,sz, lscopewidth,lscopeheight, lscope_crinner, lscope_crsize); // Store a copy in our list if (cmaps == 0) cmaps = nw; else cmaps->Link(nw); } return nw; }; #ifdef LCD_DISPLAY int VideoIO::InitLCD (char *devname, int baud) { struct termios term; // Open lcd_handle = open(devname, O_RDWR | O_NOCTTY /*| O_NONBLOCK*/); if (lcd_handle <= 0) { printf("InitLCD: Failed to connect to USB LCD\n"); return 1; } if (tcgetattr(lcd_handle, &term) != 0) { printf("InitLCD: tcgetattr() failed\n"); return 1; } // Input modes term.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|INPCK|ISTRIP|INLCR|IGNCR|ICRNL |IXON|IXOFF); term.c_iflag |= IGNPAR; // Output modes term.c_oflag &= ~(OPOST|ONLCR|OCRNL|ONOCR|ONLRET|OFILL |OFDEL|NLDLY|CRDLY|TABDLY|BSDLY|VTDLY|FFDLY); term.c_oflag |= NL0|CR0|TAB0|BS0|VT0|FF0; // Control modes term.c_cflag &= ~(CSIZE|PARENB|PARODD|HUPCL|CRTSCTS); term.c_cflag |= CREAD|CS8|CSTOPB|CLOCAL; // Local modes term.c_lflag &= ~(ISIG|ICANON|IEXTEN|ECHO); term.c_lflag |= NOFLSH; // Set baud rate cfsetospeed(&term, baud); cfsetispeed(&term, baud); // Set if (tcsetattr(lcd_handle, TCSANOW, &term) != 0) { printf("InitLCD: tcsetattr() failed\n"); return 1; } // Backlight off LCD_Send(14); LCD_Send(0); // Hide cursor LCD_Send(4); // Turn off "scroll" and "wrap" LCD_Send(20); LCD_Send(24); // Clear display LCD_Send(12); memset(lcd_dat,sizeof(lcd_dat),' '); lcd_curb = 0; printf("InitLCD: success\n"); return 0; } void VideoIO::LCDB_Dump () { int oldb = (lcd_curb == 0 ? 1 : 0); // Compare old and current buffers if (memcmp(&lcd_dat[lcd_curb][0][0],&lcd_dat[oldb][0][0], sizeof(char) * LCD_ROWS * LCD_COLS) != 0) { // Buffers differ, dump difference int lu_r = -2, lu_c = -2; // Last update row/col for (int r = 0; r < LCD_ROWS; r++) for (int c = 0; c < LCD_COLS; c++) if (lcd_dat[lcd_curb][r][c] != lcd_dat[oldb][r][c]) { // This cell differs- send if (r != lu_r || c != lu_c+1) { // Need to reposition- not the next character // printf("pos: %d %d\n",c,r); LCD_Send(17); LCD_Send(c); LCD_Send(r); } // Send new character // printf("%c\n",lcd_dat[lcd_curb][r][c]); LCD_Send(lcd_dat[lcd_curb][r][c]); /* printf("BUF#%d Sending: %c @ (%d,%d)\n",lcd_curb, lcd_dat[lcd_curb][r][c],c,r); */ lu_r = r; lu_c = c; } } // Switch write buffers lcd_curb = oldb; }; #endif // This is the video event loop void VideoIO::video_event_loop () { FloConfig *fs = app->getCFG(); LoopManager *loopmgr = app->getLOOPMGR(); #ifndef NO_VIDEO const static SDL_Color red = { 0xFF, 0x50, 0x20, 0 }, //blue = { 0x30, 0x20, 0xEF, 0 }, white = { 0xEF, 0xAF, 0xFF, 0 }, truewhite = { 0xFF, 0xFF, 0xFF, 0 }, gray = { 0x77, 0x88, 0x99, 0 }, yellow = { 0xDF, 0xEF, 0x20, 0 }; int nt = app->getCFG()->GetNumTriggers(); const static int num_loopcolors = 4; SDL_Color loopcolors[num_loopcolors][4] = { { { 0x5F, 0x7C, 0x2B, 0 }, { 0xD3, 0xFF, 0x82, 0 }, { 0xFF, 0xFF, 0xFF, 0 }, { 0xDE, 0xE2, 0xD5, 0 } }, { { 0x8E, 0x75, 0x62, 0 }, { 0xFF, 0x9C, 0x4C, 0 }, { 0xFF, 0xFF, 0xFF, 0 }, { 0xE0, 0xDA, 0xD5, 0 } }, { { 0x62, 0x8C, 0x85, 0 }, { 0x43, 0xF2, 0xD5, 0 }, { 0xFF, 0xFF, 0xFF, 0 }, { 0xA9, 0xC6, 0xC1, 0 } }, { { 0x69, 0x4B, 0x89, 0 }, { 0xA8, 0x56, 0xFF, 0 }, { 0xFF, 0xFF, 0xFF, 0 }, { 0xDF, 0xCB, 0xF4, 0 } } }; char tmp[255]; curpeakidx = new nframes_t[nt]; lastpeakidx = new nframes_t[nt]; oldpeak = new float[nt]; memset(curpeakidx,0,sizeof(nframes_t) * nt); memset(lastpeakidx,0,sizeof(nframes_t) * nt); for (int i = 0; i < nt; i++) oldpeak[i] = 1.0; // Video coordinates & settings const int patchx = OCX(35), patchy = OCY(460), pulsex = OCX(600), pulsey = OCY(30), pulsespc = OCY(40), pulsepiemag = OCX(10), progressbar_x = OCX(20), progressbar_y = OCY(400), progressbar_xs = OCX(640)-progressbar_x*2, progressbar_ys = OCY(20); // Flat loop scope dimensions-- lscopewidth = OCX(320); lscopeheight = OCY(30); const static float loop_colorbase = 0.5; // Loop scope bitmap Uint8 video_bpp = screen->format->BitsPerPixel; Uint32 Rmask = screen->format->Rmask, Gmask = screen->format->Gmask, Bmask = screen->format->Bmask, Amask = screen->format->Amask; printf("VIDEO: Creating temporary buffers at %d bits\n",video_bpp); lscopepic = SDL_CreateRGBSurface(SDL_HWSURFACE, lscopewidth, lscopeheight, video_bpp, Rmask, Gmask, Bmask, Amask); // Flat // Generate circular maps for all the different sized layout elements // as defined in config // Mappings from flat to circular for loops shown at different sizes cmaps = 0; FloLayout *curlayout = fs->GetLayouts(); while (curlayout != 0) { FloLayoutElement *curel = curlayout->elems; while (curel != 0) { int sz = curel->loopsize; if (sz > 0) curel->loopmap = CreateMap(lscopepic,sz); curel = curel->next; } curlayout = curlayout->next; } #if 0 // Load title image printf("VIDEO: Loading title bitmap.\n"); SDL_Surface *titlepic = SDL_LoadBMP(FWEELIN_TITLE_IMAGE); if (titlepic == 0) { printf("Couldn't load title image from: %s\n" "Did you run 'make install'?\n", FWEELIN_TITLE_IMAGE); return; } SDL_Surface *titletemppic = SDL_CreateRGBSurface(SDL_HWSURFACE, titlepic->w, titlepic->h, video_bpp, Rmask, Gmask, Bmask, Amask); // Flat // Draw final title image with fweelin version SDL_BlitSurface(titlepic, 0, titletemppic, 0); int ver_x, ver_y; TTF_SizeText(mainfont,VERSION,&ver_x,&ver_y); draw_text(titletemppic,mainfont,VERSION, titletemppic->w-ver_x-15,titletemppic->h-ver_y-15,truewhite); SDL_FreeSurface(titlepic); #endif // Logo image SDL_Surface *logopic = 0; if (fweelin_logo.bytes_per_pixel != 4) printf("VIDEO: Warning: Logo image must be 32-bit.\n"); else { logopic = SDL_CreateRGBSurface(SDL_HWSURFACE, fweelin_logo.width, fweelin_logo.height, 32, 0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000); memcpy(logopic->pixels,fweelin_logo.pixel_data, fweelin_logo.width * fweelin_logo.height * fweelin_logo.bytes_per_pixel); } // Help setup const static int helpx = OCX(0), helpy = OCY(10), helpmaxy2 = OCY(460), maxhelppages = 255; // Maximum # of help pages int helpstartidx[maxhelppages], helpendidx[maxhelppages], curstartidx; int helpx2 = helpx, curhelpy2 = helpy, helpy2 = helpy, helpmaxcol1 = 0, helpmaxcol2 = 0; int x, y1, y2; // Size up and paginate help numhelppages = 0; curstartidx = 0; for (int i = 0; i < fs->GetNumHelpLines(); i++) { char *s1 = fs->GetHelpLine(i,0), *s2 = fs->GetHelpLine(i,1); if (s1 != 0) { TTF_SizeText(helpfont,s1,&x,&y1); if (s2 != 0) { helpmaxcol1 = MAX(helpmaxcol1,x); TTF_SizeText(helpfont,s2,&x,&y2); helpmaxcol2 = MAX(helpmaxcol2,x); } else { y2 = 0; } if (curhelpy2 + MAX(y1,y2) >= helpmaxy2) { // New page helpstartidx[numhelppages] = curstartidx; helpendidx[numhelppages] = i-1; curstartidx = i; numhelppages++; if (numhelppages >= maxhelppages) { printf("VIDEO: ERROR: Too many help pages!\n"); exit(1); } helpy2 = MAX(helpy2,curhelpy2); curhelpy2 = helpy + MAX(y1,y2); } else { // Same page curhelpy2 += MAX(y1,y2); } } } helpstartidx[numhelppages] = curstartidx; helpendidx[numhelppages] = fs->GetNumHelpLines()-1; numhelppages++; // 1 is considered first help page helpx2 = helpx + helpmaxcol1 + helpmaxcol2; // Only check stream stats periodically (not every video update) const static int CHECK_SIZE_FRAMES = 20; int checksizecnt = CHECK_SIZE_FRAMES; int num_streams = 0; // Number of output streams char *stream_type = ""; // Type (extension) of output stream double streamoutsize = 0.0; // Last checked size of all output streams. video_time = 0; double video_start = mygettime(); #endif // NO_VIDEO #ifdef LCD_DISPLAY #define LCD_FLASHLEN 5 #define LOOPROW 1 float prev_pct = 0.0; int flashcnt = LCD_FLASHLEN; InitLCD("/dev/ttyUSB0",B19200); #endif while (videothreadgo) { // This video thread eats CPU // So for slower machines I advise using a higher delay time usleep(app->getCFG()->GetVDelay()); // Lock video space from changes pthread_mutex_lock (&video_thread_lock); #ifdef LCD_DISPLAY { LCDB_Clear(); // Draw pulse Pulse *a = loopmgr->GetPulseByIndex(0); if (a != 0) { float pct = a->GetPct(); if (pct < prev_pct) flashcnt = 0; // LCDB_SetChar(0,LCD_COLS-1,'*'); if (flashcnt++ < LCD_FLASHLEN) LCDB_SetStr(0,0,"********************"); else LCDB_SetChar(0,(int) (a->GetPct()*LCD_COLS),'*'); prev_pct = pct; } // Draw loops loopmgr->LockLoops(); FloLayout *curlayout = fs->GetLayouts(); int lc = 0, lr = LOOPROW; while (curlayout != 0) { if (curlayout->show && curlayout->elems != 0) { // Draw each element in this layout FloLayoutElement *curel = curlayout->elems; int firstid = curlayout->loopids.lo, curid = firstid, maxid = curlayout->loopids.hi; while (curel != 0 && curid <= maxid) { // Calculate the actual loop ID that corresponds to this element int i = firstid + curel->id; char loopexists; if (loopmgr->GetSlot(i) || loopmgr->IsActive(i)) loopexists = 1; else loopexists = 0; // Draw loop for this element if (loopexists && curlayout->showelabel) { // printf("el: %s\n",curel->name); if (loopmgr->IsActive(i)) { /* LCDB_SetChar(lr,lc-1,'-'); char *buf; */ LCDB_SetStr(lr,lc,strup(curel->name)); // LCDB_SetChar(lr,lc+strlen(buf),'-'); } else LCDB_SetStr(lr,lc,strlwr(curel->name)); lc += strlen(curel->name) + 1; if (lc >= LCD_COLS - 3) { lc = 0; lr++; } } /*if (loopexists) DrawLoop(loopmgr,i,screen,lscopepic, loopcolors[clrnum],colormag, fs,curel,0,0,0, lvol);*/ curel = curel->next; curid++; } } curlayout = curlayout->next; } loopmgr->UnlockLoops(); // LCDB_Debug(); LCDB_Dump(); } #endif // LCD_DISPLAY #ifndef NO_VIDEO //double t1 = mygettime(); float lvol = app->getMASTERLIMITER()->GetLimiterVolume(); // Clear screen SDL_FillRect(screen,NULL,0); // Draw layouts #if 1 FloLayout *curlayout = fs->GetLayouts(); while (curlayout != 0) { // Draw this layout, if active if (curlayout->show && curlayout->elems != 0) { // Draw each element in this layout FloLayoutElement *curel = curlayout->elems; int firstid = curlayout->loopids.lo, curid = firstid, maxid = curlayout->loopids.hi; while (curel != 0 && curid <= maxid) { // Calculate the actual loop ID that corresponds to this element int i = firstid + curel->id; // What color should this element be? int clrnum = i % num_loopcolors; float colormag; char loopexists; if (loopmgr->GetSlot(i) || loopmgr->IsActive(i)) { loopexists = 1; colormag = loop_colorbase + loopmgr->GetTriggerVol(i); if (colormag > 1.0) colormag = 1.0; } else { loopexists = 0; colormag = loop_colorbase; } SDL_Color elclr; Loop *l = loopmgr->GetSlot(i); if (l != 0 && l->selcnt > 0) { // Selected loop static SDL_Color selcolor[4] = { { 0xF9, 0xE6, 0x13, 0 }, { 0x62, 0x62, 0x62, 0 }, { 0xFF, 0xFF, 0xFF, 0 }, { 0xE0, 0xDA, 0xD5, 0 } }; elclr.r = selcolor[0].r; elclr.g = selcolor[0].g; elclr.b = selcolor[0].b; elclr.unused = 0; } else { elclr.r = (int) (loopcolors[clrnum][0].r*colormag); elclr.g = (int) (loopcolors[clrnum][0].g*colormag); elclr.b = (int) (loopcolors[clrnum][0].b*colormag); elclr.unused = 0; } // Draw each geometry of this element FloLayoutElementGeometry *curgeo = curel->geo; while (curgeo != 0) { curgeo->Draw(screen,elclr); curgeo = curgeo->next; } // Draw loop for this element if (loopexists) DrawLoop(loopmgr,i,screen,lscopepic, loopcolors[clrnum],colormag, fs,curel,0,0,0, lvol); // Label this element if (curlayout->showelabel) draw_text(screen,mainfont,curel->name,curel->nxpos,curel->nypos, white); curel = curel->next; curid++; } // Label the layout if (curlayout->showlabel) draw_text(screen,mainfont,curlayout->name, curlayout->nxpos,curlayout->nypos,white); } curlayout = curlayout->next; } #endif // Show pies for pulses int curpulsey = pulsey; for (int i = 0; i < MAX_PULSES; i++) { Pulse *a = loopmgr->GetPulseByIndex(i); if (a != 0) { float pulsescale = 1.0; if (loopmgr->GetCurPulseIndex() == i) // Selected pulse twice as big! pulsescale *= 2; const static float LC_MAG = 1.3; float lc_theta_break = 7; float thetacur = 0, thetalen = (float) 360.0/a->GetLongCount_Len(); while (thetalen < lc_theta_break) lc_theta_break /= 1.5; for (int j = 0; j < a->GetLongCount_Cur(); j++, thetacur += thetalen) FILLED_PIE(screen,pulsex,curpulsey,(int) (pulsepiemag * pulsescale * LC_MAG),round(thetacur), round(thetacur+thetalen-lc_theta_break), 255,188,0,180); FILLED_PIE(screen,pulsex,curpulsey,(int) (pulsepiemag * pulsescale),0,359,0,0,0,255); FILLED_PIE(screen,pulsex,curpulsey,(int) (pulsepiemag * pulsescale),0, (int) (360*a->GetPct()),127,127,127,255); sprintf(tmp,"%d",i+1); draw_text(screen,mainfont,tmp,pulsex-pulsepiemag,curpulsey- pulsepiemag,red); curpulsey += pulsespc; } } // Draw input scope #if 0 int XSIZE = fs->GetVSize()[0]; const int scopemag = OCY(40), metermag = OCY(25), iscopey = OCY(350), //oscopex = 260, //oscopey = iscopey, //oscopemag = 100 // Input scope width scopewidth = XSIZE, // Y position of time marker ticks tmarky = iscopey + OCY(100); nframes_t scopelen = app->getCFG()->GetScopeSampleLen(); sample_t *peakbuf, *avgbuf; peakbuf = app->getAMPEAKS()->buf, avgbuf = app->getAMAVGS()->buf; int midpt = iscopey; float mul = scopemag*lvol, // Ratio of visual size to audio scope buffer length ispd = scopewidth / scopelen; // Write into the buffer on sliding position to give animated scope effect float pos = -(float)app->getAMPEAKSI()->GetTotalLength2Cur()*ispd; if (pos < 0.) pos += (float)scopewidth; for (nframes_t i = 0; i < scopelen; i++, pos += ispd) { float pbi = peakbuf[i]; int peakd = (int) (mul*pbi); //avgd = (int) (mul*1.5*avgbuf[i]); if (pos >= (float)scopewidth) pos = 0.; float peaky = avgbuf[i]/(pbi*pbi + 0.00000001)*2; if (peaky > 1.0) peaky = 1.0; float rv = 0xC2 * peaky + 0xF9 * (1.-peaky), gv = 0x7E * peaky + 0xBB * (1.-peaky), bv = 0xDD * peaky + 0x2A * (1.-peaky); //if (rv > 255) rv = 255; //if (gv > 255) gv = 255; //if (bv > 255) bv = 255; vlineRGBA(screen, (int) pos, midpt-peakd, midpt+peakd, (int) rv, (int) gv, (int) bv, 255); } // Scope meter marks BED_MarkerPoints *mp = app->getAMPEAKSPULSE(); TimeMarker *cur = 0; if (mp != 0) cur = mp->markers; while (cur != 0) { pos = (float) ((signed int) cur->markofs - (signed int) app->getAMPEAKSI()->GetTotalLength2Cur()) *ispd; if (pos < 0.) pos += (float)scopewidth; vlineRGBA(screen, (int) pos, tmarky-metermag, tmarky, 255,255,255,255); cur = cur->next; } #endif // Output scope #if 0 int ox = -1, oy = -1; for (nframes_t i = 0; i < app->getSCOPELEN(); i++) { int x = oscopex+i*2, y = oscopey+(int) (oscopemag*app->getSCOPE()[i]); if (ox != -1) lineRGBA(screen,ox,oy,x,y,127,127,255,255); ox = x; oy = y; } #endif // ** These two hardcoded displays could be made configurable // Stream output status if (app->getSTREAMOUTNAME_DISPLAY() == "") { strcpy(tmp,"stream off"); // No output checksizecnt = CHECK_SIZE_FRAMES; } else { if (++checksizecnt >= CHECK_SIZE_FRAMES) { // Stat for size of file checksizecnt = 0; streamoutsize = app->getSTREAMSTATS(stream_type,num_streams); } sprintf(tmp,"%s %.1f mb (%d streams)", app->getSTREAMOUTNAME_DISPLAY().c_str(),streamoutsize,num_streams); } draw_text(screen,mainfont,tmp,patchx,patchy-OCY(22),gray); // Scene name SceneBrowserItem *curscene = app->getCURSCENE(); if (curscene != 0) draw_text(screen,mainfont,curscene->name,0,0,gray); // ** // Draw displays #if 1 FloDisplay *curdisplay = fs->GetDisplays(); while (curdisplay != 0) { if (curdisplay->show || curdisplay->forceshow) curdisplay->Draw(screen); curdisplay = curdisplay->next; } #endif // Show save/load progress bar char draw_progress = 0; int progress_size = 0; if (loopmgr->GetNumSave() != 0) { draw_progress = 1; progress_size = (int) ((float)loopmgr->GetCurSave()/ loopmgr->GetNumSave()* progressbar_xs); } if (loopmgr->GetNumLoad() != 0) { draw_progress = 1; progress_size = (int) ((float)loopmgr->GetCurLoad()/ loopmgr->GetNumLoad()* progressbar_xs); } if (draw_progress) { boxRGBA(screen,progressbar_x+progress_size,progressbar_y, progressbar_x+progressbar_xs, progressbar_y+progressbar_ys, 50,50,10,255); boxRGBA(screen,progressbar_x,progressbar_y, progressbar_x+progress_size, progressbar_y+progressbar_ys, 255,255,30,255); hlineRGBA(screen,progressbar_x,progressbar_x+progress_size, progressbar_y,40,40,40,255); hlineRGBA(screen,progressbar_x,progressbar_x+progress_size, progressbar_y+progressbar_ys,40,40,40,255); vlineRGBA(screen,progressbar_x,progressbar_y, progressbar_y+progressbar_ys,40,40,40,255); vlineRGBA(screen,progressbar_x+progress_size,progressbar_y, progressbar_y+progressbar_ys,40,40,40,255); } // Show help on top if (showhelppage) { int spacey1, spacey2, curhelpy = helpy; // Dim the background // This doesn't work for large regions- bug in SDL_gfx? // boxRGBA(screen,helpx,helpy,helpx2,helpy2,255,255,255,0); for (int i = helpy; i <= helpy2; i++) hlineRGBA(screen,helpx,helpx2,i,0,0,0,180); hlineRGBA(screen,helpx,helpx2,helpy,255,255,255,127); hlineRGBA(screen,helpx,helpx2,helpy2,255,255,255,127); vlineRGBA(screen,helpx,helpy,helpy2,255,255,255,127); vlineRGBA(screen,helpx2,helpy,helpy2,255,255,255,127); // Now, draw help for (int i = helpstartidx[showhelppage-1]; i <= helpendidx[showhelppage-1]; i++) { char *s1 = fs->GetHelpLine(i,0), *s2 = fs->GetHelpLine(i,1); if (s1 != 0) draw_text(screen,helpfont,s1,helpx,curhelpy,yellow,0,0,0,&spacey1); else spacey1 = 0; if (s2 != 0) draw_text(screen,helpfont,s2,helpx+helpmaxcol1,curhelpy, truewhite,0,0,0,&spacey2); else spacey2 = 0; curhelpy += MAX(spacey1,spacey2); } } #if 0 // Old title image drawing-- // Draw title image double video_elapsed = mygettime() - video_start; float titlepct = video_elapsed/0.5; /* if (titletemppic->format->BytesPerPixel == 4) { int sz = titletemppic->w*titletemppic->h; char *pix = (char *) titletemppic->pixels; char vid = (char) (video_elapsed*255); for (int i = 0; i < sz; i++, pix += 4) if (*(pix+1) != 0 || *(pix+2) != 0 || *(pix+3) != 0) { // int val = (int) ((float)rand()/RAND_MAX*vid); //if (val > 255) // val = 255; *pix = vid; } else *pix = 0; } */ if (titlepct < 1.0) { int titlepos = (int) (titlepct*titletemppic->h); SDL_Rect dst; dst.x = screen->w/2-titletemppic->w/2; dst.y = screen->h/2-titlepos/2; dst.w = titletemppic->w; dst.h = titlepos; Squeeze_BlitSurface(titletemppic,screen,&dst); } else if (titlepct >= 1.0 && titlepct <= 4.0) { int titlepos = (int) (1.0*titletemppic->h); SDL_Rect dst; dst.x = screen->w/2-titletemppic->w/2; dst.y = screen->h/2-titlepos/2; dst.w = titletemppic->w; dst.h = titlepos; Squeeze_BlitSurface(titletemppic,screen,&dst); } else if (titlepct > 4.0 && titlepct < 5.0) { int titlepos = (int) ((5.0-titlepct)*titletemppic->h); SDL_Rect dst; dst.x = screen->w/2-titletemppic->w/2; dst.y = screen->h/2-titlepos/2; dst.w = titletemppic->w; dst.h = titlepos; Squeeze_BlitSurface(titletemppic,screen,&dst); } else if (titletemppic != 0) { SDL_FreeSurface(titletemppic); titletemppic = 0; } #endif // Draw logo #if 1 if (logopic != 0) { double video_elapsed = mygettime() - video_start; float titlepct = video_elapsed; float t_floatin = 2.0, t_floatout = 4.0; if (titlepct < 1.0) { SDL_Rect dst; dst.x = screen->w-logopic->w; dst.y = (int) (-logopic->h + screen->h*titlepct); dst.w = logopic->w; dst.h = logopic->h; SDL_BlitSurface(logopic, NULL, screen, &dst); } else if (titlepct > t_floatin && titlepct < t_floatin+1.0) { SDL_Rect dst; dst.x = screen->w-logopic->w; dst.y = screen->h-logopic->h; dst.w = logopic->w; dst.h = logopic->h; SDL_BlitSurface(logopic, NULL, screen, &dst); int ver_x, ver_y; TTF_SizeText(mainfont,VERSION,&ver_x,&ver_y); draw_text(screen,mainfont,VERSION, (int) (screen->w-(titlepct-t_floatin)*(ver_x+5)), screen->h-ver_y-5,truewhite); } else if (titlepct >= t_floatin && titlepct <= t_floatout) { SDL_Rect dst; dst.x = screen->w-logopic->w; dst.y = screen->h-logopic->h; dst.w = logopic->w; dst.h = logopic->h; SDL_BlitSurface(logopic, NULL, screen, &dst); int ver_x, ver_y; TTF_SizeText(mainfont,VERSION,&ver_x,&ver_y); draw_text(screen,mainfont,VERSION, screen->w-(ver_x+5), screen->h-ver_y-5,truewhite); } else if (titlepct > t_floatout && titlepct < t_floatout+1.0) { SDL_Rect dst; dst.x = screen->w-logopic->w; dst.y = screen->h-logopic->h; dst.w = logopic->w; dst.h = logopic->h; SDL_BlitSurface(logopic, NULL, screen, &dst); int ver_x, ver_y; TTF_SizeText(mainfont,VERSION,&ver_x,&ver_y); draw_text(screen,mainfont,VERSION, (int) (screen->w-(1.0-(titlepct-t_floatout))*(ver_x+5)), screen->h-ver_y-5,truewhite); } else { SDL_Rect dst; dst.x = screen->w-logopic->w; dst.y = screen->h-logopic->h; dst.w = logopic->w; dst.h = logopic->h; SDL_BlitSurface(logopic, NULL, screen, &dst); } } #endif // Now update screen! SDL_UpdateRect(screen, 0, 0, 0, 0); //video_time = mygettime() - t1; #endif // NO_VIDEO // Unlock video space from changes pthread_mutex_unlock (&video_thread_lock); } #ifndef NO_VIDEO delete[] curpeakidx; delete[] lastpeakidx; delete[] oldpeak; // Erase circular maps CircularMap *cur = cmaps; while (cur != 0) { CircularMap *tmp = cur->next; delete cur; cur = tmp; } // Close things up if (logopic != 0) SDL_FreeSurface(logopic); SDL_FreeSurface(lscopepic); #endif // NO_VIDEO } void VideoIO::SetVideoMode(char fullscreen) { const SDL_VideoInfo *info; Uint8 video_bpp; Uint32 videoflags; pthread_mutex_lock (&video_thread_lock); if (screen != 0) // Free existing screen SDL_FreeSurface(screen); screen = 0; /* Alpha blending doesn't work well at 8-bit color */ info = SDL_GetVideoInfo(); if ( info->vfmt->BitsPerPixel > 8 ) { video_bpp = info->vfmt->BitsPerPixel; } else { video_bpp = 16; } printf("VIDEO: SetVideoMode: Using %d-bit color\n", video_bpp); // Disabled (slower) options: /*| SDL_SRCALPHA | SDL_RESIZABLE |*/ videoflags = SDL_HWSURFACE | SDL_DOUBLEBUF; this->fullscreen = fullscreen; if (fullscreen) videoflags |= SDL_FULLSCREEN | SDL_NOFRAME; /* Set right video mode */ int XSIZE = app->getCFG()->GetVSize()[0], YSIZE = app->getCFG()->GetVSize()[1]; if ( (screen=SDL_SetVideoMode(XSIZE,YSIZE,video_bpp,videoflags)) == NULL ) { printf("VIDEO: Couldn't set %ix%i video mode: %s\n",XSIZE,YSIZE, SDL_GetError()); exit(1); } /* Use alpha blending */ //SDL_SetAlpha(inst->screen, SDL_SRCALPHA, 0); /* Set title for window */ SDL_WM_SetCaption("FreeWheeling","FreeWheeling"); pthread_mutex_unlock (&video_thread_lock); } void *VideoIO::run_video_thread(void *ptr) { VideoIO *inst = static_cast(ptr); printf("VIDEO: Thread start..\n"); // printf("*** VIDEO THREAD: %li\n",pthread_self()); #ifdef __MACOSX__ inst->cocoa.SetupCocoaThread(); #endif #ifndef NO_VIDEO // Initialize the font library if ( TTF_Init() < 0 ) { fprintf(stderr, "Couldn't initialize TTF: %s\n",SDL_GetError()); return 0; } atexit(TTF_Quit); // Load all fonts inst->mainfont = 0; inst->helpfont = 0; inst->smallfont = 0; inst->tinyfont = 0; { FloFont *cur = inst->app->getCFG()->GetFonts(); char system_font_path[255]; char fweelin_font_path[255]; while (cur != 0) { if (cur->name != 0 && cur->filename != 0 && cur->size != 0) { snprintf(system_font_path,255,"%s/%s","/usr/share/fonts/",cur->filename); snprintf(fweelin_font_path,255,"%s/fonts/%s",FWEELIN_DATADIR,cur->filename); printf("VIDEO: Loading %s font: %s (%d pt)\n",cur->name,cur->filename,cur->size); struct stat st; if (stat(system_font_path,&st) != 0 && stat(fweelin_font_path,&st) != 0) { printf("VIDEO: Couldn't find font file: %s " "in either %s/ or /usr/share/fonts/\n" "Did you run 'make install'?\n", cur->filename, FWEELIN_DATADIR); exit(1); } cur->font = TTF_OpenFont(system_font_path, cur->size); if (cur->font == 0) cur->font = TTF_OpenFont(fweelin_font_path, cur->size); if (cur->font == 0) { printf("VIDEO: Couldn't load %d pt font: %s " "from either %s/ or /usr/share/fonts/\n" "Did you run 'make install'?\n", cur->size, cur->filename, FWEELIN_DATADIR); exit(1); } TTF_SetFontStyle(cur->font, TTF_STYLE_NORMAL); // Check if this is a font we use if (!strcmp(cur->name,"main")) inst->mainfont = cur->font; else if (!strcmp(cur->name,"help")) inst->helpfont = cur->font; else if (!strcmp(cur->name,"small")) inst->smallfont = cur->font; else if (!strcmp(cur->name,"tiny")) inst->tinyfont = cur->font; } cur = cur->next; } } if (inst->mainfont == 0) { printf("VIDEO: Error, no 'main' font loaded!\n"); exit(1); } if (inst->helpfont == 0) { printf("VIDEO: Error, no 'help' font loaded!\n"); exit(1); } if (inst->smallfont == 0) { printf("VIDEO: Error, no 'small' font loaded!\n"); exit(1); } if (inst->tinyfont == 0) { printf("VIDEO: Error, no 'tiny' font loaded!\n"); exit(1); } #endif // NO_VIDEO inst->videothreadgo = 1; printf("VIDEO: SDL Ready!\n"); // Wait until we are actually running! while (!inst->app->IsRunning()) usleep(10000); #ifndef __MACOSX__ // On Mac OS X, this is done in the main thread // Set video mode / window size inst->SetVideoMode(0); #endif // Start main loop inst->video_event_loop(); #ifndef NO_VIDEO // Close all fonts { FloFont *cur = inst->app->getCFG()->GetFonts(); while (cur != 0) { if (cur->font != 0) TTF_CloseFont(cur->font); cur = cur->next; } } #endif // NO_VIDEO // Close things up SDL_QuitSubSystem(SDL_INIT_VIDEO); #ifdef __MACOSX__ inst->cocoa.TakedownCocoaThread(); #endif printf("VIDEO: thread done\n"); return 0; } freewheeling-0.6.6/src/fweelin_videoio.h000066400000000000000000000162421370736313100203070ustar00rootroot00000000000000#ifndef __FWEELIN_VIDEOIO_H #define __FWEELIN_VIDEOIO_H /* Copyright 2004-2011 Jan Pekau This file is part of Freewheeling. Freewheeling is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. Freewheeling 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 Freewheeling. If not, see . */ #include "fweelin_event.h" #include #ifdef __MACOSX__ #include #include #include "FweelinMac.h" #else #include #include #endif #ifdef __MACOSX__ #define CAPITAL_FILLED_PIE #endif // Different versions of sdl-gfx have different naming #ifdef CAPITAL_FILLED_PIE #define FILLED_PIE filledPieRGBA #else #define FILLED_PIE filledpieRGBA #endif // Convert from 640,480 screen size to the user's coordinate system #define OCX(x) (app->getCFG()->XCvt((float)(x)/640)) #define OCY(y) (app->getCFG()->YCvt((float)(y)/480)) #define FWEELIN_TITLE_IMAGE FWEELIN_DATADIR "/fweelin.bmp" extern double mygettime(void); extern int myround(float num); class Fweelin; class LoopManager; class FloConfig; class FloLayoutElement; // This crazy class computes a mapping // to bend a flat strip bitmap into a circle-- good for makin wheels! class CircularMap { public: // Create a mapping from the flat surface 'in' to a circular region // of the given dimensions-- the output surface location is specified when // actually mapping CircularMap(SDL_Surface *in, int map_xs, int map_ys, int in_xs, int in_ys, int rinner, int rsize); // Frees this map ~CircularMap(); // Map flat scope onto circle char Map(SDL_Surface *out, int dstx, int dsty); // Scans for a map with map_xs == sz CircularMap *Scan(int sz) { CircularMap *cur = this; while (cur != 0 && cur->map_xs != sz) cur = cur->next; return cur; }; // Links the given map to the end of this map list void Link(CircularMap *nw) { CircularMap *cur = this; while (cur->next != 0) cur = cur->next; cur->next = nw; }; SDL_Surface *in; Uint8 **map; int *scanmap; int map_xs, map_ys, in_xs, in_ys, rinner, rsize; CircularMap *next; }; // Video Handler class VideoIO : public EventProducer, public EventListener { friend class Fweelin; public: VideoIO (Fweelin *app) : app(app), screen(0), cmaps(0), showlooprange(0,0), showhelppage(0), cur_iid(0), videothreadgo(0) {}; virtual ~VideoIO() {}; int activate (); void close (); char IsActive () { return videothreadgo; }; double GetVideoTime() { return video_time; }; void SetVideoMode(char fullscreen); char GetVideoMode() { return fullscreen; }; void ReceiveEvent(Event *ev, EventProducer */*from*/); // Draw text, and optionally return size of text drawn in sx and sy static int draw_text(SDL_Surface *out, TTF_Font *font, char *str, int x, int y, SDL_Color clr, char centerx = 0, char centery = 0, int *sx = 0, int *sy = 0); // If no suitable map exists in list 'cmaps', creates a planar>circular map // of diameter 'sz', mapping from the given surface. CircularMap *CreateMap(SDL_Surface *lscopepic, int sz); inline SDL_Surface *getLSCOPEPIC() { return lscopepic; }; // Draw the circular scope and status information for one loop-- // given by loopid 'i' and optional layout element 'curel'.. // if curel is null, we draw direct with the given circular map // and position. // Returns nonzero if loop not drawn char DrawLoop(LoopManager *loopmgr, int i, SDL_Surface *screen, SDL_Surface *lscopepic, SDL_Color *loopcolors, float colormag, FloConfig *fs, FloLayoutElement *curel, CircularMap *direct_map, int direct_xpos, int direct_ypos, float lvol, char drawtext = 1); protected: // Core app Fweelin *app; // Video event handler thread static void *run_video_thread (void *ptr); void video_event_loop (); // This is a custom surface blitter that doesn't use large block // memory writes and thus avoids the strange video glitch of introducing // audio pops on some machines-- some loss in performance! void Custom_BlitSurface(SDL_Surface *in, SDL_Surface *out, SDL_Rect *dstrect); void Squeeze_BlitSurface(SDL_Surface *in, SDL_Surface *out, SDL_Rect *dstrect); #ifdef __MACOSX__ FweelinMac cocoa; // Cocoa thread setup #endif char fullscreen; // Fullscreen video? SDL_Surface *screen; // Pointers to fonts that video uses - links into FloFont structures TTF_Font *mainfont, *helpfont, *smallfont, *tinyfont; // Planar->Circular mapping variables CircularMap *cmaps; int lscopewidth, lscopeheight; SDL_Surface *lscopepic; nframes_t *curpeakidx, *lastpeakidx; float *oldpeak; Range showlooprange; // Which loops to show onscreen int showhelppage, // Which help page to show (0=off) numhelppages; // Number of help pages that are defined int cur_iid; // ID of currently visible (switchable) interface // Length of time taken (s) for one iteration of video loop double video_time; pthread_t video_thread; char videothreadgo; pthread_mutex_t video_thread_lock; #ifdef LCD_DISPLAY #define LCD_ROWS 4 #define LCD_COLS 20 // Initialize LCD connection int InitLCD (char *devname, int baud); // Writing directly to LCD inline void LCD_Send (unsigned char dat) { if (lcd_handle) while (write(lcd_handle, &dat, 1) != 1) { printf("LCD_Send failed\n"); usleep(1000); } }; inline void LCD_SendStr (char *data) { while (*data) LCD_Send(*data++); } // Writing to LCD via double buffer (more efficient) inline void LCDB_SetChar (int row, int col, char dat) { if (row >= 0 && row < LCD_ROWS && col >= 0 && col < LCD_COLS) lcd_dat[lcd_curb][row][col] = dat; }; inline void LCDB_SetStr (int row, int col, char *data) { while (*data) LCDB_SetChar(row,col++,*data++); } inline void LCDB_Clear () { memset(lcd_dat[lcd_curb],' ',sizeof(char) * LCD_ROWS * LCD_COLS); }; inline void LCDB_Debug () { char buf[LCD_COLS+1]; buf[LCD_COLS] = '\0'; for (int r = 0; r < LCD_ROWS; r++) { strncpy(buf,lcd_dat[lcd_curb][r],LCD_COLS); printf("%s\n",buf); } }; // Dump buffer to LCD, writing any changes, then switch buffer void LCDB_Dump (); // Handle for LCD output int lcd_handle; char lcd_dat[2][LCD_ROWS][LCD_COLS]; // Double buffer for LCD screen int lcd_curb; // Which of two double buffers is // being written to #endif }; #endif freewheeling-0.6.6/src/fweelin_videoio_displays.cc000066400000000000000000000647051370736313100223640ustar00rootroot00000000000000/* Art is the beginning. */ /* Copyright 2004-2011 Jan Pekau This file is part of Freewheeling. Freewheeling is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. Freewheeling 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 Freewheeling. If not, see . */ #include #include #include #include #include #include #include #include #include #include #include #include "fweelin_videoio.h" #include "fweelin_core.h" #include "fweelin_paramset.h" #include "fweelin_logo.h" void FloDisplayPanel::Draw(SDL_Surface *screen) { const static SDL_Color titleclr = { 0x77, 0x88, 0x99, 0 }; const static SDL_Color borderclr = { 0xFF, 0x50, 0x20, 0 }; boxRGBA(screen, xpos,ypos,xpos+sx,ypos+sy, 0,0,0,190); vlineRGBA(screen,xpos,ypos,ypos+sy, borderclr.r,borderclr.g,borderclr.b,255); vlineRGBA(screen,xpos+sx,ypos,ypos+sy, borderclr.r,borderclr.g,borderclr.b,255); hlineRGBA(screen,xpos,xpos+sx,ypos, borderclr.r,borderclr.g,borderclr.b,255); hlineRGBA(screen,xpos,xpos+sx,ypos+sy, borderclr.r,borderclr.g,borderclr.b,255); if (font == 0 || font->font == 0) { printf("VIDEO: WARNING: No font specified for parameter set.\n"); return; } int textheight = 0; TTF_SizeText(font->font,VERSION,0,&textheight); // Draw title if (title != 0) VideoIO::draw_text(screen,font->font, title,xpos+sx-margin,ypos,titleclr,2,0); } void LoopTray::Draw(SDL_Surface *screen) { const static SDL_Color borderclr = {100, 100, 90, 0}; LockBrowser(); // **** Add event to change placenames when 'video-show-loop' is called VideoIO *vid = app->getVIDEO(); // Generate circular map for loop tray if (loopmap == 0) loopmap = vid->CreateMap(vid->getLSCOPEPIC(),loopsize); // Draw iconified version boxRGBA(screen,xpos,ypos,xpos+iconsize,ypos+iconsize, borderclr.r,borderclr.g,borderclr.b,255); hlineRGBA(screen,xpos,xpos+iconsize,ypos,40,40,40,255); hlineRGBA(screen,xpos,xpos+iconsize,ypos+iconsize,40,40,40,255); vlineRGBA(screen,xpos,ypos,ypos+iconsize,40,40,40,255); vlineRGBA(screen,xpos+iconsize,ypos,ypos+iconsize,40,40,40,255); FILLED_PIE(screen,xpos+iconsize/2,ypos+iconsize/2, iconsize*3/8, 30,359, 0xF9,0xE6,0x13,255); circleRGBA(screen,xpos+iconsize/2,ypos+iconsize/2, iconsize*3/8, 40,40,40, 255); // Outline if (xpanded) { // Draw background { int xpand_yb1 = xpand_y1+basepos, xpand_yb2 = xpand_y2-basepos, xpand_xb1 = xpand_x1+basepos, xpand_xb2 = xpand_x2-basepos; boxRGBA(screen,xpand_x1,xpand_y1,xpand_xb1,xpand_y2, borderclr.r,borderclr.g,borderclr.b,255); boxRGBA(screen,xpand_xb1,xpand_y1,xpand_x2,xpand_y2, borderclr.r,borderclr.g,borderclr.b,255); boxRGBA(screen,xpand_x1,xpand_y1,xpand_x2,xpand_yb1, borderclr.r,borderclr.g,borderclr.b,255); boxRGBA(screen,xpand_x1,xpand_yb2,xpand_x2,xpand_y2, borderclr.r,borderclr.g,borderclr.b,255); boxRGBA(screen,xpand_xb1,xpand_yb1,xpand_xb2,xpand_yb2,0,0,0,255); } hlineRGBA(screen,xpand_x1,xpand_x2,xpand_y1,40,40,40,255); hlineRGBA(screen,xpand_x1,xpand_x2,xpand_y2,40,40,40,255); vlineRGBA(screen,xpand_x1,xpand_y1,xpand_y2,40,40,40,255); vlineRGBA(screen,xpand_x2,xpand_y1,xpand_y2,40,40,40,255); LoopTrayItem *curl = (LoopTrayItem *) first; // If necessary, recalc positions for loops if (touchtray) { char go = 1; int curx = basepos, cury = basepos; int loopjump = loopsize+basepos; // Space for loops? if (curx >= xpand_x2-xpand_x1-loopjump || cury >= xpand_y2-xpand_y1-loopjump) go = 0; while (curl != 0) { if (go) { curl->xpos = curx; curl->ypos = cury; // Move to next spot curx += loopjump; if (curx >= xpand_x2-xpand_x1-loopjump) { curx = basepos; cury += loopjump; if (cury >= xpand_y2-xpand_y1-loopjump) go = 0; } } else { curl->xpos = -1; curl->ypos = -1; } curl = (LoopTrayItem *) curl->next; } touchtray = 0; } // Draw items curl = (LoopTrayItem *) first; char go = 1; while (curl != 0 && go) { if (curl->xpos != -1) Draw_Item(screen,curl,xpand_x1+curl->xpos,xpand_y1+curl->ypos); else go = 0; curl = (LoopTrayItem *) curl->next; } } UnlockBrowser(); }; void LoopTray::Draw_Item(SDL_Surface *screen, BrowserItem *i, int x, int y) { const static float loop_colorbase = 0.5; const static SDL_Color white = { 0xEF, 0xAF, 0xFF, 0 }; const static SDL_Color cursorclr = { 0xEF, 0x11, 0x11, 0 }; static SDL_Color loop_color[4] = { { 0x62, 0x62, 0x62, 0 }, { 0xF9, 0xE6, 0x13, 0 }, { 0xFF, 0xFF, 0xFF, 0 }, { 0xE0, 0xDA, 0xD5, 0 } }; LoopManager *loopmgr = app->getLOOPMGR(); LoopTrayItem *li = (LoopTrayItem *) i; float colormag; char loopexists; if (loopmgr->GetSlot(li->loopid) || loopmgr->IsActive(li->loopid)) { loopexists = 1; colormag = loop_colorbase + loopmgr->GetTriggerVol(li->loopid); if (colormag > 1.0) colormag = 1.0; } else { loopexists = 0; colormag = loop_colorbase; } // Draw loop if (loopexists) { if (!app->getVIDEO()-> DrawLoop(loopmgr,li->loopid,screen,app->getVIDEO()->getLSCOPEPIC(), loop_color,colormag,app->getCFG(),0,loopmap,x,y, app->getMASTERLIMITER()->GetLimiterVolume(),0)) { // Place name if (li->placename != 0) VideoIO::draw_text(screen,font->font,li->placename,x,y,white); // Loop name if (xpand_liney == -1) TTF_SizeText(font->font,VERSION,0,&xpand_liney); // printf("cur: %p\n",cur); if (i == cur && renamer != 0) { RenameUIVars *rui = renamer->UpdateUIVars(); // Draw text with cursor int sx, sy; int txty = y+loopsize-xpand_liney; char *curn = renamer->GetCurName(); if (*curn != '\0') VideoIO::draw_text(screen,font->font,curn, x,txty,white,0,0,&sx,&sy); else { sx = 0; sy = xpand_liney; } if (rui->rename_cursor_toggle) boxRGBA(screen, x+sx,txty, x+sx+sy/2,txty+sy, cursorclr.r,cursorclr.g,cursorclr.b,255); } else if (li->name != 0) VideoIO::draw_text(screen,font->font,li->name, x,y+loopsize-xpand_liney, white); } } // Browser::Draw_Item(screen,i,x,y); }; // Draw browser display void Browser::Draw_Item(SDL_Surface *screen, BrowserItem *i, int x, int y) { const static SDL_Color white = { 0xEF, 0xAF, 0xFF, 0 }; const static SDL_Color cursorclr = { 0x77, 0x77, 0x77, 0 }; const static unsigned int tmp_size = 256; static char tmp[tmp_size]; if (font != 0 && font->font != 0 && i != 0) { switch (i->GetType()) { case B_Patch : { PatchItem *p = (PatchItem *) i; // Current patch snprintf(tmp,tmp_size,"%02d: %s",p->id,p->name); VideoIO::draw_text(screen,font->font,tmp,x,y,white); } break; case B_Division : break; default : { if (i->GetType() == B_Loop) snprintf(tmp,tmp_size,"%s-",FWEELIN_OUTPUT_LOOP_NAME); else if (i->GetType() == B_Scene) snprintf(tmp,tmp_size,"%s-",FWEELIN_OUTPUT_SCENE_NAME); else tmp[0] = '\0'; if (i == cur && renamer != 0) { RenameUIVars *rui = renamer->UpdateUIVars(); strncat(tmp,renamer->GetCurName(),tmp_size-1); tmp[tmp_size-1] = '\0'; // Draw text with cursor int sx, sy; VideoIO::draw_text(screen,font->font,tmp,x,y,white,0,0, &sx,&sy); if (rui->rename_cursor_toggle) boxRGBA(screen, x+sx,y, x+sx+sy/2,y+sy, cursorclr.r,cursorclr.g,cursorclr.b,255); } else if (i->name != 0) { strncat(tmp,i->name,tmp_size-1); tmp[tmp_size-1] = '\0'; VideoIO::draw_text(screen,font->font,tmp,x,y,white); } } break; } } }; // Draw browser display void Browser::Draw(SDL_Surface *screen) { LockBrowser(); if (xpanded) { // Draw expanded view // Dim the background for (int i = xpand_y1; i <= xpand_y2; i++) hlineRGBA(screen,xpand_x1,xpand_x2,i,0,0,0,200); hlineRGBA(screen,xpand_x1,xpand_x2,xpand_y1,127,127,127,255); hlineRGBA(screen,xpand_x1,xpand_x2,xpand_y2,127,127,127,255); vlineRGBA(screen,xpand_x1,xpand_y1,xpand_y2,127,127,127,255); vlineRGBA(screen,xpand_x2,xpand_y1,xpand_y2,127,127,127,255); if (cur != 0) { BrowserItem *sp_1 = cur, *sp_2 = cur; // Compute text height and center of expanded window-- once! if (xpand_liney == -1) { TTF_SizeText(font->font,VERSION,0,&xpand_liney); xpand_centery = (xpand_y1+xpand_y2)/2; xpand_spread = MIN(xpand_centery-xpand_y1, xpand_y2-xpand_centery); xpand_spread /= xpand_liney; // printf("compute xpand_liney: %d xpand_centery: %d\n", // xpand_liney, xpand_centery); } int ofs_1 = 0; boxRGBA(screen, xpand_x1,xpand_centery, xpand_x2,xpand_centery+xpand_liney, 127,0,0,255); Draw_Item(screen,sp_1,xpand_x1, xpand_centery-xpand_liney*ofs_1); while (ofs_1 < xpand_spread && sp_1->prev != 0) { sp_1 = sp_1->prev; ofs_1++; Draw_Item(screen,sp_1,xpand_x1, xpand_centery-xpand_liney*ofs_1); } int ofs_2 = 0; while (ofs_2 < xpand_spread-1 && sp_2->next != 0) { sp_2 = sp_2->next; ofs_2++; Draw_Item(screen,sp_2,xpand_x1, xpand_centery+xpand_liney*ofs_2); } } if (mygettime()-xpand_lastactivity >= xpand_delay) { // No activity, close expanded window xpanded = 0; } } // Draw single-line view Draw_Item(screen,cur,xpos,ypos); UnlockBrowser(); } void FloDisplayParamSet::Draw(SDL_Surface *screen) { const static SDL_Color titleclr = { 0x77, 0x88, 0x99, 0 }; const static SDL_Color barclr = { 0xFF, 0x50, 0x20, 0 }; const static SDL_Color borderclr = { 0xFF, 0x50, 0x20, 0 }; boxRGBA(screen, xpos,ypos,xpos+sx,ypos+sy, 0,0,0,190); vlineRGBA(screen,xpos,ypos,ypos+sy, borderclr.r,borderclr.g,borderclr.b,255); vlineRGBA(screen,xpos+sx,ypos,ypos+sy, borderclr.r,borderclr.g,borderclr.b,255); hlineRGBA(screen,xpos,xpos+sx,ypos, borderclr.r,borderclr.g,borderclr.b,255); hlineRGBA(screen,xpos,xpos+sx,ypos+sy, borderclr.r,borderclr.g,borderclr.b,255); if (font == 0 || font->font == 0) { printf("VIDEO: WARNING: No font specified for parameter set.\n"); return; } int textheight = 0; TTF_SizeText(font->font,VERSION,0,&textheight); // Draw title if (title != 0) VideoIO::draw_text(screen,font->font, title,xpos+sx-margin,ypos,titleclr,2,0); if (curbank < numbanks) { ParamSetBank *b = &banks[curbank]; if (b->name != 0) VideoIO::draw_text(screen,font->font,banks[curbank].name, xpos+margin,ypos,titleclr,0,0); // Draw bars for all active parameters in this bank int spacing = (sx - margin*2) / numactiveparams, cury = ypos + sy - margin, curbary = cury - textheight - margin; int maxheight = sy - margin*3 - textheight*3; float barscale = maxheight / b->maxvalue; int thickness = spacing / 4; int curx = xpos + thickness*2 + margin; for (int i = b->firstparamidx; i < b->numparams && i < b->firstparamidx + numactiveparams; i++, curx += spacing) { // Param name if (b->params[i].name != 0) VideoIO::draw_text(screen,font->font,b->params[i].name, curx,cury,titleclr,1,2); float lvl = b->params[i].value * barscale; // Show max value boxRGBA(screen, curx-thickness/2,curbary, curx+thickness/2,curbary-maxheight, barclr.r/2,barclr.g/2,barclr.b/2,255); // Bar boxRGBA(screen, curx-thickness,curbary, curx+thickness,curbary-lvl, barclr.r/2,barclr.g/2,barclr.b/2,255); boxRGBA(screen, curx-thickness/2,curbary, curx+thickness/2,curbary-lvl, barclr.r,barclr.g,barclr.b,255); } } }; // Draw text display void FloDisplayText::Draw(SDL_Surface *screen) { static char tmp[255]; const static SDL_Color titleclr = { 0x77, 0x88, 0x99, 0 }; const static SDL_Color valclr = { 0xDF, 0xEF, 0x20, 0 }; if (font != 0 && font->font != 0) { int xofs = 0, yofs = 0; // Draw title if (title != 0) VideoIO::draw_text(screen,font->font, title,xpos,ypos,titleclr,0,1, &xofs,&yofs); // Draw value UserVariable val = exp->Evaluate(0); val.Print(tmp,255); VideoIO::draw_text(screen,font->font, tmp,xpos+xofs,ypos,valclr,0,1); } }; // Draw switch display void FloDisplaySwitch::Draw(SDL_Surface *screen) { const static SDL_Color title1clr = { 0xDF, 0xEF, 0x20, 0 }; const static SDL_Color title0clr = { 0x11, 0x22, 0x33, 0 }; if (font != 0 && font->font != 0 && title != 0) { // Evaluate exp UserVariable val = exp->Evaluate(0); char nonz = (char) val; // Draw title VideoIO::draw_text(screen,font->font, title,xpos,ypos,(nonz ? title1clr : title0clr),0,1); } }; // Draw circular switch display void FloDisplayCircleSwitch::Draw(SDL_Surface *screen) { const static SDL_Color titleclr = { 0x77, 0x88, 0x99, 0 }; SDL_Color c1clr = { 0xDF, 0x20, 0x20, 0 }; SDL_Color c0clr = { 0x11, 0x22, 0x33, 0 }; const static float flashspd = 4.0; double dt = mygettime()-nonztime; char flashon = 1; if (flash) flashon = !((char) (((long int) (dt*flashspd)) % 2)); // Evaluate exp UserVariable val = exp->Evaluate(0); char nonz = (char) val; if (nonz && !prevnonz) // Value is switching on-- store time nonztime = mygettime(); prevnonz = nonz; // Draw circle SDL_Color *c = (nonz && flashon ? &c1clr : &c0clr); filledCircleRGBA(screen,xpos,ypos,(nonz && flashon ? rad1 : rad0), c->r, c->g, c->b, 255); if (font != 0 && font->font != 0 && title != 0) { // Draw title VideoIO::draw_text(screen,font->font, title,xpos+2*rad0,ypos,titleclr,0,1); } }; // Draw text switch display void FloDisplayTextSwitch::Draw(SDL_Surface *screen) { // No title displayed SDL_Color c1clr = { 0x77, 0x88, 0x99, 0 }; SDL_Color c0clr = { 0x99, 0x88, 0x77, 0 }; // Evaluate exp UserVariable val = exp->Evaluate(0); char nonz = (char) val; // Draw appropriate text char *dtxt = (nonz ? text1 : text0); if (dtxt != 0) VideoIO::draw_text(screen,font->font,dtxt, xpos,ypos, (nonz ? c1clr : c0clr),0,1); }; // Draw text display void FloDisplayBar::Draw(SDL_Surface *screen) { const static SDL_Color titleclr = { 0x77, 0x88, 0x99, 0 }; const static SDL_Color barclr = { 0xFF, 0x50, 0x20, 0 }; const static float calwidth = 1.1; if (font != 0 && font->font != 0) { // Draw title if (title != 0) VideoIO::draw_text(screen,font->font, title,xpos,ypos,titleclr, (orient == O_Vertical ? 1 : 2), (orient == O_Horizontal ? 1 : 0)); } // Get value of expression UserVariable val = exp->Evaluate(0); float fval = (float) val; if (dbscale) { // dB // Convert linear value to dB and then to fader level: int lvl = (int) (AudioLevel::dB_to_fader(LIN2DB(fval), maxdb) * barscale); // Draw bar if (orient == O_Vertical) { // Vertical if (marks) { // Show calibration const static float mindb = -60., dbstep = 6.0; int clrstep = (int) (255/((maxdb-mindb)/dbstep)), clr = 0; for (float i = mindb; i <= maxdb; i += dbstep, clr += clrstep) { // printf("%f > %f def\n",i,AudioLevel::dB_to_fader(i, maxdb)); int clvl = (int) (AudioLevel::dB_to_fader(i, maxdb) * barscale); hlineRGBA(screen, xpos-(int) (calwidth*thickness), xpos-thickness, ypos-clvl, clr,clr,clr,255); hlineRGBA(screen, xpos+thickness, xpos+(int) (calwidth*thickness), ypos-clvl, clr,clr,clr,255); } } // Bar boxRGBA(screen, xpos-thickness,ypos, xpos+thickness,ypos-lvl, barclr.r/2,barclr.g/2,barclr.b/2,255); boxRGBA(screen, xpos-thickness/2,ypos, xpos+thickness/2,ypos-lvl, barclr.r,barclr.g,barclr.b,255); } else { // Horizontal if (marks) { // Show calibration const static float mindb = -60., dbstep = 6.0; int clrstep = (int) (255/((maxdb-mindb)/dbstep)), clr = 0; for (float i = mindb; i <= maxdb; i += dbstep, clr += clrstep) { int clvl = (int) (AudioLevel::dB_to_fader(i, maxdb) * barscale); vlineRGBA(screen, xpos+clvl, ypos-(int) (calwidth*thickness), ypos-thickness, clr,clr,clr,255); vlineRGBA(screen, xpos+clvl, ypos+thickness, ypos+(int) (calwidth*thickness), clr,clr,clr,255); } } // Bar boxRGBA(screen, xpos,ypos-thickness, xpos+lvl,ypos+thickness, barclr.r/2,barclr.g/2,barclr.b/2,255); boxRGBA(screen, xpos,ypos-thickness/2, xpos+lvl,ypos+thickness/2, barclr.r,barclr.g,barclr.b,255); } } else { // Linear // Draw bar if (orient == O_Vertical) { // Vertical // Show calibration boxRGBA(screen, xpos-thickness/2,ypos, xpos+thickness/2,(int) (ypos-barscale), barclr.r/2,barclr.g/2,barclr.b/2,255); // Bar boxRGBA(screen, xpos-thickness,ypos, xpos+thickness,(int) (ypos-fval*barscale), barclr.r/2,barclr.g/2,barclr.b/2,255); boxRGBA(screen, xpos-thickness/2,ypos, xpos+thickness/2,(int) (ypos-fval*barscale), barclr.r,barclr.g,barclr.b,255); } else { // Horizontal // Show calibration boxRGBA(screen, xpos,ypos-thickness/2, (int) (xpos+barscale),ypos+thickness/2, barclr.r/2,barclr.g/2,barclr.b/2,255); // Bar boxRGBA(screen, xpos,ypos-thickness, (int) (xpos+fval*barscale),ypos+thickness, barclr.r/2,barclr.g/2,barclr.b/2,255); boxRGBA(screen, xpos,ypos-thickness/2, (int) (xpos+fval*barscale),ypos+thickness/2, barclr.r,barclr.g,barclr.b,255); } } }; // Draw text display void FloDisplayBarSwitch::Draw(SDL_Surface *screen) { const static SDL_Color titleclr = { 0x77, 0x88, 0x99, 0 }, warnclr = { 0xFF, 0, 0, 0 }; const static SDL_Color barclr[2] = { { 0xEF, 0xAF, 0xFF, 0 }, { 0xCF, 0x4F, 0xFC, 0 } }; const static float calwidth = 1.1; const SDL_Color *bc = (color == 2 ? &barclr[1] : &barclr[0]); if (font != 0 && font->font != 0) { // Draw title if (title != 0) VideoIO::draw_text(screen,font->font, title,xpos,ypos,titleclr, (orient == O_Vertical ? 1 : 2), (orient == O_Horizontal ? 1 : 0)); } // Get value of expression UserVariable val = exp->Evaluate(0); float fval = (float) val; UserVariable sval = switchexp->Evaluate(0); char sw = (char) sval; if (calibrate && fval >= cval) bc = &warnclr; if (dbscale) { // dB // Convert linear value to dB and then to fader level: int lvl = (int) (AudioLevel::dB_to_fader(LIN2DB(fval), maxdb) * barscale); // Draw bar if (orient == O_Vertical) { // Vertical if (marks) { // Show calibration const static float mindb = -60., dbstep = 6.0; int clrstep = (int) (255/((maxdb-mindb)/dbstep)), clr = 0; for (float i = mindb; i <= maxdb; i += dbstep, clr += clrstep) { int clvl = (int) (AudioLevel::dB_to_fader(i, maxdb) * barscale); hlineRGBA(screen, xpos-(int) (calwidth*thickness/2), xpos-thickness/2, ypos-clvl, clr,clr,clr,(sw ? 255 : 127)); hlineRGBA(screen, xpos+thickness/2, xpos+(int) (calwidth*thickness/2), ypos-clvl, clr,clr,clr,(sw ? 255 : 127)); } } // Bar boxRGBA(screen, xpos-thickness/2,ypos, xpos+thickness/2,ypos-lvl, bc->r,bc->g,bc->b,(sw ? 255 : 127)); } else { // Horizontal if (marks) { // Show calibration const static float mindb = -60., dbstep = 6.0; int clrstep = (int) (255/((maxdb-mindb)/dbstep)), clr = 0; for (float i = mindb; i <= maxdb; i += dbstep, clr += clrstep) { int clvl = (int) (AudioLevel::dB_to_fader(i, maxdb) * barscale); vlineRGBA(screen, xpos+clvl, ypos-(int) (calwidth*thickness/2), ypos-thickness/2, clr,clr,clr,(sw ? 255 : 127)); vlineRGBA(screen, xpos+clvl, ypos+thickness/2, ypos+(int) (calwidth*thickness/2), clr,clr,clr,(sw ? 255 : 127)); } } // Bar boxRGBA(screen, xpos,ypos-thickness/2, xpos+lvl,ypos+thickness/2, bc->r,bc->g,bc->b,(sw ? 255 : 127)); } } else { // Linear // Draw bar if (orient == O_Vertical) { // Vertical // Bar boxRGBA(screen, xpos-thickness/2,ypos, xpos+thickness/2,(int) (ypos-fval*barscale), bc->r,bc->g,bc->b,(sw ? 255 : 127)); // Calibrate if (calibrate) hlineRGBA(screen, xpos-thickness/2, xpos+thickness/2, (int) (ypos-cval*barscale), 255,255,255,(sw ? 255 : 127)); } else { // Horizontal // Bar boxRGBA(screen, xpos,ypos-thickness/2, (int) (xpos+fval*barscale),ypos+thickness/2, bc->r,bc->g,bc->b,(sw ? 255 : 127)); // Calibrate if (calibrate) vlineRGBA(screen, (int) (xpos+cval*barscale), ypos-thickness/2, ypos+thickness/2, 255,255,255,(sw ? 255 : 127)); } } }; // Draw this element to the given screen- // implementation given in videoio.cc void FloLayoutBox::Draw(SDL_Surface *screen, SDL_Color clr) { // Solid box boxRGBA(screen, left,top,right,bottom, clr.r,clr.g,clr.b,255); // Outline if (lineleft) vlineRGBA(screen,left,top,bottom,0,0,0,255); if (lineright) vlineRGBA(screen,right,top,bottom,0,0,0,255); if (linetop) hlineRGBA(screen,left,right,top,0,0,0,255); if (linebottom) hlineRGBA(screen,left,right,bottom,0,0,0,255); }; // Draw snapshots display void FloDisplaySnapshots::Draw(SDL_Surface *screen) { const static SDL_Color titleclr = { 0x77, 0x88, 0x99, 0 }; const static SDL_Color borderclr = { 0xFF, 0x50, 0x20, 0 }; const static SDL_Color cursorclr = { 0xEF, 0x11, 0x11, 0 }; LockSnaps(); if (numdisp == -1) { int height = TTF_FontHeight(font->font); numdisp = sy/height; } boxRGBA(screen, xpos,ypos,xpos+sx,ypos+sy, 0,0,0,190); vlineRGBA(screen,xpos,ypos,ypos+sy, borderclr.r,borderclr.g,borderclr.b,255); vlineRGBA(screen,xpos+sx,ypos,ypos+sy, borderclr.r,borderclr.g,borderclr.b,255); hlineRGBA(screen,xpos,xpos+sx,ypos, borderclr.r,borderclr.g,borderclr.b,255); hlineRGBA(screen,xpos,xpos+sx,ypos+sy, borderclr.r,borderclr.g,borderclr.b,255); if (font != 0 && font->font != 0) { // Draw title if (title != 0) VideoIO::draw_text(screen,font->font, title,xpos+sx/2,ypos,titleclr,1,2); } // Draw items int cury = ypos+margin; int height = TTF_FontHeight(font->font); for (int i = firstidx; i < firstidx + numdisp; i++, cury += height) { const static int SNAP_NAME_LEN = 512; char buf[SNAP_NAME_LEN]; Snapshot *sn = app->getSNAP(i); if (sn != 0) { RenameUIVars *rui = 0; char *nm = sn->name; if (renamer != 0 && i == rename_idx) { // Use current name from renamer rui = renamer->UpdateUIVars(); nm = renamer->GetCurName(); } if (nm != 0) snprintf(buf,SNAP_NAME_LEN,"%2d %s",i+1,nm); else if (sn->exists != 0) snprintf(buf,SNAP_NAME_LEN,"%2d **",i+1); else snprintf(buf,SNAP_NAME_LEN,"%2d",i+1); int sx, sy; VideoIO::draw_text(screen,font->font, buf,xpos+margin,cury,titleclr,0,0,&sx,&sy); if (rui != 0 && rui->rename_cursor_toggle) boxRGBA(screen, xpos+margin+sx,cury, xpos+margin+sx+sy/2,cury+sy, cursorclr.r,cursorclr.g,cursorclr.b,255); } } UnlockSnaps(); }; freewheeling-0.6.6/src/stacktrace.c000066400000000000000000000455031370736313100172610ustar00rootroot00000000000000/************************************************************************* * * Copyright (c) 1998 by Bjorn Reese * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS AND * CONTRIBUTORS ACCEPT NO RESPONSIBILITY IN ANY CONCEIVABLE MANNER. * ************************************************************************ * * 2008/12/28 - JMP * - Modified to avoid '(gdb) Hangup detected on fd 0' * by getting GDB commands from file * * 1999/08/19 - breese * - Cleaned up the interface * * 1999/08/06 - breese * - Added U_STACK_TRACE for HP/UX * * 1999/01/24 - breese * - Added GCC_DumpStack * * 1998/12/21 - breese * - Fixed include files and arguments for waitpid() * - Made an AIX workaround for waitpid() exiting with EINTR * - Added a missing 'quit' command for OSF dbx * ************************************************************************/ #if defined(unix) || defined(__unix) || defined(__xlC__) # define PLATFORM_UNIX #elif defined(WIN32) || defined(_WIN32) # define PLATFORM_WIN32 #else # warning "No platform defined, automatic stack trace will fail!" #endif // defined(unix) || defined(__unix) || defined(__xlC__) #if defined(_AIX) || defined(__xlC__) # define PLATFORM_AIX #elif defined(__FreeBSD__) # define PLATFORM_FREEBSD #elif defined(hpux) || defined(__hpux) || defined(_HPUX_SOURCE) # define PLATFORM_HPUX #elif defined(sgi) || defined(mips) || defined(_SGI_SOURCE) # define PLATFORM_IRIX #elif defined(__osf__) # define PLATFORM_OSF #elif defined(M_I386) || defined(_SCO_DS) || defined(_SCO_C_DIALECT) # define PLATFORM_SCO #elif defined(sun) || defined(__sun__) || defined(__SUNPRO_C) # if defined(__SVR4) || defined(__svr4__) # define PLATFORM_SOLARIS # endif #endif // defined(_AIX) || defined(__xlC__) /* ANSI C includes */ #include #include #include #include #include #include #include #if defined(PLATFORM_UNIX) # include # include # include # if defined(PLATFORM_IRIX) && defined(USE_BUILTIN) /* Compile with -DUSE_BUILTIN and -lexc */ # include # elif defined(PLATFORM_HPUX) && defined(USE_BUILTIN) /* Compile with -DUSE_BUILTIN and -lcl */ extern void U_STACK_TRACE(void); # endif #endif // defined(PLATFORM_UNIX) #include "stacktrace.h" #ifndef FALSE # define FALSE (0 == 1) # define TRUE (! FALSE) #endif #define SYS_ERROR -1 #ifndef EXIT_SUCCESS # define EXIT_SUCCESS 0 #endif #ifndef EXIT_FAILURE # define EXIT_FAILURE 1 #endif #define MAX_BUFFER_SIZE 512 #if defined(__GNUC__) /* Change the code if ADDRESSLIST_SIZE is increased */ # define ADDRESSLIST_SIZE 20 #endif /************************************************************************* * Globals * * We cannot pass custom arguments to signal handlers so we store * them as global variables (but limit their scope to this file.) */ static const char *global_progname; static int global_output = STDOUT_FILENO; #if defined(PLATFORM_UNIX) /************************************************************************* * my_pclose [private] */ static void my_pclose(int fd, int pid) { close(fd); /* Make sure the the child process has terminated */ (void)kill(pid, SIGTERM); } /************************************************************************* * my_popen [private] */ static int my_popen(const char *command, pid_t *pid) { int rc; //int pipefd[2]; //FIXME: deactivated separate piping of debugger output, as it caused problems in conjunction with threads //rc = pipe(pipefd); rc = SYS_ERROR; //if (SYS_ERROR != rc) { *pid = fork(); switch (*pid) { case SYS_ERROR: //rc = SYS_ERROR; //close(pipefd[0]); //close(pipefd[1]); break; case 0: /* Child */ //close(pipefd[0]); //close(STDOUT_FILENO); //close(STDERR_FILENO); //dup2(pipefd[1], STDOUT_FILENO); //dup2(pipefd[1], STDERR_FILENO); /* * The System() call assumes that /bin/sh is * always available, and so will we. */ execl("/bin/sh", "/bin/sh", "-c", command, NULL); _exit(EXIT_FAILURE); break; default: /* Parent */ //close(pipefd[1]); //rc = pipefd[0]; rc = 0; // success break; } /* switch */ } return rc; } /************************************************************************* * my_getline [private] */ static int my_getline(int fd, char *buffer, int max) { char c; int i = 0; do { if (read(fd, &c, 1) < 1) return 0; if (i < max) buffer[i++] = c; } while (c != '\n'); buffer[i] = (char)0; return i; } # if defined(__GNUC__) && defined(USE_BUILTIN) /************************************************************************* * GCC_DumpStack [private] * * * This code is still experimental. * * Stackbased arrays are used to prevent allocating from the heap. * Warning: sprintf/sscanf are not ASync safe. They were used for * convenience. * * 'nm' is used because it is most widespread * GNU: nm [-B] * Solaris: nm -x -p * IRIX: nm -x -B (but __builtin_return_address() always returns NULL) * AIX: nm -x -B * OSF/1: nm -B * SCO/OpenServer: nm -x -p * HP/UX nm -x -p */ typedef struct { unsigned long realAddress; unsigned long closestAddress; char name[MAX_BUFFER_SIZE + 1]; char type; } address_T; static void GCC_DumpStack(void) { int i; void *p = &p; /* dummy start value */ address_T syms[ADDRESSLIST_SIZE + 1]; char buffer[MAX_BUFFER_SIZE]; int fd; pid_t pid; unsigned long addr; unsigned long highestAddress; unsigned long lowestAddress; char type; char *pname; char name[MAX_BUFFER_SIZE]; int number; for (i = 0; p; i++) { /* * This is based on code by Steve Coleman * * __builtin_return_address() only accepts a constant as argument. */ switch (i) { case 0: p = __builtin_return_address(0); break; case 1: p = __builtin_return_address(1); break; case 2: p = __builtin_return_address(2); break; case 3: p = __builtin_return_address(3); break; case 4: p = __builtin_return_address(4); break; case 5: p = __builtin_return_address(5); break; case 6: p = __builtin_return_address(6); break; case 7: p = __builtin_return_address(7); break; case 8: p = __builtin_return_address(8); break; case 9: p = __builtin_return_address(9); break; case 10: p = __builtin_return_address(10); break; case 11: p = __builtin_return_address(11); break; case 12: p = __builtin_return_address(12); break; case 13: p = __builtin_return_address(13); break; case 14: p = __builtin_return_address(14); break; case 15: p = __builtin_return_address(15); break; case 16: p = __builtin_return_address(16); break; case 17: p = __builtin_return_address(17); break; case 18: p = __builtin_return_address(18); break; case 19: p = __builtin_return_address(19); break; default: /* Change ADDRESSLIST_SIZE if more are added */ p = NULL; break; } if ((p) && (i < ADDRESSLIST_SIZE)) { syms[i].realAddress = (unsigned long)p; syms[i].closestAddress = 0; syms[i].name[0] = (char)0; syms[i].type = ' '; } else { syms[i].realAddress = 0; break; /* for */ } } /* for */ /* First find out if we are using GNU or vendor nm */ number = 0; strcpy(buffer, "nm -V 2>/dev/null | grep GNU | wc -l"); fd = my_popen(buffer, &pid); if (SYS_ERROR != fd) { if (my_getline(fd, buffer, sizeof(buffer))) { sscanf(buffer, "%d", &number); } my_pclose(fd, pid); } if (number == 0) /* vendor nm */ { # if defined(PLATFORM_SOLARIS) || defined(PLATFORM_SCO) || defined(PLATFORM_HPUX) strcpy(buffer, "nm -x -p "); # elif defined(PLATFORM_AIX) || defined(PLATFORM_IRIX) || defined(PLATFORM_OSF) strcpy(buffer, "nm -x -B "); # else strcpy(buffer, "nm -B "); # endif } else /* GNU nm */ strcpy(buffer, "nm -B "); strcat(buffer, global_progname); lowestAddress = ULONG_MAX; highestAddress = 0; fd = my_popen(buffer, &pid); if (SYS_ERROR != fd) { while (my_getline(fd, buffer, sizeof(buffer))) { if (buffer[0] == '\n') continue; if (3 == sscanf(buffer, "%lx %c %s", &addr, &type, name)) { if ((type == 't') || type == 'T') { if (addr == 0) continue; /* while */ if (addr < lowestAddress) lowestAddress = addr; if (addr > highestAddress) highestAddress = addr; for (i = 0; syms[i].realAddress != 0; i++) { if ((addr <= syms[i].realAddress) && (addr > syms[i].closestAddress)) { syms[i].closestAddress = addr; strncpy(syms[i].name, name, MAX_BUFFER_SIZE); syms[i].name[MAX_BUFFER_SIZE] = (char)0; syms[i].type = type; } } } } } my_pclose(fd, pid); for (i = 0; syms[i].realAddress != 0; i++) { if ((syms[i].name[0] == (char)0) || (syms[i].realAddress <= lowestAddress) || (syms[i].realAddress >= highestAddress)) { sprintf(buffer, "[%d] 0x%08lx ???\n", i, syms[i].realAddress); } else { sprintf(buffer, "[%d] 0x%08lx <%s + 0x%lx> %c\n", i, syms[i].realAddress, syms[i].name, syms[i].realAddress - syms[i].closestAddress, syms[i].type); } write(global_output, buffer, strlen(buffer)); } } } # endif // defined(__GNUC__) && defined(USE_BUILTIN) /************************************************************************* * DumpStack [private] */ static int DumpStack(char *format, ...) { int gotSomething = FALSE; int fd; pid_t pid; int status = EXIT_FAILURE; int rc; va_list args; char cmd[MAX_BUFFER_SIZE]; /* * Please note that vsprintf() is not ASync safe (ie. cannot safely * be used from a signal handler.) If this proves to be a problem * then the cmd string can be built by more basic functions such as * strcpy, strcat, and a homemade integer-to-ascii function. */ va_start(args, format); vsprintf(cmd, format, args); va_end(args); fd = my_popen(cmd, &pid); if (SYS_ERROR != fd) { /* * Wait for the child to exit. This must be done * to make the debugger attach successfully. * The output from the debugger is buffered on * the pipe. * * AIX needs the looping hack */ do { rc = waitpid(pid, &status, 0); } while ((SYS_ERROR == rc) && (EINTR == errno)); #define NO_SEPARATE_DEBUG_PIPING #ifdef NO_SEPARATE_DEBUG_PIPING //FIXME: deactivated separate piping of debugger output, as it caused problems in conjunction with threads gotSomething = TRUE; //HACK: my_getline(-1, NULL, 0); // avoid 'unused-function' compiler warning #else char *buffer; char buf[MAX_BUFFER_SIZE]; if ((WIFEXITED(status)) && (WEXITSTATUS(status) == EXIT_SUCCESS)) { while (my_getline(fd, buf, sizeof(buf))) { buffer = buf; if (! gotSomething) { write(global_output, "Output from ", strlen("Output from ")); strtok(cmd, " "); write(global_output, cmd, strlen(cmd)); write(global_output, "\n", strlen("\n")); gotSomething = TRUE; } if ('\n' == buf[strlen(buf)-1]) { buf[strlen(buf)-1] = (char)0; } write(global_output, buffer, strlen(buffer)); write(global_output, "\n", strlen("\n")); } } #endif // NO_SEPARATE_DEBUG_PIPING my_pclose(fd, pid); } return gotSomething; } #endif // defined(PLATFORM_UNIX) /************************************************************************* * StackTrace */ void StackTrace(char *gdb_command_file) { #if defined(PLATFORM_UNIX) /* * In general dbx seems to do a better job than gdb. * * Different dbx implementations require different flags/commands. */ # if defined(PLATFORM_AIX) if (DumpStack("dbx -a %d 2>/dev/null </dev/null </dev/null <&1 </dev/null </dev/null </dev/null </dev/null </dev/null </dev/null </dev/null </dev/null </dev/null <&1 < </dev/null </dev/null <%s >fweelin-stackdump", global_progname, (int)getpid(), gdb_command_file)) return; #if 0 // This version does not work (piping from stdin) if (DumpStack("gdb -q %s %d 2>/dev/null < * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS AND * CONTRIBUTORS ACCEPT NO RESPONSIBILITY IN ANY CONCEIVABLE MANNER. * ************************************************************************ * * Purpose: * To generate a stacktrace of a program. * * Description: * If a debugger is located on the machine we will try this first, * as it usually give better information than built-in methods. * The debugger needs the name of the program to be able to attach * to it, so this must be passed to StackTraceInit(). The second * argument is a filedescriptor that StackTrace() writes to. If this * argument is -1 then standard output will be used. * * Compilation: * Some platforms have a built-in method to generate stacktraces, but * they are usually located in some non-standard library. The following * are supported: * * IRIX Compile with -DUSE_BUILTIN and -lexc * HP/UX Compile with -DUSE_BUILTIN and -lcl * GCC Compile with -DUSE_BUILTIN * ************************************************************************/ #ifndef H_DEBUG_STACKTRACE #define H_DEBUG_STACKTRACE #if defined(__cplusplus) extern "C" { #endif // __cplusplus void StackTrace(char *gdb_command_file); void StackTraceInit(const char *progname, int handle); #if defined(__cplusplus) } #endif // __cplusplus #endif /* H_DEBUG_STACKTRACE */